diff --git a/.travis.yml b/.travis.yml index 80677c4c030..1fbffbcaa3e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,11 +47,11 @@ env: - PACKAGE='Stream_support Subdivision_method_3 Surface_mesh ' - PACKAGE='Surface_mesh_approximation Surface_mesh_deformation Surface_mesh_parameterization ' - PACKAGE='Surface_mesh_segmentation Surface_mesh_shortest_path Surface_mesh_simplification ' - - PACKAGE='Surface_mesh_skeletonization Surface_mesher Surface_sweep_2 ' - - PACKAGE='TDS_2 TDS_3 Testsuite ' - - PACKAGE='Three Triangulation Triangulation_2 ' - - PACKAGE='Triangulation_3 Union_find Visibility_2 ' - - PACKAGE='Voronoi_diagram_2 wininst ' + - PACKAGE='Surface_mesh_skeletonization Surface_mesh_topology Surface_mesher ' + - PACKAGE='Surface_sweep_2 TDS_2 TDS_3 ' + - PACKAGE='Testsuite Three Triangulation ' + - PACKAGE='Triangulation_2 Triangulation_3 Union_find ' + - PACKAGE='Visibility_2 Voronoi_diagram_2 wininst ' compiler: clang install: - echo "$PWD" diff --git a/.travis/packages.txt b/.travis/packages.txt index 8bcfe911043..731c19e675c 100644 --- a/.travis/packages.txt +++ b/.travis/packages.txt @@ -122,6 +122,7 @@ Surface_mesh_segmentation Surface_mesh_shortest_path Surface_mesh_simplification Surface_mesh_skeletonization +Surface_mesh_topology Surface_mesher Surface_sweep_2 TDS_2 diff --git a/.travis/test_package.sh b/.travis/test_package.sh index f91f9982916..7b01d24ceb4 100644 --- a/.travis/test_package.sh +++ b/.travis/test_package.sh @@ -5,11 +5,17 @@ DO_IGNORE=FALSE cd $1 -if [ ! -f "$2/package_info/$2/dependencies" ];then + +if [ ! -d "$2" ]; then + echo "$2 : MISSING PACKAGE. Ignoring." + DO_IGNORE=TRUE + exit 1 +fi + + +if [ ! -f "$2/package_info/$2/dependencies" ];then echo "No dependencies found for $2" - bash Scripts/developer_scripts/cgal_check_dependencies.sh --check_headers /usr/bin/doxygen - - + bash Scripts/developer_scripts/cgal_check_dependencies.sh --check_headers /usr/bin/doxygen exit 1 fi LIST_OF_FILES=$(git diff --name-only origin/master... |cut -d/ -f1 |uniq |sort) diff --git a/AABB_tree/doc/AABB_tree/Concepts/AABBTraits.h b/AABB_tree/doc/AABB_tree/Concepts/AABBTraits.h index 613723bdef3..a6348816d31 100644 --- a/AABB_tree/doc/AABB_tree/Concepts/AABBTraits.h +++ b/AABB_tree/doc/AABB_tree/Concepts/AABBTraits.h @@ -75,7 +75,7 @@ using Intersection_and_primitive_id = unspecified_type; /// \name Splitting /// During the construction of the AABB tree, the primitives are -/// splitted according to some comparison functions related to the longest axis: +/// split according to some comparison functions related to the longest axis: /// @{ /*! diff --git a/Advancing_front_surface_reconstruction/examples/Advancing_front_surface_reconstruction/reconstruction_fct.cpp b/Advancing_front_surface_reconstruction/examples/Advancing_front_surface_reconstruction/reconstruction_fct.cpp index f3b259d80e4..9b3d83f3eef 100644 --- a/Advancing_front_surface_reconstruction/examples/Advancing_front_surface_reconstruction/reconstruction_fct.cpp +++ b/Advancing_front_surface_reconstruction/examples/Advancing_front_surface_reconstruction/reconstruction_fct.cpp @@ -60,6 +60,8 @@ int main(int argc, char* argv[]) { std::ifstream in((argc>1)?argv[1]:"data/half.xyz"); double per = (argc>2)?boost::lexical_cast(argv[2]):0; + double radius_ratio_bound = (argc>3)?boost::lexical_cast(argv[3]):5.0; + std::vector points; std::vector facets; @@ -71,7 +73,8 @@ int main(int argc, char* argv[]) CGAL::advancing_front_surface_reconstruction(points.begin(), points.end(), std::back_inserter(facets), - perimeter); + perimeter, + radius_ratio_bound); std::cout << "OFF\n" << points.size() << " " << facets.size() << " 0\n"; std::copy(points.begin(), diff --git a/Advancing_front_surface_reconstruction/examples/Advancing_front_surface_reconstruction/reconstruction_structured.cpp b/Advancing_front_surface_reconstruction/examples/Advancing_front_surface_reconstruction/reconstruction_structured.cpp index 6bb2f610ab4..4b984f317d9 100644 --- a/Advancing_front_surface_reconstruction/examples/Advancing_front_surface_reconstruction/reconstruction_structured.cpp +++ b/Advancing_front_surface_reconstruction/examples/Advancing_front_surface_reconstruction/reconstruction_structured.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/Apollonius_graph_2.txt b/Apollonius_graph_2/doc/Apollonius_graph_2/Apollonius_graph_2.txt index 8f29331cbfb..196fc8451f1 100644 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/Apollonius_graph_2.txt +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/Apollonius_graph_2.txt @@ -369,9 +369,9 @@ concept. The second template parameter is a tag that indicates what operations are allowed in the computations that take place within the traits class. The two possible values of the `Method_tag` parameter are -`Ring_tag` and `Sqrt_field_tag`. When -`Ring_tag` is used, only ring operations are used during the -evaluation of the predicates, whereas if `Sqrt_field_tag` is +`Integral_domain_without_division_tag` and `Field_with_sqrt_tag`. When +`Integral_domain_without_division_tag` is used, only ring operations are used during the +evaluation of the predicates, whereas if `Field_with_sqrt_tag` is chosen, all four field operations, as well as square roots, are used during the predicate evaluation. @@ -379,32 +379,22 @@ The `Apollonius_graph_traits_2` class provides exact predicates if the number type in the kernel `K` is an exact number type. This is to be associated with the type of operations allowed for the predicate evaluation. For example `MP_Float` as number -type, with `Ring_tag` as tag will give exact predicates, -whereas `MP_Float` with `Sqrt_field_tag` will give +type, with `Integral_domain_without_division_tag` as tag will give exact predicates, +whereas `MP_Float` with `Field_with_sqrt_tag` will give inexact predicates. -Since using an exact number type may be too slow, the -`Apollonius_graph_traits_2` class is designed to -support the dynamic filtering of \cgal through the -`Filtered_exact` mechanism. In particular if `CT` -is an inexact number type that supports the operations denoted by the -tag `Method_tag` and `ET` is an exact number type for these -operations, then kernel with number type -`Filtered_exact` will yield exact predicates for the -Apollonius graph traits. To give a concrete example, -`CGAL::Filtered_exact` with -`Ring_tag` will produce exact predicates. - -Another possibility for fast and exact predicate evaluation is to use -the -`Apollonius_graph_filtered_traits_2` -class. This class is the analog of a filtered kernel. It takes a +Although exact number types provide exact predicates and constructions, +their use often results in unacceptably large runtimes. +The class `Apollonius_graph_filtered_traits_2` +aims to paliate this shortcoming. Similar to a filtered kernel, it takes a constructions kernel `CK`, a filtering kernel `FK` and an exact kernel `EK`, as well as the corresponding tags (`CM`, `FM` and `EM`, respectively). -It evaluates the predicates by first using the filtering kernel, and -if this fails the evaluation is performed using the exact kernel. The -constructions are done using the kernel `CK`, which means that +Predicates are evaluated by first using the filtering kernel, and +if this fails the evaluation is performed using the exact kernel, +thus yielding exact predicates at a generally much cheaper cost +than directly using an exact number type. The constructions +are done using the kernel `CK`, which means that they are not necessarily exact. All template parameters except `CK` have default values, which are explained in the reference manual. diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_filtered_traits_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_filtered_traits_2.h index a1b4a8003d5..c49c4a0bb76 100644 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_filtered_traits_2.h +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_filtered_traits_2.h @@ -20,8 +20,8 @@ This class has six template parameters. The first, third and fifth template parameters must be a models of the `Kernel` concept. The second, fourth and sixth template parameters correspond to how predicates are evaluated. There are two predefined possible values for -`Method_tag`, namely `CGAL::Sqrt_field_tag` and -`CGAL::Ring_tag`. The first one must be used when the number type +`Method_tag`, namely `CGAL::Field_with_sqrt_tag` and +`CGAL::Integral_domain_without_division_tag`. The first one must be used when the number type used in the representation supports the exact evaluation of signs of expressions involving all four basic operations and square roots, whereas the second one requires the exact evaluation of signs of @@ -31,7 +31,7 @@ The way the predicates are evaluated is discussed in \cgalCite{cgal:ke-ppawv-02}, \cgalCite{cgal:ke-rctac-03}. The default values for the template parameters are as follows: -`CM = CGAL::Ring_tag`, +`CM = CGAL::Integral_domain_without_division_tag`, `EK = CGAL::Simple_cartesian`, `EM = CM`, `FK = CGAL::Simple_cartesian >`, @@ -41,8 +41,8 @@ The default values for the template parameters are as follows: \sa `Kernel` \sa `ApolloniusGraphTraits_2` -\sa `CGAL::Ring_tag` -\sa `CGAL::Sqrt_field_tag` +\sa `CGAL::Integral_domain_without_division_tag` +\sa `CGAL::Field_with_sqrt_tag` \sa `CGAL::Apollonius_graph_2` \sa `CGAL::Apollonius_graph_traits_2` diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_traits_2.h b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_traits_2.h index 6f3d11a7517..2b9ebca5625 100644 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_traits_2.h +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/CGAL/Apollonius_graph_traits_2.h @@ -10,13 +10,13 @@ This class has two template parameters. The first template parameter must be a model of the `Kernel` concept. The second template parameter corresponds to how predicates are evaluated. There are two predefined possible values for `Method_tag`, namely -`CGAL::Sqrt_field_tag` and `CGAL::Ring_tag`. The first one +`CGAL::Field_with_sqrt_tag` and `CGAL::Integral_domain_without_division_tag`. The first one must be used when the number type used in the representation supports the exact evaluation of signs of expressions involving all four basic operations and square roots, whereas the second one requires the exact evaluation of signs of ring-type expressions, i.e., expressions involving only additions, subtractions and multiplications. The -default value for `Method_tag` is `CGAL::Ring_tag`. +default value for `Method_tag` is `CGAL::Integral_domain_without_division_tag`. The way the predicates are evaluated is discussed in \cgalCite{cgal:ke-ppawv-02}, \cgalCite{cgal:ke-rctac-03}. @@ -24,8 +24,8 @@ The way the predicates are evaluated is discussed in \sa `Kernel` \sa `ApolloniusGraphTraits_2` -\sa `CGAL::Ring_tag` -\sa `CGAL::Sqrt_field_tag` +\sa `CGAL::Integral_domain_without_division_tag` +\sa `CGAL::Field_with_sqrt_tag` \sa `CGAL::Apollonius_graph_2` \sa `CGAL::Apollonius_graph_filtered_traits_2` diff --git a/Apollonius_graph_2/doc/Apollonius_graph_2/dependencies b/Apollonius_graph_2/doc/Apollonius_graph_2/dependencies index 49ad6034b25..6270b1d0d3b 100644 --- a/Apollonius_graph_2/doc/Apollonius_graph_2/dependencies +++ b/Apollonius_graph_2/doc/Apollonius_graph_2/dependencies @@ -5,5 +5,6 @@ Algebraic_foundations Circulator Stream_support Voronoi_diagram_2 +Number_types TDS_2 Triangulation_2 diff --git a/Apollonius_graph_2/include/CGAL/Apollonius_graph_2/check_filter.h b/Apollonius_graph_2/include/CGAL/Apollonius_graph_2/check_filter.h deleted file mode 100644 index d2395df4880..00000000000 --- a/Apollonius_graph_2/include/CGAL/Apollonius_graph_2/check_filter.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2003,2004 INRIA Sophia-Antipolis (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// -// Author(s) : Menelaos Karavelas - - - -#ifndef CGAL_CHECK_FILTER_H -#define CGAL_CHECK_FILTER_H - -#include - - -#undef CGAL_IA_NEW_FILTERS - -namespace CGAL { - -template < class T> -void must_be_filtered(const T&) -{} - -#if defined CGAL_ARITHMETIC_FILTER_H -template < class CT, class ET, class Type, bool Protection, class Cache> -void must_be_filtered(const Filtered_exact &) -{ dont_compile(CT(), ET()); } -#endif - -} - -#endif diff --git a/Apollonius_graph_2/include/CGAL/Apollonius_graph_filtered_traits_2.h b/Apollonius_graph_2/include/CGAL/Apollonius_graph_filtered_traits_2.h index a3e7e957521..0f2a088f716 100644 --- a/Apollonius_graph_2/include/CGAL/Apollonius_graph_filtered_traits_2.h +++ b/Apollonius_graph_2/include/CGAL/Apollonius_graph_filtered_traits_2.h @@ -165,6 +165,7 @@ public: //--------------------------------- typedef typename CK_traits::Construct_object_2 Construct_object_2; typedef typename CK_traits::Assign_2 Assign_2; + typedef typename CK_traits::Construct_point_2 Construct_point_2; // CONSTRUCTIONS //-------------- @@ -329,6 +330,10 @@ public: return Construct_object_2(); } + Construct_point_2 + construct_point_2_object() const { + return Construct_point_2(); + } // CONSTRUCTIONS //-------------- diff --git a/Apollonius_graph_2/include/CGAL/Apollonius_graph_traits_2.h b/Apollonius_graph_2/include/CGAL/Apollonius_graph_traits_2.h index 040d4bef6ee..335b43cf0d0 100644 --- a/Apollonius_graph_2/include/CGAL/Apollonius_graph_traits_2.h +++ b/Apollonius_graph_2/include/CGAL/Apollonius_graph_traits_2.h @@ -75,6 +75,8 @@ public: // CONSTRUCTIONS //-------------- + typedef typename Kernel::Construct_point_2 Construct_point_2; + // vertex and dual site typedef CGAL_APOLLONIUS_GRAPH_2_NS::Construct_Apollonius_vertex_2 /* */ Construct_Apollonius_vertex_2; @@ -142,6 +144,10 @@ public: return Construct_object_2(); } + Construct_point_2 + construct_point_2_object() const { + return Construct_point_2(); + } // CONSTRUCTIONS //-------------- diff --git a/Apollonius_graph_2/include/CGAL/Hyperbola_segment_2.h b/Apollonius_graph_2/include/CGAL/Hyperbola_segment_2.h index 318a7d0643b..0a8d0357fb6 100644 --- a/Apollonius_graph_2/include/CGAL/Hyperbola_segment_2.h +++ b/Apollonius_graph_2/include/CGAL/Hyperbola_segment_2.h @@ -83,6 +83,10 @@ public: this->p2 = p2; } + int compute_k(const FT tt) const { + return int(CGAL::to_double(CGAL::sqrt(tt / this->STEP))); + } + void generate_points(std::vector& p) const { if ( CGAL::is_zero(this->r) ) { @@ -91,76 +95,70 @@ public: return; } - - // FT STEP = W.width() / 100.0; - FT s0, s1; s0 = t(p1); s1 = t(p2); - if (CGAL::compare(s0, s1) == LARGER) { + if (CGAL::compare(s0, s1) == LARGER) std::swap(s0, s1); - } p.clear(); - if ( !(CGAL::is_positive(s0)) && - !(CGAL::is_negative(s1)) ) { - FT tt; - int k; + if ( !(CGAL::is_positive(s0)) && !(CGAL::is_negative(s1)) ) + { + FT tt = FT(-this->STEP); + int k = -1; p.push_back( this->o ); - k = 1; - tt = FT(-this->STEP); - while ( CGAL::compare(tt, s0) == LARGER ) { - p.insert( p.begin(), f(tt) ); - k--; - tt = -FT(k * k) * this->STEP; + + while ( CGAL::compare(tt, s0) == LARGER ) + { + p.insert( p.begin(), f(tt) ); + --k; + tt = - FT(k * k) * this->STEP; } + p.insert( p.begin(), f(s0) ); k = 1; tt = FT(this->STEP); - while ( CGAL::compare(tt, s1) == SMALLER ) { - p.push_back( f(tt) ); - k++; - tt = FT(k * k) * this->STEP; + while ( CGAL::compare(tt, s1) == SMALLER ) + { + p.push_back( f(tt) ); + ++k; + tt = FT(k * k) * this->STEP; } p.push_back( f(s1) ); - } else if ( !(CGAL::is_negative(s0)) && - !(CGAL::is_negative(s1)) ) { - FT tt; - int k; + } + else if ( !(CGAL::is_negative(s0)) && !(CGAL::is_negative(s1)) ) + { + FT tt = s0; + int k = - compute_k(-tt); - - p.push_back( f(s0) ); - - tt = s0; - k = int(CGAL::to_double(CGAL::sqrt(tt / this->STEP))); - - while ( CGAL::compare(tt, s1) == SMALLER ) { - if ( CGAL::compare(tt, s0) != SMALLER ) - p.push_back( f(tt) ); - k++; - tt = FT(k * k) * this->STEP; + do + { + p.push_back( f(tt) ); + ++k; + tt = FT(k * k) * this->STEP; } - p.push_back( f(s1) ); - } else { - FT tt; - int k; + while ( CGAL::compare(tt, s0) == LARGER && CGAL::compare(tt, s1) == SMALLER ); p.push_back( f(s1) ); + } + else + { + FT tt = s1; + int k = compute_k(tt); - tt = s1; - k = int(CGAL::to_double(-CGAL::sqrt(-tt / this->STEP))); - - while ( CGAL::compare(tt, s0) == LARGER ) { - if ( CGAL::compare(tt, s1) != LARGER ) - p.push_back( f(tt) ); - k--; - tt = -FT(k * k) * this->STEP; + do + { + p.push_back( f(tt) ); + --k; + tt = - FT(k * k) * this->STEP; } + while ( CGAL::compare(tt, s0) == LARGER && CGAL::compare(tt, s1) == SMALLER ); + p.push_back( f(s0) ); } } diff --git a/Apollonius_graph_2/include/CGAL/Parabola_segment_2.h b/Apollonius_graph_2/include/CGAL/Parabola_segment_2.h index 52cbc6c72de..7f7271d3f57 100644 --- a/Apollonius_graph_2/include/CGAL/Parabola_segment_2.h +++ b/Apollonius_graph_2/include/CGAL/Parabola_segment_2.h @@ -62,85 +62,100 @@ public: this->p2 = p2; } - int compute_k(const FT& tt) const { - return int(CGAL::sqrt(CGAL::to_double(tt) / 2)); + int compute_k(const FT tt, const FT STEP) const { + return int(CGAL::to_double(CGAL::sqrt(tt / STEP))); } + // s0 and s1 define a desired drawing "range" void generate_points(std::vector& p, - const FT STEP = FT(2)) const + const FT STEP, + FT s0, FT s1) const { - FT s0, s1; - - s0 = t(p1); - s1 = t(p2); - - if (CGAL::compare(s0, s1) == LARGER) { - std::swap(s0, s1); - } + CGAL_precondition(STEP > 0); p.clear(); - if ( !(CGAL::is_positive(s0)) && - !(CGAL::is_negative(s1)) ) { - FT tt; - int k; + if (CGAL::compare(s0, s1) == LARGER) + std::swap(s0, s1); + + // This is a parabola segment that exists between only between p1 and p2 so we gotta crop + // the desired range to actually fit the parabola segment + FT tp1 = t(p1), tp2 = t(p2); + + if (CGAL::compare(tp1, tp2) == LARGER) + std::swap(tp1, tp2); + + if(tp2 < s0 || s1 < tp1) // nothing to draw because the ranges are completely disjoint + return; + + s0 = (std::max)(s0, tp1); + s1 = (std::min)(s1, tp2); + + if ( !(CGAL::is_positive(s0)) && !(CGAL::is_negative(s1)) ) + { + FT tt = - STEP; + int k = -1; p.push_back( this->o ); - k = -1; - tt = - STEP; - while ( CGAL::compare(tt, s0) == LARGER ) { - p.insert( p.begin(), f(tt) ); - k--; - tt = -FT(k * k) * STEP; + // no need to check tt < s1 since we have tt < 0, s1 >= 0 and tt is moving towards -inf + while ( CGAL::compare(tt, s0) == LARGER ) + { + p.insert( p.begin(), f(tt) ); + --k; + tt = - FT(k * k) * STEP; } p.insert( p.begin(), f(s0) ); k = 1; tt = STEP; - while ( CGAL::compare(tt, s1) == SMALLER ) { - p.push_back( f(tt) ); - k++; - tt = FT(k * k) * STEP; + + // no need to check tt > s0 since we have tt > 0, s0 <= 0 and tt is moving towards +inf + while ( CGAL::compare(tt, s1) == SMALLER ) + { + p.push_back( f(tt) ); + ++k; + tt = FT(k * k) * STEP; } p.push_back( f(s1) ); - } else if ( !(CGAL::is_negative(s0)) && - !(CGAL::is_negative(s1)) ) { - FT tt; - int k; + } + else if ( !(CGAL::is_negative(s0)) && !(CGAL::is_negative(s1)) ) + { + FT tt = s0; + int k = compute_k(tt, STEP); - - p.push_back( f(s0) ); - - tt = s0; - k = compute_k(tt); - - while ( CGAL::compare(tt, s1) == SMALLER ) { - if ( CGAL::compare(tt, s0) != SMALLER ) - p.push_back( f(tt) ); - k++; - tt = FT(k * k) * STEP; + do + { + p.push_back( f(tt) ); + ++k; + tt = FT(k * k) * STEP; } - p.push_back( f(s1) ); - } else { - FT tt; - int k; + while ( CGAL::compare(tt, s0) == LARGER && CGAL::compare(tt, s1) == SMALLER ); p.push_back( f(s1) ); + } + else + { + FT tt = s1; + int k = - compute_k(-tt, STEP); - tt = s1; - k = -compute_k(-tt); - - while ( CGAL::compare(tt, s0) == LARGER ) { - if ( CGAL::compare(tt, s1) != LARGER ) - p.push_back( f(tt) ); - k--; - tt = -FT(k * k) * STEP; + do + { + p.push_back( f(tt) ); + --k; + tt = - FT(k * k) * STEP; } + while ( CGAL::compare(tt, s0) == LARGER && CGAL::compare(tt, s1) == SMALLER ); + p.push_back( f(s0) ); } } + void generate_points(std::vector& p, + const FT STEP = FT(2)) const + { + return generate_points(p, STEP, t(p1), t(p2)); + } template< class Stream > void draw(Stream& W) const diff --git a/Apollonius_graph_2/test/Apollonius_graph_2/test_ag2.cpp b/Apollonius_graph_2/test/Apollonius_graph_2/test_ag2.cpp index 22c23e75145..9b338b30edb 100644 --- a/Apollonius_graph_2/test/Apollonius_graph_2/test_ag2.cpp +++ b/Apollonius_graph_2/test/Apollonius_graph_2/test_ag2.cpp @@ -3,76 +3,31 @@ #include #include -#define DONT_USE_FILTERED_EXACT // choose number type #include -#ifndef DONT_USE_FILTERED_EXACT -# include -#endif typedef double inexact_type; typedef CGAL::MP_Float exact_type; -#ifndef DONT_USE_FILTERED_EXACT -typedef CGAL::Filtered_exact number_t; -#endif - #include -#ifndef DONT_USE_FILTERED_EXACT -typedef CGAL::Simple_cartesian Kernel; -#endif - typedef CGAL::Integral_domain_without_division_tag Method_tag; #include "./include/test.h" - typedef CGAL::Simple_cartesian CK; typedef CGAL::Simple_cartesian EK; - int main() { -#ifndef DONT_USE_FILTERED_EXACT - { - std::ifstream ifs_algo("./data/algo.dat"); + std::ifstream ifs_algo("./data/algo.dat"); + assert( ifs_algo ); - assert( ifs_algo ); - - std::cout << "testing the Apollonius graph class..." << std::flush; - bool algo_ok = - CGAL::test_algo(ifs_algo); - - assert( algo_ok ); - std::cout << " done!" << std::endl; - - ifs_algo.close(); - - std::cout << std::endl; - } -#endif - //------------------------------------------------------------------------ - - { - std::ifstream ifs_algo("./data/algo.dat"); - - assert( ifs_algo ); - - std::cout << "testing the Apollonius graph class" - << " with filtered traits..." << std::flush; - bool algo_ok = - CGAL::test_filtered_traits_algo(ifs_algo); - - assert( algo_ok ); - std::cout << " done!" << std::endl; - - ifs_algo.close(); - - std::cout << std::endl; - } + std::cout << "testing the Apollonius graph class" << " with filtered traits..." << std::flush; + bool algo_ok = CGAL::test_filtered_traits_algo(ifs_algo); + assert( algo_ok ); + std::cout << " done!" << std::endl; return 0; } diff --git a/Apollonius_graph_2/test/Apollonius_graph_2/test_ag_hierarchy_2.cpp b/Apollonius_graph_2/test/Apollonius_graph_2/test_ag_hierarchy_2.cpp index 51baa1a0cab..9bb7f335333 100644 --- a/Apollonius_graph_2/test/Apollonius_graph_2/test_ag_hierarchy_2.cpp +++ b/Apollonius_graph_2/test/Apollonius_graph_2/test_ag_hierarchy_2.cpp @@ -3,79 +3,31 @@ #include #include -#define DNOT_USE_FILTERED_EXACT - // choose number type #include -#ifndef DNOT_USE_FILTERED_EXACT -# include -#endif - typedef double inexact_type; typedef CGAL::MP_Float exact_type; -#ifndef DNOT_USE_FILTERED_EXACT -typedef CGAL::Filtered_exact number_t; -#endif - #include -#ifndef DNOT_USE_FILTERED_EXACT -typedef CGAL::Simple_cartesian K; -#endif - typedef CGAL::Integral_domain_without_division_tag Method_tag; #include "./include/test.h" - typedef CGAL::Simple_cartesian CK; typedef CGAL::Simple_cartesian EK; - int main() { -#ifndef DNOT_USE_FILTERED_EXACT - { - std::ifstream ifs_hierarchy("./data/hierarchy.dat"); + std::ifstream ifs_hierarchy("./data/hierarchy.dat"); + assert( ifs_hierarchy ); - assert( ifs_hierarchy ); + std::cout << "testing the Apollonius graph hierarchy class" << " with filtered traits..." << std::flush; + bool hierarchy_ok = CGAL::test_filtered_traits_hierarchy_algo(ifs_hierarchy); - std::cout << "testing the Apollonius graph hierarchy class..." - << std::flush; - bool hierarchy_ok = - CGAL::test_hierarchy_algo(ifs_hierarchy); - - assert( hierarchy_ok ); - std::cout << " done!" << std::endl; - - ifs_hierarchy.close(); - - std::cout << std::endl; - } -#endif - //------------------------------------------------------------------------ - - { - std::ifstream ifs_hierarchy("./data/hierarchy.dat"); - - assert( ifs_hierarchy ); - - std::cout << "testing the Apollonius graph hierarchy class" - << " with filtered traits..." << std::flush; - bool hierarchy_ok = - CGAL::test_filtered_traits_hierarchy_algo(ifs_hierarchy); - - assert( hierarchy_ok ); - std::cout << " done!" << std::endl; - - ifs_hierarchy.close(); - - std::cout << std::endl; - } + assert( hierarchy_ok ); + std::cout << " done!" << std::endl; return 0; } diff --git a/Apollonius_graph_2/test/Apollonius_graph_2/test_ag_traits_2.cpp b/Apollonius_graph_2/test/Apollonius_graph_2/test_ag_traits_2.cpp index 3739b77cad4..1a8d4781bd9 100644 --- a/Apollonius_graph_2/test/Apollonius_graph_2/test_ag_traits_2.cpp +++ b/Apollonius_graph_2/test/Apollonius_graph_2/test_ag_traits_2.cpp @@ -2,79 +2,33 @@ #include #include -#define DONT_USE_FILTERED_EXACT - // choose number type #include -#ifndef DONT_USE_FILTERED_EXACT -# include -#endif typedef double inexact_type; typedef CGAL::MP_Float exact_type; -#ifndef DONT_USE_FILTERED_EXACT -typedef CGAL::Filtered_exact number_t; -#endif - #include -#ifndef DONT_USE_FILTERED_EXACT -typedef CGAL::Simple_cartesian Kernel; -#endif - typedef CGAL::Integral_domain_without_division_tag Method_tag; #include "./include/test.h" - typedef CGAL::Simple_cartesian CK; typedef CGAL::Simple_cartesian EK; - int main() { -#ifndef DONT_USE_FILTERED_EXACT - { - std::ifstream ifs_traits("./data/traits.dat"); + std::ifstream ifs_traits("./data/traits.dat"); + assert( ifs_traits ); - assert( ifs_traits ); + std::cout << "testing the filtered traits class..." << std::flush; - // bool is_ok = - // CGAL::test_traits(ifs_traits); + CGAL::Filtered_traits_tester test_traits; + bool traits_ok = test_traits(); + assert( traits_ok ); - std::cout << "testing the traits class..." << std::flush; - - CGAL::Traits_tester test_traits; - bool traits_ok = test_traits(); - - assert( traits_ok ); - std::cout << " done!" << std::endl; - - ifs_traits.close(); - - std::cout << std::endl; - } -#endif - //------------------------------------------------------------------------ - - { - std::ifstream ifs_traits("./data/traits.dat"); - - assert( ifs_traits ); - - std::cout << "testing the filtered traits class..." << std::flush; - - CGAL::Filtered_traits_tester test_traits; - bool traits_ok = test_traits(); - - assert( traits_ok ); - std::cout << " done!" << std::endl; - - ifs_traits.close(); - - std::cout << std::endl; - } + std::cout << " done!" << std::endl; return 0; } diff --git a/BGL/doc/BGL/CGAL/HalfedgeDS_face_max_base_with_id.h b/BGL/doc/BGL/CGAL/HalfedgeDS_face_max_base_with_id.h index 446481b9fc4..0006a4332e8 100644 --- a/BGL/doc/BGL/CGAL/HalfedgeDS_face_max_base_with_id.h +++ b/BGL/doc/BGL/CGAL/HalfedgeDS_face_max_base_with_id.h @@ -2,7 +2,7 @@ namespace CGAL { /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices The class `HalfedgeDS_face_max_base_with_id` is a model of the `HalfedgeDSFace` concept. diff --git a/BGL/doc/BGL/CGAL/HalfedgeDS_halfedge_max_base_with_id.h b/BGL/doc/BGL/CGAL/HalfedgeDS_halfedge_max_base_with_id.h index 6e597c7d346..b9d7f4142eb 100644 --- a/BGL/doc/BGL/CGAL/HalfedgeDS_halfedge_max_base_with_id.h +++ b/BGL/doc/BGL/CGAL/HalfedgeDS_halfedge_max_base_with_id.h @@ -2,7 +2,7 @@ namespace CGAL { /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices The class `HalfedgeDS_halfedge_max_base_with_id` is a model of the `HalfedgeDSHalfedge` concept. diff --git a/BGL/doc/BGL/CGAL/HalfedgeDS_vertex_max_base_with_id.h b/BGL/doc/BGL/CGAL/HalfedgeDS_vertex_max_base_with_id.h index 0839d254c8f..565236d880e 100644 --- a/BGL/doc/BGL/CGAL/HalfedgeDS_vertex_max_base_with_id.h +++ b/BGL/doc/BGL/CGAL/HalfedgeDS_vertex_max_base_with_id.h @@ -2,7 +2,7 @@ namespace CGAL { /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices The class `HalfedgeDS_vertex_max_base_with_id` is a model of the `HalfedgeDSVertex` concept. It is diff --git a/BGL/doc/BGL/CGAL/Linear_cell_complex_bgl_min_items.h b/BGL/doc/BGL/CGAL/Linear_cell_complex_bgl_min_items.h index 0c9ab30a613..611ff3cd88b 100644 --- a/BGL/doc/BGL/CGAL/Linear_cell_complex_bgl_min_items.h +++ b/BGL/doc/BGL/CGAL/Linear_cell_complex_bgl_min_items.h @@ -2,7 +2,7 @@ namespace CGAL { /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices The class `Linear_cell_complex_bgl_min_items` defines `void` as the information associated with darts, darts have ids and 0- and 2-attributes are enabled and have ids. diff --git a/BGL/doc/BGL/CGAL/Linear_cell_complex_for_bgl_combinatorial_map_helper.h b/BGL/doc/BGL/CGAL/Linear_cell_complex_for_bgl_combinatorial_map_helper.h index 72ba704077c..8bebd8f9e53 100644 --- a/BGL/doc/BGL/CGAL/Linear_cell_complex_for_bgl_combinatorial_map_helper.h +++ b/BGL/doc/BGL/CGAL/Linear_cell_complex_for_bgl_combinatorial_map_helper.h @@ -2,7 +2,7 @@ namespace CGAL { /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices The class `Linear_cell_complex_for_bgl_combinatorial_map_helper` defines a `CGAL::Linear_cell_complex_for_combinatorial_map` as inner type, named `type`, having `CGAL::Linear_cell_complex_bgl_min_items` as items class. With this item class, no information are associated with darts, darts have ids and 0- and 2-attributes are enabled and have ids. diff --git a/BGL/doc/BGL/CGAL/Polyhedron_items_with_id_3.h b/BGL/doc/BGL/CGAL/Polyhedron_items_with_id_3.h index fdfee46c400..a64795aaa74 100644 --- a/BGL/doc/BGL/CGAL/Polyhedron_items_with_id_3.h +++ b/BGL/doc/BGL/CGAL/Polyhedron_items_with_id_3.h @@ -2,7 +2,7 @@ namespace CGAL { /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices The class `Polyhedron_items_with_id_3` is a model of the `PolyhedronItems_3` concept. It provides definitions for vertices with points, halfedges, @@ -63,7 +63,7 @@ public: /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices Given a `CGAL::Polyhedron_3`, for each simplex type (vertex, halfedge, facet) associates an index from diff --git a/BGL/doc/BGL/CGAL/Triangulation_face_base_with_id_2.h b/BGL/doc/BGL/CGAL/Triangulation_face_base_with_id_2.h index 83e14e58af7..15827d6758b 100644 --- a/BGL/doc/BGL/CGAL/Triangulation_face_base_with_id_2.h +++ b/BGL/doc/BGL/CGAL/Triangulation_face_base_with_id_2.h @@ -1,15 +1,16 @@ namespace CGAL { /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices The class `Triangulation_face_base_with_id_2` is a model of the concept `TriangulationFaceBase_2`, the base face of a -2D-triangulation. It provides an integer field that can be used to +2D-triangulation. It provides an integer field that can be used to index faces for \sc{Bgl} algorithms. Note that the user is in charge of setting indices correctly before -running a graph algorithm. +running a graph algorithm, by calling the function +`CGAL::set_triangulation_ids(Triangulation&)`. \tparam TriangulationTraits_2 is the geometric traits class and must be a model of `TriangulationTraits_2`. @@ -42,4 +43,19 @@ int& id(); /// @} }; /* end Triangulation_face_base_with_id_2 */ + +/// \ingroup BGLGraphExternalIndices +/// +/// This function initializes vertex, edge, and face indices of the triangulation `tr` and must +/// be called prior to using `tr` as a BGL graph in an algorithm that requires +/// vertex, halfedge, edge, or face indices. +/// +/// \tparam Triangulation a 2D triangulation of \cgal, whose combinatorial data structure +/// has been initialized with the vertex and face classes `Triangulation_vertex_base_with_id_2` +/// and `Triangulation_face_base_with_id_2`. +/// +/// \sa the \ref PkgTriangulation2 package +template +void set_triangulation_ids(Triangulation& tr); + } /* end namespace CGAL */ diff --git a/BGL/doc/BGL/CGAL/Triangulation_vertex_base_with_id_2.h b/BGL/doc/BGL/CGAL/Triangulation_vertex_base_with_id_2.h index a93691aa0b4..bc156657b30 100644 --- a/BGL/doc/BGL/CGAL/Triangulation_vertex_base_with_id_2.h +++ b/BGL/doc/BGL/CGAL/Triangulation_vertex_base_with_id_2.h @@ -1,7 +1,7 @@ namespace CGAL { /*! -\ingroup PkgBGLHelper +\ingroup BGLGraphExternalIndices The class `Triangulation_vertex_base_with_id_2` is a model of the concept `TriangulationVertexBase_2`, the base vertex of a @@ -9,7 +9,8 @@ concept `TriangulationVertexBase_2`, the base vertex of a index vertices for \sc{Bgl} algorithms. Note that the user is in charge of setting indices correctly before -running a graph algorithm. +running a graph algorithm, by calling the function +`CGAL::set_triangulation_ids(Triangulation&)`. \tparam TriangulationTraits_2 is the geometric traits class and must be a model of `TriangulationTraits_2`. diff --git a/BGL/doc/BGL/CGAL/boost/graph/properties.h b/BGL/doc/BGL/CGAL/boost/graph/properties.h index cbd4d4f960f..a7416d53eae 100644 --- a/BGL/doc/BGL/CGAL/boost/graph/properties.h +++ b/BGL/doc/BGL/CGAL/boost/graph/properties.h @@ -1,14 +1,9 @@ -/// Boost Namespace -namespace boost { +/// CGAL Namespace +namespace CGAL { /// \ingroup PkgBGLProperties /// @{ -/// The constant `edge_index` is a property tag which identifies the index property of an edge of a \sc{Bgl} -/// Graph. -/// \cgalModels PropertyTag -enum edge_index_t { edge_index}; - /// The constant `vertex_index` is a property tag which identifies the index property of a vertex of a \sc{Bgl} /// Graph. /// \cgalModels PropertyTag @@ -20,13 +15,17 @@ enum vertex_index_t { vertex_index }; /// \cgalModels PropertyTag enum halfedge_index_t { halfedge_index }; +/// The constant `edge_index` is a property tag which identifies the index property of an edge of a \sc{Bgl} +/// Graph. +/// \cgalModels PropertyTag +enum edge_index_t { edge_index }; + /// The constant `face_index` is a property tag which identifies the index property of a face of a `FaceGraph`. /// /// This is a property tag introduced by \cgal. /// \cgalModels PropertyTag enum face_index_t { face_index }; - /// The constant `vertex_point` is a property tag which refers to the geometric embedding property of /// a vertex of a `HalfedgeGraph`. /// @@ -34,12 +33,22 @@ enum face_index_t { face_index }; /// \cgalModels PropertyTag enum vertex_point_t { vertex_point }; - /// @} -} // namespace boost - -namespace CGAL { +/// \ingroup PkgBGLProperties +/// +/// \brief graph_has_property is used to indicate if a model of `HalfedgeGraph` or `FaceGraph` +/// has an internal property associated with the given `PropertyTag`. +/// +/// It inherits from \link Tag_true `CGAL::Tag_true` \endlink if there is a +/// default internal property map for the corresponding property tag and from +/// \link Tag_false `CGAL::Tag_false` \endlink otherwise. +/// +/// \tparam Graph a model of `HalfedgeGraph` or `FaceGraph` +/// \tparam PropertyTag the type of a property tag referring to the property of interest. +/// +template +struct graph_has_property; /// @{ diff --git a/BGL/doc/BGL/NamedParameters.txt b/BGL/doc/BGL/NamedParameters.txt index 56daa128e1b..4536402290b 100644 --- a/BGL/doc/BGL/NamedParameters.txt +++ b/BGL/doc/BGL/NamedParameters.txt @@ -38,38 +38,51 @@ a \cgal point type as value type. \n \cgalNPEnd \cgalNPBegin{vertex_index_map} \anchor BGL_vertex_index_map -is the property map containing the index of each vertex of the input polygon mesh.\n +is the property map associating a unique index to each vertex of a polygon mesh `g`, +between `0` and `num_vertices(g)-1`. +If this parameter is not passed, internal machinery will create and initialize a vertex index +property map, either using the internal property map if it exists or using an external map. The latter +might result in - slightly - worsened performance in case of non-constant complexity for index access.\n Type: a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` as key type and the value type \code typename boost::property_traits::type>::value_type \endcode -Default: \code boost::get(CGAL::vertex_index, pmesh)\endcode +Default: an initialized vertex index property map \cgalNPEnd \cgalNPBegin{halfedge_index_map} \anchor BGL_halfedge_index_map -is the property map containing the index of each halfedge of the input polygon mesh.\n +is the property map associating a unique index to each halfedge of a polygon mesh, +between `0` and `num_halfedges(g)-1`. +If this parameter is not passed, internal machinery will create and initialize a halfedge index +property map, either using the internal property map if it exists or using an external map. The latter +might result in - slightly - worsened performance in case of non-constant complexity for index access.\n Type: a class model of `ReadablePropertyMap` with `boost::graph_traits::%halfedge_descriptor` as key type and the value type: \code typename boost::property_traits::type>::value_type \endcode -Default: \code boost::get(CGAL::halfedge_index, pmesh)\endcode -If this internal property map exists, its values should be initialized. +Default: an initialized halfedge index property map \cgalNPEnd \cgalNPBegin{edge_index_map} \anchor BGL_edge_index_map -is the property map containing the index of each edge of the input polygon mesh.\n +is the property map associating a unique index to each edge of a polygon mesh, +between `0` and `num_edges(g)-1`. +If this parameter is not passed, internal machinery will create and initialize a edge index +property map, either using the internal property map if it exists or using an external map. The latter +might result in - slightly - worsened performance in case of non-constant complexity for index access.\n Type: a class model of `ReadablePropertyMap` with `boost::graph_traits::%edge_descriptor` as key type and the value type: \code typename boost::property_traits::type>::value_type \endcode -Default: \code boost::get(CGAL::edge_index, pmesh)\endcode -If this internal property map exists, its values should be initialized. +Default: an initialized edge index property map \cgalNPEnd \cgalNPBegin{face_index_map} \anchor BGL_face_index_map -is the property map containing the index of each face of the input polygon mesh.\n +is the property map associating a unique index to each face of a polygon mesh, +between `0` and `num_faces(g)-1`. +If this parameter is not passed, internal machinery will create and initialize a face index +property map, either using the internal property map if it exists or using an external map. The latter +might result in - slightly - worsened performance in case of non-constant complexity for index access.\n Type: a class model of `ReadablePropertyMap` with `boost::graph_traits::%face_descriptor` as key type and the value type: \code typename boost::property_traits::type>::value_type \endcode -Default: \code boost::get(CGAL::face_index, pmesh)\endcode -If this internal property map exists, its values should be initialized. +Default: an initialized face index property map \cgalNPEnd \cgalNPBegin{edge_is_constrained_map} \anchor BGL_edge_is_constrained_map diff --git a/BGL/doc/BGL/PackageDescription.txt b/BGL/doc/BGL/PackageDescription.txt index 4675f24d7d2..ec9014139a3 100644 --- a/BGL/doc/BGL/PackageDescription.txt +++ b/BGL/doc/BGL/PackageDescription.txt @@ -443,7 +443,7 @@ the requirement for traversal of all faces in a graph. /// \defgroup PkgBGLPropertiesDynamic Dynamic Properties /// \ingroup PkgBGLRef -/// \defgroup PkgBGLHelper Helper Classes +/// \defgroup PkgBGLGraphExternalIndices External Indices /// \ingroup PkgBGLRef /// \defgroup PkgBGLHelperFct Helper Functions @@ -473,8 +473,11 @@ The dynamic property tags enable to associate information to simplices of a `Fac */ /*! -\addtogroup PkgBGLHelper -Several classes that enable to store ids in vertices/halfedges/faces of a `CGAL::Polyhedron_3`, as well as adapters such as `CGAL::Dual`. +\addtogroup BGLGraphExternalIndices +A number of BGL and \cgal algorithms require the graph to have (initialized) integer-like indices +for its vertices, edges, or faces. However, not all graphs intrinsically offer a natural way +to attach a unique ID to each element. The following classes and functions paliate this +by attaching and initializing external IDs to the elements of the graph. */ /*! @@ -575,25 +578,25 @@ Methods to read and write graphs. - `MutableFaceGraph` \cgalCRPSection{Properties} -- `boost::vertex_index_t` -- `boost::halfedge_index_t` -- `boost::edge_index_t` -- `boost::face_index_t` -- `boost::vertex_point_t` +- `CGAL::vertex_index_t` +- `CGAL::halfedge_index_t` +- `CGAL::edge_index_t` +- `CGAL::face_index_t` +- `CGAL::vertex_point_t` \cgalCRPSection{%CGAL Classes Adapted for the Graph API} -Different \cgal types have been adapted as graphs for the \sc{Bgl}. All +A number of \cgal structures have been adapted as graphs for the \sc{Bgl}. All adapted types are listed here. The pages document which concepts they model, the properties they support, and any possible caveats that a user might encounter. -- \link BGLSMGT `boost::graph_traits< CGAL::Surface_mesh

>` \endlink -- \link BGLPolyGT `boost::graph_traits< CGAL::Polyhedron_3 >` \endlink -- \link BGLLCCGT `boost::graph_traits< CGAL::Linear_cell_complex_for_combinatorial_map<...> >` \endlink -- \link BGLSeam_meshGT `boost::graph_traits< CGAL::Seam_mesh >` \endlink -- \link BGLT2GT `boost::graph_traits< CGAL::Triangulation_2 >` \endlink -- \link BGLArgtGT `boost::graph_traits< CGAL::Arrangement_2 >` \endlink +- \link BGLSMGT `boost::graph_traits >` \endlink +- \link BGLPolyGT `boost::graph_traits >` \endlink +- \link BGLLCCGT `boost::graph_traits >` \endlink +- \link BGLSeam_meshGT `boost::graph_traits >` \endlink +- \link BGLT2GT `boost::graph_traits >` \endlink and other 2D triangulations +- \link BGLArgtGT `boost::graph_traits >` \endlink - \link BGLOMPAK `boost::graph_traits >` \endlink - \link BGLOMTMAK `boost::graph_traits >` \endlink @@ -643,6 +646,8 @@ user might encounter. - `CGAL::clear()` - `CGAL::copy_face_graph()` +- `CGAL::set_triangulation_ids()` + \cgalCRPSection{Iterators} - `CGAL::Halfedge_around_source_iterator` - `CGAL::Halfedge_around_target_iterator` diff --git a/BGL/examples/BGL_LCC/copy_lcc.cpp b/BGL/examples/BGL_LCC/copy_lcc.cpp index d47c0216fbb..ecc43fefc59 100644 --- a/BGL/examples/BGL_LCC/copy_lcc.cpp +++ b/BGL/examples/BGL_LCC/copy_lcc.cpp @@ -55,6 +55,7 @@ int main(int argc, char* argv[]) CGAL::copy_face_graph(T1, S, CGAL::parameters::vertex_to_vertex_output_iterator(std::inserter(v2v, v2v.end())) .halfedge_to_halfedge_output_iterator(std::inserter(h2h, h2h.end()))); std::ofstream out("reverse.off"); + out.precision(17); out << S; } return 0; diff --git a/BGL/examples/BGL_polyhedron_3/copy_polyhedron.cpp b/BGL/examples/BGL_polyhedron_3/copy_polyhedron.cpp index 76aa1235c54..3f9e7b76bef 100644 --- a/BGL/examples/BGL_polyhedron_3/copy_polyhedron.cpp +++ b/BGL/examples/BGL_polyhedron_3/copy_polyhedron.cpp @@ -43,6 +43,7 @@ int main(int argc, char* argv[]) { CGAL::copy_face_graph(S, T1); std::ofstream out("sm.off"); + out.precision(17); out << T1; } @@ -81,6 +82,7 @@ int main(int argc, char* argv[]) boost::unordered_map f2f; CGAL::copy_face_graph(T1, S, std::inserter(v2v, v2v.end()), std::inserter(h2h, h2h.end())); std::ofstream out("reverse.off"); + out.precision(17); out << S; CGAL::copy_face_graph(T1, S, CGAL::parameters::vertex_to_vertex_map(boost::make_assoc_property_map(v2v)) .halfedge_to_halfedge_output_iterator(std::inserter(h2h, h2h.end())) diff --git a/BGL/examples/BGL_surface_mesh/write_inp.cpp b/BGL/examples/BGL_surface_mesh/write_inp.cpp index fce8f932b11..ba9e3545bb5 100644 --- a/BGL/examples/BGL_surface_mesh/write_inp.cpp +++ b/BGL/examples/BGL_surface_mesh/write_inp.cpp @@ -20,6 +20,7 @@ int main() CGAL::make_quad(Point(0,0,1), Point(1,0,1),Point(1,1,1),Point(0,1,1), sm); std::ofstream out("out.inp"); + out.precision(17); CGAL::write_inp(out, sm, "out.inp", "S4R"); return 0; } diff --git a/BGL/include/CGAL/boost/graph/Euler_operations.h b/BGL/include/CGAL/boost/graph/Euler_operations.h index 12e6ed25252..f362aef6e17 100644 --- a/BGL/include/CGAL/boost/graph/Euler_operations.h +++ b/BGL/include/CGAL/boost/graph/Euler_operations.h @@ -702,19 +702,35 @@ add_face(const VertexRange& vr, Graph& g) break; case 3: // both are new - if (halfedge(v, g) == boost::graph_traits::null_halfedge()) { - set_halfedge(v, outer_prev, g); - next_cache.push_back(NextCacheEntry(outer_prev, outer_next)); + // try to pick a border halfedge with v as target + halfedge_descriptor hv = halfedge(v, g); + if (hv != boost::graph_traits::null_halfedge() && !is_border(hv, g)) + { + for(halfedge_descriptor h_around_v : halfedges_around_target(hv, g)) + if (is_border(h_around_v, g)) + { + hv = h_around_v; + break; + } + if (!is_border(hv, g)) + hv = boost::graph_traits::null_halfedge(); + } + + if (hv == boost::graph_traits::null_halfedge()) + { + set_halfedge(v, outer_prev, g); + next_cache.push_back(NextCacheEntry(outer_prev, outer_next)); + } + else + { + border_prev = hv; + border_next = next(border_prev, g); + next_cache.push_back(NextCacheEntry(border_prev, outer_next)); + next_cache.push_back(NextCacheEntry(outer_prev, border_next)); + } + break; } - else - { - border_prev = halfedge(v, g); - border_next = next(border_prev, g); - next_cache.push_back(NextCacheEntry(border_prev, outer_next)); - next_cache.push_back(NextCacheEntry(outer_prev, border_next)); - } - break; } // set inner link @@ -1323,7 +1339,7 @@ flip_edge(typename boost::graph_traits::halfedge_descriptor h, template bool does_satisfy_link_condition(typename boost::graph_traits::edge_descriptor e, - Graph& g) + const Graph& g) { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; @@ -1423,7 +1439,7 @@ does_satisfy_link_condition(typename boost::graph_traits::edge_descriptor template bool satisfies_link_condition(typename boost::graph_traits::edge_descriptor e, - Graph& g) + const Graph& g) { return does_satisfy_link_condition(e, g); } diff --git a/BGL/include/CGAL/boost/graph/Face_filtered_graph.h b/BGL/include/CGAL/boost/graph/Face_filtered_graph.h index ffd943fb9c4..875eb7f3e73 100644 --- a/BGL/include/CGAL/boost/graph/Face_filtered_graph.h +++ b/BGL/include/CGAL/boost/graph/Face_filtered_graph.h @@ -16,23 +16,24 @@ #include #include #include +#include #include -#include -#include -#include -#include #include -#include +#include +#include + #include +#include +#include #include +#include #ifdef DOXYGEN_RUNNING #define CGAL_BGL_NP_TEMPLATE_PARAMETERS NamedParameters #define CGAL_BGL_NP_CLASS NamedParameters #endif -namespace CGAL -{ +namespace CGAL { /*! * \ingroup PkgBGLAdaptors @@ -62,18 +63,18 @@ namespace CGAL * missing if the default is fine. * * \tparam Graph must be a model of a `FaceListGraph`, `HalfedgeListGraph`, and \bgllink{VertexListGraph}. - * \tparam FIMap a model of `ReadablePropertyMap` with `face_descriptor` as key and `graph_traits::%faces_size_type` as value - * \tparam VIMap a model of `ReadablePropertyMap` with `vertex_descriptor` as key and `graph_traits::%vertices_size_type` as value - * \tparam HIMap a model of `ReadablePropertyMap` with `halfedge_descriptor` as key and `graph_traits::%halfedges_size_type` as value + * \tparam FIMap a model of `ReadablePropertyMap` with `graph_traits::%face_descriptor` as key and `graph_traits::%faces_size_type` as value + * \tparam VIMap a model of `ReadablePropertyMap` with `graph_traits::%vertex_descriptor` as key and `graph_traits::%vertices_size_type` as value + * \tparam HIMap a model of `ReadablePropertyMap` with `graph_traits::%halfedge_descriptor` as key and `graph_traits::%halfedges_size_type` as value * * \cgalModels `FaceListGraph` * \cgalModels `HalfedgeListGraph` * \cgalModels \bgllink{VertexListGraph} */ template::type, - typename VIMap = typename boost::property_map::type, - typename HIMap = typename boost::property_map::type> + typename FIMap = Default, + typename VIMap = Default, + typename HIMap = Default> struct Face_filtered_graph { typedef boost::graph_traits gt; @@ -93,10 +94,15 @@ struct Face_filtered_graph #endif // non documented types - typedef typename boost::property_traits< FIMap >::value_type face_index_type; - typedef typename boost::property_traits< VIMap >::value_type vertex_index_type; - typedef typename boost::property_traits< HIMap >::value_type halfedge_index_type; - typedef Face_filtered_graph Self; + typedef typename Default::Get::const_type>::type FIM; + typedef typename Default::Get::const_type>::type VIM; + typedef typename Default::Get::const_type>::type HIM; + + typedef typename boost::property_traits::value_type face_index_type; + typedef typename boost::property_traits::value_type vertex_index_type; + typedef typename boost::property_traits::value_type halfedge_index_type; + + typedef Face_filtered_graph Self; /*! * \brief Constructor where the set of selected faces is specified as a range of patch ids. @@ -115,31 +121,31 @@ struct Face_filtered_graph * * \cgalNamedParamsBegin * \cgalParamBegin{face_index_map} - * a property map containing an index for each face initialized from 0 to `num_vertices(graph)` + * a property map containing for each face of `graph` a unique index between `0` and `num_faces(graph)-1` * \cgalParamEnd * \cgalParamBegin{vertex_index_map} - * a property map containing an index for each vertex initialized 0 to `num_vertices(graph)` + * a property map containing for each vertex of `graph` a unique index between `0` and `num_vertices(graph)-1` * \cgalParamEnd * \cgalParamBegin{halfedge_index_map} - * a property map containing an index for each halfedge initialized 0 to `num_halfedges(graph)` + * a property map containing for each halfedge of `graph` a unique index between `0` and `num_halfedges(graph)-1` * \cgalParamEnd * \cgalNamedParamsEnd */ template Face_filtered_graph(const Graph& graph, const FacePatchIndexRange& selected_face_patch_indices, - FacePatchIndexMap face_patch_index_map, - const CGAL_BGL_NP_CLASS& np - #ifndef DOXYGEN_RUNNING - , typename boost::enable_if< - typename boost::has_range_const_iterator::type - >::type* = 0 - #endif - ) - : _graph(const_cast(graph)) - , fimap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), get_const_property_map(face_index, graph))) - , vimap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_index), get_const_property_map(boost::vertex_index, graph))) - , himap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::halfedge_index), get_const_property_map(halfedge_index, graph))) + FacePatchIndexMap face_patch_index_map, + const CGAL_BGL_NP_CLASS& np +#ifndef DOXYGEN_RUNNING + , typename boost::enable_if< + typename boost::has_range_const_iterator::type + >::type* = 0 +#endif + ) + : _graph(const_cast(graph)), + fimap(CGAL::get_initialized_face_index_map(graph, np)), + vimap(CGAL::get_initialized_vertex_index_map(graph, np)), + himap(CGAL::get_initialized_halfedge_index_map(graph, np)) { set_selected_faces(selected_face_patch_indices, face_patch_index_map); } @@ -152,10 +158,10 @@ struct Face_filtered_graph typename boost::has_range_const_iterator::type >::type* = 0 ) - : _graph(const_cast(graph)) - , fimap(get(CGAL::face_index, graph)) - , vimap(get(boost::vertex_index, graph)) - , himap(get(CGAL::halfedge_index, graph)) + : _graph(const_cast(graph)), + fimap(CGAL::get_initialized_face_index_map(graph)), + vimap(CGAL::get_initialized_vertex_index_map(graph)), + himap(CGAL::get_initialized_halfedge_index_map(graph)) { set_selected_faces(selected_face_patch_indices, face_patch_index_map); } @@ -175,38 +181,37 @@ struct Face_filtered_graph * * \cgalNamedParamsBegin * \cgalParamBegin{face_index_map} - * a property map containing an index for each face initialized from 0 to `num_vertices(graph)` + * a property map containing for each face of `graph` a unique index between `0` and `num_faces(graph)-1` * \cgalParamEnd * \cgalParamBegin{vertex_index_map} - * a property map containing an index for each vertex initialized 0 to `num_vertices(graph)` + * a property map containing for each vertex of `graph` a unique index between `0` and `num_vertices(graph)-1` * \cgalParamEnd * \cgalParamBegin{halfedge_index_map} - * a property map containing an index for each halfedge initialized 0 to `num_halfedges(graph)` + * a property map containing for each halfedge of `graph` a unique index between `0` and `num_halfedges(graph)-1` * \cgalParamEnd * \cgalNamedParamsEnd */ template Face_filtered_graph(const Graph& graph, - typename boost::property_traits::value_type selected_face_patch_index, - FacePatchIndexMap face_patch_index_map, - const CGAL_BGL_NP_CLASS& np - ) - : _graph(const_cast(graph)) - , fimap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), get_const_property_map(face_index, graph))) - , vimap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_index), get_const_property_map(boost::vertex_index, graph))) - , himap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::halfedge_index), get_const_property_map(halfedge_index, graph))) + typename boost::property_traits::value_type selected_face_patch_index, + FacePatchIndexMap face_patch_index_map, + const CGAL_BGL_NP_CLASS& np) + : _graph(const_cast(graph)), + fimap(CGAL::get_initialized_face_index_map(graph, np)), + vimap(CGAL::get_initialized_vertex_index_map(graph, np)), + himap(CGAL::get_initialized_halfedge_index_map(graph, np)) { set_selected_faces(selected_face_patch_index, face_patch_index_map); } template Face_filtered_graph(const Graph& graph, - typename boost::property_traits::value_type pid, - FacePatchIndexMap face_patch_index_map) - : _graph(const_cast(graph)) - , fimap(get(CGAL::face_index, graph)) - , vimap(get(boost::vertex_index, graph)) - , himap(get(CGAL::halfedge_index, graph)) + typename boost::property_traits::value_type pid, + FacePatchIndexMap face_patch_index_map) + : _graph(const_cast(graph)), + fimap(CGAL::get_initialized_face_index_map(graph)), + vimap(CGAL::get_initialized_vertex_index_map(graph)), + himap(CGAL::get_initialized_halfedge_index_map(graph)) { set_selected_faces(pid, face_patch_index_map); } @@ -236,10 +241,10 @@ struct Face_filtered_graph Face_filtered_graph(const Graph& graph, const FaceRange& selected_faces, const CGAL_BGL_NP_CLASS& np) - : _graph(const_cast(graph)) - , fimap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), get_const_property_map(face_index, graph))) - , vimap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_index), get_const_property_map(boost::vertex_index, graph))) - , himap(parameters::choose_parameter(parameters::get_parameter(np, internal_np::halfedge_index), get_const_property_map(halfedge_index, graph))) + : _graph(const_cast(graph)), + fimap(CGAL::get_initialized_face_index_map(graph, np)), + vimap(CGAL::get_initialized_vertex_index_map(graph, np)), + himap(CGAL::get_initialized_halfedge_index_map(graph, np)) { set_selected_faces(selected_faces); } @@ -247,10 +252,10 @@ struct Face_filtered_graph template Face_filtered_graph(const Graph& graph, const FaceRange& selected_faces) - : _graph(const_cast(graph)) - , fimap(get(CGAL::face_index, graph)) - , vimap(get(boost::vertex_index, graph)) - , himap(get(CGAL::halfedge_index, graph)) + : _graph(const_cast(graph)), + fimap(CGAL::get_initialized_face_index_map(graph)), + vimap(CGAL::get_initialized_vertex_index_map(graph)), + himap(CGAL::get_initialized_halfedge_index_map(graph)) { set_selected_faces(selected_faces); } @@ -293,12 +298,12 @@ struct Face_filtered_graph template void set_selected_faces(const FacePatchIndexRange& selected_face_patch_indices, FacePatchIndexMap face_patch_index_map - #ifndef DOXYGEN_RUNNING +#ifndef DOXYGEN_RUNNING , typename boost::enable_if< typename boost::has_range_const_iterator::type >::type* = 0 - #endif - ) +#endif + ) { face_indices.clear(); vertex_indices.clear(); @@ -407,7 +412,7 @@ struct Face_filtered_graph return selected_halfedges.count(); } - Property_map_binder< FIMap, typename Pointer_property_map< typename boost::property_traits< FIMap >::value_type >::type > + Property_map_binder::value_type>::type> get_face_index_map() const { if (face_indices.empty()) @@ -422,7 +427,7 @@ struct Face_filtered_graph return bind_property_maps(fimap, make_property_map(face_indices) ); } - Property_map_binder< VIMap, typename Pointer_property_map< typename boost::property_traits< VIMap >::value_type >::type > + Property_map_binder::value_type>::type> get_vertex_index_map() const { if (vertex_indices.empty()) @@ -437,7 +442,7 @@ struct Face_filtered_graph return bind_property_maps(vimap, make_property_map(vertex_indices) ); } - Property_map_binder< HIMap, typename Pointer_property_map< typename boost::property_traits< HIMap >::value_type >::type > + Property_map_binder::value_type >::type> get_halfedge_index_map() const { if (halfedge_indices.empty()) @@ -510,9 +515,9 @@ struct Face_filtered_graph private: Graph& _graph; - FIMap fimap; - VIMap vimap; - HIMap himap; + FIM fimap; + VIM vimap; + HIM himap; boost::dynamic_bitset<> selected_faces; boost::dynamic_bitset<> selected_vertices; boost::dynamic_bitset<> selected_halfedges; @@ -1142,38 +1147,40 @@ CGAL_FILTERED_FACE_GRAPH_DYNAMIC_PMAP_SPECIALIZATION(dynamic_face_property_t) #undef CGAL_FILTERED_FACE_GRAPH_DYNAMIC_PMAP_SPECIALIZATION - - //specializations for indices -template -struct property_map, CGAL::face_index_t>{ - typedef typename CGAL::Property_map_binder< FIMap, - typename CGAL::Pointer_property_map< typename boost::property_traits< FIMap >::value_type >::type > type; - typedef type const_type; +template +struct property_map, CGAL::face_index_t> +{ + typedef typename CGAL::Face_filtered_graph::FIM FIM; + typedef typename CGAL::Property_map_binder::value_type>::type> type; + typedef type const_type; +}; + +template +struct property_map, boost::vertex_index_t> +{ + typedef typename CGAL::Face_filtered_graph::VIM VIM; + typedef typename CGAL::Property_map_binder::value_type>::type> type; + typedef type const_type; }; template -struct property_map, boost::vertex_index_t>{ - typedef typename CGAL::Property_map_binder< VIMap, - typename CGAL::Pointer_property_map< typename boost::property_traits< VIMap >::value_type >::type > type; - typedef type const_type; +struct property_map, CGAL::halfedge_index_t> +{ + typedef typename CGAL::Face_filtered_graph::HIM HIM; + typedef typename CGAL::Property_map_binder::value_type>::type> type; + typedef type const_type; }; -template +} // namespace boost -struct property_map, CGAL::halfedge_index_t>{ - typedef typename CGAL::Property_map_binder< HIMap, - typename CGAL::Pointer_property_map< typename boost::property_traits< HIMap >::value_type >::type > type; - typedef type const_type; -}; -}// namespace boost #endif // CGAL_BOOST_GRAPH_FACE_FILTERED_GRAPH_H diff --git a/BGL/include/CGAL/boost/graph/METIS/partition_dual_graph.h b/BGL/include/CGAL/boost/graph/METIS/partition_dual_graph.h index 50c0bcf7e37..d11a426b5e1 100644 --- a/BGL/include/CGAL/boost/graph/METIS/partition_dual_graph.h +++ b/BGL/include/CGAL/boost/graph/METIS/partition_dual_graph.h @@ -42,17 +42,14 @@ void partition_dual_graph(const TriangleMesh& tm, CGAL_precondition(CGAL::is_triangle_mesh(tm)); CGAL_precondition_msg(nparts > 1, ("Partitioning requires a number of parts > 1")); - using parameters::choose_parameter; using parameters::get_parameter; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_iterator face_iterator; - // vertex index map - typedef typename CGAL::GetVertexIndexMap::type Indices; - Indices indices = choose_parameter(get_parameter(np, internal_np::vertex_index), - get_const_property_map(boost::vertex_index, tm)); + typedef typename CGAL::GetInitializedVertexIndexMap::type Indices; + Indices indices = CGAL::get_initialized_vertex_index_map(tm, np); idx_t nn = static_cast(num_vertices(tm)); idx_t ne = static_cast(num_faces(tm)); @@ -136,9 +133,6 @@ void partition_dual_graph(const TriangleMesh& tm, int nparts, /// based on the mesh's dual graph. The resulting partition is stored in the vertex and/or face /// property maps that are passed as parameters using \ref bgl_namedparameters "Named Parameters". /// -/// Property map for `CGAL::vertex_index_t` should be either available -/// as an internal property map to `tm` or provided as \ref bgl_namedparameters "Named Parameters". -/// /// \param tm a triangle mesh /// \param nparts the number of parts in the final partition /// \param np optional \ref bgl_namedparameters "Named Parameters" described below @@ -148,7 +142,7 @@ void partition_dual_graph(const TriangleMesh& tm, int nparts, /// /// \cgalNamedParamsBegin /// \cgalParamBegin{vertex_index_map} -/// is a property map containing the index of each vertex of `tm` intialized from `0` to `num_vertices(tm)-1`. +/// is a property map containing for each vertex of `tm` a unique index between `0` and `num_vertices(tm)-1`. /// \cgalParamEnd /// \cgalParamBegin{METIS_options} /// is a parameter used in to pass options to the METIS mesh diff --git a/BGL/include/CGAL/boost/graph/METIS/partition_graph.h b/BGL/include/CGAL/boost/graph/METIS/partition_graph.h index ec60ecbc11a..4ef813efcc6 100644 --- a/BGL/include/CGAL/boost/graph/METIS/partition_graph.h +++ b/BGL/include/CGAL/boost/graph/METIS/partition_graph.h @@ -77,17 +77,14 @@ void partition_graph(const TriangleMesh& tm, CGAL_precondition(CGAL::is_triangle_mesh(tm)); CGAL_precondition_msg(nparts > 1, ("Partitioning requires a number of parts > 1")); - using parameters::choose_parameter; using parameters::get_parameter; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_iterator face_iterator; - //Vertex index map - typedef typename CGAL::GetVertexIndexMap::type Indices; - Indices indices = choose_parameter(get_parameter(np, internal_np::vertex_index), - get_const_property_map(boost::vertex_index, tm)); + typedef typename CGAL::GetInitializedVertexIndexMap::type Indices; + Indices indices = CGAL::get_initialized_vertex_index_map(tm, np); idx_t nn = static_cast(num_vertices(tm)); idx_t ne = static_cast(num_faces(tm)); @@ -168,9 +165,6 @@ void partition_graph(const TriangleMesh& tm, int nparts, /// mesh's nodal graph. The resulting partition is stored in the vertex and/or face /// property maps that are passed as parameters using \ref bgl_namedparameters "Named Parameters". /// -/// Property map for `CGAL::vertex_index_t` should be either available -/// as an internal property map to `tm` or provided as \ref bgl_namedparameters "Named Parameters". -/// /// \param tm a triangle mesh /// \param nparts the number of parts in the final partition /// \param np optional \ref bgl_namedparameters "Named Parameters" described below @@ -180,7 +174,7 @@ void partition_graph(const TriangleMesh& tm, int nparts, /// /// \cgalNamedParamsBegin /// \cgalParamBegin{vertex_index_map} -/// is a property map containing the index of each vertex of `tm` intialized from `0` to `num_vertices(tm)-1`. +/// is a property map containing for each vertex of `tm` a unique index between `0` and `num_vertices(tm)-1`. /// \cgalParamEnd /// \cgalParamBegin{METIS_options} /// is a parameter used in to pass options to the METIS mesh diff --git a/BGL/include/CGAL/boost/graph/Named_function_parameters.h b/BGL/include/CGAL/boost/graph/Named_function_parameters.h index 66bc5c18b99..bac4f7885bd 100644 --- a/BGL/include/CGAL/boost/graph/Named_function_parameters.h +++ b/BGL/include/CGAL/boost/graph/Named_function_parameters.h @@ -194,6 +194,20 @@ get_parameter(const Named_function_parameters& np, Query_tag tag) return internal_np::get_parameter_impl(static_cast&>(np), tag); } +// single parameter so that we can avoid a default construction +template +D choose_parameter(const internal_np::Param_not_found&) +{ + return D(); +} + +template +const T& choose_parameter(const T& t) +{ + return t; +} + +// Two parameters, non-trivial default value template D choose_parameter(const internal_np::Param_not_found&, const D& d) { @@ -201,8 +215,7 @@ D choose_parameter(const internal_np::Param_not_found&, const D& d) } template -const T& -choose_parameter(const T& t, const D&) +const T& choose_parameter(const T& t, const D&) { return t; } diff --git a/BGL/include/CGAL/boost/graph/Seam_mesh.h b/BGL/include/CGAL/boost/graph/Seam_mesh.h index 33a995dba43..07ed312307f 100644 --- a/BGL/include/CGAL/boost/graph/Seam_mesh.h +++ b/BGL/include/CGAL/boost/graph/Seam_mesh.h @@ -124,8 +124,8 @@ public: /// The type for the objects used to identify halfedges in the underlying mesh. typedef typename boost::graph_traits::halfedge_descriptor TM_halfedge_descriptor; - /// The type for the iterators that traverse through the complete halfedge set of the underlying mesh. - typedef typename boost::graph_traits::halfedge_iterator TM_halfedge_iterator; + /// The type for the iterators that traverse through the complete halfedge set of the underlying mesh. + typedef typename boost::graph_traits::halfedge_iterator TM_halfedge_iterator; /// The type for the objects used to identify edges in the underlying mesh. typedef typename boost::graph_traits::edge_descriptor TM_edge_descriptor; @@ -439,6 +439,11 @@ public: { return ! (e1 == e2); } + + friend std::size_t hash_value(const edge_descriptor& ed) + { + return hash_value((std::min)(ed.hd, ed.mesh_->opposite(ed.hd))); + } }; #ifndef DOXYGEN_RUNNING diff --git a/BGL/include/CGAL/boost/graph/copy_face_graph.h b/BGL/include/CGAL/boost/graph/copy_face_graph.h index 5eafa161533..84ec4184dfb 100644 --- a/BGL/include/CGAL/boost/graph/copy_face_graph.h +++ b/BGL/include/CGAL/boost/graph/copy_face_graph.h @@ -199,13 +199,8 @@ void copy_face_graph(const SourceMesh& sm, TargetMesh& tm, typedef typename boost::graph_traits::halfedge_descriptor tm_halfedge_descriptor; std::vector hedges(num_halfedges(sm)); - // init halfedge index map - /// \TODO shall we keep that? - helpers::init_halfedge_indices(const_cast(sm), - get(boost::halfedge_index, sm)); - copy_face_graph_impl(sm, tm, - bind_property_maps(get(boost::halfedge_index, sm), + bind_property_maps(get_initialized_halfedge_index_map(sm), make_property_map(hedges)), v2v, h2h, f2f, sm_vpm, tm_vpm); @@ -333,18 +328,19 @@ void copy_face_graph(const SourceMesh& sm, TargetMesh& tm, { using parameters::choose_parameter; using parameters::get_parameter; + internal::copy_face_graph(sm, tm, CGAL::graph_has_property(), choose_parameter(get_parameter(np1, internal_np::vertex_to_vertex_output_iterator), - impl::make_functor(get_parameter(np1, internal_np::vertex_to_vertex_map))), + impl::make_functor(get_parameter(np1, internal_np::vertex_to_vertex_map))), choose_parameter(get_parameter(np1, internal_np::halfedge_to_halfedge_output_iterator), - impl::make_functor(get_parameter(np1, internal_np::halfedge_to_halfedge_map))), + impl::make_functor(get_parameter(np1, internal_np::halfedge_to_halfedge_map))), choose_parameter(get_parameter(np1, internal_np::face_to_face_output_iterator), - impl::make_functor(get_parameter(np1, internal_np::face_to_face_map))), + impl::make_functor(get_parameter(np1, internal_np::face_to_face_map))), choose_parameter(get_parameter(np1, internal_np::vertex_point), - get(vertex_point, sm)), + get(vertex_point, sm)), choose_parameter(get_parameter(np2, internal_np::vertex_point), - get(vertex_point, tm))); + get(vertex_point, tm))); } template diff --git a/BGL/include/CGAL/boost/graph/internal/initialized_index_maps_helpers.h b/BGL/include/CGAL/boost/graph/internal/initialized_index_maps_helpers.h new file mode 100644 index 00000000000..e392ff064a0 --- /dev/null +++ b/BGL/include/CGAL/boost/graph/internal/initialized_index_maps_helpers.h @@ -0,0 +1,307 @@ +// Copyright (c) 2020 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) : Mael Rouxel-Labbé +// Maxime Gimeno + +#ifndef CGAL_BOOST_GRAPH_INITIALIZED_INTERNAL_INDEX_MAPS_HELPERS +#define CGAL_BOOST_GRAPH_INITIALIZED_INTERNAL_INDEX_MAPS_HELPERS + +#include +#include +#include +#include +#include + +#include +#include + +namespace CGAL { +namespace BGL { +namespace internal { + +// Check that an index map has been correctly initialized +template +bool is_index_map_valid(IndexMap idmap, + const std::size_t num_simplices, + const DescriptorRange& range) +{ + typedef typename boost::property_traits::value_type Id_type; + + Id_type max_id = static_cast(num_simplices); + std::vector indices(max_id); + for(const auto& d : range) + { + const Id_type id = get(idmap, d); + if(id >= 0 && id < max_id && !indices[id]) + { + indices[id] = true; + } + else + { +#ifdef CGAL_BGL_INDEX_MAP_DEBUG + std::cerr << "Invalid ID: " << id << " num_simplices: " << num_simplices << std::endl; +#endif + return false; + } + } + + return true; +} + +template +bool is_index_map_valid(const CGAL::internal_np::vertex_index_t, VertexIndexPropertyMap vertex_index_map, const Graph& g) +{ + return is_index_map_valid(vertex_index_map, num_vertices(g), vertices(g)); +} + +template +bool is_index_map_valid(const CGAL::internal_np::halfedge_index_t, HalfedgeIndexPropertyMap halfedge_index_map, const Graph& g) +{ + return is_index_map_valid(halfedge_index_map, num_halfedges(g), halfedges(g)); +} + +template +bool is_index_map_valid(const CGAL::internal_np::edge_index_t, EdgeIndexPropertyMap edge_index_map, const Graph& g) +{ + return is_index_map_valid(edge_index_map, num_edges(g), edges(g)); +} + +template +bool is_index_map_valid(const CGAL::internal_np::face_index_t, FaceIndexPropertyMap face_index_map, const Graph& g) +{ + return is_index_map_valid(face_index_map, num_faces(g), faces(g)); +} + +template +void initialize_index_map(const PropertyTag, IndexPropertyMap, const Graph&) +{ + // Unknown parameter; should never be here. + CGAL_assertion(false); +} + +template ::value> +struct Index_map_initializer +{ + void operator()(const CGAL::internal_np::vertex_index_t, IndexPropertyMap vertex_index_map, const Graph& g) + { + typename boost::property_traits::value_type i = 0; + for(typename boost::graph_traits::vertex_descriptor vd : vertices(g)) + put(vertex_index_map, vd, i++); + } + + void operator()(const CGAL::internal_np::halfedge_index_t, IndexPropertyMap halfedge_index_map, const Graph& g) + { + typename boost::property_traits::value_type i = 0; + for(typename boost::graph_traits::halfedge_descriptor hd : halfedges(g)) + put(halfedge_index_map, hd, i++); + } + + void operator()(const CGAL::internal_np::edge_index_t, IndexPropertyMap edge_index_map, const Graph& g) + { + typename boost::property_traits::value_type i = 0; + for(typename boost::graph_traits::edge_descriptor ed : edges(g)) + put(edge_index_map, ed, i++); + } + + void operator()(const CGAL::internal_np::face_index_t, IndexPropertyMap face_index_map, const Graph& g) + { + typename boost::property_traits::value_type i = 0; + for(typename boost::graph_traits::face_descriptor fd : faces(g)) + put(face_index_map, fd, i++); + } + + template + void operator()(const PropertyTag, IndexPropertyMap, const Graph&) + { + // Unknown parameter; should never be here. + CGAL_assertion(false); + } +}; + +template +struct Index_map_initializer +{ + template + void operator()(const PropertyTag, IndexPropertyMap, const Graph&) + { + // The property map is not writable; should never be here. + CGAL_assertion_msg(false, "You are trying to initialize a non-writable property map"); + } +}; + +// Just for convenience, define the following functions: +// +// BGL::internal::initialize_vertex_index_map() +// BGL::internal::initialize_halfedge_index_map() +// BGL::internal::initialize_edge_index_map() +// BGL::internal::initialize_face_index_map() + +#define CGAL_DEF_INITIALIZE_ID_MAP_FUNCTION(TYPE) \ +template \ +void initialize_##TYPE##_index_map(WritableIndexPropertyMap index_map, \ + const Graph& g) \ +{ \ + Index_map_initializer initializer; \ + initializer(CGAL::internal_np::TYPE##_index_t{}, index_map, g); \ +} + +CGAL_DEF_INITIALIZE_ID_MAP_FUNCTION(vertex) +CGAL_DEF_INITIALIZE_ID_MAP_FUNCTION(halfedge) +CGAL_DEF_INITIALIZE_ID_MAP_FUNCTION(edge) +CGAL_DEF_INITIALIZE_ID_MAP_FUNCTION(face) + +#undef CGAL_DEF_INITIALIZE_ID_FUCNTION + +// Using the pmap passed in named parameters ------------------------------------------------------- +template +IndexMap get_initialized_index_map_const(const IndexMap index_map, + const PropertyTag p, Tag, DynamicTag, + const Graph& g) +{ + CGAL_USE(g); + CGAL_USE(p); + + // If you are passing a pmap via NPs, it must be initialized + CGAL_assertion(is_index_map_valid(p, index_map, g)); + + return index_map; +} + +template +IndexMap get_initialized_index_map(const IndexMap index_map, + const PropertyTag p, Tag, DynamicTag, + Graph& g) +{ + CGAL_USE(g); + CGAL_USE(p); + + // If you are passing a pmap via NPs, it must be initialized + CGAL_assertion(is_index_map_valid(p, index_map, g)); + + return index_map; +} + +// Using the internal to the mesh ------------------------------------------------------------------ +template +InternalIndexMap +get_initialized_internal_index_map(InternalIndexMap index_map, + const PropertyTag p, + const Graph& g) +{ + if(CGAL::internal::Is_writable_property_map::value) + { + if(!is_index_map_valid(p, index_map, g)) + Index_map_initializer{}(p, index_map, g); + } + else // not writable + { + CGAL_assertion(is_index_map_valid(p, index_map, g)); + } + + return index_map; +} + +template +typename boost::property_map::const_type +get_initialized_index_map_const(CGAL::internal_np::Param_not_found, + const PropertyTag p, const Tag tag, DynamicTag, + const Graph& g) +{ + return get_initialized_internal_index_map(get(tag, g), p, g); +} + +// same as above, non-const graph overload +template +typename boost::property_map::type +get_initialized_index_map(CGAL::internal_np::Param_not_found, + const PropertyTag p, const Tag tag, DynamicTag, + Graph& g) +{ + // From now on the correct property map has been acquired + // and there is no need to distinguish between const and non-const mesh + return get_initialized_internal_index_map(get(tag, g), p, g); +} + +// Create a dynamic property and initialize it ----------------------------------------------------- +template +DynamicIndexMap +get_initialized_dynamic_index_map(DynamicIndexMap index_map, + const PropertyTag p, + const Graph& g) +{ +#ifdef CGAL_PERFORMANCE_WARNINGS + std::cerr << "Warning: the automatically selected index map is a dynamic property map," + << " which might not have constant-time access complexity." << std::endl; +#endif + + Index_map_initializer{}(p, index_map, g); + return index_map; +} + +template +typename boost::property_map::const_type +get_initialized_index_map_const(CGAL::internal_np::Param_not_found, + const PropertyTag p, const DynamicTag dtag, DynamicTag, + const Graph& g) +{ + return get_initialized_dynamic_index_map(get(dtag, g), p, g); +} + +// same as above, non-const graph overload +template +typename boost::property_map::type +get_initialized_index_map(CGAL::internal_np::Param_not_found, + const PropertyTag p, const DynamicTag dtag, DynamicTag, + Graph& g) +{ + // From now on the correct property map has been acquired + // and there is no need to distinguish between const and non-const mesh + return get_initialized_dynamic_index_map(get(dtag, g), p, g); +} + +template > +class GetInitializedIndexMap +{ +public: + // Check if there is an internal property map; if not, we must a dynamic property map + typedef typename boost::mpl::if_c< + CGAL::graph_has_property::value, Tag, DynamicTag>::type Final_tag; + + typedef typename internal_np::Lookup_named_param_def< + PropertyTag, + NamedParameters, + typename boost::property_map::const_type>::type const_type; + + typedef typename internal_np::Lookup_named_param_def< + PropertyTag, + NamedParameters, + typename boost::property_map::type>::type type; + + static const_type get_const(const PropertyTag p, const Graph& g, const NamedParameters& np) + { + return BGL::internal::get_initialized_index_map_const(parameters::get_parameter(np, p), + p, Final_tag{}, DynamicTag{}, g); + } + + static type get(const PropertyTag p, Graph& g, const NamedParameters& np) + { + return BGL::internal::get_initialized_index_map(parameters::get_parameter(np, p), + p, Final_tag{}, DynamicTag{}, g); + } +}; + +} // namespace internal +} // namespace BGL +} // namespace CGAL + +#endif // CGAL_BOOST_GRAPH_INITIALIZED_INTERNAL_INDEX_MAPS_HELPERS diff --git a/BGL/include/CGAL/boost/graph/io.h b/BGL/include/CGAL/boost/graph/io.h index f8e91ea49c2..dd41b28a65f 100644 --- a/BGL/include/CGAL/boost/graph/io.h +++ b/BGL/include/CGAL/boost/graph/io.h @@ -417,13 +417,9 @@ write_polys(std::ostream& os, { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_iterator face_iterator; - typedef typename CGAL::GetVertexIndexMap::type Vimap; - using parameters::get_parameter; - using parameters::choose_parameter; - - Vimap V = choose_parameter(get_parameter(np, internal_np::vertex_index), - get_const_property_map(boost::vertex_index, mesh)); + typedef typename CGAL::GetInitializedVertexIndexMap::const_type Vimap; + Vimap V = CGAL::get_initialized_vertex_index_map(mesh, np); std::vector connectivity_table; std::vector offsets; @@ -456,13 +452,9 @@ write_polys_tag(std::ostream& os, { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_iterator face_iterator; - typedef typename CGAL::GetVertexIndexMap::type Vimap; - using parameters::get_parameter; - using parameters::choose_parameter; - - Vimap V = choose_parameter(get_parameter(np, internal_np::vertex_index), - get_const_property_map(boost::vertex_index, mesh)); + typedef typename CGAL::GetInitializedVertexIndexMap::const_type Vimap; + Vimap V = CGAL::get_initialized_vertex_index_map(mesh, np); std::string formatattribute = binary ? " format=\"appended\"" : " format=\"ascii\""; @@ -638,8 +630,7 @@ write_polys_points(std::ostream& os, * `CGAL::vertex_point_t` must be available in `TriangleMesh`. * \cgalParamEnd * \cgalParamBegin{vertex_index_map} the property map with the indices associated to - * the vertices of `mesh`. If this parameter is omitted, an internal property map for - * `CGAL::vertex_index_t` must be available in `TriangleMesh`. + * the vertices of `mesh`. * \cgalParamEnd * \cgalNamedParamsEnd */ diff --git a/BGL/include/CGAL/boost/graph/named_params_helper.h b/BGL/include/CGAL/boost/graph/named_params_helper.h index 9339db5b585..e30c9238ad5 100644 --- a/BGL/include/CGAL/boost/graph/named_params_helper.h +++ b/BGL/include/CGAL/boost/graph/named_params_helper.h @@ -19,18 +19,19 @@ #ifndef CGAL_BOOST_GRAPH_NAMED_PARAMETERS_HELPERS_H #define CGAL_BOOST_GRAPH_NAMED_PARAMETERS_HELPERS_H +#include #include - +#include +#include #include #include - #include -#include + #include #include - #include +#include namespace CGAL { @@ -41,8 +42,8 @@ namespace CGAL { class Lapack_svd; struct Alpha_expansion_boost_adjacency_list_tag; // - - + + //helper classes template class property_map_selector @@ -105,7 +106,8 @@ namespace CGAL { property_map_selector pms; return pms.get_const_pmap(p, pmesh); } -// shortcut for accessing the value type of the property map + + // Shortcut for accessing the value type of the property map template class property_map_value { typedef typename boost::property_map::const_type PMap; @@ -113,7 +115,8 @@ namespace CGAL { typedef typename boost::property_traits::value_type type; }; - template + template > class GetVertexPointMap { typedef typename property_map_selector::const_type @@ -175,37 +178,105 @@ namespace CGAL { > ::type type; }; - template - class GetFaceIndexMap - { - typedef typename property_map_selector::type DefaultMap; - typedef typename property_map_selector::const_type DefaultMap_const; - public: - typedef typename internal_np::Lookup_named_param_def < - internal_np::face_index_t, - NamedParameters, - DefaultMap - > ::type type; - typedef typename internal_np::Lookup_named_param_def < - internal_np::face_index_t, - NamedParameters, - DefaultMap_const - > ::type const_type; - typedef typename boost::is_same::type Is_internal_map; - typedef typename boost::is_same::type Is_internal_map_const; - }; +// Define the following structs: +// +// GetInitializedVertexIndexMap +// GetInitializedHalfedgeIndexMap +// GetInitializedEdgeIndexMap +// GetInitializedFaceIndexMap - template - class GetVertexIndexMap - { - typedef typename property_map_selector::type DefaultMap; - public: - typedef typename internal_np::Lookup_named_param_def < - internal_np::vertex_index_t, - NamedParameters, - DefaultMap - > ::type type; - }; +#define CGAL_DEF_GET_INDEX_TYPE(CTYPE, DTYPE, STYPE) \ +template > \ +struct GetInitialized##CTYPE##IndexMap \ + : public BGL::internal::GetInitializedIndexMap, \ + Graph, NamedParameters> \ +{ }; + +CGAL_DEF_GET_INDEX_TYPE(Vertex, vertex, typename boost::graph_traits::vertices_size_type) +CGAL_DEF_GET_INDEX_TYPE(Halfedge, halfedge, typename boost::graph_traits::halfedges_size_type) +CGAL_DEF_GET_INDEX_TYPE(Edge, edge, typename boost::graph_traits::edges_size_type) +CGAL_DEF_GET_INDEX_TYPE(Face, face, typename boost::graph_traits::faces_size_type) + +#undef CGAL_DEF_GET_INDEX_TYPE + +// Define the following functions: +// +// get_initialized_vertex_index_map() +// get_initialized_halfedge_index_map() +// get_initialized_edge_index_map() +// get_initialized_face_index_map() +// +// The function returns: +// - the index property map passed in the NPs, if passed in the NPs; it must be initialized by the user; +// - the internal index property map if it is the graph has one. It is initialized if needed and possible; +// - an initialized dynamic pmap otherwise. + +#define CGAL_DEF_GET_INITIALIZED_INDEX_MAP(DTYPE, STYPE) \ +template \ +typename BGL::internal::GetInitializedIndexMap, \ + Graph, NamedParameters>::const_type \ +get_initialized_##DTYPE##_index_map(const Graph& g, \ + const NamedParameters& np) \ +{ \ + typedef BGL::internal::GetInitializedIndexMap, \ + Graph, NamedParameters> Index_map_getter; \ + return Index_map_getter::get_const(CGAL::internal_np::DTYPE##_index_t{}, g, np); \ +} \ +template \ +typename BGL::internal::GetInitializedIndexMap, \ + Graph>::const_type \ +get_initialized_##DTYPE##_index_map(const Graph& g) \ +{ \ + return get_initialized_##DTYPE##_index_map(g, CGAL::parameters::all_default()); \ +} \ +/* same as above, non-const version*/ \ +template ::type>::value, int> = 0> \ +typename BGL::internal::GetInitializedIndexMap, \ + Graph, NamedParameters>::type \ +get_initialized_##DTYPE##_index_map(Graph& g, \ + const NamedParameters& np) \ +{ \ + typedef BGL::internal::GetInitializedIndexMap, \ + Graph, NamedParameters> Index_map_getter; \ + return Index_map_getter::get(CGAL::internal_np::DTYPE##_index_t{}, g, np); \ +} \ +template ::type>::value, int> = 0> \ +typename BGL::internal::GetInitializedIndexMap, \ + Graph>::type \ +get_initialized_##DTYPE##_index_map(Graph& g) \ +{ \ + return get_initialized_##DTYPE##_index_map(g, CGAL::parameters::all_default()); \ +} + +CGAL_DEF_GET_INITIALIZED_INDEX_MAP(vertex, typename boost::graph_traits::vertices_size_type) +CGAL_DEF_GET_INITIALIZED_INDEX_MAP(halfedge, typename boost::graph_traits::halfedges_size_type) +CGAL_DEF_GET_INITIALIZED_INDEX_MAP(edge, typename boost::graph_traits::edges_size_type) +CGAL_DEF_GET_INITIALIZED_INDEX_MAP(face, typename boost::graph_traits::faces_size_type) + +#undef CGAL_DEF_GET_INITIALIZED_INDEX_MAP template class GetFaceNormalMap @@ -230,8 +301,45 @@ namespace CGAL { > ::type type; }; - namespace Point_set_processing_3 + + namespace internal { + BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(Has_nested_type_iterator, iterator, false) + } + + template, + bool has_nested_iterator = internal::Has_nested_type_iterator::value> + class GetPointMap { + typedef typename std::iterator_traits::value_type Point; + typedef typename CGAL::Identity_property_map DefaultPMap; + + public: + typedef typename internal_np::Lookup_named_param_def< + internal_np::point_t, + NamedParameters, + DefaultPMap + > ::type type; + + typedef typename internal_np::Lookup_named_param_def< + internal_np::point_t, + NamedParameters, + DefaultPMap + > ::type const_type; + }; + + // to please compiler instantiating non valid overloads + template + class GetPointMap + { + struct Dummy_point{}; + public: + typedef typename CGAL::Identity_property_map type; + typedef typename CGAL::Identity_property_map const_type; + }; + + namespace Point_set_processing_3 { + template struct Fake_point_range { @@ -255,41 +363,6 @@ namespace CGAL { } } - namespace internal{ - BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(Has_nested_type_iterator, iterator, false) - } - - template::value> - class GetPointMap - { - typedef typename std::iterator_traits::value_type Point; - typedef typename CGAL::Identity_property_map DefaultPMap; - - public: - typedef typename internal_np::Lookup_named_param_def< - internal_np::point_t, - NamedParameters, - DefaultPMap - > ::type type; - - typedef typename internal_np::Lookup_named_param_def< - internal_np::point_t, - NamedParameters, - DefaultPMap - > ::type const_type; - }; - - // to please compiler instantiating non valid overloads - template - class GetPointMap - { - struct Dummy_point{}; - public: - typedef typename CGAL::Identity_property_map type; - typedef typename CGAL::Identity_property_map const_type; - }; - template class GetFT { @@ -380,7 +453,7 @@ namespace CGAL { DefaultPMap > ::type const_type; }; - + template class GetPlaneIndexMap { @@ -428,7 +501,7 @@ namespace CGAL { }; } // namespace Point_set_processing_3 - + template class GetSolver { @@ -461,10 +534,10 @@ namespace CGAL { typedef int Matrix; static FT solve (const Matrix&, Vector&) { return 0.; } }; - + public: typedef DummySvdTraits NoTraits; - + typedef typename internal_np::Lookup_named_param_def < internal_np::svd_traits_t, NamedParameters, @@ -488,8 +561,6 @@ namespace CGAL { DefaultImplementation >::type type; }; - - } //namespace CGAL diff --git a/BGL/include/CGAL/boost/graph/parameters_interface.h b/BGL/include/CGAL/boost/graph/parameters_interface.h index df7ddaab0c0..ca561d7f665 100644 --- a/BGL/include/CGAL/boost/graph/parameters_interface.h +++ b/BGL/include/CGAL/boost/graph/parameters_interface.h @@ -17,6 +17,8 @@ CGAL_add_named_parameter(face_index_t, face_index, face_index_map) CGAL_add_named_parameter(vertex_index_t, vertex_index, vertex_index_map) CGAL_add_named_parameter(graph_visitor_t, graph_visitor, visitor) +CGAL_add_named_parameter(point_t, point_map, point_map) + CGAL_add_named_parameter(edge_is_constrained_t, edge_is_constrained, edge_is_constrained_map) CGAL_add_named_parameter(first_index_t, first_index, first_index) CGAL_add_named_parameter(number_of_iterations_t, number_of_iterations, number_of_iterations) @@ -83,6 +85,9 @@ CGAL_add_named_parameter(use_angle_smoothing_t, use_angle_smoothing, use_angle_s CGAL_add_named_parameter(use_area_smoothing_t, use_area_smoothing, use_area_smoothing) CGAL_add_named_parameter(use_Delaunay_flips_t, use_Delaunay_flips, use_Delaunay_flips) CGAL_add_named_parameter(do_project_t, do_project, do_project) +CGAL_add_named_parameter(area_threshold_t, area_threshold, area_threshold) +CGAL_add_named_parameter(volume_threshold_t, volume_threshold, volume_threshold) +CGAL_add_named_parameter(dry_run_t, dry_run, dry_run) // List of named parameters that we use in the package 'Surface Mesh Simplification' CGAL_add_named_parameter(get_cost_policy_t, get_cost_policy, get_cost) @@ -91,14 +96,14 @@ CGAL_add_named_parameter(get_placement_policy_t, get_placement_policy, get_place //to be documented CGAL_add_named_parameter(face_normal_t, face_normal, face_normal_map) CGAL_add_named_parameter(random_seed_t, random_seed, random_seed) -CGAL_add_named_parameter(tolerance_map_t, tolerance_map, tolerance_map) +CGAL_add_named_parameter(do_lock_mesh_t, do_lock_mesh, do_lock_mesh) +CGAL_add_named_parameter(do_simplify_border_t, do_simplify_border, do_simplify_border) //internal CGAL_add_named_parameter(weight_calculator_t, weight_calculator, weight_calculator) CGAL_add_named_parameter(use_bool_op_to_clip_surface_t, use_bool_op_to_clip_surface, use_bool_op_to_clip_surface) // List of named parameters used in the Point Set Processing package -CGAL_add_named_parameter(point_t, point_map, point_map) CGAL_add_named_parameter(query_point_t, query_point_map, query_point_map) CGAL_add_named_parameter(normal_t, normal_map, normal_map) CGAL_add_named_parameter(diagonalize_traits_t, diagonalize_traits, diagonalize_traits) @@ -120,6 +125,15 @@ CGAL_add_named_parameter(plane_index_t, plane_index_map, plane_index_map) CGAL_add_named_parameter(select_percentage_t, select_percentage, select_percentage) CGAL_add_named_parameter(require_uniform_sampling_t, require_uniform_sampling, require_uniform_sampling) CGAL_add_named_parameter(point_is_constrained_t, point_is_constrained, point_is_constrained_map) +CGAL_add_named_parameter(transformation_t, transformation, transformation) +CGAL_add_named_parameter(point_set_filters_t, point_set_filters, point_set_filters) +CGAL_add_named_parameter(matcher_t, matcher, matcher) +CGAL_add_named_parameter(outlier_filters_t, outlier_filters, outlier_filters) +CGAL_add_named_parameter(error_minimizer_t, error_minimizer, error_minimizer) +CGAL_add_named_parameter(transformation_checkers_t, transformation_checkers, transformation_checkers) +CGAL_add_named_parameter(inspector_t, inspector, inspector) +CGAL_add_named_parameter(logger_t, logger, logger) +CGAL_add_named_parameter(pointmatcher_config_t, pointmatcher_config, pointmatcher_config) // List of named parameters used in Surface_mesh_approximation package CGAL_add_named_parameter(verbose_level_t, verbose_level, verbose_level) @@ -141,3 +155,9 @@ CGAL_add_named_parameter(proxies_t, proxies, proxies) CGAL_add_named_parameter(anchors_t, anchors, anchors) CGAL_add_named_parameter(triangles_t, triangles, triangles) +CGAL_add_named_parameter(number_of_samples_t, number_of_samples, number_of_samples) +CGAL_add_named_parameter(accuracy_t, accuracy, accuracy) +CGAL_add_named_parameter(maximum_running_time_t, maximum_running_time, maximum_running_time) +CGAL_add_named_parameter(overlap_t, overlap, overlap) +CGAL_add_named_parameter(maximum_normal_deviation_t, maximum_normal_deviation, maximum_normal_deviation) + diff --git a/BGL/include/CGAL/boost/graph/properties.h b/BGL/include/CGAL/boost/graph/properties.h index 6460f9f88e6..589662ce0dc 100644 --- a/BGL/include/CGAL/boost/graph/properties.h +++ b/BGL/include/CGAL/boost/graph/properties.h @@ -14,72 +14,45 @@ #define CGAL_BOOST_GRAPH_BGL_PROPERTIES_H #include +#include +#include + #include #include -#include -#include -#include -#include #include +#include +#include + +namespace CGAL { -namespace CGAL{ -/// \ingroup PkgBGLProperties -/// \brief graph_has_property is used to indicate if -/// a model of `HalfedgeGraph` or `FaceGraph` -/// has an internal property associated with the -/// given `PropertyTag`. -/// -/// It inherits from `CGAL::Tag_true` if there is a -/// default internal property map for the -/// corresponding property tag and from -/// `CGAL::Tag_false` otherwise. -/// -/// \tparam Graph a model of `HalfedgeGraph` or `FaceGraph` -/// \tparam PropertyTag the type of a property tag -/// referring to the property of interest. -/// template -struct graph_has_property -#ifndef DOXYGEN_RUNNING - : CGAL::Tag_false -#endif -{}; -} -/// Boost Namespace +struct graph_has_property : CGAL::Tag_false { }; + +} // namespace CGAL + namespace boost { -/// \ingroup PkgBGLProperties -/// @{ - -/// A property tag which refers to the geometric embedding property -/// of a vertex of a \ref HalfedgeGraph. enum vertex_point_t { vertex_point }; -enum vertex_external_index_t { vertex_external_index } ; -/// A property tag which refers to the property -/// of a halfedge of being a border halfedge. -enum edge_external_index_t { edge_external_index } ; +// vertex_index_t is defined in boost +enum vertex_external_index_t { vertex_external_index }; -/// A property tag which identifies the *index* property of -/// a halfedge of a \ref HalfedgeGraph. -enum halfedge_index_t { halfedge_index }; -enum halfedge_external_index_t { halfedge_external_index } ; +enum halfedge_index_t { halfedge_index }; +enum halfedge_external_index_t { halfedge_external_index }; + +// edge_index_t is defined in boost +enum edge_external_index_t { edge_external_index }; -/// A property tag which identifies the *index* property of -/// a face of a \ref FaceGraph. enum face_index_t { face_index }; -enum face_external_index_t { face_external_index } ; +enum face_external_index_t { face_external_index }; - struct cgal_no_property { typedef bool type; typedef const bool const_type; }; -/// @} - // Introduce those two tags so we can use BOOST_INSTALL_PROPERTY // macro. This is dangerous because we now rely on implementation // details. @@ -97,12 +70,16 @@ BOOST_INSTALL_PROPERTY(face, external_index); namespace CGAL { using boost::vertex_point_t; using boost::vertex_point; +using boost::vertex_index_t; +using boost::vertex_index; using boost::vertex_external_index_t; using boost::vertex_external_index; using boost::halfedge_index_t; using boost::halfedge_index; using boost::halfedge_external_index_t; using boost::halfedge_external_index; +using boost::edge_index_t; +using boost::edge_index; using boost::edge_external_index_t; using boost::edge_external_index; using boost::face_index_t; @@ -111,128 +88,7 @@ using boost::face_external_index_t; using boost::face_external_index; } // CGAL -namespace CGAL{ -namespace helpers { - -// matches read-write property maps -template -void init_face_indices(PolygonMesh& pm, - FaceIndexMap& fid, - boost::read_write_property_map_tag, - Tag) -{ - typename boost::property_traits::value_type i = 0; - for(typename boost::graph_traits::face_descriptor fd : - faces(pm)) - { - put(fid, fd, i); - ++i; - } -} -template -void init_vertex_indices(PolygonMesh& pm, - VertexIndexMap& vid, - boost::read_write_property_map_tag, - Tag) -{ - typename boost::property_traits::value_type i = 0; - for(typename boost::graph_traits::vertex_descriptor vd : - vertices(pm)) - { - put(vid, vd, i); - ++i; - } -} -template -void init_halfedge_indices(PolygonMesh& pm, - HalfedgeIndexMap& hid, - boost::read_write_property_map_tag, - Tag) -{ - typename boost::property_traits::value_type i = 0; - for(typename boost::graph_traits::halfedge_descriptor hd : - halfedges(pm)) - { - put(hid, hd, i); - ++i; - } -} - -// matches mutable Lvalue property maps -template -void init_face_indices(PolygonMesh& pm, - FaceIndexMap& fid, - boost::lvalue_property_map_tag, - boost::false_type) -{ - init_face_indices(pm, fid, - boost::read_write_property_map_tag(), boost::false_type()); -} -template -void init_vertex_indices(PolygonMesh& pm, - VertexIndexMap& vid, - boost::lvalue_property_map_tag, - boost::false_type) -{ - init_vertex_indices(pm, vid, - boost::read_write_property_map_tag(), boost::false_type()); -} -template -void init_halfedge_indices(PolygonMesh& pm, - HalfedgeIndexMap& hid, - boost::lvalue_property_map_tag, - boost::false_type) -{ - init_halfedge_indices(pm, hid, - boost::read_write_property_map_tag(), boost::false_type()); -} - -// matches all other types of property map -template -void init_face_indices(PolygonMesh&, FaceIndexMap, MapTag, Tag) -{} -template -void init_vertex_indices(PolygonMesh&, VertexIndexMap, MapTag, Tag) -{} -template -void init_halfedge_indices(PolygonMesh&, HalfedgeIndexMap, MapTag, Tag) -{} - -template -void init_face_indices(PolygonMesh& pm, FaceIndexMap fid) -{ - init_face_indices(pm, fid, - typename boost::property_traits::category(), - typename boost::is_const< - typename boost::remove_reference< - typename boost::property_traits::reference - >::type >::type() ); -} - -template -void init_vertex_indices(PolygonMesh& pm, VertexIndexMap vid) -{ - init_vertex_indices(pm, vid, - typename boost::property_traits::category(), - typename boost::is_const< - typename boost::remove_reference< - typename boost::property_traits::reference - >::type >::type() ); -} - -template -void init_halfedge_indices(PolygonMesh& pm, HalfedgeIndexMap hid) -{ - init_halfedge_indices(pm, hid, - typename boost::property_traits::category(), - typename boost::is_const< - typename boost::remove_reference< - typename boost::property_traits::reference - >::type >::type() ); -} - -} //namespace helpers - +namespace CGAL { namespace internal { template @@ -260,8 +116,8 @@ struct Edge_index_accessor }; template::type >::value> + bool is_const = std::is_const< + typename std::remove_reference::type >::value> struct Point_accessor : boost::put_get_helper< Reference, Point_accessor > { @@ -293,6 +149,32 @@ struct Point_accessor reference operator[](Handle h) const { return h->point(); } }; +// this one is basically 'readable_property_map_tag' +template ::category> +struct Is_writable_property_map : CGAL::Tag_false { }; + +template +struct Is_writable_property_map : CGAL::Tag_true { }; + +template +struct Is_writable_property_map : CGAL::Tag_true { }; + +// 'lvalue_pmap_tag' is annoying, because the property map is allowed to be non-mutable, +// but boost::lvalue_property_map_tag is defined as: +// struct lvalue_property_map_tag : public read_write_property_map_tag +// so we can't just check that 'writable_property_map_tag' is a base of the the lvalue tag. +// +// This checks if the reference is non-const, which is not completely correct: map[key] returning +// a non-const reference doesn't mean that 'put(map, key, val)' exists, which is what a writable +// property map must define. +template +struct Is_writable_property_map + : boost::mpl::if_c::reference>::type>::value, + CGAL::Tag_false, CGAL::Tag_true>::type +{ }; + } // namespace internal // Needed by PMP::detec_features and Mesh_3 @@ -303,12 +185,12 @@ enum vertex_time_stamp_t { vertex_time_stamp}; enum halfedge_time_stamp_t { halfedge_time_stamp}; enum face_time_stamp_t { face_time_stamp}; -template +template struct vertex_incident_patches_t { typedef ID type; }; -template +template struct face_patch_id_t { typedef ID type; }; diff --git a/BGL/include/CGAL/boost/graph/properties_Seam_mesh.h b/BGL/include/CGAL/boost/graph/properties_Seam_mesh.h index 96bf18fa8ab..53acfbce101 100644 --- a/BGL/include/CGAL/boost/graph/properties_Seam_mesh.h +++ b/BGL/include/CGAL/boost/graph/properties_Seam_mesh.h @@ -112,6 +112,39 @@ struct property_map, CGAL::vertex_point_t> typedef CGAL::Seam_mesh_point_map type; typedef type const_type; }; + +template +struct property_map, CGAL::dynamic_vertex_property_t > +{ + typedef typename boost::graph_traits >::vertex_descriptor vertex_descriptor; + typedef CGAL::internal::Dynamic_property_map type; + typedef type const_type; +}; + +template +struct property_map, CGAL::dynamic_halfedge_property_t > +{ + typedef typename boost::graph_traits >::halfedge_descriptor halfedge_descriptor; + typedef CGAL::internal::Dynamic_property_map type; + typedef type const_type; +}; + + +template +struct property_map, CGAL::dynamic_edge_property_t > +{ + typedef typename boost::graph_traits >::edge_descriptor edge_descriptor; + typedef CGAL::internal::Dynamic_property_map type; + typedef type const_type; +}; + +template +struct property_map, CGAL::dynamic_face_property_t > +{ + typedef typename boost::graph_traits >::face_descriptor face_descriptor; + typedef CGAL::internal::Dynamic_property_map type; + typedef type const_type; +}; } // namespace boost namespace CGAL { diff --git a/BGL/include/CGAL/boost/graph/selection.h b/BGL/include/CGAL/boost/graph/selection.h index e023e68ca44..ae44f79c0fa 100644 --- a/BGL/include/CGAL/boost/graph/selection.h +++ b/BGL/include/CGAL/boost/graph/selection.h @@ -578,32 +578,44 @@ void expand_face_selection_for_removal(const FaceRange& faces_to_be_deleted, next_around_vertex = opposite( next(hd, tm), tm); if (hd==start) break; } - if ( get(is_selected, face(next_around_vertex, tm) ) ) continue; //all incident faces will be removed + if ( is_border(next_around_vertex,tm) || get(is_selected, face(next_around_vertex, tm) ) ) continue; //all incident faces will be removed while( true ) { // collect non-selected faces std::vector faces_traversed; + bool non_selected_face_range_has_boundary = false; // handle non-manifold situations when crossing a border do { faces_traversed.push_back(next_around_vertex); next_around_vertex = opposite( next(next_around_vertex, tm), tm); if (is_border(next_around_vertex,tm)) + { next_around_vertex = opposite( next(next_around_vertex, tm), tm); + if (!get(is_selected, face(next_around_vertex, tm) )) + { + non_selected_face_range_has_boundary=true; // always non-manifold after removal of the selection + break; + } + } CGAL_assertion(!is_border(next_around_vertex,tm)); } while( !get(is_selected, face(next_around_vertex, tm) ) ); - // go over the connected components of faces to remove - do{ + if (!non_selected_face_range_has_boundary) + { + // go over the connected components of faces to remove + do{ + if (next_around_vertex==start) + break; + next_around_vertex = opposite( next(next_around_vertex, tm), tm); + } + while(is_border(next_around_vertex,tm) || get(is_selected, face(next_around_vertex, tm) ) ); + if (next_around_vertex==start) break; - next_around_vertex = opposite( next(next_around_vertex, tm), tm); } - while( get(is_selected, face(next_around_vertex, tm) ) ); - - if (next_around_vertex==start) - break; + // else we simply mark the range of traversed faces and start a new range after the border for(halfedge_descriptor f_hd : faces_traversed) { diff --git a/BGL/test/BGL/data/nm_selection_removal.off b/BGL/test/BGL/data/nm_selection_removal.off new file mode 100644 index 00000000000..d9a07f81dba --- /dev/null +++ b/BGL/test/BGL/data/nm_selection_removal.off @@ -0,0 +1,18 @@ +OFF +9 7 0 +0 0 0 +1 0 0 +2 0 0 +2 1 0 +2 2 0 +1 2 0 +0 2 0 +0 1 0 +1 1 0 +3 0 1 8 +3 1 2 8 +3 2 3 8 +3 3 4 8 +3 5 6 8 +3 6 7 8 +3 7 0 8 diff --git a/BGL/test/BGL/test_Euler_operations.cpp b/BGL/test/BGL/test_Euler_operations.cpp index 7b5439470a8..2edc8060d89 100644 --- a/BGL/test/BGL/test_Euler_operations.cpp +++ b/BGL/test/BGL/test_Euler_operations.cpp @@ -402,6 +402,44 @@ test_swap_edges() } } +template +void +add_face_bug() +{ + typedef boost::graph_traits GT; + typedef typename GT::vertex_descriptor vertex_descriptor; + typedef typename GT::halfedge_descriptor halfedge_descriptor; + + T g; + + std::vector vs; + vs.push_back( add_vertex(g) ); // Kernel::Point_3(0,1,0) + vs.push_back( add_vertex(g) ); // Kernel::Point_3(4,1,0) + vs.push_back( add_vertex(g) ); // Kernel::Point_3(5,2,0) + vs.push_back( add_vertex(g) ); // Kernel::Point_3(4,0,0) + + CGAL::Euler::add_face(CGAL::make_array(vs[0], vs[1], vs[2]), g); + CGAL::Euler::add_face(CGAL::make_array(vs[1], vs[3], vs[2]), g); + + // force vertex halfedge to not be a border halfedge + for(vertex_descriptor v : vertices(g)) + { + halfedge_descriptor h = halfedge(v, g); + if ( CGAL::is_border(h, g) ) + set_halfedge(v, prev(opposite(h, g), g), g); + assert(target(halfedge(v, g), g)==v); + } + + vs.push_back( add_vertex(g) ); // Kernel::Point_3(0,0,0) + vs.push_back( add_vertex(g) ); // Kernel::Point_3(1,0,0) + CGAL::Euler::add_face(CGAL::make_array(vs[4],vs[5],vs[0]), g); + + vs.push_back( add_vertex(g) ); // Kernel::Point_3(2,0,0) + vs.push_back( add_vertex(g) ); // Kernel::Point_3(3,0,0) + CGAL::Euler::add_face(CGAL::make_array(vs[6],vs[7],vs[1]), g); + CGAL::Euler::add_face(CGAL::make_array(vs[7],vs[3],vs[1]), g); +} + template void test_Euler_operations() @@ -421,6 +459,7 @@ test_Euler_operations() join_split_inverse(); does_satisfy_link_condition(); test_swap_edges(); + add_face_bug(); } int main() diff --git a/BGL/test/BGL/test_Face_filtered_graph.cpp b/BGL/test/BGL/test_Face_filtered_graph.cpp index bbf57e5b2c2..0a579fe96cc 100644 --- a/BGL/test/BGL/test_Face_filtered_graph.cpp +++ b/BGL/test/BGL/test_Face_filtered_graph.cpp @@ -491,13 +491,13 @@ int main() typedef boost::graph_traits PolyTraits; - typedef boost::property_map::type VPMap; + typedef boost::property_map::const_type VPMap; typedef PolyTraits::face_descriptor poly_face_descriptor; typedef boost::associative_property_map< std::map > FCMap; - typedef boost::property_map::type FIMap; - typedef boost::property_map::type VIMap; - typedef boost::property_map::type HIMap; + typedef boost::property_map::const_type FIMap; + typedef boost::property_map::const_type VIMap; + typedef boost::property_map::const_type HIMap; typedef CGAL::Face_filtered_graph Poly_Adapter; auto poly = std::make_unique(); CGAL::make_tetrahedron( @@ -516,14 +516,14 @@ int main() FCMap poly_fccmap(fc_map); VPMap vpmap = get(boost::vertex_point, *poly); - CGAL::Polygon_mesh_processing::connected_components(*poly, poly_fccmap, CGAL::Polygon_mesh_processing::parameters:: - edge_is_constrained_map(Constraint(*poly, vpmap)). - face_index_map(poly_fimap)); + CGAL::Polygon_mesh_processing::connected_components(*poly, poly_fccmap, + CGAL::Polygon_mesh_processing::parameters::edge_is_constrained_map(Constraint(*poly, vpmap)) + .face_index_map(poly_fimap)); Poly_Adapter poly_adapter(*poly, pids, poly_fccmap, - CGAL::parameters::face_index_map(poly_fimap). - vertex_index_map(poly_vimap). - halfedge_index_map(poly_himap)); + CGAL::parameters::face_index_map(poly_fimap) + .vertex_index_map(poly_vimap) + .halfedge_index_map(poly_himap)); test_mesh(poly_adapter); } diff --git a/BGL/test/BGL/test_Manifold_face_removal.cpp b/BGL/test/BGL/test_Manifold_face_removal.cpp index 97ab16b3026..4e5e75dd0c8 100644 --- a/BGL/test/BGL/test_Manifold_face_removal.cpp +++ b/BGL/test/BGL/test_Manifold_face_removal.cpp @@ -14,6 +14,68 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef CGAL::Surface_mesh SM; typedef boost::graph_traits::face_descriptor face_descriptor; +void border_cases() +{ + SM sm_ref; + std::ifstream input("data/nm_selection_removal.off"); + input >> sm_ref; + + { + SM sm = sm_ref; + std::vector faces_to_remove; + faces_to_remove.push_back(SM::Face_index(5)); + faces_to_remove.push_back(SM::Face_index(6)); + SM::Property_map is_selected = sm.add_property_map("f:is_selected", false).first; + is_selected[SM::Face_index(5)]=true; + is_selected[SM::Face_index(6)]=true; + CGAL::expand_face_selection_for_removal(faces_to_remove, + sm, + is_selected); + int i=0; + for(face_descriptor fh : sm.faces()) + if(!is_selected[fh]) ++i; + assert(i==4); + } + + { + SM sm = sm_ref; + std::vector faces_to_remove; + faces_to_remove.push_back(SM::Face_index(4)); + faces_to_remove.push_back(SM::Face_index(6)); + SM::Property_map is_selected = sm.add_property_map("f:is_selected", false).first; + is_selected[SM::Face_index(4)]=true; + is_selected[SM::Face_index(6)]=true; + CGAL::expand_face_selection_for_removal(faces_to_remove, + sm, + is_selected); + int i=0; + for(face_descriptor fh : sm.faces()) + if(!is_selected[fh]) ++i; + + assert(i==1 || i==4); // depends on the start point + } + + { + SM sm = sm_ref; + std::vector faces_to_remove; + faces_to_remove.push_back(SM::Face_index(4)); + faces_to_remove.push_back(SM::Face_index(5)); + faces_to_remove.push_back(SM::Face_index(6)); + SM::Property_map is_selected = sm.add_property_map("f:is_selected", false).first; + is_selected[SM::Face_index(4)]=true; + is_selected[SM::Face_index(5)]=true; + is_selected[SM::Face_index(6)]=true; + CGAL::expand_face_selection_for_removal(faces_to_remove, + sm, + is_selected); + int i=0; + for(face_descriptor fh : sm.faces()) + if(!is_selected[fh]) ++i; + assert(i==4); // depends on the start point + } + +} + int main() { SM sm; @@ -60,6 +122,8 @@ int main() assert( sm.number_of_faces()+30 < nb_input_faces); assert(is_valid_polygon_mesh(sm)); + border_cases(); + return 0; } diff --git a/BGL/test/BGL/test_Prefix.h b/BGL/test/BGL/test_Prefix.h index e5343a10659..4ca383561f1 100644 --- a/BGL/test/BGL/test_Prefix.h +++ b/BGL/test/BGL/test_Prefix.h @@ -38,6 +38,7 @@ #include #include #include +#include #include @@ -57,6 +58,10 @@ typedef CGAL::Linear_cell_complex_for_bgl_combinatorial_map_helper typedef CGAL::Surface_mesh SM; +typedef SM::Property_map Seam_edge_pmap; +typedef SM::Property_map Seam_vertex_pmap; +typedef CGAL::Seam_mesh Seam_mesh; + #if defined(CGAL_USE_OPENMESH) #include @@ -73,6 +78,8 @@ typedef OpenMesh::PolyMesh_ArrayKernelT OMesh; typedef CGAL::Triangulation_vertex_base_with_id_2 Vbb; typedef CGAL::Triangulation_face_base_with_id_2 Fbb; +typedef CGAL::Triangulation_2 Triangulation_no_id_2; + typedef CGAL::Triangulation_2 > Triangulation_2; typedef CGAL::Delaunay_triangulation_2 Tr build_dummy_triangulation() { typedef typename Tr::Point Point; - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::face_descriptor face_descriptor; Tr t; t.insert(Point(0.1,0)); @@ -199,24 +204,25 @@ Tr build_dummy_triangulation() t.insert(Point(0,1)); t.insert(Point(0,2)); - int id = 0; - for(vertex_descriptor vd : vertices(t)) - vd->id() = id++; - - id = 0; - for(face_descriptor fd : faces(t)) - fd->id() = id++; - return t; } -Triangulation_2 t2_data() { return build_dummy_triangulation(); } -Delaunay_triangulation_2 dt2_data() { return build_dummy_triangulation(); } -Regular_triangulation_2 rt2_data() { return build_dummy_triangulation(); } -Constrained_triangulation_2 ct2_data() { return build_dummy_triangulation(); } -Constrained_Delaunay_triangulation_2 cdt2_data() { return build_dummy_triangulation(); } -CDT_P2 cdtp2_data() { return build_dummy_triangulation(); } -Triangulation_hierarchy_2 t2h_data() { return build_dummy_triangulation(); } +template +Tr build_dummy_triangulation_with_ids() +{ + Tr t = build_dummy_triangulation(); + CGAL::set_triangulation_ids(t); + return t; +} + +Triangulation_no_id_2 t2_no_id_data() { return build_dummy_triangulation(); } +Triangulation_2 t2_data() { return build_dummy_triangulation_with_ids(); } +Delaunay_triangulation_2 dt2_data() { return build_dummy_triangulation_with_ids(); } +Regular_triangulation_2 rt2_data() { return build_dummy_triangulation_with_ids(); } +Constrained_triangulation_2 ct2_data() { return build_dummy_triangulation_with_ids(); } +Constrained_Delaunay_triangulation_2 cdt2_data() { return build_dummy_triangulation_with_ids(); } +CDT_P2 cdtp2_data() { return build_dummy_triangulation_with_ids(); } +Triangulation_hierarchy_2 t2h_data() { return build_dummy_triangulation_with_ids(); } template struct Surface_fixture_1 { diff --git a/BGL/test/BGL/test_Properties.cpp b/BGL/test/BGL/test_Properties.cpp index 3ffd9d1720e..984891b4ca9 100644 --- a/BGL/test/BGL/test_Properties.cpp +++ b/BGL/test/BGL/test_Properties.cpp @@ -1,115 +1,459 @@ #include "test_Prefix.h" +#include + #include -template< typename G, - typename ForwardRange, - typename IndexPropertyMap - > -void index_uniqueness(const G&, - ForwardRange range, - IndexPropertyMap pm) +// #define CGAL_TEST_PROPERTIES_DEBUG + +namespace CGAL { + +template +struct Non_mutable_property_map { + typedef Key key_type; + typedef Value value_type; + typedef value_type reference; + typedef boost::readable_property_map_tag category; + + Non_mutable_property_map(const Container& c) : m_c(c) { } + + friend reference get(const Non_mutable_property_map& pmap, key_type k) + { + return pmap.m_c.at(k); + } + +private: + const Container& m_c; +}; + +template +struct RW_property_map +{ + typedef Key key_type; + typedef Value value_type; + typedef value_type& reference; + typedef boost::read_write_property_map_tag category; + + RW_property_map(Container& c) : m_c(c) { } + + friend void put(RW_property_map& pmap, const key_type& k, const value_type& val) + { + pmap.m_c[k] = val; + } + + friend reference get(RW_property_map& pmap, const key_type& k) + { + return pmap.m_c[k]; + } + +private: + Container& m_c; +}; + +} // namespace CGAL + +template +void test_uniqueness(const Graph&, + const ForwardRange& range, + IndexPropertyMap index_map) +{ +#ifdef CGAL_TEST_PROPERTIES_DEBUG + std::cout << std::endl + << "Checking the uniqueness of the property map of type: " + << typeid(IndexPropertyMap).name() << std::endl; + std::cout << "Element type: " << typeid(typename boost::range_value::type).name() << std::endl; +#endif + typename boost::range_iterator::type - begin = boost::begin(range), + begin = boost::begin(range), begin2 = boost::begin(range), end = boost::end(range); typedef boost::unordered_set id_map; typedef std::pair resultp; - id_map m; - while(begin != end) { - resultp r = m.insert(get(pm, *begin)); + id_map m; + while(begin != end) + { + resultp r = m.insert(get(index_map, *begin)); +#ifdef CGAL_TEST_PROPERTIES_DEBUG + std::cout << "id: " << get(index_map, *begin) << std::endl; +#endif ++begin; - assert(r.second); + assert(r.second); // already seen that id } assert(std::distance(begin2, end) == static_cast(m.size())); } - -void index_uniqueness_poly(const Polyhedron& g) +template +void test_vertex_index_map_uniqueness(const Graph& g, + const NamedParameters& np) { - index_uniqueness(g, edges(g) , get(boost::edge_index, g)); - index_uniqueness(g, vertices(g), get(boost::vertex_index, g)); - index_uniqueness(g, faces(g), get(boost::face_index, g)); - index_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); + typedef typename CGAL::GetInitializedVertexIndexMap::type VIM; + typedef typename CGAL::GetInitializedVertexIndexMap::const_type CVIM; - index_uniqueness(g, edges(g) , get(boost::edge_external_index, g)); - index_uniqueness(g, vertices(g), get(boost::vertex_external_index, g)); - index_uniqueness(g, faces(g), get(boost::face_external_index, g)); - index_uniqueness(g, halfedges(g), get(boost::halfedge_external_index, g)); + // in the case where the map is passed by NP, its type doesn't depend on whether the mesh is const or not + static_assert((std::is_same::value), "VIM, CVIM must be the same type"); + + VIM ivim = CGAL::get_initialized_vertex_index_map(g, np); + + return test_uniqueness(g, vertices(g), ivim); } -void index_uniqueness_lcc(const LCC& g) +template +void test_halfedge_index_map_uniqueness(const Graph& g, + const NamedParameters& np) { - index_uniqueness(g, edges(g) , get(boost::edge_index, g)); - index_uniqueness(g, vertices(g), get(boost::vertex_index, g)); - index_uniqueness(g, faces(g), get(boost::face_index, g)); - index_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); + typedef typename CGAL::GetInitializedHalfedgeIndexMap::type HIM; + typedef typename CGAL::GetInitializedHalfedgeIndexMap::const_type CHIM; + + // in the case where the map is passed by NP, its type doesn't depend on whether the mesh is const or not + static_assert((std::is_same::value), "HIM, CHIM must be the same type"); + + HIM ihim = CGAL::get_initialized_halfedge_index_map(g, np); + + return test_uniqueness(g, halfedges(g), ihim); } -void index_uniqueness_sm(const SM& g) +template +void test_edge_index_map_uniqueness(const Graph& g, + const NamedParameters& np) { - index_uniqueness(g, edges(g) , get(boost::edge_index, g)); - index_uniqueness(g, vertices(g), get(boost::vertex_index, g)); - index_uniqueness(g, faces(g), get(boost::face_index, g)); - index_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); + typedef typename CGAL::GetInitializedEdgeIndexMap::type EIM; + typedef typename CGAL::GetInitializedEdgeIndexMap::const_type CEIM; + + // in the case where the map is passed by NP, its type doesn't depend on whether the mesh is const or not + static_assert((std::is_same::value), "EIM, CEIM must be the same type"); + + EIM ieim = CGAL::get_initialized_edge_index_map(g, np); + + return test_uniqueness(g, edges(g), ieim); } -#if defined(CGAL_USE_OPENMESH) -void index_uniqueness_omesh(const OMesh& g) +template +void test_face_index_map_uniqueness(const Graph& g, + const NamedParameters& np) { - index_uniqueness(g, edges(g) , get(boost::edge_index, g)); - index_uniqueness(g, vertices(g), get(boost::vertex_index, g)); - index_uniqueness(g, faces(g), get(boost::face_index, g)); - index_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); + typedef typename CGAL::GetInitializedFaceIndexMap::type FIM; + typedef typename CGAL::GetInitializedFaceIndexMap::const_type CFIM; + + // in the case where the map is passed by NP, its type doesn't depend on whether the mesh is const or not + static_assert((std::is_same::value), "FIM, CFIM must be the same type"); + + FIM ifim = CGAL::get_initialized_face_index_map(g, np); + + return test_uniqueness(g, faces(g), ifim); } + +////////////////////////////////////////// const /////////////////////////////////////////////////// + +template +void test_internal_index_maps_const(const Graph& g) +{ + test_uniqueness(g, vertices(g), get(boost::vertex_index, g)); + test_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); + test_uniqueness(g, edges(g) , get(boost::edge_index, g)); + test_uniqueness(g, faces(g), get(boost::face_index, g)); +} + +template +void test_initialized_index_maps_const(const Graph& g) +{ + typedef typename CGAL::GetInitializedVertexIndexMap::const_type VIM; + VIM ivim = CGAL::get_initialized_vertex_index_map(g); + test_uniqueness(g, vertices(g), ivim); + + typedef typename CGAL::GetInitializedHalfedgeIndexMap::const_type HIM; + HIM ihim = CGAL::get_initialized_halfedge_index_map(g); + test_uniqueness(g, halfedges(g), ihim); + + typedef typename CGAL::GetInitializedEdgeIndexMap::const_type EIM; + EIM ieim = CGAL::get_initialized_edge_index_map(g); + test_uniqueness(g, edges(g), ieim); + + typedef typename CGAL::GetInitializedFaceIndexMap::const_type FIM; + FIM ifim = CGAL::get_initialized_face_index_map(g); + test_uniqueness(g, faces(g), ifim); + + // Passing an index map via NP + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef std::map VertexIndexMap; + typedef boost::associative_property_map VertexIdPropertyMap; // lvalue_pmap + + int vi = static_cast(num_vertices(g)); + VertexIndexMap vim; + VertexIdPropertyMap external_vertex_index_map(vim); + for(vertex_descriptor v : vertices(g)) + put(external_vertex_index_map, v, --vi); + + test_vertex_index_map_uniqueness(g, CGAL::parameters::vertex_index_map(external_vertex_index_map)); + + // Read-only pmap + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef std::map HalfedgeIndexMap; + typedef CGAL::Non_mutable_property_map HalfedgeIdPropertyMap; + + int hi = 0; + HalfedgeIndexMap him; + HalfedgeIdPropertyMap external_halfedge_index_map(him); + + // this should complain that the map is not writable (commented because it does assert) +// CGAL::BGL::internal::initialize_halfedge_index_map(external_halfedge_index_map, g); + + // forced to initialize the underlying map + for(halfedge_descriptor h : halfedges(g)) + him[h] = hi++; + + test_halfedge_index_map_uniqueness(g, CGAL::parameters::halfedge_index_map(external_halfedge_index_map)); + + // Writable pmap + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef boost::unordered_map EdgeIndexMap; + typedef CGAL::RW_property_map EdgeIdPropertyMap; + + EdgeIndexMap eim; + EdgeIdPropertyMap external_edge_index_map(eim); + CGAL::BGL::internal::initialize_edge_index_map(external_edge_index_map, g); + + test_edge_index_map_uniqueness(g, CGAL::parameters::edge_index_map(external_edge_index_map)); + + // Just so face_index_map don't feel excluded + typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef std::map FaceIndexMap; + typedef boost::const_associative_property_map FaceIdPropertyMap; + + FaceIndexMap fim; + FaceIdPropertyMap external_face_index_map(fim); + + // 'const_associative_pmap' has category 'lvalue_property_map_tag' but it's not writable + // so below should complain (commented because it does assert) +// CGAL::BGL::internal::initialize_face_index_map(external_face_index_map, g); + + // gotta initialize the underlying map + int fi = 0; + for(face_descriptor f : faces(g)) + fim[f] = fi++; + + test_face_index_map_uniqueness(g, CGAL::parameters::face_index_map(external_face_index_map)); +} + +template +void test_all_index_maps_const(const Graph& g) +{ +#ifdef CGAL_TEST_PROPERTIES_DEBUG + std::cout << " ---------------------------- Const graph tests" << std::endl; #endif -template -void index_uniqueness_tr(const Triangulation& g) -{ - index_uniqueness(g, edges(g) , get(boost::edge_index, g)); - index_uniqueness(g, vertices(g), get(boost::vertex_index, g)); - index_uniqueness(g, faces(g), get(boost::face_index, g)); - index_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); + test_internal_index_maps_const(g); + test_initialized_index_maps_const(g); } -int main() +///////////////////////////////////// non-const //////////////////////////////////////////////////// + +template +void test_internal_index_maps(Graph& g) +{ + test_uniqueness(g, vertices(g), get(boost::vertex_index, g)); + test_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); + test_uniqueness(g, edges(g) , get(boost::edge_index, g)); + test_uniqueness(g, faces(g), get(boost::face_index, g)); +} + +template +void test_initialized_index_maps(Graph& g) +{ + typedef typename CGAL::GetInitializedVertexIndexMap::type VIM; + VIM ivim = CGAL::get_initialized_vertex_index_map(g); + test_uniqueness(g, vertices(g), ivim); + + typedef typename CGAL::GetInitializedHalfedgeIndexMap::type HIM; + HIM ihim = CGAL::get_initialized_halfedge_index_map(g); + test_uniqueness(g, halfedges(g), ihim); + + typedef typename CGAL::GetInitializedEdgeIndexMap::type EIM; + EIM ieim = CGAL::get_initialized_edge_index_map(g); + test_uniqueness(g, edges(g), ieim); + + typedef typename CGAL::GetInitializedFaceIndexMap::type FIM; + FIM ifim = CGAL::get_initialized_face_index_map(g); + test_uniqueness(g, faces(g), ifim); + + // Passing an index map via NP + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef std::map VertexIndexMap; + typedef boost::associative_property_map VertexIdPropertyMap; // lvalue_pmap + + int vi = static_cast(num_vertices(g)); + VertexIndexMap vim; + VertexIdPropertyMap external_vertex_index_map(vim); + for(vertex_descriptor v : vertices(g)) + put(external_vertex_index_map, v, --vi); + + test_vertex_index_map_uniqueness(g, CGAL::parameters::vertex_index_map(external_vertex_index_map)); + + // Read-only pmap + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef std::map HalfedgeIndexMap; + typedef CGAL::Non_mutable_property_map HalfedgeIdPropertyMap; + + int hi = 0; + HalfedgeIndexMap him; + HalfedgeIdPropertyMap external_halfedge_index_map(him); + + // this should complain that the map is not writable (commented because it does assert) +// CGAL::BGL::internal::initialize_halfedge_index_map(external_halfedge_index_map, g); + + // forced to initialize the underlying map + for(halfedge_descriptor h : halfedges(g)) + him[h] = hi++; + + test_halfedge_index_map_uniqueness(g, CGAL::parameters::halfedge_index_map(external_halfedge_index_map)); + + // Writable pmap + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef boost::unordered_map EdgeIndexMap; + typedef CGAL::RW_property_map EdgeIdPropertyMap; + + EdgeIndexMap eim; + EdgeIdPropertyMap external_edge_index_map(eim); + CGAL::BGL::internal::initialize_edge_index_map(external_edge_index_map, g); + + test_edge_index_map_uniqueness(g, CGAL::parameters::edge_index_map(external_edge_index_map)); + + // Just so face_index_map don't feel excluded + typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef std::map FaceIndexMap; + typedef boost::const_associative_property_map FaceIdPropertyMap; + + FaceIndexMap fim; + FaceIdPropertyMap external_face_index_map(fim); + + // 'const_associative_pmap' has category 'lvalue_property_map_tag' but it's not writable + // so below should complain (commented because it does assert) +// CGAL::BGL::internal::initialize_face_index_map(external_face_index_map, g); + + // gotta initialize the underlying map + int fi = 0; + for(face_descriptor f : faces(g)) + fim[f] = fi++; + + test_face_index_map_uniqueness(g, CGAL::parameters::face_index_map(external_face_index_map)); +} + +template +void test_all_index_maps(Graph& g) +{ +#ifdef CGAL_TEST_PROPERTIES_DEBUG + std::cout << " ---------------------------- Non-const graph tests" << std::endl; +#endif + + test_internal_index_maps(g); + test_initialized_index_maps(g); +} + +template +void test_graph(Graph& g) +{ +#ifdef CGAL_TEST_PROPERTIES_DEBUG + std::cout << "Graph has:" << std::endl + << "\t" << num_vertices(g) << " vertices (actual: " << vertices(g).size() << ")" << std::endl + << "\t" << num_halfedges(g) << " halfedges (actual: " << halfedges(g).size() << ")" << std::endl + << "\t" << num_edges(g) << " edges (actual: " << edges(g).size() << ")" << std::endl + << "\t" << num_faces(g) << " faces (actual: " << faces(g).size() << ")" << std::endl; +#endif + + test_all_index_maps(g); + test_all_index_maps_const(g); +} + +void test_poly(Polyhedron& g) +{ + test_graph(g); + + test_uniqueness(g, edges(g) , get(boost::edge_external_index, g)); + test_uniqueness(g, vertices(g), get(boost::vertex_external_index, g)); + test_uniqueness(g, faces(g), get(boost::face_external_index, g)); + test_uniqueness(g, halfedges(g), get(boost::halfedge_external_index, g)); +} + +int main(int, char**) { std::cout << "testing Polyhedron\n"; std::vector polys = poly_data(); - for(Polyhedron p : polys) - index_uniqueness_poly(p); + for(Polyhedron& p : polys) + test_poly(p); std::cout << "testing Linear_cell_complex\n"; std::vector lccs = lcc_data(); - for(LCC p : lccs) - index_uniqueness_lcc(p); + for(LCC& p : lccs) + test_graph(p); std::cout << "testing Surface_mesh\n"; std::vector sms = sm_data(); - for(SM p : sms) - index_uniqueness_sm(p); + for(SM& sm : sms) + { + assert(!CGAL::is_empty(sm)); + + // Add some garbage + CGAL::Euler::join_vertex(*(halfedges(sm).begin()), sm); + + test_graph(sm); + + // Test on a mesh with no internal index maps + Seam_edge_pmap seam_edges = sm.add_property_map("e:on_seam", false).first; + Seam_vertex_pmap seam_vertices = sm.add_property_map("v:on_seam", false).first; + Seam_mesh seam_mesh(sm, seam_edges, seam_vertices); + + test_initialized_index_maps(seam_mesh); + test_initialized_index_maps_const(seam_mesh); + } #if defined(CGAL_USE_OPENMESH) std::cout << "testing OpenMesh\n"; std::vector omeshs = omesh_data(); - for(OMesh p : omeshs) - index_uniqueness_omesh(p); + for(OMesh& p : omeshs) + test_graph(p); #endif std::cout << "testing Triangulations\n"; - index_uniqueness_tr(t2_data()); - index_uniqueness_tr(dt2_data()); - index_uniqueness_tr(rt2_data()); - index_uniqueness_tr(ct2_data()); - index_uniqueness_tr(cdt2_data()); - index_uniqueness_tr(cdtp2_data()); - index_uniqueness_tr(t2h_data()); - std::cerr << "done\n"; - return 0; + Triangulation_2 t2 = t2_data(); + test_graph(t2); + + Delaunay_triangulation_2 dt2 = dt2_data(); + test_graph(dt2); + + Regular_triangulation_2 rt2 = rt2_data(); + test_graph(rt2); + + Constrained_triangulation_2 ct2 = ct2_data(); + test_graph(ct2); + + Constrained_Delaunay_triangulation_2 cdt2 = cdt2_data(); + test_graph(cdt2); + + CDT_P2 cdtp2 = cdtp2_data(); + test_graph(cdtp2); + + Triangulation_hierarchy_2 t2h = t2h_data(); + test_graph(t2h); + + // no dynamic pmaps in triangulations (yet) +// Triangulation_no_id_2 t2_no_id = t2_no_id_data(); +// test_initialized_index_maps(t2_no_id); +// test_initialized_index_maps_const(t2_no_id); + + std::cout << "Done!" << std::endl; + + return EXIT_SUCCESS; } diff --git a/BGL/test/BGL/test_cgal_bgl_named_params.cpp b/BGL/test/BGL/test_cgal_bgl_named_params.cpp index 70b757b4af0..07dc883392d 100644 --- a/BGL/test/BGL/test_cgal_bgl_named_params.cpp +++ b/BGL/test/BGL/test_cgal_bgl_named_params.cpp @@ -91,6 +91,11 @@ void test(const NamedParameters& np) assert(get_parameter(np, CGAL::internal_np::use_area_smoothing).v == 54); assert(get_parameter(np, CGAL::internal_np::use_Delaunay_flips).v == 55); assert(get_parameter(np, CGAL::internal_np::use_safety_constraints).v == 56); + assert(get_parameter(np, CGAL::internal_np::area_threshold).v == 57); + assert(get_parameter(np, CGAL::internal_np::volume_threshold).v == 58); + assert(get_parameter(np, CGAL::internal_np::dry_run).v == 59); + assert(get_parameter(np, CGAL::internal_np::do_lock_mesh).v == 60); + assert(get_parameter(np, CGAL::internal_np::do_simplify_border).v == 61); // Named parameters that we use in the package 'Surface Mesh Simplification' assert(get_parameter(np, CGAL::internal_np::get_cost_policy).v == 34); @@ -175,6 +180,11 @@ void test(const NamedParameters& np) check_same_type<54>(get_parameter(np, CGAL::internal_np::use_area_smoothing)); check_same_type<55>(get_parameter(np, CGAL::internal_np::use_Delaunay_flips)); check_same_type<56>(get_parameter(np, CGAL::internal_np::use_safety_constraints)); + check_same_type<57>(get_parameter(np, CGAL::internal_np::area_threshold)); + check_same_type<58>(get_parameter(np, CGAL::internal_np::volume_threshold)); + check_same_type<59>(get_parameter(np, CGAL::internal_np::dry_run)); + check_same_type<60>(get_parameter(np, CGAL::internal_np::do_lock_mesh)); + check_same_type<61>(get_parameter(np, CGAL::internal_np::do_simplify_border)); // Named parameters that we use in the package 'Surface Mesh Simplification' check_same_type<34>(get_parameter(np, CGAL::internal_np::get_cost_policy)); @@ -193,6 +203,43 @@ void test(const NamedParameters& np) check_same_type<42>(get_parameter(np, CGAL::internal_np::projection_functor)); check_same_type<46>(get_parameter(np, CGAL::internal_np::apply_per_connected_component)); check_same_type<47>(get_parameter(np, CGAL::internal_np::output_iterator)); + + // Named parameters used in the package 'Point Set Processing' + check_same_type<9000>(get_parameter(np, CGAL::internal_np::point_map)); + check_same_type<9001>(get_parameter(np, CGAL::internal_np::query_point_map)); + check_same_type<9002>(get_parameter(np, CGAL::internal_np::normal_map)); + check_same_type<9003>(get_parameter(np, CGAL::internal_np::diagonalize_traits)); + check_same_type<9004>(get_parameter(np, CGAL::internal_np::svd_traits)); + check_same_type<9005>(get_parameter(np, CGAL::internal_np::callback)); + check_same_type<9006>(get_parameter(np, CGAL::internal_np::sharpness_angle)); + check_same_type<9007>(get_parameter(np, CGAL::internal_np::edge_sensitivity)); + check_same_type<9008>(get_parameter(np, CGAL::internal_np::neighbor_radius)); + check_same_type<9009>(get_parameter(np, CGAL::internal_np::number_of_output_points)); + check_same_type<9010>(get_parameter(np, CGAL::internal_np::size)); + check_same_type<9011>(get_parameter(np, CGAL::internal_np::maximum_variation)); + check_same_type<9012>(get_parameter(np, CGAL::internal_np::degree_fitting)); + check_same_type<9013>(get_parameter(np, CGAL::internal_np::degree_monge)); + check_same_type<9014>(get_parameter(np, CGAL::internal_np::threshold_percent)); + check_same_type<9015>(get_parameter(np, CGAL::internal_np::threshold_distance)); + check_same_type<9016>(get_parameter(np, CGAL::internal_np::attraction_factor)); + check_same_type<9017>(get_parameter(np, CGAL::internal_np::plane_map)); + check_same_type<9018>(get_parameter(np, CGAL::internal_np::plane_index_map)); + check_same_type<9019>(get_parameter(np, CGAL::internal_np::select_percentage)); + check_same_type<9020>(get_parameter(np, CGAL::internal_np::require_uniform_sampling)); + check_same_type<9021>(get_parameter(np, CGAL::internal_np::point_is_constrained)); + check_same_type<9022>(get_parameter(np, CGAL::internal_np::number_of_samples)); + check_same_type<9023>(get_parameter(np, CGAL::internal_np::accuracy)); + check_same_type<9024>(get_parameter(np, CGAL::internal_np::maximum_running_time)); + check_same_type<9025>(get_parameter(np, CGAL::internal_np::overlap)); + check_same_type<9026>(get_parameter(np, CGAL::internal_np::transformation)); + check_same_type<9027>(get_parameter(np, CGAL::internal_np::point_set_filters)); + check_same_type<9028>(get_parameter(np, CGAL::internal_np::matcher)); + check_same_type<9029>(get_parameter(np, CGAL::internal_np::outlier_filters)); + check_same_type<9030>(get_parameter(np, CGAL::internal_np::error_minimizer)); + check_same_type<9031>(get_parameter(np, CGAL::internal_np::transformation_checkers)); + check_same_type<9032>(get_parameter(np, CGAL::internal_np::inspector)); + check_same_type<9033>(get_parameter(np, CGAL::internal_np::logger)); + check_same_type<9034>(get_parameter(np, CGAL::internal_np::maximum_normal_deviation)); } int main() @@ -265,7 +312,46 @@ int main() .use_area_smoothing(A<54>(54)) .use_Delaunay_flips(A<55>(55)) .use_safety_constraints(A<56>(56)) + .area_threshold(A<57>(57)) + .volume_threshold(A<58>(58)) + .dry_run(A<59>(59)) + .do_lock_mesh(A<60>(60)) + .do_simplify_border(A<61>(61)) + .point_map(A<9000>(9000)) + .query_point_map(A<9001>(9001)) + .normal_map(A<9002>(9002)) + .diagonalize_traits(A<9003>(9003)) + .svd_traits(A<9004>(9004)) + .callback(A<9005>(9005)) + .sharpness_angle(A<9006>(9006)) + .edge_sensitivity(A<9007>(9007)) + .neighbor_radius(A<9008>(9008)) + .number_of_output_points(A<9009>(9009)) + .size(A<9010>(9010)) + .maximum_variation(A<9011>(9011)) + .degree_fitting(A<9012>(9012)) + .degree_monge(A<9013>(9013)) + .threshold_percent(A<9014>(9014)) + .threshold_distance(A<9015>(9015)) + .attraction_factor(A<9016>(9016)) + .plane_map(A<9017>(9017)) + .plane_index_map(A<9018>(9018)) + .select_percentage(A<9019>(9019)) + .require_uniform_sampling(A<9020>(9020)) + .point_is_constrained_map(A<9021>(9021)) + .number_of_samples(A<9022>(9022)) + .accuracy(A<9023>(9023)) + .maximum_running_time(A<9024>(9024)) + .overlap(A<9025>(9025)) + .transformation(A<9026>(9026)) + .point_set_filters(A<9027>(9027)) + .matcher(A<9028>(9028)) + .outlier_filters(A<9029>(9029)) + .error_minimizer(A<9030>(9030)) + .transformation_checkers(A<9031>(9031)) + .inspector(A<9032>(9032)) + .logger(A<9033>(9033)) + .maximum_normal_deviation(A<9034>(9034)) ); - return EXIT_SUCCESS; } diff --git a/Barycentric_coordinates_2/benchmark/Barycentric_coordinates_2/Discrete_harmonic_coordinates/DH_speed_test_100_vertices.cpp b/Barycentric_coordinates_2/benchmark/Barycentric_coordinates_2/Discrete_harmonic_coordinates/DH_speed_test_100_vertices.cpp index 561a45ccecd..0b37ce54e32 100644 --- a/Barycentric_coordinates_2/benchmark/Barycentric_coordinates_2/Discrete_harmonic_coordinates/DH_speed_test_100_vertices.cpp +++ b/Barycentric_coordinates_2/benchmark/Barycentric_coordinates_2/Discrete_harmonic_coordinates/DH_speed_test_100_vertices.cpp @@ -2,6 +2,7 @@ // We test speed of discrete harmonic coordinates on a set of automatically generated // points inside a regular polygon with 100 vertices. We use inexact kernel. +#include #include #include #include @@ -28,12 +29,11 @@ void generate_regular_polygon(const int number_of_vertices, const double polygon { const int n = number_of_vertices; const double r = polygon_radius; - const double number_pi = 3.14159; vertices.resize(n); for(int i = 0; i < n; ++i) - vertices[i] = Point(Scalar(r*sin((number_pi / n) + ((i * 2.0 * number_pi) / n))), Scalar(-r*cos((number_pi / n) + ((i * 2.0 * number_pi) / n)))); + vertices[i] = Point(Scalar(r*sin((CGAL_PI / n) + ((i * 2.0 * CGAL_PI) / n))), Scalar(-r*cos((CGAL_PI / n) + ((i * 2.0 * CGAL_PI) / n)))); } int main() diff --git a/Barycentric_coordinates_2/benchmark/Barycentric_coordinates_2/Mean_value_coordinates/MV_speed_test_100_vertices.cpp b/Barycentric_coordinates_2/benchmark/Barycentric_coordinates_2/Mean_value_coordinates/MV_speed_test_100_vertices.cpp index 261c4315dfb..1d568bf03db 100644 --- a/Barycentric_coordinates_2/benchmark/Barycentric_coordinates_2/Mean_value_coordinates/MV_speed_test_100_vertices.cpp +++ b/Barycentric_coordinates_2/benchmark/Barycentric_coordinates_2/Mean_value_coordinates/MV_speed_test_100_vertices.cpp @@ -2,6 +2,7 @@ // We test speed of mean value coordinates on a set of automatically generated // points inside a regular polygon with 100 vertices. We use inexact kernel. +#include #include #include #include @@ -28,12 +29,11 @@ void generate_regular_polygon(const int number_of_vertices, const double polygon { const int n = number_of_vertices; const double r = polygon_radius; - const double number_pi = 3.14159; vertices.resize(n); for(int i = 0; i < n; ++i) - vertices[i] = Point(Scalar(r*sin((number_pi / n) + ((i * 2.0 * number_pi) / n))), Scalar(-r*cos((number_pi / n) + ((i * 2.0 * number_pi) / n)))); + vertices[i] = Point(Scalar(r*sin((CGAL_PI / n) + ((i * 2.0 * CGAL_PI) / n))), Scalar(-r*cos((CGAL_PI / n) + ((i * 2.0 * CGAL_PI) / n)))); } int main() diff --git a/Barycentric_coordinates_2/benchmark/Barycentric_coordinates_2/Wachspress_coordinates/WP_speed_test_100_vertices.cpp b/Barycentric_coordinates_2/benchmark/Barycentric_coordinates_2/Wachspress_coordinates/WP_speed_test_100_vertices.cpp index 97468098ea0..0d28ec26fd2 100644 --- a/Barycentric_coordinates_2/benchmark/Barycentric_coordinates_2/Wachspress_coordinates/WP_speed_test_100_vertices.cpp +++ b/Barycentric_coordinates_2/benchmark/Barycentric_coordinates_2/Wachspress_coordinates/WP_speed_test_100_vertices.cpp @@ -2,6 +2,7 @@ // We test speed of Wachspress coordinates on a set of automatically generated // points inside a regular polygon with 100 vertices. We use inexact kernel. +#include #include #include #include @@ -28,12 +29,11 @@ void generate_regular_polygon(const int number_of_vertices, const double polygon { const int n = number_of_vertices; const double r = polygon_radius; - const double number_pi = 3.14159; vertices.resize(n); for(int i = 0; i < n; ++i) - vertices[i] = Point(Scalar(r*sin((number_pi / n) + ((i * 2.0 * number_pi) / n))), Scalar(-r*cos((number_pi / n) + ((i * 2.0 * number_pi) / n)))); + vertices[i] = Point(Scalar(r*sin((CGAL_PI / n) + ((i * 2.0 * CGAL_PI) / n))), Scalar(-r*cos((CGAL_PI / n) + ((i * 2.0 * CGAL_PI) / n)))); } int main() diff --git a/Bounding_volumes/examples/Approximate_min_ellipsoid_d/CMakeLists.txt b/Bounding_volumes/examples/Approximate_min_ellipsoid_d/CMakeLists.txt index 8802463b72d..9e5c6bb914e 100644 --- a/Bounding_volumes/examples/Approximate_min_ellipsoid_d/CMakeLists.txt +++ b/Bounding_volumes/examples/Approximate_min_ellipsoid_d/CMakeLists.txt @@ -8,15 +8,16 @@ if ( CGAL_FOUND ) # Use Eigen find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater) - if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - endif() # create a target per cppfile file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(cppfile ${cppfiles}) if(NOT (${cppfile} STREQUAL "ellipsoid.cpp") OR EIGEN3_FOUND) create_single_source_cgal_program( "${cppfile}" ) + if (EIGEN3_FOUND) + get_filename_component(target ${cppfile} NAME_WE) + CGAL_target_use_Eigen(${target}) + endif() endif() endforeach() diff --git a/Bounding_volumes/test/Bounding_volumes/CMakeLists.txt b/Bounding_volumes/test/Bounding_volumes/CMakeLists.txt index 403e652475c..dd6813bb97e 100644 --- a/Bounding_volumes/test/Bounding_volumes/CMakeLists.txt +++ b/Bounding_volumes/test/Bounding_volumes/CMakeLists.txt @@ -14,15 +14,16 @@ if ( CGAL_FOUND ) # Use Eigen find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater) - if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - endif() # create a target per cppfile file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(cppfile ${cppfiles}) if(NOT (${cppfile} STREQUAL "Approximate_min_ellipsoid_d.cpp") OR EIGEN3_FOUND) create_single_source_cgal_program( "${cppfile}" ) + if (EIGEN3_FOUND) + get_filename_component(target ${cppfile} NAME_WE) + CGAL_target_use_Eigen(${target}) + endif() endif() endforeach() diff --git a/Box_intersection_d/doc/Box_intersection_d/CGAL/box_intersection_d.h b/Box_intersection_d/doc/Box_intersection_d/CGAL/box_intersection_d.h index 89b6facc3cc..b8eb1310a32 100644 --- a/Box_intersection_d/doc/Box_intersection_d/CGAL/box_intersection_d.h +++ b/Box_intersection_d/doc/Box_intersection_d/CGAL/box_intersection_d.h @@ -242,6 +242,29 @@ void box_intersection_all_pairs_d( cutoff parameters are recommended. See also Section \ref secboxintersperformance . +\cgalHeading{Concurrency} + + The first template parameter of the function enables to choose whether + the algorithm is to be run in parallel, if `CGAL::Parallel_tag` is specified + and %CGAL has been linked with the Intel TBB library, or sequentially, + if `CGAL::Sequential_tag` - the default value - is specified. + The parallelization of the algorithm is based on a divide-and-conquer + approach: the two ranges are split in a number of smaller ranges, and + all combinations of subranges are treated in parallel. It is thus + recommended to use ranges of pointers to bounding boxes, to keep + these copies light. + + \warning The parallel mode comes with a small overhead due to the + duplication and splitting of the input ranges. It is an improvement + for almost all inputs, but not all. A configuration where the two ranges + are small and entirely disjoint might result in a slightly worse + runtime when using the parallel version. Users should benchmark both + versions to verify that their data does not fall in this (small) + set of inputs. + + \warning When using the parallel mode, the callback function must + be threadsafe. + \cgalHeading{Example} The box implementation provided with @@ -274,7 +297,8 @@ void box_intersection_all_pairs_d( */ -template< class RandomAccessIterator1, +template< class ConcurrencyTag = CGAL::Sequential_tag, + class RandomAccessIterator1, class RandomAccessIterator2, class Callback > void box_intersection_d( @@ -291,7 +315,8 @@ void box_intersection_d( Invocation with custom box traits. */ -template< class RandomAccessIterator1, +template< class ConcurrencyTag = CGAL::Sequential_tag, + class RandomAccessIterator1, class RandomAccessIterator2, class Callback, class BoxTraits > void box_intersection_d( @@ -489,8 +514,11 @@ namespace CGAL { \cgalHeading{Implementation} - See the implementation section of the `box_intersection_d()` - function. + See the implementation section of the `box_intersection_d()` function. + +\cgalHeading{Concurrency} + + See the concurrency section of the `box_intersection_d()` function. \cgalHeading{Example} @@ -520,7 +548,8 @@ namespace CGAL { `RandomAccessIterator`. */ -template< class RandomAccessIterator, class Callback > +template< class ConcurrencyTag = CGAL::Sequential_tag, + class RandomAccessIterator, class Callback > void box_self_intersection_d( RandomAccessIterator begin, RandomAccessIterator end, Callback callback, @@ -532,7 +561,8 @@ void box_self_intersection_d( Invocation with custom box traits. */ -template< class RandomAccessIterator, +template< class ConcurrencyTag = CGAL::Sequential_tag + class RandomAccessIterator, class Callback, class BoxTraits > void box_self_intersection_d( RandomAccessIterator begin, RandomAccessIterator end, diff --git a/Box_intersection_d/include/CGAL/Box_intersection_d/Box_with_info_d.h b/Box_intersection_d/include/CGAL/Box_intersection_d/Box_with_info_d.h index 2a53c9db171..eeccd7f9819 100644 --- a/Box_intersection_d/include/CGAL/Box_intersection_d/Box_with_info_d.h +++ b/Box_intersection_d/include/CGAL/Box_intersection_d/Box_with_info_d.h @@ -16,34 +16,34 @@ #include - #include #include namespace CGAL { - namespace Box_intersection_d { -template -class Box_with_info_d : public Box_d< NT_, N, ID_FROM_BOX_ADDRESS> { +template +class Box_with_info_d + : public Box_d< NT_, N, IdPolicy> +{ protected: Info_ m_info; public: - typedef Box_d< NT_, N, ID_FROM_BOX_ADDRESS> Base; - typedef NT_ NT; - typedef Info_ Info; + typedef Box_d< NT_, N, IdPolicy> Base; + typedef NT_ NT; + typedef Info_ Info; + Box_with_info_d() {} Box_with_info_d( Info h) : m_info(h) {} Box_with_info_d( bool complete, Info h): Base(complete), m_info(h) {} Box_with_info_d(NT l[N], NT h[N], Info n) : Base( l, h), m_info(n) {} Box_with_info_d( const Bbox_2& b, Info h) : Base( b), m_info(h) {} Box_with_info_d( const Bbox_3& b, Info h) : Base( b), m_info(h) {} + Info info() const { return m_info; } }; -} // end namespace Box_intersection_d +} // namespace Box_intersection_d +} // namespace CGAL - -} //namespace CGAL - -#endif +#endif // CGAL_BOX_INTERSECTION_D_BOX_WITH_INFO_D_H diff --git a/Box_intersection_d/include/CGAL/Box_intersection_d/segment_tree.h b/Box_intersection_d/include/CGAL/Box_intersection_d/segment_tree.h index 74a113c46b8..d9fccef3776 100644 --- a/Box_intersection_d/include/CGAL/Box_intersection_d/segment_tree.h +++ b/Box_intersection_d/include/CGAL/Box_intersection_d/segment_tree.h @@ -16,7 +16,6 @@ #include - #include #include @@ -24,7 +23,6 @@ #include #include - #include #include #include @@ -93,6 +91,8 @@ void one_way_scan( RandomAccessIter1 p_begin, RandomAccessIter1 p_end, bool in_order = true ) { typedef typename Traits::Compare Compare; + + // Putting a parallel sort here slows down the overall parallel algorithm std::sort( p_begin, p_end, Compare( 0 ) ); std::sort( i_begin, i_end, Compare( 0 ) ); @@ -323,7 +323,7 @@ void segment_tree( RandomAccessIter1 p_begin, RandomAccessIter1 p_end, RandomAccessIter2 i_begin, RandomAccessIter2 i_end, T lo, T hi, Callback callback, Predicate_traits traits, - std::ptrdiff_t cutoff, int dim, bool in_order ) + std::ptrdiff_t cutoff, int dim, bool in_order) { typedef typename Predicate_traits::Spanning Spanning; typedef typename Predicate_traits::Lo_less Lo_less; diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index d7952400617..94752c41462 100644 --- a/Box_intersection_d/include/CGAL/box_intersection_d.h +++ b/Box_intersection_d/include/CGAL/box_intersection_d.h @@ -6,7 +6,7 @@ // $URL$ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// +// // // Author(s) : Lutz Kettner // Andreas Meyer @@ -25,12 +25,191 @@ #include #include +#include +#include + +#ifdef CGAL_LINKED_WITH_TBB +#include +#endif + +#include #include +//////////////////////////////////////////////////////////////////////////////////////////////// +/// THE CALLBACK MUST BE THREADSAFE IF YOU ARE USING THE PARALLEL MODE +//////////////////////////////////////////////////////////////////////////////////////////////// + namespace CGAL { +namespace internal { // Generic call with custom predicate traits parameter. -template< class RandomAccessIter1, class RandomAccessIter2, +template< class ConcurrencyTag, + class RandomAccessIter1, class RandomAccessIter2, + class Callback, class Traits > +void box_intersection_segment_tree_d( + RandomAccessIter1 begin1, RandomAccessIter1 end1, + RandomAccessIter2 begin2, RandomAccessIter2 end2, + Callback callback, + const Traits& traits, + const std::ptrdiff_t cutoff, + const bool in_order) +{ + typedef typename Traits::NT NT; + + CGAL_assertion(Traits::dimension() > 0); + const int dim = Traits::dimension() - 1; + + const NT inf = Box_intersection_d::box_limits::inf(); + const NT sup = Box_intersection_d::box_limits::sup(); + +#ifndef CGAL_LINKED_WITH_TBB + CGAL_static_assertion_msg (!(boost::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable."); +#else // CGAL_LINKED_WITH_TBB + if(boost::is_convertible::value) + { + // Here is an illustration for n=2. + // + // Doing a R1-R2 intersection with a 2-split is doing 4 subpairs in parallel + // a-c and b-d + // r1[0][0] --a-- r1[0][1] --b-- r1[0][2] + // r2[0][0] --c-- r2[0][1] --d-- r2[0][2] + // + // a-d and b-c + // r1[1][0] --a-- r1[1][1] --b-- r1[1][2] + // r2[1][0] --c-- r2[1][1] --d-- r2[1][2] + // + // Ranges must be duplicates since sorting is performed + + typedef typename std::iterator_traits::value_type val_t; + typedef typename std::iterator_traits::difference_type diff_size; + + typedef std::vector val_container; + typedef typename val_container::iterator It; + + static constexpr int n = 4; + + const diff_size r1s = std::distance(begin1, end1); + const diff_size r2s = std::distance(begin2, end2); + + val_container range_1_copies, range_2_copies; + range_1_copies.reserve(r1s * n); + range_2_copies.reserve(r2s * n); + + const diff_size r1_step = r1s / n; + const diff_size r2_step = r2s / n; + + for(int i=0; i, n> range_1_iterators; + std::array, n> range_2_iterators; + + for(int i=0; i void box_intersection_custom_predicates_d( RandomAccessIter1 begin1, RandomAccessIter1 end1, @@ -40,23 +219,15 @@ void box_intersection_custom_predicates_d( std::ptrdiff_t cutoff = 10, Box_intersection_d::Setting setting = Box_intersection_d::BIPARTITE) { - typedef BoxPredicateTraits Traits; - typedef typename Traits::NT NT; - CGAL_assertion( Traits::dimension() > 0 ); - const int dim = Traits::dimension() - 1; - const NT inf = Box_intersection_d::box_limits::inf(); - const NT sup = Box_intersection_d::box_limits::sup(); - Box_intersection_d::segment_tree(begin1, end1, begin2, end2, - inf, sup, callback, traits, cutoff, dim, true); - if(setting == Box_intersection_d::BIPARTITE) - Box_intersection_d::segment_tree(begin2, end2, begin1, end1, - inf, sup, callback, traits, cutoff, dim, false); + internal::box_intersection_segment_tree_d(begin1, end1, begin2, end2, callback, traits, cutoff, true); + if(setting == Box_intersection_d::BIPARTITE) + internal::box_intersection_segment_tree_d(begin2, end2, begin1, end1, callback, traits, cutoff, false); } - // Generic call with box traits parameter. // - make all default parameters explicit overloads (workaround) -template< class RandomAccessIter1, class RandomAccessIter2, +template< class ConcurrencyTag = Sequential_tag, + class RandomAccessIter1, class RandomAccessIter2, class Callback, class BoxTraits > void box_intersection_d( RandomAccessIter1 begin1, RandomAccessIter1 end1, @@ -67,18 +238,19 @@ void box_intersection_d( Box_intersection_d::Topology topology, Box_intersection_d::Setting setting) { - if (topology == Box_intersection_d::CLOSED) { - typedef Box_intersection_d::Predicate_traits_d Traits; - box_intersection_custom_predicates_d(begin1, end1, begin2, end2, - callback, Traits(), cutoff, setting); - } else { - typedef Box_intersection_d::Predicate_traits_d Traits; - box_intersection_custom_predicates_d(begin1, end1, begin2, end2, - callback, Traits(), cutoff, setting); - } + if (topology == Box_intersection_d::CLOSED) { + typedef Box_intersection_d::Predicate_traits_d Traits; + box_intersection_custom_predicates_d(begin1, end1, begin2, end2, + callback, Traits(), cutoff, setting); + } else { + typedef Box_intersection_d::Predicate_traits_d Traits; + box_intersection_custom_predicates_d(begin1, end1, begin2, end2, + callback, Traits(), cutoff, setting); + } } -template< class RandomAccessIter1, class RandomAccessIter2, +template< class ConcurrencyTag = Sequential_tag, + class RandomAccessIter1, class RandomAccessIter2, class Callback, class BoxTraits > void box_intersection_d( RandomAccessIter1 begin1, RandomAccessIter1 end1, @@ -86,35 +258,39 @@ void box_intersection_d( Callback callback, BoxTraits box_traits, std::ptrdiff_t cutoff, Box_intersection_d::Topology topology) { - box_intersection_d( begin1, end1, begin2, end2, callback, box_traits, - cutoff, topology, Box_intersection_d::BIPARTITE); + box_intersection_d( begin1, end1, begin2, end2, callback, box_traits, + cutoff, topology, Box_intersection_d::BIPARTITE); } -template< class RandomAccessIter1, class RandomAccessIter2, +template< class ConcurrencyTag = Sequential_tag, + class RandomAccessIter1, class RandomAccessIter2, class Callback, class BoxTraits > void box_intersection_d( RandomAccessIter1 begin1, RandomAccessIter1 end1, RandomAccessIter2 begin2, RandomAccessIter2 end2, Callback callback, BoxTraits box_traits, std::ptrdiff_t cutoff) { - box_intersection_d( begin1, end1, begin2, end2, callback, box_traits, - cutoff, Box_intersection_d::CLOSED, - Box_intersection_d::BIPARTITE); + box_intersection_d( begin1, end1, begin2, end2, callback, box_traits, + cutoff, Box_intersection_d::CLOSED, + Box_intersection_d::BIPARTITE); } -template< class RandomAccessIter1, class RandomAccessIter2, + +template< class ConcurrencyTag = Sequential_tag, + class RandomAccessIter1, class RandomAccessIter2, class Callback, class BoxTraits > void box_intersection_d( RandomAccessIter1 begin1, RandomAccessIter1 end1, RandomAccessIter2 begin2, RandomAccessIter2 end2, Callback callback, BoxTraits box_traits) { - box_intersection_d( begin1, end1, begin2, end2, callback, box_traits, - 10, Box_intersection_d::CLOSED, - Box_intersection_d::BIPARTITE); + box_intersection_d( begin1, end1, begin2, end2, callback, box_traits, + 10, Box_intersection_d::CLOSED, + Box_intersection_d::BIPARTITE); } // Specialized call with default box traits. // - make all default parameters explicit overloads (workaround) -template< class RandomAccessIter1, class RandomAccessIter2, class Callback > +template< class ConcurrencyTag = Sequential_tag, + class RandomAccessIter1, class RandomAccessIter2, class Callback > void box_intersection_d( RandomAccessIter1 begin1, RandomAccessIter1 end1, RandomAccessIter2 begin2, RandomAccessIter2 end2, @@ -122,53 +298,58 @@ void box_intersection_d( Box_intersection_d::Topology topology, Box_intersection_d::Setting setting) { - typedef typename std::iterator_traits::value_type val_t; - typedef Box_intersection_d::Box_traits_d< val_t> Box_traits; - box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(), - cutoff, topology, setting); + typedef typename std::iterator_traits::value_type val_t; + typedef Box_intersection_d::Box_traits_d< val_t> Box_traits; + + box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(), + cutoff, topology, setting); } -template< class RandomAccessIter1, class RandomAccessIter2, class Callback > +template< class ConcurrencyTag = Sequential_tag, + class RandomAccessIter1, class RandomAccessIter2, class Callback > void box_intersection_d( RandomAccessIter1 begin1, RandomAccessIter1 end1, RandomAccessIter2 begin2, RandomAccessIter2 end2, Callback callback, std::ptrdiff_t cutoff, Box_intersection_d::Topology topology) { - typedef typename std::iterator_traits::value_type val_t; - typedef Box_intersection_d::Box_traits_d< val_t> Box_traits; - box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(), - cutoff, topology, Box_intersection_d::BIPARTITE); + typedef typename std::iterator_traits::value_type val_t; + typedef Box_intersection_d::Box_traits_d< val_t> Box_traits; + + box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(), + cutoff, topology, Box_intersection_d::BIPARTITE); } -template< class RandomAccessIter1, class RandomAccessIter2, class Callback > +template< class ConcurrencyTag = Sequential_tag, + class RandomAccessIter1, class RandomAccessIter2, class Callback > void box_intersection_d( RandomAccessIter1 begin1, RandomAccessIter1 end1, RandomAccessIter2 begin2, RandomAccessIter2 end2, Callback callback, std::ptrdiff_t cutoff) { - typedef typename std::iterator_traits::value_type val_t; - typedef Box_intersection_d::Box_traits_d< val_t> Box_traits; - box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(), - cutoff, Box_intersection_d::CLOSED, - Box_intersection_d::BIPARTITE); + typedef typename std::iterator_traits::value_type val_t; + typedef Box_intersection_d::Box_traits_d< val_t> Box_traits; + box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(), + cutoff, Box_intersection_d::CLOSED, + Box_intersection_d::BIPARTITE); } -template< class RandomAccessIter1, class RandomAccessIter2, class Callback > +template< class ConcurrencyTag = Sequential_tag, + class RandomAccessIter1, class RandomAccessIter2, class Callback > void box_intersection_d( RandomAccessIter1 begin1, RandomAccessIter1 end1, RandomAccessIter2 begin2, RandomAccessIter2 end2, Callback callback) { - typedef typename std::iterator_traits::value_type val_t; - typedef Box_intersection_d::Box_traits_d< val_t> Box_traits; - box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(), - 10, Box_intersection_d::CLOSED, - Box_intersection_d::BIPARTITE); + typedef typename std::iterator_traits::value_type val_t; + typedef Box_intersection_d::Box_traits_d< val_t> Box_traits; + box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(), + 10, Box_intersection_d::CLOSED, + Box_intersection_d::BIPARTITE); } - // Generic call with box traits parameter, specialized for self-intersection. // - make all default parameters explicit overloads (workaround) -template< class RandomAccessIter, class Callback, class BoxTraits > +template< class ConcurrencyTag = Sequential_tag, + class RandomAccessIter, class Callback, class BoxTraits > void box_self_intersection_d( RandomAccessIter begin, RandomAccessIter end, Callback callback, @@ -176,49 +357,52 @@ void box_self_intersection_d( std::ptrdiff_t cutoff, Box_intersection_d::Topology topology) { - // Copying rather than calling 'box_intersection_d(begin, end, begin, end, ...' - // is necessary because the 'std::partition' and range splits on the first range - // would be messed up by sorts on the second range otherwise. - typedef typename std::iterator_traits::value_type val_t; - std::vector< val_t> i( begin, end); - box_intersection_d( begin, end, i.begin(), i.end(), - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); + // Copying rather than calling 'box_intersection_d(begin, end, begin, end, ...' + // is necessary because the 'std::partition' and range splits on the first range + // would be messed up by sorts on the second range otherwise. + typedef typename std::iterator_traits::value_type val_t; + std::vector< val_t> i( begin, end); + + box_intersection_d( begin, end, i.begin(), i.end(), + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); } -template< class RandomAccessIter, class Callback, class BoxTraits > +template< class ConcurrencyTag = Sequential_tag, + class RandomAccessIter, class Callback, class BoxTraits > void box_self_intersection_d( RandomAccessIter begin, RandomAccessIter end, Callback callback, BoxTraits box_traits, std::ptrdiff_t cutoff) { - return box_self_intersection_d(begin, end, callback, box_traits, cutoff, - Box_intersection_d::CLOSED); + return box_self_intersection_d(begin, end, callback, box_traits, cutoff, + Box_intersection_d::CLOSED); } -template< class RandomAccessIter, class Callback, class BoxTraits > +template< class ConcurrencyTag = Sequential_tag, + class RandomAccessIter, class Callback, class BoxTraits > void box_self_intersection_d( RandomAccessIter begin, RandomAccessIter end, Callback callback, BoxTraits box_traits) { - return box_self_intersection_d(begin, end, callback, box_traits, 10); + return box_self_intersection_d(begin, end, callback, box_traits, 10); } // Specialized call with default box traits, specialized for self-intersection. // - make all default parameters explicit overloads (workaround) -template< class RandomAccessIter, class Callback > +template< class ConcurrencyTag = Sequential_tag, class RandomAccessIter, class Callback > void box_self_intersection_d( RandomAccessIter begin, RandomAccessIter end, Callback callback) { typedef typename std::iterator_traits::value_type val_t; typedef Box_intersection_d::Box_traits_d< val_t> Box_traits; - box_self_intersection_d(begin, end, callback, Box_traits()); + box_self_intersection_d(begin, end, callback, Box_traits()); } -template< class RandomAccessIter, class Callback > +template< class ConcurrencyTag = Sequential_tag, class RandomAccessIter, class Callback > void box_self_intersection_d( RandomAccessIter begin, RandomAccessIter end, Callback callback, @@ -226,10 +410,10 @@ void box_self_intersection_d( { typedef typename std::iterator_traits::value_type val_t; typedef Box_intersection_d::Box_traits_d< val_t> Box_traits; - box_self_intersection_d(begin, end, callback, Box_traits(), cutoff); + box_self_intersection_d(begin, end, callback, Box_traits(), cutoff); } -template< class RandomAccessIter, class Callback > + template< class ConcurrencyTag = Sequential_tag, class RandomAccessIter, class Callback > void box_self_intersection_d( RandomAccessIter begin, RandomAccessIter end, Callback callback, @@ -238,28 +422,27 @@ void box_self_intersection_d( { typedef typename std::iterator_traits::value_type val_t; typedef Box_intersection_d::Box_traits_d< val_t> Box_traits; - box_self_intersection_d(begin, end, callback, - Box_traits(), cutoff, topology ); + box_self_intersection_d(begin, end, callback, + Box_traits(), cutoff, topology ); } - // Generic call for trivial all-pairs algorithm with box traits parameter. // - make all default parameters explicit overloads (workaround) template< class ForwardIter1, class ForwardIter2, class Callback, class BoxTraits > -void box_intersection_all_pairs_d( +void box_intersection_all_pairs_d( ForwardIter1 begin1, ForwardIter1 end1, ForwardIter2 begin2, ForwardIter2 end2, Callback callback, BoxTraits) { typedef Box_intersection_d::Predicate_traits_d Traits; - Box_intersection_d::all_pairs( begin1, end1, begin2, end2, + Box_intersection_d::all_pairs( begin1, end1, begin2, end2, callback, Traits()); } template< class ForwardIter1, class ForwardIter2, class Callback, class BoxTraits > -void box_intersection_all_pairs_d( +void box_intersection_all_pairs_d( ForwardIter1 begin1, ForwardIter1 end1, ForwardIter2 begin2, ForwardIter2 end2, Callback callback, BoxTraits, @@ -269,18 +452,18 @@ void box_intersection_all_pairs_d( bool complete_case = (setting != Box_intersection_d::BIPARTITE); if (topology == Box_intersection_d::CLOSED) { typedef Box_intersection_d::Predicate_traits_d Traits; - Box_intersection_d::all_pairs( begin1, end1, begin2, end2, + Box_intersection_d::all_pairs( begin1, end1, begin2, end2, callback, Traits(), complete_case); } else { typedef Box_intersection_d::Predicate_traits_d Traits; - Box_intersection_d::all_pairs( begin1, end1, begin2, end2, + Box_intersection_d::all_pairs( begin1, end1, begin2, end2, callback, Traits(), complete_case); } } template< class ForwardIter1, class ForwardIter2, class Callback, class BoxTraits > -void box_intersection_all_pairs_d( +void box_intersection_all_pairs_d( ForwardIter1 begin1, ForwardIter1 end1, ForwardIter2 begin2, ForwardIter2 end2, Callback callback, BoxTraits traits, @@ -293,20 +476,20 @@ void box_intersection_all_pairs_d( // Specialized call for trivial all-pairs algorithm with default box traits. // - make all default parameters explicit overloads (workaround) template< class ForwardIter1, class ForwardIter2, class Callback > -void box_intersection_all_pairs_d( +void box_intersection_all_pairs_d( ForwardIter1 begin1, ForwardIter1 end1, ForwardIter2 begin2, ForwardIter2 end2, Callback callback) { typedef typename std::iterator_traits::value_type val_t; typedef Box_intersection_d::Box_traits_d< val_t> Box_traits; - box_intersection_all_pairs_d( begin1, end1, begin2, end2, - callback, Box_traits(), - Box_intersection_d::CLOSED ); + box_intersection_all_pairs_d( begin1, end1, begin2, end2, + callback, Box_traits(), + Box_intersection_d::CLOSED ); } template< class ForwardIter1, class ForwardIter2, class Callback > -void box_intersection_all_pairs_d( +void box_intersection_all_pairs_d( ForwardIter1 begin1, ForwardIter1 end1, ForwardIter2 begin2, ForwardIter2 end2, Callback callback, @@ -314,12 +497,12 @@ void box_intersection_all_pairs_d( { typedef typename std::iterator_traits::value_type val_t; typedef Box_intersection_d::Box_traits_d< val_t> Box_traits; - box_intersection_all_pairs_d( begin1, end1, begin2, end2, + box_intersection_all_pairs_d( begin1, end1, begin2, end2, callback, Box_traits(), topology); } template< class ForwardIter1, class ForwardIter2, class Callback > -void box_intersection_all_pairs_d( +void box_intersection_all_pairs_d( ForwardIter1 begin1, ForwardIter1 end1, ForwardIter2 begin2, ForwardIter2 end2, Callback callback, @@ -328,7 +511,7 @@ void box_intersection_all_pairs_d( { typedef typename std::iterator_traits::value_type val_t; typedef Box_intersection_d::Box_traits_d< val_t> Box_traits; - box_intersection_all_pairs_d( begin1, end1, begin2, end2, + box_intersection_all_pairs_d( begin1, end1, begin2, end2, callback, Box_traits(), topology, setting); } @@ -336,7 +519,7 @@ void box_intersection_all_pairs_d( // specialized for self-intersection test. // - make all default parameters explicit overloads (workaround) template< class ForwardIter, class Callback, class BoxTraits > -void box_self_intersection_all_pairs_d( +void box_self_intersection_all_pairs_d( ForwardIter begin1, ForwardIter end1, Callback callback, BoxTraits /* traits */) { typedef Box_intersection_d::Predicate_traits_d Traits; @@ -344,7 +527,7 @@ void box_self_intersection_all_pairs_d( } template< class ForwardIter, class Callback, class BoxTraits > -void box_self_intersection_all_pairs_d( +void box_self_intersection_all_pairs_d( ForwardIter begin1, ForwardIter end1, Callback callback, BoxTraits, Box_intersection_d::Topology topology) { @@ -361,17 +544,17 @@ void box_self_intersection_all_pairs_d( // specialized for self-intersection test. // - make all default parameters explicit overloads (workaround) template< class ForwardIter, class Callback > -void box_self_intersection_all_pairs_d( +void box_self_intersection_all_pairs_d( ForwardIter begin1, ForwardIter end1, Callback callback) { typedef typename std::iterator_traits::value_type val_t; typedef Box_intersection_d::Box_traits_d< val_t> Box_traits; - box_self_intersection_all_pairs_d( begin1, end1, callback, Box_traits(), - Box_intersection_d::CLOSED ); + box_self_intersection_all_pairs_d( begin1, end1, callback, Box_traits(), + Box_intersection_d::CLOSED ); } template< class ForwardIter, class Callback > -void box_self_intersection_all_pairs_d( +void box_self_intersection_all_pairs_d( ForwardIter begin1, ForwardIter end1, Callback callback, Box_intersection_d::Topology topology) { diff --git a/Box_intersection_d/test/Box_intersection_d/CMakeLists.txt b/Box_intersection_d/test/Box_intersection_d/CMakeLists.txt index 1beb02ff8d0..6f4ec1704ce 100644 --- a/Box_intersection_d/test/Box_intersection_d/CMakeLists.txt +++ b/Box_intersection_d/test/Box_intersection_d/CMakeLists.txt @@ -5,20 +5,23 @@ cmake_minimum_required(VERSION 3.1...3.15) project( Box_intersection_d_Tests ) +find_package( CGAL QUIET ) -find_package(CGAL QUIET) +find_package( TBB ) if ( CGAL_FOUND ) - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() + create_single_source_cgal_program( "automated_test.cpp" ) + create_single_source_cgal_program( "benchmark_box_intersection.cpp" ) + create_single_source_cgal_program( "random_set_test.cpp" ) + create_single_source_cgal_program( "test_box_grid.cpp" ) + if( TBB_FOUND ) + CGAL_target_use_TBB( test_box_grid ) + else() + message( STATUS "NOTICE: Intel TBB was not found. Sequential code will be used." ) + endif() else() - message(STATUS "This program requires the CGAL library, and will not be compiled.") - endif() diff --git a/Box_intersection_d/test/Box_intersection_d/test_box_grid.cpp b/Box_intersection_d/test/Box_intersection_d/test_box_grid.cpp index 4d51695b9bd..0b06520214f 100644 --- a/Box_intersection_d/test/Box_intersection_d/test_box_grid.cpp +++ b/Box_intersection_d/test/Box_intersection_d/test_box_grid.cpp @@ -1,217 +1,297 @@ // file: test/Box_intersection_d/box_grid.C // similar to examples/Box_intersection_d/box_grid.C but stricter in checking // and more extensive in what is tested. -#include -#include -#include -#include -#include -typedef CGAL::Box_intersection_d::Box_d Box; +#include +#include + +#include +#include +#include +#include + +#ifdef CGAL_LINKED_WITH_TBB +#include +#endif + +typedef CGAL::Box_intersection_d::Box_d Box; // coordinates for 9 boxes of a grid int p[9*4] = { 0,0,1,1, 1,0,2,1, 2,0,3,1, // lower 0,1,1,2, 1,1,2,2, 2,1,3,2, // middle 0,2,1,3, 1,2,2,3, 2,2,3,3};// upper // 9 boxes + 2 selected boxes as query; center and upper right -Box init_boxes[11] = { Box( p, p+ 2), Box( p+ 4, p+ 6), Box( p+ 8, p+10), - Box( p+12, p+14), Box( p+16, p+18), Box( p+20, p+22), - Box( p+24, p+26), Box( p+28, p+30), Box( p+32, p+34), - Box( p+16, p+18), Box( p+32, p+34)}; +const Box init_boxes[11] = { Box( p, p+ 2), Box( p+ 4, p+ 6), Box( p+ 8, p+10), + Box( p+12, p+14), Box( p+16, p+18), Box( p+20, p+22), + Box( p+24, p+26), Box( p+28, p+30), Box( p+32, p+34), + Box( p+16, p+18), Box( p+32, p+34)}; Box boxes[11]; Box* query = boxes+9; -void init() { - for ( int i = 0; i < 11; ++i) - boxes[i] = init_boxes[i]; +void init() +{ + for ( int i = 0; i < 11; ++i) + boxes[i] = init_boxes[i]; } -void check_result( const char* text, std::vector& result, - const std::size_t* check, std::size_t size) { - // sort, show, and check result - std::sort( result.begin(), result.end()); - std::cout << text << ": got " << result.size() << " elements, expected " - << size << " elements\n got : "; - std::copy( result.begin(), result.end(), - std::ostream_iterator( std::cout, ",")); - std::cout << "\n expected: "; - std::copy( check, check+size, - std::ostream_iterator( std::cout, ",")); - std::cout << '\n' << std::endl; - assert( result.size() == size - && std::equal( check, check+size, result.begin())); +template +void check_result( const char* text, + Vector& result, + const std::size_t* check, + std::size_t size) +{ + // sort, show, and check result + std::sort( result.begin(), result.end()); + std::cout << text << ": got " << result.size() << " elements, expected " + << size << " elements\n got : "; + std::copy( result.begin(), result.end(), + std::ostream_iterator( std::cout, ",")); + std::cout << "\n expected: "; + std::copy( check, check+size, + std::ostream_iterator( std::cout, ",")); + std::cout << '\n' << std::endl; + assert( result.size() == size + && std::equal( check, check+size, result.begin())); } // callback function object writing results to an output iterator -template -struct Report { - OutputIterator it; - Report( OutputIterator i) : it(i) {} // store iterator in object - // We encode both id-numbers in a single number, a.id() + 100 * b.id(), - // and write that number to the output iterator. - void operator()( const Box& a, const Box& b) { *it++ = a.id()+100*b.id(); } +template +struct Report +{ + Container& c_; + + Report(Container& c) : c_(c) {} // store iterator in object + // We encode both id-numbers in a single number, a.id() + 100 * b.id(), + // and write that number to the output iterator. + void operator()(const Box& a, const Box& b) { c_.push_back(a.id()+100*b.id()); } + void operator()(const Box* a, const Box* b) { c_.push_back(a->id()+100*b->id()); } }; -template // helper function to create the function object -Report report( Iter it) { return Report(it); } + +template // helper function to create the function object +Report report(Container& c) { return Report(c); } // --------------------------------------------------------------------- // box_intersection_d // run the intersection algorithms and store results in a vector // --------------------------------------------------------------------- -void test_box_intersection() { - // intersect 3x3 with 2 query boxes, closed boxes - init(); - std::vector result; - CGAL::box_intersection_d( boxes, boxes+9, query, query+2, - report( std::back_inserter( result))); - std::size_t check1[13] = {900,901,902,903,904,905,906,907,908, - 1004,1005,1007,1008}; - check_result( "Box inters. 3x3, 2, closed", result, check1, 13); +void test_box_intersection() +{ +#ifdef CGAL_LINKED_WITH_TBB + tbb::concurrent_vector result; +#else + std::vector result; +#endif - // intersect 3x3 with 2 query boxes, half-open boxes and changed cutoff - init(); - result.clear(); - CGAL::box_intersection_d( boxes, boxes+9, query, query+2, - report( std::back_inserter( result)), - std::ptrdiff_t(1), - CGAL::Box_intersection_d::HALF_OPEN); - std::size_t check2[2] = {904,1008}; - check_result( "Box inters. 3x3, 2, half-open", result, check2, 2); + // Some degenerate cases + init(); + CGAL::box_intersection_d(boxes, boxes, boxes, boxes, + report(result)); + assert(result.empty()); - // self intersect 3x2, closed boxes - init(); - result.clear(); - CGAL::box_self_intersection_d( boxes, boxes+6, - report( std::back_inserter( result))); - std::size_t check3[11] = {1,3,4,102,103,104,105,204,205,304,405}; - check_result( "Box self inters. 3x2, closed", result, check3, 11); + init(); + CGAL::box_intersection_d(boxes, boxes, query, query + 1, + report(result)); + assert(result.empty()); - // self intersect 3x2, half-open boxes - init(); - result.clear(); - CGAL::box_self_intersection_d( boxes, boxes+6, - report( std::back_inserter( result)), - std::ptrdiff_t(1), - CGAL::Box_intersection_d::HALF_OPEN); - std::size_t check4[1] = {9999}; - check_result( "Box self inters. 3x2, half-open", result, check4, 0); + init(); + CGAL::box_intersection_d(boxes, boxes + 3, query, query, + report(result)); + assert(result.empty()); - // self intersect 3x3+2 query boxes, half-open boxes - init(); - result.clear(); - CGAL::box_self_intersection_d( boxes, boxes+11, - report( std::back_inserter( result)), - std::ptrdiff_t(1), - CGAL::Box_intersection_d::HALF_OPEN); - std::size_t check5[2] = {409,810}; - check_result( "Box self inters. 3x3+2, half-open", result, check5, 2); + // With pointers + init(); + std::vector range_1 = {{ boxes, boxes+1, boxes+2, boxes+3, boxes+4, boxes+5, + boxes+6, boxes+7, boxes+8 }}; + std::vector range_2 = {{ query, query+1 }}; - // self intersect 3x3+2 query boxes, half-open boxes, full function interf. - // tests also mixed types for the two iterator ranges - init(); - result.clear(); - std::vector boxes2( boxes, boxes+11); - CGAL::box_intersection_d( boxes, boxes+11, boxes2.begin(), boxes2.end(), - report( std::back_inserter( result)), - std::ptrdiff_t(1), - CGAL::Box_intersection_d::HALF_OPEN, - CGAL::Box_intersection_d::COMPLETE); - check_result( "Box inters. 3x3+2, half-open", result, check5, 2); - - // compare this with the bipartite case - // self intersect 3x3+2 query boxes, half-open boxes - // tests also mixed types for the two iterator ranges - init(); - result.clear(); - boxes2 = std::vector( boxes, boxes+11); - CGAL::box_intersection_d( boxes, boxes+11, boxes2.begin(), boxes2.end(), - report( std::back_inserter( result)), - std::ptrdiff_t(20), - CGAL::Box_intersection_d::HALF_OPEN, - CGAL::Box_intersection_d::BIPARTITE); - std::size_t check6[4] = {409,810,904,1008}; - check_result( "Box inters. 3x3+2, half-open", result, check6, 4); + CGAL::box_intersection_d(range_1.begin(), range_1.begin(), + range_2.begin(), range_2.end(), + report(result)); + assert(result.empty()); + + CGAL::box_intersection_d(range_1.begin(), range_1.end(), + range_2.begin(), range_2.begin(), + report(result)); + assert(result.empty()); + + CGAL::box_intersection_d(range_1.begin(), range_1.end(), + range_2.begin(), range_2.end(), + report(result)); + std::size_t check0[13] = {900,901,902,903,904,905,906,907,908, + 1004,1005,1007,1008}; + check_result( "Box inters. 3x3 (ptr), 2, closed", result, check0, 13); + + // intersect 3x3 with 2 query boxes, closed boxes + init(); + result.clear(); + CGAL::box_intersection_d(boxes, boxes+9, query, query+1, report(result)); + std::size_t check1[13] = {900,901,902,903,904,905,906,907,908}; + check_result( "Box inters. 3x3, 2, closed", result, check1, 9); + + // intersect 3x3 with 2 query boxes, closed boxes + init(); + result.clear(); + CGAL::box_intersection_d(boxes, boxes+9, query, query+2, report(result)); + std::size_t check1bis[13] = {900,901,902,903,904,905,906,907,908, + 1004,1005,1007,1008}; + check_result( "Box inters. 3x3, 2, closed", result, check1bis, 13); + + // intersect 3x3 with 2 query boxes, half-open boxes and changed cutoff + init(); + result.clear(); + CGAL::box_intersection_d( boxes, boxes+9, query, query+2, + report(result), + std::ptrdiff_t(1), + CGAL::Box_intersection_d::HALF_OPEN); + std::size_t check2[2] = {904,1008}; + check_result( "Box inters. 3x3, 2, half-open", result, check2, 2); + + // intersect 3x3 with 2 query boxes, half-open boxes and changed cutoff (reversed) + init(); + result.clear(); + CGAL::box_intersection_d( query, query+2, boxes, boxes+9, + report(result), + std::ptrdiff_t(1), + CGAL::Box_intersection_d::HALF_OPEN); + std::size_t check2bis[2] = {409,810}; + check_result( "Box inters. 3x3 (reversed), 2, half-open", result, check2bis, 2); + + // self intersect 3x2, closed boxes + init(); + result.clear(); + CGAL::box_self_intersection_d( boxes, boxes+6, + report(result)); + std::size_t check3[11] = {1,3,4,102,103,104,105,204,205,304,405}; + check_result( "Box self inters. 3x2, closed", result, check3, 11); + + // self intersect 3x2, half-open boxes + init(); + result.clear(); + CGAL::box_self_intersection_d( boxes, boxes+6, + report(result), + std::ptrdiff_t(1), + CGAL::Box_intersection_d::HALF_OPEN); + std::size_t check4[1] = {9999}; + check_result( "Box self inters. 3x2, half-open", result, check4, 0); + + // self intersect 3x3+2 query boxes, half-open boxes + init(); + result.clear(); + CGAL::box_self_intersection_d( boxes, boxes+11, + report(result), + std::ptrdiff_t(1), + CGAL::Box_intersection_d::HALF_OPEN); + std::size_t check5[2] = {409,810}; + check_result( "Box self inters. 3x3+2, half-open", result, check5, 2); + + // self intersect 3x3+2 query boxes, half-open boxes, full function interf. + // tests also mixed types for the two iterator ranges + init(); + result.clear(); + std::vector boxes2( boxes, boxes+11); + CGAL::box_intersection_d( boxes, boxes+11, boxes2.begin(), boxes2.end(), + report(result), + std::ptrdiff_t(1), + CGAL::Box_intersection_d::HALF_OPEN, + CGAL::Box_intersection_d::COMPLETE); + check_result( "Box inters. 3x3+2, half-open", result, check5, 2); + + // compare this with the bipartite case + // self intersect 3x3+2 query boxes, half-open boxes + // tests also mixed types for the two iterator ranges + init(); + result.clear(); + boxes2 = std::vector( boxes, boxes+11); + CGAL::box_intersection_d( boxes, boxes+11, boxes2.begin(), boxes2.end(), + report(result), + std::ptrdiff_t(20), + CGAL::Box_intersection_d::HALF_OPEN, + CGAL::Box_intersection_d::BIPARTITE); + std::size_t check6[4] = {409,810,904,1008}; + check_result( "Box inters. 3x3+2, half-open", result, check6, 4); } // --------------------------------------------------------------------- // box_intersection_all_pairs_d // run the intersection algorithms and store results in a vector // --------------------------------------------------------------------- -void test_box_intersection_all_pairs() { - // intersect 3x3 with 2 query boxes, closed boxes - init(); - std::vector result; - CGAL::box_intersection_all_pairs_d( boxes, boxes+9, query, query+2, - report( std::back_inserter( result))); - std::size_t check1[13] = {900,901,902,903,904,905,906,907,908, - 1004,1005,1007,1008}; - check_result( "All-pairs inters. 3x3, 2, closed", result, check1, 13); +void test_box_intersection_all_pairs() +{ + // intersect 3x3 with 2 query boxes, closed boxes + init(); + std::vector result; + CGAL::box_intersection_all_pairs_d( boxes, boxes+9, query, query+2, + report(result)); + std::size_t check1[13] = {900,901,902,903,904,905,906,907,908, + 1004,1005,1007,1008}; + check_result( "All-pairs inters. 3x3, 2, closed", result, check1, 13); - // intersect 3x3 with 2 query boxes, half-open boxes - init(); - result.clear(); - CGAL::box_intersection_all_pairs_d( boxes, boxes+9, query, query+2, - report( std::back_inserter( result)), - CGAL::Box_intersection_d::HALF_OPEN); - std::size_t check2[2] = {904,1008}; - check_result( "All-pairs inters. 3x3, 2, half-open", result, check2, 2); + // intersect 3x3 with 2 query boxes, half-open boxes + init(); + result.clear(); + CGAL::box_intersection_all_pairs_d( boxes, boxes+9, query, query+2, + report(result), + CGAL::Box_intersection_d::HALF_OPEN); + std::size_t check2[2] = {904,1008}; + check_result( "All-pairs inters. 3x3, 2, half-open", result, check2, 2); - // self intersect 3x2, closed boxes - init(); - result.clear(); - CGAL::box_self_intersection_all_pairs_d( boxes, boxes+6, - report( std::back_inserter( result))); - std::size_t check3[11] = {100,201,300,301,400,401,402,403,501,502,504}; - check_result( "All-pairs self inters. 3x2, closed", result, check3, 11); + // self intersect 3x2, closed boxes + init(); + result.clear(); + CGAL::box_self_intersection_all_pairs_d( boxes, boxes+6, + report(result)); + std::size_t check3[11] = {100,201,300,301,400,401,402,403,501,502,504}; + check_result( "All-pairs self inters. 3x2, closed", result, check3, 11); - // self intersect 3x2, half-open boxes - init(); - result.clear(); - CGAL::box_self_intersection_all_pairs_d( boxes, boxes+6, - report( std::back_inserter( result)), - CGAL::Box_intersection_d::HALF_OPEN); - std::size_t check4[1] = {9999}; - check_result( "All-pairs self inters. 3x2, half-open", result, check4, 0); + // self intersect 3x2, half-open boxes + init(); + result.clear(); + CGAL::box_self_intersection_all_pairs_d( boxes, boxes+6, + report(result), + CGAL::Box_intersection_d::HALF_OPEN); + std::size_t check4[1] = {9999}; + check_result( "All-pairs self inters. 3x2, half-open", result, check4, 0); - // self intersect 3x3+2 query boxes, half-open boxes - init(); - result.clear(); - CGAL::box_self_intersection_all_pairs_d( boxes, boxes+11, - report( std::back_inserter( result)), - CGAL::Box_intersection_d::HALF_OPEN); - std::size_t check5[2] = {904,1008}; - check_result( "All-pairs self inters. 3x3+2, half-open", result, check5,2); + // self intersect 3x3+2 query boxes, half-open boxes + init(); + result.clear(); + CGAL::box_self_intersection_all_pairs_d( boxes, boxes+11, + report(result), + CGAL::Box_intersection_d::HALF_OPEN); + std::size_t check5[2] = {904,1008}; + check_result( "All-pairs self inters. 3x3+2, half-open", result, check5,2); - // self intersect 3x3+2 query boxes, half-open boxes, full function interf. - // tests also mixed types for the two iterator ranges - init(); - result.clear(); - std::vector boxes2( boxes, boxes+11); - CGAL::box_intersection_all_pairs_d( boxes, boxes+11, - boxes2.begin(), boxes2.end(), - report( std::back_inserter( result)), - CGAL::Box_intersection_d::HALF_OPEN, - CGAL::Box_intersection_d::COMPLETE); - check_result( "All-pairs self inters. 3x3+2, half-open", result, check5,2); - - // compare this with the bipartite case - // self intersect 3x3+2 query boxes, half-open boxes - // tests also mixed types for the two iterator ranges - init(); - result.clear(); - boxes2 = std::vector( boxes, boxes+11); - CGAL::box_intersection_all_pairs_d( boxes, boxes+11, - boxes2.begin(), boxes2.end(), - report( std::back_inserter( result)), - CGAL::Box_intersection_d::HALF_OPEN, - CGAL::Box_intersection_d::BIPARTITE); - std::size_t check6[4] = {409,810,904,1008}; - check_result( "All-pairs inters. 3x3+2, half-open", result, check6, 4); + // self intersect 3x3+2 query boxes, half-open boxes, full function interf. + // tests also mixed types for the two iterator ranges + init(); + result.clear(); + std::vector boxes2( boxes, boxes+11); + CGAL::box_intersection_all_pairs_d( boxes, boxes+11, + boxes2.begin(), boxes2.end(), + report(result), + CGAL::Box_intersection_d::HALF_OPEN, + CGAL::Box_intersection_d::COMPLETE); + check_result( "All-pairs self inters. 3x3+2, half-open", result, check5,2); + + // compare this with the bipartite case + // self intersect 3x3+2 query boxes, half-open boxes + // tests also mixed types for the two iterator ranges + init(); + result.clear(); + boxes2 = std::vector( boxes, boxes+11); + CGAL::box_intersection_all_pairs_d( boxes, boxes+11, + boxes2.begin(), boxes2.end(), + report(result), + CGAL::Box_intersection_d::HALF_OPEN, + CGAL::Box_intersection_d::BIPARTITE); + std::size_t check6[4] = {409,810,904,1008}; + check_result( "All-pairs inters. 3x3+2, half-open", result, check6, 4); } +int main() +{ + test_box_intersection(); + test_box_intersection_all_pairs(); -int main() { - test_box_intersection(); - test_box_intersection_all_pairs(); - return 0; + return EXIT_SUCCESS; } diff --git a/CGAL_ImageIO/include/CGAL/read_vtk_image_data.h b/CGAL_ImageIO/include/CGAL/read_vtk_image_data.h index a0e892fb416..3dee3352a19 100644 --- a/CGAL_ImageIO/include/CGAL/read_vtk_image_data.h +++ b/CGAL_ImageIO/include/CGAL/read_vtk_image_data.h @@ -76,6 +76,10 @@ read_vtk_image_data(vtkImageData* vtk_image, Image_3::Own owning = Image_3::OWN_ image->wdim = imageio_type.wdim; image->wordKind = imageio_type.wordKind; image->sign = imageio_type.sign; + if (!vtk_image->GetPointData() || !vtk_image->GetPointData()->GetScalars()) { + ::_freeImage(image); + return Image_3(); + } CGAL_assertion(vtk_image->GetPointData()->GetScalars()->GetNumberOfTuples() == dims[0]*dims[1]*dims[2]); if(owning == Image_3::OWN_THE_DATA) { image->data = ::ImageIO_alloc(dims[0]*dims[1]*dims[2]*image->wdim); diff --git a/CGAL_ipelets/demo/CGAL_ipelets/CMakeLists.txt b/CGAL_ipelets/demo/CGAL_ipelets/CMakeLists.txt index 64206c30223..a764689a9d9 100644 --- a/CGAL_ipelets/demo/CGAL_ipelets/CMakeLists.txt +++ b/CGAL_ipelets/demo/CGAL_ipelets/CMakeLists.txt @@ -27,9 +27,7 @@ if ( CGAL_FOUND ) include(${CGAL_USE_FILE}) find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) - if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - else() + if (NOT EIGEN3_FOUND) message(STATUS "NOTICE: This project requires the Eigen library, and will not be compiled.") return() endif() @@ -143,6 +141,7 @@ if ( CGAL_FOUND ) add_library(CGAL_${IPELET} MODULE ${IPELET}.cpp) add_to_cached_list(CGAL_EXECUTABLE_TARGETS CGAL_${IPELET}) target_link_libraries(CGAL_${IPELET} PRIVATE CGAL::CGAL ${IPE_LIBRARIES}) + CGAL_target_use_Eigen(CGAL_${IPELET}) if ( IPELET_INSTALL_DIR ) install(TARGETS CGAL_${IPELET} DESTINATION ${IPELET_INSTALL_DIR}) if (WITH_IPE_7) @@ -153,12 +152,13 @@ if ( CGAL_FOUND ) endforeach(IPELET) if(CGAL_Core_FOUND) target_link_libraries(CGAL_cone_spanners PRIVATE CGAL::CGAL_Core) + CGAL_target_use_Eigen(CGAL_cone_spanners) endif() #example in doc not installed add_library(simple_triangulation MODULE simple_triangulation.cpp) add_to_cached_list(CGAL_EXECUTABLE_TARGETS simple_triangulation) target_link_libraries(simple_triangulation ${IPE_LIBRARIES}) - + CGAL_target_use_Eigen(simple_triangulation) cgal_add_compilation_test(simple_triangulation) else() diff --git a/Cartesian_kernel/include/CGAL/Cartesian/Point_2.h b/Cartesian_kernel/include/CGAL/Cartesian/Point_2.h index 92985777bbb..028c772c102 100644 --- a/Cartesian_kernel/include/CGAL/Cartesian/Point_2.h +++ b/Cartesian_kernel/include/CGAL/Cartesian/Point_2.h @@ -50,6 +50,15 @@ public: PointC2(const FT &hx, const FT &hy, const FT &hw) : base(hx, hy, hw) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.base, b.base); + } + const FT& x() const { return base.x(); diff --git a/Cartesian_kernel/include/CGAL/Cartesian/Point_3.h b/Cartesian_kernel/include/CGAL/Cartesian/Point_3.h index 614ec31fcc5..b46ab99284b 100644 --- a/Cartesian_kernel/include/CGAL/Cartesian/Point_3.h +++ b/Cartesian_kernel/include/CGAL/Cartesian/Point_3.h @@ -24,6 +24,7 @@ namespace CGAL { template < class R_ > class PointC3 { + typedef PointC3 Self; typedef typename R_::Vector_3 Vector_3; typedef typename R_::Point_3 Point_3; typedef typename R_::Aff_transformation_3 Aff_transformation_3; @@ -47,6 +48,15 @@ public: PointC3(const FT &x, const FT &y, const FT &z, const FT &w) : base(x, y, z, w) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.base, b.base); + } + const FT & x() const { return base.x(); diff --git a/Cartesian_kernel/include/CGAL/Cartesian/Vector_2.h b/Cartesian_kernel/include/CGAL/Cartesian/Vector_2.h index 6331471dff7..01986b321a3 100644 --- a/Cartesian_kernel/include/CGAL/Cartesian/Vector_2.h +++ b/Cartesian_kernel/include/CGAL/Cartesian/Vector_2.h @@ -27,6 +27,7 @@ namespace CGAL { template < class R_ > class VectorC2 { + typedef VectorC2 Self; typedef typename R_::FT FT; typedef typename R_::Point_2 Point_2; typedef typename R_::Vector_2 Vector_2; @@ -55,6 +56,15 @@ public: : base( hw != FT(1) ? CGAL::make_array(hx/hw, hy/hw) : CGAL::make_array(hx, hy) ) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.base, b.base); + } + const FT & x() const { return CGAL::get_pointee_or_identity(base)[0]; diff --git a/Cartesian_kernel/include/CGAL/Cartesian/Vector_3.h b/Cartesian_kernel/include/CGAL/Cartesian/Vector_3.h index ccad6ad574c..72954931d0b 100644 --- a/Cartesian_kernel/include/CGAL/Cartesian/Vector_3.h +++ b/Cartesian_kernel/include/CGAL/Cartesian/Vector_3.h @@ -27,6 +27,7 @@ template < class R_ > class VectorC3 { // https://doc.cgal.org/latest/Manual/devman_code_format.html#secprogramming_conventions + typedef VectorC3 Self; typedef typename R_::FT FT_; typedef typename R_::Point_3 Point_3; typedef typename R_::Vector_3 Vector_3; @@ -70,6 +71,15 @@ public: : base( w != FT_(1) ? CGAL::make_array(x/w, y/w, z/w) : CGAL::make_array(x, y, z) ) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.base, b.base); + } + const FT_ & x() const { return get_pointee_or_identity(base)[0]; diff --git a/Circular_kernel_3/include/CGAL/Circular_kernel_3/internal_functions_on_circle_3.h b/Circular_kernel_3/include/CGAL/Circular_kernel_3/internal_functions_on_circle_3.h index 795c3209191..eb94585d053 100644 --- a/Circular_kernel_3/include/CGAL/Circular_kernel_3/internal_functions_on_circle_3.h +++ b/Circular_kernel_3/include/CGAL/Circular_kernel_3/internal_functions_on_circle_3.h @@ -179,7 +179,7 @@ namespace CGAL { } break; case BIPOLAR: - CGAL_kernel_precondition(!"This function does not accept bipolar circle as input."); + CGAL_kernel_precondition_msg(false, "This function does not accept bipolar circle as input."); } return out_it; } diff --git a/Circular_kernel_3/include/CGAL/Circular_kernel_3/internal_functions_on_circular_arc_3.h b/Circular_kernel_3/include/CGAL/Circular_kernel_3/internal_functions_on_circular_arc_3.h index 6041dd2eb6f..15d3c549c51 100644 --- a/Circular_kernel_3/include/CGAL/Circular_kernel_3/internal_functions_on_circular_arc_3.h +++ b/Circular_kernel_3/include/CGAL/Circular_kernel_3/internal_functions_on_circular_arc_3.h @@ -516,7 +516,7 @@ namespace CGAL { break; } case BIPOLAR: - CGAL_kernel_precondition(!"This function does not accept bipolar circle as input."); + CGAL_kernel_precondition_msg(false, "This function does not accept bipolar circle as input."); } return out_it; diff --git a/Classification/examples/Classification/CMakeLists.txt b/Classification/examples/Classification/CMakeLists.txt index 79ad8c5bf03..4cdfe2e2c08 100644 --- a/Classification/examples/Classification/CMakeLists.txt +++ b/Classification/examples/Classification/CMakeLists.txt @@ -5,7 +5,6 @@ cmake_minimum_required(VERSION 3.1...3.15) project( Classification_Examples ) - # CGAL and its components find_package( CGAL QUIET COMPONENTS ) @@ -22,127 +21,73 @@ if ( NOT Boost_FOUND ) return() endif() -find_package( Boost OPTIONAL_COMPONENTS serialization iostreams ) +set(Classification_dependencies_met TRUE) -if( WIN32 ) -# to avoid a warning with old cmake - set(_Boost_BZIP2_HEADERS "boost/iostreams/filter/bzip2.hpp") - set(_Boost_ZLIB_HEADERS "boost/iostreams/filter/zlib.hpp") - find_package( Boost OPTIONAL_COMPONENTS bzip2 zlib) -else() - find_package(ZLIB QUIET) +find_package( Boost OPTIONAL_COMPONENTS serialization iostreams ) +if (NOT Boost_SERIALIZATION_FOUND) + message(STATUS "NOTICE: This project requires Boost Serialization, and will not be compiled.") + set(Classification_dependencies_met FALSE) +endif() +if (NOT Boost_IOSTREAMS_FOUND) + message(STATUS "NOTICE: This project requires Boost IO Streams, and will not be compiled.") + set(Classification_dependencies_met FALSE) +endif() + +find_package(OpenCV QUIET COMPONENTS core ml) # Need core + machine learning +if (NOT OpenCV_FOUND) + message(STATUS "NOTICE: OpenCV was not found. OpenCV random forest predicate for classification won't be available.") +endif() + +find_package(TensorFlow QUIET) +if (NOT TensorFlow_FOUND) + message(STATUS "NOTICE: TensorFlow was not found. TensorFlow neural network predicate for classification won't be available.") +endif() + +find_package(Eigen3 3.1.0 REQUIRED) #(3.1.0 or greater) +if (NOT EIGEN3_FOUND) + message(STATUS "This project requires the Eigen library, and will not be compiled.") + set(Classification_dependencies_met FALSE) endif() find_package(TBB QUIET) -find_package(OpenCV QUIET COMPONENTS core ml) # Need core + machine learning - -# Use Eigen -find_package(Eigen3 3.1.0 REQUIRED) #(3.1.0 or greater) -if (NOT EIGEN3_FOUND) - message(STATUS "This project requires the Eigen library, and will not be compiled.") - return() -else() - include( ${EIGEN3_USE_FILE} ) -endif() - - -# Creating entries for all C++ files with "main" routine -# ########################################################## - -# Classification examples -set(targets - example_classification - example_ethz_random_forest - example_feature - example_generation_and_training - example_mesh_classification - example_cluster_classification) - -# Classification requires some C++11 features -set(needed_cxx_features cxx_rvalue_references cxx_variadic_templates) - -# Libraries and flags -set(classification_linked_libraries) -set(classification_compile_definitions) - - -if (Boost_SERIALIZATION_FOUND AND Boost_IOSTREAMS_FOUND) - if(TARGET Boost::serialization AND TARGET Boost::iostreams) - set(classification_linked_libraries Boost::serialization Boost::iostreams) - else() - set(classification_linked_libraries ${classification_linked_libraries} - ${Boost_SERIALIZATION_LIBRARY} - ${Boost_IOSTREAMS_LIBRARY}) - endif() -else() - if (NOT Boost_SERIALIZATION_FOUND) - message(STATUS "NOTICE: This project requires Boost Serialization, and will not be compiled.") - endif() - if (NOT Boost_IOSTREAMS_FOUND) - message(STATUS "NOTICE: This project requires Boost IO Streams, and will not be compiled.") - endif() +if (NOT Classification_dependencies_met) return() endif() -if( WIN32 ) - if (Boost_ZLIB_FOUND AND Boost_BZIP2_FOUND) - set(classification_linked_libraries ${classification_linked_libraries} - ${Boost_ZLIB_LIBRARY} ${Boost_BZIP2_LIBRARY}) - else() - message(STATUS "NOTICE: This project requires Boost ZLIB and Boost BZIP2, and will not be compiled.") - return() - endif() -else() - if(ZLIB_FOUND) - set(classification_linked_libraries ${classification_linked_libraries} ZLIB::ZLIB) - else() - message(STATUS "NOTICE: This project requires ZLIB, and will not be compiled.") - return() - endif() -endif() +create_single_source_cgal_program( "example_classification.cpp" ) +create_single_source_cgal_program( "example_ethz_random_forest.cpp" ) +create_single_source_cgal_program( "example_feature.cpp" ) +create_single_source_cgal_program( "example_generation_and_training.cpp" ) +create_single_source_cgal_program( "example_mesh_classification.cpp" ) +create_single_source_cgal_program( "example_cluster_classification.cpp" ) if (OpenCV_FOUND) - message(STATUS "Found OpenCV ${OpenCV_VERSION}") - include_directories(${OpenCV_INCLUDE_DIRS}) - set(classification_linked_libraries ${classification_linked_libraries} - ${OpenCV_LIBS}) - set(classification_compile_definitions ${classification_compile_definitions} - "-DCGAL_LINKED_WITH_OPENCV") - - set(targets ${targets} example_opencv_random_forest) -else() - message(STATUS "NOTICE: OpenCV was not found. OpenCV random forest predicate for classification won't be available.") + create_single_source_cgal_program( "example_opencv_random_forest.cpp" ) + CGAL_target_use_OpenCV(example_opencv_random_forest) endif() -find_package(TensorFlow QUIET) if (TensorFlow_FOUND) - message(STATUS "Found TensorFlow") - include_directories( ${TensorFlow_INCLUDE_DIR} ) - set(classification_linked_libraries ${classification_linked_libraries} - ${TensorFlow_LIBRARY}) - set(classification_compile_definitions ${classification_compile_definitions} - "-DCGAL_LINKED_WITH_TENSORFLOW") - - set(targets ${targets} example_tensorflow_neural_network) -else() - message(STATUS "NOTICE: TensorFlow not found, Neural Network predicate for classification won't be available.") + create_single_source_cgal_program( "example_tensorflow_neural_network.cpp" ) + CGAL_target_use_TensorFlow(example_tensorflow_neural_network) endif() - -# Creating targets with correct libraries and flags -foreach(target ${targets}) - create_single_source_cgal_program( "${target}.cpp" CXX_FEATURES ${needed_cxx_features} ) +foreach(target + example_classification + example_ethz_random_forest + example_feature + example_generation_and_training + example_mesh_classification + example_cluster_classification + example_opencv_random_forest + example_tensorflow_neural_network) if(TARGET ${target}) - target_link_libraries(${target} PUBLIC ${classification_linked_libraries}) - target_compile_definitions(${target} PUBLIC ${classification_compile_definitions}) + CGAL_target_use_Eigen(${target}) + CGAL_target_use_Boost_IOStreams(${target}) + CGAL_target_use_Boost_Serialization(${target}) if(TBB_FOUND) CGAL_target_use_TBB(${target}) endif() endif() endforeach() - - - - diff --git a/Classification/examples/Classification/example_classification.cpp b/Classification/examples/Classification/example_classification.cpp index 665fb17f064..0475fdfcfb3 100644 --- a/Classification/examples/Classification/example_classification.cpp +++ b/Classification/examples/Classification/example_classification.cpp @@ -11,16 +11,12 @@ #include #include #include - +#include #include #include -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; typedef CGAL::Simple_cartesian Kernel; typedef Kernel::Point_3 Point; diff --git a/Classification/examples/Classification/example_cluster_classification.cpp b/Classification/examples/Classification/example_cluster_classification.cpp index e4ff944803a..78f48b8ddde 100644 --- a/Classification/examples/Classification/example_cluster_classification.cpp +++ b/Classification/examples/Classification/example_cluster_classification.cpp @@ -18,11 +18,7 @@ #include #include -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; typedef CGAL::Simple_cartesian Kernel; typedef Kernel::Point_3 Point; diff --git a/Classification/include/CGAL/Classification/ETHZ/Random_forest_classifier.h b/Classification/include/CGAL/Classification/ETHZ/Random_forest_classifier.h index 513c939bb8e..62b6dc57d26 100644 --- a/Classification/include/CGAL/Classification/ETHZ/Random_forest_classifier.h +++ b/Classification/include/CGAL/Classification/ETHZ/Random_forest_classifier.h @@ -127,11 +127,7 @@ public: std::size_t num_trees = 25, std::size_t max_depth = 20) { -#ifdef CGAL_LINKED_WITH_TBB - train(ground_truth, reset_trees, num_trees, max_depth); -#else - train(ground_truth, reset_trees, num_trees, max_depth); -#endif + train(ground_truth, reset_trees, num_trees, max_depth); } /// \endcond @@ -146,7 +142,7 @@ public: label. \tparam ConcurrencyTag enables sequential versus parallel - algorithm. Possible values are `Parallel_tag` (default value is + algorithm. Possible values are `Parallel_tag` (default value if %CGAL is linked with TBB) or `Sequential_tag` (default value otherwise). diff --git a/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/forest.hpp b/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/forest.hpp index 67c4d4bb562..93af45cefd6 100644 --- a/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/forest.hpp +++ b/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/forest.hpp @@ -38,7 +38,7 @@ #include #include #include -#include +#include #endif // CGAL_LINKED_WITH_TBB diff --git a/Classification/include/CGAL/Classification/Feature_set.h b/Classification/include/CGAL/Classification/Feature_set.h index b234f380fdb..e225649cf84 100644 --- a/Classification/include/CGAL/Classification/Feature_set.h +++ b/Classification/include/CGAL/Classification/Feature_set.h @@ -19,7 +19,7 @@ #include #ifdef CGAL_LINKED_WITH_TBB -#include +#include #include #endif // CGAL_LINKED_WITH_TBB diff --git a/Classification/include/CGAL/Classification/Local_eigen_analysis.h b/Classification/include/CGAL/Classification/Local_eigen_analysis.h index b3849220d54..d25cf4cfd0b 100644 --- a/Classification/include/CGAL/Classification/Local_eigen_analysis.h +++ b/Classification/include/CGAL/Classification/Local_eigen_analysis.h @@ -34,7 +34,8 @@ #include #include #include -#include +#include + #endif // CGAL_LINKED_WITH_TBB namespace CGAL { @@ -69,7 +70,7 @@ private: PointMap m_point_map; const NeighborQuery& m_neighbor_query; float& m_mean_range; - tbb::mutex& m_mutex; + std::mutex& m_mutex; public: @@ -78,7 +79,7 @@ private: PointMap point_map, const NeighborQuery& neighbor_query, float& mean_range, - tbb::mutex& mutex) + std::mutex& mutex) : m_eigen (eigen), m_input (input), m_point_map (point_map), m_neighbor_query (neighbor_query), m_mean_range (mean_range), m_mutex (mutex) { } @@ -120,7 +121,7 @@ private: const FaceListGraph& m_input; const NeighborQuery& m_neighbor_query; float& m_mean_range; - tbb::mutex& m_mutex; + std::mutex& m_mutex; public: @@ -128,7 +129,7 @@ private: const FaceListGraph& input, const NeighborQuery& neighbor_query, float& mean_range, - tbb::mutex& mutex) + std::mutex& mutex) : m_eigen (eigen), m_input (input), m_neighbor_query (neighbor_query), m_mean_range (mean_range), m_mutex (mutex) { } @@ -225,7 +226,7 @@ public: is `CGAL::Point_3`. \tparam NeighborQuery model of `NeighborQuery` \tparam ConcurrencyTag enables sequential versus parallel - algorithm. Possible values are `Parallel_tag` (default value is %CGAL + algorithm. Possible values are `Parallel_tag` (default value if %CGAL is linked with TBB) or `Sequential_tag` (default value otherwise). \tparam DiagonalizeTraits model of `DiagonalizeTraits` used for matrix diagonalization. It can be omitted if Eigen 3 (or greater) @@ -241,10 +242,8 @@ public: typename NeighborQuery, #if defined(DOXYGEN_RUNNING) typename ConcurrencyTag, -#elif defined(CGAL_LINKED_WITH_TBB) - typename ConcurrencyTag = CGAL::Parallel_tag, #else - typename ConcurrencyTag = CGAL::Sequential_tag, + typename ConcurrencyTag = CGAL::Parallel_if_available_tag, #endif #if defined(DOXYGEN_RUNNING) typename DiagonalizeTraits> @@ -271,7 +270,7 @@ public: #else if (boost::is_convertible::value) { - tbb::mutex mutex; + std::mutex mutex; Compute_eigen_values f(out, input, point_map, neighbor_query, out.m_content->mean_range, mutex); tbb::parallel_for(tbb::blocked_range(0, input.size ()), f); @@ -309,7 +308,7 @@ public: \tparam FaceListGraph model of `FaceListGraph`. \tparam NeighborQuery model of `NeighborQuery` \tparam ConcurrencyTag enables sequential versus parallel - algorithm. Possible values are `Parallel_tag` (default value is %CGAL + algorithm. Possible values are `Parallel_tag` (default value if %CGAL is linked with TBB) or `Sequential_tag` (default value otherwise). \tparam DiagonalizeTraits model of `DiagonalizeTraits` used for matrix diagonalization. It can be omitted: if Eigen 3 (or greater) @@ -324,10 +323,8 @@ public: typename NeighborQuery, #if defined(DOXYGEN_RUNNING) typename ConcurrencyTag, -#elif defined(CGAL_LINKED_WITH_TBB) - typename ConcurrencyTag = CGAL::Parallel_tag, #else - typename ConcurrencyTag = CGAL::Sequential_tag, + typename ConcurrencyTag = CGAL::Parallel_if_available_tag, #endif #if defined(DOXYGEN_RUNNING) typename DiagonalizeTraits> @@ -361,7 +358,7 @@ public: #else if (boost::is_convertible::value) { - tbb::mutex mutex; + std::mutex mutex; Compute_eigen_values_graph f(out, input, neighbor_query, out.m_content->mean_range, mutex); @@ -395,7 +392,7 @@ public: `RandomAccessIterator` and its value type is the key type of `PointMap`. \tparam ConcurrencyTag enables sequential versus parallel - algorithm. Possible values are `Parallel_tag` (default value is %CGAL + algorithm. Possible values are `Parallel_tag` (default value if %CGAL is linked with TBB) or `Sequential_tag` (default value otherwise). \tparam DiagonalizeTraits model of `DiagonalizeTraits` used for matrix diagonalization. It can be omitted: if Eigen 3 (or greater) @@ -408,10 +405,8 @@ public: template diff --git a/Classification/include/CGAL/Classification/Mesh_feature_generator.h b/Classification/include/CGAL/Classification/Mesh_feature_generator.h index 5b90b74b379..b68fce17bc8 100644 --- a/Classification/include/CGAL/Classification/Mesh_feature_generator.h +++ b/Classification/include/CGAL/Classification/Mesh_feature_generator.h @@ -45,7 +45,7 @@ #ifdef CGAL_LINKED_WITH_TBB #include -#include +#include #endif // CGAL_LINKED_WITH_TBB namespace CGAL { @@ -79,7 +79,7 @@ namespace Classification { is `GeomTraits::Point_3`. \tparam ConcurrencyTag enables sequential versus parallel computation of `CGAL::Classification::Local_eigen_analysis` - objects. Possible values are `Parallel_tag` (default value is %CGAL + objects. Possible values are `Parallel_tag` (default value if %CGAL is linked with TBB) or `Sequential_tag` (default value otherwise). \tparam DiagonalizeTraits model of `DiagonalizeTraits` used for matrix diagonalization. It can be omitted: if Eigen 3 (or greater) @@ -93,10 +93,8 @@ template > class Mesh_feature_generator diff --git a/Classification/include/CGAL/Classification/Point_set_feature_generator.h b/Classification/include/CGAL/Classification/Point_set_feature_generator.h index 8169e4acec4..58e58bb54dc 100644 --- a/Classification/include/CGAL/Classification/Point_set_feature_generator.h +++ b/Classification/include/CGAL/Classification/Point_set_feature_generator.h @@ -90,10 +90,8 @@ template diff --git a/Classification/include/CGAL/Classification/Sum_of_weighted_features_classifier.h b/Classification/include/CGAL/Classification/Sum_of_weighted_features_classifier.h index 5b7dc929185..4f17b7da445 100644 --- a/Classification/include/CGAL/Classification/Sum_of_weighted_features_classifier.h +++ b/Classification/include/CGAL/Classification/Sum_of_weighted_features_classifier.h @@ -33,7 +33,7 @@ #include #include #include -#include +#include #endif // CGAL_LINKED_WITH_TBB #define CLASSIFICATION_TRAINING_QUICK_ESTIMATION @@ -72,9 +72,9 @@ private: std::vector& m_true_positives; std::vector& m_false_positives; std::vector& m_false_negatives; - std::vector& m_tp_mutex; - std::vector& m_fp_mutex; - std::vector& m_fn_mutex; + std::vector& m_tp_mutex; + std::vector& m_fp_mutex; + std::vector& m_fn_mutex; public: @@ -85,9 +85,9 @@ private: std::vector& true_positives, std::vector& false_positives, std::vector& false_negatives, - std::vector& tp_mutex, - std::vector& fp_mutex, - std::vector& fn_mutex) + std::vector& tp_mutex, + std::vector& fp_mutex, + std::vector& fn_mutex) : m_training_set (training_set) , m_classifier (classifier) , m_label (label) @@ -901,9 +901,9 @@ private: #else if (boost::is_convertible::value) { - std::vector tp_mutex (m_labels.size()); - std::vector fp_mutex (m_labels.size()); - std::vector fn_mutex (m_labels.size()); + std::vector tp_mutex (m_labels.size()); + std::vector fp_mutex (m_labels.size()); + std::vector fn_mutex (m_labels.size()); Compute_iou f(training_sets[j], *this, j, true_positives, false_positives, false_negatives, tp_mutex, fp_mutex, fn_mutex); diff --git a/Classification/include/CGAL/Classification/classify.h b/Classification/include/CGAL/Classification/classify.h index 35d7e69c2ef..ffd89a6530b 100644 --- a/Classification/include/CGAL/Classification/classify.h +++ b/Classification/include/CGAL/Classification/classify.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include #endif // CGAL_LINKED_WITH_TBB namespace CGAL { @@ -327,7 +327,7 @@ namespace internal { suboptimal results. \tparam ConcurrencyTag enables sequential versus parallel - algorithm. Possible values are `Parallel_tag` or `Sequential_tag`. + algorithm. Possible values are `Parallel_if_available_tag`, `Parallel_tag` or `Sequential_tag`. \tparam ItemRange model of `ConstRange`. Its iterator type is `RandomAccessIterator`. Its value type depends on the data that is @@ -417,7 +417,7 @@ namespace internal { efficiency and better quality results. \tparam ConcurrencyTag enables sequential versus parallel - algorithm. Possible values are `Parallel_tag` or `Sequential_tag`. + algorithm. Possible values are `Parallel_if_available_tag`, `Parallel_tag` or `Sequential_tag`. \tparam ItemRange model of `ConstRange`. Its iterator type is `RandomAccessIterator`. \tparam ItemMap model of `ReadablePropertyMap` whose key @@ -495,7 +495,7 @@ namespace internal { results. \tparam ConcurrencyTag enables sequential versus parallel - algorithm. Possible values are `Parallel_tag` or `Sequential_tag`. + algorithm. Possible values are `Parallel_if_available_tag`, `Parallel_tag` or `Sequential_tag`. \tparam ItemRange model of `ConstRange`. Its iterator type is `RandomAccessIterator`. \tparam ItemMap model of `ReadablePropertyMap` whose key diff --git a/Classification/test/Classification/CMakeLists.txt b/Classification/test/Classification/CMakeLists.txt index ae7699281d1..c108ca45a56 100644 --- a/Classification/test/Classification/CMakeLists.txt +++ b/Classification/test/Classification/CMakeLists.txt @@ -5,7 +5,6 @@ cmake_minimum_required(VERSION 3.1...3.15) project( Classification_Tests ) - # CGAL and its components find_package( CGAL QUIET COMPONENTS ) @@ -22,88 +21,39 @@ if ( NOT Boost_FOUND ) return() endif() +set(Classification_dependencies_met TRUE) + find_package( Boost OPTIONAL_COMPONENTS serialization iostreams ) - -if( WIN32 ) -# to avoid a warning with old cmake - set(_Boost_BZIP2_HEADERS "boost/iostreams/filter/bzip2.hpp") - set(_Boost_ZLIB_HEADERS "boost/iostreams/filter/zlib.hpp") - find_package( Boost OPTIONAL_COMPONENTS bzip2 zlib) -else() - find_package(ZLIB QUIET) +if (NOT Boost_SERIALIZATION_FOUND) + message(STATUS "NOTICE: This project requires Boost Serialization, and will not be compiled.") + set(Classification_dependencies_met FALSE) +endif() +if (NOT Boost_IOSTREAMS_FOUND) + message(STATUS "NOTICE: This project requires Boost IO Streams, and will not be compiled.") + set(Classification_dependencies_met FALSE) endif() -# Use Eigen -find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) -if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) +find_package(Eigen3 3.1.0 REQUIRED) #(3.1.0 or greater) +if (NOT EIGEN3_FOUND) + message(STATUS "This project requires the Eigen library, and will not be compiled.") + set(Classification_dependencies_met FALSE) endif() -find_package( TBB ) +find_package(TBB QUIET) -# include for local directory -include_directories( BEFORE include ) - -# include for local package - -# Creating entries for all C++ files with "main" routine -# ########################################################## - -#add_definitions("-DCGAL_DO_NOT_USE_BOYKOV_KOLMOGOROV_MAXFLOW_SOFTWARE") - -# Classification requires some C++11 features -set(needed_cxx_features cxx_rvalue_references cxx_variadic_templates) - -# Libraries and flags -set(classification_linked_libraries) - -if (Boost_SERIALIZATION_FOUND AND Boost_IOSTREAMS_FOUND) - if(TARGET Boost::serialization AND TARGET Boost::iostreams) - set(classification_linked_libraries Boost::serialization Boost::iostreams) - else() - set(classification_linked_libraries ${classification_linked_libraries} - ${Boost_SERIALIZATION_LIBRARY} - ${Boost_IOSTREAMS_LIBRARY}) - endif() -else() - if (NOT Boost_SERIALIZATION_FOUND) - message(STATUS "NOTICE: This project requires Boost Serialization, and will not be compiled.") - endif() - if (NOT Boost_IOSTREAMS_FOUND) - message(STATUS "NOTICE: This project requires Boost IO Streams, and will not be compiled.") - endif() +if (NOT Classification_dependencies_met) return() endif() -if( WIN32 ) - if (Boost_ZLIB_FOUND AND Boost_BZIP2_FOUND) - set(classification_linked_libraries ${classification_linked_libraries} - ${Boost_ZLIB_LIBRARY} ${Boost_BZIP2_LIBRARY}) - else() - message(STATUS "NOTICE: This project requires Boost ZLIB and Boost BZIP2, and will not be compiled.") - return() - endif() -else() - if(ZLIB_FOUND) - set(classification_linked_libraries ${classification_linked_libraries} ZLIB::ZLIB) - else() - message(STATUS "NOTICE: This project requires ZLIB, and will not be compiled.") - return() - endif() -endif() +create_single_source_cgal_program( "test_classification_point_set.cpp" ) +create_single_source_cgal_program( "test_classification_io.cpp" ) -create_single_source_cgal_program( "test_classification_point_set.cpp" CXX_FEATURES ${needed_cxx_features} ) -if(TARGET test_classification_point_set) - target_link_libraries(test_classification_point_set PUBLIC ${classification_linked_libraries}) - if (TBB_FOUND) - CGAL_target_use_TBB( test_classification_point_set ) +foreach(target test_classification_point_set test_classification_io) + CGAL_target_use_Eigen(${target}) + CGAL_target_use_Boost_IOStreams(${target}) + CGAL_target_use_Boost_Serialization(${target}) + if(TBB_FOUND) + CGAL_target_use_TBB(${target}) endif() -endif() +endforeach() -create_single_source_cgal_program( "test_classification_io.cpp" CXX_FEATURES ${needed_cxx_features} ) -if(TARGET test_classification_io) - target_link_libraries(test_classification_io PUBLIC ${classification_linked_libraries}) - if (TBB_FOUND) - CGAL_target_use_TBB( test_classification_io ) - endif() -endif() diff --git a/Combinatorial_map/include/CGAL/Combinatorial_map.h b/Combinatorial_map/include/CGAL/Combinatorial_map.h index 42d5a12ca76..1551bff9f46 100644 --- a/Combinatorial_map/include/CGAL/Combinatorial_map.h +++ b/Combinatorial_map/include/CGAL/Combinatorial_map.h @@ -41,6 +41,9 @@ #include #include #include +#include +#include + #include #if defined( __INTEL_COMPILER ) @@ -55,6 +58,16 @@ _Pragma("GCC diagnostic ignored \"-Warray-bounds\"") #endif namespace CGAL { + // functions to allow the call to next/opposite by ADL + template + auto CM_ADL_next(Desc&& d, G&& g) { + return next(std::forward(d), std::forward(g)); + } + + template + auto CM_ADL_opposite(Desc&& d, G&& g) { + return opposite(std::forward(d), std::forward(g)); + } /** @file Combinatorial_map.h * Definition of generic dD Combinatorial map. @@ -199,18 +212,27 @@ namespace CGAL { CGAL_assertion(number_of_darts()==0); } - /** Copy the given combinatorial map into *this. + /** Copy the given combinatorial map 'amap' into *this. * Note that both CMap can have different dimensions and/or non void attributes. * @param amap the combinatorial map to copy. * @post *this is valid. */ - template - void copy(const CMap2& amap, const Converters& converters, + void copy(const Combinatorial_map_base& amap, + const Converters& converters, const DartInfoConverter& dartinfoconverter, const PointConverter& pointconverter, - boost::unordered_map* dart_mapping=nullptr) + boost::unordered_map + :: + Dart_const_handle, Dart_handle>* origin_to_copy=NULL, + boost::unordered_map + ::Dart_const_handle>* copy_to_origin=NULL) { + typedef Combinatorial_map_base CMap2; this->clear(); this->mnb_used_marks = amap.mnb_used_marks; @@ -232,81 +254,113 @@ namespace CGAL { // Create an mapping between darts of the two maps (originals->copies). // (here we cannot use CGAL::Unique_hash_map because it does not provide // iterators... - boost::unordered_map local_dartmap; - if (dart_mapping==nullptr) - { dart_mapping=&local_dartmap; } - + boost::unordered_map + local_dartmap; + if (origin_to_copy==NULL) // Used local_dartmap if user does not provides its own unordered_map + { origin_to_copy=&local_dartmap; } + + Dart_handle new_dart; for (typename CMap2::Dart_const_range::const_iterator it=amap.darts().begin(), itend=amap.darts().end(); it!=itend; ++it) { - (*dart_mapping)[it]=mdarts.emplace(); - init_dart((*dart_mapping)[it], amap.get_marks(it)); - internal::Copy_dart_info_functor::run - (amap, static_cast(*this), it, (*dart_mapping)[it], - dartinfoconverter); + new_dart=mdarts.emplace(); + init_dart(new_dart, amap.get_marks(it)); + + (*origin_to_copy)[it]=new_dart; + if (copy_to_origin!=NULL) { (*copy_to_origin)[new_dart]=it; } + + internal::Copy_dart_info_functor::run + (static_cast(amap), static_cast(*this), + it, new_dart, dartinfoconverter); } unsigned int min_dim=(dimension - ::iterator dartmap_iter, dartmap_iter_end=dart_mapping->end(); - for (dartmap_iter=dart_mapping->begin(); dartmap_iter!=dartmap_iter_end; + ::iterator dartmap_iter, dartmap_iter_end=origin_to_copy->end(); + for (dartmap_iter=origin_to_copy->begin(); dartmap_iter!=dartmap_iter_end; ++dartmap_iter) { for (unsigned int i=0; i<=min_dim; i++) { if (!amap.is_free(dartmap_iter->first,i) && - (dartmap_iter->first)<(amap.beta(dartmap_iter->first,i))) + is_free(dartmap_iter->second,i)) { basic_link_beta(dartmap_iter->second, - (*dart_mapping)[amap.beta(dartmap_iter->first,i)], i); + (*origin_to_copy)[amap.beta(dartmap_iter->first,i)], i); } } } /** Copy attributes */ - for (dartmap_iter=dart_mapping->begin(); dartmap_iter!=dartmap_iter_end; + for (dartmap_iter=origin_to_copy->begin(); dartmap_iter!=dartmap_iter_end; ++dartmap_iter) { Helper::template Foreach_enabled_attributes - < internal::Copy_attributes_functor >:: - run(amap, static_cast(*this), + run(static_cast(amap), static_cast(*this), dartmap_iter->first, dartmap_iter->second, converters, pointconverter); } - CGAL_assertion (is_valid () == 1); + CGAL_assertion (is_valid()); } - template - void copy(const CMap2& amap, - boost::unordered_map* dart_mapping=nullptr) + template + void copy(const Combinatorial_map_base& amap, + boost::unordered_map + ::Dart_const_handle, Dart_handle>* origin_to_copy=NULL, + boost::unordered_map + ::Dart_const_handle>* copy_to_origin=NULL) { - std::tuple<> converters; - Default_converter_dart_info dartinfoconverter; - Default_converter_cmap_0attributes_with_point pointconverter; - copy(amap, converters, dartinfoconverter, pointconverter, dart_mapping); + CGAL::cpp11::tuple<> converters; + Default_converter_dart_info dartinfoconverter; + Default_converter_cmap_0attributes_with_point pointconverter; + copy(amap, converters, dartinfoconverter, pointconverter, + origin_to_copy, copy_to_origin); } - template - void copy(const CMap2& amap, const Converters& converters, - boost::unordered_map* dart_mapping=nullptr) + template + void copy(const Combinatorial_map_base& amap, + const Converters& converters, + boost::unordered_map + ::Dart_const_handle, Dart_handle>* origin_to_copy=NULL, + boost::unordered_map + ::Dart_const_handle>* copy_to_origin=NULL) { - Default_converter_cmap_0attributes_with_point pointconverter; - Default_converter_dart_info dartinfoconverter; - copy(amap, converters, dartinfoconverter, pointconverter, dart_mapping); + Default_converter_cmap_0attributes_with_point pointconverter; + Default_converter_dart_info dartinfoconverter; + copy(amap, converters, dartinfoconverter, pointconverter, + origin_to_copy, copy_to_origin); } - template - void copy(const CMap2& amap, const Converters& converters, + template + void copy(const Combinatorial_map_base& amap, + const Converters& converters, const DartInfoConverter& dartinfoconverter, - boost::unordered_map* dart_mapping=nullptr) + boost::unordered_map + ::Dart_const_handle, Dart_handle>* origin_to_copy=NULL, + boost::unordered_map + ::Dart_const_handle>* copy_to_origin=NULL) { - Default_converter_cmap_0attributes_with_point pointconverter; - copy(amap, converters, dartinfoconverter, pointconverter, dart_mapping); + Default_converter_cmap_0attributes_with_point pointconverter; + copy(amap, converters, dartinfoconverter, pointconverter, + origin_to_copy, copy_to_origin); } // Copy constructor from a map having exactly the same type. @@ -314,25 +368,37 @@ namespace CGAL { { copy(amap); } // "Copy constructor" from a map having different type. - template - Combinatorial_map_base(const CMap2& amap) + template + Combinatorial_map_base(const Combinatorial_map_base& amap) { copy(amap); } // "Copy constructor" from a map having different type. - template - Combinatorial_map_base(const CMap2& amap, Converters& converters) + template + Combinatorial_map_base(const Combinatorial_map_base& amap, + const Converters& converters) { copy(amap, converters); } // "Copy constructor" from a map having different type. - template - Combinatorial_map_base(const CMap2& amap, Converters& converters, + template + Combinatorial_map_base(const Combinatorial_map_base& amap, + const Converters& converters, const DartInfoConverter& dartinfoconverter) { copy(amap, converters, dartinfoconverter); } // "Copy constructor" from a map having different type. - template - Combinatorial_map_base(const CMap2& amap, Converters& converters, + template + Combinatorial_map_base(const Combinatorial_map_base& amap, + const Converters& converters, const DartInfoConverter& dartinfoconverter, const PointConverter& pointconverter) { copy(amap, converters, dartinfoconverter, pointconverter); } @@ -385,6 +451,62 @@ namespace CGAL { } } + /** Import the given hds which should be a model of an halfedge graph. */ + template + void import_from_halfedge_graph(const HEG& heg, + boost::unordered_map + ::halfedge_descriptor, + Dart_handle>* origin_to_copy=NULL, + boost::unordered_map + ::halfedge_descriptor>* + copy_to_origin=NULL) + + { + // Create an mapping between darts of the two maps (originals->copies). + // (here we cannot use CGAL::Unique_hash_map because it does not provide + // iterators... + boost::unordered_map + ::halfedge_descriptor, + Dart_handle> local_dartmap; + if (origin_to_copy==NULL) // Used local_dartmap if user does not provides its own unordered_map + { origin_to_copy=&local_dartmap; } + + Dart_handle new_dart; + for (typename boost::graph_traits::halfedge_iterator + it=halfedges(heg).begin(), itend=halfedges(heg).end(); + it!=itend; ++it) + { + if (!CGAL::is_border(*it, heg)) + { + new_dart=mdarts.emplace(); + (*origin_to_copy)[*it]=new_dart; + if (copy_to_origin!=NULL) { (*copy_to_origin)[new_dart]=*it; } + } + } + + typename boost::unordered_map + ::halfedge_descriptor, + Dart_handle>::iterator dartmap_iter, dartmap_iter_end=origin_to_copy->end(); + for (dartmap_iter=origin_to_copy->begin(); dartmap_iter!=dartmap_iter_end; + ++dartmap_iter) + { + basic_link_beta(dartmap_iter->second, + (*origin_to_copy)[CM_ADL_next(dartmap_iter->first, heg)], + 1); + + if (!CGAL::is_border(CM_ADL_opposite(dartmap_iter->first, heg), heg) && + (dartmap_iter->first)first, heg)) + { + basic_link_beta(dartmap_iter->second, + (*origin_to_copy) + [CM_ADL_opposite(dartmap_iter->first, heg)], 2); + } + } + + CGAL_assertion (is_valid()); + } + /** Clear the combinatorial map. Remove all darts and all attributes. * Note that reserved marks are not free. */ @@ -498,6 +620,16 @@ namespace CGAL { { return mdarts.iterator_to(adart); } Dart_const_handle dart_handle(const Dart& adart) const { return mdarts.iterator_to(adart); } + Dart_handle dart_handle(size_type i) + { + CGAL_assertion(darts().is_used(i)); + return mdarts.iterator_to(darts()[i]); + } + Dart_const_handle dart_handle(size_type i) const + { + CGAL_assertion(darts().is_used(i)); + return mdarts.iterator_to(darts()[i]); + } /** Return the highest dimension for which dh is not free. * @param dh a dart handle @@ -673,6 +805,11 @@ namespace CGAL { Dart_const_handle next(Dart_const_handle ADart) const { return this->template beta<1>(ADart); } + Dart_handle opposite2(Dart_handle ADart) + { return this->template beta<2>(ADart); } + Dart_const_handle opposite2(Dart_const_handle ADart) const + { return this->template beta<2>(ADart); } + template Dart_handle opposite(Dart_handle ADart) { return this->template beta(ADart); } @@ -950,6 +1087,27 @@ namespace CGAL { mnb_times_reserved_marks[amark]=0; } + template + bool belong_to_same_cell(Dart_const_handle adart1, + Dart_const_handle adart2) const + { return CGAL::belong_to_same_cell(*this, adart1, adart2); } + + template + bool is_whole_cell_unmarked(Dart_const_handle adart, size_type amark) const + { return CGAL::is_whole_cell_unmarked(*this, adart, amark); } + + template + bool is_whole_cell_marked(Dart_const_handle adart, size_type amark) const + { return CGAL::is_whole_cell_marked(*this, adart, amark); } + + template + size_type mark_cell(Dart_const_handle adart, size_type amark) const + { return CGAL::mark_cell(*this, adart, amark); } + + template + size_type unmark_cell(Dart_const_handle adart, size_type amark) const + { return CGAL::unmark_cell(*this, adart, amark); } + /** Test if this map is without boundary for a given dimension. * @param i the dimension. * @return true iff all the darts are not i-free. @@ -2300,6 +2458,30 @@ namespace CGAL { run(*this, adart, amark); } + /// Keep the biggest connected component. + /// @return the size (in number of darts) of the biggest cc. + std::size_t keep_biggest_connected_component() + { + std::map ccs; + + size_type treated=get_new_mark(); + for (auto it=darts().begin(), itend=darts().end(); it!=itend; ++it) + { + if (!is_marked(it, treated)) + { ccs[mark_cell(it, treated)]=it; } + } + + if (ccs.size()>1) + { // Here all darts are marked + this->template unmark_cell(ccs.rbegin()->second, treated); // Unmark the biggest cc + erase_marked_darts(treated); + } + + free_mark(treated); + + return ccs.rbegin()->first; + } + /** Count the marked cells (at least one marked dart). * @param amark the mark to consider. * @param avector containing the dimensions of the cells to count. @@ -2433,6 +2615,64 @@ namespace CGAL { } public: + + /// @return the positive turn between the two given darts. + // @pre beta1(d1) and d2 must belong to the same vertex. + std::size_t positive_turn(Dart_const_handle d1, Dart_const_handle d2) const + { + CGAL_assertion((!this->template is_free<1>(d1))); + /* CGAL_assertion((belong_to_same_cell<0>(this->template beta<1>(d1), + d2))); */ + + if (d2==beta<2>(d1)) { return 0; } + + Dart_const_handle dd1=d1; + std::size_t res=1; + while (beta<1>(dd1)!=d2) + { + if (this->template is_free<2>(beta<1>(dd1))) + { return std::numeric_limits::max(); } + + ++res; + dd1=beta<1, 2>(dd1); + + CGAL_assertion(!this->template is_free<1>(dd1)); + CGAL_assertion(beta<1>(dd1)==d2 || dd1!=d1); + } + return res; + } + + /// @return the negative turn between the two given darts. + // @pre beta1(d1) and d2 must belong to the same vertex. + std::size_t negative_turn(Dart_const_handle d1, Dart_const_handle d2) const + { + CGAL_assertion((!this->template is_free<1>(d1))); + /* CGAL_assertion((belong_to_same_cell<0>(this->template beta<1>(d1), + d2))); */ + + if (d2==beta<2>(d1)) { return 0; } + + if (this->template is_free<2>(d1) || this->template is_free<2>(d2)) + { return std::numeric_limits::max(); } + + d1=beta<2>(d1); + d2=beta<2>(d2); + Dart_const_handle dd1=d1; + std::size_t res=1; + while (beta<0>(dd1)!=d2) + { + if (this->template is_free<2>(beta<0>(dd1))) + { return std::numeric_limits::max(); } + + ++res; + dd1=beta<0, 2>(dd1); + + CGAL_assertion(!this->template is_free<0>(dd1)); + CGAL_assertion(beta<0>(dd1)==d2 || dd1!=d1); + } + return res; + } + /** Erase marked darts from the map. * Marked darts are unlinked before to be removed, thus surviving darts * are correctly linked, but the map is not necessarily valid depending @@ -3513,12 +3753,12 @@ namespace CGAL { !is_face_combinatorial_polygon(d4, 3) ) return false; // TODO do better with marks (?). - if ( belong_to_same_cell(*this, d1, d2) || - belong_to_same_cell(*this, d1, d3) || - belong_to_same_cell(*this, d1, d4) || - belong_to_same_cell(*this, d2, d3) || - belong_to_same_cell(*this, d2, d4) || - belong_to_same_cell(*this, d3, d4) ) return false; + if ( belong_to_same_cell<2,1>(d1, d2) || + belong_to_same_cell<2,1>(d1, d3) || + belong_to_same_cell<2,1>(d1, d4) || + belong_to_same_cell<2,1>(d2, d3) || + belong_to_same_cell<2,1>(d2, d4) || + belong_to_same_cell<2,1>(d3, d4) ) return false; if ( beta(d1,1,2)!=beta(d3,0) || beta(d4,0,2)!=beta(d3,1) || @@ -3611,21 +3851,21 @@ namespace CGAL { !is_face_combinatorial_polygon(d6, 4) ) return false; // TODO do better with marks. - if ( belong_to_same_cell(*this, d1, d2) || - belong_to_same_cell(*this, d1, d3) || - belong_to_same_cell(*this, d1, d4) || - belong_to_same_cell(*this, d1, d5) || - belong_to_same_cell(*this, d1, d6) || - belong_to_same_cell(*this, d2, d3) || - belong_to_same_cell(*this, d2, d4) || - belong_to_same_cell(*this, d2, d5) || - belong_to_same_cell(*this, d2, d6) || - belong_to_same_cell(*this, d3, d4) || - belong_to_same_cell(*this, d3, d5) || - belong_to_same_cell(*this, d3, d6) || - belong_to_same_cell(*this, d4, d5) || - belong_to_same_cell(*this, d4, d6) || - belong_to_same_cell(*this, d5, d6) ) + if ( belong_to_same_cell<2,1>(d1, d2) || + belong_to_same_cell<2,1>(d1, d3) || + belong_to_same_cell<2,1>(d1, d4) || + belong_to_same_cell<2,1>(d1, d5) || + belong_to_same_cell<2,1>(d1, d6) || + belong_to_same_cell<2,1>(d2, d3) || + belong_to_same_cell<2,1>(d2, d4) || + belong_to_same_cell<2,1>(d2, d5) || + belong_to_same_cell<2,1>(d2, d6) || + belong_to_same_cell<2,1>(d3, d4) || + belong_to_same_cell<2,1>(d3, d5) || + belong_to_same_cell<2,1>(d3, d6) || + belong_to_same_cell<2,1>(d4, d5) || + belong_to_same_cell<2,1>(d4, d6) || + belong_to_same_cell<2,1>(d5, d6) ) return false; if ( beta(d1,2) !=beta(d4,1,1) || @@ -3781,7 +4021,7 @@ namespace CGAL { return this->template beta<1>(adart); } - /** Insert a vertex in the given 2-cell which is splitted in triangles, + /** Insert a vertex in the given 2-cell which is split in triangles, * once for each inital edge of the facet. * @param adart a dart of the facet to triangulate. * @param update_attributes a boolean to update the enabled attributes @@ -4213,7 +4453,7 @@ namespace CGAL { if ( od==null_handle ) return false; // of and *it must belong to the same vertex of the same volume - if ( !belong_to_same_cell(*this, od, *it) ) + if ( !belong_to_same_cell<0, 2>(od, *it) ) return false; } prec = *it; @@ -4223,7 +4463,7 @@ namespace CGAL { od = other_extremity(prec); if ( od==null_handle ) return false; - if (!belong_to_same_cell(*this, od, *afirst)) + if (!belong_to_same_cell<0, 2>(od, *afirst)) return false; return true; @@ -4437,24 +4677,33 @@ namespace CGAL { Combinatorial_map(const Self & amap) : Base(amap) {} - template < class CMap > - Combinatorial_map(const CMap & amap) : Base(amap) + template + Combinatorial_map(const Combinatorial_map_base& + amap) : Base(amap) {} - template < class CMap, typename Converters > - Combinatorial_map(const CMap & amap, const Converters& converters) : + template + Combinatorial_map(const Combinatorial_map_base& + amap, const Converters& converters) : Base(amap, converters) {} - template < class CMap, typename Converters, typename DartInfoConverter > - Combinatorial_map(const CMap & amap, const Converters& converters, + template + Combinatorial_map(const Combinatorial_map_base& + amap, const Converters& converters, const DartInfoConverter& dartinfoconverter) : Base(amap, converters, dartinfoconverter) {} - template < class CMap, typename Converters, typename DartInfoConverter, - typename PointConverter > - Combinatorial_map(const CMap & amap, const Converters& converters, + template + Combinatorial_map(const Combinatorial_map_base& + amap, const Converters& converters, const DartInfoConverter& dartinfoconverter, const PointConverter& pointconverter) : Base(amap, converters, dartinfoconverter, pointconverter) diff --git a/Combinatorial_map/include/CGAL/Combinatorial_map_basic_operations.h b/Combinatorial_map/include/CGAL/Combinatorial_map_basic_operations.h index 2a0a2018d02..2c289df31bc 100644 --- a/Combinatorial_map/include/CGAL/Combinatorial_map_basic_operations.h +++ b/Combinatorial_map/include/CGAL/Combinatorial_map_basic_operations.h @@ -194,7 +194,7 @@ namespace CGAL typename Map::size_type amark) { return CGAL::is_whole_orbit_unmarked::iterator> + typename Map::template Dart_of_cell_range::const_iterator> (amap, adart, amark); } diff --git a/Combinatorial_map/include/CGAL/Combinatorial_map_insertions.h b/Combinatorial_map/include/CGAL/Combinatorial_map_insertions.h index 74fa659825a..fa2bee50c3e 100644 --- a/Combinatorial_map/include/CGAL/Combinatorial_map_insertions.h +++ b/Combinatorial_map/include/CGAL/Combinatorial_map_insertions.h @@ -39,7 +39,7 @@ insert_cell_0_in_cell_1( CMap& amap, typename CMap::Dart_handle adart, return amap.insert_cell_0_in_cell_1(adart, ah, update_attributes); } -/** Insert a vertex in the given 2-cell which is splitted in triangles, +/** Insert a vertex in the given 2-cell which is split in triangles, * once for each inital edge of the facet. * @param amap the used combinatorial map. * @param adart a dart of the facet to triangulate. diff --git a/Combinatorial_map/include/CGAL/Combinatorial_map_iterators_base.h b/Combinatorial_map/include/CGAL/Combinatorial_map_iterators_base.h index 0aed0028bea..b0f2943c707 100644 --- a/Combinatorial_map/include/CGAL/Combinatorial_map_iterators_base.h +++ b/Combinatorial_map/include/CGAL/Combinatorial_map_iterators_base.h @@ -106,7 +106,7 @@ namespace CGAL { { return ( ((*this==mmap->null_handle) && (aiterator==mmap->null_handle)) || (mfirst_dart == aiterator.mfirst_dart && - static_cast(*this)== + static_cast(*this)== static_cast(aiterator)) ); } diff --git a/Combinatorial_map/include/CGAL/Combinatorial_map_storages.h b/Combinatorial_map/include/CGAL/Combinatorial_map_storages.h index 8158718153d..70ab1e3b1dd 100644 --- a/Combinatorial_map/include/CGAL/Combinatorial_map_storages.h +++ b/Combinatorial_map/include/CGAL/Combinatorial_map_storages.h @@ -127,6 +127,8 @@ namespace CGAL { CGAL_assertion(i <= dimension); return dh->mf[i]==null_dart_handle; } + bool is_perforated(Dart_const_handle /*dh*/) const + { return false; } /// Set simultaneously all the marks of this dart to a given value. void set_dart_marks(Dart_const_handle ADart, diff --git a/Combinatorial_map/include/CGAL/Face_graph_wrapper.h b/Combinatorial_map/include/CGAL/Face_graph_wrapper.h new file mode 100644 index 00000000000..a0915e45758 --- /dev/null +++ b/Combinatorial_map/include/CGAL/Face_graph_wrapper.h @@ -0,0 +1,941 @@ +// Copyright (c) 2019 CNRS and LIRIS' Establishments (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) : Guillaume Damiand +// +#ifndef CGAL_FACE_GRAPH_WRAPPER_H +#define CGAL_FACE_GRAPH_WRAPPER_H 1 + +#include +#include +#include +#include +#include +#include + +namespace CGAL +{ + // Forward declarations of all classes model of Face_graph + template + class Combinatorial_map_base; + + template + class Generalized_map_base; + + template + class Map, typename Refs, typename Storage> + class Linear_cell_complex_base; + + template + class Combinatorial_map; + + template + class Generalized_map; + + template + class Map, typename Storage> + class Linear_cell_complex_for_combinatorial_map; + + template + class Map, typename Storage> + class Linear_cell_complex_for_generalized_map; + + namespace Surface_mesh_topology + { + template + class Polygonal_schema_with_combinatorial_map; + + template + class Polygonal_schema_with_generalized_map; + } + +//////////////////////////////////////////////////////////////////////////////// +/** Class Face_graph_wrapper: to wrap any model of FaceGraph into a + * Combinatorial map. For now, only for const models, i.e. does not support + * modification operators. + */ +template +class Face_graph_wrapper +{ +public: + typedef HEG_ HEG; + typedef Face_graph_wrapper Self; + typedef std::size_t size_type; + + struct Dart_container + { + typedef typename boost::graph_traits::halfedge_iterator iterator; + typedef typename boost::graph_traits::halfedge_iterator const_iterator; // TODO ? + // typedef My_halfedge_iterator iterator; + // typedef My_halfedge_iterator const_iterator; // TODO ? + }; + + typedef typename boost::graph_traits::halfedge_descriptor Dart_handle; + typedef typename boost::graph_traits::halfedge_descriptor Dart_const_handle; + + typedef Dart_handle Null_handle_type; + // typedef CGAL::Void* Null_handle_type; + static const Null_handle_type null_handle; //=Dart_handle(); + static const Null_handle_type null_dart_handle; //=Dart_handle(); + + /// Number of marks + static const size_type NB_MARKS = 32; + static const size_type INVALID_MARK = NB_MARKS; + + /// The dimension of the combinatorial map. + static const unsigned int dimension=2; + static const unsigned int ambient_dimension=3; + + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef boost::undirected_tag directed_category; + typedef boost::disallow_parallel_edge_tag edge_parallel_category; + + struct SM_graph_traversal_category : public virtual boost::bidirectional_graph_tag, + public virtual boost::vertex_list_graph_tag, + public virtual boost::edge_list_graph_tag + {}; + typedef SM_graph_traversal_category traversal_category; + + + Face_graph_wrapper(const HEG& f) : m_fg(f), + mdarts(*this), + m_nb_darts(0), + mnb_used_marks(0) + + { + mmask_marks.reset(); + + for (size_type i=0; i >(), m_fg); + for (typename Dart_range::const_iterator it(darts().begin()), + itend(darts().end()); it!=itend; ++it) + { put(m_all_marks, it, std::bitset()); } + } + + const HEG& get_fg() const + { return m_fg; } + + template + bool is_free(Dart_const_handle /* dh */) const + { return false; } // Not possible to have a free dart with an HEG. + bool is_free(Dart_const_handle /*dh*/, unsigned int /*i*/) const + { return false; } // Not possible to have a free dart with an HEG. + + bool is_perforated(Dart_const_handle dh) const + { return is_border(dh, m_fg); } + + Dart_const_handle get_beta(Dart_const_handle ADart, int B1) const + { + CGAL_assertion(B1>=0 && B1<=static_cast(dimension)); + if (B1==1) return Get_beta::value(m_fg, ADart); + if (B1==2) return Get_beta::value(m_fg, ADart); + return Get_beta::value(m_fg, ADart); + } + template + Dart_const_handle get_beta(Dart_const_handle ADart) const + { + CGAL_assertion(B1>=0 && B1<=static_cast(dimension)); + return Get_beta::value(m_fg, ADart); + } + + bool is_empty() const + { return number_of_darts()==0; } + + /* ?? bool is_dart_used(Dart_const_handle dh) const + { return true; ?? } */ + + int highest_nonfree_dimension(Dart_const_handle /* dh */) const + { return 2; } + + Dart_const_handle previous(Dart_const_handle ADart) const + { return get_beta<0>(ADart); } + Dart_const_handle next(Dart_const_handle ADart) const + { return get_beta<1>(ADart); } + Dart_const_handle opposite(Dart_const_handle dh) const + { return get_beta<2>(dh); } + Dart_const_handle opposite2(Dart_const_handle dh) const + { return get_beta<2>(dh); } + Dart_const_handle other_extremity(Dart_const_handle dh) const + { return get_beta<1>(dh); } + + template + Dart_const_handle opposite(Dart_const_handle ADart) const + { return this->template get_beta(ADart); } + Dart_const_handle other_orientation(Dart_const_handle ADart) const + { return ADart; } + + bool is_previous_exist(Dart_const_handle) const + { return true; } + bool is_next_exist(Dart_const_handle) const + { return true; } + template + bool is_opposite_exist(Dart_const_handle /* ADart */) const + { return true; } + + template + Dart_handle beta(Dart_handle ADart, Betas... betas) + { return CGAL::internal::Beta_functor:: + run(*this, ADart, betas...); } + template + Dart_const_handle beta(Dart_const_handle ADart, Betas... betas) const + { return CGAL::internal::Beta_functor:: + run(*this, ADart, betas...); } + template + Dart_handle beta(Dart_handle ADart) + { return CGAL::internal::Beta_functor_static:: + run(*this, ADart); } + template + Dart_const_handle beta(Dart_const_handle ADart) const + { return CGAL::internal::Beta_functor_static:: + run(*this, ADart); } + + size_type number_of_darts() const + { return m_nb_darts; } + + size_type number_of_halfedges() const + { return number_of_darts(); } + + size_type number_of_used_marks() const + { return mnb_used_marks; } + + bool is_reserved(size_type amark) const + { + CGAL_assertion(amark& >(get(m_all_marks, ADart)).set(amark, avalue); + } + + void flip_dart_mark(Dart_const_handle ADart, size_type amark) const + { set_dart_mark(ADart, amark, !get_dart_mark(ADart, amark)); } + + bool is_marked(Dart_const_handle adart, size_type amark) const + { + CGAL_assertion(is_reserved(amark)); + return get_dart_mark(adart, amark)!=mmask_marks[amark]; + } + + void set_mark_to(Dart_const_handle adart, size_type amark, + bool astate) const + { + CGAL_assertion(is_reserved(amark)); + + if (is_marked(adart, amark)!=astate) + { + if (astate) ++mnb_marked_darts[amark]; + else --mnb_marked_darts[amark]; + + flip_dart_mark(adart, amark); + } + } + + void mark(Dart_const_handle adart, size_type amark) const + { + CGAL_assertion(is_reserved(amark)); + + if (is_marked(adart, amark)) return; + + ++mnb_marked_darts[amark]; + flip_dart_mark(adart, amark); + } + + void unmark(Dart_const_handle adart, size_type amark) const + { + CGAL_assertion( adart!=this->null_dart_handle ); + CGAL_assertion( is_reserved(amark) ); + + if (!is_marked(adart, amark)) return; + + --mnb_marked_darts[amark]; + flip_dart_mark(adart, amark); + } + + void unmark_all(size_type amark) const + { + CGAL_assertion( is_reserved(amark) ); + + if ( is_whole_map_marked(amark) ) + { + negate_mark(amark); + } + else if ( !is_whole_map_unmarked(amark) ) + { + for (typename Dart_range::const_iterator it(darts().begin()), + itend(darts().end()); it!=itend; ++it) + unmark(*it, amark); + } + CGAL_assertion(is_whole_map_unmarked(amark)); + } + + void free_mark(size_type amark) const + { + CGAL_assertion( is_reserved(amark) ); + + if ( mnb_times_reserved_marks[amark]>1 ) + { + --mnb_times_reserved_marks[amark]; + return; + } + + unmark_all(amark); + + // 1) We remove amark from the array mused_marks_stack by + // replacing it with the last mark in this array. + mused_marks_stack[mindex_marks[amark]] = + mused_marks_stack[--mnb_used_marks]; + mindex_marks[mused_marks_stack[mnb_used_marks]] = + mindex_marks[amark]; + + // 2) We add amark in the array mfree_marks_stack and update its index. + mfree_marks_stack[ mnb_used_marks ]=amark; + mindex_marks[amark] = mnb_used_marks; + + mnb_times_reserved_marks[amark]=0; + } + + bool is_without_boundary(unsigned int i) const + { + CGAL_assertion(1<=i && i<=dimension); + if (i==1) return true; + + for ( typename Dart_range::const_iterator it(darts().begin()), + itend(darts().end()); it!=itend; ++it) + { if (is_perforated(it)) return false; } + return true; + } + + bool is_without_boundary() const + { return is_without_boundary(2); } + + //************************************************************************** + // Dart_of_cell_range + template + struct Dart_of_cell_range + { + typedef CGAL::FGW_cell_iterator iterator; + typedef CGAL::FGW_cell_iterator const_iterator; + Dart_of_cell_range(const Self &amap, Dart_handle adart) : mmap(amap), + m_initdart(adart), + msize(0) + {} + const_iterator begin() const { return const_iterator(mmap, m_initdart); } + const_iterator end() const { return const_iterator(mmap, m_initdart, mmap.null_handle); } + size_type size() const + { + if (msize==0) + { + for (const_iterator it=begin(), itend=end(); it!=itend; ++it) + { ++msize; } + } + return msize; + } + + bool empty() const + { return mmap.is_empty(); } + private: + const Self & mmap; + Dart_handle m_initdart; + mutable typename Self::size_type msize; + }; + //************************************************************************** + // Dart_of_cell_const_range + /* template + struct Dart_of_cell_const_range // TODO REMOVE ?? + {}; */ + //-------------------------------------------------------------------------- + template + Dart_of_cell_range darts_of_cell(Dart_handle adart) + { return Dart_of_cell_range(*this,adart); } + //-------------------------------------------------------------------------- + template + Dart_of_cell_range darts_of_cell(Dart_const_handle adart) const + { return Dart_of_cell_range(*this,adart); } // Before it was Dart_of_cell_const_range + //************************************************************************** + // Dart_range + struct Dart_range { + typedef CGAL::FGW_dart_iterator_basic_of_all iterator; + typedef CGAL::FGW_dart_iterator_basic_of_all const_iterator; + Dart_range(const Self &amap) : mmap(amap), msize(0) + {} + iterator begin() { return iterator(mmap); } + iterator end() { return iterator(mmap,mmap.null_handle); } + const_iterator begin() const { return const_iterator(mmap); } + const_iterator end() const { return const_iterator(mmap,mmap.null_handle); } + size_type size() const + { + if (msize==0) + { msize=halfedges(mmap.get_fg()).size(); } + return msize; + } + bool empty() const + { return mmap.is_empty(); } + + size_type capacity() const + { return num_halfedges(mmap.get_fg()); } + + bool is_used(size_type i) const + { + for (typename boost::template graph_traits::halfedge_iterator + it=halfedges(mmap.get_fg()).begin(), + itend=halfedges(mmap.get_fg()).end(); it!=itend; ++it) + { + if (i==0) { return !is_border(*it, mmap.get_fg()); } + --i; + } + return false; + } + + private: + const Self & mmap; + mutable typename Self::size_type msize; + }; + //************************************************************************** + // Dart_const_range // TODO REMOVE ? + /* struct Dart_const_range { + typedef CGAL::FGW_dart_iterator_basic_of_all const_iterator; + Dart_const_range(const Self &amap) : mmap(amap), msize(0) + {} + const_iterator begin() const { return const_iterator(mmap); } + const_iterator end() const { return const_iterator(mmap,mmap.null_handle); } + size_type size() const + { + if (msize==0) + { + for (const_iterator it=begin(), itend=end(); it!=itend; ++it) + { ++msize; } + } + return msize; + } + + bool empty() const + { return mmap.is_empty(); } + private: + const Self & mmap; + mutable typename Self::size_type msize; + };*/ + //************************************************************************** + Dart_range& darts() + { return mdarts; } + //-------------------------------------------------------------------------- + const Dart_range& darts() const + { return mdarts; } // Before it was Dart_const_range(*this) + //************************************************************************** + Dart_handle dart_handle(size_type i) + { + CGAL_assertion(darts().is_used(i)); + for (typename boost::template graph_traits::halfedge_iterator + it=halfedges(get_fg()).begin(), + itend=halfedges(get_fg()).end(); it!=itend; ++it) + { + if (i==0) { return *it; } + --i; + } + CGAL_assertion(false); + return Dart_handle(); + } + Dart_const_handle dart_handle(size_type i) const + { + CGAL_assertion(darts().is_used(i)); + for (typename boost::template graph_traits::halfedge_iterator + it=halfedges(get_fg()).begin(), + itend=halfedges(get_fg()).end(); it!=itend; ++it) + { + if (i==0) { return *it; } + --i; + } + CGAL_assertion(false); + return Dart_const_handle(); + } + + template + bool belong_to_same_cell(Dart_const_handle adart1, + Dart_const_handle adart2) const + { + for (typename Dart_of_cell_range::iterator it=darts_of_cell(adart1).begin(), + itend=darts_of_cell(adart1).end(); it!=itend; ++it) + { if (*it==adart2) { return true; } } + return false; + } + + template + bool is_whole_cell_unmarked(Dart_const_handle adart, size_type amark) const + { + for (typename Dart_of_cell_range::iterator it=darts_of_cell(adart).begin(), + itend=darts_of_cell(adart).end(); it!=itend; ++it) + { if (is_marked(*it, amark)) { return false; } } + return true; + } + + template + bool is_whole_cell_marked(Dart_const_handle adart, size_type amark) const + { + for (typename Dart_of_cell_range::iterator it=darts_of_cell(adart).begin(), + itend=darts_of_cell(adart).end(); it!=itend; ++it) + { if (!is_marked(*it, amark)) { return false; } } + return true; + } + + template + size_type mark_cell(Dart_const_handle adart, size_type amark) const + { + size_type res=0; + for (typename Dart_of_cell_range::iterator it=darts_of_cell(adart).begin(), + itend=darts_of_cell(adart).end(); it!=itend; ++it) + { mark(*it, amark); ++res; } + return res; +} + + size_type mark_cell(Dart_const_handle adart, unsigned int i, size_type amark) const + { + if (i==0) { return mark_cell<0>(adart, amark); } + else if (i==1) { return mark_cell<1>(adart, amark); } + else if (i==2) { return mark_cell<2>(adart, amark); } + return mark_cell<3>(adart, amark); + } + + template + size_type unmark_cell(Dart_const_handle adart, size_type amark) const + { + size_type res=0; + for (typename Dart_of_cell_range::iterator it=darts_of_cell(adart).begin(), + itend=darts_of_cell(adart).end(); it!=itend; ++it) + { unmark(*it, amark); ++res; } + return res; + } + + std::vector + count_marked_cells(size_type amark, const std::vector& acells) const + { + std::vector res(dimension+2); + std::vector marks(dimension+2); + + // Initialization of the result + for (unsigned int i=0; i tounmark; + for (unsigned int i=0; i0) + { + for (typename Dart_range::const_iterator it(darts().begin()), + itend(darts().end()); it!=itend; ++it) + { + for (unsigned int i=0; i + count_cells(const std::vector& acells) const + { + std::vector res; + size_type m=get_new_mark(); + negate_mark(m); // We mark all the cells. + + res=count_marked_cells(m, acells); + + negate_mark(m); // We unmark the cells + free_mark(m); + + return res; + } + + std::vector count_all_cells() const + { + std::vector dim(dimension+2); + + for ( unsigned int i=0; i<=dimension+1; ++i) + { dim[i]=i; } + + return count_cells(dim); + } + + std::ostream& display_characteristics(std::ostream & os) const + { + std::vector cells(dimension+2); + for ( unsigned int i=0; i<=dimension+1; ++i) + { cells[i]=i; } + + std::vector res=count_cells(cells); + + os<<"#Darts="< > >::const_type MarkPMap; + mutable MarkPMap m_all_marks; +}; + + /// null_handle + // template + // const typename Face_graph_wrapper::Null_handle_type + // Face_graph_wrapper::null_handle=nullptr; + template + const typename Face_graph_wrapper::Null_handle_type + Face_graph_wrapper::null_handle=typename Face_graph_wrapper::Dart_handle(); + + /// null_dart_handle + // template + // const typename Face_graph_wrapper::Null_handle_type + // Face_graph_wrapper::null_dart_handle=nullptr; + template + const typename Face_graph_wrapper::Null_handle_type + Face_graph_wrapper::null_dart_handle=typename Face_graph_wrapper::Dart_handle(); + + template + struct Get_map + { + typedef Face_graph_wrapper type; + typedef const Face_graph_wrapper storage_type; + Get_map(const HEG& heg): m_map(heg) {} + static const HEG& get_mesh(const storage_type& amap) + { return amap.get_fg(); } + + storage_type m_map; + }; + + template + struct Get_map, Map> + { + typedef Map type; + typedef const Map& storage_type; + Get_map(const Map& heg): m_map(heg) {} + static const Map& get_mesh(storage_type& amap) + { return amap; } + storage_type m_map; + }; + + template + struct Get_map, Map> + { + typedef Map type; + typedef const Map& storage_type; + Get_map(const Map& heg): m_map(heg) {} + static const Map& get_mesh(storage_type& amap) + { return amap; } + storage_type m_map; + }; + + template + class Map, typename Refs, typename Storage, class LCC> + struct Get_map, LCC> + { + typedef LCC type; + typedef const LCC& storage_type; + Get_map(const LCC& heg): m_map(heg) {} + static const LCC& get_mesh(storage_type& amap) + { return amap; } + storage_type m_map; + }; + + template + struct Get_map, Map> + { + typedef Map type; + typedef const Map& storage_type; + Get_map(const Map& heg): m_map(heg) {} + static const Map& get_mesh(storage_type& amap) + { return amap; } + storage_type m_map; + }; + + template + struct Get_map, Map> + { + typedef Map type; + typedef const Map& storage_type; + Get_map(const Map& heg): m_map(heg) {} + static const Map& get_mesh(storage_type& amap) + { return amap; } + storage_type m_map; + }; + + template + struct Get_map, Map> + { + typedef Map type; + typedef const Map& storage_type; + Get_map(const Map& heg): m_map(heg) {} + static const Map& get_mesh(storage_type& amap) + { return amap; } + storage_type m_map; + }; + + template + struct Get_map, Map> + { + typedef Map type; + typedef const Map& storage_type; + Get_map(const Map& heg): m_map(heg) {} + static const Map& get_mesh(storage_type& amap) + { return amap; } + storage_type m_map; + }; + + template + class Map, typename Storage, class LCC> + struct Get_map, LCC> + { + typedef LCC type; + typedef const LCC& storage_type; + Get_map(const LCC& heg): m_map(heg) {} + static const LCC& get_mesh(storage_type& amap) + { return amap; } + storage_type m_map; + }; + + template + class Map, typename Storage, class LCC> + struct Get_map, LCC> + { + typedef LCC type; + typedef const LCC& storage_type; + Get_map(const LCC& heg): m_map(heg) {} + static const LCC& get_mesh(storage_type& amap) + { return amap; } + storage_type m_map; + }; + + template + struct Get_traits + { + typedef Mesh_ Mesh; + typedef typename Mesh::Traits Kernel; + typedef typename Mesh::Point Point; + typedef typename Mesh::Vector Vector; + + template + static const Point& get_point(const Mesh& m, Dart_handle dh) + { return m.point(dh); } + }; + + template + struct Get_traits > + { + typedef CGAL::Surface_mesh

Mesh; + typedef typename CGAL::Kernel_traits

::Kernel Kernel; + typedef typename Kernel::Point_3 Point; + typedef typename Kernel::Vector_3 Vector; + + template + static const Point& get_point(const Mesh& m, Dart_handle dh) + { return m.point(m.source(dh)); } + }; + + template class T_HDS, + class Alloc> + struct Get_traits > + { + typedef CGAL::Polyhedron_3 Mesh; + typedef PolyhedronTraits_3 Kernel; + typedef typename Kernel::Point_3 Point; + typedef typename Kernel::Vector_3 Vector; + + template + static const Point& get_point(const Mesh& /*m*/, Dart_handle dh) + { return dh->opposite()->vertex()->point(); } + }; + +} // Namespace CGAL + +#endif // CGAL_FACE_GRAPH_WRAPPER_H // +// EOF // diff --git a/Combinatorial_map/include/CGAL/Functors_for_face_graph_wrapper.h b/Combinatorial_map/include/CGAL/Functors_for_face_graph_wrapper.h new file mode 100644 index 00000000000..9f4360d328c --- /dev/null +++ b/Combinatorial_map/include/CGAL/Functors_for_face_graph_wrapper.h @@ -0,0 +1,87 @@ +// Copyright (c) 2019 CNRS and LIRIS' Establishments (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) : Guillaume Damiand +// +#ifndef CGAL_FUNCTORS_FOR_FACE_GRAPH_WRAPPER_H +#define CGAL_FUNCTORS_FOR_FACE_GRAPH_WRAPPER_H 1 + +#include +#include +#include + +//////////////////////////////////////////////////////////////////////////////// +/** This file contains the following functors for Face_graph_wrapper: + * Is_free:: + operator() (const HEG& heg, Dart_const_handle dh) + * Get_beta:: + operator() (const HEG& heg, Dart_const_handle dh) +*/ +//////////////////////////////////////////////////////////////////////////////// +namespace CGAL +{ +/// Is_free +//template +//struct Is_free +//{ +// typedef typename boost::graph_traits::halfedge_descriptor Dart_const_handle; + +// static bool value(const HEG& /*heg*/, Dart_const_handle /*dh*/) +// { CGAL_static_assertion(i==0 || i==1); return false; } +//}; +//template +//struct Is_free +//{ +// typedef typename boost::graph_traits::halfedge_descriptor Dart_const_handle; +// static bool value(const HEG& heg, Dart_const_handle dh) +// { return is_border(opposite(dh, heg), heg); } +//}; +//////////////////////////////////////////////////////////////////////////////// +/// Get_beta +template +struct Get_beta +{ + typedef typename boost::graph_traits::halfedge_descriptor Dart_const_handle; + + static Dart_const_handle value(const HEG& /*heg*/, Dart_const_handle /*dh*/) + { /* CGAL_static_assertion(false);*/ + std::cout<<"ERROR Get_beta"< +struct Get_beta +{ + typedef typename boost::graph_traits::halfedge_descriptor Dart_const_handle; + static Dart_const_handle value(const HEG& heg, Dart_const_handle dh) + { return prev(dh, heg); } +}; +template +struct Get_beta +{ + typedef typename boost::graph_traits::halfedge_descriptor Dart_const_handle; + static Dart_const_handle value(const HEG& heg, Dart_const_handle dh) + { return next(dh, heg); } +}; +template +struct Get_beta +{ + typedef typename boost::graph_traits::halfedge_descriptor Dart_const_handle; + static Dart_const_handle value(const HEG& heg, Dart_const_handle dh) + { + //if (Is_free::value(heg, dh)) return Dart_const_handle(); + return opposite(dh, heg); + } +}; +//////////////////////////////////////////////////////////////////////////////// +} // namespace CGAL + +#endif // CGAL_FUNCTORS_FOR_FACE_GRAPH_WRAPPER_H // +// EOF // diff --git a/Combinatorial_map/include/CGAL/Iterators_for_face_graph_wrapper.h b/Combinatorial_map/include/CGAL/Iterators_for_face_graph_wrapper.h new file mode 100644 index 00000000000..d30d5889b22 --- /dev/null +++ b/Combinatorial_map/include/CGAL/Iterators_for_face_graph_wrapper.h @@ -0,0 +1,332 @@ +// Copyright (c) 2019 CNRS and LIRIS' Establishments (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) : Guillaume Damiand +// +#ifndef CGAL_ITERATORS_FOR_FACE_GRAPH_WRAPPER_H +#define CGAL_ITERATORS_FOR_FACE_GRAPH_WRAPPER_H 1 + +#include +#include +#include + +namespace CGAL +{ + + //**************************************************************************** + /* Class CMap_dart_iterator_basic_of_all: to iterate onto all the + * darts of the face graph. + */ + template + class FGW_dart_iterator_basic_of_all + { + public: + typedef FGW_dart_iterator_basic_of_all Self; + + typedef Map_ Map; + typedef typename Map::Dart_handle Dart_handle; + typedef typename Map::size_type size_type; + + public: + /// Main constructor. + FGW_dart_iterator_basic_of_all(const Map& amap): + mmap(amap), + m_it(halfedges(amap.get_fg()).begin()) + { + /*if (m_it!=halfedges(amap.get_fg()).end() && + is_border(*m_it, amap.get_fg())) + { operator++(0); } */ + } + + /// Constructor with a dart in parameter (for end iterator). + FGW_dart_iterator_basic_of_all(const Map& amap, Dart_handle /*adart*/): + mmap(amap), + m_it(halfedges(amap.get_fg()).end()) + {} + + FGW_dart_iterator_basic_of_all(const FGW_dart_iterator_basic_of_all& other): + mmap(other.mmap), + m_it(other.m_it) + {} + + operator Dart_handle() const + { return operator*(); } + + bool operator==(const Self& other) const + { return &mmap==&(other.mmap) && m_it==other.m_it; } + + bool operator!=(const Self& other) const + { return !(operator==(other)); } + + /// Prefix ++ operator. + Self& operator++() + { + CGAL_assertion(m_it!=halfedges(this->mmap.get_fg()).end()); + + //do + { + ++m_it; + } + /*while(m_it!=halfedges(this->mmap.get_fg()).end() && + is_border(*m_it, this->mmap.get_fg())); */ + + return *this; + } + + /// Postfix ++ operator. + Self operator++(int) + { Self res=*this; operator ++(); return res; } + + Dart_handle operator*() const + { + CGAL_assertion(m_it!=halfedges(this->mmap.get_fg()).end()); + return *m_it; + } + + protected: + const Map& mmap; + typename boost::graph_traits::halfedge_iterator m_it; + }; + +//////////////////////////////////////////////////////////////////////////////// + template + class FGW_basis_for_cell_iterator + { + public: + typedef FGW_basis_for_cell_iterator Self; + typedef Map_ Map; + typedef typename Map::Dart_handle Dart_handle; + typedef typename Map::size_type size_type; + + /// Main constructor. + FGW_basis_for_cell_iterator(const Map& amap, Dart_handle adart): + mmap(amap), + m_firstdart(adart), + m_curdart(adart) + {} + + /// Constructor with two darts in parameter (for end iterator). + FGW_basis_for_cell_iterator(const Map& amap, Dart_handle adart, + Dart_handle /* d2 */): + mmap(amap), + m_firstdart(adart), + m_curdart(Dart_handle()) + {} + + bool operator==(const Self& other) const + { return &mmap==&(other.mmap) && m_firstdart==other.m_firstdart && + m_curdart==other.m_curdart; } + + bool operator!=(const Self& other) const + { return !(this->operator==(other)); } + + operator Dart_handle() const + { return operator*(); } + + Dart_handle operator*() const + { + CGAL_assertion(m_curdart!=Dart_handle()); + return m_curdart; + } + + protected: + const Map& mmap; + Dart_handle m_firstdart, m_curdart; + }; +//////////////////////////////////////////////////////////////////////////////// + template + class FGW_cell_iterator + {}; +//////////////////////////////////////////////////////////////////////////////// +/// Vertex iterator + template + class FGW_cell_iterator: public FGW_basis_for_cell_iterator // Vertex + { + public: + typedef FGW_cell_iterator Self; + typedef FGW_basis_for_cell_iterator Base; + typedef Map_ Map; + typedef typename Map::Dart_handle Dart_handle; + typedef typename Map::size_type size_type; + + FGW_cell_iterator(const Map& amap, Dart_handle adart) : Base(amap, adart), + m_second_way(false) + {} + + /// Constructor with two darts in parameter (for end iterator). + FGW_cell_iterator(const Map& amap, Dart_handle adart, + Dart_handle d2): Base(amap, adart, d2) + {} + + /// Prefix ++ operator. + Self& operator++() + { + if (!m_second_way) + { + if (this->mmap.template is_free<2>(this->m_curdart)) + { + m_second_way=true; + this->m_curdart=this->mmap.template beta<0>(this->m_firstdart); + if (this->mmap.template is_free<2>(this->m_curdart)) + { this->m_curdart=Dart_handle(); } + else { this->m_curdart=this->mmap.template beta<2>(this->m_curdart); } + } + else + { + this->m_curdart=this->mmap.template beta<2, 1>(this->m_curdart); + if (this->m_curdart==this->m_firstdart) + { this->m_curdart=Dart_handle(); } + } + } + else + { + this->m_curdart=this->mmap.template beta<0>(this->m_curdart); + if (this->mmap.template is_free<2>(this->m_curdart)) + { this->m_curdart=Dart_handle(); } + else { this->m_curdart=this->mmap.template beta<2>(this->m_curdart); } + } + + return *this; + } + + /// Postfix ++ operator. + Self operator++(int) + { Self res=*this; operator ++(); return res; } + +protected: + /// True if we already found a border dart, and thus turn in the second way + bool m_second_way; +}; +template +class FGW_cell_iterator: public FGW_basis_for_cell_iterator // Edge +{ + public: + typedef FGW_cell_iterator Self; + typedef FGW_basis_for_cell_iterator Base; + typedef Map_ Map; + typedef typename Map::Dart_handle Dart_handle; + typedef typename Map::size_type size_type; + + FGW_cell_iterator(const Map& amap, Dart_handle adart) : Base(amap, adart) + {} + + /// Constructor with two darts in parameter (for end iterator). + FGW_cell_iterator(const Map& amap, Dart_handle adart, + Dart_handle d2): Base(amap, adart, d2) + {} + + /// Prefix ++ operator. + Self& operator++() + { + if (this->m_curdart==this->m_firstdart) + { + if (this->mmap.template is_free<2>(this->m_curdart)) + { this->m_curdart=Dart_handle(); } + else { this->m_curdart=this->mmap.template beta<2>(this->m_curdart); } + } + else + { this->m_curdart=Dart_handle(); } + + return *this; + } + + /// Postfix ++ operator. + Self operator++(int) + { Self res=*this; operator ++(); return res; } +}; +template +class FGW_cell_iterator: public FGW_basis_for_cell_iterator // Face +{ +public: + typedef FGW_cell_iterator Self; + typedef FGW_basis_for_cell_iterator Base; + typedef Map_ Map; + typedef typename Map::Dart_handle Dart_handle; + typedef typename Map::size_type size_type; + + FGW_cell_iterator(const Map& amap, Dart_handle adart) : Base(amap, adart) + {} + + /// Constructor with two darts in parameter (for end iterator). + FGW_cell_iterator(const Map& amap, Dart_handle adart, + Dart_handle d2): Base(amap, adart, d2) + {} + + /// Prefix ++ operator. + Self& operator++() + { + this->m_curdart=this->mmap.template beta<1>(this->m_curdart); + if (this->m_curdart==this->m_firstdart) + { this->m_curdart=Dart_handle(); } + + return *this; + } + + /// Postfix ++ operator. + Self operator++(int) + { Self res=*this; operator ++(); return res; } +}; +template +class FGW_cell_iterator: public FGW_basis_for_cell_iterator // CC +{ +public: + typedef FGW_cell_iterator Self; + typedef FGW_basis_for_cell_iterator Base; + typedef Map_ Map; + typedef typename Map::Dart_handle Dart_handle; + typedef typename Map::size_type size_type; + + FGW_cell_iterator(const Map& amap, Dart_handle adart) : Base(amap, adart) + { m_mark=this->mmap.get_new_mark(); } + + /// Constructor with two darts in parameter (for end iterator). + FGW_cell_iterator(const Map& amap, Dart_handle adart, + Dart_handle d2): Base(amap, adart, d2) + { m_mark=this->mmap.get_new_mark(); } + + ~FGW_cell_iterator() + { this->mmap.free_mark(m_mark); } + + /// Prefix ++ operator. + Self& operator++() + { + if (!this->mmap.is_marked(this->mmap.template beta<1>(this->m_curdart), m_mark)) + { + m_to_treat.push(this->mmap.template beta<1>(this->m_curdart)); + this->mmap.mark(this->mmap.template beta<1>(this->m_curdart), m_mark); + } + if (!this->mmap.template is_free<2>(this->m_curdart) && + !this->mmap.is_marked(this->mmap.template beta<2>(this->m_curdart), m_mark)) + { + m_to_treat.push(this->mmap.template beta<2>(this->m_curdart)); + this->mmap.mark(this->mmap.template beta<2>(this->m_curdart), m_mark); + } + + if (m_to_treat.empty()) + { this->m_curdart=Dart_handle(); } + else + { this->m_curdart=m_to_treat.top(); m_to_treat.pop(); } + + return *this; + } + + /// Postfix ++ operator. + Self operator++(int) + { Self res=*this; operator ++(); return res; } + +protected: + typename Map_::size_type m_mark; + std::stack m_to_treat; +}; +//////////////////////////////////////////////////////////////////////////////// + +} // namespace CGAL + +#endif // CGAL_ITERATORS_FOR_FACE_GRAPH_WRAPPER_H // +// EOF // diff --git a/Combinatorial_map/package_info/Combinatorial_map/dependencies b/Combinatorial_map/package_info/Combinatorial_map/dependencies index 4078db76b93..eb4d232541d 100644 --- a/Combinatorial_map/package_info/Combinatorial_map/dependencies +++ b/Combinatorial_map/package_info/Combinatorial_map/dependencies @@ -1,5 +1,6 @@ Algebraic_foundations Arithmetic_kernel +BGL Cartesian_kernel Circulator Combinatorial_map @@ -17,5 +18,7 @@ Kernel_d Modular_arithmetic Number_types Profiling_tools +Property_map STL_Extension Stream_support +Random_numbers diff --git a/Combinatorial_map/test/Combinatorial_map/CMakeLists.txt b/Combinatorial_map/test/Combinatorial_map/CMakeLists.txt index 6beb2c68493..98a88794f8a 100644 --- a/Combinatorial_map/test/Combinatorial_map/CMakeLists.txt +++ b/Combinatorial_map/test/Combinatorial_map/CMakeLists.txt @@ -16,6 +16,11 @@ if ( CGAL_FOUND ) create_single_source_cgal_program( "${cppfile}" ) endforeach() + find_package( OpenMesh QUIET ) + if (TARGET OpenMesh::OpenMesh) + target_link_libraries(Combinatorial_map_copy_test PRIVATE OpenMesh::OpenMesh) + endif() + else() message(STATUS "This program requires the CGAL library, and will not be compiled.") diff --git a/Combinatorial_map/test/Combinatorial_map/Combinatorial_map_copy_test.cpp b/Combinatorial_map/test/Combinatorial_map/Combinatorial_map_copy_test.cpp index ce21c604ef9..27de63ed00d 100644 --- a/Combinatorial_map/test/Combinatorial_map/Combinatorial_map_copy_test.cpp +++ b/Combinatorial_map/test/Combinatorial_map/Combinatorial_map_copy_test.cpp @@ -1,6 +1,13 @@ #include #include #include "Combinatorial_map_test_iterators.h" +#include +#if CGAL_USE_OPENMESH +# include +# include +# include + typedef OpenMesh::TriMesh_ArrayKernelT OpenMesh_mesh; +#endif // CGAL_USE_OPENMESH #include #include @@ -152,6 +159,10 @@ typedef CGAL::Combinatorial_map<4, Map_dart_items_4> Map8; // info=char, int, int, int, int, double typedef CGAL::Combinatorial_map<4, Map_dart_max_items_4> Map9; +struct Traits { typedef int Point_2; typedef int Point_3; }; +typedef CGAL::HalfedgeDS_default HDS; + +//////////////////////////////////////////////////////////////////////////////// template::type> struct CreateAttributes @@ -579,6 +590,31 @@ bool testCopy() return true; } +bool testImportFromHalfedge() +{ + bool res=true; + + HDS hds; + CGAL::HalfedgeDS_decorator decorator(hds); + decorator.create_loop(); + decorator.create_segment(); + + Map1 map1; map1.import_from_halfedge_graph(hds); + Map2 map2; map2.import_from_halfedge_graph(hds); + Map3 map3; map3.import_from_halfedge_graph(hds); + +#if CGAL_USE_OPENMESH + { + // test the compilation, with an empty mesh + OpenMesh_mesh hds; + Map1 map1; map1.import_from_halfedge_graph(hds); + Map2 map2; map2.import_from_halfedge_graph(hds); + Map3 map3; map3.import_from_halfedge_graph(hds); + } +#endif // CGAL_USE_OPENMESH + return res; // TODO compare number of darts/cells +} + int main() { std::cout<<"Combinatorial map copy test (v1)."< #include +#include +#include +#include +#include +#include #include "Combinatorial_map_2_test.h" #include "Combinatorial_map_3_test.h" @@ -193,8 +198,64 @@ bool test_get_new_mark() return true; } +bool test_face_graph_wrapper() +{ + bool res=true; + + typedef CGAL::Surface_mesh::Point_3> SMesh; + SMesh m; + std::ifstream in1("data/head.off"); + if (in1.fail()) + { + std::cout<<"Error: impossible to open 'data/head.off'"<>m; + + CGAL::Face_graph_wrapper fgw1(m); + std::vector cells=fgw1.count_all_cells(); + if (cells[0]!=1487 || cells[1]!=4406 || cells[2]!=2921 || + fgw1.number_of_darts()!=8812) + { + std::cout<<"Error: incorrect number of cells in test_face_graph_wrapper " + <<"for Surface_mesh: " + < > Polyhedron; + Polyhedron p; + std::ifstream in2("data/head.off"); + if (in2.fail()) + { + std::cout<<"Error: impossible to open 'data/head.off'"<>p; + CGAL::Face_graph_wrapper fgw2(p); + cells=fgw2.count_all_cells(); + if (cells[0]!=1487 || cells[1]!=4406 || cells[2]!=2921 || + fgw2.number_of_darts()!=8812) + { + std::cout<<"Error: incorrect number of cells in test_face_graph_wrapper " + <<"for Polyhedron." + < -

  • The value type of `InputIterator` and +
  • The value type of `ForwardIterator` and `OutputIterator` is equivalent to `Traits::Point_2`.
  • `Traits` defines the following subset of types from the concept `ConvexHullTraits_2` and their corresponding member @@ -46,10 +46,10 @@ in the worst case for \f$ n\f$ input points with \f$ h\f$ extreme points. */ -template +template OutputIterator -ch_jarvis( InputIterator first, -InputIterator beyond, +ch_jarvis( ForwardIterator first, +ForwardIterator beyond, OutputIterator result, const Traits & ch_traits = Default_traits); diff --git a/Convex_hull_3/doc/Convex_hull_3/CGAL/convex_hull_3.h b/Convex_hull_3/doc/Convex_hull_3/CGAL/convex_hull_3.h index bc83e1d13a0..78e5d46a00f 100644 --- a/Convex_hull_3/doc/Convex_hull_3/CGAL/convex_hull_3.h +++ b/Convex_hull_3/doc/Convex_hull_3/CGAL/convex_hull_3.h @@ -21,7 +21,7 @@ is a kernel with exact predicates but inexact constructions (in practice we check `R::Has_filtered_predicates_tag` is `Tag_true` and `R::FT` is a floating point type), then the default traits class of `::convex_hull_3()` is `Convex_hull_traits_3`, and `R` otherwise. -\attention The user must include the header file of the `Polygon_mesh` type. +\attention The user must include the header file of the `PolygonMesh` type. \cgalHeading{Implementation} @@ -34,6 +34,36 @@ Barnard et al. \cgalCite{bdh-qach-96}. template void convex_hull_3(InputIterator first, InputIterator last, PolygonMesh& pm, const Traits& ch_traits = Default_traits); + +/*! +\ingroup PkgConvexHull3Functions + * \brief computes the convex hull of the points associated to the vertices of `g`. + * The polygon mesh `pm` is cleared, then + * the convex hull is stored in `pm`. Note that the convex hull will be triangulated, + * that is `pm` will contain only triangular faces. + * if the convex hull is a point or a segment, endpoints will be added in `pm` as isolated vertices. + * + * \tparam VertexListGraph a model of `VertexListGraph`. + * \tparam PolygonMesh must be a model of `MutableFaceGraph`. + * \tparam NamedParameters a sequence of named parameters + * + * \param g the graph + * \param pm the `PolygonMesh` that will contain the convex hull + * \param np optional sequence of named parameters among the ones listed below + * + * \cgalNamedParamsBegin + * \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `g`. + * If this parameter is omitted, an internal property map for + * `CGAL::vertex_point_t` must be available in `VertexListGraph` + * \cgalParamEnd +* \cgalNamedParamsEnd + * \attention The user must include the header file of the `PolygonMesh` and `VertexListGraph` types. + */ +template +void convex_hull_3(const VertexListGraph& g, + PolygonMesh& pm, + const NamedParameters& np); + /*! \ingroup PkgConvexHull3Functions @@ -47,7 +77,7 @@ that is the polygon mesh will contain only triangular facets. \tparam Traits must be model of the concept `ConvexHullTraits_3`. For the purposes of checking the postcondition that the convex hull is valid, `Traits` must also be a model of the concept -`IsStronglyConvexTraits_3`. Furthermore, `Traits` must define a type `Polygon_mesh` that is a model of +`IsStronglyConvexTraits_3`. Furthermore, `Traits` must define a type `PolygonMesh` that is a model of `MutableFaceGraph`. If the kernel `R` of the points determined by the value type of `InputIterator` @@ -55,7 +85,7 @@ is a kernel with exact predicates but inexact constructions (in practice we check `R::Has_filtered_predicates_tag` is `Tag_true` and `R::FT` is a floating point type), then the default traits class of `convex_hull_3()` is `Convex_hull_traits_3`, and `R` otherwise. -\attention The user must include the header file of the `Polygon_mesh` type. +\attention The user must include the header file of the `PolygonMesh` type. */ template diff --git a/Convex_hull_3/doc/Convex_hull_3/Doxyfile.in b/Convex_hull_3/doc/Convex_hull_3/Doxyfile.in index a114b807a2b..860593ed992 100644 --- a/Convex_hull_3/doc/Convex_hull_3/Doxyfile.in +++ b/Convex_hull_3/doc/Convex_hull_3/Doxyfile.in @@ -1,3 +1,9 @@ @INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS} PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 3D Convex Hulls" + +\# macros to be used inside the code +ALIASES += "cgalNamedParamsBegin=
    Named Parameters
    " +ALIASES += "cgalNamedParamsEnd=
    " +ALIASES += "cgalParamBegin{1}=\ref BGL_\1 \"\1\"" +ALIASES += "cgalParamEnd=" diff --git a/Convex_hull_3/examples/Convex_hull_3/CMakeLists.txt b/Convex_hull_3/examples/Convex_hull_3/CMakeLists.txt index 18d983da969..a5b3583a751 100644 --- a/Convex_hull_3/examples/Convex_hull_3/CMakeLists.txt +++ b/Convex_hull_3/examples/Convex_hull_3/CMakeLists.txt @@ -54,6 +54,9 @@ create_single_source_cgal_program( "lloyd_algorithm.cpp" ) create_single_source_cgal_program( "quickhull_3.cpp" ) +create_single_source_cgal_program( "graph_hull_3.cpp" ) + + create_single_source_cgal_program( "quickhull_any_dim_3.cpp" ) create_single_source_cgal_program( "extreme_points_3_sm.cpp" ) diff --git a/Convex_hull_3/examples/Convex_hull_3/graph_hull_3.cpp b/Convex_hull_3/examples/Convex_hull_3/graph_hull_3.cpp new file mode 100644 index 00000000000..1769315fe5b --- /dev/null +++ b/Convex_hull_3/examples/Convex_hull_3/graph_hull_3.cpp @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include +#include + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef K::Point_3 Point_3; +typedef CGAL::Surface_mesh Surface_mesh; + + +int main(int argc, char* argv[]) +{ + std::ifstream in( (argc>1)? argv[1] : "data/star.off"); + + Surface_mesh poly; + if(!(in >> poly)) + { + std::cerr<<"Could not find input file."< #include #include +#include #include #include #include @@ -49,6 +50,9 @@ #include #include #include +#include +#include +#include #include @@ -1036,7 +1040,10 @@ void convex_hull_3(InputIterator first, InputIterator beyond, template void convex_hull_3(InputIterator first, InputIterator beyond, - Polyhedron_3& polyhedron) + Polyhedron_3& polyhedron, + typename std::enable_if< + CGAL::is_iterator::value + >::type* =0) //workaround to avoid ambiguity with next overload. { typedef typename std::iterator_traits::value_type Point_3; typedef typename internal::Convex_hull_3::Default_traits_for_Chull_3::type Traits; @@ -1044,6 +1051,29 @@ void convex_hull_3(InputIterator first, InputIterator beyond, } +template +void convex_hull_3(const VertexListGraph& g, + PolygonMesh& pm, + const NamedParameters& np) +{ + typedef typename GetVertexPointMap::const_type Vpmap; + typedef CGAL::Property_map_to_unary_function Vpmap_fct; + Vpmap vpm = CGAL::parameters::choose_parameter( + CGAL::parameters::get_parameter(np, internal_np::vertex_point), + get_const_property_map(boost::vertex_point, g)); + + Vpmap_fct v2p(vpm); + convex_hull_3(boost::make_transform_iterator(vertices(g).begin(), v2p), + boost::make_transform_iterator(vertices(g).end(), v2p), pm); +} + +template +void convex_hull_3(const VertexListGraph& g, + PolygonMesh& pm) +{ + convex_hull_3(g,pm,CGAL::parameters::all_default()); +} + template OutputIterator extreme_points_3(const InputRange& range, diff --git a/Convex_hull_3/test/Convex_hull_3/test_ch_3_ambiguity.cpp b/Convex_hull_3/test/Convex_hull_3/test_ch_3_ambiguity.cpp new file mode 100644 index 00000000000..0b67fa73bdc --- /dev/null +++ b/Convex_hull_3/test/Convex_hull_3/test_ch_3_ambiguity.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include +#include + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Polyhedron_3 Polyhedron_3; +typedef K::Point_3 Point_3; +typedef CGAL::Surface_mesh Surface_mesh; + + +int main(int argc, char* argv[]) +{ + std::ifstream in( (argc>1)? argv[1] : "data/cross.off"); + + Surface_mesh poly; + if(!in || !(in >> poly)) + { + std::cerr<<"Could not find a correct input file."<Package Overview page. +In \cgal, \sc{Eigen} is used in many packages such as \ref +PkgPoissonSurfaceReconstruction3 or \ref PkgJetFitting3, providing +sparse linear solvers and singular value decompositions. A package +dependency over \sc{Eigen} is marked on the Package +Overview page. In order to use Eigen in \cgal programs, the +provided CMake function `CGAL_target_use_Eigen()` should be +used. The \sc{Eigen} web site is `http://eigen.tuxfamily.org`. +\subsection thirdpartyOpenGR OpenGR + +\sc{OpenGR} is a set C++ libraries for 3D Global Registration released under the terms of the APACHE V2 licence. + +\cgal provides wrappers for the Super4PCS algorithm of \sc{OpenGR} in the \ref PkgPointSetProcessing3Ref +packages. In order to use \sc{OpenGR} in \cgal programs, the provided CMake function +`CGAL_target_use_OpenGR()` should be used. + +The \sc{OpenGR} web site is `https://github.com/STORM-IRIT/OpenGR`. + +\subsection thirdpartylibpointmatcher PointMatcher + +\sc{libpointmatcher} is a modular library implementing the Iterative Closest Point (ICP) algorithm for aligning point clouds, released under a permissive BSD license. + +\cgal provides wrappers for the ICP algorithm of \sc{libpointmatcher} in the \ref PkgPointSetProcessing3Ref +packages. In order to use \sc{libpointmatcher} in \cgal programs, the provided CMake function +`CGAL_target_use_pointmatcher()` should be used. + +The \sc{libpointmatcher} web site is `https://github.com/ethz-asl/libpointmatcher`. + \subsection thirdpartyLeda LEDA Version 6.2 or later @@ -194,7 +219,9 @@ It can be downloaded from `http://esbtl. \sc{Tbb} (Threading Building Blocks) is a library developed by Intel Corporation for writing software programs that take advantage of multi-core processors. -In \cgal, \sc{Tbb} is used by the packages that offer parallel code. +In \cgal, \sc{Tbb} is used by the packages that offer parallel +code. In order to use \sc{Tbb} in \cgal programs, the provided CMake +function `CGAL_target_use_TBB()` should be used. The \sc{Tbb} web site is `https://www.threadingbuildingblocks.org`. @@ -204,7 +231,9 @@ The \sc{Tbb} web site is `http the LAS format (or the compressed LAZ format). In \cgal, \sc{LASlib} is used to provide input and output functions in -the \ref PkgPointSetProcessing3 package. +the \ref PkgPointSetProcessing3 package. In order to use \sc{LASlib} in +\cgal programs, the provided CMake function +`CGAL_target_use_LASLIB()` should be used. The \sc{LASlib} web site is `https://rapidlasso.com/lastools/`. \sc{LASlib} @@ -217,7 +246,9 @@ CMake based install procedure. \sc{OpenCV} (Open Computer Vision) is a library designed for computer vision, computer graphics and machine learning. -In \cgal, \sc{OpenCV} is used by the \ref PkgClassification package. +In \cgal, \sc{OpenCV} is used by the \ref PkgClassification +package. In order to use \sc{OpenCV} in \cgal programs, the provided +CMake function `CGAL_target_use_OpenCV()` should be used. The \sc{OpenCV} web site is `https://opencv.org/`. @@ -235,6 +266,9 @@ enable and compile the following targets: - `tensorflow_BUILD_PYTHON_BINDINGS` - `tensorflow_BUILD_SHARED_LIB`. +In order to use \sc{TensorFlow} in \cgal programs, the provided CMake +function `CGAL_target_use_TensorFlow()` should be used. + The \sc{TensorFlow} web site is `https://www.tensorflow.org/`. \subsection thirdpartyMETIS METIS @@ -274,7 +308,10 @@ for more information. \sc{GLPK} (GNU Linear Programming Kit) is a library for solving linear programming (LP), mixed integer programming (MIP), and other related problems. -In \cgal, \sc{GLPK} provides an optional linear integer program solver in the \ref PkgPolygonalSurfaceReconstruction package. +In \cgal, \sc{GLPK} provides an optional linear integer program solver +in the \ref PkgPolygonalSurfaceReconstruction package. In order to use +\sc{GLPK} in \cgal programs, the provided CMake function +`CGAL_target_use_GLPK()` should be used. The \sc{GLPK} web site is `https://www.gnu.org/software/glpk/`. @@ -282,7 +319,10 @@ The \sc{GLPK} web site is `https:// \sc{SCIP} (Solving Constraint Integer Programs) is currently one of the fastest open source solvers for mixed integer programming (MIP) and mixed integer nonlinear programming (MINLP). -In \cgal, \sc{SCIP} provides an optional linear integer program solver in the \ref PkgPolygonalSurfaceReconstruction package. +In \cgal, \sc{SCIP} provides an optional linear integer program solver +in the \ref PkgPolygonalSurfaceReconstruction package. In order to use +\sc{SCIP} in \cgal programs, the provided CMake function +`CGAL_target_use_SCIP()` should be used. The \sc{SCIP} web site is `http://scip.zib.de/`. diff --git a/Documentation/doc/Documentation/Usage.txt b/Documentation/doc/Documentation/Usage.txt index b1a21d4c121..38d2b257697 100644 --- a/Documentation/doc/Documentation/Usage.txt +++ b/Documentation/doc/Documentation/Usage.txt @@ -60,6 +60,12 @@ On most operating systems, package managers offer \cgal and its essential third On macOS, we recommend using of Homebrew in the following way: brew install cgal + brew install cgal-qt5 #(only for GUI) + +You should check that cgal and cgal-qt5 are correctly "linked", especially when upgrading from an old version. If not, run the following command: + + brew link cgal + brew link cgal-qt5 #(if you installed it) On Linux distributions such as `Debian`/`Ubuntu`/`Mint`, use `apt-get` in the following way: @@ -148,10 +154,14 @@ The variable `CGAL_DIR` is also generally found when \cgal has been obtained via In the rare event that it has not, the variable `CGAL_DIR` should be set manually to:
      -
    • something like `/usr/local/Cellar/cgal/CGAL-\cgalReleaseNumber/lib/cmake/CGAL`, for Brew.
    • +
    • something like `/usr/local/opt/cgal/lib/cmake/CGAL`, for Brew.
    • something like `/usr/lib/x86_64-linux-gnu/cmake/CGAL`, for Linux distributions.
    +Note that you can also use `CMAKE_PREFIX_PATH` to point to a directory that contains all dependencies, like so: + + cmake -DCMAKE_PREFIX_PATH=/my/custom/brew/installation/dir -DCMAKE_BUILD_TYPE=Release . + If \cgal has been obtained via other means, `CGAL_DIR` must point to the root directory of the \cgal source code (either the root of the unpacked release tarball or the root of the Git working directory). @@ -162,6 +172,13 @@ if no debugging is intended. Users should thus run: cd CGAL-\cgalReleaseNumber/examples/Triangulation_2 cmake -DCGAL_DIR=$HOME/CGAL-\cgalReleaseNumber -DCMAKE_BUILD_TYPE=Release . # we are here using a release tarball +Note that the package Qt on brew is "keg-only", which means it cannot be "linked" with brew. +You will have to specify the Qt5_DIR by hand to cmake, using something like + + -DQt5_DIR=/usr/local/opt/qt/lib/cmake/Qt5 + +where '/usr/local/` is actually your current brew installation directory. + \subsection usage_configuring_cmake_gui Specifying Missing Dependencies The configuration process launched above might fail if CMake fails to find diff --git a/Documentation/doc/Documentation/advanced/Configuration_variables.txt b/Documentation/doc/Documentation/advanced/Configuration_variables.txt index 1bebdc5ddd7..2a880f1e488 100644 --- a/Documentation/doc/Documentation/advanced/Configuration_variables.txt +++ b/Documentation/doc/Documentation/advanced/Configuration_variables.txt @@ -85,6 +85,7 @@ and will serverly limit performances. | Variable | Description | Type | %Default Value | | :- | :- | :- | :- | | `CGAL_DIR` | Full-path to the binary directory where \cgal was configured |Either CMake or Environment | none | +| `Qt5_DIR` | Full-path to the Qt cmake directory |CMake| platform-dependent| \subsection installation_variables_third_party Variables Providing Information About 3rd-Party Libraries @@ -300,6 +301,20 @@ environment variable is sufficient. | `ESBTL_INC_DIR` | Directory containing the `ESBTL/default.h` file | Environment | | `ESBTL_INCLUDE_DIR` | Directory containing the `ESBTL/default.h` file | CMake | +\subsection installation_metis METIS Library + +Some BGL examples require the \sc{Metis} library in order to partition \sc{Metis} meshes. + +If \sc{Metis} is not automatically found, setting the `METIS_INCLUDE_DIR` and `METIS_LIBRARY` +cmake variables is necessary. + + +| Variable | Description | Type | +| :- | :- | :- | +| `METIS_INCLUDE_DIR` | Directory of \sc{Metis} default installation | CMAKE | +| `METIS_LIBRARY` | Directory containing the `libmetis.so or .lib` file | CMAKE | + + \subsection installation_tbb TBB Library If \sc{Tbb} is not automatically found, the user must set the `TBB_ROOT` @@ -324,6 +339,44 @@ Note that the variables in the table below are being used. | `TBB_MALLOCPROXY_DEBUG_LIBRARY` | Full pathname of the compiled TBB debug malloc_proxy library (optional) | CMake | | `TBB_MALLOCPROXY_RELEASE_LIBRARY` | Full pathname of the compiled TBB release malloc_proxy library (optional) | CMake | +\subsection installation_laslib LASlib library + +If LASLIB is not automatically found, the following variables must be set: + +| Variable | Description | Type | +| :- | :- | :- | +| `LASLIB_INCLUDE_DIR` | Directory containing the file `lasreader.hpp` | CMake | +| `LASZIP_INCLUDE_DIR` | Directory containing the file `mydefs.hpp` | CMake | +| `LASLIB_LIBRARIES` | Full pathname of the compiled LASLIB library | CMake | + +\subsection installation_OpenCV OpenCV library + +The environment variable `OPENCV_DIR` should be set to the directory +containing the file `OpenCVConfig.cmake` provided by OpenCV. + +\subsection installation_TensorFlow TensorFlow library + +If TensorFlow is not automatically found, the following variables must be set: + +| Variable | Description | Type | +| :- | :- | :- | +| `TensorFlow_INCLUDE_DIR` | Directory containing the directories `tensorflow/core`, `tensorflow/cc`, etc. | CMake | +| `TensorFlow_LIBRARY` | Full pathname of the compiled TensorFlow C++ library | CMake | + +\subsection installation_SCIP SCIP library + +The environment variable `SCIP_DIR` should be set to the directory +containing the file `scip-config.cmake` provided by SCIP. + +\subsection installation_GLPK GLPK library + +If GLPK is not automatically found, the following variables must be set: + +| Variable | Description | Type | +| :- | :- | :- | +| `GLPK_INCLUDE_DIR` | Directory containing the file `glpk.h` | CMake | +| `GLPK_LIBRARIES` | Full pathname of the compiled GLPK library | CMake | + \section installation_compiler_workarounds Compiler Workarounds A number of boolean flags are used to workaround compiler bugs and diff --git a/Documentation/doc/Documentation/dependencies b/Documentation/doc/Documentation/dependencies index 80dae5968ef..88c6b6d48c1 100644 --- a/Documentation/doc/Documentation/dependencies +++ b/Documentation/doc/Documentation/dependencies @@ -102,3 +102,5 @@ Classification Hyperbolic_triangulation_2 Periodic_4_hyperbolic_triangulation_2 Surface_mesh_approximation +Surface_mesh_topology + diff --git a/Documentation/doc/Documentation/packages.txt b/Documentation/doc/Documentation/packages.txt index 8aa49408b96..f33f7dde95b 100644 --- a/Documentation/doc/Documentation/packages.txt +++ b/Documentation/doc/Documentation/packages.txt @@ -119,6 +119,7 @@ \package_listing{Stream_lines_2} \package_listing{Classification} \package_listing{Heat_method_3} +\package_listing{Surface_mesh_topology} \cgalPackageSection{PartSearchStructures,Spatial Searching and Sorting} diff --git a/Documentation/doc/Documentation/windows.txt b/Documentation/doc/Documentation/windows.txt index ca37e021001..c123b537496 100644 --- a/Documentation/doc/Documentation/windows.txt +++ b/Documentation/doc/Documentation/windows.txt @@ -37,8 +37,8 @@ The first step is to clone or download `vcpkg` from By default `vcpkg` installs for 32 bit binaries and will use the latest version of Visual C++ installed on your machine. If you develop 64 bit software you must -set the Windows environment variable `VCPKG_DEFAULT_TRIPLE` to `x64-windows` -or pass the option `--triplet x64-windows` whenever you install a package. +set the Windows environment variable `VCPKG_DEFAULT_TRIPLET` to `x64-windows` +or add the suffix `:x64-windows` to the package name you want to install (for example `cgal:x64-windows`). We refer to the official documentation of `vcpkg` if you want to compile for an older version of a compiler. diff --git a/Documentation/doc/biblio/cgal_manual.bib b/Documentation/doc/biblio/cgal_manual.bib index ec232cbda8e..41fe234c9dc 100644 --- a/Documentation/doc/biblio/cgal_manual.bib +++ b/Documentation/doc/biblio/cgal_manual.bib @@ -1543,6 +1543,13 @@ ABSTRACT = {We present the first complete, exact and efficient C++ implementatio ,update = "97.04 schoenherr" } +@misc{ cgal:m-ogr-17, + author = {Nicolas Mellado and others}, + title = {OpenGR: A C++ library for 3D Global Registration}, + howpublished = {https://storm-irit.github.io/OpenGR/}, + year = {2017} +} + @inproceedings{ cgal:m-pppd-96 ,author = "Kurt Mehlhorn" ,title = "Position Paper for Panel Discussion" @@ -1583,6 +1590,19 @@ ABSTRACT = {We present the first complete, exact and efficient C++ implementatio , booktitle = "Proceeding of IEEE Visualization" } +@article {cgal:mam-sffgp-14, + author = {Mellado, Nicolas and Aiger, Dror and Mitra, Niloy J.}, + title = {Super 4PCS Fast Global Pointcloud Registration via Smart Indexing}, + journal = {Computer Graphics Forum}, + volume = {33}, + number = {5}, + issn = {1467-8659}, + url = {http://dx.doi.org/10.1111/cgf.12446}, + doi = {10.1111/cgf.12446}, + pages = {205--215}, + year = {2014} +} + @inproceedings{ cgal:mdsb-ddgot-02, author="M. Meyer and M. Desbrun and P. Schr{\"o}der and A. H. Barr", title="Discrete Differential-Geometry Operators for Triangulated 2-Manifolds", diff --git a/Documentation/doc/biblio/geom.bib b/Documentation/doc/biblio/geom.bib index 81a983cac21..93ad91acdb8 100644 --- a/Documentation/doc/biblio/geom.bib +++ b/Documentation/doc/biblio/geom.bib @@ -152023,3 +152023,21 @@ pages = {179--189} HAL_ID = {inria-00412437}, HAL_VERSION = {v1}, } + +@InProceedings{ew-tcsr-13, + Title = {Transforming curves on surfaces redux}, + Author = {Erickson, Jeff and Whittelsey, Kim}, + Booktitle = {24rd Annual ACM-SIAM Symposium on Discrete Algorithms (SODA)}, + Year = {2013}, + Pages = {1646--1655}, + Url = {http://jeffe.cs.illinois.edu/pubs/pdf/dehn.pdf} + } + +@InProceedings{lr-hts-12, + Title = {On the homotopy test on surfaces}, + Author = {Lazarus, Francis and Rivaud, Julien}, + Booktitle = {53rd Annual IEEE Symposium on Foundations of Computer Science (FOCS)}, + Year = {2012}, + Pages = {440-449}, + Url = {http://arxiv.org/abs/1110.4573} +} \ No newline at end of file diff --git a/Documentation/doc/resources/1.8.13/cgal_stylesheet.css b/Documentation/doc/resources/1.8.13/cgal_stylesheet.css index 75907c829e2..7311b632554 100644 --- a/Documentation/doc/resources/1.8.13/cgal_stylesheet.css +++ b/Documentation/doc/resources/1.8.13/cgal_stylesheet.css @@ -339,3 +339,9 @@ div.fragment { padding: 4px; margin: 1em 4px 1em 4px; } + +/* Make summary smaller to avoid wrapping of classes and concepts */ +div.summary +{ + width: auto; +} diff --git a/Documentation/doc/resources/1.8.13/menu_version.js b/Documentation/doc/resources/1.8.13/menu_version.js index b6eb67f73fc..36b298ee045 100644 --- a/Documentation/doc/resources/1.8.13/menu_version.js +++ b/Documentation/doc/resources/1.8.13/menu_version.js @@ -3,12 +3,12 @@ var url_re = /(cgal\.geometryfactory\.com\/CGAL\/doc\/|doc\.cgal\.org\/)(master|latest|(\d\.\d+|\d\.\d+\.\d+))\//; var url_local = /.*\/doc_output\//; - var current_version_local = '5.0' + var current_version_local = '5.1-dev' var all_versions = [ 'master', 'latest', - '5.0', - '4.14.2', + '5.0.2', + '4.14.3', '4.13.2', '4.12.2', '4.11.3', diff --git a/Documentation/doc/resources/1.8.14/cgal_stylesheet.css b/Documentation/doc/resources/1.8.14/cgal_stylesheet.css index 5d2f6b629ff..c30ec92aa9e 100644 --- a/Documentation/doc/resources/1.8.14/cgal_stylesheet.css +++ b/Documentation/doc/resources/1.8.14/cgal_stylesheet.css @@ -339,3 +339,9 @@ div.fragment { padding: 4px; margin: 1em 4px 1em 4px; } + +/* Make summary smaller to avoid wrapping of classes and concepts */ +div.summary +{ + width: auto; +} diff --git a/Documentation/doc/resources/1.8.14/menu_version.js b/Documentation/doc/resources/1.8.14/menu_version.js index b6eb67f73fc..36b298ee045 100644 --- a/Documentation/doc/resources/1.8.14/menu_version.js +++ b/Documentation/doc/resources/1.8.14/menu_version.js @@ -3,12 +3,12 @@ var url_re = /(cgal\.geometryfactory\.com\/CGAL\/doc\/|doc\.cgal\.org\/)(master|latest|(\d\.\d+|\d\.\d+\.\d+))\//; var url_local = /.*\/doc_output\//; - var current_version_local = '5.0' + var current_version_local = '5.1-dev' var all_versions = [ 'master', 'latest', - '5.0', - '4.14.2', + '5.0.2', + '4.14.3', '4.13.2', '4.12.2', '4.11.3', diff --git a/Documentation/doc/resources/1.8.4/cgal_stylesheet.css b/Documentation/doc/resources/1.8.4/cgal_stylesheet.css index 3074c662f0f..c49b3c055ac 100644 --- a/Documentation/doc/resources/1.8.4/cgal_stylesheet.css +++ b/Documentation/doc/resources/1.8.4/cgal_stylesheet.css @@ -329,3 +329,10 @@ div.fragment { padding: 4px; margin: 1em 4px 1em 4px; } + + +/* Make summary smaller to avoid wrapping of classes and concepts */ +div.summary +{ + width: auto; +} diff --git a/Documentation/doc/resources/1.8.4/menu_version.js b/Documentation/doc/resources/1.8.4/menu_version.js index b6eb67f73fc..36b298ee045 100644 --- a/Documentation/doc/resources/1.8.4/menu_version.js +++ b/Documentation/doc/resources/1.8.4/menu_version.js @@ -3,12 +3,12 @@ var url_re = /(cgal\.geometryfactory\.com\/CGAL\/doc\/|doc\.cgal\.org\/)(master|latest|(\d\.\d+|\d\.\d+\.\d+))\//; var url_local = /.*\/doc_output\//; - var current_version_local = '5.0' + var current_version_local = '5.1-dev' var all_versions = [ 'master', 'latest', - '5.0', - '4.14.2', + '5.0.2', + '4.14.3', '4.13.2', '4.12.2', '4.11.3', diff --git a/Filtered_kernel/include/CGAL/Kernel_profiler.h b/Filtered_kernel/include/CGAL/Kernel_profiler.h index 9a55a12ea13..d592de79fc9 100644 --- a/Filtered_kernel/include/CGAL/Kernel_profiler.h +++ b/Filtered_kernel/include/CGAL/Kernel_profiler.h @@ -34,77 +34,13 @@ struct Primitive_profiler Primitive_profiler(const P& p = P()) : P(p) {} - template + template result_type - operator()(const A1 &a1) const + operator()(A&& ... a) const { CGAL_KERNEL_PROFILER; - return P::operator()(a1); + return P::operator()(std::forward(a)...); } - - template - result_type - operator()(const A1 &a1, const A2 &a2) const - { - CGAL_KERNEL_PROFILER; - return P::operator()(a1, a2); - } - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3) const - { - CGAL_KERNEL_PROFILER; - return P::operator()(a1, a2, a3); - } - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4) const - { - CGAL_KERNEL_PROFILER; - return P::operator()(a1, a2, a3, a4); - } - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5) const - { - CGAL_KERNEL_PROFILER; - return P::operator()(a1, a2, a3, a4, a5); - } - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5, const A6 &a6) const - { - CGAL_KERNEL_PROFILER; - return P::operator()(a1, a2, a3, a4, a5, a6); - } - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5, const A6 &a6, const A7 &a7) const - { - CGAL_KERNEL_PROFILER; - return P::operator()(a1, a2, a3, a4, a5, a6, a7); - } - - template - result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, - const A5 &a5, const A6 &a6, const A7 &a7, const A8 &a8) const - { - CGAL_KERNEL_PROFILER; - return P::operator()(a1, a2, a3, a4, a5, a6, a7, a8); - } - - // ... }; // We inherit all geometric objects from K, and just replace the primitives. diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 2a887d57b48..dd3616d4a7e 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -731,6 +731,9 @@ public : PTR = new Lazy_rep_0(std::move(e)); } + friend void swap(Lazy& a, Lazy& b) noexcept + { swap(static_cast(a), static_cast(b)); } + const AT& approx() const { return ptr()->approx(); } diff --git a/Filtered_kernel/include/CGAL/internal/Static_filters/Coplanar_3.h b/Filtered_kernel/include/CGAL/internal/Static_filters/Coplanar_3.h new file mode 100644 index 00000000000..20fbade4402 --- /dev/null +++ b/Filtered_kernel/include/CGAL/internal/Static_filters/Coplanar_3.h @@ -0,0 +1,54 @@ +// Copyright (c) 2011 GeometryFactory (France) +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Andreas Fabri, Laurent Rineau + + +#ifndef CGAL_INTERNAL_STATIC_FILTERS_COPLANAR_3_H +#define CGAL_INTERNAL_STATIC_FILTERS_COPLANAR_3_H + +namespace CGAL { + +namespace internal { + +namespace Static_filters_predicates { + + +template < typename K_base, typename SFK > +class Coplanar_3 + : public K_base::Coplanar_3 +{ + typedef typename K_base::Point_3 Point_3; + typedef typename K_base::Coplanar_3 Base; + typedef typename SFK::Orientation_3 Orientation_3; + +public: + + typedef typename Base::result_type result_type; + + + + result_type + operator()(const Point_3& p,const Point_3& q, const Point_3& r, const Point_3& s) const + { + return Orientation_3()(p,q,r,s) == COPLANAR; + } + + + +}; // end class Coplanar_3 + +} // end namespace Static_filters_predicates + +} // end namespace internal + +} // end namespace CGAL + +#endif // CGAL_INTERNAL_STATIC_FILTERS_COPLANAR_3_H diff --git a/Filtered_kernel/include/CGAL/internal/Static_filters/Static_filters.h b/Filtered_kernel/include/CGAL/internal/Static_filters/Static_filters.h index 9dbf6c02f5b..55bd1d3778b 100644 --- a/Filtered_kernel/include/CGAL/internal/Static_filters/Static_filters.h +++ b/Filtered_kernel/include/CGAL/internal/Static_filters/Static_filters.h @@ -41,7 +41,6 @@ #endif // CGAL_DISABLE_STATIC_FILTERS_ADDED_2011 - #ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS # include # include @@ -65,6 +64,7 @@ # include #endif // NOT NOT CGAL_NO_DO_INTERSECT_STATIC_FILTERS +#include #include #include #include @@ -121,6 +121,7 @@ public: typedef Static_filters_predicates::Side_of_oriented_circle_2 Side_of_oriented_circle_2; typedef Static_filters_predicates::Side_of_oriented_sphere_3 Side_of_oriented_sphere_3; typedef Static_filters_predicates::Compare_squared_radius_3 Compare_squared_radius_3; + typedef Static_filters_predicates::Coplanar_3 Coplanar_3; typedef Static_filters_predicates::Compare_weighted_squared_radius_3 Compare_weighted_squared_radius_3; typedef Static_filters_predicates::Power_side_of_oriented_power_sphere_3 Power_side_of_oriented_power_sphere_3; @@ -138,28 +139,28 @@ public: { return Collinear_3(); } #ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS - Equal_2 + Equal_2 equal_2_object() const { return Equal_2(); } - Equal_3 + Equal_3 equal_3_object() const { return Equal_3(); } #endif // NOT CGAL_NO_EQUAL_3_STATIC_FILTERS #ifndef CGAL_NO_COMPARE_X_2_STATIC_FILTERS - Compare_x_2 + Compare_x_2 compare_x_2_object() const { return Compare_x_2(); } -Compare_y_2 + Compare_y_2 compare_y_2_object() const { return Compare_y_2(); } #endif // NOT CGAL_NO_COMPARE_Y_2_STATIC_FILTERS #ifndef CGAL_NO_IS_DEGENERATE_3_STATIC_FILTERS - Is_degenerate_3 + Is_degenerate_3 is_degenerate_3_object() const { return Is_degenerate_3(); } #endif // NOT CGAL_NO_IS_DEGENERATE_3_STATIC_FILTERS @@ -182,7 +183,12 @@ Compare_y_2 compare_squared_radius_3_object() const { return Compare_squared_radius_3(); } - Power_side_of_oriented_power_sphere_3 power_side_of_oriented_power_sphere_3_object() const + Coplanar_3 + coplanar_3_object() const + { return Coplanar_3(); } + + Power_side_of_oriented_power_sphere_3 + power_side_of_oriented_power_sphere_3_object() const { return Power_side_of_oriented_power_sphere_3();} Compare_weighted_squared_radius_3 diff --git a/Generalized_map/include/CGAL/Generalized_map.h b/Generalized_map/include/CGAL/Generalized_map.h index 3365b9f8aeb..2b39468477f 100644 --- a/Generalized_map/include/CGAL/Generalized_map.h +++ b/Generalized_map/include/CGAL/Generalized_map.h @@ -181,13 +181,22 @@ namespace CGAL { * @param amap the generalized map to copy. * @post *this is valid. */ - template - void copy(const GMap2& amap, const Converters& converters, + void copy(const Generalized_map_base& amap, + const Converters& converters, const DartInfoConverter& dartinfoconverter, const PointConverter& pointconverter, - boost::unordered_map* dart_mapping=nullptr) + boost::unordered_map + :: + Dart_const_handle, Dart_handle>* origin_to_copy=NULL, + boost::unordered_map + ::Dart_const_handle>* copy_to_origin=NULL) { + typedef Generalized_map_base GMap2; this->clear(); this->mnb_used_marks = amap.mnb_used_marks; @@ -207,107 +216,145 @@ namespace CGAL { // Create an mapping between darts of the two maps (originals->copies). // (here we cannot use CGAL::Unique_hash_map because it does not provide // iterators... - boost::unordered_map local_dartmap; - if (dart_mapping==nullptr) - { dart_mapping=&local_dartmap; } - + boost::unordered_map + local_dartmap; + if (origin_to_copy==NULL) // Used local_dartmap if user does not provides its own unordered_map + { origin_to_copy=&local_dartmap; } + Dart_handle new_dart; for (typename GMap2::Dart_const_range::const_iterator it=amap.darts().begin(), itend=amap.darts().end(); it!=itend; ++it) { - (*dart_mapping)[it]=mdarts.emplace(); - init_dart((*dart_mapping)[it], amap.get_marks(it)); - internal::Copy_dart_info_functor:: - run(amap, static_cast(*this), it, (*dart_mapping)[it], - dartinfoconverter); + new_dart=mdarts.emplace(); + init_dart(new_dart, amap.get_marks(it)); + + (*origin_to_copy)[it]=new_dart; + if (copy_to_origin!=NULL) { (*copy_to_origin)[new_dart]=it; } + + internal::Copy_dart_info_functor:: + run(static_cast(amap), static_cast(*this), + it, new_dart, dartinfoconverter); } unsigned int min_dim=(dimension - ::iterator dartmap_iter, dartmap_iter_end=dart_mapping->end(); - for (dartmap_iter=dart_mapping->begin(); dartmap_iter!=dartmap_iter_end; + ::iterator dartmap_iter, dartmap_iter_end=origin_to_copy->end(); + for (dartmap_iter=origin_to_copy->begin(); dartmap_iter!=dartmap_iter_end; ++dartmap_iter) { for (unsigned int i=0; i<=min_dim; i++) { if (!amap.is_free(dartmap_iter->first,i) && - (dartmap_iter->first)<(amap.alpha(dartmap_iter->first,i))) + is_free(dartmap_iter->second,i)) { basic_link_alpha(dartmap_iter->second, - (*dart_mapping)[amap.alpha(dartmap_iter->first,i)], i); + (*origin_to_copy)[amap.alpha(dartmap_iter->first,i)], i); } } } /** Copy attributes */ - for (dartmap_iter=dart_mapping->begin(); dartmap_iter!=dartmap_iter_end; + for (dartmap_iter=origin_to_copy->begin(); dartmap_iter!=dartmap_iter_end; ++dartmap_iter) { Helper::template Foreach_enabled_attributes - < internal::Copy_attributes_functor >:: - run(amap, static_cast(*this), + run(static_cast(amap), static_cast(*this), dartmap_iter->first, dartmap_iter->second, converters, pointconverter); } - CGAL_assertion (is_valid () == 1); + CGAL_assertion(is_valid()); } - template - void copy(const GMap2& amap, - boost::unordered_map* dart_mapping=nullptr) + template + void copy(const Generalized_map_base& amap, + boost::unordered_map + :: + Dart_const_handle, Dart_handle>* origin_to_copy=NULL, + boost::unordered_map + ::Dart_const_handle>* copy_to_origin=NULL) { - std::tuple<> converters; - Default_converter_dart_info dartinfoconverter; - Default_converter_cmap_0attributes_with_point pointconverter; - copy(amap, converters, dartinfoconverter, pointconverter, dart_mapping); + CGAL::cpp11::tuple<> converters; + Default_converter_dart_info dartinfoconverter; + Default_converter_cmap_0attributes_with_point pointconverter; + copy(amap, converters, dartinfoconverter, pointconverter, + origin_to_copy, copy_to_origin); } - template - void copy(const GMap2& amap, const Converters& converters, - boost::unordered_map* dart_mapping=nullptr) + template + void copy(const Generalized_map_base& amap, + const Converters& converters, + boost::unordered_map + :: + Dart_const_handle, Dart_handle>* origin_to_copy=NULL, + boost::unordered_map + ::Dart_const_handle>* copy_to_origin=NULL) { - Default_converter_cmap_0attributes_with_point pointconverter; - Default_converter_dart_info dartinfoconverter; - copy(amap, converters, dartinfoconverter, pointconverter, dart_mapping); + Default_converter_cmap_0attributes_with_point pointconverter; + Default_converter_dart_info dartinfoconverter; + copy(amap, converters, dartinfoconverter, pointconverter, + origin_to_copy, copy_to_origin); } - template - void copy(const GMap2& amap, const Converters& converters, + template + void copy(const Generalized_map_base& amap, + const Converters& converters, const DartInfoConverter& dartinfoconverter, - boost::unordered_map* dart_mapping=nullptr) + boost::unordered_map + :: + Dart_const_handle, Dart_handle>* origin_to_copy=NULL, + boost::unordered_map + ::Dart_const_handle>* copy_to_origin=NULL) { - Default_converter_cmap_0attributes_with_point pointconverter; - copy(amap, converters, dartinfoconverter, pointconverter, dart_mapping); + Default_converter_cmap_0attributes_with_point pointconverter; + copy(amap, converters, dartinfoconverter, pointconverter, + origin_to_copy, copy_to_origin); } // Copy constructor from a map having exactly the same type. Generalized_map_base (const Self & amap) - { copy(amap); } - - // "Copy constructor" from a map having different type. - template - Generalized_map_base(const GMap2& amap) { copy(amap); } // "Copy constructor" from a map having different type. - template - Generalized_map_base(const GMap2& amap, Converters& converters) + template + Generalized_map_base(const Generalized_map_base& amap) + { copy(amap); } + + // "Copy constructor" from a map having different type. + template + Generalized_map_base(const Generalized_map_base& amap, + const Converters& converters) { copy(amap, converters); } // "Copy constructor" from a map having different type. - template - Generalized_map_base(const GMap2& amap, Converters& converters, + template + Generalized_map_base(const Generalized_map_base& amap, + const Converters& converters, const DartInfoConverter& dartinfoconverter) { copy(amap, converters, dartinfoconverter); } // "Copy constructor" from a map having different type. - template - Generalized_map_base(const GMap2& amap, Converters& converters, + Generalized_map_base(const Generalized_map_base& amap, + const Converters& converters, const DartInfoConverter& dartinfoconverter, const PointConverter& pointconverter) { copy(amap, converters, dartinfoconverter, pointconverter); } @@ -579,6 +626,11 @@ namespace CGAL { Dart_const_handle next(Dart_const_handle ADart) const { return this->template alpha<0, 1>(ADart); } + Dart_handle opposite2(Dart_handle ADart) + { return this->template alpha<0, 2>(ADart); } + Dart_const_handle opposite2(Dart_const_handle ADart) const + { return this->template alpha<0, 2>(ADart); } + template Dart_handle opposite(Dart_handle ADart) { return this->template alpha<0, dim>(ADart); } @@ -849,6 +901,27 @@ namespace CGAL { mnb_times_reserved_marks[amark]=0; } + template + bool belong_to_same_cell(Dart_const_handle adart1, + Dart_const_handle adart2) const + { return CGAL::belong_to_same_cell(*this, adart1, adart2); } + + template + bool is_whole_cell_unmarked(Dart_const_handle adart, size_type amark) const + { return CGAL::is_whole_cell_unmarked(*this, adart, amark); } + + template + bool is_whole_cell_marked(Dart_const_handle adart, size_type amark) const + { return CGAL::is_whole_cell_marked(*this, adart, amark); } + + template + size_type mark_cell(Dart_const_handle adart, size_type amark) const + { return CGAL::mark_cell(*this, adart, amark); } + + template + size_type unmark_cell(Dart_const_handle adart, size_type amark) const + { return CGAL::unmark_cell(*this, adart, amark); } + /** Test if this map is without boundary for a given dimension. * @param i the dimension. * @return true iff all the darts are not i-free. @@ -1647,6 +1720,61 @@ namespace CGAL { } public: + /// @return the positive turn between the two given darts. + // @pre next(d1) and d2 must belong to the same vertex. + std::size_t positive_turn(Dart_const_handle d1, Dart_const_handle d2) const + { + CGAL_assertion((!this->template is_free<1>(d1))); + /* CGAL_assertion((belong_to_same_cell<0>(this->next(d1), d2))); */ + + if (d2==opposite2(d1)) { return 0; } + + Dart_const_handle dd1=d1; + std::size_t res=1; + while (next(dd1)!=d2) + { + if (this->template is_free<2>(next(dd1))) + { return std::numeric_limits::max(); } + + ++res; + dd1=opposite2(next(dd1)); + + CGAL_assertion(!this->template is_free<1>(dd1)); + CGAL_assertion(next(dd1)==d2 || dd1!=d1); + } + return res; + } + + /// @return the negative turn between the two given darts. + // @pre next(d1) and d2 must belong to the same vertex. + std::size_t negative_turn(Dart_const_handle d1, Dart_const_handle d2) const + { + CGAL_assertion((!this->template is_free<1>(d1))); + /* CGAL_assertion((belong_to_same_cell<0>(this->next(d1), d2))); */ + + if (d2==opposite2(d1)) { return 0; } + + if (this->template is_free<2>(d1) || this->template is_free<2>(d2)) + { return std::numeric_limits::max(); } + + d1=opposite2(d1); + d2=opposite2(d2); + Dart_const_handle dd1=d1; + std::size_t res=1; + while (previous(dd1)!=d2) + { + if (this->template is_free<2>(previous(dd1))) + { return std::numeric_limits::max(); } + + ++res; + dd1=opposite2(previous(dd1)); + + CGAL_assertion(!this->template is_free<0>(dd1)); + CGAL_assertion(previous(dd1)==d2 || dd1!=d1); + } + return res; + } + /** Erase marked darts from the map. * Marked darts are unlinked before to be removed, thus surviving darts * are correctly linked, but the map is not necessarily valid depending @@ -1666,7 +1794,7 @@ namespace CGAL { if (is_marked(d, amark)) { for ( i = 0; i <= dimension; ++i) - { if (!is_free(d, i)) unlink_beta(d, i); } + { if (!is_free(d, i)) topo_unsew(d, i); } erase_dart(d); ++res; } } @@ -2766,12 +2894,12 @@ namespace CGAL { !is_face_combinatorial_polygon(d4, 3) ) return false; // TODO do better with marks (?). - if ( belong_to_same_cell(*this, d1, d2) || - belong_to_same_cell(*this, d1, d3) || - belong_to_same_cell(*this, d1, d4) || - belong_to_same_cell(*this, d2, d3) || - belong_to_same_cell(*this, d2, d4) || - belong_to_same_cell(*this, d3, d4) ) return false; + if ( belong_to_same_cell<2,1>(d1, d2) || + belong_to_same_cell<2,1>(d1, d3) || + belong_to_same_cell<2,1>(d1, d4) || + belong_to_same_cell<2,1>(d2, d3) || + belong_to_same_cell<2,1>(d2, d4) || + belong_to_same_cell<2,1>(d3, d4) ) return false; if ( alpha(d1, 0,1,2)!=alpha(d3,1) || alpha(d4, 1,2)!=alpha(d3,0,1) || @@ -2847,21 +2975,21 @@ namespace CGAL { !is_face_combinatorial_polygon(d6, 4) ) return false; // TODO do better with marks. - if ( belong_to_same_cell(*this, d1, d2) || - belong_to_same_cell(*this, d1, d3) || - belong_to_same_cell(*this, d1, d4) || - belong_to_same_cell(*this, d1, d5) || - belong_to_same_cell(*this, d1, d6) || - belong_to_same_cell(*this, d2, d3) || - belong_to_same_cell(*this, d2, d4) || - belong_to_same_cell(*this, d2, d5) || - belong_to_same_cell(*this, d2, d6) || - belong_to_same_cell(*this, d3, d4) || - belong_to_same_cell(*this, d3, d5) || - belong_to_same_cell(*this, d3, d6) || - belong_to_same_cell(*this, d4, d5) || - belong_to_same_cell(*this, d4, d6) || - belong_to_same_cell(*this, d5, d6) ) + if ( belong_to_same_cell<2,1>(d1, d2) || + belong_to_same_cell<2,1>(d1, d3) || + belong_to_same_cell<2,1>(d1, d4) || + belong_to_same_cell<2,1>(d1, d5) || + belong_to_same_cell<2,1>(d1, d6) || + belong_to_same_cell<2,1>(d2, d3) || + belong_to_same_cell<2,1>(d2, d4) || + belong_to_same_cell<2,1>(d2, d5) || + belong_to_same_cell<2,1>(d2, d6) || + belong_to_same_cell<2,1>(d3, d4) || + belong_to_same_cell<2,1>(d3, d5) || + belong_to_same_cell<2,1>(d3, d6) || + belong_to_same_cell<2,1>(d4, d5) || + belong_to_same_cell<2,1>(d4, d6) || + belong_to_same_cell<2,1>(d5, d6) ) return false; if ( alpha(d1,2) !=alpha(d4,1,0,1) || @@ -3020,7 +3148,7 @@ namespace CGAL { return alpha<0, 1>(adart); } - /** Insert a vertex in the given 2-cell which is splitted in triangles, + /** Insert a vertex in the given 2-cell which is split in triangles, * once for each inital edge of the facet. * @param adart a dart of the facet to triangulate. * @return A dart incident to the new vertex. @@ -3341,14 +3469,14 @@ namespace CGAL { if (prec!=null_handle) { // prec and *it must belong to the same vertex of the same volume - if ( !CGAL::belong_to_same_cell(*this, prec, *it) ) + if ( !belong_to_same_cell<0, 2>(prec, *it) ) return false; } prec = this->template alpha<0>(*it); } // The path must be closed. - if (!CGAL::belong_to_same_cell(*this, prec, *afirst)) + if (!belong_to_same_cell<0, 2>(prec, *afirst)) return false; return true; @@ -3589,24 +3717,34 @@ namespace CGAL { Generalized_map(const Self & amap) : Base(amap) {} - template < class Gmap > - Generalized_map(const Gmap & amap) : Base(amap) + template + Generalized_map(const Generalized_map_base& amap) : + Base(amap) {} - template < class Gmap, typename Converters > - Generalized_map(const Gmap & amap, const Converters& converters) : + template + Generalized_map(const Generalized_map_base& amap, + const Converters& converters) : Base(amap, converters) {} - template < class Gmap, typename Converters, typename DartInfoConverter > - Generalized_map(const Gmap & amap, const Converters& converters, + template + Generalized_map(const Generalized_map_base& amap, + const Converters& converters, const DartInfoConverter& dartinfoconverter) : Base(amap, converters, dartinfoconverter) {} - template < class Gmap, typename Converters, typename DartInfoConverter, - typename PointConverter > - Generalized_map(const Gmap & amap, const Converters& converters, + template + Generalized_map(const Generalized_map_base& amap, + const Converters& converters, const DartInfoConverter& dartinfoconverter, const PointConverter& pointconverter) : Base(amap, converters, dartinfoconverter, pointconverter) diff --git a/Generalized_map/include/CGAL/Generalized_map_storages.h b/Generalized_map/include/CGAL/Generalized_map_storages.h index 134a267d7a4..2e27d2acdb6 100644 --- a/Generalized_map/include/CGAL/Generalized_map_storages.h +++ b/Generalized_map/include/CGAL/Generalized_map_storages.h @@ -123,6 +123,8 @@ namespace CGAL { CGAL_assertion(i <= dimension); return dh->mf[i]==dh; } + bool is_perforated(Dart_const_handle /*dh*/) const + { return false; } /// Set simultaneously all the marks of this dart to a given value. void set_dart_marks(Dart_const_handle ADart, diff --git a/Generator/examples/Generator/CMakeLists.txt b/Generator/examples/Generator/CMakeLists.txt index 8ef7883800d..0fa1a97db40 100644 --- a/Generator/examples/Generator/CMakeLists.txt +++ b/Generator/examples/Generator/CMakeLists.txt @@ -12,9 +12,6 @@ if ( CGAL_FOUND ) # Use Eigen find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater) - if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - endif() # create a target per cppfile file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) @@ -23,6 +20,10 @@ if ( CGAL_FOUND ) OR NOT (${cppfile} STREQUAL "random_points_on_tetrahedral_mesh_3.cpp") OR EIGEN3_FOUND) create_single_source_cgal_program( "${cppfile}" ) + if (EIGEN3_FOUND) + get_filename_component(target ${cppfile} NAME_WE) + CGAL_target_use_Eigen(${target}) + endif() endif() endforeach() diff --git a/Generator/include/CGAL/point_generators_d.h b/Generator/include/CGAL/point_generators_d.h index 9661e647a42..9fc0b0b9193 100644 --- a/Generator/include/CGAL/point_generators_d.h +++ b/Generator/include/CGAL/point_generators_d.h @@ -18,6 +18,8 @@ #include #include +#include + #include #include @@ -56,11 +58,10 @@ generate_point() { for(int i=0; i_rnd.get_double(); a = std::sqrt( -2* std::log(1-a) ); double b=this->_rnd.get_double(); - b = std::cos(2*pi*b); + b = std::cos(2*CGAL_PI*b); coord[i]= a*b; norm += coord[i]*coord[i]; } @@ -104,11 +105,10 @@ generate_point() { for(int i=0; i_rnd.get_double(); a = std::sqrt( -2* std::log(1-a) ); double b=this->_rnd.get_double(); - b = std::cos(2*pi*b); + b = std::cos(2*CGAL_PI*b); coord[i]= a*b; norm += coord[i]*coord[i]; } diff --git a/Generator/test/Generator/CMakeLists.txt b/Generator/test/Generator/CMakeLists.txt index 8842178b20b..0eb1657d2a9 100644 --- a/Generator/test/Generator/CMakeLists.txt +++ b/Generator/test/Generator/CMakeLists.txt @@ -12,15 +12,16 @@ if ( CGAL_FOUND ) # Use Eigen find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater) - if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - endif() # create a target per cppfile file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(cppfile ${cppfiles}) if(NOT (${cppfile} STREQUAL "generic_random_test.cpp") OR EIGEN3_FOUND) create_single_source_cgal_program( "${cppfile}" ) + if (EIGEN3_FOUND) + get_filename_component(target ${cppfile} NAME_WE) + CGAL_target_use_Eigen(${target}) + endif() endif() endforeach() diff --git a/GraphicsView/demo/Polygon/CMakeLists.txt b/GraphicsView/demo/Polygon/CMakeLists.txt index 8d0df276e19..1a84a55e34a 100644 --- a/GraphicsView/demo/Polygon/CMakeLists.txt +++ b/GraphicsView/demo/Polygon/CMakeLists.txt @@ -16,9 +16,7 @@ endif() find_package(CGAL COMPONENTS Qt5 Core) find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) -if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) -else() +if (NOT EIGEN3_FOUND) message(STATUS "NOTICE: This project requires the Eigen library, and will not be compiled.") return() endif() @@ -48,6 +46,7 @@ if ( CGAL_FOUND AND CGAL_Qt5_FOUND AND Qt5_FOUND ) # The executable itself. add_executable ( Polygon_2 Polygon_2.cpp ${DT_UI_FILES} ${DT_RESOURCE_FILES} ${CGAL_Qt5_RESOURCE_FILES} ${CGAL_Qt5_MOC_FILES} ) + CGAL_target_use_Eigen(Polygon_2) add_to_cached_list( CGAL_EXECUTABLE_TARGETS Polygon_2 ) diff --git a/GraphicsView/include/CGAL/Buffer_for_vao.h b/GraphicsView/include/CGAL/Buffer_for_vao.h index e6f7cb8e341..a166558b25f 100644 --- a/GraphicsView/include/CGAL/Buffer_for_vao.h +++ b/GraphicsView/include/CGAL/Buffer_for_vao.h @@ -71,7 +71,7 @@ namespace internal static typename Local_kernel::Point_3 get_local_point(const typename K::Point_2& p) { CGAL::Cartesian_converter converter; - return typename Local_kernel::Point_3(converter(p.x()), 0, converter(p.y())); + return typename Local_kernel::Point_3(converter(p.x()), converter(p.y()), 0); } static typename Local_kernel::Point_3 get_local_point(const typename K::Weighted_point_2& p) { @@ -91,7 +91,7 @@ namespace internal static typename Local_kernel::Vector_3 get_local_vector(const typename K::Vector_2& v) { CGAL::Cartesian_converter converter; - return typename Local_kernel::Vector_3(converter(v.x()), 0, converter(v.y())); + return typename Local_kernel::Vector_3(converter(v.x()), converter(v.y()), 0); } static typename Local_kernel::Vector_3 get_local_vector(const typename K::Vector_3& v) { @@ -110,15 +110,15 @@ namespace internal struct Geom_utils { static typename Local_kernel::Point_3 get_local_point(const typename Local_kernel::Point_2& p) - { return typename Local_kernel::Point_3(p.x(), 0, p.y()); } + { return typename Local_kernel::Point_3(p.x(), p.y(), 0); } static typename Local_kernel::Point_3 get_local_point(const typename Local_kernel::Weighted_point_2& p) - { return typename Local_kernel::Point_3(p.point().x(), 0, p.point().y());} + { return typename Local_kernel::Point_3(p.point().x(), p.point().y(), 0);} static const typename Local_kernel::Point_3 & get_local_point(const typename Local_kernel::Point_3& p) { return p; } static typename Local_kernel::Point_3 get_local_point(const typename Local_kernel::Weighted_point_3& p) { return typename Local_kernel::Point_3(p);} static typename Local_kernel::Vector_3 get_local_vector(const typename Local_kernel::Vector_2& v) - { return typename Local_kernel::Vector_3(v.x(), 0, v.y()); } + { return typename Local_kernel::Vector_3(v.x(), v.y(), 0); } static const typename Local_kernel::Vector_3& get_local_vector(const typename Local_kernel::Vector_3& v) { return v; } static const typename Local_kernel::Ray_2& get_local_ray(const typename Local_kernel::Ray_2& r) @@ -406,8 +406,8 @@ public: if (m_points_of_face.size()<3) { - std::cerr<<"PB: you try to triangulate a face with "<key()==::Qt::Key_U) && (modifiers==::Qt::NoButton)) + { + if (is_two_dimensional()) + { + displayMessage(QString("Move camera direction upside down.")); + /* CGAL::qglviewer::Vec cur=camera()->viewDirection(); + double cx=cur.x, cy=cur.y, cz=cur.z; + if (has_zero_x()) { cx=-cx; } + else if (has_zero_y()) { cy=-cy; } + else { cz=-cz; } + double cx=0., cy=0., cz=0.; + if (has_zero_x()) { cx=(cur.x<0?-1.:1); } + else if (has_zero_y()) { cy=(cur.y<0?-1.:1); } + else { cz=(cur.z<0?-1.:1); }*/ + + camera()->setUpVector(-camera()->upVector()); + //camera()->frame()->setConstraint(NULL); + // camera()->setViewDirection(CGAL::qglviewer::Vec(-cx,-cy,-cz)); + //constraint.setRotationConstraintDirection(CGAL::qglviewer::Vec(cx, cy, cz)); + //camera()->frame()->setConstraint(&constraint); + //update(); + redraw(); + } + } else if ((e->key()==::Qt::Key_T) && (modifiers==::Qt::NoButton)) { m_draw_text=!m_draw_text; diff --git a/GraphicsView/include/CGAL/Qt/DemosMainWindow_impl.h b/GraphicsView/include/CGAL/Qt/DemosMainWindow_impl.h index dd02f4170da..5fcd56a002c 100644 --- a/GraphicsView/include/CGAL/Qt/DemosMainWindow_impl.h +++ b/GraphicsView/include/CGAL/Qt/DemosMainWindow_impl.h @@ -195,7 +195,6 @@ void DemosMainWindow::setUseAntialiasing(bool checked) { view->setRenderHint(QPainter::Antialiasing, checked); - view->setRenderHint(QPainter::HighQualityAntialiasing, checked); statusBar()->showMessage(tr("Antialiasing %1activated").arg(checked?"":"de-"), 1000); diff --git a/GraphicsView/include/CGAL/Qt/manipulatedFrame.h b/GraphicsView/include/CGAL/Qt/manipulatedFrame.h index 5cac20e055f..bbef82923c0 100644 --- a/GraphicsView/include/CGAL/Qt/manipulatedFrame.h +++ b/GraphicsView/include/CGAL/Qt/manipulatedFrame.h @@ -21,6 +21,7 @@ #include #include #include +#include namespace CGAL{ namespace qglviewer { @@ -348,7 +349,7 @@ private: qreal zoomSensitivity_; // Mouse speed and spinning - QTime last_move_time; + QElapsedTimer last_move_time; qreal mouseSpeed_; int delay_; bool isSpinning_; diff --git a/GraphicsView/include/CGAL/Qt/qglviewer.h b/GraphicsView/include/CGAL/Qt/qglviewer.h index 605bba35dc4..feddd6e72b2 100644 --- a/GraphicsView/include/CGAL/Qt/qglviewer.h +++ b/GraphicsView/include/CGAL/Qt/qglviewer.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include @@ -1038,7 +1038,7 @@ protected: int animationTimerId_; // F P S d i s p l a y - QTime fpsTime_; + QElapsedTimer fpsTime_; unsigned int fpsCounter_; QString fpsString_; qreal f_p_s_; diff --git a/GraphicsView/include/CGAL/Qt/qglviewer_impl.h b/GraphicsView/include/CGAL/Qt/qglviewer_impl.h index f0e9a5b5334..8b2cad8f9a1 100644 --- a/GraphicsView/include/CGAL/Qt/qglviewer_impl.h +++ b/GraphicsView/include/CGAL/Qt/qglviewer_impl.h @@ -46,6 +46,7 @@ #include #include #include +#include namespace CGAL{ // Static private variable @@ -2244,7 +2245,7 @@ void CGAL::QGLViewer::keyPressEvent(QKeyEvent *e) { unsigned int index = pathIndex_[::Qt::Key(key)]; // not safe, but try to double press on two viewers at the same time ! - static QTime doublePress; + static QElapsedTimer doublePress; if (modifiers == playPathKeyboardModifiers()) { int elapsed = doublePress.restart(); diff --git a/GraphicsView/src/CGAL_Qt5/CMakeLists.txt b/GraphicsView/src/CGAL_Qt5/CMakeLists.txt index 224de8bbe4b..c9ab3d99241 100644 --- a/GraphicsView/src/CGAL_Qt5/CMakeLists.txt +++ b/GraphicsView/src/CGAL_Qt5/CMakeLists.txt @@ -31,8 +31,8 @@ if(COMMAND add_config_flag) add_config_flag( CGAL_HAS_QT5 ) endif() +install(DIRECTORY "../../include/CGAL/Qt/" DESTINATION "${CGAL_INSTALL_INC_DIR}/CGAL/Qt" COMPONENT CGAL_Qt5) if (CGAL_HEADER_ONLY) - install(DIRECTORY "../../include/CGAL/Qt/" DESTINATION "${CGAL_INSTALL_INC_DIR}/CGAL/include/CGAL/Qt" COMPONENT CGAL_Qt5) install(DIRECTORY "../../demo/resources/" DESTINATION "${CGAL_INSTALL_CMAKE_DIR}/demo/resources" COMPONENT CGAL_Qt5) install(DIRECTORY "../../demo/icons/" DESTINATION "${CGAL_INSTALL_CMAKE_DIR}/demo/icons" COMPONENT CGAL_Qt5) endif() diff --git a/Hash_map/test/Hash_map/Hash.cpp b/Hash_map/test/Hash_map/Hash.cpp index fc46d118a25..beb15ce87f0 100644 --- a/Hash_map/test/Hash_map/Hash.cpp +++ b/Hash_map/test/Hash_map/Hash.cpp @@ -145,8 +145,9 @@ int main() #ifdef CGAL_LINKED_WITH_TBB Triangulation_3 T3; -fct3(T3); + fct3(T3); #endif + return 0; } diff --git a/Heat_method_3/examples/Heat_method_3/CMakeLists.txt b/Heat_method_3/examples/Heat_method_3/CMakeLists.txt index ee40274e08e..f9703071b81 100644 --- a/Heat_method_3/examples/Heat_method_3/CMakeLists.txt +++ b/Heat_method_3/examples/Heat_method_3/CMakeLists.txt @@ -34,11 +34,8 @@ endif() find_package(Eigen3 3.3.0) -if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) -else() +if (NOT EIGEN3_FOUND) message(STATUS "This project requires the Eigen library (3.3 or greater), and will not be compiled.") - return() endif() @@ -54,6 +51,10 @@ include_directories( BEFORE include ) include( CGAL_CreateSingleSourceCGALProgram ) create_single_source_cgal_program( "heat_method.cpp" ) +CGAL_target_use_Eigen(heat_method) create_single_source_cgal_program( "heat_method_polyhedron.cpp" ) +CGAL_target_use_Eigen(heat_method_polyhedron) create_single_source_cgal_program( "heat_method_surface_mesh.cpp" ) +CGAL_target_use_Eigen(heat_method_surface_mesh) create_single_source_cgal_program( "heat_method_surface_mesh_direct.cpp" ) +CGAL_target_use_Eigen(heat_method_surface_mesh_direct) diff --git a/Heat_method_3/test/Heat_method_3/CMakeLists.txt b/Heat_method_3/test/Heat_method_3/CMakeLists.txt index adb6cfa80c0..af4fd6eb470 100644 --- a/Heat_method_3/test/Heat_method_3/CMakeLists.txt +++ b/Heat_method_3/test/Heat_method_3/CMakeLists.txt @@ -34,11 +34,8 @@ endif() find_package(Eigen3 3.3.0) -if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) -else() +if (NOT EIGEN3_FOUND) message(STATUS "This project requires the Eigen library (3.3 or greater), and will not be compiled.") - return() endif() @@ -52,5 +49,8 @@ include_directories( BEFORE include ) include( CGAL_CreateSingleSourceCGALProgram ) create_single_source_cgal_program( "heat_method_concept.cpp" ) +CGAL_target_use_Eigen(heat_method_concept) create_single_source_cgal_program( "heat_method_surface_mesh_test.cpp" ) +CGAL_target_use_Eigen(heat_method_surface_mesh_test) create_single_source_cgal_program( "heat_method_surface_mesh_direct_test.cpp" ) +CGAL_target_use_Eigen(heat_method_surface_mesh_direct_test) diff --git a/INSTALL.md b/INSTALL.md index 8913be934e0..50f7a3d3e8c 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,55 +1,52 @@ -NOTICE -====== +Building an Example or a Demo of CGAL +===================================== -Since Version 5.0, CGAL is a header-only library it is not needed -to build and install it. Usage of CGAL should thus simply amount to: +Since Version 5.0, CGAL is a header-only library, hence it is not needed to build it. Usage of CGAL should simply amount to: ``` {.bash} git clone https://github.com/CGAL/cgal.git /path/to/cgal.git cd /path/to/cgal.git/Triangulation_2/examples/Triangulation_2 mkdir -p build/debug cd build/debug -cmake -DCMAKE_BUILD_TYPE=Debug -DCGAL_DIR=/path/to/cgal.git +cmake -DCMAKE_BUILD_TYPE=Debug -DCGAL_DIR=/path/to/cgal.git ../.. make ``` -in the case of the building of an example in debug mode. - -For more information head over to the [CGAL manual](https://doc.cgal.org/latest/Manual/general_intro.html). -Note that this page describes the setting of CGAL as a sources release and, as such, -files are organized in a slightly different way, see the [Layout of the CGAL Git Repository](README.md). +in the case of building some CGAL-provided examples in debug mode. +Note that although CGAL is a header-only library, some parts of it must link to several external libraries, such as GMP, MPFR, etc. Building a Program Using CGAL ============================= -To compile a program using CGAL, simply set `CGAL_DIR` to the location -of the directory containing `CGALConfig.cmake` (for example the root -of the extracted source archive or the root of a git checkout). - -Here is an example of how to build in debug the examples from the 3D Triangulations package: +If you wish to build a program that is not provided with CGAL and does not already have a `CMakeLists.txt`, +you can trigger the creation of a basic `CMakeLists.txt` by calling the script [`cgal_create_cmake_script`](Scripts/scripts/cgal_create_cmake_script) +found in `/path/to/cgal.git/Scripts/scripts/` at the root of your program directory. ``` {.bash} - cd /path/to/cgal.git/Triangulation_3/examples/Triangulation_3 - mkdir -p build/debug - cd build/debug - cmake -DCGAL_DIR:PATH=/path/to/cgal.git ../.. - make -``` - -If you are trying to build examples or tests that do not already have a `CMakeLists.txt`, -you can trigger its creation by calling the script [`cgal_create_cmake_script`](Scripts/scripts/cgal_create_cmake_script) -found in `/path/to/cgal.git/Scripts/scripts/` at the root of the example/test directory. -Here is an example for the examples of the 2D Triangulation package: - -``` {.bash} - cd /path/to/cgal.git/Triangulation_2/examples/Triangulation_2 + git clone https://github.com/CGAL/cgal.git /path/to/cgal.git + cd /path/to/your/program /path/to/cgal.git/Scripts/scripts/cgal_create_cmake_script - cd /path/to/cgal.git/Triangulation_2/examples/Triangulation_2 mkdir -p build/debug cd build/debug - cmake -DCGAL_DIR:PATH=/path/to/cgal.git ../.. - make + cmake -DCMAKE_BUILD_TYPE=Debug -DCGAL_DIR:PATH=/path/to/cgal.git ../.. + make your_program ``` -For more information head over to the [CGAL manual](https://doc.cgal.org/latest/Manual/general_intro.html). +Since the basic `CMakeLists.txt` created by the script `cgal_create_cmake_script` cannot +guess which part(s) of CGAL you are using, it does not link with any optional third party +dependency of CGAL. You should look at the documentation of the package(s) that you +are using to learn which dependencies you must add. The `CMakeLists.txt` +of the examples and demos provided with the package(s) that you are using can be used +to complete your basic `CMakeLists.txt`. + + +Repository Structure +==================== + +If you have downloaded a source release instead of cloning the Git repository, the files will be organized in a slightly different way, see the [Layout of the CGAL Git Repository](README.md). + +Documentation +============= + +For more information see the [CGAL manual](https://doc.cgal.org/latest/Manual/general_intro.html). diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 85bb3555c90..7affa98b961 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -1,19 +1,65 @@ Release History =============== -Release 5.1 +[Release 5.1] (https://github.com/CGAL/cgal/releases/tag/releases%2FCGAL-5.1) ----------- Release date: June 2020 +### Surface Mesh Topology (new package) + + - This package allows to compute some topological invariants of + surfaces. For now, it is possible to test if two (closed) curves + on a combinatorial surface are homotopic. The user can choose + between free homotopy and homotopy with fixed endpoints. + A contractibility test is also provided. + ### 3D Fast Intersection and Distance Computation - **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()`. + +### CGAL and the Boost Graph Library (BGL) + - Introduced the function `set_triangulation_ids(Triangulation& tr)` which must be used to initialize vertex, + edge, and face indices of a triangulation meant to be used with BGL algorithms. + - Added function `alpha_expansion_graphcut()` which regularizes a + multi-label partition over a user-defined graph. + ### Polygon Mesh Processing +- Introduced a new function, `CGAL::Polygon_mesh_processing::remove_connected_components_of_negligible_size()`, + which can be used to remove connected components whose area or volume is under a certain threshold. + Area and volume thresholds are either specified by the user or deduced from the bounding box of the mesh. +- Added a new named parameter for `keep_large_connected_components()` and `remove_connected_components_of_negligible_size` + that can be used to perform a dry run of the operation, meaning that the function will return the number of connected + 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. +- New function to split meshes along a mesh or a plane: + `CGAL::Polygon_mesh_processing::split()` +- New function to split a single mesh containing several connected components into several meshes containing one connected component: + `CGAL::Polygon_mesh_processing::split_connected_components()` + - Added parallel versions of the functions `CGAL::Polygon_mesh_processing::does_self_intersect()` + and `CGAL::Polygon_mesh_processing::self_intersections()`. + - The function `CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh` now allows passing a point map (for the point range) + and a vertex point map (for the polygon mesh) via named parameters. + - Added the function `CGAL::Polygon_mesh_processing::polygon_mesh_to_polygon_soup()`. + +### Point Set Processing + - Added wrapper functions for registration: + - `CGAL::OpenGR::compute_registration_transformation()` computes the registration transformation + for two point sets using Super4PCS algorithm implemented in the third party library OpenGR. + - `CGAL::OpenGR::register_point_sets()` computes the registration transformation for two point + sets using Super4PCS algorithm implemented in the third party library OpenGR, and registers + the points sets by transforming the data point set using the computed transformation. + - `CGAL::pointmatcher::compute_registration_transformation()` computes the registration + transformation for two point sets using ICP algorithm implemented in the third party library + libpointmatcher. + - `CGAL::pointmatcher::register_point_sets()` computes the registration transformation for two point + sets using ICP algorithm implemented in the third party library libpointmatcher, and registers + the points sets by transforming the data point set using the computed transformation. ### 2D Triangulations - To fix an inconsistency between code and documentation and to clarify which types of intersections @@ -51,6 +97,10 @@ Release date: June 2020 k-NN search to interrupt some distance computations before its end, saving precious milliseconds, in particular in medium-to-high dimension. +### Spatial Sorting + - Added parallel versions of `hilbert_sort()` and `spatial_sort()` in 2D and 3D when the median policy is used. + The parallel versions use up to four threads in 2D, and up to eight threads in 3D. + ### dD Geometry Kernel - Epick\_d and Epeck\_d gain 2 new functors: `Power_side_of_bounded_power_sphere_d` and `Compute_squared_radius_smallest_orthogonal_sphere_d`. Those are @@ -61,9 +111,12 @@ Release date: June 2020 - The concept "EdgeProfile" has been removed. This concept was not actually in use as the CGAL-provided model `CGAL::Edge_profile` was imposed to the user. Other concepts have been clarified to reflect the fact that the API uses this particular class. -### CGAL and the Boost Graph Library (BGL) -- Added function `alpha_expansion_graphcut()` which regularizes a - multi-label partition over a user-defined graph. +### STL Extensions for CGAL + - Added a new concurrency tag: `CGAL::Parallel_if_available_tag`. This tag is a convenience typedef to `CGAL::Parallel_tag` + if the third party library TBB has been found and linked with, and to `CGAL::Sequential_tag` otherwise. + +### Convex_hull_3 +- A new overload for `convex_hull_3()` that takes a model of `VertexListGraph` has been added. [Release 5.0](https://github.com/CGAL/cgal/releases/tag/releases%2FCGAL-5.0) diff --git a/Installation/CMakeLists.txt b/Installation/CMakeLists.txt index db6e3120e77..4b5aaa2f173 100644 --- a/Installation/CMakeLists.txt +++ b/Installation/CMakeLists.txt @@ -568,10 +568,6 @@ message("== Detect external libraries ==") # Coin is used in KDS, but no FindCoin or FindCOIN exists # There exists FindIPE, FindMKL, but they are only used to support supporting libs list (INSERT CGAL_SUPPORTING_3RD_PARTY_LIBRARIES 0 GMP MPFR ZLIB OpenGL LEDA MPFI RS RS3 OpenNL Eigen3 ESBTL Coin3D NTL IPE) -if (NOT WIN32) - # GMPXX is not supported on WIN32 machines - list (INSERT CGAL_SUPPORTING_3RD_PARTY_LIBRARIES 1 GMPXX) -endif() # Where CMake is run several times, to avoid duplicates list(REMOVE_DUPLICATES CGAL_SUPPORTING_3RD_PARTY_LIBRARIES) @@ -611,8 +607,6 @@ if(CGAL_DISABLE_GMP) unset(WITH_GMP CACHE) unset(CGAL_USE_GMP) unset(CGAL_USE_GMP CACHE) - unset(WITH_GMPXX) - unset(WITH_GMPXX CACHE) unset(WITH_MPFR) unset(WITH_MPFR CACHE) @@ -621,9 +615,6 @@ if(CGAL_DISABLE_GMP) "#error GMP is disabled by the CMake option CGAL_DISABLE_GMP") else() list(APPEND CGAL_ESSENTIAL_3RD_PARTY_LIBRARIES GMP MPFR) - if(WITH_GMPXX) - list(APPEND CGAL_ESSENTIAL_3RD_PARTY_LIBRARIES GMPXX) - endif() # When CMake is run several times, to avoid duplicates list (REMOVE_DUPLICATES CGAL_ESSENTIAL_3RD_PARTY_LIBRARIES) @@ -643,7 +634,7 @@ foreach (lib ${CGAL_SUPPORTING_3RD_PARTY_LIBRARIES}) # add option list( FIND CGAL_ESSENTIAL_3RD_PARTY_LIBRARIES "${lib}" POSITION ) if ( "${POSITION}" STRGREATER "-1" ) # if lib is essential - option(WITH_${lib} "Select external library ${lib}" ON) + option(WITH_${lib} "Select external library ${lib}" ON) else() option(WITH_${lib} "Select external library ${lib}" OFF) endif() @@ -891,11 +882,11 @@ endif() foreach (dir ${CGAL_CONFIGURED_PACKAGES}) if (EXISTS ${dir}/include/CGAL) - install(DIRECTORY ${dir}/include/CGAL DESTINATION ${CGAL_INSTALL_INC_DIR} PATTERN ".svn" EXCLUDE) + install(DIRECTORY ${dir}/include/CGAL DESTINATION ${CGAL_INSTALL_INC_DIR} PATTERN ".svn" EXCLUDE PATTERN "Qt" EXCLUDE) endif() endforeach() if(EXISTS ${CMAKE_BINARY_DIR}/include/CGAL) - install(DIRECTORY ${CMAKE_BINARY_DIR}/include/CGAL DESTINATION ${CGAL_INSTALL_INC_DIR} PATTERN ".svn" EXCLUDE) + install(DIRECTORY ${CMAKE_BINARY_DIR}/include/CGAL DESTINATION ${CGAL_INSTALL_INC_DIR} PATTERN ".svn" EXCLUDE PATTERN "Qt" EXCLUDE) endif() file(GLOB scripts "scripts/*") diff --git a/Installation/cmake/modules/CGAL_Common.cmake b/Installation/cmake/modules/CGAL_Common.cmake index 51967d5f6d5..786763eb01f 100644 --- a/Installation/cmake/modules/CGAL_Common.cmake +++ b/Installation/cmake/modules/CGAL_Common.cmake @@ -61,5 +61,15 @@ if( NOT CGAL_COMMON_FILE_INCLUDED ) # set use-file for Eigen3 (needed to have default solvers) set(EIGEN3_USE_FILE "UseEigen3") + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_Boost_IOStreams.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_Boost_Serialization.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_Eigen.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_GLPK.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_LASLIB.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_OpenCV.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_OpenGR.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_pointmatcher.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_SCIP.cmake) include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_TBB.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/CGAL_target_use_TensorFlow.cmake) endif() diff --git a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake index f0a2f7c3ea3..9125a477c93 100644 --- a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake +++ b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake @@ -119,12 +119,23 @@ function(CGAL_setup_CGAL_dependencies target) # Now setup compilation flags if(MSVC) target_compile_options(${target} ${keyword} - "-D_SCL_SECURE_NO_DEPRECATE;-D_SCL_SECURE_NO_WARNINGS" - "/fp:strict" - "/fp:except-" - "/wd4503" # Suppress warnings C4503 about "decorated name length exceeded" - "/bigobj" # Use /bigobj by default - ) + "-D_SCL_SECURE_NO_DEPRECATE;-D_SCL_SECURE_NO_WARNINGS") + if(CMAKE_VERSION VERSION_LESS 3.11) + target_compile_options(${target} ${keyword} + /fp:strict + /fp:except- + /wd4503 # Suppress warnings C4503 about "decorated name length exceeded" + /bigobj # Use /bigobj by default + ) + else() + # The MSVC generator supports `$` since CMake 3.11. + target_compile_options(${target} ${keyword} + $<$:/fp:strict> + $<$:/fp:except-> + $<$:/wd4503> # Suppress warnings C4503 about "decorated name length exceeded" + $<$:/bigobj> # Use /bigobj by default + ) + endif() elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") message( STATUS "Using Intel Compiler. Adding -fp-model strict" ) if(WIN32) diff --git a/Installation/cmake/modules/CGAL_SetupGMP.cmake b/Installation/cmake/modules/CGAL_SetupGMP.cmake index 1a8c28a3c13..6627df01796 100644 --- a/Installation/cmake/modules/CGAL_SetupGMP.cmake +++ b/Installation/cmake/modules/CGAL_SetupGMP.cmake @@ -23,12 +23,12 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CGAL_MODULES_DIR}) find_package(GMP REQUIRED) find_package(MPFR REQUIRED) +find_package(GMPXX QUIET) -if(NOT DEFINED WITH_GMPXX) +if(NOT GMPXX_FOUND) option(CGAL_WITH_GMPXX "Use CGAL with GMPXX: use C++ classes of GNU MP instead of CGAL wrappers" OFF) -endif() -if(WITH_GMPXX OR CGAL_WITH_GMPXX) - find_package(GMPXX REQUIRED) +else() + option(CGAL_WITH_GMPXX "Use CGAL with GMPXX: use C++ classes of GNU MP instead of CGAL wrappers" ON) endif() #.rst: diff --git a/Installation/cmake/modules/CGAL_target_use_Boost_IOStreams.cmake b/Installation/cmake/modules/CGAL_target_use_Boost_IOStreams.cmake new file mode 100644 index 00000000000..d57f785d54f --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_Boost_IOStreams.cmake @@ -0,0 +1,39 @@ +if (CGAL_target_use_Boost_IOStreams_included) + return() +endif() +set(CGAL_target_use_Boost_IOStreams_included TRUE) + +function(CGAL_target_use_Boost_IOStreams target) + + if( WIN32 ) + # to avoid a warning with old cmake + set(_Boost_BZIP2_HEADERS "boost/iostreams/filter/bzip2.hpp") + set(_Boost_ZLIB_HEADERS "boost/iostreams/filter/zlib.hpp") + find_package( Boost OPTIONAL_COMPONENTS bzip2 zlib) + else() + find_package(ZLIB QUIET) + endif() + + if(TARGET Boost::iostreams) + target_link_libraries(${target} PUBLIC Boost::iostreams) + else() + target_link_libraries(${target} PUBLIC ${Boost_IOSTREAMS_LIBRARY}) + endif() + + if( WIN32 ) + if (Boost_ZLIB_FOUND AND Boost_BZIP2_FOUND) + target_link_libraries(${target} PUBLIC ${Boost_ZLIB_LIBRARY} ${Boost_BZIP2_LIBRARY}) + else() + message(STATUS "NOTICE: This project requires Boost ZLIB and Boost BZIP2, and will not be compiled.") + return() + endif() + else() + if(ZLIB_FOUND) + target_link_libraries(${target} PUBLIC ZLIB::ZLIB) + else() + message(STATUS "NOTICE: This project requires ZLIB, and will not be compiled.") + return() + endif() + endif() + +endfunction() diff --git a/Installation/cmake/modules/CGAL_target_use_Boost_Serialization.cmake b/Installation/cmake/modules/CGAL_target_use_Boost_Serialization.cmake new file mode 100644 index 00000000000..d6ae805efd8 --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_Boost_Serialization.cmake @@ -0,0 +1,14 @@ +if (CGAL_target_use_Boost_Serialization_included) + return() +endif() +set(CGAL_target_use_Boost_Serialization_included TRUE) + +function(CGAL_target_use_Boost_Serialization target) + + if(TARGET Boost::serialization) + target_link_libraries(${target} PUBLIC Boost::serialization) + else() + target_link_libraries(${target} PUBLIC ${Boost_SERIALIZATION_LIBRARY}) + endif() + +endfunction() diff --git a/Installation/cmake/modules/CGAL_target_use_Eigen.cmake b/Installation/cmake/modules/CGAL_target_use_Eigen.cmake new file mode 100644 index 00000000000..84f9f3be721 --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_Eigen.cmake @@ -0,0 +1,13 @@ +if (CGAL_target_use_Eigen_included) + return() +endif() +set(CGAL_target_use_Eigen_included TRUE) + +set( Eigen3_FIND_VERSION "3.1.0") +set(EIGEN3_USE_FILE "UseEigen3") + +function(CGAL_target_use_Eigen target) + target_include_directories(${target} PUBLIC ${EIGEN3_INCLUDE_DIR}) + target_compile_options( ${target} PUBLIC -DCGAL_EIGEN3_ENABLED) +endfunction() + diff --git a/Installation/cmake/modules/CGAL_target_use_GLPK.cmake b/Installation/cmake/modules/CGAL_target_use_GLPK.cmake new file mode 100644 index 00000000000..f19bd315b16 --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_GLPK.cmake @@ -0,0 +1,11 @@ +if (CGAL_target_use_GLPK_included) + return() +endif() +set(CGAL_target_use_GLPK_included TRUE) + +function(CGAL_target_use_GLPK target) + target_include_directories(${target} PUBLIC ${GLPK_INCLUDE_DIR}) + target_compile_options(${target} PUBLIC -DCGAL_USE_GLPK) + target_link_libraries(${target} PUBLIC ${GLPK_LIBRARIES}) +endfunction() + diff --git a/Installation/cmake/modules/CGAL_target_use_LASLIB.cmake b/Installation/cmake/modules/CGAL_target_use_LASLIB.cmake new file mode 100644 index 00000000000..65ad9084e5a --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_LASLIB.cmake @@ -0,0 +1,11 @@ +if (CGAL_target_use_LASLIB_included) + return() +endif() +set(CGAL_target_use_LASLIB_included TRUE) + +function(CGAL_target_use_LASLIB target) + target_include_directories(${target} PUBLIC ${LASLIB_INCLUDE_DIR}) + target_include_directories(${target} PUBLIC ${LASZIP_INCLUDE_DIR}) + target_compile_options( ${target} PUBLIC -DCGAL_LINKED_WITH_LASLIB) + target_link_libraries(${target} PUBLIC ${LASLIB_LIBRARIES}) +endfunction() diff --git a/Installation/cmake/modules/CGAL_target_use_OpenCV.cmake b/Installation/cmake/modules/CGAL_target_use_OpenCV.cmake new file mode 100644 index 00000000000..d378d50aead --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_OpenCV.cmake @@ -0,0 +1,10 @@ +if (CGAL_target_use_OpenCV_included) + return() +endif() +set(CGAL_target_use_OpenCV_included TRUE) + +function(CGAL_target_use_OpenCV target) + target_include_directories(${target} PUBLIC ${OpenCV_INCLUDE_DIRS}) + target_compile_options( ${target} PUBLIC -DCGAL_LINKED_WITH_OPENCV) + target_link_libraries(${target} PUBLIC ${OpenCV_LIBS}) +endfunction() diff --git a/Installation/cmake/modules/CGAL_target_use_OpenGR.cmake b/Installation/cmake/modules/CGAL_target_use_OpenGR.cmake new file mode 100644 index 00000000000..dc6044f8926 --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_OpenGR.cmake @@ -0,0 +1,9 @@ +if (CGAL_target_use_OpenGR_included) + return() +endif() +set(CGAL_target_use_OpenGR_included TRUE) + +function(CGAL_target_use_OpenGR target) + target_include_directories(${target} PUBLIC ${OpenGR_INCLUDE_DIR}) + target_compile_options( ${target} PUBLIC -DCGAL_LINKED_WITH_OPENGR) +endfunction() diff --git a/Installation/cmake/modules/CGAL_target_use_SCIP.cmake b/Installation/cmake/modules/CGAL_target_use_SCIP.cmake new file mode 100644 index 00000000000..354216bb1f7 --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_SCIP.cmake @@ -0,0 +1,11 @@ +if (CGAL_target_use_SCIP_included) + return() +endif() +set(CGAL_target_use_SCIP_included TRUE) + +function(CGAL_target_use_SCIP target) + target_include_directories(${target} PUBLIC ${SCIP_INCLUDE_DIRS}) + target_compile_options(${target} PUBLIC -DCGAL_USE_SCIP) + target_link_libraries(${target} PUBLIC ${SCIP_LIBRARIES}) +endfunction() + diff --git a/Installation/cmake/modules/CGAL_target_use_TensorFlow.cmake b/Installation/cmake/modules/CGAL_target_use_TensorFlow.cmake new file mode 100644 index 00000000000..80bda689dab --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_TensorFlow.cmake @@ -0,0 +1,10 @@ +if (CGAL_target_use_TensorFlow_included) + return() +endif() +set(CGAL_target_use_TensorFlow_included TRUE) + +function(CGAL_target_use_TensorFlow target) + target_include_directories(${target} PUBLIC ${TensorFlow_INCLUDE_DIR}) + target_compile_options( ${target} PUBLIC -DCGAL_LINKED_WITH_TENSORFLOW) + target_link_libraries(${target} PUBLIC ${TensorFlow_LIBRARU}) +endfunction() diff --git a/Installation/cmake/modules/CGAL_target_use_pointmatcher.cmake b/Installation/cmake/modules/CGAL_target_use_pointmatcher.cmake new file mode 100644 index 00000000000..5047815a336 --- /dev/null +++ b/Installation/cmake/modules/CGAL_target_use_pointmatcher.cmake @@ -0,0 +1,10 @@ +if (CGAL_target_use_pointmatcher_included) + return() +endif() +set(CGAL_target_use_pointmatcher_included TRUE) + +function(CGAL_target_use_pointmatcher target) + target_include_directories(${target} PUBLIC ${libpointmatcher_INCLUDE_DIR}) + target_compile_options( ${target} PUBLIC -DCGAL_LINKED_WITH_POINTMATCHER) + target_link_libraries(${target} PUBLIC ${libpointmatcher_LIBRARIES}) +endfunction() diff --git a/Installation/cmake/modules/FindGLPK.cmake b/Installation/cmake/modules/FindGLPK.cmake index b2e6f4476c5..9e060acf81d 100644 --- a/Installation/cmake/modules/FindGLPK.cmake +++ b/Installation/cmake/modules/FindGLPK.cmake @@ -15,7 +15,7 @@ if (NOT GLPK_FOUND) ) find_library(GLPK_LIBRARIES - NAMES libglpk + NAMES libglpk glpk PATHS ENV LD_LIBRARY_PATH ENV LIBRARY_PATH /usr/local/lib diff --git a/Installation/cmake/modules/FindLibSSH.cmake b/Installation/cmake/modules/FindLibSSH.cmake new file mode 100644 index 00000000000..e2c49ee2fce --- /dev/null +++ b/Installation/cmake/modules/FindLibSSH.cmake @@ -0,0 +1,39 @@ +# - Try to find the LibSSH libraries +# This module defines: +# LIBSSH_FOUND - system has LibSSH lib +# LIBSSH_INCLUDE_DIR - the LibSSH include directory +# LIBSSH_LIBRARIES_DIR - directory where the LibSSH libraries are located +# LIBSSH_LIBRARIES - Link these to use LibSSH + + +include(FindPackageHandleStandardArgs) +include(${CMAKE_CURRENT_LIST_DIR}/CGAL_GeneratorSpecificSettings.cmake) + +if(LIBSSH_INCLUDE_DIR) + set(LIBSSH_in_cache TRUE) +else() + set(LIBSSH_in_cache FALSE) +endif() +if(NOT LIBSSH_LIBRARIES) + set(LIBSSH_in_cache FALSE) +endif() + +# Is it already configured? +if( NOT LIBSSH_in_cache ) + + find_path(LIBSSH_INCLUDE_DIR + NAMES "libssh/libssh.h" + ) + + find_library(LIBSSH_LIBRARIES NAMES ssh libssh + HINTS "/usr/lib" + "usr/lib/x86_64-linux-gnu" + PATH_SUFFIXES lib + DOC "Path to the LIBSSH library" + ) +endif() + +SET(LIBSSH_FOUND TRUE) +if( NOT LIBSSH_LIBRARIES OR NOT LIBSSH_INCLUDE_DIR) + SET(LIBSSH_FOUND FALSE) +endif() diff --git a/Installation/cmake/modules/FindOpenMesh.cmake b/Installation/cmake/modules/FindOpenMesh.cmake index 1a6bad504dd..823ede4de3c 100644 --- a/Installation/cmake/modules/FindOpenMesh.cmake +++ b/Installation/cmake/modules/FindOpenMesh.cmake @@ -6,6 +6,8 @@ # OPENMESH_LIBRARIES - OpenMesh libraries # +find_package(OpenMesh NO_MODULE QUIET) + # Is it already configured? if (NOT OpenMesh_FOUND) @@ -44,7 +46,34 @@ endif() include( FindPackageHandleStandardArgs ) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenMesh - REQUIRED_VARS OPENMESH_INCLUDE_DIR OPENMESH_LIBRARIES - FOUND_VAR OpenMesh_FOUND - ) +find_package_handle_standard_args(OpenMesh + REQUIRED_VARS OPENMESH_INCLUDE_DIR OPENMESH_LIBRARIES + FOUND_VAR OpenMesh_FOUND + ) + +if(OpenMesh_FOUND AND NOT TARGET OpenMesh::OpenMesh) + add_library(OpenMesh::OpenMesh UNKNOWN IMPORTED) + + if(TARGET OpenMeshCore) + target_link_libraries(OpenMesh::OpenMesh PUBLIC OpenMeshCore) + return() + endif() + + set_target_properties(OpenMesh::OpenMesh PROPERTIES + INTERFACE_COMPILE_DEFINITIONS "CGAL_USE_OPENMESH;NOMINMAX;_USE_MATH_DEFINES" + INTERFACE_INCLUDE_DIRECTORIES "${OPENMESH_INCLUDE_DIR}") + + if(OPENMESH_LIBRARY_RELEASE) + set_property(TARGET OpenMesh::OpenMesh APPEND PROPERTY + IMPORTED_CONFIGURATIONS RELEASE) + set_target_properties(OpenMesh::OpenMesh PROPERTIES + IMPORTED_LOCATION_RELEASE "${OPENMESH_LIBRARY_RELEASE}") + endif() + + if(OPENMESH_LIBRARY_DEBUG) + set_property(TARGET OpenMesh::OpenMesh APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(OpenMesh::OpenMesh PROPERTIES + IMPORTED_LOCATION_DEBUG "${OPENMESH_LIBRARY_DEBUG}") + endif() +endif() diff --git a/Installation/cmake/modules/UseEigen3.cmake b/Installation/cmake/modules/UseEigen3.cmake index e3ed18be243..850bb638392 100644 --- a/Installation/cmake/modules/UseEigen3.cmake +++ b/Installation/cmake/modules/UseEigen3.cmake @@ -7,3 +7,5 @@ include_directories( SYSTEM ${EIGEN3_INCLUDE_DIR} ) add_definitions(-DCGAL_EIGEN3_ENABLED) set (EIGEN3_SETUP TRUE) + +message(DEPRECATION "This file UseEigen.cmake is deprecated, and the function `CGAL_target_use_Eigen` from CGAL_target_use_Eigen.cmake should be used instead.") diff --git a/Installation/cmake/modules/UseLASLIB.cmake b/Installation/cmake/modules/UseLASLIB.cmake index 9235230eb1f..99f3374a24f 100644 --- a/Installation/cmake/modules/UseLASLIB.cmake +++ b/Installation/cmake/modules/UseLASLIB.cmake @@ -2,3 +2,6 @@ # It assumes that find_package(LASLIB) was already called. add_definitions(-DCGAL_LINKED_WITH_LASLIB) + +message(DEPRECATION "This file UseLASLIB.cmake is deprecated, and the function `CGAL_target_use_LASLIB` from CGAL_target_use_LASLIB.cmake should be used instead.") + diff --git a/Installation/include/CGAL/Surface_mesh/Surface_mesh_fwd.h b/Installation/include/CGAL/Surface_mesh/Surface_mesh_fwd.h index 5672f0b6780..95b8da61f33 100644 --- a/Installation/include/CGAL/Surface_mesh/Surface_mesh_fwd.h +++ b/Installation/include/CGAL/Surface_mesh/Surface_mesh_fwd.h @@ -17,7 +17,7 @@ namespace CGAL { // fwdS for the public interface -template +template class Surface_mesh; diff --git a/Installation/include/CGAL/license/Surface_mesh_topology.h b/Installation/include/CGAL/license/Surface_mesh_topology.h new file mode 100644 index 00000000000..57f92380b3a --- /dev/null +++ b/Installation/include/CGAL/license/Surface_mesh_topology.h @@ -0,0 +1,54 @@ +// Copyright (c) 2016 GeometryFactory SARL (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 +// +// Warning: this file is generated, see include/CGAL/licence/README.md + +#ifndef CGAL_LICENSE_SURFACE_MESH_TOPOLOGY_H +#define CGAL_LICENSE_SURFACE_MESH_TOPOLOGY_H + +#include +#include + +#ifdef CGAL_SURFACE_MESH_TOPOLOGY_COMMERCIAL_LICENSE + +# if CGAL_SURFACE_MESH_TOPOLOGY_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE + +# if defined(CGAL_LICENSE_WARNING) + + CGAL_pragma_warning("Your commercial license for CGAL does not cover " + "this release of the Surface Mesh Topology package.") +# endif + +# ifdef CGAL_LICENSE_ERROR +# error "Your commercial license for CGAL does not cover this release \ + of the Surface Mesh Topology package. \ + You get this error, as you defined CGAL_LICENSE_ERROR." +# endif // CGAL_LICENSE_ERROR + +# endif // CGAL_SURFACE_MESH_TOPOLOGY_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE + +#else // no CGAL_SURFACE_MESH_TOPOLOGY_COMMERCIAL_LICENSE + +# if defined(CGAL_LICENSE_WARNING) + CGAL_pragma_warning("\nThe macro CGAL_SURFACE_MESH_TOPOLOGY_COMMERCIAL_LICENSE is not defined." + "\nYou use the CGAL Surface Mesh Topology package under " + "the terms of the GPLv3+.") +# endif // CGAL_LICENSE_WARNING + +# ifdef CGAL_LICENSE_ERROR +# error "The macro CGAL_SURFACE_MESH_TOPOLOGY_COMMERCIAL_LICENSE is not defined.\ + You use the CGAL Surface Mesh Topology package under the terms of \ + the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR." +# endif // CGAL_LICENSE_ERROR + +#endif // no CGAL_SURFACE_MESH_TOPOLOGY_COMMERCIAL_LICENSE + +#endif // CGAL_LICENSE_SURFACE_MESH_TOPOLOGY_H diff --git a/Installation/include/CGAL/license/gpl_package_list.txt b/Installation/include/CGAL/license/gpl_package_list.txt index 9841982de7d..c82b04d0784 100644 --- a/Installation/include/CGAL/license/gpl_package_list.txt +++ b/Installation/include/CGAL/license/gpl_package_list.txt @@ -82,6 +82,7 @@ Surface_mesh_segmentation Triangulated Surface Mesh Segmentation Surface_mesh_shortest_path Triangulated Surface Mesh Shortest Paths Surface_mesh_simplification Triangulated Surface Mesh Simplification Surface_mesh_skeletonization Triangulated Surface Mesh Skeletonization +Surface_mesh_topology Surface Mesh Topology Surface_sweep_2 2D Intersection of Curves TDS_2 2D Triangulation Data Structure TDS_3 3D Triangulation Data Structure diff --git a/Installation/include/CGAL/version.h b/Installation/include/CGAL/version.h index 5277243907f..85ff9e71cad 100644 --- a/Installation/include/CGAL/version.h +++ b/Installation/include/CGAL/version.h @@ -16,10 +16,12 @@ #ifndef CGAL_VERSION_H #define CGAL_VERSION_H +#ifndef SWIG #define CGAL_VERSION 5.1 +#define CGAL_GIT_HASH abcdef +#endif #define CGAL_VERSION_NR 1050100000 #define CGAL_SVN_REVISION 99999 -#define CGAL_GIT_HASH abcdef #define CGAL_RELEASE_DATE 20191108 #include diff --git a/Intersections_3/test/Intersections_3/call_test.cpp b/Intersections_3/test/Intersections_3/call_test.cpp index 768c7d4ac6e..96da5418020 100644 --- a/Intersections_3/test/Intersections_3/call_test.cpp +++ b/Intersections_3/test/Intersections_3/call_test.cpp @@ -52,11 +52,13 @@ void call_do_intersect_with_kernel(const A& a, const B& b, const K&) { } -int main() +int main(int argc, char**) { CGAL::Interval_nt_advanced::Protector p; CGAL_USE(p); - try { + //we only want to check compilation + if(argc > 666 ) + { call_intersection_global(S(), S()); call_intersection_global(S(), L()); call_intersection_global(S(), Pl()); @@ -264,10 +266,6 @@ int main() call_do_intersect_with_kernel(Bbox_3(), S(), K()); call_do_intersect_with_kernel(Bbox_3(), Sph(), K()); call_do_intersect_with_kernel(Bbox_3(), Tr(), K()); - // There is no kernel to call - // call_do_intersect_with_kernel(Bbox_3(), Bbox_3(), K()); - } catch(...) { - // as long as this test compiles, it is fine } return EXIT_SUCCESS; } diff --git a/Jet_fitting_3/examples/Jet_fitting_3/CMakeLists.txt b/Jet_fitting_3/examples/Jet_fitting_3/CMakeLists.txt index 19a1b9d32bd..d53b00b46a6 100644 --- a/Jet_fitting_3/examples/Jet_fitting_3/CMakeLists.txt +++ b/Jet_fitting_3/examples/Jet_fitting_3/CMakeLists.txt @@ -14,7 +14,6 @@ if ( CGAL_FOUND ) # use Eigen find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) # Link with Boost.ProgramOptions (optional) find_package(Boost QUIET COMPONENTS program_options) if(Boost_PROGRAM_OPTIONS_FOUND) @@ -30,9 +29,11 @@ if ( CGAL_FOUND ) list(APPEND CGAL_3RD_PARTY_LIBRARIES ${Boost_PROGRAM_OPTIONS_LIBRARY}) endif() - create_single_source_cgal_program( "Mesh_estimation.cpp" ) - create_single_source_cgal_program( "Single_estimation.cpp" ) - + create_single_source_cgal_program( "Mesh_estimation.cpp" ) + CGAL_target_use_Eigen(Mesh_estimation) + create_single_source_cgal_program( "Single_estimation.cpp" ) + CGAL_target_use_Eigen(Single_estimation) + else() message(STATUS "NOTICE: This program requires Eigen 3.1 (or greater) and will not be compiled.") endif() diff --git a/Jet_fitting_3/test/Jet_fitting_3/CMakeLists.txt b/Jet_fitting_3/test/Jet_fitting_3/CMakeLists.txt index c1cbc58150d..feff5e7bb7a 100644 --- a/Jet_fitting_3/test/Jet_fitting_3/CMakeLists.txt +++ b/Jet_fitting_3/test/Jet_fitting_3/CMakeLists.txt @@ -14,8 +14,8 @@ if ( CGAL_FOUND ) # use Eigen find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) create_single_source_cgal_program( "blind_1pt.cpp" ) + CGAL_target_use_Eigen(blind_1pt) else() message(STATUS "NOTICE: This program requires Eigen 3.1 (or greater) and will not be compiled.") endif() diff --git a/Kernel_23/doc/Kernel_23/CGAL/Filtered_predicate.h b/Kernel_23/doc/Kernel_23/CGAL/Filtered_predicate.h index 4d0ba6880ec..b08e4274f56 100644 --- a/Kernel_23/doc/Kernel_23/CGAL/Filtered_predicate.h +++ b/Kernel_23/doc/Kernel_23/CGAL/Filtered_predicate.h @@ -59,19 +59,13 @@ Filtered_predicate(); /// @} /// \name Operations -/// Similar function operators are defined for up to 7 arguments. /// @{ /*! -The unary function operator for unary predicates. +The function operator for predicates. */ -template result_type operator()(A1 a1); +template result_type operator()(A a...); -/*! -The binary function operator for binary predicates. -*/ -template -result_type operator()(A1 a1, A2 a2); /// @} diff --git a/Kernel_23/include/CGAL/Kernel/interface_macros.h b/Kernel_23/include/CGAL/Kernel/interface_macros.h index efe62876159..908a6dd277c 100644 --- a/Kernel_23/include/CGAL/Kernel/interface_macros.h +++ b/Kernel_23/include/CGAL/Kernel/interface_macros.h @@ -110,8 +110,8 @@ CGAL_Kernel_pred(Compare_dihedral_angle_3, compare_dihedral_angle_3_object) CGAL_Kernel_pred(Compare_distance_2, compare_distance_2_object) -CGAL_Kernel_pred_RT(Compare_distance_3, - compare_distance_3_object) +CGAL_Kernel_pred(Compare_distance_3, + compare_distance_3_object) CGAL_Kernel_pred_RT(Compare_power_distance_2, compare_power_distance_2_object) CGAL_Kernel_pred_RT(Compare_power_distance_3, @@ -488,7 +488,7 @@ CGAL_Kernel_pred_RT(Coplanar_orientation_3, coplanar_orientation_3_object) CGAL_Kernel_pred_RT(Coplanar_side_of_bounded_circle_3, coplanar_side_of_bounded_circle_3_object) -CGAL_Kernel_pred(Coplanar_3, +CGAL_Kernel_pred_RT(Coplanar_3, coplanar_3_object) CGAL_Kernel_pred(Counterclockwise_in_between_2, counterclockwise_in_between_2_object) diff --git a/Kernel_23/include/CGAL/Kernel_checker.h b/Kernel_23/include/CGAL/Kernel_checker.h index a4ee19def63..483ab5b645d 100644 --- a/Kernel_23/include/CGAL/Kernel_checker.h +++ b/Kernel_23/include/CGAL/Kernel_checker.h @@ -79,164 +79,21 @@ public: : p1(pp1), p2(pp2), cmp(c) { } - template - typename Pairify::type, - typename CGAL::cpp11::result_of::type>::result_type - operator()(const A1 &a1) const + template + typename Pairify::type, + typename CGAL::cpp11::result_of::type>::result_type + operator()(const A&... a) const { - typedef typename CGAL::cpp11::result_of::type result_type_1; - typedef typename CGAL::cpp11::result_of::type result_type_2; - result_type_1 res1 = p1(a1.first); - result_type_2 res2 = p2(a1.second); + typedef typename CGAL::cpp11::result_of::type result_type_1; + typedef typename CGAL::cpp11::result_of::type result_type_2; + result_type_1 res1 = p1(a.first...); + result_type_2 res2 = p2(a.second...); if (! cmp(res1, res2)) { - std::cerr << "Kernel_checker error : " << res1 << " != " << res2 - << " for the inputs : " << std::endl; - std::cerr << a1.first << std::endl; - std::cerr << a1.second << std::endl; - std::cerr << "functor first kernel : " - << typeid(p1).name() << std::endl; - std::cerr << "functor second kernel: " - << typeid(p2).name() << std::endl; - std::cerr << CGAL_PRETTY_FUNCTION << std::endl; CGAL_kernel_assertion(false); } return Pairify()(res1, res2); } - - template - typename Pairify::type, - typename CGAL::cpp11::result_of::type>::result_type - operator()(const A1 &a1, const A2 &a2) const - { - typedef typename CGAL::cpp11::result_of::type result_type_1; - typedef typename CGAL::cpp11::result_of::type result_type_2; - result_type_1 res1 = p1(a1.first, a2.first); - result_type_2 res2 = p2(a1.second, a2.second); - if (! cmp(res1, res2)) - { - std::cerr << "Kernel_checker error : " << res1 << " != " << res2 - << " for the inputs : " << std::endl; - std::cerr << a1.first << std::endl; - std::cerr << a1.second << std::endl; - std::cerr << a2.first << std::endl; - std::cerr << a2.second << std::endl; - std::cerr << "functor first kernel : " - << typeid(p1).name() << std::endl; - std::cerr << "functor second kernel: " - << typeid(p2).name() << std::endl; - std::cerr << CGAL_PRETTY_FUNCTION << std::endl; - CGAL_kernel_assertion(false); - } - return Pairify()(res1, res2); - } - - template - typename Pairify::type, - typename CGAL::cpp11::result_of::type>::result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3) const - { - typedef typename CGAL::cpp11::result_of::type result_type_1; - typedef typename CGAL::cpp11::result_of::type result_type_2; - result_type_1 res1 = p1(a1.first, a2.first, a3.first); - result_type_2 res2 = p2(a1.second, a2.second, a3.second); - if (! cmp(res1, res2)) - { - std::cerr << "Kernel_checker error : " << res1 << " != " << res2 - << " for the inputs : " << std::endl; - std::cerr << a1.first << std::endl; - std::cerr << a1.second << std::endl; - std::cerr << a2.first << std::endl; - std::cerr << a2.second << std::endl; - std::cerr << a3.first << std::endl; - std::cerr << a3.second << std::endl; - std::cerr << "functor first kernel : " - << typeid(p1).name() << std::endl; - std::cerr << "functor second kernel: " - << typeid(p2).name() << std::endl; - std::cerr << CGAL_PRETTY_FUNCTION << std::endl; - CGAL_kernel_assertion(false); - } - return Pairify()(res1, res2); - } - - template - typename Pairify::type, - typename CGAL::cpp11::result_of::type>::result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4) const - { - typedef typename CGAL::cpp11::result_of::type result_type_1; - typedef typename CGAL::cpp11::result_of::type result_type_2; - - result_type_1 res1 = p1(a1.first, a2.first, a3.first, a4.first); - result_type_2 res2 = p2(a1.second, a2.second, a3.second, a4.second); - if (! cmp(res1, res2)) - { - std::cerr << "Kernel_checker error : " << res1 << " != " << res2 - << " for the inputs : " << std::endl; - std::cerr << a1.first << std::endl; - std::cerr << a1.second << std::endl; - std::cerr << a2.first << std::endl; - std::cerr << a2.second << std::endl; - std::cerr << a3.first << std::endl; - std::cerr << a3.second << std::endl; - std::cerr << a4.first << std::endl; - std::cerr << a4.second << std::endl; - std::cerr << "functor first kernel : " - << typeid(p1).name() << std::endl; - std::cerr << "functor second kernel: " - << typeid(p2).name() << std::endl; - std::cerr << CGAL_PRETTY_FUNCTION << std::endl; - CGAL_kernel_assertion(false); - } - return Pairify()(res1, res2); - } - - template - typename Pairify::type, - typename CGAL::cpp11::result_of::type>::result_type - operator()(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5) const - { - typedef typename CGAL::cpp11::result_of::type result_type_1; - typedef typename CGAL::cpp11::result_of::type result_type_2; - - result_type_1 res1 = p1(a1.first, a2.first, a3.first, a4.first, a5.first); - result_type_2 res2 = p2(a1.second, a2.second, a3.second, a4.second, a5.second); - if (! cmp(res1, res2)) - { - std::cerr << "Kernel_checker error : " << res1 << " != " << res2 - << " for the inputs : " << std::endl; - std::cerr << a1.first << std::endl; - std::cerr << a1.second << std::endl; - std::cerr << a2.first << std::endl; - std::cerr << a2.second << std::endl; - std::cerr << a3.first << std::endl; - std::cerr << a3.second << std::endl; - std::cerr << a4.first << std::endl; - std::cerr << a4.second << std::endl; - std::cerr << a5.first << std::endl; - std::cerr << a5.second << std::endl; - std::cerr << "functor first kernel : " - << typeid(p1).name() << std::endl; - std::cerr << "functor second kernel: " - << typeid(p2).name() << std::endl; - std::cerr << CGAL_PRETTY_FUNCTION << std::endl; - CGAL_kernel_assertion(false); - } - return Pairify()(res1, res2); - } - - // Same thing with more arguments... }; struct dont_check_equal { diff --git a/Kernel_23/include/CGAL/Point_2.h b/Kernel_23/include/CGAL/Point_2.h index a5b00bb1eb9..7358d0dc46b 100644 --- a/Kernel_23/include/CGAL/Point_2.h +++ b/Kernel_23/include/CGAL/Point_2.h @@ -48,12 +48,12 @@ public: typedef RPoint_2 Rep; typedef typename R_::Cartesian_const_iterator_2 Cartesian_const_iterator; - const Rep& rep() const + const Rep& rep() const noexcept { return *this; } - Rep& rep() + Rep& rep() noexcept { return *this; } @@ -84,6 +84,15 @@ public: : RPoint_2(typename R::Construct_point_2()(Return_base_tag(), hx, hy, hw)) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.rep(), b.rep()); + } + typename cpp11::result_of::type x() const { diff --git a/Kernel_23/include/CGAL/Point_3.h b/Kernel_23/include/CGAL/Point_3.h index bf3952fb0dc..01b07bd3e0e 100644 --- a/Kernel_23/include/CGAL/Point_3.h +++ b/Kernel_23/include/CGAL/Point_3.h @@ -46,12 +46,12 @@ public: typedef typename R_::Kernel_base::Point_3 Rep; typedef typename R_::Cartesian_const_iterator_3 Cartesian_const_iterator; - const Rep& rep() const + const Rep& rep() const noexcept { return *this; } - Rep& rep() + Rep& rep() noexcept { return *this; } @@ -81,6 +81,15 @@ public: : Rep(typename R::Construct_point_3()(Return_base_tag(), hx, hy, hz, hw)) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.rep(), b.rep()); + } + typename cpp11::result_of::type x() const { diff --git a/Kernel_23/include/CGAL/Vector_2.h b/Kernel_23/include/CGAL/Vector_2.h index 4f570ed6b02..67f07e5e3e6 100644 --- a/Kernel_23/include/CGAL/Vector_2.h +++ b/Kernel_23/include/CGAL/Vector_2.h @@ -54,12 +54,12 @@ public: typedef RVector_2 Rep; typedef typename R_::Cartesian_const_iterator_2 Cartesian_const_iterator; - const Rep& rep() const + const Rep& rep() const noexcept { return *this; } - Rep& rep() + Rep& rep() noexcept { return *this; } @@ -93,6 +93,15 @@ public: Vector_2(const RT &x, const RT &y, const RT &w) : RVector_2(typename R::Construct_vector_2()(Return_base_tag(), x,y,w)) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.rep(), b.rep()); + } + typename cpp11::result_of::type x() const diff --git a/Kernel_23/include/CGAL/Vector_3.h b/Kernel_23/include/CGAL/Vector_3.h index c3c7c0bc953..077da5d649d 100644 --- a/Kernel_23/include/CGAL/Vector_3.h +++ b/Kernel_23/include/CGAL/Vector_3.h @@ -93,6 +93,15 @@ public: Vector_3(const RT& x, const RT& y, const RT& z, const RT& w) : Rep(typename R::Construct_vector_3()(Return_base_tag(), x, y, z, w)) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.rep(), b.rep()); + } + Direction_3 direction() const { return R().construct_direction_3_object()(*this); diff --git a/Kernel_d/include/CGAL/Kernel_d/function_objects.h b/Kernel_d/include/CGAL/Kernel_d/function_objects.h index 725167722a7..25d8c84628f 100644 --- a/Kernel_d/include/CGAL/Kernel_d/function_objects.h +++ b/Kernel_d/include/CGAL/Kernel_d/function_objects.h @@ -32,81 +32,10 @@ class Construct public: typedef ToBeConstructed result_type; + template ToBeConstructed - operator()() const - { return ToBeConstructed(); } - - template - ToBeConstructed - operator()( const A1& a1) const - { return ToBeConstructed(a1); } - - template - ToBeConstructed - operator()( const A1& a1, const A2& a2) const - { return ToBeConstructed(a1,a2); } - - template - ToBeConstructed - operator()( const A1& a1, const A2& a2, const A3& a3) const - { return ToBeConstructed(a1,a2,a3); } - - template - ToBeConstructed - operator()( const A1& a1, const A2& a2, const A3& a3, const A4& a4) const - { return ToBeConstructed(a1,a2,a3,a4); } - - template - ToBeConstructed - operator()( const A1& a1, const A2& a2, const A3& a3, const A4& a4, - const A5& a5) const - { return ToBeConstructed(a1,a2,a3,a4,a5); } - - template - ToBeConstructed - operator()( const A& a1, const A& a2, const A& a3, - const A& a4, const A& a5, const A& a6 ) const - { return ToBeConstructed(a1,a2,a3,a4,a5,a6); } - - template - ToBeConstructed - operator()( const A& a1, const A& a2, const A& a3, - const A& a4, const A& a5, const A& a6, - const A& a7 ) const - { return ToBeConstructed(a1,a2,a3,a4,a5,a6,a7); } - - template - ToBeConstructed - operator()( const A& a1, const A& a2, const A& a3, - const A& a4, const A& a5, const A& a6, - const A& a7, const A& a8, const A& a9) const - { return ToBeConstructed(a1,a2,a3,a4,a5,a6,a7,a8,a9); } - - template - ToBeConstructed - operator()( const A& a1, const A& a2, const A& a3, - const A& a4, const A& a5, const A& a6, - const A& a7, const A& a8, const A& a9, - const A& a10) const - { return ToBeConstructed(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10); } - - template - ToBeConstructed - operator()( const A& a1, const A& a2, const A& a3, - const A& a4, const A& a5, const A& a6, - const A& a7, const A& a8, const A& a9, - const A& a10,const A& a11,const A& a12) const - { return ToBeConstructed(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); } - - template - ToBeConstructed - operator()( const A& a1, const A& a2, const A& a3, - const A& a4, const A& a5, const A& a6, - const A& a7, const A& a8, const A& a9, - const A& a10,const A& a11,const A& a12, - const A& a13) const - { return ToBeConstructed(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13); } - + operator()( A&& ... a) const + { return ToBeConstructed(std::forward(a)...); } }; class Call_has_on_positive_side diff --git a/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt b/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt index b9b86d10fc5..d9edd8915d6 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt +++ b/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt @@ -24,7 +24,7 @@ endif() # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg") # To use valgrind, we must disable rounding math ckeck. -# add_definition(-DCGAL_DISABLE_ROUNDING_MATH_CHECK) +# add_definitions(-DCGAL_DISABLE_ROUNDING_MATH_CHECK) if (CGAL_FOUND) diff --git a/Linear_cell_complex/include/CGAL/CMap_linear_cell_complex_storages.h b/Linear_cell_complex/include/CGAL/CMap_linear_cell_complex_storages.h index 8d852eba13a..ef414af8759 100644 --- a/Linear_cell_complex/include/CGAL/CMap_linear_cell_complex_storages.h +++ b/Linear_cell_complex/include/CGAL/CMap_linear_cell_complex_storages.h @@ -150,6 +150,8 @@ namespace CGAL { CGAL_assertion(i <= dimension); return dh->mf[i]==null_dart_handle; } + bool is_perforated(Dart_const_handle /*dh*/) const + { return false; } /// Set simultaneously all the marks of this dart to a given value. void set_dart_marks(Dart_const_handle ADart, diff --git a/Linear_cell_complex/include/CGAL/Cell_attribute_with_point.h b/Linear_cell_complex/include/CGAL/Cell_attribute_with_point.h index 6799463d399..5c6c15505e6 100644 --- a/Linear_cell_complex/include/CGAL/Cell_attribute_with_point.h +++ b/Linear_cell_complex/include/CGAL/Cell_attribute_with_point.h @@ -25,11 +25,11 @@ namespace CGAL { class Point_for_cell { public: - /// Contructor without parameter. + /// Constructor without parameter. Point_for_cell() {} - /// Contructor with a point in parameter. + /// Constructor with a point in parameter. Point_for_cell(const Point& apoint) : mpoint(apoint) {} @@ -87,15 +87,15 @@ namespace CGAL { { return !operator==(other); } protected: - /// Default contructor. + /// Default constructor. Cell_attribute_with_point() {} - /// Contructor with a point in parameter. + /// Constructor with a point in parameter. Cell_attribute_with_point(const Point& apoint) : Base2(apoint) {} - /// Contructor with a point and an attribute in parameters. + /// Constructor with a point and an attribute in parameters. Cell_attribute_with_point(const Point& apoint, const Info& ainfo) : Base1(ainfo), Base2(apoint) @@ -144,11 +144,11 @@ namespace CGAL { { return false; } protected: - /// Default contructor. + /// Default constructor. Cell_attribute_with_point() {} - /// Contructor with a point in parameter. + /// Constructor with a point in parameter. Cell_attribute_with_point(const Point& apoint) : Base2(apoint) {} }; diff --git a/Linear_cell_complex/include/CGAL/GMap_linear_cell_complex_storages.h b/Linear_cell_complex/include/CGAL/GMap_linear_cell_complex_storages.h index d6e851b433f..7a75e7824b9 100644 --- a/Linear_cell_complex/include/CGAL/GMap_linear_cell_complex_storages.h +++ b/Linear_cell_complex/include/CGAL/GMap_linear_cell_complex_storages.h @@ -142,6 +142,8 @@ namespace CGAL { CGAL_assertion(i <= dimension); return dh->mf[i]==dh; } + bool is_perforated(Dart_const_handle /*dh*/) const + { return false; } /// Set simultaneously all the marks of this dart to a given value. void set_dart_marks(Dart_const_handle ADart, diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h index 1ebe43a6a5d..1507e27c253 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h @@ -147,26 +147,48 @@ namespace CGAL { Linear_cell_complex_base(const Self& alcc) : Base(alcc) {} - template < class LCC2 > - Linear_cell_complex_base(const LCC2& alcc) : Base(alcc) + template class CMap2, + class Refs2, class Storage2> + Linear_cell_complex_base + (const Linear_cell_complex_base& alcc) : Base(alcc) {} - template < class LCC2, typename Converters > - Linear_cell_complex_base(const LCC2& alcc, Converters& converters) : + template class CMap2, + class Refs2, + class Storage2, typename Converters> + Linear_cell_complex_base + (const Linear_cell_complex_base& alcc, Converters& converters) : Base(alcc, converters) {} - template < class LCC2, typename Converters, typename DartInfoConverter > - Linear_cell_complex_base(const LCC2& alcc, Converters& converters, - const DartInfoConverter& dartinfoconverter) : + template class CMap2, + class Refs2, class Storage2, typename Converters, + typename DartInfoConverter> + Linear_cell_complex_base + (const Linear_cell_complex_base& alcc, Converters& converters, + const DartInfoConverter& dartinfoconverter) : Base(alcc, converters, dartinfoconverter) {} - template < class LCC2, typename Converters, typename DartInfoConverter, - typename Pointconverter > - Linear_cell_complex_base(const LCC2& alcc, Converters& converters, - const DartInfoConverter& dartinfoconverter, - const Pointconverter& pointconverter) : + template class CMap2, + class Refs2, class Storage2, typename Converters, + typename DartInfoConverter, typename Pointconverter> + Linear_cell_complex_base + (const Linear_cell_complex_base& alcc, Converters& converters, + const DartInfoConverter& dartinfoconverter, + const Pointconverter& pointconverter) : Base(alcc, converters, dartinfoconverter, pointconverter) {} diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex_for_combinatorial_map.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex_for_combinatorial_map.h index 052421e0e15..48519960458 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex_for_combinatorial_map.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex_for_combinatorial_map.h @@ -17,6 +17,7 @@ #include #include #include +#include namespace CGAL { @@ -100,40 +101,119 @@ namespace CGAL { * @param alcc the linear cell complex to copy. * @post *this is valid. */ -#ifdef DOXYGEN_RUNNING Linear_cell_complex_for_combinatorial_map(const Self& alcc) : Base(alcc) {} -#endif - - template < class LCC2 > - Linear_cell_complex_for_combinatorial_map(const LCC2& alcc) : Base(alcc) + + template class CMap2, + class Storage2> + Linear_cell_complex_for_combinatorial_map + (const Linear_cell_complex_for_combinatorial_map& alcc) : Base(alcc) {} - template < class LCC2, typename Converters > - Linear_cell_complex_for_combinatorial_map(const LCC2& alcc, - Converters& converters) : - Base(alcc, converters) + template class CMap2, + class Storage2, typename Converters> + Linear_cell_complex_for_combinatorial_map + (const Linear_cell_complex_for_combinatorial_map& alcc, + const Converters& converters) : Base(alcc, converters) {} - template < class LCC2, typename Converters, typename DartInfoConverter > - Linear_cell_complex_for_combinatorial_map(const LCC2& alcc, - Converters& converters, - const DartInfoConverter& - dartinfoconverter) : + template class CMap2, + class Storage2, typename Converters, typename DartInfoConverter> + Linear_cell_complex_for_combinatorial_map + (const Linear_cell_complex_for_combinatorial_map& alcc, + const Converters& converters, + const DartInfoConverter& dartinfoconverter) : Base(alcc, converters, dartinfoconverter) {} - template < class LCC2, typename Converters, typename DartInfoConverter, - typename PointConverter > - Linear_cell_complex_for_combinatorial_map(const LCC2& alcc, - Converters& converters, - const DartInfoConverter& - dartinfoconverter, - const PointConverter& - pointconverter) : + template class CMap2, + class Storage2, typename Converters, + typename DartInfoConverter, typename PointConverter> + Linear_cell_complex_for_combinatorial_map + (const Linear_cell_complex_for_combinatorial_map& alcc, + const Converters& converters, const DartInfoConverter& dartinfoconverter, + const PointConverter& pointconverter) : Base(alcc, converters, dartinfoconverter, pointconverter) {} + Self & operator= (const Self & alcc) + { + Base::operator=(alcc); + return *this; + } + + /** Import the given hds which should be a model of an halfedge graph. */ + template + void import_from_halfedge_graph(const HEG& heg , + const PointConverter& pointconverter, + boost::unordered_map + ::halfedge_descriptor, + Dart_handle>* origin_to_copy=NULL, + boost::unordered_map + ::halfedge_descriptor>* + copy_to_origin=NULL) + + { + boost::unordered_map + ::halfedge_descriptor, + Dart_handle> local_dartmap; + if (origin_to_copy==NULL) // Used local_dartmap if user does not provides its own unordered_map + { origin_to_copy=&local_dartmap; } + + Base::import_from_halfedge_graph(heg, origin_to_copy, copy_to_origin); + + typedef typename boost::property_map::const_type + Point_property_map; + Point_property_map ppmap = get(CGAL::vertex_point, heg); + + typename boost::unordered_map + ::halfedge_descriptor, + Dart_handle>::iterator dartmap_iter, dartmap_iter_end=origin_to_copy->end(); + for (dartmap_iter=origin_to_copy->begin(); dartmap_iter!=dartmap_iter_end; + ++dartmap_iter) + { + if (this->vertex_attribute(dartmap_iter->second)==NULL) + { + this->set_vertex_attribute(dartmap_iter->second, + this->create_vertex_attribute()); + pointconverter.run(ppmap[source(dartmap_iter->first, heg)], + this->point(dartmap_iter->second)); + } + } + } + + /** Import the given hds which should be a model of an halfedge graph. */ + template + void import_from_halfedge_graph(const HEG& heg, + boost::unordered_map + ::halfedge_descriptor, + Dart_handle>* origin_to_copy=NULL, + boost::unordered_map + ::halfedge_descriptor>* + copy_to_origin=NULL) + { + typedef typename boost::property_traits::type>::value_type HEG_point; + + CGAL::internal::Set_point_if_possible_cmap default_point_converter; + import_from_halfedge_graph(heg, default_point_converter, + origin_to_copy, copy_to_origin); + } + }; } // namespace CGAL diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex_for_generalized_map.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex_for_generalized_map.h index 6b2f8292b67..079a5143c7f 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex_for_generalized_map.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex_for_generalized_map.h @@ -96,40 +96,59 @@ namespace CGAL { * @param alcc the linear cell complex to copy. * @post *this is valid. */ -#ifdef DOXYGEN_RUNNING Linear_cell_complex_for_generalized_map(const Self & alcc) : Base(alcc) {} -#endif - - template < class LCC2 > - Linear_cell_complex_for_generalized_map(const LCC2& alcc) : Base(alcc) + + template class CMap2, + class Storage2> + Linear_cell_complex_for_generalized_map + (const Linear_cell_complex_for_generalized_map& alcc) : Base(alcc) {} - template < class LCC2, typename Converters > - Linear_cell_complex_for_generalized_map(const LCC2& alcc, - Converters& converters) : - Base(alcc, converters) + template class CMap2, + class Storage2, typename Converters> + Linear_cell_complex_for_generalized_map + (const Linear_cell_complex_for_generalized_map& alcc, + const Converters& converters) : Base(alcc, converters) {} - template < class LCC2, typename Converters, typename DartInfoConverter > - Linear_cell_complex_for_generalized_map(const LCC2& alcc, - Converters& converters, - const DartInfoConverter& - dartinfoconverter) : + template class CMap2, + class Storage2, typename Converters, typename DartInfoConverter> + Linear_cell_complex_for_generalized_map + (const Linear_cell_complex_for_generalized_map& alcc, + const Converters& converters, + const DartInfoConverter& dartinfoconverter) : Base(alcc, converters, dartinfoconverter) {} - template < class LCC2, typename Converters, typename DartInfoConverter, - typename PointConverter > - Linear_cell_complex_for_generalized_map(const LCC2& alcc, - Converters& converters, - const DartInfoConverter& - dartinfoconverter, - const PointConverter& - pointconverter) : + template class CMap2, + class Storage2, typename Converters, typename DartInfoConverter, + typename PointConverter> + Linear_cell_complex_for_generalized_map + (const Linear_cell_complex_for_generalized_map& alcc, + const Converters& converters, + const DartInfoConverter& dartinfoconverter, + const PointConverter& pointconverter) : Base(alcc, converters, dartinfoconverter, pointconverter) {} + Self & operator= (const Self & alcc) + { + Base::operator=(alcc); + return *this; + } }; } // namespace CGAL diff --git a/Linear_cell_complex/include/CGAL/draw_linear_cell_complex.h b/Linear_cell_complex/include/CGAL/draw_linear_cell_complex.h index 0a411c66a42..a23567726dd 100644 --- a/Linear_cell_complex/include/CGAL/draw_linear_cell_complex.h +++ b/Linear_cell_complex/include/CGAL/draw_linear_cell_complex.h @@ -16,7 +16,7 @@ #ifdef CGAL_USE_BASIC_VIEWER -#include +#include #include namespace CGAL @@ -168,7 +168,7 @@ public: bool anofaces=false, const DrawingFunctorLCC& drawing_functor=DrawingFunctorLCC()) : // First draw: vertices; edges, faces; multi-color; inverse normal - Base(parent, title, true, true, true, false, true), + Base(parent, title, true, true, true, false, false), lcc(alcc), m_nofaces(anofaces), m_random_face_color(false), diff --git a/Maintenance/infrastructure/cgal.geometryfactory.com/crontab b/Maintenance/infrastructure/cgal.geometryfactory.com/crontab index 6912301cc49..d98d42b770d 100644 --- a/Maintenance/infrastructure/cgal.geometryfactory.com/crontab +++ b/Maintenance/infrastructure/cgal.geometryfactory.com/crontab @@ -25,11 +25,11 @@ LC_CTYPE=en_US.UTF-8 # "master" alone 0 21 * * Sun cd $HOME/CGAL/create_internal_release && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/master.git --do-it || echo ERROR # "integration" -0 21 * * Mon,Tue,Wed,Thu cd $HOME/CGAL/create_internal_release && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/integration.git $HOME/CGAL/branches/empty-dir --do-it --public || echo ERROR +0 21 * * Mon,Tue,Wed,Thu,Fri cd $HOME/CGAL/create_internal_release && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/integration.git $HOME/CGAL/branches/empty-dir --do-it --public || echo ERROR # from branch 5.0 -0 21 * * Fri cd $HOME/CGAL/create_internal_release-5.0-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.0-branch.git --public --do-it || echo ERROR +0 21 * * Sat cd $HOME/CGAL/create_internal_release-5.0-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.0-branch.git --public --do-it || echo ERROR # from branch 4.14 -0 21 * * Sat cd $HOME/CGAL/create_internal_release-4.14-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-4.14-branch.git --public --do-it || echo ERROR +#0 21 * * Sat cd $HOME/CGAL/create_internal_release-4.14-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-4.14-branch.git --public --do-it || echo ERROR ## Older stuff # from branch 4.13 diff --git a/Mesh_2/include/CGAL/Delaunay_mesh_size_criteria_2.h b/Mesh_2/include/CGAL/Delaunay_mesh_size_criteria_2.h index 86b17c1030b..62de1a1e3de 100644 --- a/Mesh_2/include/CGAL/Delaunay_mesh_size_criteria_2.h +++ b/Mesh_2/include/CGAL/Delaunay_mesh_size_criteria_2.h @@ -111,10 +111,8 @@ public: typedef typename Geom_traits::Compute_squared_distance_2 Compute_squared_distance_2; - Geom_traits traits; /** @warning traits with data!! */ - Compute_squared_distance_2 squared_distance = - traits.compute_squared_distance_2_object(); + this->traits.compute_squared_distance_2_object(); const Point_2& pa = fh->vertex(0)->point(); const Point_2& pb = fh->vertex(1)->point(); @@ -165,7 +163,7 @@ public: } } - Compute_area_2 area_2 = traits.compute_area_2_object(); + Compute_area_2 area_2 = this->traits.compute_area_2_object(); double area = 2*CGAL::to_double(area_2(pa, pb, pc)); diff --git a/Mesh_2/include/CGAL/Mesh_2/Clusters.h b/Mesh_2/include/CGAL/Mesh_2/Clusters.h index 6ea340f647e..c1529bd96b8 100644 --- a/Mesh_2/include/CGAL/Mesh_2/Clusters.h +++ b/Mesh_2/include/CGAL/Mesh_2/Clusters.h @@ -89,7 +89,7 @@ public: /** * The following map tells what vertices are in the cluster and if - * the corresponding segment has been splitted once. + * the corresponding segment has been split once. */ typedef std::map Vertices_map; Vertices_map vertices; diff --git a/Mesh_2/include/CGAL/Mesh_2/Refine_edges.h b/Mesh_2/include/CGAL/Mesh_2/Refine_edges.h index 23bc7b24a16..3420990ed3c 100644 --- a/Mesh_2/include/CGAL/Mesh_2/Refine_edges.h +++ b/Mesh_2/include/CGAL/Mesh_2/Refine_edges.h @@ -493,7 +493,7 @@ public: /** This version computes the refinement point without handling clusters. The refinement point of an edge is just the middle point of the segment. - Saves the handles of the edge that will be splitted. + Saves the handles of the edge that will be split. This function is overridden in class Refine_edge_with_clusters. */ Point refinement_point_impl(const Edge& edge) diff --git a/Mesh_2/test/Mesh_2/test_mesh_projection_traits.cpp b/Mesh_2/test/Mesh_2/test_mesh_projection_traits.cpp new file mode 100644 index 00000000000..030471c0295 --- /dev/null +++ b/Mesh_2/test/Mesh_2/test_mesh_projection_traits.cpp @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include + +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K1; +typedef CGAL::Triangulation_2_projection_traits_3 K; +typedef CGAL::Triangulation_vertex_base_2 Vb; +typedef CGAL::Delaunay_mesh_face_base_2 Fb; +typedef CGAL::Triangulation_data_structure_2 Tds; +typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; +typedef CGAL::Delaunay_mesh_size_criteria_2 Criteria; + +typedef CDT::Vertex_handle Vertex_handle; +typedef CDT::Point Point; + +int main() +{ + K gt{ { 0, 0, 1} }; + CDT cdt(gt); + + Vertex_handle va = cdt.insert(Point(-4,0,0)); + Vertex_handle vb = cdt.insert(Point(0,-1,0)); + Vertex_handle vc = cdt.insert(Point(4,0,0)); + Vertex_handle vd = cdt.insert(Point(0,1,0)); + cdt.insert(Point(2, 0.6, 0)); + + cdt.insert_constraint(va, vb); + cdt.insert_constraint(vb, vc); + cdt.insert_constraint(vc, vd); + cdt.insert_constraint(vd, va); + + std::cout << "Number of vertices: " << cdt.number_of_vertices() << std::endl; + + std::cout << "Meshing the triangulation..." << std::endl; + CGAL::refine_Delaunay_mesh_2(cdt, Criteria(0.125, 0.5, gt)); + + std::cout << "Number of vertices: " << cdt.number_of_vertices() << std::endl; +} diff --git a/Mesh_3/doc/Mesh_3/CGAL/Mesh_triangulation_3.h b/Mesh_3/doc/Mesh_3/CGAL/Mesh_triangulation_3.h index 768c00b1acd..cb8834e9040 100644 --- a/Mesh_3/doc/Mesh_3/CGAL/Mesh_triangulation_3.h +++ b/Mesh_3/doc/Mesh_3/CGAL/Mesh_triangulation_3.h @@ -12,8 +12,8 @@ type to be used for the 3D triangulation embedding the mesh. and defaults to `Kernel_traits::%Kernel`. \tparam Concurrency_tag enables sequential versus parallel meshing and optimization algorithms. - Possible values are `Sequential_tag` (the default) and - `Parallel_tag`. + Possible values are `Sequential_tag` (the default), `Parallel_tag`, + and `Parallel_if_available_tag`. \tparam Vertex_base must be a model of `MeshVertexBase_3` or `Default` and defaults to `Mesh_vertex_base_3`. diff --git a/Mesh_3/examples/Mesh_3/CMakeLists.txt b/Mesh_3/examples/Mesh_3/CMakeLists.txt index dcaedc3629a..a6f7848d200 100644 --- a/Mesh_3/examples/Mesh_3/CMakeLists.txt +++ b/Mesh_3/examples/Mesh_3/CMakeLists.txt @@ -48,8 +48,6 @@ if ( CGAL_FOUND ) if (NOT EIGEN3_FOUND) message(STATUS "This project requires the Eigen library, and will not be compiled.") return() - else() - include( ${EIGEN3_USE_FILE} ) endif() find_package(VTK QUIET COMPONENTS vtkImagingGeneral vtkIOImage NO_MODULE) @@ -72,49 +70,99 @@ if ( CGAL_FOUND ) # Compilable examples create_single_source_cgal_program( "mesh_hybrid_mesh_domain.cpp" ) + CGAL_target_use_Eigen(mesh_hybrid_mesh_domain) + create_single_source_cgal_program( "mesh_implicit_sphere.cpp" ) + CGAL_target_use_Eigen(mesh_implicit_sphere) + create_single_source_cgal_program( "mesh_implicit_sphere_variable_size.cpp" ) + CGAL_target_use_Eigen(mesh_implicit_sphere_variable_size) + create_single_source_cgal_program( "mesh_two_implicit_spheres_with_balls.cpp" ) + CGAL_target_use_Eigen(mesh_two_implicit_spheres_with_balls) + create_single_source_cgal_program( "mesh_implicit_domains_2.cpp" "implicit_functions.cpp" ) + CGAL_target_use_Eigen(mesh_implicit_domains_2) + create_single_source_cgal_program( "mesh_cubes_intersection.cpp" ) + CGAL_target_use_Eigen(mesh_cubes_intersection) + create_single_source_cgal_program( "mesh_cubes_intersection_with_features.cpp" ) + CGAL_target_use_Eigen(mesh_cubes_intersection_with_features) + create_single_source_cgal_program( "mesh_implicit_domains.cpp" "implicit_functions.cpp" ) + CGAL_target_use_Eigen(mesh_implicit_domains) + create_single_source_cgal_program( "mesh_polyhedral_domain.cpp" ) + CGAL_target_use_Eigen(mesh_polyhedral_domain) + create_single_source_cgal_program( "mesh_polyhedral_domain_sm.cpp" ) + CGAL_target_use_Eigen(mesh_polyhedral_domain_sm) + create_single_source_cgal_program( "mesh_polyhedral_domain_with_surface_inside.cpp" ) + CGAL_target_use_Eigen(mesh_polyhedral_domain_with_surface_inside) + create_single_source_cgal_program( "remesh_polyhedral_surface.cpp" ) + CGAL_target_use_Eigen(remesh_polyhedral_surface) + create_single_source_cgal_program( "remesh_polyhedral_surface_sm.cpp" ) + CGAL_target_use_Eigen(remesh_polyhedral_surface_sm) + create_single_source_cgal_program( "mesh_polyhedral_domain_with_features.cpp" ) + CGAL_target_use_Eigen(mesh_polyhedral_domain_with_features) + create_single_source_cgal_program( "mesh_polyhedral_domain_with_features_sm.cpp" ) + CGAL_target_use_Eigen(mesh_polyhedral_domain_with_features_sm) + create_single_source_cgal_program( "mesh_polyhedral_domain_with_lipschitz_sizing.cpp" ) + CGAL_target_use_Eigen(mesh_polyhedral_domain_with_lipschitz_sizing) + create_single_source_cgal_program( "mesh_polyhedral_complex.cpp" ) + CGAL_target_use_Eigen(mesh_polyhedral_complex) + create_single_source_cgal_program( "mesh_polyhedral_complex_sm.cpp" ) + CGAL_target_use_Eigen(mesh_polyhedral_complex_sm) + if( WITH_CGAL_ImageIO ) if( VTK_FOUND AND ("${VTK_VERSION_MAJOR}" GREATER "5" OR VTK_VERSION VERSION_GREATER 5) ) add_executable ( mesh_3D_gray_vtk_image mesh_3D_gray_vtk_image.cpp ) + CGAL_target_use_Eigen(mesh_3D_gray_vtk_image) target_link_libraries( mesh_3D_gray_vtk_image ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} ${VTK_LIBRARIES}) cgal_add_test( mesh_3D_gray_vtk_image ) add_to_cached_list( CGAL_EXECUTABLE_TARGETS mesh_3D_gray_vtk_image ) endif() create_single_source_cgal_program( "mesh_3D_gray_image.cpp" ) + CGAL_target_use_Eigen(mesh_3D_gray_image) + create_single_source_cgal_program( "mesh_3D_gray_image_multiple_values.cpp" ) + CGAL_target_use_Eigen(mesh_3D_gray_image_multiple_values) + create_single_source_cgal_program( "mesh_3D_image_with_features.cpp" ) + CGAL_target_use_Eigen(mesh_3D_image_with_features) + if( CGAL_ImageIO_USE_ZLIB ) create_single_source_cgal_program( "mesh_optimization_example.cpp" ) + CGAL_target_use_Eigen(mesh_optimization_example) create_single_source_cgal_program( "mesh_optimization_lloyd_example.cpp" ) + CGAL_target_use_Eigen(mesh_optimization_lloyd_example) create_single_source_cgal_program( "mesh_3D_image.cpp" ) + CGAL_target_use_Eigen(mesh_3D_image) + create_single_source_cgal_program( "mesh_3D_image_with_custom_initialization.cpp" ) + CGAL_target_use_Eigen(mesh_3D_image_with_custom_initialization) create_single_source_cgal_program( "mesh_3D_image_variable_size.cpp" ) + CGAL_target_use_Eigen(mesh_3D_image_variable_size) else() message( STATUS "NOTICE: The examples mesh_3D_image.cpp, mesh_3D_image_variable_size.cpp, mesh_optimization_example.cpp and mesh_optimization_lloyd_example.cpp need CGAL_ImageIO to be configured with ZLIB support, and will not be compiled." ) endif() else() message( STATUS "NOTICE: Some examples need the CGAL_ImageIO library, and will not be compiled." ) endif() + # create_single_source_cgal_program( "mesh_polyhedral_implicit_function.cpp" ) # create_single_source_cgal_program( "mesh_polyhedral_surface_tolerance_region.cpp" ) # create_single_source_cgal_program( "mesh_polyhedral_edge_tolerance_region.cpp" ) diff --git a/Mesh_3/include/CGAL/Compact_mesh_cell_base_3.h b/Mesh_3/include/CGAL/Compact_mesh_cell_base_3.h index 077de31abcf..ae091b60be3 100644 --- a/Mesh_3/include/CGAL/Compact_mesh_cell_base_3.h +++ b/Mesh_3/include/CGAL/Compact_mesh_cell_base_3.h @@ -34,9 +34,64 @@ #ifdef CGAL_LINKED_WITH_TBB -# include +# include #endif +namespace internal_tbb +{ +//classic pointer{ +//normal +template +void set_weighted_circumcenter(T* &t, T* value) +{ + t = value; +} + +//overload for nullptr +template +void set_weighted_circumcenter(T* &t, std::nullptr_t) +{ + t = nullptr; +} +template +bool compare_weighted_circumcenter(T* t) +{ + return t == nullptr; +} + +template +void delete_circumcenter(T* &t ) +{ + delete t; +} +//} atomic { +//normal +template +void set_weighted_circumcenter(std::atomic& t, T* value) +{ + t.load() = value; +} + +//nullptr +template +void set_weighted_circumcenter(std::atomic& t, std::nullptr_t) +{ + t = nullptr; +} + +template +bool compare_weighted_circumcenter(std::atomic& t) +{ + return t.load() == nullptr; +} +template +void delete_circumcenter(std::atomic& t) +{ + delete t.load(); +} +//} +} //end internal_tbb + namespace CGAL { // Class Compact_mesh_cell_base_3_base @@ -52,8 +107,9 @@ class Compact_mesh_cell_base_3_base protected: Compact_mesh_cell_base_3_base() : bits_(0) - , weighted_circumcenter_(nullptr) - {} + { + internal_tbb::set_weighted_circumcenter(weighted_circumcenter_, nullptr); + } public: #if defined(CGAL_MESH_3_USE_LAZY_SORTED_REFINEMENT_QUEUE) \ @@ -152,7 +208,8 @@ public: { CGAL_precondition(facet>=0 && facet<4); char current_bits = bits_; - while (bits_.compare_and_swap(current_bits | char(1 << facet), current_bits) != current_bits) + + while (!bits_.compare_exchange_weak(current_bits, current_bits | char(1 << facet))) { current_bits = bits_; } @@ -165,7 +222,7 @@ public: char current_bits = bits_; char mask = char(15 & ~(1 << facet)); char wanted_value = current_bits & mask; - while (bits_.compare_and_swap(wanted_value, current_bits) != current_bits) + while (!bits_.compare_exchange_weak(current_bits, wanted_value)) { current_bits = bits_; } @@ -182,18 +239,19 @@ public: /// this function "deletes" cc void try_to_set_circumcenter(Point_3 *cc) const { - if (weighted_circumcenter_.compare_and_swap(cc, nullptr) != nullptr) + Point_3* base_test = nullptr; + if (!weighted_circumcenter_.compare_exchange_strong(base_test, cc)) delete cc; } private: - typedef tbb::atomic Erase_counter_type; + typedef std::atomic Erase_counter_type; Erase_counter_type m_erase_counter; /// Stores visited facets (4 first bits) - tbb::atomic bits_; + std::atomic bits_; protected: - mutable tbb::atomic weighted_circumcenter_; + mutable std::atomic weighted_circumcenter_; }; #endif // CGAL_LINKED_WITH_TBB @@ -244,9 +302,9 @@ public: public: void invalidate_weighted_circumcenter_cache() const { - if (weighted_circumcenter_) { - delete weighted_circumcenter_; - weighted_circumcenter_ = nullptr; + if (!internal_tbb::compare_weighted_circumcenter(weighted_circumcenter_)) { + internal_tbb::delete_circumcenter(weighted_circumcenter_); + internal_tbb::set_weighted_circumcenter(weighted_circumcenter_, nullptr); } } @@ -328,8 +386,9 @@ public: ~Compact_mesh_cell_base_3() { - if(weighted_circumcenter_ != nullptr){ - delete weighted_circumcenter_; + if(!internal_tbb::compare_weighted_circumcenter(weighted_circumcenter_)){ + internal_tbb::delete_circumcenter(weighted_circumcenter_); + internal_tbb::set_weighted_circumcenter(weighted_circumcenter_, nullptr); } } diff --git a/Mesh_3/include/CGAL/IO/File_binary_mesh_3.h b/Mesh_3/include/CGAL/IO/File_binary_mesh_3.h index 276d5cacd12..8b31530f513 100644 --- a/Mesh_3/include/CGAL/IO/File_binary_mesh_3.h +++ b/Mesh_3/include/CGAL/IO/File_binary_mesh_3.h @@ -60,7 +60,10 @@ bool load_binary_file(std::istream& is, C3T3& c3t3) return false; } std::getline(is, s); - if(s != "") { + if(!s.empty()) { + if(s[s.size()-1] == '\r') { // deal with Windows EOL + s.resize(s.size() - 1); + } if(s != std::string(" ") + CGAL::Get_io_signature()()) { std::cerr << "load_binary_file:" << "\n expected format: " << CGAL::Get_io_signature()() diff --git a/Mesh_3/include/CGAL/Labeled_mesh_domain_3.h b/Mesh_3/include/CGAL/Labeled_mesh_domain_3.h index e00ea7ade01..a35de5e6c50 100644 --- a/Mesh_3/include/CGAL/Labeled_mesh_domain_3.h +++ b/Mesh_3/include/CGAL/Labeled_mesh_domain_3.h @@ -824,7 +824,7 @@ protected: false> Wrapper; return Wrapper(image, transform_fct, - transform_fct(value_outside)); + value_outside) ; } template diff --git a/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h b/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h index a27c9556cb0..aff32baba7b 100644 --- a/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h +++ b/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h @@ -47,7 +47,7 @@ #ifdef CGAL_LINKED_WITH_TBB # include -# include +# include #endif #include @@ -595,7 +595,7 @@ public: protected: Lock_data_structure *m_lock_ds; - typedef tbb::mutex Mutex_type; + typedef std::mutex Mutex_type; mutable Mutex_type m_mut_outdated_cells; mutable Mutex_type m_mut_moving_vertices; mutable Mutex_type m_mut_vertex_to_proj; diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h b/Mesh_3/include/CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h index b2cd9715ee5..398a5bd524d 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h +++ b/Mesh_3/include/CGAL/Mesh_3/Mesh_complex_3_in_triangulation_3_base.h @@ -41,7 +41,7 @@ #ifdef CGAL_LINKED_WITH_TBB - #include + #include #include namespace CGAL { @@ -174,7 +174,7 @@ public: , manifold_info_initialized_(false) //TODO: parallel! { // We don't put it in the initialization list because - // tbb::atomic has no contructors + // std::atomic has no contructors number_of_facets_ = 0; number_of_cells_ = 0; } @@ -186,8 +186,9 @@ public: , edge_facet_counter_(rhs.edge_facet_counter_) , manifold_info_initialized_(rhs.manifold_info_initialized_) { - number_of_facets_ = rhs.number_of_facets_; - number_of_cells_ = rhs.number_of_cells_; + Init_number_of_elements init; + init(number_of_facets_, rhs.number_of_facets_); + init(number_of_cells_, rhs.number_of_cells_); } /// Destructor @@ -505,9 +506,10 @@ public: /// Swaps this & rhs void swap(Self& rhs) { - std::swap(rhs.number_of_facets_, number_of_facets_); + Swap_elements swapper; + swapper(rhs.number_of_facets_, number_of_facets_); tr_.swap(rhs.tr_); - std::swap(rhs.number_of_cells_, number_of_cells_); + swapper(rhs.number_of_cells_, number_of_cells_); } /// Returns bbox @@ -850,12 +852,55 @@ private: { typedef size_type type; }; + + template + struct Init_number_of_elements + { + template + void operator()(T& a, const T& b) + { + a = b; + } + }; + + template + struct Swap_elements + { + template + void operator()(T& a, T& b) + { + std::swap(a, b); + } + }; #ifdef CGAL_LINKED_WITH_TBB // Parallel: atomic template struct Number_of_elements { - typedef tbb::atomic type; + typedef std::atomic type; + }; + + template + struct Init_number_of_elements + { + template + void operator()(T& a, const T& b) + { + a = b.load(); + } + }; + + template + struct Swap_elements + { + template + void operator()(T& a, T& b) + { + T tmp; + tmp.exchange(a); + a.exchange(b); + b.exchange(tmp); + } }; #endif // CGAL_LINKED_WITH_TBB diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h b/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h index cd4310bf5fb..a43b7bb1d24 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h +++ b/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h @@ -47,7 +47,8 @@ #include #ifdef CGAL_LINKED_WITH_TBB -# include +# include +# include # include # include #endif @@ -122,7 +123,7 @@ protected: typedef typename Tr::Lock_data_structure Lock_data_structure; typedef tbb::concurrent_vector > Moves_vector; - typedef tbb::atomic Nb_frozen_points_type ; + typedef std::atomic Nb_frozen_points_type ; Mesh_global_optimizer_base(const Bbox_3 &bbox, int num_grid_cells_per_axis) : big_moves_size_(0) @@ -136,7 +137,7 @@ protected: { if (++big_moves_current_size_ <= big_moves_size_ ) { - tbb::mutex::scoped_lock lock(m_big_moves_mutex); + std::lock_guard lock(m_big_moves_mutex); typename std::multiset::const_iterator it = big_moves_.insert(new_sq_move); // New smallest move of all big moves? @@ -149,7 +150,7 @@ protected: if( new_sq_move > big_moves_smallest_ ) { - tbb::mutex::scoped_lock lock(m_big_moves_mutex); + std::lock_guard lock(m_big_moves_mutex); // Test it again since it may have been modified by another // thread in the meantime if( new_sq_move > big_moves_smallest_ ) @@ -185,11 +186,11 @@ protected: public: protected: - tbb::atomic big_moves_current_size_; - tbb::atomic big_moves_smallest_; + std::atomic big_moves_current_size_; + std::atomic big_moves_smallest_; std::size_t big_moves_size_; std::multiset big_moves_; - tbb::mutex m_big_moves_mutex; + std::mutex m_big_moves_mutex; /// Lock data structure Lock_data_structure m_lock_ds; diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesh_surface_cell_base_3.h b/Mesh_3/include/CGAL/Mesh_3/Mesh_surface_cell_base_3.h index e95510e101c..40b492c1467 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Mesh_surface_cell_base_3.h +++ b/Mesh_3/include/CGAL/Mesh_3/Mesh_surface_cell_base_3.h @@ -27,7 +27,7 @@ #include #ifdef CGAL_LINKED_WITH_TBB -# include +# include #endif #ifdef _MSC_VER @@ -123,7 +123,7 @@ public: protected: /// Stores visited facets (4 first bits) - tbb::atomic bits_; + std::atomic bits_; }; #endif // CGAL_LINKED_WITH_TBB diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesher_3.h b/Mesh_3/include/CGAL/Mesh_3/Mesher_3.h index e58a21ff397..b9da328ca9d 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Mesher_3.h +++ b/Mesh_3/include/CGAL/Mesh_3/Mesher_3.h @@ -50,7 +50,7 @@ #endif #ifdef CGAL_LINKED_WITH_TBB -# include +# include #endif #include @@ -659,7 +659,7 @@ initialize() # endif Random_points_on_sphere_3 random_point(radius); const int NUM_PSEUDO_INFINITE_VERTICES = static_cast( - float(tbb::task_scheduler_init::default_num_threads()) + float(std::thread::hardware_concurrency()) * Concurrent_mesher_config::get().num_pseudo_infinite_vertices_per_core); for (int i = 0 ; i < NUM_PSEUDO_INFINITE_VERTICES ; ++i, ++random_point) r_c3t3_.add_far_point(r_c3t3_.triangulation().geom_traits().construct_weighted_point_3_object() @@ -817,7 +817,13 @@ status() const if(boost::is_convertible::value) { const WorksharingDataStructureType* ws_ds = this->get_worksharing_data_structure(); - return Mesher_status(approximate_number_of_vertices(Concurrency_tag()), + return Mesher_status( +# if CGAL_CONCURRENT_COMPACT_CONTAINER_APPROXIMATE_SIZE + approximate_number_of_vertices(Concurrency_tag()), +#else + // not thread-safe, but that is not important + approximate_number_of_vertices(CGAL::Sequential_tag()), +#endif 0, ws_ds->approximate_number_of_enqueued_element()); } diff --git a/Mesh_3/include/CGAL/Mesh_3/Worksharing_data_structures.h b/Mesh_3/include/CGAL/Mesh_3/Worksharing_data_structures.h index 8abc76f5a03..32b5816c83c 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Worksharing_data_structures.h +++ b/Mesh_3/include/CGAL/Mesh_3/Worksharing_data_structures.h @@ -28,7 +28,7 @@ #include #include -#include +#include #include @@ -65,8 +65,8 @@ public: m_num_cells = num_grid_cells_per_axis*num_grid_cells_per_axis*num_grid_cells_per_axis; - m_occupation_grid = new tbb::atomic[m_num_cells]; - m_num_batches_grid = new tbb::atomic[m_num_cells]; + m_occupation_grid = new std::atomic[m_num_cells]; + m_num_batches_grid = new std::atomic[m_num_cells]; // Initialize grid for (int i = 0 ; i < m_num_cells ; ++i) { @@ -106,15 +106,15 @@ public: void add_batch(int cell_index, int to_add) { - m_num_batches_grid[cell_index].fetch_and_add(to_add); + m_num_batches_grid[cell_index].fetch_add(to_add); } void add_occupation(int cell_index, int to_add, int) { - m_occupation_grid[cell_index].fetch_and_add(to_add); + m_occupation_grid[cell_index].fetch_add(to_add); /*int new_occupation = - (m_occupation_grid[cell_index].fetch_and_add(to_add)) + (m_occupation_grid[cell_index].fetch_add(to_add)) + to_add; //m_num_batches_grid[cell_index] = num_items_in_work_queue; @@ -221,7 +221,7 @@ public: // Rotate - static tbb::atomic last_cell_index; + static std::atomic last_cell_index; //std::cerr << "last=" << last_cell_index << std::endl; int i = (last_cell_index + 1) % m_num_cells; for ( ; i != last_cell_index ; i = (i + 1) % m_num_cells) @@ -246,11 +246,11 @@ protected: int m_num_grid_cells_per_axis; int m_num_cells; - tbb::atomic * m_occupation_grid; - tbb::atomic * m_num_batches_grid; + std::atomic * m_occupation_grid; + std::atomic * m_num_batches_grid; - tbb::atomic m_laziest_cell_index; - tbb::atomic m_laziest_cell_occupation; + std::atomic m_laziest_cell_index; + std::atomic m_laziest_cell_occupation; }; @@ -504,7 +504,7 @@ public: { m_tls_work_buffers = new TLS_WorkBuffer[m_num_cells]; m_work_batches = new tbb::concurrent_queue[m_num_cells]; - m_num_batches = new tbb::atomic[m_num_cells]; + m_num_batches = new std::atomic[m_num_cells]; for (int i = 0 ; i < m_num_cells ; ++i) m_num_batches[i] = 0; @@ -673,7 +673,7 @@ protected: Work_statistics m_stats; TLS_WorkBuffer *m_tls_work_buffers; tbb::concurrent_queue *m_work_batches; - tbb::atomic *m_num_batches; + std::atomic *m_num_batches; }; @@ -822,7 +822,7 @@ protected: } const size_t NUM_WORK_ITEMS_PER_BATCH; - tbb::atomic m_cache_number_of_tasks; + std::atomic m_cache_number_of_tasks; TLS_WorkBuffer m_tls_work_buffers; }; diff --git a/Mesh_3/include/CGAL/Mesh_3/vertex_perturbation.h b/Mesh_3/include/CGAL/Mesh_3/vertex_perturbation.h index 07ceaabc6d0..1b5e004548a 100644 --- a/Mesh_3/include/CGAL/Mesh_3/vertex_perturbation.h +++ b/Mesh_3/include/CGAL/Mesh_3/vertex_perturbation.h @@ -30,7 +30,7 @@ #include #ifdef CGAL_LINKED_WITH_TBB #include - #include + #include #endif #endif @@ -193,7 +193,7 @@ public: #endif { #ifdef CGAL_MESH_3_PERTURBER_VERBOSE - // Initialized here in case it's some tbb::atomic + // Initialized here in case it's some std::atomic total_counter_ = 0; total_time_ = 0; #endif @@ -354,8 +354,8 @@ private: mutable int counter_; #ifdef CGAL_LINKED_WITH_TBB mutable tbb::enumerable_thread_specific timer_; - tbb::atomic total_counter_; - tbb::atomic total_time_; + std::atomic total_counter_; + std::atomic total_time_; #else mutable CGAL::Timer timer_; int total_counter_; diff --git a/Mesh_3/include/CGAL/Mesh_cell_base_3.h b/Mesh_3/include/CGAL/Mesh_cell_base_3.h index 75e85ea869d..379bd4c6c54 100644 --- a/Mesh_3/include/CGAL/Mesh_cell_base_3.h +++ b/Mesh_3/include/CGAL/Mesh_cell_base_3.h @@ -33,7 +33,7 @@ #include #ifdef CGAL_LINKED_WITH_TBB -# include +# include #endif namespace CGAL { @@ -87,7 +87,7 @@ public: } protected: - typedef tbb::atomic Erase_counter_type; + typedef std::atomic Erase_counter_type; Erase_counter_type m_erase_counter; }; #endif // CGAL_LINKED_WITH_TBB diff --git a/Mesh_3/include/CGAL/Polyhedral_complex_mesh_domain_3.h b/Mesh_3/include/CGAL/Polyhedral_complex_mesh_domain_3.h index ae6413ca009..9421e883a45 100644 --- a/Mesh_3/include/CGAL/Polyhedral_complex_mesh_domain_3.h +++ b/Mesh_3/include/CGAL/Polyhedral_complex_mesh_domain_3.h @@ -750,8 +750,7 @@ detect_features(FT angle_in_degree, for(Polyhedron_type& p : poly) { initialize_ts(p); - using Mesh_3::internal::Get_face_index_pmap; - Get_face_index_pmap get_face_index_pmap(p); + #ifdef CGAL_MESH_3_VERBOSE std::size_t poly_id = &p-&poly[0]; std::cerr << "Polyhedron #" << poly_id << " :\n"; @@ -768,9 +767,9 @@ detect_features(FT angle_in_degree, , eif , pid_map , PMP::parameters::first_index(nb_of_patch_plus_one) - .face_index_map(get_face_index_pmap(p)) - .vertex_incident_patches_map(vip_map) - .vertex_feature_degree_map(vertex_feature_degree_map)); + .face_index_map(get_initialized_face_index_map(p)) + .vertex_incident_patches_map(vip_map) + .vertex_feature_degree_map(vertex_feature_degree_map)); Mesh_3::internal::Is_featured_edge is_featured_edge(p); diff --git a/Mesh_3/include/CGAL/Polyhedral_mesh_domain_3.h b/Mesh_3/include/CGAL/Polyhedral_mesh_domain_3.h index f9a7a0d5cf4..42abf9d1256 100644 --- a/Mesh_3/include/CGAL/Polyhedral_mesh_domain_3.h +++ b/Mesh_3/include/CGAL/Polyhedral_mesh_domain_3.h @@ -105,47 +105,6 @@ struct IGT_generator } // end namespace details } // end namespace Mesh_3 -namespace Mesh_3 { -namespace internal { - -template ::value> -class Get_face_index_pmap { -public: - typedef typename boost::property_map::const_type Pmap; - Get_face_index_pmap(const Polyhedron_type&) {} - Pmap operator()(const Polyhedron_type& polyhedron) { - return get(CGAL::face_index, polyhedron); - } -}; - -template -class Get_face_index_pmap { - typedef typename boost::graph_traits::face_descriptor - face_descriptor; - typedef std::map Map; -public: - Get_face_index_pmap(const Polyhedron_type& polyhedron) { - int id = 0; - for(face_descriptor f : faces(polyhedron)) - { - face_ids[f] = id++; - } - } - typedef boost::associative_property_map Pmap; - - Pmap operator()(const Polyhedron_type&) { - return Pmap(face_ids); - } -private: - Map face_ids; -}; - -} // end namespace internal -} // end namespace Mesh_3 - /** * @class Polyhedral_mesh_domain_3 * diff --git a/Mesh_3/include/CGAL/Polyhedral_mesh_domain_with_features_3.h b/Mesh_3/include/CGAL/Polyhedral_mesh_domain_with_features_3.h index d5f9979bc9b..ea92e1341ea 100644 --- a/Mesh_3/include/CGAL/Polyhedral_mesh_domain_with_features_3.h +++ b/Mesh_3/include/CGAL/Polyhedral_mesh_domain_with_features_3.h @@ -348,9 +348,6 @@ detect_features(FT angle_in_degree, std::vector& poly) typedef typename boost::property_map >::type VIPMap; typedef typename boost::property_map::type EIFMap; - using Mesh_3::internal::Get_face_index_pmap; - Get_face_index_pmap get_face_index_pmap(p); - PIDMap pid_map = get(face_patch_id_t(), p); VIPMap vip_map = get(vertex_incident_patches_t(), p); EIFMap eif_map = get(CGAL::edge_is_feature, p); @@ -360,8 +357,8 @@ detect_features(FT angle_in_degree, std::vector& poly) , eif_map , pid_map , PMP::parameters::first_index(nb_of_patch_plus_one) - .face_index_map(get_face_index_pmap(p)) - .vertex_incident_patches_map(vip_map)); + .face_index_map(get_initialized_face_index_map(p)) + .vertex_incident_patches_map(vip_map)); Mesh_3::internal::Is_featured_edge is_featured_edge(p); diff --git a/Mesh_3/test/Mesh_3/CMakeLists.txt b/Mesh_3/test/Mesh_3/CMakeLists.txt index 03f021a7172..bd6221a9aa6 100644 --- a/Mesh_3/test/Mesh_3/CMakeLists.txt +++ b/Mesh_3/test/Mesh_3/CMakeLists.txt @@ -22,8 +22,6 @@ if ( CGAL_FOUND ) if (NOT EIGEN3_FOUND) message(STATUS "This project requires the Eigen library, and will not be compiled.") return() - else() - include( ${EIGEN3_USE_FILE} ) endif() create_single_source_cgal_program( "test_boost_has_xxx.cpp" ) @@ -61,18 +59,55 @@ if ( CGAL_FOUND ) create_single_source_cgal_program( "test_mesh_polyhedral_domain_with_features_deprecated.cpp" ) create_single_source_cgal_program( "test_meshing_with_one_step.cpp" ) + foreach(target + test_boost_has_xxx + test_c3t3 + test_mesh_capsule_var_distance_bound + test_implicit_multi_domain_to_labeling_function_wrapper + test_c3t3_io + test_c3t3_with_features + test_criteria + test_domain_with_polyline_features + test_labeled_mesh_domain_3 + test_mesh_criteria_creation + test_c3t3_into_facegraph + test_without_detect_features + test_meshing_3D_image + test_meshing_3D_image_deprecated + test_meshing_3D_gray_image + test_meshing_3D_gray_image_deprecated + test_meshing_implicit_function + test_meshing_implicit_function_deprecated + test_meshing_polyhedral_complex + test_meshing_polyhedron + test_meshing_polylines_only + test_meshing_polyhedron_with_features + test_meshing_verbose + test_meshing_unit_tetrahedron + test_meshing_with_default_edge_size + test_meshing_determinism + test_c3t3_extract_subdomains_boundaries + test_mesh_3_issue_1554 + test_mesh_polyhedral_domain_with_features_deprecated + test_meshing_with_one_step.cpp) + if(TARGET ${target}) + CGAL_target_use_Eigen(${target}) + endif() + endforeach() + foreach(target test_meshing_verbose test_meshing_polyhedron_with_features test_meshing_utilities.h - test_mesh_implicit_domains test_meshing_implicit_function test_meshing_3D_image test_meshing_3D_gray_image test_meshing_unit_tetrahedron - test_backward_compatibility test_meshing_polyhedron test_meshing_polyhedral_complex + test_mesh_capsule_var_distance_bound + test_mesh_3_issue_1554 + test_mesh_polyhedral_domain_with_features_deprecated ) if(TBB_FOUND AND TARGET ${target}) CGAL_target_use_TBB(${target}) diff --git a/Mesh_3/test/Mesh_3/test_mesh_3_issue_1554.cpp b/Mesh_3/test/Mesh_3/test_mesh_3_issue_1554.cpp index 24c7bb6f445..c64f5455ffb 100644 --- a/Mesh_3/test/Mesh_3/test_mesh_3_issue_1554.cpp +++ b/Mesh_3/test/Mesh_3/test_mesh_3_issue_1554.cpp @@ -18,11 +18,7 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Mesh_polyhedron_3::type Polyhedron; typedef CGAL::Polyhedral_mesh_domain_with_features_3 Mesh_domain; -#ifdef CGAL_CONCURRENT_MESH_3 -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; // Triangulation typedef CGAL::Mesh_triangulation_3 Mesh_domain; -#ifdef CGAL_CONCURRENT_MESH_3 -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; // Triangulation typedef CGAL::Mesh_triangulation_3::type Tr; diff --git a/Mesh_3/test/Mesh_3/test_mesh_polyhedral_domain_with_features_deprecated.cpp b/Mesh_3/test/Mesh_3/test_mesh_polyhedral_domain_with_features_deprecated.cpp index 26e7093cb91..5fd13080c01 100644 --- a/Mesh_3/test/Mesh_3/test_mesh_polyhedral_domain_with_features_deprecated.cpp +++ b/Mesh_3/test/Mesh_3/test_mesh_polyhedral_domain_with_features_deprecated.cpp @@ -14,12 +14,7 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Mesh_polyhedron_3::type Polyhedron; typedef CGAL::Polyhedral_mesh_domain_with_features_3 Mesh_domain; - -#ifdef CGAL_CONCURRENT_MESH_3 -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; // Triangulation typedef CGAL::Mesh_triangulation_3::type Tr; diff --git a/Mesh_3/test/Mesh_3/test_meshing_3D_gray_image.cpp b/Mesh_3/test/Mesh_3/test_meshing_3D_gray_image.cpp index 0055e50b125..4b232d42d20 100644 --- a/Mesh_3/test/Mesh_3/test_meshing_3D_gray_image.cpp +++ b/Mesh_3/test/Mesh_3/test_meshing_3D_gray_image.cpp @@ -13,7 +13,6 @@ //****************************************************************************** // File Description : //*************************************************************************** - #include "test_meshing_utilities.h" #include #include diff --git a/Mesh_3/test/Mesh_3/test_meshing_determinism.cpp b/Mesh_3/test/Mesh_3/test_meshing_determinism.cpp index e71c56853bd..e184d689e99 100644 --- a/Mesh_3/test/Mesh_3/test_meshing_determinism.cpp +++ b/Mesh_3/test/Mesh_3/test_meshing_determinism.cpp @@ -13,9 +13,9 @@ #include #include #include - #ifdef CGAL_LINKED_WITH_TBB -# include +#define TBB_PREVIEW_GLOBAL_CONTROL 1 +# include #endif // To avoid verbose function and named parameters call @@ -119,7 +119,7 @@ int main(int, char*[]) { test(); #ifdef CGAL_LINKED_WITH_TBB - tbb::task_scheduler_init init(1); + tbb::global_control c(tbb::global_control::max_allowed_parallelism, 1); test(); #endif } diff --git a/Nef_3/include/CGAL/Nef_3/SNC_const_decorator.h b/Nef_3/include/CGAL/Nef_3/SNC_const_decorator.h index d747eee7f9e..9695ab1580d 100644 --- a/Nef_3/include/CGAL/Nef_3/SNC_const_decorator.h +++ b/Nef_3/include/CGAL/Nef_3/SNC_const_decorator.h @@ -229,7 +229,7 @@ public: if(!Infi_box::is_standard(hf->plane())) ++i; } - CGAL_warning("altered code"); + // CGAL_warning("altered code"); // CGAL_assertion(i>=6); return (i == 6); } diff --git a/Nef_3/include/CGAL/Nef_3/SNC_point_locator.h b/Nef_3/include/CGAL/Nef_3/SNC_point_locator.h index 3aafa4e5cbf..74586d759d5 100644 --- a/Nef_3/include/CGAL/Nef_3/SNC_point_locator.h +++ b/Nef_3/include/CGAL/Nef_3/SNC_point_locator.h @@ -884,7 +884,7 @@ public: else CGAL_error_msg( "wrong handle type"); } - CGAL_warning("altered code in SNC_point_locator"); + //CGAL_warning("altered code in SNC_point_locator"); /* Halffacet_iterator fc; CGAL_forall_facets(fc, *this->sncp()) { @@ -907,7 +907,7 @@ public: if( CGAL::assign( v, result)) { _CGAL_NEF_TRACEN("vertex hit, obtaining volume..." << v->point()); - CGAL_warning("altered code in SNC_point_locator"); + //CGAL_warning("altered code in SNC_point_locator"); SM_point_locator L(&*v); // Object_handle so = L.locate(s.source()-s.target(), true); Object_handle so = L.locate(s.source()-s.target()); diff --git a/Nef_3/include/CGAL/Nef_3/SNC_simplify.h b/Nef_3/include/CGAL/Nef_3/SNC_simplify.h index e561af6b2d4..835a6052ecd 100644 --- a/Nef_3/include/CGAL/Nef_3/SNC_simplify.h +++ b/Nef_3/include/CGAL/Nef_3/SNC_simplify.h @@ -192,7 +192,7 @@ class SNC_simplify_base : public SNC_decorator { } bool simplify_redundant_box_vertex(Vertex_handle v, bool snc_computed) { - CGAL_warning("altered code"); + //CGAL_warning("altered code"); return false; if(snc_computed) return false; if(!Infi_box::is_redundant_box_vertex(*v)) return false; diff --git a/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h b/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h index 5e0e24254fe..7c3c8e01878 100644 --- a/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h +++ b/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h @@ -109,6 +109,12 @@ template, private EC { + // `default_construct()` is the same as `T{}`. But, this is a + // workaround to a MSVC-2015 bug (fixed in MSVC-2017): its parser + // seemed confused by `T{}` somewhere below. + template + static T default_construct() { return T(); } + // Lazy_rep_0 does not inherit from EC or take a parameter AC. It has different constructors. static_assert(sizeof...(L)>0, "Use Lazy_rep_0 instead"); template friend class Lazy_kernel_base; @@ -138,7 +144,7 @@ class Lazy_rep_XXX : // Currently we construct the vectors, then move them into the tuple. It would be nicer to construct them in their final destination, because eventually we will also have arrays instead of vectors. template Lazy_rep_XXX(Lazy_internal::typelist, const AC& ac, const EC& ec, LLL const&lll, LL const&...ll) : - Lazy_rep(ac(CGAL::approx(ll)...)), EC(ec), l(Lazy_internal::do_extract(T{},lll)...) + Lazy_rep(ac(CGAL::approx(ll)...)), EC(ec), l(Lazy_internal::do_extract(default_construct(),lll)...) { //this->set_depth(std::max({ -1, (int)CGAL::depth(ll)...}) + 1); this->set_depth(1); // FIXME: now that we have ranges, we could actually compute the depth if we cared... diff --git a/NewKernel_d/include/CGAL/NewKernel_d/Wrapper/Point_d.h b/NewKernel_d/include/CGAL/NewKernel_d/Wrapper/Point_d.h index 404eca88bf3..5c0dce2db1f 100644 --- a/NewKernel_d/include/CGAL/NewKernel_d/Wrapper/Point_d.h +++ b/NewKernel_d/include/CGAL/NewKernel_d/Wrapper/Point_d.h @@ -51,12 +51,12 @@ public: typedef typename Get_type::type Rep; //typedef typename CGAL::decay::type>::type Cartesian_const_iterator; - const Rep& rep() const + const Rep& rep() const noexcept { return *this; } - Rep& rep() + Rep& rep() noexcept { return *this; } @@ -101,6 +101,14 @@ public: Point_d(Origin&& v) : Rep(CPBase()(std::move(v))) {} + friend void swap(Self& a, Self& b) +#ifdef __cpp_lib_is_swappable + noexcept(std::is_nothrow_swappable_v) +#endif + { + using std::swap; + swap(a.rep(), b.rep()); + } decltype(auto) cartesian(int i)const{ return CCBase()(rep(),i); diff --git a/NewKernel_d/test/NewKernel_d/CMakeLists.txt b/NewKernel_d/test/NewKernel_d/CMakeLists.txt index 9cbe76d8204..8f7ee2b990c 100644 --- a/NewKernel_d/test/NewKernel_d/CMakeLists.txt +++ b/NewKernel_d/test/NewKernel_d/CMakeLists.txt @@ -18,10 +18,8 @@ if ( CGAL_FOUND ) find_package(Eigen3) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - create_single_source_cgal_program( "Epick_d.cpp" ) - + CGAL_target_use_Eigen(Epick_d) else() message(STATUS "NOTICE: This program requires the Eigen3 library, and will not be compiled.") diff --git a/Number_types/include/CGAL/FPU.h b/Number_types/include/CGAL/FPU.h index 1ed1d728d34..1d290381603 100644 --- a/Number_types/include/CGAL/FPU.h +++ b/Number_types/include/CGAL/FPU.h @@ -408,7 +408,7 @@ typedef unsigned int FPU_CW_t; #elif defined __mips__ #define CGAL_IA_SETFPCW(CW) asm volatile ("ctc1 %0,$31" : :"r" (CW)) -#define CGAL_IA_GETFPCW(CW) asm volatile ("cfc1 %0,$31" : "=r" (CW)) +#define CGAL_IA_GETFPCW(CW) asm volatile ("cfc1 %0,$31" : "=r" (CW)); CW &= 3 typedef unsigned int FPU_CW_t; #define CGAL_FE_TONEAREST (0x0) #define CGAL_FE_TOWARDZERO (0x1) diff --git a/Number_types/include/CGAL/GMP/Gmpq_type.h b/Number_types/include/CGAL/GMP/Gmpq_type.h index 8fa397492d5..e339590b8d1 100644 --- a/Number_types/include/CGAL/GMP/Gmpq_type.h +++ b/Number_types/include/CGAL/GMP/Gmpq_type.h @@ -222,20 +222,23 @@ public: Gmpq& operator*=(const Gmpq &q); Gmpq& operator/=(const Gmpq &q); - bool operator==(const Gmpq &q) const { return mpq_equal(this->mpq(), q.mpq()) != 0;} - bool operator< (const Gmpq &q) const { return mpq_cmp(this->mpq(), q.mpq()) < 0; } + bool operator==(const Gmpq &q) const noexcept { return mpq_equal(this->mpq(), q.mpq()) != 0;} + bool operator< (const Gmpq &q) const noexcept { return mpq_cmp(this->mpq(), q.mpq()) < 0; } - double to_double() const; - Sign sign() const; + double to_double() const noexcept; + Sign sign() const noexcept; - const mpq_t & mpq() const { return Ptr()->mpQ; } - mpq_t & mpq() { return ptr()->mpQ; } + const mpq_t & mpq() const noexcept { return Ptr()->mpQ; } + mpq_t & mpq() noexcept { return ptr()->mpQ; } + friend void swap(Gmpq &x, Gmpq &y) noexcept { x.Base::swap(y); } +#ifdef CGAL_PROFILE ~Gmpq() { CGAL_HISTOGRAM_PROFILER("[Gmpq sizes in log2 scale]", (unsigned) ( ::log(double(size())) / ::log(double(2)) ) ); } +#endif // Interoperability with int Gmpq& operator+=(int z){return (*this)+= Gmpq(z);} @@ -446,12 +449,12 @@ Gmpq& Gmpq::operator/=(const Gmpz &z){ inline double -Gmpq::to_double() const +Gmpq::to_double() const noexcept { return mpq_get_d(mpq()); } inline Sign -Gmpq::sign() const +Gmpq::sign() const noexcept { return static_cast(mpq_sgn(mpq())); } inline diff --git a/Number_types/include/CGAL/Lazy_exact_nt.h b/Number_types/include/CGAL/Lazy_exact_nt.h index 471096f37ba..41e2c597981 100644 --- a/Number_types/include/CGAL/Lazy_exact_nt.h +++ b/Number_types/include/CGAL/Lazy_exact_nt.h @@ -383,6 +383,9 @@ public : typename boost::disable_if,int>::type=0) : Base(new Lazy_lazy_exact_Cst(x)){} + friend void swap(Lazy_exact_nt& a, Lazy_exact_nt& b) noexcept + { swap(static_cast(a), static_cast(b)); } + Self operator+ () const { return *this; } diff --git a/Number_types/include/CGAL/Sqrt_extension/Eigen_NumTraits.h b/Number_types/include/CGAL/Sqrt_extension/Eigen_NumTraits.h index b51e888839a..dc934692689 100644 --- a/Number_types/include/CGAL/Sqrt_extension/Eigen_NumTraits.h +++ b/Number_types/include/CGAL/Sqrt_extension/Eigen_NumTraits.h @@ -19,13 +19,6 @@ namespace Eigen { template struct NumTraits > { - typedef CGAL::Sqrt_extension Real; - typedef Real NonInteger; - typedef Real Nested; - typedef Real Literal; - - static inline Real epsilon() { return NumTraits::epsilon(); } - enum { IsInteger = 0, IsSigned = 1, @@ -35,6 +28,19 @@ namespace Eigen { AddCost = 2*NumTraits::AddCost+NumTraits::ReadCost, MulCost = 5*NumTraits::MulCost+2*NumTraits::AddCost }; + + typedef CGAL::Sqrt_extension Real; + typedef Real NonInteger; + typedef Real Nested; + typedef Real Literal; + + static inline Real epsilon() { return NumTraits::epsilon(); } + static inline int digits10() { return NumTraits::digits10(); } + static inline Real dummy_precision() { return NumTraits::dummy_precision(); } + static inline Real highest() { return NumTraits::highest(); } + static inline Real lowest() { return NumTraits::lowest(); } + static inline Real infinity() { return NumTraits::infinity(); } + static inline Real quiet_NaN() { return NumTraits::quiet_NaN(); } }; } diff --git a/Number_types/test/Number_types/CMakeLists.txt b/Number_types/test/Number_types/CMakeLists.txt index 6a74945aea9..0bb60b63e1d 100644 --- a/Number_types/test/Number_types/CMakeLists.txt +++ b/Number_types/test/Number_types/CMakeLists.txt @@ -26,7 +26,6 @@ if ( CGAL_FOUND ) create_single_source_cgal_program( "Counted_number.cpp" ) create_single_source_cgal_program( "double.cpp" ) create_single_source_cgal_program( "doubletst.cpp" ) - create_single_source_cgal_program( "eigen.cpp" ) create_single_source_cgal_program( "float.cpp" ) create_single_source_cgal_program( "floattst.cpp" ) create_single_source_cgal_program( "Gmpfr.cpp" ) @@ -80,7 +79,13 @@ if ( CGAL_FOUND ) create_single_source_cgal_program( "Gmpfr_bug.cpp" ) create_single_source_cgal_program( "Quotient_new.cpp" ) create_single_source_cgal_program( "test_nt_Coercion_traits.cpp" ) - + + create_single_source_cgal_program( "eigen.cpp" ) + find_package(Eigen3 3.2.0) #(requires 3.2.0 or greater) + if (EIGEN3_FOUND) + cgal_target_use_Eigen(eigen) + endif() + else( CGAL_FOUND ) message(STATUS diff --git a/Number_types/test/Number_types/eigen.cpp b/Number_types/test/Number_types/eigen.cpp index 91f620b0b3b..8e0dd9bf194 100644 --- a/Number_types/test/Number_types/eigen.cpp +++ b/Number_types/test/Number_types/eigen.cpp @@ -34,7 +34,7 @@ void check_(){ v << 1, 2, 3; NT t=v.dot(v); v+=d*m*(t*v); - int si=v.size(); + std::ptrdiff_t si=v.size(); CGAL_USE(si); } template @@ -59,7 +59,7 @@ int main(){ //check > >(); check >(); #ifdef CGAL_USE_GMP - check(); +// check(); check(); check(); check >(); @@ -69,7 +69,7 @@ int main(){ check(); #endif #ifdef CGAL_USE_CORE - check(); +// check(); check(); check(); check(); diff --git a/Optimal_transportation_reconstruction_2/demo/Optimal_transportation_reconstruction_2/scene.h b/Optimal_transportation_reconstruction_2/demo/Optimal_transportation_reconstruction_2/scene.h index 5c2444aefc9..5693f0fbb30 100644 --- a/Optimal_transportation_reconstruction_2/demo/Optimal_transportation_reconstruction_2/scene.h +++ b/Optimal_transportation_reconstruction_2/demo/Optimal_transportation_reconstruction_2/scene.h @@ -18,9 +18,11 @@ #define cimg_display 0 // To avoid X11 or Windows-GDI dependency #include #endif -#include #include // std::pair #include + +#include +#include #include #include #include @@ -953,7 +955,7 @@ public: void append_star(const int nb_branches, const int density) { std::cerr << "append star..."; - const double deg_in_rad = 3.1415926535897932384626 / 180.0; + const double deg_in_rad = CGAL_PI / 180.0; const double incr = 180.0 / nb_branches; double angle = 0.0; const Point center(0.5, 0.5); @@ -970,7 +972,7 @@ public: void append_predefined_increasingly_sharp_angles(const int density, const double min_angle) { - const double deg_in_rad = 3.1415926535897932384626 / 180.0; + const double deg_in_rad = CGAL_PI / 180.0; double prev_angle = 0.0; double curr_angle = min_angle; double incr = min_angle; diff --git a/Periodic_3_mesh_3/examples/Periodic_3_mesh_3/CMakeLists.txt b/Periodic_3_mesh_3/examples/Periodic_3_mesh_3/CMakeLists.txt index b18274683b9..8b1fb98c95f 100644 --- a/Periodic_3_mesh_3/examples/Periodic_3_mesh_3/CMakeLists.txt +++ b/Periodic_3_mesh_3/examples/Periodic_3_mesh_3/CMakeLists.txt @@ -26,8 +26,6 @@ find_package(Eigen3 3.1.0 REQUIRED) #(3.1.0 or greater) if (NOT EIGEN3_FOUND) message(STATUS "This project requires the Eigen library, and will not be compiled.") return() -else() - include( ${EIGEN3_USE_FILE} ) endif() # Boost and its components @@ -46,3 +44,13 @@ create_single_source_cgal_program( "mesh_implicit_multi_domain.cpp" ) create_single_source_cgal_program( "mesh_implicit_shape_with_subdomains.cpp" ) create_single_source_cgal_program( "mesh_implicit_shape_with_optimizers.cpp" ) create_single_source_cgal_program( "mesh_implicit_shape_with_features.cpp" ) + + +foreach(target + mesh_implicit_shape + mesh_implicit_multi_domain + mesh_implicit_shape_with_subdomains + mesh_implicit_shape_with_optimizers + mesh_implicit_shape_with_features) + CGAL_target_use_Eigen(${target}) +endforeach() diff --git a/Periodic_3_mesh_3/test/Periodic_3_mesh_3/CMakeLists.txt b/Periodic_3_mesh_3/test/Periodic_3_mesh_3/CMakeLists.txt index dddf3a8f260..d1929fd2bbb 100644 --- a/Periodic_3_mesh_3/test/Periodic_3_mesh_3/CMakeLists.txt +++ b/Periodic_3_mesh_3/test/Periodic_3_mesh_3/CMakeLists.txt @@ -19,14 +19,15 @@ if ( CGAL_FOUND ) if (NOT EIGEN3_FOUND) message(STATUS "This project requires the Eigen library, and will not be compiled.") return() - else() - include( ${EIGEN3_USE_FILE} ) endif() create_single_source_cgal_program( "test_implicit_shapes_bunch.cpp" ) + CGAL_target_use_Eigen(test_implicit_shapes_bunch) create_single_source_cgal_program( "test_implicit_shapes_with_features.cpp" ) + CGAL_target_use_Eigen(test_implicit_shapes_with_features) create_single_source_cgal_program( "test_triply_periodic_minimal_surfaces.cpp" ) - + CGAL_target_use_Eigen(test_triply_periodic_minimal_surfaces) + else() message(STATUS "This program requires the CGAL library, and will not be compiled.") diff --git a/Periodic_3_triangulation_3/demo/Periodic_3_triangulation_3/Scene.h b/Periodic_3_triangulation_3/demo/Periodic_3_triangulation_3/Scene.h index 296d1bc5427..18f4d42663c 100644 --- a/Periodic_3_triangulation_3/demo/Periodic_3_triangulation_3/Scene.h +++ b/Periodic_3_triangulation_3/demo/Periodic_3_triangulation_3/Scene.h @@ -106,9 +106,8 @@ public Q_SLOTS: void insert_mp() { insert_point(moving_point); - QString str; - ui->viewer->displayMessage(str.sprintf("Added point (%f, %f, %f)", - moving_point.x(),moving_point.y(),moving_point.z())); + ui->viewer->displayMessage(QString("Added point (%1, %2, %3)").arg( + moving_point.x()).arg(moving_point.y()).arg(moving_point.z())); changed(); } @@ -117,9 +116,8 @@ public Q_SLOTS: Point pt = *rp+Vector(0.5,0.5,0.5); rp++; insert_point(Point(pt.x(),pt.y(),(in_plane? 0.0:pt.z()))); - QString str; - ui->viewer->displayMessage(str.sprintf("Added point (%f, %f, %f)", - pt.x(),pt.y(),(in_plane? 0.0:pt.z()))); + ui->viewer->displayMessage(QString("Added point (%1, %2, %3)").arg( + pt.x()).arg(pt.y()).arg((in_plane? 0.0:pt.z()))); changed(); } void insert_point(Point p) { diff --git a/Periodic_3_triangulation_3/demo/Periodic_Lloyd_3/MainWindow.cpp b/Periodic_3_triangulation_3/demo/Periodic_Lloyd_3/MainWindow.cpp index 6fd19cdf7c9..9d82538f863 100644 --- a/Periodic_3_triangulation_3/demo/Periodic_Lloyd_3/MainWindow.cpp +++ b/Periodic_3_triangulation_3/demo/Periodic_Lloyd_3/MainWindow.cpp @@ -16,7 +16,7 @@ MainWindow::MainWindow(QWidget* parent): CGAL::Qt::DemosMainWindow(parent) scene.eight_copies=false; scene.two_dimensional=false; - qtimer = new QTimer(this); + qtimer= new QTimer(this); connect(qtimer, SIGNAL(timeout()), this, SLOT(lloydStep())); } diff --git a/Periodic_3_triangulation_3/include/CGAL/Periodic_3_triangulation_3.h b/Periodic_3_triangulation_3/include/CGAL/Periodic_3_triangulation_3.h index a30f19dacb5..c96cb05bc11 100644 --- a/Periodic_3_triangulation_3/include/CGAL/Periodic_3_triangulation_3.h +++ b/Periodic_3_triangulation_3/include/CGAL/Periodic_3_triangulation_3.h @@ -21,11 +21,6 @@ #include -#include -#include -#include -#include -#include #include #include #include @@ -48,6 +43,13 @@ #include #endif // no CGAL_NO_STRUCTURAL_FILTERING +#include +#include +#include +#include +#include +#include + #include #include #include @@ -648,7 +650,8 @@ public: // but point() -like functions have return type Point template // can be Point or Point_3 - Point_3 construct_point(const P& p) const { + typename boost::result_of::type + construct_point(const P& p) const { return geom_traits().construct_point_3_object()(p); } diff --git a/Periodic_3_triangulation_3/include/CGAL/internal/Periodic_3_Delaunay_triangulation_remove_traits_3.h b/Periodic_3_triangulation_3/include/CGAL/internal/Periodic_3_Delaunay_triangulation_remove_traits_3.h index eb29597983a..1e856c3ade5 100644 --- a/Periodic_3_triangulation_3/include/CGAL/internal/Periodic_3_Delaunay_triangulation_remove_traits_3.h +++ b/Periodic_3_triangulation_3/include/CGAL/internal/Periodic_3_Delaunay_triangulation_remove_traits_3.h @@ -40,7 +40,7 @@ public: using Base::operator(); - const Point_3& operator()(const Point_3& p) { return p; } + const Point_3& operator()(const Point_3& p) const { return p; } }; template < class Traits_, class Functor_ > diff --git a/Periodic_3_triangulation_3/include/CGAL/internal/Periodic_3_regular_triangulation_remove_traits_3.h b/Periodic_3_triangulation_3/include/CGAL/internal/Periodic_3_regular_triangulation_remove_traits_3.h index dbfa8b8687c..a3584d7aad1 100644 --- a/Periodic_3_triangulation_3/include/CGAL/internal/Periodic_3_regular_triangulation_remove_traits_3.h +++ b/Periodic_3_triangulation_3/include/CGAL/internal/Periodic_3_regular_triangulation_remove_traits_3.h @@ -49,7 +49,7 @@ public: using Base::operator(); // for K::Weighted_point_3 to Point_3 - Point_3 operator()(const Weighted_point_3& wp) { + Point_3 operator()(const Weighted_point_3& wp) const { return std::make_pair(operator()(wp.first), wp.second /* offset */); } }; diff --git a/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_tds_cell.h b/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_tds_cell.h index f6bd867855d..fb949a078fc 100644 --- a/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_tds_cell.h +++ b/Periodic_3_triangulation_3/test/Periodic_3_triangulation_3/include/CGAL/_test_cls_periodic_3_tds_cell.h @@ -88,11 +88,6 @@ _test_cell_tds_3(const Tds &) assert(c2->index(v1)==0); assert(c2->index(v2)==1); assert(c2->index(v3)==2); - // c2->set_vertices(); - // assert(c2->vertex(0)==NULL); - // assert(c2->vertex(1)==NULL); - // assert(c2->vertex(2)==NULL); - // assert(c2->vertex(3)==NULL); c2->set_vertices(v0, v1, v2, v3); assert(c2->index(v0)==0); assert(c2->index(v1)==1); @@ -107,11 +102,6 @@ _test_cell_tds_3(const Tds &) assert(c2->index(n1)==0); assert(c2->index(n2)==1); assert(c2->index(n3)==2); - // c2->set_neighbors(); - // assert(c2->neighbor(0)==NULL); - // assert(c2->neighbor(1)==NULL); - // assert(c2->neighbor(2)==NULL); - // assert(c2->neighbor(3)==NULL); c2->set_neighbors(n0, n1, n2, n3); assert(c2->index(n0)==0); assert(c2->index(n1)==1); diff --git a/Point_set_3/examples/Point_set_3/CMakeLists.txt b/Point_set_3/examples/Point_set_3/CMakeLists.txt index 45172ef603d..21055796731 100644 --- a/Point_set_3/examples/Point_set_3/CMakeLists.txt +++ b/Point_set_3/examples/Point_set_3/CMakeLists.txt @@ -44,14 +44,9 @@ set(needed_cxx_features cxx_rvalue_references cxx_variadic_templates) create_single_source_cgal_program( "point_set_read_ply.cpp" CXX_FEATURES ${needed_cxx_features} ) find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) -if (NOT EIGEN3_FOUND) - find_package(LAPACK) - if(LAPACK_FOUND) - include( ${LAPACK_USE_FILE} ) - endif(LAPACK_FOUND) -else() - include( ${EIGEN3_USE_FILE} ) +if (EIGEN3_FOUND) create_single_source_cgal_program( "point_set_algo.cpp" ) + CGAL_target_use_Eigen(point_set_algo) endif() create_single_source_cgal_program("draw_point_set_3.cpp" ) diff --git a/Point_set_3/include/CGAL/Point_set_3.h b/Point_set_3/include/CGAL/Point_set_3.h index 8fe32fbdbfa..16cd9ddf3c8 100644 --- a/Point_set_3/include/CGAL/Point_set_3.h +++ b/Point_set_3/include/CGAL/Point_set_3.h @@ -231,6 +231,18 @@ public: return *this; } + /// \cond SKIP_IN_MANUAL + // copy constructor (same as assignment) + Point_set_3 (const Point_set_3& ps) + { + m_base = ps.m_base; + m_indices = this->property_map ("index").first; + m_points = this->property_map ("point").first; + m_normals = this->property_map ("normal").first; + m_nb_removed = ps.m_nb_removed; + } + /// \endcond + /// @} /// \cond SKIP_IN_MANUAL diff --git a/Point_set_processing_3/doc/Point_set_processing_3/NamedParameters.txt b/Point_set_processing_3/doc/Point_set_processing_3/NamedParameters.txt index e2c64e40efb..7f7c42ad9eb 100644 --- a/Point_set_processing_3/doc/Point_set_processing_3/NamedParameters.txt +++ b/Point_set_processing_3/doc/Point_set_processing_3/NamedParameters.txt @@ -191,6 +191,84 @@ Constrained points are left unaltered and are used as seeds in `mst_orient_norma Default value: a property map with only the highest point constrained. \cgalNPEnd +\cgalNPBegin{number_of_samples} \anchor PSP_number_of_samples +is the number of input points used for computation.\n +\b Type: \c unsigned \c int \n +Default value: `200` +\cgalNPEnd + +\cgalNPBegin{accuracy} \anchor PSP_accuracy +is the wanted output accuracy, expressed in scene units.\n +\b Type: floating scalar value\n +Default value: `5.00` +\cgalNPEnd + +\cgalNPBegin{maximum_normal_deviation} \anchor PSP_maximum_normal_deviation +is the maximum angle between the normals of a pair of points, expressed in degrees.\n +\b Type: floating scalar value\n +Default value: `90.00` +\cgalNPEnd + +\cgalNPBegin{overlap} \anchor PSP_overlap +is the expected overlap ratio (between 0 and 1) between two points sets to register.\n +\b Type: floating scalar value\n +Default value: `0.20` +\cgalNPEnd + +\cgalNPBegin{maximum_running_time} \anchor PSP_maximum_running_time +is the maximum time (in seconds) allowed to the function before ending and returning the best solution found so far.\n +\b Type: floating scalar value\n +Default value: `1000` +\cgalNPEnd + +\cgalNPBegin{transformation} \anchor PSP_transformation +is the transformation to be applied to the point set before the function starts to further process.\n +\b Type: Aff_transformation_3\n +No default value. +\cgalNPEnd + +\cgalNPBegin{point_set_filters} \anchor PSP_point_set_filters +is the chain of filters to be applied to the point set.\n +\b Type: a model of `Range` with `CGAL::pointmatcher::ICP_config` as value type.\n +No default value. +\cgalNPEnd + +\cgalNPBegin{matcher} \anchor PSP_matcher +is the method used for matching (linking) the point set to the reference point set.\n +\b Type: a model of `CGAL::pointmatcher::ICP_config`\n +No default value. +\cgalNPEnd + +\cgalNPBegin{outlier_filters} \anchor PSP_outlier_filters +is the chain of filters to be applied to the matched (linked) point set after each processing iteration of the registration to reject the outliers for the next iteration.\n +\b Type: a model of `Range` with `CGAL::pointmatcher::ICP_config` as value type.\n +No default value. +\cgalNPEnd + +\cgalNPBegin{error_minimizer} \anchor PSP_error_minimizer +is the error minimizer that computes a transformation matrix such as to minimize the error between the point sets in registration process.\n +\b Type: a model of `CGAL::pointmatcher::ICP_config`\n +No default value. +\cgalNPEnd + +\cgalNPBegin{transformation_checkers} \anchor PSP_transformation_checkers +is the chain of transformation checkers that can stop the iteration depending on the conditions it defines.\n +\b Type: a model of `Range` with `CGAL::pointmatcher::ICP_config` as value type.\n +No default value. +\cgalNPEnd + +\cgalNPBegin{inspector} \anchor PSP_inspector +is the inspector that allows to log data at different steps of the running algorithm to allow analysis.\n +\b Type: a model of `CGAL::pointmatcher::ICP_config`\n +No default value. +\cgalNPEnd + +\cgalNPBegin{logger} \anchor PSP_logger +is for logging information regarding the process.\n +\b Type: a model of `CGAL::pointmatcher::ICP_config`\n +No default value. +\cgalNPEnd + \cgalNPTableEnd */ diff --git a/Point_set_processing_3/doc/Point_set_processing_3/PackageDescription.txt b/Point_set_processing_3/doc/Point_set_processing_3/PackageDescription.txt index dc3bf7ab968..51df668b49d 100644 --- a/Point_set_processing_3/doc/Point_set_processing_3/PackageDescription.txt +++ b/Point_set_processing_3/doc/Point_set_processing_3/PackageDescription.txt @@ -29,8 +29,8 @@ format. \cgalPkgDescriptionBegin{Point Set Processing,PkgPointSetProcessing3} \cgalPkgPicture{point_set_processing_detail.png} \cgalPkgSummaryBegin -\cgalPkgAuthors{Pierre Alliez, Simon Giraudot, Clément Jamin, Florent Lafarge, Quentin Mérigot, Jocelyn Meyron, Laurent Saboret, Nader Salman, Shihao Wu} -\cgalPkgDesc{This \cgal component implements methods to analyze and process unorganized point sets. The input is an unorganized point set, possibly with normal attributes (unoriented or oriented). The point set can be analyzed to measure its average spacing, and processed through functions devoted to the simplification, outlier removal, smoothing, normal estimation, normal orientation and feature edges estimation.} +\cgalPkgAuthors{Pierre Alliez, Simon Giraudot, Clément Jamin, Florent Lafarge, Quentin Mérigot, Jocelyn Meyron, Laurent Saboret, Nader Salman, Shihao Wu, Necip Fazil Yildiran} +\cgalPkgDesc{This \cgal component implements methods to analyze and process unorganized point sets. The input is an unorganized point set, possibly with normal attributes (unoriented or oriented). The point set can be analyzed to measure its average spacing, and processed through functions devoted to the simplification, outlier removal, smoothing, normal estimation, normal orientation, feature edges estimation and registration.} \cgalPkgManuals{Chapter_Point_Set_Processing,PkgPointSetProcessing3Ref} \cgalPkgSummaryEnd \cgalPkgShortInfoBegin @@ -51,10 +51,14 @@ format. - `CGAL::estimate_global_range_scale()` - `CGAL::estimate_local_k_neighbor_scales()` - `CGAL::estimate_local_range_scales()` +- `CGAL::OpenGR::compute_registration_transformation()` +- `CGAL::OpenGR::register_point_sets()` +- `CGAL::pointmatcher::compute_registration_transformation()` +- `CGAL::pointmatcher::register_point_sets()` - `CGAL::remove_outliers()` - `CGAL::grid_simplify_point_set()` - `CGAL::random_simplify_point_set()` -- `CGAL::hierarchy_simplify_point_set()` +- `CGAL::hierarchy_simplify_point_set()` - `CGAL::wlop_simplify_and_regularize_point_set()` - `CGAL::jet_smooth_point_set()` - `CGAL::bilateral_smooth_point_set()` diff --git a/Point_set_processing_3/doc/Point_set_processing_3/Point_set_processing_3.txt b/Point_set_processing_3/doc/Point_set_processing_3/Point_set_processing_3.txt index 275ecf450fb..63a5ac80806 100644 --- a/Point_set_processing_3/doc/Point_set_processing_3/Point_set_processing_3.txt +++ b/Point_set_processing_3/doc/Point_set_processing_3/Point_set_processing_3.txt @@ -7,7 +7,7 @@ \cgalAutoToc -\authors Pierre Alliez, Simon Giraudot, Clément Jamin, Florent Lafarge, Quentin Mérigot, Jocelyn Meyron, Laurent Saboret, Nader Salman, Shihao Wu +\authors Pierre Alliez, Simon Giraudot, Clément Jamin, Florent Lafarge, Quentin Mérigot, Jocelyn Meyron, Laurent Saboret, Nader Salman, Shihao Wu, Necip Fazil Yildiran \section Point_set_processing_3Introduction Introduction @@ -23,8 +23,8 @@ In the context of surface reconstruction we can position the elements of this component along the common surface reconstruction pipeline (\cgalFigureRef{Point_set_processing_3figpipeline}) which involves the following steps: --# Scanning and scan alignment to produce a set of -points or points with normals (alignment is not covered in \cgal); +-# Scanning and scan registration to produce a set of +points or points with normals; -# Outlier removal; -# Simplification to reduce the number of input points; -# Smoothing to reduce noise in the input data; @@ -272,7 +272,7 @@ number of points (or the minimal local range) such that the subset of points has the appearance of a curve in 2D or a surface in 3D \cgalCite{cgal:gcsa-nasr-13}. -\cgal provides 2 functions that automatically estimate the scale of a +\cgal provides two functions that automatically estimate the scale of a 2D point set sampling a curve or a 3D point set sampling a surface: - `estimate_global_k_neighbor_scale()` @@ -285,7 +285,7 @@ K neighbor scale or a range scale. In some specific cases, the scale of a point set might not be homogeneous (for example if the point set contains variable -noise). \cgal also provides 2 functions that automatically estimate +noise). \cgal also provides two functions that automatically estimate the scales of a point set at a set of user-defined query points: - `estimate_local_k_neighbor_scales()` @@ -314,6 +314,304 @@ points in the domain. \cgalExample{Point_set_processing_3/scale_estimation_2d_example.cpp} +\section Point_set_processing_3Registration Registration + +\cgal provides two functions as wrapper for the \ref thirdpartyOpenGR library +\cgalCite{cgal:m-ogr-17}, and two functions as wrapper for the \ref thirdpartylibpointmatcher +library : + +- `CGAL::OpenGR::compute_registration_transformation()` computes the +registration of one point set w.r.t. another in the form of a +`CGAL::Aff_transformation_3` object, using the Super4PCS algorithm +\cgalCite{cgal:mam-sffgp-14}; + +- `CGAL::OpenGR::register_point_sets()` computes the registration of +one point set w.r.t. another and directly aligns it to it; + +- `CGAL::pointmatcher::compute_registration_transformation()` computes the +registration of one point set w.r.t. another in the form of a +`CGAL::Aff_transformation_3` object, using the ICP (Iterative Closest Point) +algorithm; + +- `CGAL::pointmatcher::register_point_sets()` computes the registration of +one point set w.r.t. another and directly aligns it to it. + +\subsection Point_set_processing_3Examples_registration_OpenGR OpenGR Example + +The following example reads two point sets and aligns them using the +\ref thirdpartyOpenGR library, using the Super4PCS algorithm: +\cgalExample{Point_set_processing_3/registration_with_OpenGR.cpp} + +\cgalFigureRef{Point_set_processing_3tableRegistrationRegistration_visualization_table} demonstrates +visualization of a scan data before and after different registration methods are applied, +including the %OpenGR registration method. To obtain the results for %OpenGR registration +in the visualization table, above-mentioned example was used. + +\subsubsection Point_set_processing_3Examples_registration_OpenGR_parameter_number_of_samples Parameter: number_of_samples + +Input clouds are sub-sampled prior exploration, to ensure fast computations. +Super4PCS has a linear complexity w.r.t. the number of input samples, allowing +to use larger values than 4PCS. +Simple geometry with large overlap can be matched with only 200 samples. +However, with Super4PCS, smaller details can be used during the process by using +up to thousands of points. There is no theoretical limit to this parameter; +however, using too large values leads to very a large congruent set, +which requires more time and memory to be explored. + +Using a large number of samples is recommended when: + +- geometrical details are required to perform the matching, for instance to disambiguate +between several similar configurations, + +- the clouds have a very low overlap: using a too sparse sampling can result in +an empty overlapping area, causing the algorithm to fail, + +- the clouds are very noisy, and require a dense sampling. + +Note that Super4PCS is a global registration algorithm, which finds a good approximate +of the rigid transformation aligning two clouds. Increasing the number of samples +in order to get a fine registration is not optimal: it is usually faster to use +fewer samples, and refine the transformation using a local algorithm, like the ICP, +or its variant SparseICP. + +\subsubsection Point_set_processing_3Examples_registration_OpenGR_parameter_accuracy Parameter: accuracy + +This parameter controls the registration accuracy: setting a small value means that +the two clouds need to be very close to be considered as well aligned. It is expressed in scene units. + +A simple way to understand its impact is to consider the computation of the Largest Common Pointset (LCP), +the metric used to verify how aligned the clouds are. For each transformation matrix produced +by Super4PCS, OpenGR computes the LCP measure by considering a shell around the reference cloud, and +count the percentage of points of the target cloud lying in the shell. The thickness of the shell is +defined by the parameter delta (accuracy). + +Using too wide values will slow down the algorithm by increasing the size of the congruent set, +while using to small values prevents to find a solution. This parameter impacts other steps of +the algorithm, see the paper \cgalCite{cgal:mam-sffgp-14} for more details. + +\subsubsection Point_set_processing_3Examples_registration_OpenGR_parameter_normal Parameter: maximum normal deviation + +This parameter sets an angle threshold above which two pairs of points are discarded as candidates +for matching. It is expressed in degrees. + +The default value is 90° (no filtering). Decreasing this value allows to decrease the computation +time by being more selective on candidates. Using too small values might result in ignoring +candidates that should indeed have been matched and may thus result in a quality decrease. + +\subsubsection Point_set_processing_3Examples_registration_OpenGR_parameter_overlap Parameter: overlap + +Ratio of expected overlap between the two point sets: it is ranging between 0 (no overlap) to 1 (100% overlap). + +The overlap parameter controls the size of the basis used for registration, as shown below: + +\cgalFigureBegin{Point_set_processing_3figOpenGR_parameter_overlap,super4PCS_overlap.png} +The effect of varying overlap parameter on the size of the basis used for registration. The overlap is smaller for left (a) than right (b). +\cgalFigureEnd + +Usually, the larger the overlap, the faster the algorithm. +When the overlap is unknown, a simple way to set this parameter is to start from +100% overlap, and decrease the value until obtaining a good result. +Using too small values will slow down the algorithm, and +reduce the accuracy of the result. + +\subsubsection Point_set_processing_3Examples_registration_OpenGR_parameter_maximum_running_time Parameter: maximum_running_time + +Maximum number of seconds after which the algorithm stops. Super4PCS explores the +transformation space to align the two input clouds. Since the exploration is performed +randomly, it is recommended to use a large time value to explore the whole space. + +\subsection Point_set_processing_3Examples_registration_PointMatcher PointMatcher Example + +The following example reads two point sets and aligns them using the +\ref thirdpartylibpointmatcher library, using the ICP algorithm. It also shows how +to customize ICP algorithm by using possible configurations: +\cgalExample{Point_set_processing_3/registration_with_pointmatcher.cpp} + +\cgalFigureRef{Point_set_processing_3tableRegistrationRegistration_visualization_table} demonstrates +visualization of a scan data before and after different registration methods are applied, +including the PointMatcher registration method. To obtain the results for PointMatcher registration +in the visualization table, above-mentioned example was used. + +\subsubsection Point_set_processing_3Examples_registration_PointMatcher_parameter_point_set_filters Parameter: point_set_filters + +The chain of filters to be applied to the point cloud. The +point cloud is processed into an intermediate point cloud with the given chain +of filters to be used in the alignment procedure. The chain is organized with +the forward traversal order of the point set filters range. + +The chain of point set filters are applied only once at the beginning of the +ICP procedure, i.e., before the first iteration of the ICP algorithm. + +The filters can have several purposes, including but not limited to: + +- removal of noisy points which render alignment of point clouds difficult, + +- removal of redundant points so as to speed up alignment, + +- addition of descriptive information to the points such as a surface normal vector or the direction from the point to the sensor. + +In registration, there are two point clouds in consideration, one of which is the reference point +cloud while the other one is the point cloud to register. The point set filters corresponds to `readingDataPointsFilters` configuration module of \ref thirdpartylibpointmatcher +library while it corresponds to the `referenceDataPointsFilters` for the other point cloud. +The filters should be chosen and set from possible components of those configuration modules. + +\subsubsection Point_set_processing_3Examples_registration_PointMatcher_parameter_matcher Parameter: matcher + +The method used for matching (linking) the points from to the points in the reference cloud. + +Corresponds to `matcher` configuration module of \ref thirdpartylibpointmatcher +library. The matcher should be chosen and set from possible components of +the `matcher` configuration module. +See libpointmatcher documentation +for possible configurations. + +\subsubsection Point_set_processing_3Examples_registration_PointMatcher_parameter_outlier_filters Parameter: outlier_filters + +The chain of filters to be applied to the matched (linked) point clouds after +each processing iteration of the ICP algorithm to remove the links which do not +correspond to true point correspondences. The outliers are rejected. Points +with no link are ignored in the subsequent error minimization step. +The chain is organized with the forward traversal order of the outlier filters +range. + +Corresponds to `outlierFilters` configuration module of \ref thirdpartylibpointmatcher +library. The filters should be chosen and set from possible components of +the `outlierFilters` configuration module. +See libpointmatcher documentation +for possible configurations. + +\subsubsection Point_set_processing_3Examples_registration_PointMatcher_parameter_error_minimizer Parameter: error_minimizer + +The error minimizer that computes a transformation matrix such as to minimize +the error between the point sets. + +Corresponds to `errorMinimizer` configuration module of \ref thirdpartylibpointmatcher +library. The error minimizer should be chosen and set from possible components of +the `errorMinimizer` configuration module. +See libpointmatcher documentation +for possible configurations. + +\subsubsection Point_set_processing_3Examples_registration_PointMatcher_parameter_inspector Parameter: inspector + +The inspector allows to log data at different steps for analysis. Inspectors +typically provide deeper scrutiny than the logger. + +Corresponds to `inspector` configuration module of \ref thirdpartylibpointmatcher +library. The inspector should be chosen and set from possible components of +the `inspector` configuration module. +See libpointmatcher documentation +for possible configurations. + +\subsubsection Point_set_processing_3Examples_registration_PointMatcher_parameter_logger Parameter: logger + +The method for logging information regarding the registration process outputted +by \ref thirdpartylibpointmatcher library. The logs generated by CGAL library +does not get effected by this configuration. + +Corresponds to `logger` configuration module of \ref thirdpartylibpointmatcher +library. The logger should be chosen and set from possible components of +the `logger` configuration module. +See libpointmatcher documentation +for possible configurations. + +\subsubsection Point_set_processing_3Examples_registration_PointMatcher_parameter_transformation Parameter: transformation + +The affine transformation that is used as the initial transformation for the reference point cloud. + +\subsection Point_set_processing_3Examples_registration_OpenGR_PointMatcher_Pipeline OpenGR/PointMatcher Pipeline Example + +The following example reads two point sets and aligns them by using both +\ref thirdpartyOpenGR and \ref thirdpartylibpointmatcher libraries, respectively. +It depicts a use case where a coarse estimation of a registration transformation +is done using the Super4PCS algorithm. Then, a fine registration from this coarse +registration using the ICP algorithm. +\cgalExample{Point_set_processing_3/registration_with_opengr_pointmatcher_pipeline.cpp} + +\cgalFigureRef{Point_set_processing_3tableRegistrationRegistration_visualization_table} demonstrates +visualization of a scan data before and after different registration methods are applied, +including the pipeline of %OpenGR and PointMatcher registration methods. To obtain the results +for the pipeline of %OpenGR and PointMatcher registration methods in the visualization table, +above-mentioned example was used. + +\cgalFigureAnchor{Point_set_processing_3tableRegistrationRegistration_visualization_table} + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Scan 1 Scan 1 (possibly transformed, green) and Scan 2 (the reference, red)
    Unregistered + \cgalFigureBegin{Point_set_processing_3figRegistrationUnregistered_hippo2_view1, registration_view1_hippo2_unregistered.png} + \cgalFigureEnd + + \cgalFigureBegin{Point_set_processing_3figRegistrationUnregistered_hippo1_hippo2_view1, registration_view1_hippo1_hippo2_unregistered.png} + \cgalFigureEnd +
    + Registered + using + %OpenGR + + \cgalFigureBegin{Point_set_processing_3figRegistrationOpenGR_hippo2_view1, registration_view1_hippo2_opengr.png} + \cgalFigureEnd + + \cgalFigureBegin{Point_set_processing_3figRegistrationOpenGR_hippo1_hippo2_view1, registration_view1_hippo1_hippo2_opengr.png} + \cgalFigureEnd +
    + Registered + using + PointMatcher + + \cgalFigureBegin{Point_set_processing_3figRegistrationPointMatcher_hippo2_view1, registration_view1_hippo2_pointmatcher.png} + \cgalFigureEnd + + \cgalFigureBegin{Point_set_processing_3figRegistrationPointMatcher_hippo1_hippo2_view1, registration_view1_hippo1_hippo2_pointmatcher.png} + \cgalFigureEnd +
    + Registered + using + OpenGR+PointMatcher + Pipeline + + \cgalFigureBegin{Point_set_processing_3figRegistrationPipeline_hippo2_view1, registration_view1_hippo2_opengr_pointmatcher_pipeline.png} + \cgalFigureEnd + + \cgalFigureBegin{Point_set_processing_3figRegistrationPipeline_hippo1_hippo2_view1, registration_view1_hippo1_hippo2_opengr_pointmatcher_pipeline.png} + \cgalFigureEnd +
    +\cgalFigureCaptionBegin{Point_set_processing_3tableRegistrationRegistration_visualization_table} +Visualization of registered hippo scans with different registration methods. +Two scans are used: red as the reference, green as the one for which the transformation +is computed and applied. To obtain the results, the example code given in +\ref Point_set_processing_3Examples_registration_OpenGR , +\ref Point_set_processing_3Examples_registration_PointMatcher , +\ref Point_set_processing_3Examples_registration_OpenGR_PointMatcher_Pipeline +were applied, respectively. The parameters of the algorithms used to obtain those +results are not optimized for the shown scans; therefore, better parameter choice +might result in better results in terms of registration accuracy for each algorithm +individually. +\cgalFigureCaptionEnd + + \section Point_set_processing_3OutlierRemoval Outlier Removal @@ -664,6 +962,9 @@ Started from GSoC'2013, three new algorithms were implemented by Shihao Wu and C Started from GSoC'2014, Jocelyn Meyron with the help of Quentin Mérigot introduced the computation of the Voronoi covariance measure of a point set, as well as the normal and feature edge estimation functions based on it. Florent Lafarge with the help of Simon Giraudot contributed the point set structuring algorithm. +Started from GSoC'2019, Necip Fazil Yildiran with the help of Nicolas Mellado and Simon Giraudot introduced the wrappers for OpenGR and PointMatcher +libraries that perform registration on two point sets. + */ } /* namespace CGAL */ diff --git a/Point_set_processing_3/doc/Point_set_processing_3/examples.txt b/Point_set_processing_3/doc/Point_set_processing_3/examples.txt index 43849ae022c..32ee499ff83 100644 --- a/Point_set_processing_3/doc/Point_set_processing_3/examples.txt +++ b/Point_set_processing_3/doc/Point_set_processing_3/examples.txt @@ -6,6 +6,9 @@ \example Point_set_processing_3/average_spacing_example.cpp \example Point_set_processing_3/scale_estimation_example.cpp \example Point_set_processing_3/scale_estimation_2d_example.cpp +\example Point_set_processing_3/registration_with_OpenGR.cpp +\example Point_set_processing_3/registration_with_pointmatcher.cpp +\example Point_set_processing_3/registration_with_opengr_pointmatcher_pipeline.cpp \example Point_set_processing_3/remove_outliers_example.cpp \example Point_set_processing_3/grid_simplification_example.cpp \example Point_set_processing_3/grid_simplify_indices.cpp diff --git a/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo1_hippo2_opengr.png b/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo1_hippo2_opengr.png new file mode 100644 index 00000000000..cd2e069f754 Binary files /dev/null and b/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo1_hippo2_opengr.png differ diff --git a/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo1_hippo2_opengr_pointmatcher_pipeline.png b/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo1_hippo2_opengr_pointmatcher_pipeline.png new file mode 100644 index 00000000000..be57be7c962 Binary files /dev/null and b/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo1_hippo2_opengr_pointmatcher_pipeline.png differ diff --git a/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo1_hippo2_pointmatcher.png b/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo1_hippo2_pointmatcher.png new file mode 100644 index 00000000000..6fd42c4d8dc Binary files /dev/null and b/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo1_hippo2_pointmatcher.png differ diff --git a/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo1_hippo2_unregistered.png b/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo1_hippo2_unregistered.png new file mode 100644 index 00000000000..0b3e445ab81 Binary files /dev/null and b/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo1_hippo2_unregistered.png differ diff --git a/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo2_opengr.png b/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo2_opengr.png new file mode 100644 index 00000000000..e784a3c7bb4 Binary files /dev/null and b/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo2_opengr.png differ diff --git a/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo2_opengr_pointmatcher_pipeline.png b/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo2_opengr_pointmatcher_pipeline.png new file mode 100644 index 00000000000..3a79d8d1ddb Binary files /dev/null and b/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo2_opengr_pointmatcher_pipeline.png differ diff --git a/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo2_pointmatcher.png b/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo2_pointmatcher.png new file mode 100644 index 00000000000..400c8f34035 Binary files /dev/null and b/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo2_pointmatcher.png differ diff --git a/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo2_unregistered.png b/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo2_unregistered.png new file mode 100644 index 00000000000..89c4be0bc00 Binary files /dev/null and b/Point_set_processing_3/doc/Point_set_processing_3/fig/registration_view1_hippo2_unregistered.png differ diff --git a/Point_set_processing_3/doc/Point_set_processing_3/fig/super4PCS_overlap.png b/Point_set_processing_3/doc/Point_set_processing_3/fig/super4PCS_overlap.png new file mode 100644 index 00000000000..90bebedc29b Binary files /dev/null and b/Point_set_processing_3/doc/Point_set_processing_3/fig/super4PCS_overlap.png differ diff --git a/Point_set_processing_3/examples/Point_set_processing_3/CMakeLists.txt b/Point_set_processing_3/examples/Point_set_processing_3/CMakeLists.txt index c2da826d49b..532d19c5cf5 100644 --- a/Point_set_processing_3/examples/Point_set_processing_3/CMakeLists.txt +++ b/Point_set_processing_3/examples/Point_set_processing_3/CMakeLists.txt @@ -3,8 +3,6 @@ cmake_minimum_required(VERSION 3.1...3.15) project( Point_set_processing_3_Examples ) - - # Find CGAL find_package(CGAL QUIET) @@ -42,30 +40,21 @@ if ( CGAL_FOUND ) create_single_source_cgal_program( "bilateral_smooth_point_set_example.cpp" ) create_single_source_cgal_program( "grid_simplification_example.cpp" ) create_single_source_cgal_program( "grid_simplify_indices.cpp" ) - create_single_source_cgal_program( "hierarchy_simplification_example.cpp" ) - create_single_source_cgal_program( "normals_example.cpp" ) create_single_source_cgal_program( "property_map.cpp" ) create_single_source_cgal_program( "random_simplification_example.cpp" ) create_single_source_cgal_program( "read_write_xyz_point_set_example.cpp" ) create_single_source_cgal_program( "remove_outliers_example.cpp" ) - create_single_source_cgal_program( "scale_estimation_example.cpp" ) - create_single_source_cgal_program( "scale_estimation_2d_example.cpp" ) create_single_source_cgal_program( "wlop_simplify_and_regularize_point_set_example.cpp" ) create_single_source_cgal_program( "edge_aware_upsample_point_set_example.cpp" ) create_single_source_cgal_program( "structuring_example.cpp" ) - create_single_source_cgal_program( "callback_example.cpp" ) - set(needed_cxx_features cxx_rvalue_references cxx_variadic_templates) - create_single_source_cgal_program( "read_ply_points_with_colors_example.cpp" CXX_FEATURES ${needed_cxx_features} ) - create_single_source_cgal_program( "write_ply_points_example.cpp" CXX_FEATURES ${needed_cxx_features} ) + create_single_source_cgal_program( "read_ply_points_with_colors_example.cpp" ) + create_single_source_cgal_program( "write_ply_points_example.cpp" ) find_package(LASLIB) if (LASLIB_FOUND) - include(${LASLIB_USE_FILE}) - include_directories(${LASLIB_INCLUDE_DIR}) - include_directories(${LASZIP_INCLUDE_DIR}) - create_single_source_cgal_program( "read_las_example.cpp" CXX_FEATURES ${needed_cxx_features} ) - target_link_libraries(read_las_example PRIVATE ${LASLIB_LIBRARIES}) + create_single_source_cgal_program( "read_las_example.cpp" ) + CGAL_target_use_LASLIB(read_las_example) else() message(STATUS "NOTICE : the LAS reader test requires LASlib and will not be compiled.") endif() @@ -73,30 +62,82 @@ if ( CGAL_FOUND ) # Use Eigen find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) # Executables that require Eigen create_single_source_cgal_program( "jet_smoothing_example.cpp" ) + CGAL_target_use_Eigen(jet_smoothing_example) + create_single_source_cgal_program( "normal_estimation.cpp" ) + CGAL_target_use_Eigen(normal_estimation) + create_single_source_cgal_program( "edges_example.cpp" ) - else() + # Executables that require libpointmatcher + find_package(libpointmatcher QUIET) + if (libpointmatcher_FOUND) + create_single_source_cgal_program( "registration_with_pointmatcher.cpp" ) + CGAL_target_use_pointmatcher(registration_with_pointmatcher) + CGAL_target_use_Eigen(registration_with_pointmatcher) + else() + message(STATUS "NOTICE : the registration_with_pointmatcher test requires libpointmatcher and will not be compiled.") + endif() + + # Executables that require OpenGR + find_package(OpenGR QUIET) + if (OpenGR_FOUND) + create_single_source_cgal_program( "registration_with_OpenGR.cpp" ) + CGAL_target_use_OpenGR(registration_with_OpenGR) + CGAL_target_use_Eigen(registration_with_OpenGR) + else() + message(STATUS "NOTICE : registration_with_OpenGR requires OpenGR, and will not be compiled.") + endif() + + # Executables that require both libpointmatcher and OpenGR + if (libpointmatcher_FOUND AND OpenGR_FOUND) + create_single_source_cgal_program( "registration_with_opengr_pointmatcher_pipeline.cpp" ) + CGAL_target_use_OpenGR(registration_with_opengr_pointmatcher_pipeline) + CGAL_target_use_pointmatcher(registration_with_opengr_pointmatcher_pipeline) + CGAL_target_use_Eigen(registration_with_opengr_pointmatcher_pipeline) + else() + message(STATUS "NOTICE : registration_with_opengr_pointmatcher_pipeline requires libpointmatcher and OpenGR, and will not be compiled.") + endif() + + CGAL_target_use_Eigen(edges_example) + + create_single_source_cgal_program( "callback_example.cpp" ) + CGAL_target_use_Eigen(callback_example) + + create_single_source_cgal_program( "scale_estimation_example.cpp" ) + CGAL_target_use_Eigen(scale_estimation_example) + + create_single_source_cgal_program( "scale_estimation_2d_example.cpp" ) + CGAL_target_use_Eigen(scale_estimation_2d_example) + + create_single_source_cgal_program( "hierarchy_simplification_example.cpp" ) + CGAL_target_use_Eigen(hierarchy_simplification_example) + + create_single_source_cgal_program( "normals_example.cpp" ) + CGAL_target_use_Eigen(normals_example) + + else() message(STATUS "NOTICE: Some of the executables in this directory need Eigen 3.1 (or greater) and will not be compiled.") endif() - foreach(target - scale_estimation_example - wlop_simplify_and_regularize_point_set_example - bilateral_smooth_point_set_example - edge_aware_upsample_point_set_example - average_spacing_example - normals_example - jet_smoothing_example - normal_estimation - callback_example) - if(TBB_FOUND AND TARGET ${target}) - CGAL_target_use_TBB(${target}) - endif() - endforeach() + if (TBB_FOUND) + foreach(target + scale_estimation_example + wlop_simplify_and_regularize_point_set_example + bilateral_smooth_point_set_example + edge_aware_upsample_point_set_example + average_spacing_example + normals_example + jet_smoothing_example + normal_estimation + callback_example) + if(TARGET ${target}) + CGAL_target_use_TBB(${target}) + endif() + endforeach() + endif() else() message(STATUS "NOTICE: This program requires the CGAL library, and will not be compiled.") diff --git a/Point_set_processing_3/examples/Point_set_processing_3/average_spacing_example.cpp b/Point_set_processing_3/examples/Point_set_processing_3/average_spacing_example.cpp index e97432aa79b..776f640c83c 100644 --- a/Point_set_processing_3/examples/Point_set_processing_3/average_spacing_example.cpp +++ b/Point_set_processing_3/examples/Point_set_processing_3/average_spacing_example.cpp @@ -16,12 +16,7 @@ typedef Kernel::Point_3 Point; typedef boost::tuple IndexedPointWithColorTuple; // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif - +typedef CGAL::Parallel_if_available_tag Concurrency_tag; int main(int argc, char*argv[]) { diff --git a/Point_set_processing_3/examples/Point_set_processing_3/bilateral_smooth_point_set_example.cpp b/Point_set_processing_3/examples/Point_set_processing_3/bilateral_smooth_point_set_example.cpp index 956f89cfe80..0f87a437e4a 100644 --- a/Point_set_processing_3/examples/Point_set_processing_3/bilateral_smooth_point_set_example.cpp +++ b/Point_set_processing_3/examples/Point_set_processing_3/bilateral_smooth_point_set_example.cpp @@ -17,12 +17,7 @@ typedef Kernel::Vector_3 Vector; typedef std::pair PointVectorPair; // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif - +typedef CGAL::Parallel_if_available_tag Concurrency_tag; int main(int argc, char*argv[]) { diff --git a/Point_set_processing_3/examples/Point_set_processing_3/callback_example.cpp b/Point_set_processing_3/examples/Point_set_processing_3/callback_example.cpp index 4004c7e832c..addaaeefaa3 100644 --- a/Point_set_processing_3/examples/Point_set_processing_3/callback_example.cpp +++ b/Point_set_processing_3/examples/Point_set_processing_3/callback_example.cpp @@ -18,12 +18,7 @@ typedef Kernel::Point_3 Point; typedef CGAL::Random_points_on_sphere_3 Generator; // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif - +typedef CGAL::Parallel_if_available_tag Concurrency_tag; // instance of std::function struct Progress_to_std_cerr_callback diff --git a/Point_set_processing_3/examples/Point_set_processing_3/data/hippo1.ply b/Point_set_processing_3/examples/Point_set_processing_3/data/hippo1.ply new file mode 100644 index 00000000000..3dd54ca58d9 Binary files /dev/null and b/Point_set_processing_3/examples/Point_set_processing_3/data/hippo1.ply differ diff --git a/Point_set_processing_3/examples/Point_set_processing_3/data/hippo2.ply b/Point_set_processing_3/examples/Point_set_processing_3/data/hippo2.ply new file mode 100644 index 00000000000..4fb9e674be3 Binary files /dev/null and b/Point_set_processing_3/examples/Point_set_processing_3/data/hippo2.ply differ diff --git a/Point_set_processing_3/examples/Point_set_processing_3/edge_aware_upsample_point_set_example.cpp b/Point_set_processing_3/examples/Point_set_processing_3/edge_aware_upsample_point_set_example.cpp index 7ca76b9a055..173c07e9f1c 100644 --- a/Point_set_processing_3/examples/Point_set_processing_3/edge_aware_upsample_point_set_example.cpp +++ b/Point_set_processing_3/examples/Point_set_processing_3/edge_aware_upsample_point_set_example.cpp @@ -16,12 +16,7 @@ typedef Kernel::Vector_3 Vector; typedef std::pair PointVectorPair; // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif - +typedef CGAL::Parallel_if_available_tag Concurrency_tag; int main(int argc, char* argv[]) { diff --git a/Point_set_processing_3/examples/Point_set_processing_3/jet_smoothing_example.cpp b/Point_set_processing_3/examples/Point_set_processing_3/jet_smoothing_example.cpp index f228c8d69f6..85be76af70d 100644 --- a/Point_set_processing_3/examples/Point_set_processing_3/jet_smoothing_example.cpp +++ b/Point_set_processing_3/examples/Point_set_processing_3/jet_smoothing_example.cpp @@ -8,12 +8,7 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::Point_3 Point; // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif - +typedef CGAL::Parallel_if_available_tag Concurrency_tag; int main(void) { diff --git a/Point_set_processing_3/examples/Point_set_processing_3/normal_estimation.cpp b/Point_set_processing_3/examples/Point_set_processing_3/normal_estimation.cpp index befba2133f5..5f881c12647 100644 --- a/Point_set_processing_3/examples/Point_set_processing_3/normal_estimation.cpp +++ b/Point_set_processing_3/examples/Point_set_processing_3/normal_estimation.cpp @@ -48,12 +48,7 @@ typedef std::pair PointVectorPair; typedef std::vector PointList; // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif - +typedef CGAL::Parallel_if_available_tag Concurrency_tag; // ---------------------------------------------------------------------------- // Private functions diff --git a/Point_set_processing_3/examples/Point_set_processing_3/normals_example.cpp b/Point_set_processing_3/examples/Point_set_processing_3/normals_example.cpp index 25a28429661..629b836555d 100644 --- a/Point_set_processing_3/examples/Point_set_processing_3/normals_example.cpp +++ b/Point_set_processing_3/examples/Point_set_processing_3/normals_example.cpp @@ -18,11 +18,7 @@ typedef Kernel::Vector_3 Vector; typedef std::pair PointVectorPair; // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; int main(int argc, char*argv[]) { diff --git a/Point_set_processing_3/examples/Point_set_processing_3/registration_with_OpenGR.cpp b/Point_set_processing_3/examples/Point_set_processing_3/registration_with_OpenGR.cpp new file mode 100644 index 00000000000..c418d78523e --- /dev/null +++ b/Point_set_processing_3/examples/Point_set_processing_3/registration_with_OpenGR.cpp @@ -0,0 +1,87 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +typedef CGAL::Simple_cartesian K; +typedef K::Point_3 Point_3; +typedef K::Vector_3 Vector_3; +typedef std::pair Pwn; +typedef CGAL::First_of_pair_property_map Point_map; +typedef CGAL::Second_of_pair_property_map Normal_map; + +namespace params = CGAL::parameters; + +int main(int argc, const char** argv) +{ + const char* fname1 = (argc>1)?argv[1]:"data/hippo1.ply"; + const char* fname2 = (argc>2)?argv[2]:"data/hippo2.ply"; + + std::vector pwns1, pwns2; + std::ifstream input(fname1); + if (!input || + !CGAL::read_ply_points(input, std::back_inserter(pwns1), + CGAL::parameters::point_map (CGAL::First_of_pair_property_map()). + normal_map (Normal_map()))) + { + std::cerr << "Error: cannot read file " << fname1 << std::endl; + return EXIT_FAILURE; + } + input.close(); + + input.open(fname2); + if (!input || + !CGAL::read_ply_points(input, std::back_inserter(pwns2), + CGAL::parameters::point_map (Point_map()). + normal_map (Normal_map()))) + { + std::cerr << "Error: cannot read file " << fname2 << std::endl; + return EXIT_FAILURE; + } + input.close(); + + // EITHER call the registration method Super4PCS from OpenGR to get the transformation to apply to pwns2 + // std::pair res = + CGAL::OpenGR::compute_registration_transformation(pwns1, pwns2, + params::point_map(Point_map()) + .normal_map(Normal_map()) + .number_of_samples(200) + .maximum_running_time(60) + .accuracy(0.01), + params::point_map(Point_map()) + .normal_map(Normal_map())); + + // OR call the registration method Super4PCS from OpenGR and apply the transformation to pwn2 + double score = + CGAL::OpenGR::register_point_sets(pwns1, pwns2, + params::point_map(Point_map()) + .normal_map(Normal_map()) + .number_of_samples(200) + .maximum_running_time(60) + .accuracy(0.01), + params::point_map(Point_map()) + .normal_map(Normal_map())); + + std::ofstream out("pwns2_aligned.ply"); + if (!out || + !CGAL::write_ply_points( + out, pwns2, + CGAL::parameters::point_map(Point_map()). + normal_map(Normal_map()))) + { + return EXIT_FAILURE; + } + + std::cout << "Registration score: " << score << ".\n" + << "Transformed version of " << fname2 + << " written to pwn2_aligned.ply.\n"; + + return EXIT_SUCCESS; +} diff --git a/Point_set_processing_3/examples/Point_set_processing_3/registration_with_opengr_pointmatcher_pipeline.cpp b/Point_set_processing_3/examples/Point_set_processing_3/registration_with_opengr_pointmatcher_pipeline.cpp new file mode 100644 index 00000000000..5093ed485a8 --- /dev/null +++ b/Point_set_processing_3/examples/Point_set_processing_3/registration_with_opengr_pointmatcher_pipeline.cpp @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +typedef CGAL::Simple_cartesian K; +typedef K::Point_3 Point_3; +typedef K::Vector_3 Vector_3; +typedef std::pair Pwn; +typedef CGAL::First_of_pair_property_map Point_map; +typedef CGAL::Second_of_pair_property_map Normal_map; + +namespace params = CGAL::parameters; + +int main(int argc, const char** argv) +{ + const char* fname1 = (argc>1)?argv[1]:"data/hippo1.ply"; + const char* fname2 = (argc>2)?argv[2]:"data/hippo2.ply"; + + std::vector pwns1, pwns2; + std::ifstream input(fname1); + if (!input || + !CGAL::read_ply_points(input, std::back_inserter(pwns1), + CGAL::parameters::point_map (CGAL::First_of_pair_property_map()). + normal_map (Normal_map()))) + { + std::cerr << "Error: cannot read file " << fname1 << std::endl; + return EXIT_FAILURE; + } + input.close(); + + input.open(fname2); + if (!input || + !CGAL::read_ply_points(input, std::back_inserter(pwns2), + CGAL::parameters::point_map (Point_map()). + normal_map (Normal_map()))) + { + std::cerr << "Error: cannot read file " << fname2 << std::endl; + return EXIT_FAILURE; + } + input.close(); + + std::cerr << "Computing registration transformation using OpenGR Super4PCS.." << std::endl; + // First, compute registration transformation using OpenGR Super4PCS + K::Aff_transformation_3 res = + std::get<0>( // get first of pair, which is the transformation + CGAL::OpenGR::compute_registration_transformation + (pwns1, pwns2, + params::point_map(Point_map()).normal_map(Normal_map()), + params::point_map(Point_map()).normal_map(Normal_map())) + ); + + std::cerr << "Computing registration transformation using PointMatcher ICP, " + << "taking transformation computed by OpenGR Super4PCS as initial transformation.." << std::endl; + // Then, compute registration transformation using PointMatcher ICP, taking transformation computed + // by OpenGR as initial transformation, and apply the transformation to pwns2 + // bool converged = + CGAL::pointmatcher::register_point_sets + (pwns1, pwns2, + params::point_map(Point_map()).normal_map(Normal_map()), + params::point_map(Point_map()).normal_map(Normal_map()) + .transformation(res)); + + std::ofstream out("pwns2_aligned.ply"); + if (!out || + !CGAL::write_ply_points( + out, pwns2, + CGAL::parameters::point_map(Point_map()). + normal_map(Normal_map()))) + { + return EXIT_FAILURE; + } + + std::cerr << "Transformed version of " << fname2 + << " written to pwn2_aligned.ply.\n"; + + return EXIT_SUCCESS; +} diff --git a/Point_set_processing_3/examples/Point_set_processing_3/registration_with_pointmatcher.cpp b/Point_set_processing_3/examples/Point_set_processing_3/registration_with_pointmatcher.cpp new file mode 100644 index 00000000000..d0827f416d4 --- /dev/null +++ b/Point_set_processing_3/examples/Point_set_processing_3/registration_with_pointmatcher.cpp @@ -0,0 +1,158 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +typedef CGAL::Simple_cartesian K; +typedef K::Point_3 Point_3; +typedef K::Vector_3 Vector_3; +typedef std::pair Pwn; +typedef CGAL::First_of_pair_property_map Point_map; +typedef CGAL::Second_of_pair_property_map Normal_map; + +namespace params = CGAL::parameters; + +int main(int argc, const char** argv) +{ + const char* fname1 = (argc>1)?argv[1]:"data/hippo1.ply"; + const char* fname2 = (argc>2)?argv[2]:"data/hippo2.ply"; + + std::vector pwns1, pwns2; + std::ifstream input(fname1); + if (!input || + !CGAL::read_ply_points(input, std::back_inserter(pwns1), + CGAL::parameters::point_map (CGAL::First_of_pair_property_map()). + normal_map (Normal_map()))) + { + std::cerr << "Error: cannot read file " << fname1 << std::endl; + return EXIT_FAILURE; + } + input.close(); + + input.open(fname2); + if (!input || + !CGAL::read_ply_points(input, std::back_inserter(pwns2), + CGAL::parameters::point_map (Point_map()). + normal_map (Normal_map()))) + { + std::cerr << "Error: cannot read file " << fname2 << std::endl; + return EXIT_FAILURE; + } + input.close(); + + // + // Prepare ICP config + // + using CGAL::pointmatcher::ICP_config; + + // Possible config modules/components: https://libpointmatcher.readthedocs.io/en/latest/Configuration/#configuration-of-an-icp-chain + // See documentation of optional named parameters for CGAL PM ICP configuration / pointmatcher config module mapping + + // Prepare point set 1 filters (PM::ReferenceDataPointsFilters) + std::vector point_set_1_filters; + point_set_1_filters.push_back( ICP_config { /*.name=*/"MinDistDataPointsFilter" , /*.params=*/{ {"minDist", "0.5" }} } ); + point_set_1_filters.push_back( ICP_config { /*.name=*/"RandomSamplingDataPointsFilter", /*.params=*/{ {"prob" , "0.05"}} } ); + + // Prepare point set 2 filters (PM::ReadingDataPointsFilters) + std::vector point_set_2_filters; + point_set_2_filters.push_back( ICP_config { /*.name=*/"MinDistDataPointsFilter" , /*.params=*/{ {"minDist", "0.5" }} } ); + point_set_2_filters.push_back( ICP_config { /*.name=*/"RandomSamplingDataPointsFilter", /*.params=*/{ {"prob" , "0.05"}} } ); + + // Prepare matcher function + ICP_config matcher { /*.name=*/"KDTreeMatcher", /*.params=*/{ {"knn", "1"}, {"epsilon", "3.16"} } }; + + // Prepare outlier filters + std::vector outlier_filters; + outlier_filters.push_back( ICP_config { /*.name=*/"TrimmedDistOutlierFilter", /*.params=*/{ {"ratio", "0.75" }} } ); + + // Prepare error minimizer + ICP_config error_minimizer { /*.name=*/"PointToPointErrorMinimizer"}; + + // Prepare transformation checker + std::vector transformation_checkers; + transformation_checkers.push_back( ICP_config { /*.name=*/"CounterTransformationChecker", /*.params=*/{ {"maxIterationCount", "150" }} } ); + transformation_checkers.push_back( ICP_config { /*.name=*/"DifferentialTransformationChecker", /*.params=*/{ {"minDiffRotErr" , "0.001" }, + {"minDiffTransErr", "0.01" }, + {"smoothLength" , "4" } } + } ); + // Prepare inspector + ICP_config inspector { /*.name=*/"NullInspector" }; + + // Prepare logger + ICP_config logger { /*.name=*/"FileLogger" }; + + const K::Aff_transformation_3 identity_transform = K::Aff_transformation_3(CGAL::Identity_transformation()); + + // EITHER call the ICP registration method pointmatcher to get the transformation to apply to pwns2 + std::pair res = + CGAL::pointmatcher::compute_registration_transformation + (pwns1, pwns2, + params::point_map(Point_map()).normal_map(Normal_map()) + .point_set_filters(point_set_1_filters) + .matcher(matcher) + .outlier_filters(outlier_filters) + .error_minimizer(error_minimizer) + .transformation_checkers(transformation_checkers) + .inspector(inspector) + .logger(logger), + params::point_map(Point_map()).normal_map(Normal_map()) + .point_set_filters(point_set_2_filters) + .transformation(identity_transform) /* initial transform for pwns2. + * default value is already identity transform. + * a proper initial transform could be given, for example, + * a transform returned from a coarse registration algorithm. + * */ + ); + + // OR call the ICP registration method from pointmatcher and apply the transformation to pwn2 + bool converged = + CGAL::pointmatcher::register_point_sets + (pwns1, pwns2, + params::point_map(Point_map()).normal_map(Normal_map()) + .point_set_filters(point_set_1_filters) + .matcher(matcher) + .outlier_filters(outlier_filters) + .error_minimizer(error_minimizer) + .transformation_checkers(transformation_checkers) + .inspector(inspector) + .logger(logger), + params::point_map(Point_map()).normal_map(Normal_map()) + .point_set_filters(point_set_2_filters) + .transformation(res.first) /* pass the above computed transformation as initial transformation. + * as a result, the registration will require less iterations to converge. + * */ + ); + + if (converged) + std::cerr << "Success" << std::endl; + else + { + std::cerr << "Failure" << std::endl; + return EXIT_FAILURE; + } + + std::ofstream out("pwns2_aligned.ply"); + if (!out || + !CGAL::write_ply_points( + out, pwns2, + CGAL::parameters::point_map(Point_map()). + normal_map(Normal_map()))) + { + return EXIT_FAILURE; + } + + std::cout << "Transformed version of " << fname2 + << " written to pwn2_aligned.ply.\n"; + + return EXIT_SUCCESS; +} diff --git a/Point_set_processing_3/examples/Point_set_processing_3/scale_estimation_example.cpp b/Point_set_processing_3/examples/Point_set_processing_3/scale_estimation_example.cpp index bdd2ebb5730..a85f56bea45 100644 --- a/Point_set_processing_3/examples/Point_set_processing_3/scale_estimation_example.cpp +++ b/Point_set_processing_3/examples/Point_set_processing_3/scale_estimation_example.cpp @@ -12,11 +12,7 @@ #include // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; // Types typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; diff --git a/Point_set_processing_3/examples/Point_set_processing_3/structuring_example.cpp b/Point_set_processing_3/examples/Point_set_processing_3/structuring_example.cpp index a45d8663c5f..21d18ea6799 100644 --- a/Point_set_processing_3/examples/Point_set_processing_3/structuring_example.cpp +++ b/Point_set_processing_3/examples/Point_set_processing_3/structuring_example.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include diff --git a/Point_set_processing_3/examples/Point_set_processing_3/wlop_simplify_and_regularize_point_set_example.cpp b/Point_set_processing_3/examples/Point_set_processing_3/wlop_simplify_and_regularize_point_set_example.cpp index e8485c3e5f8..d6ef47246fe 100644 --- a/Point_set_processing_3/examples/Point_set_processing_3/wlop_simplify_and_regularize_point_set_example.cpp +++ b/Point_set_processing_3/examples/Point_set_processing_3/wlop_simplify_and_regularize_point_set_example.cpp @@ -12,11 +12,7 @@ typedef CGAL::Simple_cartesian Kernel; typedef Kernel::Point_3 Point; // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; int main(int argc, char** argv) { diff --git a/Point_set_processing_3/include/CGAL/IO/read_las_points.h b/Point_set_processing_3/include/CGAL/IO/read_las_points.h index 9762a674d44..fde0db5e573 100644 --- a/Point_set_processing_3/include/CGAL/IO/read_las_points.h +++ b/Point_set_processing_3/include/CGAL/IO/read_las_points.h @@ -461,9 +461,9 @@ bool read_las_points(std::istream& stream, typedef Point_set_processing_3::Fake_point_range PointRange; - typedef typename Point_set_processing_3::GetPointMap::type PointMap; - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - + typedef typename CGAL::GetPointMap::type PointMap; + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + return read_las_points_with_properties (stream, output, make_las_point_reader (point_map)); } diff --git a/Point_set_processing_3/include/CGAL/IO/read_off_points.h b/Point_set_processing_3/include/CGAL/IO/read_off_points.h index c5e738dc099..84a8a18828e 100644 --- a/Point_set_processing_3/include/CGAL/IO/read_off_points.h +++ b/Point_set_processing_3/include/CGAL/IO/read_off_points.h @@ -82,16 +82,16 @@ read_off_points( typedef Point_set_processing_3::Fake_point_range PointRange; // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetNormalMap::type NormalMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; bool has_normals = !(boost::is_same::NoMap>::value); - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map), NormalMap()); - + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map)); + // value_type_traits is a workaround as back_insert_iterator's value_type is void // typedef typename value_type_traits::type Enriched_point; typedef OutputIteratorValueType Enriched_point; diff --git a/Point_set_processing_3/include/CGAL/IO/read_ply_points.h b/Point_set_processing_3/include/CGAL/IO/read_ply_points.h index 9d1797c0709..e9af2bd49e0 100644 --- a/Point_set_processing_3/include/CGAL/IO/read_ply_points.h +++ b/Point_set_processing_3/include/CGAL/IO/read_ply_points.h @@ -238,14 +238,14 @@ bool read_ply_points(std::istream& stream, typedef Point_set_processing_3::Fake_point_range PointRange; // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetNormalMap::type NormalMap; bool has_normals = !(boost::is_same::NoMap>::value); - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map), NormalMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map)); if (has_normals) return read_ply_points_with_properties (stream, output, diff --git a/Point_set_processing_3/include/CGAL/IO/read_xyz_points.h b/Point_set_processing_3/include/CGAL/IO/read_xyz_points.h index 0c31bd3b461..944352ffdcc 100644 --- a/Point_set_processing_3/include/CGAL/IO/read_xyz_points.h +++ b/Point_set_processing_3/include/CGAL/IO/read_xyz_points.h @@ -81,15 +81,15 @@ read_xyz_points( typedef Point_set_processing_3::Fake_point_range PointRange; // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetNormalMap::type NormalMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; bool has_normals = !(boost::is_same::NoMap>::value); - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map), NormalMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map)); // value_type_traits is a workaround as back_insert_iterator's value_type is void //typedef typename value_type_traits::type Enriched_point; diff --git a/Point_set_processing_3/include/CGAL/IO/write_las_points.h b/Point_set_processing_3/include/CGAL/IO/write_las_points.h index d0540f54c14..82206c0a891 100644 --- a/Point_set_processing_3/include/CGAL/IO/write_las_points.h +++ b/Point_set_processing_3/include/CGAL/IO/write_las_points.h @@ -276,9 +276,9 @@ write_las_points( using parameters::choose_parameter; using parameters::get_parameter; - typedef typename Point_set_processing_3::GetPointMap::type PointMap; - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - + typedef typename CGAL::GetPointMap::type PointMap; + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + return write_las_points_with_properties (stream, points, make_las_point_writer(point_map)); } diff --git a/Point_set_processing_3/include/CGAL/IO/write_off_points.h b/Point_set_processing_3/include/CGAL/IO/write_off_points.h index ddbb37ae764..2c681d5373c 100644 --- a/Point_set_processing_3/include/CGAL/IO/write_off_points.h +++ b/Point_set_processing_3/include/CGAL/IO/write_off_points.h @@ -66,15 +66,15 @@ write_off_points( using parameters::get_parameter; // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetNormalMap::type NormalMap; bool has_normals = !(boost::is_same::NoMap>::value); - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map), NormalMap()); - + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map)); + CGAL_point_set_processing_precondition(points.begin() != points.end()); if(!stream) diff --git a/Point_set_processing_3/include/CGAL/IO/write_ply_points.h b/Point_set_processing_3/include/CGAL/IO/write_ply_points.h index c6511f157f6..0776660e1b9 100644 --- a/Point_set_processing_3/include/CGAL/IO/write_ply_points.h +++ b/Point_set_processing_3/include/CGAL/IO/write_ply_points.h @@ -185,14 +185,14 @@ write_ply_points( using parameters::get_parameter; // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetNormalMap::type NormalMap; bool has_normals = !(boost::is_same::NoMap>::value); - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map), NormalMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map)); if (has_normals) return write_ply_points_with_properties( diff --git a/Point_set_processing_3/include/CGAL/IO/write_xyz_points.h b/Point_set_processing_3/include/CGAL/IO/write_xyz_points.h index 6dd3de3b35b..e27599459b2 100644 --- a/Point_set_processing_3/include/CGAL/IO/write_xyz_points.h +++ b/Point_set_processing_3/include/CGAL/IO/write_xyz_points.h @@ -66,15 +66,15 @@ write_xyz_points( using parameters::get_parameter; // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetNormalMap::type NormalMap; bool has_normals = !(boost::is_same::NoMap>::value); - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map), NormalMap()); - + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map)); + CGAL_point_set_processing_precondition(points.begin() != points.end()); if(!stream) diff --git a/Point_set_processing_3/include/CGAL/OpenGR/compute_registration_transformation.h b/Point_set_processing_3/include/CGAL/OpenGR/compute_registration_transformation.h new file mode 100644 index 00000000000..80294dab7e4 --- /dev/null +++ b/Point_set_processing_3/include/CGAL/OpenGR/compute_registration_transformation.h @@ -0,0 +1,337 @@ +// Copyright (c) 2019 GeometryFactory(France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Sebastien Loriot, Necip Fazil Yildiran + +#ifndef CGAL_OPENGR_COMPUTE_REGISTRATION_TRANSFORMATION_H +#define CGAL_OPENGR_COMPUTE_REGISTRATION_TRANSFORMATION_H + +#include + +#if defined(CGAL_LINKED_WITH_OPENGR) || defined(DOXYGEN_RUNNING) + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +namespace CGAL { + +namespace OpenGR { + +template +using Options = typename gr::Match4pcsBase, + gr::DummyTransformVisitor, + gr::AdaptivePointFilter, + gr::AdaptivePointFilter::Options>::OptionsType; + +namespace internal { + +template +struct CGAL_range_and_pmaps_to_opengr_point3d_range +{ + typedef typename InputRange::const_iterator::value_type argument_type; + typedef gr::Point3D result_type; + typedef typename result_type::VectorType vector_type; + + PointMap point_map; + VectorMap normal_map; + + CGAL_range_and_pmaps_to_opengr_point3d_range (PointMap point_map, VectorMap normal_map) + : point_map (point_map), normal_map (normal_map) + { } + + result_type operator() (const argument_type& arg) const + { + const auto& p = get (point_map, arg); + const auto& n = get (normal_map, arg); + + result_type out (p.x(), p.y(), p.z()); + out.set_normal ( vector_type(n.x(), n.y(), n.z()) ); + + return out; + } +}; + +template +std::pair +compute_registration_transformation(const PointRange1& range1, const PointRange2& range2, + PointMap1 point_map1, PointMap2 point_map2, + VectorMap1 vector_map1, VectorMap2 vector_map2, + Options& options) +{ + typedef gr::Point3D PointType; + + namespace GR=gr; + + // TODO: see if should allow user to change those types + typedef Eigen::Matrix MatrixType; + typedef gr::UniformDistSampler SamplerType; + typedef gr::DummyTransformVisitor TrVisitorType; + typedef gr::Match4pcsBase MatcherType; + + MatrixType mat (MatrixType::Identity()); + SamplerType sampler; + TrVisitorType visitor; + + // Unary functions that convert value_type of point ranges to gr::Point3D + CGAL_range_and_pmaps_to_opengr_point3d_range // TODO: remove deductible ones + unary_function_1 (point_map1, vector_map1); + + CGAL_range_and_pmaps_to_opengr_point3d_range // TODO: remove deductible ones + unary_function_2 (point_map2, vector_map2); + + auto gr_point_range_1 = boost::make_iterator_range( + boost::make_transform_iterator (range1.begin(), unary_function_1), + boost::make_transform_iterator (range1.end(), unary_function_1)); + + auto gr_point_range_2 = boost::make_iterator_range( + boost::make_transform_iterator (range2.begin(), unary_function_2), + boost::make_transform_iterator (range2.end(), unary_function_2)); + + // logger + GR::Utils::Logger logger(GR::Utils::NoLog); + + // matcher + MatcherType matcher(options, logger); + double score = + matcher.ComputeTransformation(gr_point_range_1, gr_point_range_2, mat, sampler, visitor); + +#ifdef CGAL_OPENGR_VERBOSE + std::cerr << "Transformation matrix: " << std::endl; + for (std::size_t i = 0; i < 4; ++ i) + { + for (std::size_t j = 0; j < 4; ++ j) + std::cerr << mat.coeff(i,j) << " "; + std::cerr << std::endl; + } +#endif + + typename Kernel::Aff_transformation_3 cgal_trsf( + mat.coeff(0,0), mat.coeff(0,1), mat.coeff(0,2), mat.coeff(0,3), + mat.coeff(1,0), mat.coeff(1,1), mat.coeff(1,2), mat.coeff(1,3), + mat.coeff(2,0), mat.coeff(2,1), mat.coeff(2,2), mat.coeff(2,3)); + + return std::make_pair(cgal_trsf, score); +} + +} // end of namespace internal + +/** + \ingroup PkgPointSetProcessing3Algorithms + + Computes the registration of `point_set_2` with respect to `point_set_1` and + returns the corresponding affine transformation along with the registration + score. + + Registration is computed using the Super4PCS algorithm \cgalCite{cgal:mam-sffgp-14}. + + \note This function requires the \ref thirdpartyOpenGR library. + + \warning Although this may seem counter-intuitive, if one of the + two point set matches only a small section of the other one, it is + advised to _use the small point set as reference_ instead of the + big one. The reason is that the reference point set is used to + construct a base that is sought after in the other point set: if + the big point set is used as reference, chances are the constructed + base will not be present in the small point set. + + \tparam PointRange1 is a model of `Range`. The value type of its iterator is + the key type of the named parameter `point_map` in `NamedParameters1`. + \tparam PointRange2 is a model of `Range`. The value type of its iterator is + the key type of the named parameter `point_map` in `NamedParameters2`. + + \param point_set_1 input point range used as reference. + \param point_set_2 input point range whose registration w.r.t. `point_set_1` will be computed. + \param np1 optional sequence of \ref psp_namedparameters "Named Parameters" among the ones listed below. + + \cgalNamedParamsBegin + \cgalParamBegin{point_map} a model of `ReadablePropertyMap` whose key type + is the value type of the iterator of `PointRange1` and whose value type is + `geom_traits::Point_3`. If this parameter is omitted, + `CGAL::Identity_property_map` is used.\cgalParamEnd + \cgalParamBegin{normal_map} a model of `ReadablePropertyMap` whose key + type is the value type of the iterator of `PointRange1` and whose value + type `geom_traits::Vector_3`.\cgalParamEnd + + \cgalParamBegin{number_of_samples} size of the subset of input points used + to compute registration. Input clouds are sub-sampled prior exploration, + to ensure fast computations. Super4PCS has a linear complexity w.r.t. the + number of input samples, allowing to use larger values than 4PCS. Simple + geometry with large overlap can be matched with only 200 samples. However, + with Super4PCS, smaller details can be used during the process by using up + to thousands of points. There is no theoretical limit to this parameter, + however using too large values leads to very a large congruent set, which + requires more time and memory to be explored. Using a large number of + samples is recommended when: geometrical details are required to perform + the matching, for instance to disambiguate between several similar + configurations; the clouds have a very low overlap: using a too sparse + sampling can prevent to have samples in the overlapping area, causing the + algorithm to fail; the clouds are very noisy, and require a dense + sampling. Note that Super4PCS is a global registration algorithm, which + finds a good approximate of the rigid transformation aligning too + clouds. Increasing the number of samples in order to get a fine + registration is not optimal: it is usually faster to use less samples, and + refine the transformation using a local algorithm, like the ICP, or its + variant SparseICP.\cgalParamEnd + + \cgalParamBegin{maximum_normal_deviation} angle threshold (in + degrees) used to filter pairs of points according to their normal + consistency. Small values decrease computation time but may also + decrease the quality if pairs of points that should match have + a normal deviation higher than the threshold.\cgalParamEnd + + \cgalParamBegin{accuracy} registration accuracy (delta in the + paper). Setting a small value means that the two clouds needs to be very + close to be considered as well aligned. It is expressed in scene units. A + simple way to understand its impact is to consider the computation of the + Largest Common Pointset (LCP), the metric used to verify how much the + clouds are aligned. For each transformation matrix produced by Super4PCS, + we compute the LCP measure by considering a shell around the reference + cloud, and count the percentage of points of the target cloud lying in the + shell. The thickness of the shell is defined by the parameter + delta.\cgalParamEnd + + \cgalParamBegin{overlap} ratio of expected overlap between the two point + sets: it is ranging between 0 (no overlap) to 1 (100% overlap). The + overlap parameter controls the size of the basis used for + registration. Usually, the larger the overlap, the faster the + algorithm. When the overlap is unknown, a simple way to set this parameter + is to start from 100% overlap, and decrease the value until obtaining a + good result. Using too small values will slow down the algorithm, and + reduce the accuracy of the result.\cgalParamEnd + + \cgalParamBegin{maximum_running_time} maximum number of seconds after + which the algorithm stops. Super4PCS explores the transformation space to + align the two input clouds. Since the exploration is performed randomly, + it is recommended to use a large time value to explore the whole space. + \cgalParamEnd + + \cgalParamBegin{geom_traits} an instance of a geometric traits class, + model of `Kernel`\cgalParamEnd + \cgalNamedParamsEnd + + \param np2 optional sequence of \ref psp_namedparameters "Named Parameters" among the ones listed below. + + \cgalNamedParamsBegin + \cgalParamBegin{point_map} a model of `ReadablePropertyMap` whose key type + is the value type of the iterator of `PointRange2` and whose value type is + `geom_traits::Point_3`. If this parameter is omitted, + `CGAL::Identity_property_map` is used.\cgalParamEnd + \cgalParamBegin{normal_map} a model of `ReadablePropertyMap` whose key + type is the value type of the iterator of `PointRange2` and whose value + type `geom_traits::Vector_3`.\cgalParamEnd + \cgalNamedParamsEnd + + \return a pair containing the affine transformation that should be applied + to `point_set_2` to make it registered w.r.t. `point_set_1` and the + registration score. +*/ +template +#ifdef DOXYGEN_RUNNING +std::pair +#else +std::pair + ::Kernel::Aff_transformation_3, double> +#endif +compute_registration_transformation (const PointRange1& point_set_1, const PointRange2& point_set_2, + const NamedParameters1& np1, const NamedParameters2& np2) +{ + namespace PSP = CGAL::Point_set_processing_3; + namespace GR = gr; + using parameters::choose_parameter; + using parameters::get_parameter; + + // property map types + typedef typename CGAL::GetPointMap::type PointMap1; + typedef typename CGAL::GetPointMap::type PointMap2; + CGAL_static_assertion_msg((boost::is_same< typename boost::property_traits::value_type, + typename boost::property_traits::value_type> ::value), + "The point type of input ranges must be the same"); + + typedef typename PSP::GetNormalMap::type NormalMap1; + typedef typename PSP::GetNormalMap::type NormalMap2; + CGAL_static_assertion_msg((boost::is_same< typename boost::property_traits::value_type, + typename boost::property_traits::value_type> ::value), + "The vector type of input ranges must be the same"); + + typedef typename PSP::GetK::Kernel Kernel; + + PointMap1 point_map1 = choose_parameter(get_parameter(np1, internal_np::point_map), PointMap1()); + NormalMap1 normal_map1 = choose_parameter(get_parameter(np1, internal_np::normal_map), NormalMap1()); + PointMap2 point_map2 = choose_parameter(get_parameter(np2, internal_np::point_map), PointMap2()); + NormalMap2 normal_map2 = choose_parameter(get_parameter(np2, internal_np::normal_map), NormalMap2()); + + Options options; + options.sample_size = choose_parameter(get_parameter(np1, internal_np::number_of_samples), 200); + options.delta = choose_parameter(get_parameter(np1, internal_np::accuracy), 5.00); + options.max_time_seconds = choose_parameter(get_parameter(np1, internal_np::maximum_running_time), 1000); + options.max_normal_difference = choose_parameter(get_parameter(np1, internal_np::maximum_normal_deviation), 90.); + + bool overlap_ok = options.configureOverlap (choose_parameter(get_parameter(np1, internal_np::overlap), 0.20)); + CGAL_USE (overlap_ok); + CGAL_assertion_msg (overlap_ok, "Invalid overlap configuration."); + + return internal::compute_registration_transformation(point_set_1, point_set_2, + point_map1, point_map2, + normal_map1, normal_map2, + options); + +} + +// convenience overloads +template +std::pair + ::Kernel::Aff_transformation_3, double> +compute_registration_transformation(const PointRange1& point_set_1, PointRange2& point_set_2, + const NamedParameters1& np1) +{ + namespace params = CGAL::Point_set_processing_3::parameters; + return compute_registration_transformation(point_set_1, point_set_2, np1, params::all_default(point_set_1)); +} + +template +std::pair > + ::Kernel::Aff_transformation_3, double> +compute_registration_transformation(const PointRange1& point_set_1, PointRange2& point_set_2) +{ + namespace params = CGAL::Point_set_processing_3::parameters; + return compute_registration_transformation(point_set_1, point_set_2, + params::all_default(point_set_1), + params::all_default(point_set_2)); +} + +} } // end of namespace CGAL::OpenGR + +#endif // CGAL_LINKED_WITH_OPENGR + +#endif // CGAL_OPENGR_COMPUTE_REGISTRATION_TRANSFORMATION_H diff --git a/Point_set_processing_3/include/CGAL/OpenGR/register_point_sets.h b/Point_set_processing_3/include/CGAL/OpenGR/register_point_sets.h new file mode 100644 index 00000000000..cfa8983296f --- /dev/null +++ b/Point_set_processing_3/include/CGAL/OpenGR/register_point_sets.h @@ -0,0 +1,247 @@ +// Copyright (c) 2019 GeometryFactory(France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Sebastien Loriot, Necip Fazil Yildiran + +#ifndef CGAL_OPENGR_REGISTER_POINT_SETS_H +#define CGAL_OPENGR_REGISTER_POINT_SETS_H + +#include + +#if defined(CGAL_LINKED_WITH_OPENGR) || defined(DOXYGEN_RUNNING) + +#include +#include +#include +#include + +#include + +#include + +#include + +namespace CGAL { + +namespace OpenGR { + +namespace internal { + +template +double +register_point_sets(const PointRange1& range1, PointRange2& range2, + PointMap1 point_map1, PointMap2 point_map2, + VectorMap1 vector_map1, VectorMap2 vector_map2, + Options& options) +{ + std::pair res = + compute_registration_transformation(range1, range2, + point_map1, point_map2, + vector_map1, vector_map2, + options); + + // update CGAL points + for (typename PointRange2::iterator it=range2.begin(), + end=range2.end(); it!=end; ++it) + { + put(point_map2, *it, get(point_map2, *it).transform(res.first)); + } + + return res.second; +} + +} // end of namespace internal + +/** + \ingroup PkgPointSetProcessing3Algorithms + + Computes the registration of `point_set_2` with respect to `point_set_1` and + applies it. + + Registration is computed using the Super4PCS algorithm + \cgalCite{cgal:mam-sffgp-14}. Parameters documentation is copy-pasted from [the official documentation of OpenGR](https://storm-irit.github.io/OpenGR/a00012.html). For more details on this method, please refer to it. + + \note This function requires the \ref thirdpartyOpenGR library. + + \warning Although this may seem counter-intuitive, if one of the two + point set matches only a small section of the other one, it is + advised to _use the small point set as reference_ instead of the + big one. The reason is that the reference point set is used to + construct a base that is sought after in the other point set: if + the big point set is used as reference, chances are the constructed + base will not be present in the small point set. + + \tparam PointRange1 is a model of `Range`. The value type of its iterator is + the key type of the named parameter `point_map` in `NamedParameters1`. + \tparam PointRange2 is a model of `Range`. The value type of its iterator is + the key type of the named parameter `point_map` in `NamedParameters2`. + + \param point_set_1 input point range used as reference. + \param point_set_2 input point range whose registration w.r.t. `point_set_1` will be computed. + \param np1 optional sequence of \ref psp_namedparameters "Named Parameters" among the ones listed below. + + \cgalNamedParamsBegin + \cgalParamBegin{point_map} a model of `ReadablePropertyMap` whose key type + is the value type of the iterator of `PointRange1` and whose value type is + `geom_traits::Point_3`. If this parameter is omitted, + `CGAL::Identity_property_map` is used.\cgalParamEnd + \cgalParamBegin{normal_map} a model of `ReadablePropertyMap` whose key + type is the value type of the iterator of `PointRange1` and whose value + type `geom_traits::Vector_3`.\cgalParamEnd + + \cgalParamBegin{number_of_samples} size of the subset of input points used + to compute registration. Input clouds are sub-sampled prior exploration, + to ensure fast computations. Super4PCS has a linear complexity w.r.t. the + number of input samples, allowing to use larger values than 4PCS. Simple + geometry with large overlap can be matched with only 200 samples. However, + with Super4PCS, smaller details can be used during the process by using up + to thousands of points. There is no theoretical limit to this parameter, + however using too large values leads to very a large congruent set, which + requires more time and memory to be explored. Using a large number of + samples is recommended when: geometrical details are required to perform + the matching, for instance to disambiguate between several similar + configurations; the clouds have a very low overlap: using a too sparse + sampling can prevent to have samples in the overlapping area, causing the + algorithm to fail; the clouds are very noisy, and require a dense + sampling. Note that Super4PCS is a global registration algorithm, which + finds a good approximate of the rigid transformation aligning too + clouds. Increasing the number of samples in order to get a fine + registration is not optimal: it is usually faster to use less samples, and + refine the transformation using a local algorithm, like the ICP, or its + variant SparseICP.\cgalParamEnd + + \cgalParamBegin{accuracy} registration accuracy (delta in the + paper). Setting a small value means that the two clouds needs to be very + close to be considered as well aligned. It is expressed in scene units. A + simple way to understand its impact is to consider the computation of the + Largest Common Pointset (LCP), the metric used to verify how much the + clouds are aligned. For each transformation matrix produced by Super4PCS, + we compute the LCP measure by considering a shell around the reference + cloud, and count the percentage of points of the target cloud lying in the + shell. The thickness of the shell is defined by the parameter + delta.\cgalParamEnd + + \cgalParamBegin{maximum_normal_deviation} angle threshold (in + degrees) used to filter pairs of points according to their normal + consistency. Small values decrease computation time but may also + decrease the quality if pairs of points that should match have + a normal deviation higher than the threshold.\cgalParamEnd + + \cgalParamBegin{overlap} ratio of expected overlap between the two point + sets: it is ranging between 0 (no overlap) to 1 (100% overlap). The + overlap parameter controls the size of the basis used for + registration. Usually, the larger the overlap, the faster the + algorithm. When the overlap is unknown, a simple way to set this parameter + is to start from 100% overlap, and decrease the value until obtaining a + good result. Using too small values will slow down the algorithm, and + reduce the accuracy of the result.\cgalParamEnd + + \cgalParamBegin{maximum_running_time} maximum number of seconds after + which the algorithm stops. Super4PCS explores the transformation space to + align the two input clouds. Since the exploration is performed randomly, + it is recommended to use a large time value to explore the whole space. + \cgalParamEnd + + \cgalParamBegin{geom_traits} an instance of a geometric traits class, + model of `Kernel`\cgalParamEnd + \cgalNamedParamsEnd + + \param np2 optional sequence of \ref psp_namedparameters "Named Parameters" among the ones listed below. + + \cgalNamedParamsBegin + \cgalParamBegin{point_map} a model of `ReadablePropertyMap` whose key type + is the value type of the iterator of `PointRange2` and whose value type is + `geom_traits::Point_3`. If this parameter is omitted, + `CGAL::Identity_property_map` is used.\cgalParamEnd + \cgalParamBegin{normal_map} a model of `ReadablePropertyMap` whose key + type is the value type of the iterator of `PointRange2` and whose value + type `geom_traits::Vector_3`.\cgalParamEnd + \cgalNamedParamsEnd + + \return the registration score. +*/ +template +double +register_point_sets (const PointRange1& point_set_1, PointRange2& point_set_2, + const NamedParameters1& np1, const NamedParameters2& np2) +{ + namespace PSP = CGAL::Point_set_processing_3; + namespace GR = gr; + using parameters::choose_parameter; + using parameters::get_parameter; + + // property map types + typedef typename CGAL::GetPointMap::type PointMap1; + typedef typename CGAL::GetPointMap::type PointMap2; + CGAL_static_assertion_msg((boost::is_same< typename boost::property_traits::value_type, + typename boost::property_traits::value_type> ::value), + "The point type of input ranges must be the same"); + + typedef typename PSP::GetNormalMap::type NormalMap1; + typedef typename PSP::GetNormalMap::type NormalMap2; + CGAL_static_assertion_msg((boost::is_same< typename boost::property_traits::value_type, + typename boost::property_traits::value_type> ::value), + "The vector type of input ranges must be the same"); + + typedef typename PSP::GetK::Kernel Kernel; + + PointMap1 point_map1 = choose_parameter(get_parameter(np1, internal_np::point_map), PointMap1()); + NormalMap1 normal_map1 = choose_parameter(get_parameter(np1, internal_np::normal_map), NormalMap1()); + PointMap1 point_map2 = choose_parameter(get_parameter(np2, internal_np::point_map), PointMap2()); + NormalMap2 normal_map2 = choose_parameter(get_parameter(np2, internal_np::normal_map), NormalMap2()); + + Options options; + options.sample_size = choose_parameter(get_parameter(np1, internal_np::number_of_samples), 200); + options.delta = choose_parameter(get_parameter(np1, internal_np::accuracy), 5.00); + options.max_time_seconds = choose_parameter(get_parameter(np1, internal_np::maximum_running_time), 1000); + options.max_normal_difference = choose_parameter(get_parameter(np1, internal_np::maximum_normal_deviation), 90.); + + bool overlap_ok = options.configureOverlap (choose_parameter(get_parameter(np1, internal_np::overlap), 0.20)); + CGAL_USE (overlap_ok); + CGAL_assertion_msg (overlap_ok, "Invalid overlap configuration."); + + return internal::register_point_sets(point_set_1, point_set_2, + point_map1, point_map2, + normal_map1, normal_map2, + options); +} + +// convenience overloads +template +double +register_point_sets(const PointRange1& point_set_1, PointRange2& point_set_2, + const NamedParameters1& np1) +{ + namespace params = CGAL::Point_set_processing_3::parameters; + return register_point_sets(point_set_1, point_set_2, np1, params::all_default(point_set_1)); +} + +template +double +register_point_sets(const PointRange1& point_set_1, PointRange2& point_set_2) +{ + namespace params = CGAL::Point_set_processing_3::parameters; + return register_point_sets(point_set_1, point_set_2, + params::all_default(point_set_1), + params::all_default(point_set_2)); +} + +} } // end of namespace CGAL::OpenGR + +#endif // CGAL_LINKED_WITH_OPENGR + +#endif // CGAL_OPENGR_REGISTER_POINT_SETS_H diff --git a/Point_set_processing_3/include/CGAL/bilateral_smooth_point_set.h b/Point_set_processing_3/include/CGAL/bilateral_smooth_point_set.h index e80d6a9be52..5767f93b949 100644 --- a/Point_set_processing_3/include/CGAL/bilateral_smooth_point_set.h +++ b/Point_set_processing_3/include/CGAL/bilateral_smooth_point_set.h @@ -16,6 +16,7 @@ #include +#include #include #include #include @@ -38,11 +39,12 @@ #include #ifdef CGAL_LINKED_WITH_TBB + #include #include #include #include -#include +#include #endif // CGAL_LINKED_WITH_TBB // Default allocator: use TBB allocators if available @@ -143,7 +145,7 @@ compute_denoise_projection( FT project_weight_sum = FT(0.0); Vector normal_sum = CGAL::NULL_VECTOR; - FT cos_sigma = cos(sharpness_angle / 180.0 * 3.1415926); + FT cos_sigma = cos(sharpness_angle * CGAL_PI / 180.0); FT sharpness_bandwidth = std::pow((CGAL::max)(1e-8, 1 - cos_sigma), 2); typename std::vector >::const_iterator @@ -349,9 +351,8 @@ public: \pre Normals must be unit vectors \pre k >= 2 - \tparam ConcurrencyTag enables sequential versus parallel algorithm. - Possible values are `Sequential_tag` - And `Parallel_tag`. + \tparam ConcurrencyTag enables sequential versus parallel algorithm. Possible values are `Sequential_tag`, + `Parallel_tag`, and `Parallel_if_available_tag`. \tparam PointRange is a model of `Range`. The value type of its iterator is the key type of the named parameter `point_map`. @@ -399,7 +400,7 @@ bilateral_smooth_point_set( using parameters::get_parameter; // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetNormalMap::type NormalMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; @@ -425,8 +426,8 @@ bilateral_smooth_point_set( typedef CGAL::Orthogonal_k_neighbor_search Neighbor_search; typedef typename Neighbor_search::Tree Tree; - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map), NormalMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map)); FT neighbor_radius = choose_parameter(get_parameter(np, internal_np::neighbor_radius), FT(0)); // copy points and normals diff --git a/Point_set_processing_3/include/CGAL/compute_average_spacing.h b/Point_set_processing_3/include/CGAL/compute_average_spacing.h index 01071c3b849..aaa05bbeb92 100644 --- a/Point_set_processing_3/include/CGAL/compute_average_spacing.h +++ b/Point_set_processing_3/include/CGAL/compute_average_spacing.h @@ -150,9 +150,8 @@ compute_average_spacing(const typename Kernel::Point_3& query, ///< 3D point who \pre `k >= 2.` - \tparam ConcurrencyTag enables sequential versus parallel algorithm. - Possible values are `Sequential_tag` - and `Parallel_tag`. + \tparam ConcurrencyTag enables sequential versus parallel algorithm. Possible values are `Sequential_tag`, + `Parallel_tag`, and `Parallel_if_available_tag`. \tparam PointRange is a model of `ConstRange`. The value type of its iterator is the key type of the named parameter `point_map`. @@ -196,15 +195,15 @@ compute_average_spacing( using parameters::get_parameter; // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::const_type PointMap; + typedef typename CGAL::GetPointMap::const_type PointMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; typedef typename Kernel::Point_3 Point; - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); const std::function& callback = choose_parameter(get_parameter(np, internal_np::callback), std::function()); - + // types for K nearest neighbors search structure typedef typename Kernel::FT FT; typedef Search_traits_3 Tree_traits; diff --git a/Point_set_processing_3/include/CGAL/edge_aware_upsample_point_set.h b/Point_set_processing_3/include/CGAL/edge_aware_upsample_point_set.h index 7097c2daf63..03906230d3b 100644 --- a/Point_set_processing_3/include/CGAL/edge_aware_upsample_point_set.h +++ b/Point_set_processing_3/include/CGAL/edge_aware_upsample_point_set.h @@ -280,8 +280,8 @@ update_new_point( Normals of points are required as input. For more details, please refer to \cgalCite{ear-2013}. \tparam ConcurrencyTag enables sequential versus parallel versions - of `compute_average_spacing()` (called internally). Possible - values are `Sequential_tag` and `Parallel_tag`. + of `compute_average_spacing()` (called internally). Possible + values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`. \tparam PointRange is a model of `ConstRange`. The value type of its iterator is the key type of the named parameter `point_map`. \tparam OutputIterator Type of the output iterator. @@ -323,7 +323,7 @@ edge_aware_upsample_point_set( using parameters::get_parameter; // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetNormalMap::type NormalMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; @@ -336,8 +336,8 @@ edge_aware_upsample_point_set( typedef typename Kernel::FT FT; typedef typename rich_grid_internal::Rich_point Rich_point; - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map), NormalMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map)); double sharpness_angle = choose_parameter(get_parameter(np, internal_np::sharpness_angle), 30.); double edge_sensitivity = choose_parameter(get_parameter(np, internal_np::edge_sensitivity), 1); double neighbor_radius = choose_parameter(get_parameter(np, internal_np::neighbor_radius), -1); diff --git a/Point_set_processing_3/include/CGAL/estimate_scale.h b/Point_set_processing_3/include/CGAL/estimate_scale.h index 5d6755afb71..0b58e29cba3 100644 --- a/Point_set_processing_3/include/CGAL/estimate_scale.h +++ b/Point_set_processing_3/include/CGAL/estimate_scale.h @@ -488,14 +488,14 @@ estimate_local_k_neighbor_scales( using parameters::choose_parameter; using parameters::get_parameter; - typedef typename Point_set_processing_3::GetPointMap::const_type PointMap; + typedef typename CGAL::GetPointMap::const_type PointMap; typedef typename Point_set_processing_3::GetQueryPointMap::const_type QueryPointMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; typedef typename boost::property_traits::value_type Point_d; - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - QueryPointMap query_point_map = choose_parameter(get_parameter(np, internal_np::query_point_map), QueryPointMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + QueryPointMap query_point_map = choose_parameter(get_parameter(np, internal_np::query_point_map)); // Build multi-scale KD-tree internal::Quick_multiscale_approximate_knn_distance kdtree (points.begin(), @@ -566,8 +566,8 @@ estimate_global_k_neighbor_scale( using parameters::choose_parameter; using parameters::get_parameter; - typedef typename Point_set_processing_3::GetPointMap::const_type PointMap; - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); + typedef typename CGAL::GetPointMap::const_type PointMap; + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); std::vector scales; estimate_local_k_neighbor_scales (points, points, std::back_inserter (scales), np.query_point_map(point_map)); std::sort (scales.begin(), scales.end()); @@ -641,14 +641,14 @@ estimate_local_range_scales( using parameters::choose_parameter; using parameters::get_parameter; - typedef typename Point_set_processing_3::GetPointMap::const_type PointMap; + typedef typename CGAL::GetPointMap::const_type PointMap; typedef typename Point_set_processing_3::GetQueryPointMap::const_type QueryPointMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; typedef typename boost::property_traits::value_type Point_d; - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - QueryPointMap query_point_map = choose_parameter(get_parameter(np, internal_np::query_point_map), QueryPointMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + QueryPointMap query_point_map = choose_parameter(get_parameter(np, internal_np::query_point_map)); // Build multi-scale KD-tree internal::Quick_multiscale_approximate_knn_distance kdtree (points.begin(), @@ -727,8 +727,8 @@ estimate_global_range_scale( using parameters::get_parameter; std::vector scales; - typedef typename Point_set_processing_3::GetPointMap::const_type PointMap; - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); + typedef typename CGAL::GetPointMap::const_type PointMap; + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); estimate_local_range_scales (points, points, std::back_inserter (scales), np.query_point_map(point_map)); std::sort (scales.begin(), scales.end()); return std::sqrt (scales[scales.size() / 2]); diff --git a/Point_set_processing_3/include/CGAL/grid_simplify_point_set.h b/Point_set_processing_3/include/CGAL/grid_simplify_point_set.h index 4720479cba7..0efe2775256 100644 --- a/Point_set_processing_3/include/CGAL/grid_simplify_point_set.h +++ b/Point_set_processing_3/include/CGAL/grid_simplify_point_set.h @@ -202,8 +202,8 @@ grid_simplify_point_set( using parameters::choose_parameter; using parameters::get_parameter; - typedef typename Point_set_processing_3::GetPointMap::const_type PointMap; - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); + typedef typename CGAL::GetPointMap::const_type PointMap; + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); const std::function& callback = choose_parameter(get_parameter(np, internal_np::callback), std::function()); diff --git a/Point_set_processing_3/include/CGAL/hierarchy_simplify_point_set.h b/Point_set_processing_3/include/CGAL/hierarchy_simplify_point_set.h index 00ef55a1f32..c0b3c2f1610 100644 --- a/Point_set_processing_3/include/CGAL/hierarchy_simplify_point_set.h +++ b/Point_set_processing_3/include/CGAL/hierarchy_simplify_point_set.h @@ -156,7 +156,7 @@ namespace CGAL { using parameters::get_parameter; // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; typedef typename GetDiagonalizeTraits::type DiagonalizeTraits; @@ -164,7 +164,7 @@ namespace CGAL { typedef typename Kernel::Vector_3 Vector; typedef typename Kernel::FT FT; - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); unsigned int size = choose_parameter(get_parameter(np, internal_np::size), 10); double var_max = choose_parameter(get_parameter(np, internal_np::maximum_variation), 1./3.); const std::function& callback = choose_parameter(get_parameter(np, internal_np::callback), diff --git a/Point_set_processing_3/include/CGAL/jet_estimate_normals.h b/Point_set_processing_3/include/CGAL/jet_estimate_normals.h index 746710d9240..20092e838c3 100644 --- a/Point_set_processing_3/include/CGAL/jet_estimate_normals.h +++ b/Point_set_processing_3/include/CGAL/jet_estimate_normals.h @@ -152,9 +152,8 @@ jet_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute \pre `k >= 2` - \tparam ConcurrencyTag enables sequential versus parallel algorithm. - Possible values are `Sequential_tag` - and `Parallel_tag`. + \tparam ConcurrencyTag enables sequential versus parallel algorithm. Possible values are `Sequential_tag`, + `Parallel_tag`, and `Parallel_if_available_tag`. \tparam PointRange is a model of `Range`. The value type of its iterator is the key type of the named parameter `point_map`. @@ -203,7 +202,7 @@ jet_estimate_normals( CGAL_TRACE("Calls jet_estimate_normals()\n"); // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetNormalMap::type NormalMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; typedef typename Kernel::FT FT; @@ -216,8 +215,8 @@ jet_estimate_normals( typename GetSvdTraits::NoTraits>::value), "Error: no SVD traits"); - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map), NormalMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map)); unsigned int degree_fitting = choose_parameter(get_parameter(np, internal_np::degree_fitting), 2); FT neighbor_radius = choose_parameter(get_parameter(np, internal_np::neighbor_radius), FT(0)); diff --git a/Point_set_processing_3/include/CGAL/jet_smooth_point_set.h b/Point_set_processing_3/include/CGAL/jet_smooth_point_set.h index fbe89bcd072..316fe9f8a90 100644 --- a/Point_set_processing_3/include/CGAL/jet_smooth_point_set.h +++ b/Point_set_processing_3/include/CGAL/jet_smooth_point_set.h @@ -156,9 +156,8 @@ jet_smooth_point( \pre `k >= 2` - \tparam ConcurrencyTag enables sequential versus parallel algorithm. - Possible values are `Sequential_tag` - and `Parallel_tag`. + \tparam ConcurrencyTag enables sequential versus parallel algorithm. Possible values are `Sequential_tag`, + `Parallel_tag`, and `Parallel_if_available_tag`. \tparam PointRange is a model of `Range`. The value type of its iterator is the key type of the named parameter `point_map`. @@ -205,7 +204,7 @@ jet_smooth_point_set( using parameters::get_parameter; // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; typedef typename GetSvdTraits::type SvdTraits; @@ -213,7 +212,7 @@ jet_smooth_point_set( typename GetSvdTraits::NoTraits>::value), "Error: no SVD traits"); - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); typename Kernel::FT neighbor_radius = choose_parameter(get_parameter(np, internal_np::neighbor_radius), typename Kernel::FT(0)); unsigned int degree_fitting = choose_parameter(get_parameter(np, internal_np::degree_fitting), 2); diff --git a/Point_set_processing_3/include/CGAL/mst_orient_normals.h b/Point_set_processing_3/include/CGAL/mst_orient_normals.h index b8c7030498b..7339317d4e8 100644 --- a/Point_set_processing_3/include/CGAL/mst_orient_normals.h +++ b/Point_set_processing_3/include/CGAL/mst_orient_normals.h @@ -610,7 +610,7 @@ mst_orient_normals( CGAL_TRACE("Calls mst_orient_normals()\n"); - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetNormalMap::type NormalMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; typedef typename Point_set_processing_3::GetIsConstrainedMap::type ConstrainedMap; @@ -619,11 +619,11 @@ mst_orient_normals( typename Point_set_processing_3::GetNormalMap::NoMap>::value), "Error: no normal map"); - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map), NormalMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map)); typename Kernel::FT neighbor_radius = choose_parameter(get_parameter(np, internal_np::neighbor_radius), - typename Kernel::FT(0)); - ConstrainedMap constrained_map = choose_parameter(get_parameter(np, internal_np::point_is_constrained), ConstrainedMap()); + typename Kernel::FT(0)); + ConstrainedMap constrained_map = choose_parameter(get_parameter(np, internal_np::point_is_constrained)); Kernel kernel; // Bring private stuff to scope diff --git a/Point_set_processing_3/include/CGAL/pca_estimate_normals.h b/Point_set_processing_3/include/CGAL/pca_estimate_normals.h index 6d1fb05eca7..3a8b28bfe35 100644 --- a/Point_set_processing_3/include/CGAL/pca_estimate_normals.h +++ b/Point_set_processing_3/include/CGAL/pca_estimate_normals.h @@ -142,9 +142,8 @@ pca_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute \pre `k >= 2` - \tparam ConcurrencyTag enables sequential versus parallel algorithm. - Possible values are `Sequential_tag` - and `Parallel_tag`. + \tparam ConcurrencyTag enables sequential versus parallel algorithm. Possible values are `Sequential_tag`, + `Parallel_tag`, and `Parallel_if_available_tag`. \tparam PointRange is a model of `Range`. The value type of its iterator is the key type of the named parameter `point_map`. @@ -192,7 +191,7 @@ pca_estimate_normals( CGAL_TRACE("Calls pca_estimate_normals()\n"); // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetNormalMap::type NormalMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; typedef typename Kernel::FT FT; @@ -201,8 +200,8 @@ pca_estimate_normals( typename Point_set_processing_3::GetNormalMap::NoMap>::value), "Error: no normal map"); - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map), NormalMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map)); FT neighbor_radius = choose_parameter(get_parameter(np, internal_np::neighbor_radius), FT(0)); const std::function& callback = choose_parameter(get_parameter(np, internal_np::callback), std::function()); diff --git a/Point_set_processing_3/include/CGAL/pointmatcher/compute_registration_transformation.h b/Point_set_processing_3/include/CGAL/pointmatcher/compute_registration_transformation.h new file mode 100644 index 00000000000..93f9aac39f6 --- /dev/null +++ b/Point_set_processing_3/include/CGAL/pointmatcher/compute_registration_transformation.h @@ -0,0 +1,627 @@ +// Copyright (c) 2019 GeometryFactory(France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Necip Fazil Yildiran + +#ifndef CGAL_POINTMATCHER_COMPUTE_REGISTRATION_TRANSFORMATION_H +#define CGAL_POINTMATCHER_COMPUTE_REGISTRATION_TRANSFORMATION_H + +#include + +#if defined(CGAL_LINKED_WITH_POINTMATCHER) || defined(DOXYGEN_RUNNING) + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +namespace CGAL { + +namespace pointmatcher { + +template +using ICP = typename PointMatcher::ICP; + +/*! + \ingroup PkgPointSetProcessing3Algorithms + + \brief The class `ICP_config` is designed to handle preparing and passing configurations + to the registration methods `CGAL::pointmatcher::compute_registration_transformation()` + and `CGAL::pointmatcher::register_point_sets()`. + + \details A configuration corresponds to a component of a configuration module + of \ref thirdpartylibpointmatcher library. The name and the parameters of any + configuration for the corresponding registration methods are directly passed + to \ref thirdpartylibpointmatcher library to be parsed and registered at the + \ref thirdpartylibpointmatcher side. + */ +struct ICP_config { + /// The name of the configuration component + std::string name; + + /// The set of (parameter name, parameter value) pairs as a map + std::map params; +}; + +namespace internal { + +void dump_invalid_point_matcher_config_exception_msg(const PointMatcherSupport::InvalidElement& err) { + std::cerr << "ERROR Invalid configuration for PM::ICP, omitting configuration: " << std::endl; + std::cerr << " " << err.what() << std::endl; +} + +template +ICP +construct_icp(const NamedParameters1& np1, const NamedParameters2& np2) +{ + typedef PointMatcher PM; + + using parameters::choose_parameter; + using parameters::get_parameter; + + ICP icp; + + icp.setDefault(); + + const ICP_config null_config { "_null_pm_config_in_cgal" }; + const std::vector null_config_chain { null_config }; + auto is_null_config = [&](const ICP_config& c) { return !c.name.compare(null_config.name); }; + + // Config file + std::istream* pointmatcher_config = choose_parameter(get_parameter(np1, internal_np::pointmatcher_config), nullptr); + if(pointmatcher_config != nullptr) + { + icp.loadFromYaml(*pointmatcher_config); + return icp; + } + + // In CGAL, point_set_1 is the reference while point_set_2 is the data + // However, in pointmatcher, the order is reverse: point_set_1 is the data while point_set_2 is the reference + // Therefore, filter params from np1 applies to reference data points while params from np2 applies to reading data points + + // np1.point_set_filters -> PM::ReferenceDataPointsFilter + auto reference_data_points_filter_configs = choose_parameter(get_parameter(np1, internal_np::point_set_filters), null_config_chain); + if(!reference_data_points_filter_configs.empty() && is_null_config(*reference_data_points_filter_configs.cbegin())) { + // No config provided: use default values as been set above, do nothing + ; + } else { + // Some config chain is given: clear default values and use the provided configs + icp.referenceDataPointsFilters.clear(); + + for(const auto& conf : reference_data_points_filter_configs) + { + try { + icp.referenceDataPointsFilters.push_back( PM::get().DataPointsFilterRegistrar.create(conf.name, conf.params) ); + } catch(typename PointMatcherSupport::InvalidElement& error) { + dump_invalid_point_matcher_config_exception_msg(error); + } + } + } + // np2.point_set_filters -> PM::ReadingDataPointsFilters + auto reading_data_points_filter_configs = choose_parameter(get_parameter(np2, internal_np::point_set_filters), null_config_chain); + if(!reading_data_points_filter_configs.empty() && is_null_config(*reading_data_points_filter_configs.cbegin())) { + // No config provided: use default values as been set above, do nothing + ; + } else { + // Some config chain is given: clear default values and use the provided configs + icp.readingDataPointsFilters.clear(); + + for(const auto& conf : reading_data_points_filter_configs) + { + try { + icp.readingDataPointsFilters.push_back( PM::get().DataPointsFilterRegistrar.create(conf.name, conf.params) ); + } catch(typename PointMatcherSupport::InvalidElement& error) { + dump_invalid_point_matcher_config_exception_msg(error); + } + } + } + + // Matcher + auto matcher_config = choose_parameter(get_parameter(np1, internal_np::matcher), null_config); + if(!is_null_config(matcher_config)) + { + try { + icp.matcher = PM::get().MatcherRegistrar.create(matcher_config.name, matcher_config.params); + } catch(typename PointMatcherSupport::InvalidElement& error) { + dump_invalid_point_matcher_config_exception_msg(error); + } + } + + // Outlier Filters + auto outlier_filters_config = choose_parameter(get_parameter(np1, internal_np::outlier_filters), null_config_chain); + if(!outlier_filters_config.empty() && is_null_config(*outlier_filters_config.cbegin())) { + // No config provided: use default values as been set above, do nothing + ; + } else { + // Some config chain is given: clear default values and use the provided configs + icp.outlierFilters.clear(); + + for(const auto& conf : outlier_filters_config) + { + try { + icp.outlierFilters.push_back( PM::get().OutlierFilterRegistrar.create(conf.name, conf.params) ); + } catch(typename PointMatcherSupport::InvalidElement& error) { + dump_invalid_point_matcher_config_exception_msg(error); + } + } + } + + // Error Minimizer + auto error_minimizer_config = choose_parameter(get_parameter(np1, internal_np::error_minimizer), null_config); + if(!is_null_config(error_minimizer_config)) + { + try { + icp.errorMinimizer = PM::get().ErrorMinimizerRegistrar.create(error_minimizer_config.name, error_minimizer_config.params); + } catch(typename PointMatcherSupport::InvalidElement& error) { + dump_invalid_point_matcher_config_exception_msg(error); + } + } + + // Transformation Checkers + auto transformation_checkers_config = choose_parameter(get_parameter(np1, internal_np::transformation_checkers), null_config_chain); + if(!transformation_checkers_config.empty() && is_null_config(*transformation_checkers_config.cbegin())) { + // No config provided: use default values as been set above, do nothing + ; + } else { + // Some config chain is given: clear default values and use the provided configs + icp.transformationCheckers.clear(); + + for(const auto& conf : transformation_checkers_config) + { + try { + icp.transformationCheckers.push_back( PM::get().TransformationCheckerRegistrar.create(conf.name, conf.params) ); + } catch(typename PointMatcherSupport::InvalidElement& error) { + dump_invalid_point_matcher_config_exception_msg(error); + } + } + } + + // Inspector + auto inspector_config = choose_parameter(get_parameter(np1, internal_np::inspector), null_config); + if(!is_null_config(error_minimizer_config)) + { + try { + icp.inspector = PM::get().InspectorRegistrar.create(inspector_config.name, inspector_config.params); + } catch(typename PointMatcherSupport::InvalidElement& error) { + dump_invalid_point_matcher_config_exception_msg(error); + } + } + + // Logger + auto logger_config = choose_parameter(get_parameter(np1, internal_np::logger), null_config); + if(!is_null_config(logger_config)) + { + try { + PointMatcherSupport::setLogger( PM::get().LoggerRegistrar.create(logger_config.name, logger_config.params) ); + } catch(typename PointMatcherSupport::InvalidElement& error) { + dump_invalid_point_matcher_config_exception_msg(error); + } + } + + return icp; +} + +template +void +copy_cgal_points_to_pm_matrix +(const PointRange& prange, PointMap point_map, VectorMap vector_map, PM_matrix& pm_points, PM_matrix& pm_normals) +{ + int idx = 0; + for(const auto& p : prange) + { + // position + const auto& pos = get(point_map, p); + pm_points(0, idx) = pos.x(); + pm_points(1, idx) = pos.y(); + pm_points(2, idx) = pos.z(); + pm_points(3, idx) = Scalar(1.); + + // normal + const auto& normal = get (vector_map, p); + pm_normals(0, idx) = normal.x(); + pm_normals(1, idx) = normal.y(); + pm_normals(2, idx) = normal.z(); + + ++idx; + } +} + +template +std::pair +compute_registration_transformation(const PointRange1& range1, const PointRange2& range2, + PointMap1 point_map1, PointMap2 point_map2, + VectorMap1 vector_map1, VectorMap2 vector_map2, + const typename Kernel::Aff_transformation_3& initial_transform, + ICP icp) +{ + using Scalar = typename Kernel::FT; + + using PM = PointMatcher; + using PM_cloud = typename PM::DataPoints; + using PM_matrix = typename PM::Matrix; + using PM_transform = typename PM::Transformation; + using PM_transform_params = typename PM::TransformationParameters; + + // ref_points: 1, points: 2 + std::size_t nb_ref_points = range1.size(); + std::size_t nb_points = range2.size(); + + PM_matrix ref_points_pos_matrix = PM_matrix (4, nb_ref_points); + PM_matrix ref_points_normal_matrix = PM_matrix (3, nb_ref_points); + PM_matrix points_pos_matrix = PM_matrix (4, nb_points); + PM_matrix points_normal_matrix = PM_matrix (3, nb_points); + + // In CGAL, point_set_1 is the reference while point_set_2 is the data + + // convert cgal points to pointmatcher points + internal::copy_cgal_points_to_pm_matrix(range1, + point_map1, + vector_map1, + ref_points_pos_matrix, // out + ref_points_normal_matrix); // out + + internal::copy_cgal_points_to_pm_matrix(range2, + point_map2, + vector_map2, + points_pos_matrix, // out + points_normal_matrix); // out + + auto construct_PM_cloud = [](const PM_matrix& positions, const PM_matrix& normals) -> PM_cloud + { + PM_cloud cloud; + + cloud.addFeature("x", positions.row(0)); + cloud.addFeature("y", positions.row(1)); + cloud.addFeature("z", positions.row(2)); + cloud.addFeature("pad", positions.row(3)); + cloud.addDescriptor("normals", normals); + + return cloud; + }; + + PM_cloud ref_cloud = construct_PM_cloud(ref_points_pos_matrix, ref_points_normal_matrix); + PM_cloud cloud = construct_PM_cloud(points_pos_matrix, points_normal_matrix); + + PM_transform_params pm_transform_params = PM_transform_params::Identity(4,4); + + // Convert CGAL transform to pm transform + for(int i = 0; i < 4; i++) + for(int j = 0; j < 4; j++) + pm_transform_params(i,j) = initial_transform.m(i,j); + + bool converged = false; + try + { + const PM_transform_params prior = pm_transform_params; + pm_transform_params = icp(cloud, ref_cloud, prior); + converged = true; + } + catch (typename PM::ConvergenceError& error) + { + std::cerr << "ERROR CGAL::pointmatcher registration (PM::ICP) failed to converge: " << std::endl; + std::cerr << " " << error.what() << std::endl; + converged = false; + } + + // Rigid transformation + std::shared_ptr transform = PM::get().REG(Transformation).create("RigidTransformation"); + pm_transform_params = transform->correctParameters(pm_transform_params); + + typename Kernel::Aff_transformation_3 cgal_transform + (pm_transform_params(0,0), pm_transform_params(0,1), pm_transform_params(0,2), pm_transform_params(0,3), + pm_transform_params(1,0), pm_transform_params(1,1), pm_transform_params(1,2), pm_transform_params(1,3), + pm_transform_params(2,0), pm_transform_params(2,1), pm_transform_params(2,2), pm_transform_params(2,3)); + +#ifdef CGAL_POINTMATCHER_VERBOSE + std::cerr << "Transformation matrix: " << std::endl; + for (std::size_t i = 0; i < 4; ++ i) + { + for (std::size_t j = 0; j < 4; ++ j) + std::cerr << cgal_transform.coeff(i,j) << " "; + std::cerr << std::endl; + } +#endif + + return std::make_pair(cgal_transform, converged); +} + +} // end of namespace internal + +// point_set_1 is reference while point_set_2 is data +/** + \ingroup PkgPointSetProcessing3Algorithms + + Computes the registration of `point_set_2` with respect to `point_set_1` and + returns the corresponding affine transformation. + Registration is computed using the Iterative Closest Point (ICP) algorithm. + \note This function requires the \ref thirdpartylibpointmatcher library. + \tparam PointRange1 is a model of `Range`. The value type of its iterator is + the key type of the named parameter `point_map` in `NamedParameters1`. + \tparam PointRange2 is a model of `Range`. The value type of its iterator is + the key type of the named parameter `point_map` in `NamedParameters2`. + \param point_set_1 input point range used as reference. + \param point_set_2 input point range whose registration w.r.t. `point_set_1` will be computed. + \param np1 optional sequence of \ref psp_namedparameters "Named Parameters" among the ones listed below. + \cgalNamedParamsBegin + \cgalParamBegin{point_map} a model of `ReadablePropertyMap` whose key type + is the value type of the iterator of `PointRange1` and whose value type is + `geom_traits::Point_3`. If this parameter is omitted, + `CGAL::Identity_property_map` is used.\cgalParamEnd + \cgalParamBegin{normal_map} a model of `ReadablePropertyMap` whose key + type is the value type of the iterator of `PointRange1` and whose value + type `geom_traits::Vector_3`.\cgalParamEnd + + \cgalParamBegin{point_set_filters} is a model of `Range`. The value type of + its iterator is `ICP_config`. + + The chain of filters to be applied to the reference point cloud. The reference + point cloud is processed into an intermediate point cloud with the given chain + of filters to be used in the alignment procedure. The chain is organized with + the forward traversal order of the point set filters range. + + The chain of point set filters are applied only once at the beginning of the + ICP procedure, i.e., before the first iteration of the ICP algorithm. + + The filters can have several purposes, including but are not limited to + i) removal of noisy points which render alignment of point clouds difficult, + ii) removal of redundant points so as to speed up alignment, iii) addition + of descriptive information to the points such as a surface normal vector, + or the direction from the point to the sensor. + + Corresponds to `referenceDataPointsFilters` configuration module of \ref thirdpartylibpointmatcher + library. The filters should be chosen and set from possible components of + the `referenceDataPointsFilters` configuration module. + See libpointmatcher documentation + for possible configurations. + + If this parameter is omitted, `RandomSamplingDataPointsFilter` is used. + \cgalParamEnd + + \cgalParamBegin{matcher} is a model of `ICP_config`. + The method used for matching (linking) the points from `point_set_2`, to the + points in the reference cloud, `point_set_1`. + + Corresponds to `matcher` configuration module of \ref thirdpartylibpointmatcher + library. The matcher should be chosen and set from possible components of + the `matcher` configuration module. + See libpointmatcher documentation + for possible configurations. + + If this parameter is omitted, `KDTreeMatcher` is used. + \cgalParamEnd + + + \cgalParamBegin{outlier_filters} is a model of `Range`. The value type of + its iterator is `ICP_config`. + The chain of filters to be applied to the matched (linked) point clouds after + each processing iteration of the ICP algorithm to remove the links which do not + correspond to true point correspondences. The outliers are rejected. Points + with no link are ignored in the subsequent error minimization step. + The chain is organized with the forward traversal order of the outlier filters + range. + + Corresponds to `outlierFilters` configuration module of \ref thirdpartylibpointmatcher + library. The filters should be chosen and set from possible components of + the `outlierFilters` configuration module. + See libpointmatcher documentation + for possible configurations. + + If this parameter is omitted, `TrimmedDistOutlierFilter` is used. + \cgalParamEnd + + \cgalParamBegin{error_minimizer} is a model of `ICP_config`. + The error minimizer that computes a transformation matrix such as to minimize + the error between the point sets. + + Corresponds to `errorMinimizer` configuration module of \ref thirdpartylibpointmatcher + library. The error minimizer should be chosen and set from possible components of + the `errorMinimizer` configuration module. + See libpointmatcher documentation + for possible configurations. + + If this parameter is omitted, `PointToPlaneErrorMinimizer` is used. + \cgalParamEnd + + \cgalParamBegin{transformation_checkers} is a model of `Range`. The value type of + its iterator is `ICP_config`. + The chain of transformation checkers. A transformation checker can stop the + iteration depending on the conditions it defines. + + The chain is organized with the forward traversal order of the transformation + checkers range. + + Corresponds to `transformationCheckers` configuration module of \ref thirdpartylibpointmatcher + library. The transformation checkers should be chosen and set from possible components of + the `transformationCheckers` configuration module. + See libpointmatcher documentation + for possible configurations. + + If this parameter is omitted, the chain of `CounterTransformationChecker` and + `DifferentialTransformationChecker` is used. + \cgalParamEnd + + \cgalParamBegin{inspector} is a model of `ICP_config`. + The inspector allows to log data at different steps for analysis. Inspectors + typically provide deeper scrutiny than the logger. + + Corresponds to `inspector` configuration module of \ref thirdpartylibpointmatcher + library. The inspector should be chosen and set from possible components of + the `inspector` configuration module. + See libpointmatcher documentation + for possible configurations. + + If this parameter is omitted, `NullInspector` is used. + \cgalParamEnd + + \cgalParamBegin{logger} is a model of `ICP_config`. + The method for logging information regarding the registration process outputted + by \ref thirdpartylibpointmatcher library. The logs generated by CGAL library + does not get effected by this configuration. + + Corresponds to `logger` configuration module of \ref thirdpartylibpointmatcher + library. The logger should be chosen and set from possible components of + the `logger` configuration module. + See libpointmatcher documentation + for possible configurations. + + If this parameter is omitted, `NullLogger` is used. + \cgalParamEnd + + \cgalParamBegin{geom_traits} an instance of a geometric traits class, + model of `Kernel`\cgalParamEnd + + \cgalNamedParamsEnd + + \param np2 optional sequence of \ref psp_namedparameters "Named Parameters" among the ones listed below. + \cgalNamedParamsBegin + \cgalParamBegin{point_map} a model of `ReadablePropertyMap` whose key type + is the value type of the iterator of `PointRange2` and whose value type is + `geom_traits::Point_3`. If this parameter is omitted, + `CGAL::Identity_property_map` is used.\cgalParamEnd + \cgalParamBegin{normal_map} a model of `ReadablePropertyMap` whose key + type is the value type of the iterator of `PointRange2` and whose value + type `geom_traits::Vector_3`.\cgalParamEnd + + \cgalParamBegin{point_set_filters} is a model of `Range`. The value type of + its iterator is `ICP_config`. + + The chain of filters to be applied to the point cloud, `point_set_2`. The + point cloud is processed into an intermediate point cloud with the given chain + of filters to be used in the alignment procedure. The chain is organized with + the forward traversal order of the point set filters range. + + The chain of point set filters are applied only once at the beginning of the + ICP procedure, i.e., before the first iteration of ICP algorithm. + + The filters can have several purposes, including but are not limited to + i) removal of noisy points which render alignment of point clouds difficult, + ii) removal of redundant points so as to speed up alignment, iii) addition + of descriptive information to the points such as a surface normal vector, + or the direction from the point to the sensor. + + Corresponds to `readingDataPointsFilters` configuration module of \ref thirdpartylibpointmatcher + library. The filters should be chosen and set from possible components of + the `readingDataPointsFilters` configuration module. + See libpointmatcher documentation + for possible configurations. + + If this parameter is omitted, `SamplingSurfaceNormalDataPointsFilter` is used. + \cgalParamEnd + + \cgalParamBegin{transformation} The affine transformation that is used as the + initial transformation for `point_set_2`. + + If this parameter is omitted, identity transformation is used. + \cgalParamEnd + + \cgalNamedParamsEnd + \return a pair containing the affine transformation that should be applied + to `point_set_2` to make it registered w.r.t. `point_set_1` and the + boolean value indicating if the registration converged. The second + of the pair is `true` if converged, `false` otherwise. A log why it failed to + converge is written to `std::cerr` if the registration cannot converge. +*/ +template +#ifdef DOXYGEN_RUNNING +std::pair +#else +std::pair + ::Kernel::Aff_transformation_3, bool> +#endif +compute_registration_transformation (const PointRange1& point_set_1, const PointRange2& point_set_2, + const NamedParameters1& np1, const NamedParameters2& np2) +{ + using parameters::choose_parameter; + using parameters::get_parameter; + + namespace PSP = CGAL::Point_set_processing_3; + + // property map types + typedef typename CGAL::GetPointMap::type PointMap1; + typedef typename CGAL::GetPointMap::type PointMap2; + CGAL_static_assertion_msg((boost::is_same< typename boost::property_traits::value_type, + typename boost::property_traits::value_type> ::value), + "The point type of input ranges must be the same"); + + typedef typename PSP::GetNormalMap::type NormalMap1; + typedef typename PSP::GetNormalMap::type NormalMap2; + CGAL_static_assertion_msg((boost::is_same< typename boost::property_traits::value_type, + typename boost::property_traits::value_type> ::value), + "The vector type of input ranges must be the same"); + + typedef typename PSP::GetK::Kernel Kernel; + typedef typename Kernel::FT Scalar; + typedef typename Kernel::Aff_transformation_3 Transformation; + + PointMap1 point_map1 = choose_parameter(get_parameter(np1, internal_np::point_map), PointMap1()); + NormalMap1 normal_map1 = choose_parameter(get_parameter(np1, internal_np::normal_map), NormalMap1()); + PointMap2 point_map2 = choose_parameter(get_parameter(np2, internal_np::point_map), PointMap2()); + NormalMap2 normal_map2 = choose_parameter(get_parameter(np2, internal_np::normal_map), NormalMap2()); + + // initial transformation + Transformation initial_transformation + = choose_parameter(get_parameter(np2, internal_np::transformation), Transformation(Identity_transformation())); + + return internal::compute_registration_transformation(point_set_1, point_set_2, + point_map1, point_map2, + normal_map1, normal_map2, + initial_transformation, + internal::construct_icp(np1, np2)); +} + +// convenience overloads +template +std::pair + ::Kernel::Aff_transformation_3, bool> +compute_registration_transformation(const PointRange1& point_set_1, const PointRange2& point_set_2, + const NamedParameters1& np1) +{ + namespace params = CGAL::Point_set_processing_3::parameters; + return compute_registration_transformation(point_set_1, point_set_2, np1, params::all_default(point_set_1)); +} + +template +std::pair > + ::Kernel::Aff_transformation_3, bool> +compute_registration_transformation(const PointRange1& point_set_1, const PointRange2& point_set_2) +{ + namespace params = CGAL::Point_set_processing_3::parameters; + return compute_registration_transformation(point_set_1, point_set_2, + params::all_default(point_set_1), + params::all_default(point_set_2)); +} + + +} } // end of namespace CGAL::pointmatcher + +#endif // CGAL_LINKED_WITH_POINTMATCHER + +#endif // CGAL_POINTMATCHER_COMPUTE_REGISTRATION_TRANSFORMATION_H diff --git a/Point_set_processing_3/include/CGAL/pointmatcher/register_point_sets.h b/Point_set_processing_3/include/CGAL/pointmatcher/register_point_sets.h new file mode 100644 index 00000000000..0110b968b4a --- /dev/null +++ b/Point_set_processing_3/include/CGAL/pointmatcher/register_point_sets.h @@ -0,0 +1,283 @@ +// Copyright (c) 2019 GeometryFactory(France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Necip Fazil Yildiran + +#ifndef CGAL_POINTMATCHER_REGISTER_POINT_SETS_H +#define CGAL_POINTMATCHER_REGISTER_POINT_SETS_H + +#include + +#if defined(CGAL_LINKED_WITH_POINTMATCHER) || defined(DOXYGEN_RUNNING) + +#include +#include +#include +#include + +#include + +#include + +#include + +namespace CGAL { + +namespace pointmatcher { + +// point_set_1 is reference while point_set_2 is data +/** + \ingroup PkgPointSetProcessing3Algorithms + + Computes the registration of `point_set_2` with respect to `point_set_1` and + applies it. + + Registration is computed using the Iterative Closest Point (ICP) algorithm. + + \note This function requires the \ref thirdpartylibpointmatcher library. + + \tparam PointRange1 is a model of `Range`. The value type of its iterator is + the key type of the named parameter `point_map` in `NamedParameters1`. + \tparam PointRange2 is a model of `Range`. The value type of its iterator is + the key type of the named parameter `point_map` in `NamedParameters2`. + + \param point_set_1 input point range used as reference. + \param point_set_2 input point range whose registration w.r.t. `point_set_1` will be computed. + \param np1 optional sequence of \ref psp_namedparameters "Named Parameters" among the ones listed below. + + \cgalNamedParamsBegin + \cgalParamBegin{point_map} a model of `ReadablePropertyMap` whose key type + is the value type of the iterator of `PointRange1` and whose value type is + `geom_traits::Point_3`. If this parameter is omitted, + `CGAL::Identity_property_map` is used.\cgalParamEnd + \cgalParamBegin{normal_map} a model of `ReadablePropertyMap` whose key + type is the value type of the iterator of `PointRange1` and whose value + type `geom_traits::Vector_3`.\cgalParamEnd + + \cgalParamBegin{point_set_filters} is a model of `Range`. The value type of + its iterator is `ICP_config`. + + The chain of filters to be applied to the reference point cloud. The reference + point cloud is processed into an intermediate point cloud with the given chain + of filters to be used in the alignment procedure. The chain is organized with + the forward traversal order of the point set filters range. + + The chain of point set filters are applied only once at the beginning of the + ICP procedure, i.e., before the first iteration of the ICP algorithm. + + The filters can have several purposes, including but are not limited to + i) removal of noisy points which render alignment of point clouds difficult, + ii) removal of redundant points so as to speed up alignment, iii) addition + of descriptive information to the points such as a surface normal vector, + or the direction from the point to the sensor. + + Corresponds to `referenceDataPointsFilters` configuration module of \ref thirdpartylibpointmatcher + library. The filters should be chosen and set from possible components of + the `referenceDataPointsFilters` configuration module. + See libpointmatcher documentation + for possible configurations. + + If this parameter is omitted, `RandomSamplingDataPointsFilter` is used. + \cgalParamEnd + + \cgalParamBegin{matcher} is a model of `ICP_config`. + The method used for matching (linking) the points from `point_set_2`, to the + points in the reference cloud, `point_set_1`. + + Corresponds to `matcher` configuration module of \ref thirdpartylibpointmatcher + library. The matcher should be chosen and set from possible components of + the `matcher` configuration module. + See libpointmatcher documentation + for possible configurations. + + If this parameter is omitted, `KDTreeMatcher` is used. + \cgalParamEnd + + \cgalParamBegin{outlier_filters} is a model of `Range`. The value type of + its iterator is `ICP_config`. + The chain of filters to be applied to the matched (linked) point clouds after + each processing iteration of the ICP algorithm to remove the links which do not + correspond to true point correspondences. The outliers are rejected. Points + with no link are ignored in the subsequent error minimization step. + The chain is organized with the forward traversal order of the outlier filters + range. + + Corresponds to `outlierFilters` configuration module of \ref thirdpartylibpointmatcher + library. The filters should be chosen and set from possible components of + the `outlierFilters` configuration module. + See libpointmatcher documentation + for possible configurations. + + If this parameter is omitted, `TrimmedDistOutlierFilter` is used. + \cgalParamEnd + + \cgalParamBegin{error_minimizer} is a model of `ICP_config`. + The error minimizer that computes a transformation matrix such as to minimize + the error between the point sets. + + Corresponds to `errorMinimizer` configuration module of \ref thirdpartylibpointmatcher + library. The error minimizer should be chosen and set from possible components of + the `errorMinimizer` configuration module. + See libpointmatcher documentation + for possible configurations. + + If this parameter is omitted, `PointToPlaneErrorMinimizer` is used. + \cgalParamEnd + + \cgalParamBegin{transformation_checkers} is a model of `Range`. The value type of + its iterator is `ICP_config`. + The chain of transformation checkers. A transformation checker can stop the + iteration depending on the conditions it defines. + + The chain is organized with the forward traversal order of the transformation + checkers range. + + Corresponds to `transformationCheckers` configuration module of \ref thirdpartylibpointmatcher + library. The transformation checkers should be chosen and set from possible components of + the `transformationCheckers` configuration module. + See libpointmatcher documentation + for possible configurations. + + If this parameter is omitted, the chain of `CounterTransformationChecker` and + `DifferentialTransformationChecker` is used. + \cgalParamEnd + + \cgalParamBegin{inspector} is a model of `ICP_config`. + The inspector allows to log data at different steps for analysis. Inspectors + typically provide deeper scrutiny than the logger. + + Corresponds to `inspector` configuration module of \ref thirdpartylibpointmatcher + library. The inspector should be chosen and set from possible components of + the `inspector` configuration module. + See libpointmatcher documentation + for possible configurations. + + If this parameter is omitted, `NullInspector` is used. + \cgalParamEnd + + \cgalParamBegin{logger} is a model of `ICP_config`. + The method for logging information regarding the registration process outputted + by \ref thirdpartylibpointmatcher library. The logs generated by CGAL library + does not get effected by this configuration. + + Corresponds to `logger` configuration module of \ref thirdpartylibpointmatcher + library. The logger should be chosen and set from possible components of + the `logger` configuration module. + See libpointmatcher documentation + for possible configurations. + + If this parameter is omitted, `NullLogger` is used. + \cgalParamEnd + + \cgalParamBegin{geom_traits} an instance of a geometric traits class, + model of `Kernel`\cgalParamEnd + \cgalNamedParamsEnd + + \param np2 optional sequence of \ref psp_namedparameters "Named Parameters" among the ones listed below. + \cgalNamedParamsBegin + \cgalParamBegin{point_map} a model of `ReadablePropertyMap` whose key type + is the value type of the iterator of `PointRange2` and whose value type is + `geom_traits::Point_3`. If this parameter is omitted, + `CGAL::Identity_property_map` is used.\cgalParamEnd + \cgalParamBegin{normal_map} a model of `ReadablePropertyMap` whose key + type is the value type of the iterator of `PointRange2` and whose value + type `geom_traits::Vector_3`.\cgalParamEnd + + \cgalParamBegin{point_set_filters} is a model of `Range`. The value type of + its iterator is `ICP_config`. + + The chain of filters to be applied to the point cloud, `point_set_2`. The + point cloud is processed into an intermediate point cloud with the given chain + of filters to be used in the alignment procedure. The chain is organized with + the forward traversal order of the point set filters range. + + The chain of point set filters are applied only once at the beginning of the + ICP procedure, i.e., before the first iteration of ICP algorithm. + + The filters can have several purposes, including but are not limited to + i) removal of noisy points which render alignment of point clouds difficult, + ii) removal of redundant points so as to speed up alignment, iii) addition + of descriptive information to the points such as a surface normal vector, + or the direction from the point to the sensor. + + Corresponds to `readingDataPointsFilters` configuration module of \ref thirdpartylibpointmatcher + library. The filters should be chosen and set from possible components of + the `readingDataPointsFilters` configuration module. + See libpointmatcher documentation + for possible configurations. + + If this parameter is omitted, `SamplingSurfaceNormalDataPointsFilter` is used. + \cgalParamEnd + + \cgalParamBegin{transformation} The affine transformation that is used as the + initial transformation for `point_set_2`. + + If this parameter is omitted, identity transformation is used. + \cgalParamEnd + + \cgalNamedParamsEnd + \return `true` if registration is converged, `false` otherwise. A log why it + failed to converge is written to `std::cerr` if the registration cannot converge. +*/ +template +bool +register_point_sets (const PointRange1& point_set_1, PointRange2& point_set_2, + const NamedParameters1& np1, const NamedParameters2& np2) +{ + using parameters::choose_parameter; + using parameters::get_parameter; + + namespace PSP = CGAL::Point_set_processing_3; + typedef typename PSP::GetK::Kernel Kernel; + + // compute registration transformation + std::pair res = + compute_registration_transformation(point_set_1, point_set_2, np1, np2); + + // property map type of point_set_2 + typedef typename CGAL::GetPointMap::type PointMap2; + PointMap2 point_map2 = choose_parameter(get_parameter(np2, internal_np::point_map), PointMap2()); + + // update CGAL points + for (typename PointRange2::iterator it=point_set_2.begin(), + end=point_set_2.end(); it!=end; ++it) + { + put(point_map2, *it, get(point_map2, *it).transform(res.first)); + } + + return res.second; +} + +// convenience overloads +template +bool +register_point_sets(const PointRange1& point_set_1, PointRange2& point_set_2, + const NamedParameters1& np1) +{ + namespace params = CGAL::Point_set_processing_3::parameters; + return register_point_sets(point_set_1, point_set_2, np1, params::all_default(point_set_1)); +} + +template +bool +register_point_sets(const PointRange1& point_set_1, PointRange2& point_set_2) +{ + namespace params = CGAL::Point_set_processing_3::parameters; + return register_point_sets(point_set_1, point_set_2, + params::all_default(point_set_1), + params::all_default(point_set_2)); +} + +} } // end of namespace CGAL::pointmatcher + +#endif // CGAL_LINKED_WITH_POINTMATCHER + +#endif // CGAL_POINTMATCHER_REGISTER_POINT_SETS_H diff --git a/Point_set_processing_3/include/CGAL/remove_outliers.h b/Point_set_processing_3/include/CGAL/remove_outliers.h index 60a5f2c4af0..55b7e4011ce 100644 --- a/Point_set_processing_3/include/CGAL/remove_outliers.h +++ b/Point_set_processing_3/include/CGAL/remove_outliers.h @@ -148,16 +148,16 @@ remove_outliers( using parameters::get_parameter; // geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); typename Kernel::FT neighbor_radius = choose_parameter(get_parameter(np, internal_np::neighbor_radius), typename Kernel::FT(0)); double threshold_percent = choose_parameter(get_parameter(np, internal_np::threshold_percent), 10.); double threshold_distance = choose_parameter(get_parameter(np, internal_np::threshold_distance), 0.); const std::function& callback = choose_parameter(get_parameter(np, internal_np::callback), - std::function()); + std::function()); typedef typename Kernel::FT FT; diff --git a/Point_set_processing_3/include/CGAL/structure_point_set.h b/Point_set_processing_3/include/CGAL/structure_point_set.h index 0a98d88c331..10f4ec1f446 100644 --- a/Point_set_processing_3/include/CGAL/structure_point_set.h +++ b/Point_set_processing_3/include/CGAL/structure_point_set.h @@ -206,7 +206,7 @@ public: using parameters::get_parameter; // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetNormalMap::type NormalMap; typedef typename Point_set_processing_3::GetPlaneMap::type PlaneMap; typedef typename Point_set_processing_3::GetPlaneIndexMap::type PlaneIndexMap; @@ -218,10 +218,10 @@ public: typename Point_set_processing_3::GetPlaneIndexMap::NoMap>::value), "Error: no plane index map"); - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map), NormalMap()); - PlaneMap plane_map = choose_parameter(get_parameter(np, internal_np::plane_map), PlaneMap()); - PlaneIndexMap index_map = choose_parameter(get_parameter(np, internal_np::plane_index_map), PlaneIndexMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map)); + PlaneMap plane_map = choose_parameter(get_parameter(np, internal_np::plane_map)); + PlaneIndexMap index_map = choose_parameter(get_parameter(np, internal_np::plane_index_map)); double attraction_factor = choose_parameter(get_parameter(np, internal_np::attraction_factor), 3.); m_points.reserve(points.size()); diff --git a/Point_set_processing_3/include/CGAL/vcm_estimate_normals.h b/Point_set_processing_3/include/CGAL/vcm_estimate_normals.h index fde906bd6e0..5c243828181 100644 --- a/Point_set_processing_3/include/CGAL/vcm_estimate_normals.h +++ b/Point_set_processing_3/include/CGAL/vcm_estimate_normals.h @@ -260,10 +260,10 @@ compute_vcm (const PointRange& points, using parameters::get_parameter; // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); Kernel kernel; // First, compute the VCM for each point @@ -320,7 +320,7 @@ vcm_estimate_normals_internal (PointRange& points, using parameters::get_parameter; // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetNormalMap::type NormalMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; typedef typename GetDiagonalizeTraits::type DiagonalizeTraits; @@ -329,8 +329,8 @@ vcm_estimate_normals_internal (PointRange& points, typename Point_set_processing_3::GetNormalMap::NoMap>::value), "Error: no normal map"); - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); - NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map), NormalMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); + NormalMap normal_map = choose_parameter(get_parameter(np, internal_np::normal_map)); typedef std::array Covariance; diff --git a/Point_set_processing_3/include/CGAL/wlop_simplify_and_regularize_point_set.h b/Point_set_processing_3/include/CGAL/wlop_simplify_and_regularize_point_set.h index 3055edc1b9b..4a05708e00e 100644 --- a/Point_set_processing_3/include/CGAL/wlop_simplify_and_regularize_point_set.h +++ b/Point_set_processing_3/include/CGAL/wlop_simplify_and_regularize_point_set.h @@ -411,9 +411,8 @@ public: See the TBB documentation for more details. - \tparam ConcurrencyTag enables sequential versus parallel algorithm. - Possible values are `Sequential_tag` - and `Parallel_tag`. + \tparam ConcurrencyTag enables sequential versus parallel algorithm. Possible values are `Sequential_tag`, + `Parallel_tag`, and `Parallel_if_available_tag`. \tparam PointRange is a model of `Range`. The value type of its iterator is the key type of the named parameter `point_map`. \tparam OutputIterator Type of the output iterator. @@ -465,10 +464,10 @@ wlop_simplify_and_regularize_point_set( using parameters::get_parameter; // basic geometric types - typedef typename Point_set_processing_3::GetPointMap::type PointMap; + typedef typename CGAL::GetPointMap::type PointMap; typedef typename Point_set_processing_3::GetK::Kernel Kernel; - PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap()); + PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); double select_percentage = choose_parameter(get_parameter(np, internal_np::select_percentage), 5.); double radius = choose_parameter(get_parameter(np, internal_np::neighbor_radius), -1); unsigned int iter_number = choose_parameter(get_parameter(np, internal_np::number_of_iterations), 35); diff --git a/Point_set_processing_3/test/Point_set_processing_3/CMakeLists.txt b/Point_set_processing_3/test/Point_set_processing_3/CMakeLists.txt index 264c713ef55..1b5e1a80746 100644 --- a/Point_set_processing_3/test/Point_set_processing_3/CMakeLists.txt +++ b/Point_set_processing_3/test/Point_set_processing_3/CMakeLists.txt @@ -41,29 +41,41 @@ if ( CGAL_FOUND ) # Use Eigen find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) # Executables that require Eigen create_single_source_cgal_program( "normal_estimation_test.cpp" ) + CGAL_target_use_Eigen(normal_estimation_test) + create_single_source_cgal_program( "hierarchy_simplification_test.cpp" ) + CGAL_target_use_Eigen(hierarchy_simplification_test) + create_single_source_cgal_program( "smoothing_test.cpp" ) + CGAL_target_use_Eigen(smoothing_test) + create_single_source_cgal_program( "vcm_plane_test.cpp" ) + CGAL_target_use_Eigen(vcm_plane_test) + create_single_source_cgal_program( "vcm_all_test.cpp" ) + CGAL_target_use_Eigen(vcm_all_test) + create_single_source_cgal_program( "jet_pointer_as_property_map.cpp" ) + CGAL_target_use_Eigen(jet_pointer_as_property_map) else() message(STATUS "NOTICE: This program requires Eigen 3.1 (or greater) and will not be compiled.") endif() - foreach(target - analysis_test - smoothing_test - bilateral_smoothing_test - wlop_simplify_and_regularize_test - edge_aware_upsample_test - normal_estimation_test) - if(TBB_FOUND AND TARGET ${target}) - CGAL_target_use_TBB(${target}) - endif() - endforeach() + if (TBB_FOUND) + foreach(target + analysis_test + smoothing_test + bilateral_smoothing_test + wlop_simplify_and_regularize_test + edge_aware_upsample_test + normal_estimation_test) + if(TARGET ${target}) + CGAL_target_use_TBB(${target}) + endif() + endforeach() + endif() else() diff --git a/Point_set_processing_3/test/Point_set_processing_3/analysis_test.cpp b/Point_set_processing_3/test/Point_set_processing_3/analysis_test.cpp index 63a68155087..df1603f8efc 100644 --- a/Point_set_processing_3/test/Point_set_processing_3/analysis_test.cpp +++ b/Point_set_processing_3/test/Point_set_processing_3/analysis_test.cpp @@ -33,12 +33,7 @@ typedef Kernel::FT FT; typedef Kernel::Point_3 Point; // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif - +typedef CGAL::Parallel_if_available_tag Concurrency_tag; // ---------------------------------------------------------------------------- // Tests diff --git a/Point_set_processing_3/test/Point_set_processing_3/edge_aware_upsample_test.cpp b/Point_set_processing_3/test/Point_set_processing_3/edge_aware_upsample_test.cpp index df0e92efc37..613bf126a06 100644 --- a/Point_set_processing_3/test/Point_set_processing_3/edge_aware_upsample_test.cpp +++ b/Point_set_processing_3/test/Point_set_processing_3/edge_aware_upsample_test.cpp @@ -36,12 +36,7 @@ typedef Kernel::Vector_3 Vector; typedef std::pair PointVectorPair; // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif - +typedef CGAL::Parallel_if_available_tag Concurrency_tag; // ---------------------------------------------------------------------------- // Tests diff --git a/Point_set_processing_3/test/Point_set_processing_3/normal_estimation_test.cpp b/Point_set_processing_3/test/Point_set_processing_3/normal_estimation_test.cpp index 1c640709039..36e0adf0320 100644 --- a/Point_set_processing_3/test/Point_set_processing_3/normal_estimation_test.cpp +++ b/Point_set_processing_3/test/Point_set_processing_3/normal_estimation_test.cpp @@ -45,12 +45,7 @@ typedef CGAL::Point_with_normal_3 Point_with_normal; // position + norma typedef std::vector PointList; // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif - +typedef CGAL::Parallel_if_available_tag Concurrency_tag; // ---------------------------------------------------------------------------- // Tests diff --git a/Point_set_processing_3/test/Point_set_processing_3/smoothing_test.cpp b/Point_set_processing_3/test/Point_set_processing_3/smoothing_test.cpp index 5dad79528f7..e5333343624 100644 --- a/Point_set_processing_3/test/Point_set_processing_3/smoothing_test.cpp +++ b/Point_set_processing_3/test/Point_set_processing_3/smoothing_test.cpp @@ -36,11 +36,7 @@ typedef Kernel::Point_3 Point; typedef Kernel::Vector_3 Vector; // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; // ---------------------------------------------------------------------------- // Tests diff --git a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/CMakeLists.txt b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/CMakeLists.txt index ae0215158da..0b65cf899cf 100644 --- a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/CMakeLists.txt +++ b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/CMakeLists.txt @@ -23,15 +23,14 @@ if ( CGAL_FOUND ) # Find Eigen3 (requires 3.1.0 or greater) find_package(Eigen3 3.1.0) - if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - endif() - if (EIGEN3_FOUND) # Executables that require Eigen 3 create_single_source_cgal_program( "poisson_reconstruction_example.cpp" ) + CGAL_target_use_Eigen(poisson_reconstruction_example) create_single_source_cgal_program( "poisson_reconstruction.cpp" ) + CGAL_target_use_Eigen(poisson_reconstruction) create_single_source_cgal_program( "poisson_reconstruction_function.cpp" ) + CGAL_target_use_Eigen(poisson_reconstruction_function) else() message(STATUS "NOTICE: The examples need Eigen 3.1 (or greater) will not be compiled.") endif() diff --git a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/poisson_reconstruction.cpp b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/poisson_reconstruction.cpp index 885a70b900e..8dc1420e9cb 100644 --- a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/poisson_reconstruction.cpp +++ b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/poisson_reconstruction.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -41,7 +40,7 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::FT FT; typedef Kernel::Point_3 Point; typedef Kernel::Vector_3 Vector; -typedef CGAL::Point_with_normal_3 Point_with_normal; +typedef std::pair Point_with_normal; typedef Kernel::Sphere_3 Sphere; typedef std::deque PointList; @@ -178,7 +177,7 @@ int main(int argc, char * argv[]) vertices(input_mesh)){ const Point& p = v->point(); Vector n = CGAL::Polygon_mesh_processing::compute_vertex_normal(v,input_mesh); - points.push_back(Point_with_normal(p,n)); + points.push_back(std::make_pair(p,n)); } } // If XYZ file format @@ -188,14 +187,14 @@ int main(int argc, char * argv[]) // Reads the point set file in points[]. // Note: read_xyz_points_and_normals() requires an iterator over points // + property maps to access each point's position and normal. - // The position property map can be omitted here as we use iterators over Point_3 elements. std::ifstream stream(input_filename.c_str()); if (!stream || !CGAL::read_xyz_points( stream, std::back_inserter(points), - CGAL::parameters::normal_map - (CGAL::make_normal_of_point_with_normal_map(PointList::value_type())))) + CGAL::parameters::point_map + (CGAL::make_first_of_pair_property_map(Point_with_normal())). + normal_map (CGAL::make_second_of_pair_property_map(Point_with_normal())))) { std::cerr << "Error: cannot read file " << input_filename << std::endl; return EXIT_FAILURE; @@ -224,7 +223,7 @@ int main(int argc, char * argv[]) return EXIT_FAILURE; } - bool points_have_normals = (points.begin()->normal() != CGAL::NULL_VECTOR); + bool points_have_normals = (points.begin()->second != CGAL::NULL_VECTOR); if ( ! points_have_normals ) { std::cerr << "Input point set not supported: this reconstruction method requires oriented normals" << std::endl; @@ -247,11 +246,10 @@ int main(int argc, char * argv[]) // Creates implicit function from the read points. // Note: this method requires an iterator over points // + property maps to access each point's position and normal. - // The position property map can be omitted here as we use iterators over Point_3 elements. Poisson_reconstruction_function function( points.begin(), points.end(), - CGAL::make_identity_property_map(PointList::value_type()), - CGAL::make_normal_of_point_with_normal_map(PointList::value_type()), + CGAL::make_first_of_pair_property_map(Point_with_normal()), + CGAL::make_second_of_pair_property_map(Point_with_normal()), visitor); #ifdef CGAL_EIGEN3_ENABLED @@ -293,7 +291,9 @@ int main(int argc, char * argv[]) std::cerr << "Surface meshing...\n"; // Computes average spacing - FT average_spacing = CGAL::compute_average_spacing(points, 6 /* knn = 1 ring */); + FT average_spacing = CGAL::compute_average_spacing + (points, 6 /* knn = 1 ring */, + CGAL::parameters::point_map (CGAL::make_first_of_pair_property_map(Point_with_normal()))); // Gets one point inside the implicit surface Point inner_point = function.get_inner_point(); @@ -366,7 +366,7 @@ int main(int argc, char * argv[]) double avg_distance = 0; for (PointList::const_iterator p=points.begin(); p!=points.end(); p++) { - double distance = std::sqrt(tree.squared_distance(*p)); + double distance = std::sqrt(tree.squared_distance(p->first)); max_distance = (std::max)(max_distance, distance); avg_distance += distance; diff --git a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/poisson_reconstruction_example.cpp b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/poisson_reconstruction_example.cpp index d99c6131b48..d69b99311e6 100644 --- a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/poisson_reconstruction_example.cpp +++ b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/poisson_reconstruction_example.cpp @@ -5,13 +5,14 @@ #include #include #include -#include #include #include #include #include +#include + #include #include @@ -19,7 +20,10 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::FT FT; typedef Kernel::Point_3 Point; -typedef CGAL::Point_with_normal_3 Point_with_normal; +typedef Kernel::Vector_3 Vector; +typedef std::pair Point_with_normal; +typedef CGAL::First_of_pair_property_map Point_map; +typedef CGAL::Second_of_pair_property_map Normal_map; typedef Kernel::Sphere_3 Sphere; typedef std::vector PointList; typedef CGAL::Polyhedron_3 Polyhedron; @@ -38,14 +42,14 @@ int main(void) // Reads the point set file in points[]. // Note: read_xyz_points_and_normals() requires an iterator over points // + property maps to access each point's position and normal. - // The position property map can be omitted here as we use iterators over Point_3 elements. PointList points; std::ifstream stream("data/kitten.xyz"); if (!stream || !CGAL::read_xyz_points( stream, std::back_inserter(points), - CGAL::parameters::normal_map(CGAL::make_normal_of_point_with_normal_map(PointList::value_type())))) + CGAL::parameters::point_map (Point_map()). + normal_map (Normal_map()))) { std::cerr << "Error: cannot read file data/kitten.xyz" << std::endl; return EXIT_FAILURE; @@ -55,9 +59,7 @@ int main(void) // Note: this method requires an iterator over points // + property maps to access each point's position and normal. - // The position property map can be omitted here as we use iterators over Point_3 elements. - Poisson_reconstruction_function function(points.begin(), points.end(), - CGAL::make_normal_of_point_with_normal_map(PointList::value_type()) ); + Poisson_reconstruction_function function(points.begin(), points.end(), Point_map(), Normal_map()); // Computes the Poisson indicator function f() // at each vertex of the triangulation. @@ -65,7 +67,9 @@ int main(void) return EXIT_FAILURE; // Computes average spacing - FT average_spacing = CGAL::compute_average_spacing(points, 6 /* knn = 1 ring */); + FT average_spacing = CGAL::compute_average_spacing + (points, 6 /* knn = 1 ring */, + CGAL::parameters::point_map (Point_map())); // Gets one point inside the implicit surface // and computes implicit function bounding sphere radius. @@ -107,9 +111,13 @@ int main(void) /// [PMP_distance_snippet] // computes the approximation error of the reconstruction double max_dist = - CGAL::Polygon_mesh_processing::approximate_max_distance_to_point_set(output_mesh, - points, - 4000); + CGAL::Polygon_mesh_processing::approximate_max_distance_to_point_set + (output_mesh, + CGAL::make_range (boost::make_transform_iterator + (points.begin(), CGAL::Property_map_to_unary_function()), + boost::make_transform_iterator + (points.end(), CGAL::Property_map_to_unary_function())), + 4000); std::cout << "Max distance to point_set: " << max_dist << std::endl; /// [PMP_distance_snippet] diff --git a/Poisson_surface_reconstruction_3/test/Poisson_surface_reconstruction_3/CMakeLists.txt b/Poisson_surface_reconstruction_3/test/Poisson_surface_reconstruction_3/CMakeLists.txt index e1d9326840b..1c518a1267b 100644 --- a/Poisson_surface_reconstruction_3/test/Poisson_surface_reconstruction_3/CMakeLists.txt +++ b/Poisson_surface_reconstruction_3/test/Poisson_surface_reconstruction_3/CMakeLists.txt @@ -25,11 +25,9 @@ if ( CGAL_FOUND ) find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) if(EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - # Executables that require Eigen 3.1 create_single_source_cgal_program( "poisson_reconstruction_test.cpp" ) - + CGAL_target_use_Eigen(poisson_reconstruction_test) else() message(STATUS "NOTICE: Some of the executables in this directory need Eigen 3.1 (or greater) and will not be compiled.") diff --git a/Polygon_mesh_processing/benchmark/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/benchmark/Polygon_mesh_processing/CMakeLists.txt index 45799830a42..7db73683150 100644 --- a/Polygon_mesh_processing/benchmark/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/benchmark/Polygon_mesh_processing/CMakeLists.txt @@ -29,10 +29,6 @@ endif() # include for local package find_package(Eigen3 3.2.0) #(requires 3.2.0 or greater) -if (EIGEN3_FOUND) - # Executables that require Eigen 3.2 - include( ${EIGEN3_USE_FILE} ) -endif(EIGEN3_FOUND) # Creating entries for all .cpp/.C files with "main" routine # ########################################################## @@ -41,4 +37,8 @@ create_single_source_cgal_program( "polygon_mesh_slicer.cpp" ) create_single_source_cgal_program( "hole_filling.cpp" ) +if (EIGEN3_FOUND) + CGAL_target_use_Eigen(polygon_mesh_slicer) + CGAL_target_use_Eigen(hole_filling) +endif() diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt index 4076a5e1915..92a56bc7b64 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt @@ -32,20 +32,27 @@ is the property map with the points associated to the vertices of the polygon me \cgalNPEnd \cgalNPBegin{vertex_index_map} \anchor PMP_vertex_index_map -is the property map containing the index of each vertex of the input polygon mesh.\n +is the property map associating a unique index to each vertex of a polygon mesh, +between `0` and `num_vertices(g)-1`. +If this parameter is not passed, internal machinery will create and initialize a vertex index +property map, either using the internal property map if it exists or using an external map. The latter +might result in - slightly - worsened performance in case of non-constant complexity for index access.\n Type: a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` as key type and the value type \code typename boost::property_traits::type>::value_type \endcode -Default: \code boost::get(CGAL::vertex_index, pmesh)\endcode +Default: an initialized vertex index property map \cgalNPEnd \cgalNPBegin{face_index_map} \anchor PMP_face_index_map -is the property map containing the index of each face of the input polygon mesh.\n +is the property map associating a unique index to each face of a polygon mesh, +between `0` and `num_faces(g)-1`. +If this parameter is not passed, internal machinery will create and initialize a face index +property map, either using the internal property map if it exists or using an external map. The latter +might result in - slightly - worsened performance in case of non-constant complexity for index access.\n Type: a class model of `ReadablePropertyMap` with `boost::graph_traits::%face_descriptor` as key type and the value type: \code typename boost::property_traits::type>::value_type \endcode -Default: \code boost::get(CGAL::face_index, pmesh)\endcode -If this internal property map exists, its values must be initialized. +Default: an initialized face index property map \cgalNPEnd \cgalNPBegin{edge_is_constrained_map} \anchor PMP_edge_is_constrained_map @@ -71,6 +78,14 @@ is the geometric traits instance used for the mesh processing operation.\n typename boost::property_map::type>::value_type>::Kernel \endcode \cgalNPEnd +\cgalNPBegin{point_map} \anchor PMP_point_map + is the property map containing the points associated to the elements of the point range `points`.\n +\b Type: a class model of `ReadablePropertyMap` with +`PointRange::iterator::value_type` as key type and +`geom_traits::Point_3` as value type. \n +Default value: \code CGAL::Identity_property_map\endcode +\cgalNPEnd + \cgalNPBegin{vertex_incident_patches_map} \anchor PMP_vertex_incident_patches_map is the property map containing the surface patches incident to each vertex of the input polygon mesh.\n Type: a class model of `LvaluePropertyMap` with @@ -404,31 +419,28 @@ still ensuring that the total sum of the coordinates is `1`. Default: `0` \cgalNPEnd -\cgalNPBegin{use_angle_smoothing_t} \anchor PMP_use_angle_smoothing +\cgalNPBegin{use_angle_smoothing} \anchor PMP_use_angle_smoothing Parameter used in the function `smooth_mesh()` to indicate if angle-based smoothing should be used. When this type of smoothing is used, the algorithm attempts to equalize angles incident to each vertex. - \n Type: `bool` \n Default: `true` \cgalNPEnd -\cgalNPBegin{use_area_smoothing_t} \anchor PMP_use_area_smoothing +\cgalNPBegin{use_area_smoothing} \anchor PMP_use_area_smoothing Parameter used in the function `smooth_mesh()` to indicate if area-based smoothing should be used. When this type of smoothing is used, the algorithm attempts to equalize the areas of the triangles incident to each vertex. Since this can create elongated triangles, a second phase uses Delaunay-based flips to recover good shapes, unless specified otherwise (see below). - \n Type: `bool` \n Default: `true` \cgalNPEnd -\cgalNPBegin{use_Delaunay_flips_t} \anchor PMP_use_Delaunay_flips +\cgalNPBegin{use_Delaunay_flips} \anchor PMP_use_Delaunay_flips Parameter used in the function `smooth_mesh()` to indicate if Delaunay-based flips should be used after area-based smoothing has been performed. A user wishing to preserve combinatorial information can set this parameter to `false`, but the mesh might have elongated elements. - \n Type: `bool` \n Default: `true` @@ -439,7 +451,6 @@ Parameter used in the function `smooth_mesh()` to indicate if some sanity checks if the move of a vertex should be applied or rejected. These sanity checks consists of checking that no face incident to the vertex becomes inverted and that the minimum angle of the incident faces is not decreased by the move. - \n Type: `bool` \n Default: `true` @@ -449,7 +460,6 @@ is not decreased by the move. Parameter used in the functions `keep_large_connected_components()` and `keep_largest_connected_components()` to pass a property map that gives the size of a face when evaluating the size of a connected component (which is defined as the sum of the sizes of its faces). - \n Type: a class model of `ReadablePropertyMap` with `boost::graph_traits::%face_descriptor` as key type and @@ -457,6 +467,33 @@ a value type supporting construction from `0`, `operator+=()`, and comparison op Default: `CGAL::Constant_property_map` with value `1` \cgalNPEnd +\cgalNPBegin{area_threshold} \anchor PMP_area_threshold +Parameter used in the function `remove_connected_components_of_negligible_size()` +to pass a threshold value such that all connected components with an area smaller +than this value are removed from the mesh. +\n +Type: `Kernel::FT` \n +Default: The square of one percent of the length of the diagonal of the bounding box of the mesh. +\cgalNPEnd + +\cgalNPBegin{volume_threshold} \anchor PMP_volume_threshold +Parameter used in the function `remove_connected_components_of_negligible_size()` +to pass a threshold value such that all (closed) connected components with a volume smaller +than this value are removed from the mesh. +\n +Type: `Kernel::FT` \n +Default: The third power of one percent of the length of the diagonal of the bounding box of the mesh. +\cgalNPEnd + + +\cgalNPBegin{dry_run} \anchor PMP_dry_run +Parameter that tells a function not to alter the input, but rather to only return the expected result. +It is for example used in the fucntion `keep_large_connected_components()`. +\n +Type: `bool` \n +Default: `false` +\cgalNPEnd + \cgalNPTableEnd */ diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt index eb78d77b85c..d5b84706fa5 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -150,11 +150,13 @@ and provides a list of the parameters that are used in this package. - `CGAL::Polygon_mesh_processing::stitch_borders()` - `CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh()` - `CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh()` +- `CGAL::Polygon_mesh_processing::polygon_mesh_to_polygon_soup()` - `CGAL::Polygon_mesh_processing::remove_isolated_vertices()` - `CGAL::Polygon_mesh_processing::is_non_manifold_vertex()` - `CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices()` - `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()` - `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycles()` +- `CGAL::Polygon_mesh_processing::remove_connected_components_of_negligible_size()` \cgalCRPSection{Normal Computation Functions} - `CGAL::Polygon_mesh_processing::compute_face_normal()` @@ -168,6 +170,7 @@ and provides a list of the parameters that are used in this package. - `CGAL::Polygon_mesh_processing::connected_components()` - `CGAL::Polygon_mesh_processing::keep_large_connected_components()` - `CGAL::Polygon_mesh_processing::keep_largest_connected_components()` +- `CGAL::Polygon_mesh_processing::split_connected_components()` - \link keep_connected_components_grp `CGAL::Polygon_mesh_processing::keep_connected_components()` \endlink - \link keep_connected_components_grp `CGAL::Polygon_mesh_processing::remove_connected_components()` \endlink @@ -179,6 +182,7 @@ and provides a list of the parameters that are used in this package. - `CGAL::Polygon_mesh_processing::corefine()` - `CGAL::Polygon_mesh_processing::surface_intersection()` - `CGAL::Polygon_mesh_processing::clip()` +- `CGAL::Polygon_mesh_processing::split()` - `CGAL::Polygon_mesh_processing::does_bound_a_volume()` \cgalCRPSection{Geometric Measure Functions} diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index d543aa198bd..b038beef155 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -312,18 +312,19 @@ the limited precision of floating point numbers. As a natural extension, some clipping functionalities with a volume bounded by a closed mesh and a halfspace (defined by the negative side of a plane to be consistent with the outward normal convention) are offered. The functions `CGAL::Polygon_mesh_processing::clip()` +and `CGAL::Polygon_mesh_processing::split()` have some options to select whether the clipping should be done at the volume or surface level, and also if the clipper should be considered as compact or not. This is illustrated on \cgalFigureRef{coref_clip_close_open} and \cgalFigureRef{coref_clip_compact}. \cgalFigureBegin{coref_clip_close_open, clip_open_close.png} Clipping a cube with a halfspace. From left to right: (i) initial cube and the plane -defining the clipping halfspace; (ii) `close_volumes=false`: clipping of the surface mesh (boundary edges -depicted in red); (iii) `close_volumes=true`: clipping of the volume bounded by the surface mesh. +defining the clipping halfspace; (ii) `clip_volume=false`: clipping of the surface mesh (boundary edges +depicted in red); (iii) `clip_volume=true`: clipping of the volume bounded by the surface mesh. \cgalFigureEnd \cgalFigureBegin{coref_clip_compact, clip_compact.png} -Clipping a cube with a halfspace: compacity of the clipper (`close_volumes=false` in both cases). +Clipping a cube with a halfspace: compacity of the clipper (`clip_volume=false` in both cases). From left to right: (i) initial cube and the plane defining the clipping halfspace, note that a whole face of the cube (2 triangles) is exactly contained in the plane; (ii) `use_compact_clipper=true`: clipping of the surface mesh with a compact halfspace: coplanar faces are part of the output; @@ -412,10 +413,13 @@ one incident non-null face) after each hole filling step. Holes are filled one after the other, and the process stops when there is no border edge left. This process is illustrated by the example below, where holes are -iteratively filled, refined and faired to get a faired mesh with no hole. +iteratively filled, refined and faired. Optionally, only holes +not exceeding a certain diameter or number of edges can be filled. +This example assumes that the mesh is stored in a `Surface_mesh` +datastructure. Analogous examples when using the `Polyhedron_3` +class and a few others are part of the code base. - -\cgalExample{Polygon_mesh_processing/hole_filling_example.cpp} +\cgalExample{Polygon_mesh_processing/hole_filling_example_SM.cpp} \cgalFigureBegin{Triangulated_fork, fork.jpg} Holes in the fork model are filled with triangle patches. @@ -575,6 +579,9 @@ to build a valid polygon mesh. The function `CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh()` performs this mesh construction step. +Inversely, a polygon soup can be constructed from a polygon mesh, +using the function `CGAL::Polygon_mesh_processing::polygon_mesh_to_polygon_soup()`. + \subsection OrientingPolygonMeshes Polygon Meshes This package provides functions dealing with the orientation of faces in a closed polygon mesh. @@ -795,6 +802,11 @@ Similarly to the previous function, the function `CGAL::Polygon_mesh_processing::keep_large_connected_components()` can be used to discard all connected components whose size is below a user-defined threshold. +Also, the function `CGAL::Polygon_mesh_processing::split_connected_components()` +enables the user to split the connected components of a polygon mesh in as many +polygon meshes. + + \subsection CCExample Connected Components Example The first example shows how to record the connected diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt index a9350578648..194199ba808 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt @@ -2,6 +2,7 @@ \example Polygon_mesh_processing/self_intersections_example.cpp \example Polygon_mesh_processing/hole_filling_example.cpp +\example Polygon_mesh_processing/hole_filling_example_SM.cpp \example Polygon_mesh_processing/stitch_borders_example.cpp \example Polygon_mesh_processing/compute_normals_example.cpp \example Polygon_mesh_processing/point_inside_example.cpp diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index 95a539040ac..ec36a4b70f0 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -46,14 +46,16 @@ find_package(Eigen3 3.2.0) #(requires 3.2.0 or greater) create_single_source_cgal_program( "hausdorff_distance_remeshing_example.cpp") if (EIGEN3_FOUND) - # Executables that require Eigen 3.2 - include( ${EIGEN3_USE_FILE} ) - create_single_source_cgal_program( "hole_filling_example.cpp" ) + CGAL_target_use_Eigen(hole_filling_example) create_single_source_cgal_program( "hole_filling_example_SM.cpp" ) + CGAL_target_use_Eigen(hole_filling_example_SM) create_single_source_cgal_program( "refine_fair_example.cpp") + CGAL_target_use_Eigen(refine_fair_example) create_single_source_cgal_program( "shape_smoothing_example.cpp") - + CGAL_target_use_Eigen(shape_smoothing_example) + create_single_source_cgal_program( "hole_filling_example_LCC.cpp" ) + CGAL_target_use_Eigen(hole_filling_example_LCC) endif(EIGEN3_FOUND) create_single_source_cgal_program( "self_intersections_example.cpp" ) @@ -80,19 +82,24 @@ create_single_source_cgal_program( "corefinement_mesh_union_with_attributes.cpp" create_single_source_cgal_program( "corefinement_polyhedron_union.cpp" ) create_single_source_cgal_program( "random_perturbation_SM_example.cpp" ) create_single_source_cgal_program( "corefinement_LCC.cpp") -create_single_source_cgal_program( "hole_filling_example_LCC.cpp" ) create_single_source_cgal_program( "detect_features_example.cpp" ) create_single_source_cgal_program( "manifoldness_repair_example.cpp" ) create_single_source_cgal_program( "repair_polygon_soup_example.cpp" ) create_single_source_cgal_program( "mesh_smoothing_example.cpp") create_single_source_cgal_program( "locate_example.cpp") +#create_single_source_cgal_program( "self_snapping_example.cpp") +#create_single_source_cgal_program( "snapping_example.cpp") if(OpenMesh_FOUND) + create_single_source_cgal_program( "compute_normals_example_OM.cpp" ) target_link_libraries( compute_normals_example_OM PRIVATE ${OPENMESH_LIBRARIES} ) -create_single_source_cgal_program( "hole_filling_example_OM.cpp" ) -target_link_libraries( hole_filling_example_OM PRIVATE ${OPENMESH_LIBRARIES} ) +if (EIGEN3_FOUND) + create_single_source_cgal_program( "hole_filling_example_OM.cpp" ) + target_link_libraries( hole_filling_example_OM PRIVATE ${OPENMESH_LIBRARIES} ) + CGAL_target_use_Eigen( hole_filling_example_OM ) +endif() create_single_source_cgal_program( "point_inside_example_OM.cpp") target_link_libraries( point_inside_example_OM PRIVATE ${OPENMESH_LIBRARIES} ) @@ -109,6 +116,9 @@ endif(OpenMesh_FOUND) find_package( TBB ) if( TBB_FOUND ) +# CGAL_target_use_TBB(self_snapping_example) +# CGAL_target_use_TBB(snapping_example) + 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/compute_normals_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compute_normals_example.cpp index ac4e2c3b4a3..cd7ba66f2e4 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/compute_normals_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/compute_normals_example.cpp @@ -6,13 +6,16 @@ #include #include -typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -typedef K::Point_3 Point; -typedef K::Vector_3 Vector; +namespace PMP = CGAL::Polygon_mesh_processing; -typedef CGAL::Surface_mesh Surface_mesh; -typedef boost::graph_traits::vertex_descriptor vertex_descriptor; -typedef boost::graph_traits::face_descriptor face_descriptor; +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; + +typedef K::Point_3 Point; +typedef K::Vector_3 Vector; + +typedef CGAL::Surface_mesh Surface_mesh; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::face_descriptor face_descriptor; int main(int argc, char* argv[]) { @@ -25,24 +28,18 @@ int main(int argc, char* argv[]) return 1; } - auto fnormals = mesh.add_property_map - ("f:normals", CGAL::NULL_VECTOR).first; - auto vnormals = mesh.add_property_map - ("v:normals", CGAL::NULL_VECTOR).first; + auto vnormals = mesh.add_property_map("v:normals", CGAL::NULL_VECTOR).first; + auto fnormals = mesh.add_property_map("f:normals", CGAL::NULL_VECTOR).first; - CGAL::Polygon_mesh_processing::compute_normals(mesh, - vnormals, - fnormals, - CGAL::Polygon_mesh_processing::parameters::vertex_point_map(mesh.points()). - geom_traits(K())); + PMP::compute_normals(mesh, vnormals, fnormals); + + std::cout << "Vertex normals :" << std::endl; + for(vertex_descriptor vd: vertices(mesh)) + std::cout << vnormals[vd] << std::endl; std::cout << "Face normals :" << std::endl; - for(face_descriptor fd: faces(mesh)){ + for(face_descriptor fd: faces(mesh)) std::cout << fnormals[fd] << std::endl; - } - std::cout << "Vertex normals :" << std::endl; - for(vertex_descriptor vd: vertices(mesh)){ - std::cout << vnormals[vd] << std::endl; - } + return 0; } diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_LCC.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_LCC.cpp index f7239c96f24..5abd976cb9a 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_LCC.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_LCC.cpp @@ -34,6 +34,7 @@ int main(int argc, char* argv[]) << num_vertices(mesh2) << "\n"; std::ofstream output("mesh1_refined.off"); + output.precision(17); CGAL::write_off(output, mesh1); output.close(); output.open("mesh2_refined.off"); diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_SM.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_SM.cpp index 3eacde99ed9..77244f43fa6 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_SM.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_SM.cpp @@ -41,6 +41,7 @@ int main(int argc, char* argv[]) << num_vertices(mesh2) << "\n"; std::ofstream output("mesh1_refined.off"); + output.precision(17); output << mesh1; output.close(); output.open("mesh2_refined.off"); diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_consecutive_bool_op.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_consecutive_bool_op.cpp index cf90534b84a..bbe55ca4cbc 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_consecutive_bool_op.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_consecutive_bool_op.cpp @@ -136,6 +136,7 @@ int main(int argc, char* argv[]) { std::cout << "Intersection and union were successfully computed\n"; std::ofstream output("inter_union.off"); + output.precision(17); output << mesh2; return 0; } diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_difference_remeshed.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_difference_remeshed.cpp index 3a5068aa00b..f12868c033a 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_difference_remeshed.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_difference_remeshed.cpp @@ -67,6 +67,7 @@ int main(int argc, char* argv[]) { std::cout << "Difference was successfully computed\n"; std::ofstream output("difference.off"); + output.precision(17); output << mesh1; } else{ @@ -111,6 +112,7 @@ int main(int argc, char* argv[]) params::edge_is_constrained_map(is_constrained_map) ); std::ofstream output("difference_remeshed.off"); + output.precision(17); output << mesh1; return 0; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_mesh_union.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_mesh_union.cpp index f03403dd58b..150a1db0782 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_mesh_union.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_mesh_union.cpp @@ -37,6 +37,7 @@ int main(int argc, char* argv[]) { std::cout << "Union was successfully computed\n"; std::ofstream output("union.off"); + output.precision(17); output << out; return 0; } diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_mesh_union_and_intersection.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_mesh_union_and_intersection.cpp index 359dd989a2c..dda4e2f1f96 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_mesh_union_and_intersection.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_mesh_union_and_intersection.cpp @@ -55,6 +55,7 @@ int main(int argc, char* argv[]) { std::cout << "Union was successfully computed\n"; std::ofstream output("union.off"); + output.precision(17); output << out_union; } else @@ -64,6 +65,7 @@ int main(int argc, char* argv[]) { std::cout << "Intersection was successfully computed\n"; std::ofstream output("intersection.off"); + output.precision(17); output << out_intersection; } else diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_mesh_union_with_attributes.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_mesh_union_with_attributes.cpp index 142902bf63a..05e5d219ba9 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_mesh_union_with_attributes.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_mesh_union_with_attributes.cpp @@ -94,6 +94,7 @@ int main(int argc, char* argv[]) { std::cout << "Union was successfully computed\n"; std::ofstream output("union.off"); + output.precision(17); output << out; return 0; } diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_polyhedron_union.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_polyhedron_union.cpp index c6080f57f03..96d76e874a6 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_polyhedron_union.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/corefinement_polyhedron_union.cpp @@ -39,6 +39,7 @@ int main(int argc, char* argv[]) { std::cout << "Union was successfully computed\n"; std::ofstream output("union.off"); + output.precision(17); output << out; return 0; } diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_distance_remeshing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_distance_remeshing_example.cpp index 2830dc77768..1b032454d43 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_distance_remeshing_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hausdorff_distance_remeshing_example.cpp @@ -3,11 +3,7 @@ #include #include -#if defined(CGAL_LINKED_WITH_TBB) -#define TAG CGAL::Parallel_tag -#else -#define TAG CGAL::Sequential_tag -#endif +#define TAG CGAL::Parallel_if_available_tag typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef K::Point_3 Point; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hole_filling_example_SM.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hole_filling_example_SM.cpp index 47d9d9454e4..6eb8bd06195 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/hole_filling_example_SM.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/hole_filling_example_SM.cpp @@ -2,58 +2,96 @@ #include #include +#include + +#include #include #include #include +#include typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::Point_3 Point; typedef CGAL::Surface_mesh Mesh; -typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; +typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef boost::graph_traits::face_descriptor face_descriptor; -typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + +bool is_small_hole(halfedge_descriptor h, Mesh & mesh, + double max_hole_diam, int max_num_hole_edges) +{ + int num_hole_edges = 0; + CGAL::Bbox_3 hole_bbox; + for (halfedge_descriptor hc : CGAL::halfedges_around_face(h, mesh)) + { + const Point& p = mesh.point(target(hc, mesh)); + + hole_bbox += p.bbox(); + ++num_hole_edges; + + // Exit early, to avoid unnecessary traversal of large holes + if (num_hole_edges > max_num_hole_edges) return false; + if (hole_bbox.xmax() - hole_bbox.xmin() > max_hole_diam) return false; + if (hole_bbox.ymax() - hole_bbox.ymin() > max_hole_diam) return false; + if (hole_bbox.zmax() - hole_bbox.zmin() > max_hole_diam) return false; + } + + return true; +} + +// Incrementally fill the holes that are no larger than given diameter +// and with no more than a given number of edges (if specified). int main(int argc, char* argv[]) { const char* filename = (argc > 1) ? argv[1] : "data/mech-holes-shark.off"; - std::ifstream input(filename); + // Both of these must be positive in order to be considered + double max_hole_diam = (argc > 2) ? boost::lexical_cast(argv[2]): -1.0; + int max_num_hole_edges = (argc > 3) ? boost::lexical_cast(argv[3]) : -1; + + std::ifstream input(filename); Mesh mesh; if ( !input || !(input >> mesh) ) { std::cerr << "Not a valid off file." << std::endl; return 1; } - // Incrementally fill the holes unsigned int nb_holes = 0; - for(halfedge_descriptor h : halfedges(mesh)) - { - if(is_border(h,mesh)) - { - std::vector patch_facets; - std::vector patch_vertices; - bool success = std::get<0>( - CGAL::Polygon_mesh_processing::triangulate_refine_and_fair_hole( - mesh, - h, - std::back_inserter(patch_facets), - std::back_inserter(patch_vertices), - CGAL::Polygon_mesh_processing::parameters::vertex_point_map(get(CGAL::vertex_point, mesh)). - geom_traits(Kernel())) ); + std::vector border_cycles; - std::cout << "* Number of facets in constructed patch: " << patch_facets.size() << std::endl; - std::cout << " Number of vertices in constructed patch: " << patch_vertices.size() << std::endl; - std::cout << " Is fairing successful: " << success << std::endl; - nb_holes++; - } + // collect one halfedge per boundary cycle + CGAL::Polygon_mesh_processing::extract_boundary_cycles(mesh, std::back_inserter(border_cycles)); + + for(halfedge_descriptor h : border_cycles) + { + if(max_hole_diam > 0 && max_num_hole_edges > 0 && + !is_small_hole(h, mesh, max_hole_diam, max_num_hole_edges)) + continue; + + std::vector patch_facets; + std::vector patch_vertices; + bool success = std::get<0>( + CGAL::Polygon_mesh_processing::triangulate_refine_and_fair_hole( + mesh, + h, + std::back_inserter(patch_facets), + std::back_inserter(patch_vertices)) ); + + std::cout << "* Number of facets in constructed patch: " << patch_facets.size() << std::endl; + std::cout << " Number of vertices in constructed patch: " << patch_vertices.size() << std::endl; + std::cout << " Is fairing successful: " << success << std::endl; + ++nb_holes; } std::cout << std::endl; std::cout << nb_holes << " holes have been filled" << std::endl; - - std::ofstream out("filled_SM.off"); + + std::string outfile = "filled_SM.off"; + std::ofstream out(outfile.c_str()); + std::cout << "Mesh written to: " << outfile << std::endl; out.precision(17); out << mesh << std::endl; return 0; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_of_patch_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_of_patch_example.cpp index 52ce2fae96f..504dd5745f6 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_of_patch_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_of_patch_example.cpp @@ -74,6 +74,7 @@ int main(int argc, char* argv[]) ); std::ofstream out("out.off"); + out.precision(17); out << mesh; std::cout << "Remeshing done." << std::endl; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/mesh_smoothing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/mesh_smoothing_example.cpp index 6a1d5c2199a..ac081ec84ef 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/mesh_smoothing_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/mesh_smoothing_example.cpp @@ -48,6 +48,7 @@ int main(int argc, char** argv) .edge_is_constrained_map(eif)); std::ofstream output("mesh_smoothed.off"); + output.precision(17); output << mesh; std::cout << "Done!" << std::endl; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/orient_polygon_soup_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/orient_polygon_soup_example.cpp index 3c073c82c8b..2eec424e91c 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/orient_polygon_soup_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/orient_polygon_soup_example.cpp @@ -44,11 +44,13 @@ int main(int argc, char* argv[]) CGAL::Polygon_mesh_processing::orient_to_bound_a_volume(mesh); std::ofstream out("tet-oriented1.off"); + out.precision(17); out << mesh; out.close(); CGAL::Polygon_mesh_processing::reverse_face_orientations(mesh); std::ofstream out2("tet-oriented2.off"); + out2.precision(17); out2 << mesh; out2.close(); diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/random_perturbation_SM_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/random_perturbation_SM_example.cpp index 8d4d69dbe98..e040195334f 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/random_perturbation_SM_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/random_perturbation_SM_example.cpp @@ -33,6 +33,7 @@ int main(int argc, char* argv[]) PMP::parameters::vertex_point_map(mesh.points()).geom_traits(K())); std::ofstream out("data/eight_perturbed.off"); + out.precision(17); out << mesh; out.close(); diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/refine_fair_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/refine_fair_example.cpp index 253e76bb122..23b9af70099 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/refine_fair_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/refine_fair_example.cpp @@ -62,6 +62,7 @@ int main(int argc, char* argv[]) CGAL::Polygon_mesh_processing::parameters::density_control_factor(2.)); std::ofstream refined_off("refined.off"); + refined_off.precision(17); refined_off << poly; refined_off.close(); std::cout << "Refinement added " << new_vertices.size() << " vertices." << std::endl; @@ -75,6 +76,7 @@ int main(int argc, char* argv[]) std::cout << "Fairing : " << (success ? "succeeded" : "failed") << std::endl; std::ofstream faired_off("faired.off"); + faired_off.precision(17); faired_off << poly; faired_off.close(); diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/self_intersections_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/self_intersections_example.cpp index 93a2de84858..a44efca2da7 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/self_intersections_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/self_intersections_example.cpp @@ -2,12 +2,15 @@ #include #include +#include +#include +#include #include typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -typedef CGAL::Surface_mesh Mesh; -typedef boost::graph_traits::face_descriptor face_descriptor; +typedef CGAL::Surface_mesh Mesh; +typedef boost::graph_traits::face_descriptor face_descriptor; namespace PMP = CGAL::Polygon_mesh_processing; @@ -20,20 +23,25 @@ int main(int argc, char* argv[]) if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh)) { std::cerr << "Not a valid input file." << std::endl; - return 1; + return EXIT_FAILURE; } - bool intersecting = PMP::does_self_intersect(mesh, - PMP::parameters::vertex_point_map(get(CGAL::vertex_point, mesh))); + std::cout << "Using parallel mode? " << std::is_same::value << std::endl; - std::cout - << (intersecting ? "There are self-intersections." : "There is no self-intersection.") - << std::endl; + CGAL::Real_timer timer; + timer.start(); + + bool intersecting = PMP::does_self_intersect(mesh, CGAL::parameters::vertex_point_map(get(CGAL::vertex_point, mesh))); + std::cout << (intersecting ? "There are self-intersections." : "There is no self-intersection.") << std::endl; + std::cout << "Elapsed time (does self intersect): " << timer.time() << std::endl; + + timer.reset(); std::vector > intersected_tris; - PMP::self_intersections(mesh, std::back_inserter(intersected_tris)); - + PMP::self_intersections(faces(mesh), mesh, std::back_inserter(intersected_tris)); std::cout << intersected_tris.size() << " pairs of triangles intersect." << std::endl; - - return 0; + + std::cout << "Elapsed time (self intersections): " << timer.time() << std::endl; + + return EXIT_SUCCESS; } diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/self_snapping_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/self_snapping_example.cpp new file mode 100644 index 00000000000..c20c59a2172 --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/self_snapping_example.cpp @@ -0,0 +1,75 @@ +#include +#include + +#include +#include + +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; + +typedef Kernel::FT FT; +typedef Kernel::Point_3 Point_3; +typedef Kernel::Vector_3 Vector_3; +typedef CGAL::Surface_mesh Surface_mesh; + +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + +namespace PMP = CGAL::Polygon_mesh_processing; + +int main(int argc, char** argv) +{ + std::cout.precision(17); + + if(argc != 3) + { + std::cerr << "Usage: " << argv[0] << " input_mesh tolerance" << std::endl; + return EXIT_FAILURE; + } + + Surface_mesh sm; + std::ifstream in(argv[1]); + if(!in || in >> sm) + { + std::cerr << "Problem loading the input data" << std::endl; + return EXIT_FAILURE; + } + + Surface_mesh::Property_map tolerance_map; + tolerance_map = sm.add_property_map("v:t").first; + for(vertex_descriptor v : vertices(sm)) + put(tolerance_map, v, std::atof(argv[3])); + + std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); + + // Snap + std::size_t nb_snapped = PMP::experimental::snap_borders(sm, tolerance_map); + std::cout << "#snapped: " << nb_snapped << std::endl; + + std::chrono::steady_clock::time_point snap_time = std::chrono::steady_clock::now(); + std::cout << "Time elapsed (snap): " + << std::chrono::duration_cast(snap_time - start_time).count() + << "ms" << std::endl; + + // Stitch + std::cout << "Stitch, #ne: " << edges(sm).size() << std::endl; + PMP::stitch_borders(sm); + + std::chrono::steady_clock::time_point stitch_time = std::chrono::steady_clock::now(); + std::cout << "Time elapsed (stitch): " + << std::chrono::duration_cast(stitch_time - snap_time).count() + << "ms" << std::endl; + + std::chrono::steady_clock::time_point end_time = std::chrono::steady_clock::now(); + std::cout << "Total time elapsed: " + << std::chrono::duration_cast(end_time - start_time).count() + << "ms" << std::endl; + + std::cout << "#border: " << PMP::number_of_borders(sm) << std::endl; + std::cout << "Done!" << std::endl; + + std::ofstream("snapped.off") << std::setprecision(17) << sm; + + return EXIT_SUCCESS; +} diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/shape_smoothing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/shape_smoothing_example.cpp index fe6501c877e..6d5e7f75bd5 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/shape_smoothing_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/shape_smoothing_example.cpp @@ -41,6 +41,7 @@ int main(int argc, char* argv[]) .vertex_is_constrained_map(vcmap)); std::ofstream output("mesh_shape_smoothed.off"); + output.precision(17); output << mesh; std::cout << "Done!" << std::endl; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/snapping_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/snapping_example.cpp new file mode 100644 index 00000000000..b5bb4d913ed --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/snapping_example.cpp @@ -0,0 +1,78 @@ +#include +#include + +#include + +#include +#include + +typedef CGAL::Simple_cartesian Kernel; +typedef Kernel::Point_3 Point_3; +typedef CGAL::Surface_mesh Surface_mesh; + +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + +namespace PMP = CGAL::Polygon_mesh_processing; + +int main(int argc, char** argv) +{ + if(argc != 4) + { + std::cerr << "Usage: " << argv[0] << " movable_mesh fixed_mesh tolerance" << std::endl; + return EXIT_FAILURE; + } + + Surface_mesh movable_mesh, fixed_mesh; + + std::ifstream in_m(argv[1]); + if(!in_m || in_m >> movable_mesh) + { + std::cerr << "Problem loading the input data" << std::endl; + return EXIT_FAILURE; + } + + std::ifstream in_f(argv[2]); + if(!in_f || in_f >> fixed_mesh) + { + std::cerr << "Problem loading the input data" << std::endl; + return EXIT_FAILURE; + } + + std::cout << "Movable mesh: " << num_vertices(movable_mesh) << std::endl; + std::cout << "Fixed mesh: " << num_vertices(fixed_mesh) << std::endl; + + const double tolerance = std::atof(argv[3]); + + Surface_mesh::Property_map movable_tolerance_map; + movable_tolerance_map = movable_mesh.add_property_map("v:t").first; + for(vertex_descriptor v : vertices(movable_mesh)) + put(movable_tolerance_map, v, tolerance); + + Surface_mesh::Property_map fixed_tolerance_map; + fixed_tolerance_map = fixed_mesh.add_property_map("v:t").first; + for(vertex_descriptor v : vertices(fixed_mesh)) + put(fixed_tolerance_map, v, tolerance); + + std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); + + // Choice of named parameters indicates that: + // - We want to simplify the boundary of the first mesh + // - The geometry of the second mesh cannot change + std::size_t nb_snapped = PMP::experimental::snap_borders(movable_mesh, movable_tolerance_map, + fixed_mesh, fixed_tolerance_map, + CGAL::parameters::do_simplify_border(true), + CGAL::parameters::do_lock_mesh(true)); + + std::chrono::steady_clock::time_point end_time = std::chrono::steady_clock::now(); + + std::cout << "Time elapsed: " + << std::chrono::duration_cast(end_time - start_time).count() + << "ms" << std::endl; + + std::cout << "#Snapped: " << nb_snapped << std::endl; + + std::ofstream("snapped_movable.off") << std::setprecision(17) << movable_mesh; + std::ofstream("snapped_fixed.off") << std::setprecision(17) << fixed_mesh; + + return EXIT_SUCCESS; +} diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/stitch_borders_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/stitch_borders_example.cpp index 89ff02c4405..bd364a60773 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/stitch_borders_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/stitch_borders_example.cpp @@ -34,6 +34,7 @@ int main(int argc, char* argv[]) std::cout << "\t Number of facets :\t" << mesh.size_of_facets() << std::endl; std::ofstream output("mesh_stitched.off"); + output.precision(17); output << std::setprecision(17) << mesh; return 0; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/surface_mesh_intersection.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/surface_mesh_intersection.cpp index d519723fd02..20ccbf2da0f 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/surface_mesh_intersection.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/surface_mesh_intersection.cpp @@ -43,6 +43,7 @@ int main(int argc, char* argv[]) //dump polylines std::ofstream output("intersection_polylines.cgal"); + output.precision(17); for(const std::vector& polyline : polylines) { output << polyline.size() << " "; diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/triangulate_faces_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/triangulate_faces_example.cpp index 94d1a0f8aff..63528119d44 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/triangulate_faces_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/triangulate_faces_example.cpp @@ -32,6 +32,7 @@ int main(int argc, char* argv[]) std::cerr << "Error: non-triangular face left in mesh." << std::endl; std::ofstream cube_off(outfilename); + cube_off.precision(17); cube_off << mesh; return 0; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Weights.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Weights.h index 6d3acdabec1..8aee6e620dc 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Weights.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Weights.h @@ -55,8 +55,8 @@ struct Cotangent_value_Meyer_impl if(divider == 0 /*|| divider != divider*/) { CGAL::collinear(get(ppmap, v0), get(ppmap, v1), get(ppmap, v2)) ? - CGAL_warning(!"Infinite Cotangent value with degenerate triangle!") : - CGAL_warning(!"Infinite Cotangent value due to floating point arithmetic!"); + CGAL_warning_msg(false, "Infinite Cotangent value with degenerate triangle!") : + CGAL_warning_msg(false, "Infinite Cotangent value due to floating point arithmetic!"); return dot_ab > 0 ? (std::numeric_limits::max)() : @@ -341,7 +341,7 @@ public: } } } - CGAL_warning(voronoi_area != 0 && "Zero voronoi area!"); + CGAL_warning_msg(voronoi_area != 0, "Zero voronoi area!"); return voronoi_area; } }; @@ -806,7 +806,7 @@ public: Vector v = target(he, pmesh())->point() - source(he, pmesh())->point(); double divider = CGAL::sqrt(v.squared_length()); if(divider == 0.0) { - CGAL_warning(!"Scale dependent weight - zero length edge."); + CGAL_warning_msg(false, "Scale dependent weight - zero length edge."); return (std::numeric_limits::max)(); } return 1.0 / divider; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/bbox.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/bbox.h index 98ccd731d31..3c3789d35d4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/bbox.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/bbox.h @@ -68,12 +68,13 @@ namespace CGAL { { using parameters::choose_parameter; using parameters::get_parameter; + typename GetVertexPointMap::const_type vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(CGAL::vertex_point, pmesh)); + get_const_property_map(CGAL::vertex_point, pmesh)); typedef typename GetGeomTraits::type GT; - GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT()); + GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); typename GT::Construct_bbox_3 get_bbox = gt.construct_bbox_3_object(); typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; @@ -120,10 +121,10 @@ namespace CGAL { using parameters::get_parameter; typename GetVertexPointMap::const_type vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(CGAL::vertex_point, pmesh)); + get_const_property_map(CGAL::vertex_point, pmesh)); typedef typename GetGeomTraits::type GT; - GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT()); + GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); typename GT::Construct_bbox_3 get_bbox = gt.construct_bbox_3_object(); return get_bbox( get(vpm, vd) ); @@ -161,12 +162,13 @@ namespace CGAL { { using parameters::choose_parameter; using parameters::get_parameter; + typename GetVertexPointMap::const_type vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(CGAL::vertex_point, pmesh)); + get_const_property_map(CGAL::vertex_point, pmesh)); typedef typename GetGeomTraits::type GT; - GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT()); + GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); typename GT::Construct_bbox_3 get_bbox = gt.construct_bbox_3_object(); return get_bbox( get(vpm, source(ed, pmesh)) ) + @@ -205,12 +207,13 @@ namespace CGAL { { using parameters::choose_parameter; using parameters::get_parameter; + typename GetVertexPointMap::const_type vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(CGAL::vertex_point, pmesh)); + get_const_property_map(CGAL::vertex_point, pmesh)); typedef typename GetGeomTraits::type GT; - GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT()); + GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); typename GT::Construct_bbox_3 get_bbox = gt.construct_bbox_3_object(); typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/border.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/border.h index 54a520908e0..c52695b90cf 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/border.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/border.h @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -28,13 +29,31 @@ namespace CGAL{ namespace Polygon_mesh_processing { +namespace internal { - namespace internal +template +std::size_t border_size(typename boost::graph_traits::halfedge_descriptor h, + const PolygonMesh& pmesh) +{ + // if you want to use it on a non-border halfedge, just use `degree(face, mesh)` + CGAL_precondition(is_border(h, pmesh)); + + std::size_t res = 0; + typename boost::graph_traits::halfedge_descriptor done = h; + do { + ++res; + h = next(h, pmesh); + } + while(h != done); + + return res; +} + template - HalfedgeOutputIterator border_halfedges_impl(const FaceRange& faces + HalfedgeOutputIterator border_halfedges_impl(const FaceRange& face_range , HalfedgeOutputIterator out , const PM& pmesh) { @@ -45,7 +64,7 @@ namespace Polygon_mesh_processing { // the bool is true if the halfedge stored is the one of the face, // false if it is its opposite std::map border; - for(face_descriptor f : faces) + for(face_descriptor f : face_range) { for(halfedge_descriptor h : halfedges_around_face(halfedge(f, pmesh), pmesh)) @@ -75,13 +94,13 @@ namespace Polygon_mesh_processing { , typename FaceRange , typename HalfedgeOutputIterator , typename NamedParameters> - HalfedgeOutputIterator border_halfedges_impl(const FaceRange& faces + HalfedgeOutputIterator border_halfedges_impl(const FaceRange& face_range , typename boost::cgal_no_property::type , HalfedgeOutputIterator out , const PM& pmesh , const NamedParameters& /* np */) { - return border_halfedges_impl(faces, out, pmesh); + return border_halfedges_impl(face_range, out, pmesh); } template - HalfedgeOutputIterator border_halfedges_impl(const FaceRange& faces + HalfedgeOutputIterator border_halfedges_impl(const FaceRange& face_range , const FaceIndexMap& fmap , HalfedgeOutputIterator out , const PM& pmesh @@ -98,25 +117,13 @@ namespace Polygon_mesh_processing { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; - //make a minimal check that it's properly initialized : - //if the 2 first faces have the same id, we know the property map is not initialized - if (boost::is_same::Is_internal_map, - boost::true_type>::value) - { - typename boost::range_iterator::type it = boost::const_begin(faces); - if (get(fmap, *it) == get(fmap, *std::next(it))) - { - std::cerr << "WARNING : the internal property map for CGAL::face_index_t" << std::endl - << " is not properly initialized." << std::endl - << " Initialize it before calling border_halfedges()" << std::endl; - } - } + CGAL_assertion(BGL::internal::is_index_map_valid(fmap, num_faces(pmesh), faces(pmesh))); std::vector present(num_faces(pmesh), false); - for(face_descriptor fd : faces) + for(face_descriptor fd : face_range) present[get(fmap, fd)] = true; - for(face_descriptor fd : faces) + for(face_descriptor fd : face_range) for(halfedge_descriptor hd : halfedges_around_face(halfedge(fd, pmesh), pmesh)) { @@ -142,21 +149,16 @@ namespace Polygon_mesh_processing { * For each returned halfedge `h`, `opposite(h, pmesh)` belongs to a face of the patch, * but `face(h, pmesh)` does not belong to the patch. * - * @tparam PolygonMesh model of `HalfedgeGraph`. If `PolygonMesh` - * has an internal property map - * for `CGAL::face_index_t` and no `face_index_map` is given - * as a named parameter, then the internal one must be initialized - * @tparam FaceRange range of - `boost::graph_traits::%face_descriptor`, model of `Range`. - Its iterator type is `InputIterator`. + * @tparam PolygonMesh model of `HalfedgeGraph` + * @tparam FaceRange a model of `Range` with value type `boost::graph_traits::%face_descriptor`. * @tparam HalfedgeOutputIterator model of `OutputIterator` holding `boost::graph_traits::%halfedge_descriptor` for patch border * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" * - * @param pmesh the polygon mesh to which `faces` belong - * @param faces the range of faces defining the patch whose border halfedges - * are collected + * @param pmesh the polygon mesh to which the faces in `face_range` belong + * @param face_range the range of faces defining the patch whose border halfedges + * are collected * @param out the output iterator that collects the border halfedges of the patch, * seen from outside. * @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below @@ -171,29 +173,18 @@ namespace Polygon_mesh_processing { , typename FaceRange , typename HalfedgeOutputIterator , typename NamedParameters> - HalfedgeOutputIterator border_halfedges(const FaceRange& faces + HalfedgeOutputIterator border_halfedges(const FaceRange& face_range , const PolygonMesh& pmesh , HalfedgeOutputIterator out , const NamedParameters& np) { - if (faces.empty()) return out; + if (face_range.empty()) + return out; - typedef PolygonMesh PM; - typedef typename GetFaceIndexMap::const_type FIMap; - typedef typename boost::property_map::type Unset_FIMap; + typedef typename CGAL::GetInitializedFaceIndexMap::const_type FIMap; + FIMap fim = CGAL::get_initialized_face_index_map(pmesh, np); - if (boost::is_same::value || faces.size() == 1) - { - //face index map is not given in named parameters, nor as an internal property map - return internal::border_halfedges_impl(faces, out, pmesh); - } - - //face index map given as a named parameter, or as an internal property map - FIMap fim = parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), - get_const_property_map(CGAL::face_index, pmesh)); - - return internal::border_halfedges_impl(faces, fim, out, pmesh, np); + return internal::border_halfedges_impl(face_range, fim, out, pmesh, np); } template - HalfedgeOutputIterator border_halfedges(const FaceRange& faces + HalfedgeOutputIterator border_halfedges(const FaceRange& face_range , const PolygonMesh& pmesh , HalfedgeOutputIterator out) { - return border_halfedges(faces, pmesh, out, + return border_halfedges(face_range, pmesh, out, CGAL::Polygon_mesh_processing::parameters::all_default()); } @@ -225,7 +216,7 @@ namespace Polygon_mesh_processing { // // @tparam PolygonMesh model of `HalfedgeGraph`. // - // @param pmesh the polygon mesh to which `faces` belong + // @param pmesh the polygon mesh to which `face_range` belong // template unsigned int number_of_borders(const PolygonMesh& pmesh) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h index 0b2e28fd8fa..05ca9388ebb 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h @@ -15,15 +15,25 @@ #include - #include #include #include #include #include +#include +#include +#include +#include #include +#include +#include + +#include + +#include + namespace CGAL{ namespace Polygon_mesh_processing { @@ -40,10 +50,10 @@ inter_pt_index(int i, int j, std::pair, int>::iterator, bool> res = id_map.insert(std::make_pair(make_sorted_pair(i,j), static_cast (points.size()))); - if (res.second) + if(res.second) points.push_back( typename Geom_traits::Construct_plane_line_intersection_point_3() - (plane, points[i], points[j]) ); + (plane, points[i], points[j])); return res.first->second; } @@ -55,7 +65,7 @@ Oriented_side clip_to_bbox(const Plane_3& plane, const Bbox_3& bbox, TriangleMesh& tm_out, - const NamedParameters& np ) + const NamedParameters& np) { typedef typename GetGeomTraits::type Geom_traits; typedef typename Geom_traits::Point_3 Point_3; @@ -63,7 +73,7 @@ clip_to_bbox(const Plane_3& plane, NamedParameters>::type Vpm; Vpm vpm_out = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point), - get_property_map(boost::vertex_point, tm_out)); + get_property_map(boost::vertex_point, tm_out)); std::vector corners(8); @@ -103,9 +113,9 @@ clip_to_bbox(const Plane_3& plane, std::set in_point_ids; // to collect the set of points in the clipped bbox // for each face of the bbox, we look for intersection of the plane with its edges - for (int i=0; i<6; ++i) + for(int i=0; i<6; ++i) { - for (int k=0; k< 4; ++k) + for(int k=0; k< 4; ++k) { int current_id = face_indices[4*i + k]; int next_id = face_indices[4*i + (k+1)%4]; @@ -116,14 +126,14 @@ clip_to_bbox(const Plane_3& plane, { all_out=false; // point on or on the negative side - output_faces[i].push_back( current_id ); - in_point_ids.insert( output_faces[i].back() ); + output_faces[i].push_back(current_id); + in_point_ids.insert(output_faces[i].back()); // check for intersection of the edge - if (orientations[ next_id ] == ON_POSITIVE_SIDE) + if(orientations[ next_id ] == ON_POSITIVE_SIDE) { output_faces[i].push_back( - inter_pt_index(current_id, next_id, plane, corners, id_map) ); - in_point_ids.insert( output_faces[i].back() ); + inter_pt_index(current_id, next_id, plane, corners, id_map)); + in_point_ids.insert(output_faces[i].back()); } break; } @@ -131,31 +141,31 @@ clip_to_bbox(const Plane_3& plane, { all_in = false; // check for intersection of the edge - if ( orientations[ next_id ] == ON_NEGATIVE_SIDE ) + if(orientations[ next_id ] == ON_NEGATIVE_SIDE) { output_faces[i].push_back( - inter_pt_index(current_id, next_id, plane, corners, id_map) ); - in_point_ids.insert( output_faces[i].back() ); + inter_pt_index(current_id, next_id, plane, corners, id_map)); + in_point_ids.insert(output_faces[i].back()); } break; } case ON_ORIENTED_BOUNDARY: { - output_faces[i].push_back( current_id ); - in_point_ids.insert( output_faces[i].back() ); + output_faces[i].push_back(current_id); + in_point_ids.insert(output_faces[i].back()); } } } - if (output_faces[i].size() < 3){ + if(output_faces[i].size() < 3){ CGAL_assertion(output_faces[i].empty() || - (output_faces[i].front()<8 && output_faces[i].back()<8) ); + (output_faces[i].front()<8 && output_faces[i].back()<8)); output_faces[i].clear(); // edge of the bbox included in the plane } } // the intersection is the full bbox - if (all_in) return ON_NEGATIVE_SIDE; - if (all_out) return ON_POSITIVE_SIDE; + if(all_in) return ON_NEGATIVE_SIDE; + if(all_out) return ON_POSITIVE_SIDE; // build the clipped bbox typedef boost::graph_traits graph_traits; @@ -167,7 +177,7 @@ clip_to_bbox(const Plane_3& plane, for(int i : in_point_ids) { vertex_descriptor v = add_vertex(tm_out); - out_vertices.insert( std::make_pair(i, v ) ); + out_vertices.insert(std::make_pair(i, v)); put(vpm_out, v, corners[i]); } @@ -176,7 +186,7 @@ clip_to_bbox(const Plane_3& plane, const face_descriptor null_fd = graph_traits::null_face(); for(const std::vector& findices : output_faces) { - if (findices.empty()) continue; + if(findices.empty()) continue; const face_descriptor fd=add_face(tm_out); int prev_id = findices.back(); @@ -189,12 +199,12 @@ clip_to_bbox(const Plane_3& plane, std::pair, halfedge_descriptor>::iterator, bool> res = - hedge_map.insert( std::make_pair(std::make_pair(prev_id, current_id), null_hedge) ); - if (res.second) + hedge_map.insert(std::make_pair(std::make_pair(prev_id, current_id), null_hedge)); + if(res.second) { - res.first->second = halfedge( add_edge(tm_out), tm_out); - hedge_map.insert( std::make_pair(std::make_pair(current_id, prev_id), - opposite(res.first->second, tm_out) ) ); + res.first->second = halfedge(add_edge(tm_out), tm_out); + hedge_map.insert(std::make_pair(std::make_pair(current_id, prev_id), + opposite(res.first->second, tm_out))); set_face(opposite(res.first->second, tm_out), null_fd, tm_out); } @@ -208,7 +218,7 @@ clip_to_bbox(const Plane_3& plane, set_halfedge(src, opposite(hedges.back(), tm_out), tm_out); set_halfedge(tgt, hedges.back(), tm_out); - if (current_id==findices.front()) + if(current_id==findices.front()) set_halfedge(fd, hedges.back(), tm_out); prev_id = current_id; @@ -230,7 +240,7 @@ clip_to_bbox(const Plane_3& plane, // until we reach another border halfedge for(halfedge_descriptor h : halfedges(tm_out)) { - if (face(h, tm_out) == null_fd) + if(face(h, tm_out) == null_fd) { face_descriptor fd = add_face(tm_out); set_halfedge(fd, h, tm_out); @@ -244,7 +254,7 @@ clip_to_bbox(const Plane_3& plane, } while(face(h_curr, tm_out) != null_fd && h_curr!=h); set_face(h_prev, fd, tm_out); set_next(h_prev, h_curr, tm_out); - if (h_curr==h) + if(h_curr==h) break; h_prev=h_curr; } while(true); @@ -259,6 +269,137 @@ clip_to_bbox(const Plane_3& plane, return ON_ORIENTED_BOUNDARY; } +template +void split_along_edges(TriangleMesh& tm, + Ecm ecm, + VPM vpm) +{ + typedef boost::graph_traits GT; + typedef typename GT::face_descriptor face_descriptor; + typedef typename GT::edge_descriptor edge_descriptor; + typedef typename GT::vertex_descriptor vertex_descriptor; + typedef typename GT::halfedge_descriptor halfedge_descriptor; + + std::vector shared_edges; + for(edge_descriptor e : edges(tm)) + if(get(ecm, e)) + shared_edges.push_back(e); + + std::size_t nb_shared_edges = shared_edges.size(); + std::vector hedges_to_update; + + typedef CGAL::dynamic_halfedge_property_t H_tag; + typename boost::property_map::type + no_target_update = get(H_tag(), tm); + + std::vector< std::pair > vertices_to_duplicate; + + //collect border halfedges having as target one of the edge endpoints + std::set extra_border_hedges; + for(std::size_t k=0; k& p : vertices_to_duplicate) + { + vertex_descriptor nv = add_vertex(tm); + put(vpm, nv, get(vpm, p.second)); + for(halfedge_descriptor h : halfedges_around_target(p.first, tm)) + set_target(h, nv, tm); + set_halfedge(nv, p.first, tm); + } + + CGAL_assertion_code(for(halfedge_descriptor h : hedges_to_update)) + { + CGAL_assertion(next(prev(h, tm), tm) == h); + CGAL_assertion(prev(next(h, tm), tm) == h); + } + + for(halfedge_descriptor h : hedges_to_update) + { + for(halfedge_descriptor hh : halfedges_around_target(h, tm)) + if(h!=hh) + set_target(hh, target(h, tm), tm); + } + + CGAL_assertion(is_valid_polygon_mesh(tm)); +} + } // end of internal namespace /** @@ -266,17 +407,14 @@ clip_to_bbox(const Plane_3& plane, * clips `tm` by keeping the part that is inside the volume \link coref_def_subsec bounded \endlink * by `clipper`. * If `tm` is closed, the clipped part can be closed too if the named parameter `clip_volume` is set to `true`. - * See subsection \ref coref_clip for more details. + * See Subsection \ref coref_clip for more details. * \attention With the current implementation, `clipper` will be modified (refined with the intersection with `tm`). * - * \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(tm1)` \endlink + * \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(tm)` \endlink * \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(clipper)` \endlink * \pre \link CGAL::Polygon_mesh_processing::does_bound_a_volume() `CGAL::Polygon_mesh_processing::does_bound_a_volume(clipper)` \endlink * * @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`. - * If `TriangleMesh` has an internal property map for `CGAL::face_index_t`, - * as a named parameter, then it must be initialized. - * * @tparam NamedParameters1 a sequence of \ref pmp_namedparameters "Named Parameters" * @tparam NamedParameters2 a sequence of \ref pmp_namedparameters "Named Parameters" * @@ -291,9 +429,8 @@ clip_to_bbox(const Plane_3& plane, * If this parameter is omitted, an internal property map for * `CGAL::vertex_point_t` must be available in `TriangleMesh` * \cgalParamEnd - * \cgalParamBegin{face_index_map} a property map containing the index of each face of `tm` (`clipper`). - * Note that if the property map is writable, the indices of the faces - * of `tm` and `clipper` will be set after refining `tm` with the intersection with `clipper`. + * \cgalParamBegin{face_index_map} + * a property map containing a unique index for each face of `tm` (`clipper`). * \cgalParamEnd * \cgalParamBegin{visitor} a class model of `PMPCorefinementVisitor` * that is used to track the creation of new faces. @@ -301,14 +438,14 @@ clip_to_bbox(const Plane_3& plane, * \cgalParamBegin{throw_on_self_intersection} if `true`, * the set of triangles closed to the intersection of `tm` and `clipper` will be * checked for self-intersections and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception` - * will be thrown if at least one is found. + * will be thrown if at least one is found. Default value is `false`. * \cgalParamEnd * \cgalParamBegin{clip_volume} if `true` and `tm` is closed, the clipping will be done on * the volume \link coref_def_subsec bounded \endlink by `tm` rather than on its surface - * (i.e. `tm` will be kept closed). + * (i.e., `tm` will be kept closed). Default value is `false`. * \cgalParamEnd - * \cgalParamBegin{use_compact_clipper} if `false` and `clip_volume` is `false` and `tm` is open, the parts of `tm` coplanar with `clipper` - * will not be part of the output. + * \cgalParamBegin{use_compact_clipper} if `false`, the parts of `tm` coplanar with `clipper` + * will not be part of the output. Default value is `true`. * \cgalParamEnd * \cgalNamedParamsEnd * @@ -319,53 +456,32 @@ template bool -clip( TriangleMesh& tm, - TriangleMesh& clipper, +clip(TriangleMesh& tm, + TriangleMesh& clipper, const NamedParameters1& np_tm, const NamedParameters2& np_c) { const bool clip_volume = parameters::choose_parameter(parameters::get_parameter(np_tm, internal_np::clip_volume), false); - if (clip_volume && is_closed(tm)) + if(clip_volume && is_closed(tm)) return corefine_and_compute_intersection(tm, clipper, tm, np_tm, np_c); return corefine_and_compute_intersection(tm, clipper, tm, np_tm.use_bool_op_to_clip_surface(true), np_c); } -namespace internal{ -template -bool dispatch_clip_call(TriangleMesh& tm, TriangleMesh& clipper, - const NamedParameters& np, Tag_false) -{ - return clip(tm, clipper, - np.face_index_map(get(CGAL::dynamic_face_property_t(), tm)), - parameters::face_index_map(get(CGAL::dynamic_face_property_t(), clipper))); -} - -template -bool dispatch_clip_call(TriangleMesh& tm, TriangleMesh& clipper, - const NamedParameters& np, Tag_true) -{ - return clip(tm, clipper, - np.face_index_map(get(face_index, tm)), - parameters::face_index_map(get(face_index, clipper))); -} -} - /** * \ingroup PMP_corefinement_grp * clips `tm` by keeping the part that is on the negative side of `plane` (side opposite to its normal vector). * If `tm` is closed, the clipped part can be closed too if the named parameter `clip_volume` is set to `true`. - * See subsection \ref coref_clip for more details. + * See Subsection \ref coref_clip for more details. * - * \note In the current implementation it is not possible to set the vertex point map and the default will be used. + * \note In the current implementation it is not possible to set the vertex point map and the default will be used. `Plane_3` must be + * from the same %Kernel as the point of the vertex point map. * \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(tm)` \endlink * * @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`. - * If `TriangleMesh` has an internal property map for `CGAL::face_index_t`, - * as a named parameter, then it must be initialized. * An internal property map for `CGAL::vertex_point_t` must be available. * * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" @@ -382,14 +498,14 @@ bool dispatch_clip_call(TriangleMesh& tm, TriangleMesh& clipper, * \cgalParamBegin{throw_on_self_intersection} if `true`, * the set of triangles closed to the intersection of `tm` and `plane` will be * checked for self-intersections and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception` - * will be thrown if at least one is found. + * will be thrown if at least one is found. Default value is `false`. * \cgalParamEnd * \cgalParamBegin{clip_volume} if `true` and `tm` is closed, the clipping will be done on * the volume \link coref_def_subsec bounded \endlink by `tm` rather than on its surface - * (i.e. `tm` will be kept closed). + * (i.e., `tm` will be kept closed). Default value is `false`. * \cgalParamEnd - * \cgalParamBegin{use_compact_clipper} if `false` and `clip_volume` is `false` and `tm` is open, the parts of `tm` coplanar with `plane` - * will not be part of the output. + * \cgalParamBegin{use_compact_clipper} if `false` the parts of `tm` coplanar with `plane` + * will not be part of the output. Default value is `true`. * \cgalNamedParamsEnd * * @return `true` if the output surface mesh is manifold. @@ -397,15 +513,15 @@ bool dispatch_clip_call(TriangleMesh& tm, TriangleMesh& clipper, */ template -bool clip( TriangleMesh& tm, - #ifdef DOXYGEN_RUNNING +bool clip(TriangleMesh& tm, +#ifdef DOXYGEN_RUNNING const Plane_3& plane, - #else +#else const typename GetGeomTraits::type::Plane_3& plane, - #endif +#endif const NamedParameters& np) { - if( boost::begin(faces(tm))==boost::end(faces(tm)) ) return true; + if(boost::begin(faces(tm))==boost::end(faces(tm))) return true; CGAL::Bbox_3 bbox = ::CGAL::Polygon_mesh_processing::bbox(tm); @@ -427,27 +543,227 @@ bool clip( TriangleMesh& tm, default: break; } - // dispatch is needed because face index map for tm and clipper have to be of the same time - return internal::dispatch_clip_call(tm, clipper, - np, CGAL::graph_has_property()); + + return clip(tm, clipper, np, parameters::all_default()); +} + + +/*! + * \ingroup PMP_corefinement_grp + * corefines `tm` and `splitter` and duplicates edges in `tm` that are on the intersection with `splitter`. + * + * \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(tm)` \endlink + * \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(splitter)` \endlink + * + * @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`. + * + * @tparam NamedParameters1 a sequence of \ref pmp_namedparameters "Named Parameters" + * @tparam NamedParameters2 a sequence of \ref pmp_namedparameters "Named Parameters" + * + * @param tm input triangulated surface mesh + * @param splitter triangulated surface mesh used to split `tm` + * @param np_tm optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below + * @param np_s 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 `tm` (`splitter`). + * If this parameter is omitted, an internal property map for + * `CGAL::vertex_point_t` must be available in `TriangleMesh` + * \cgalParamEnd + * \cgalParamBegin{visitor} a class model of `PMPCorefinementVisitor` + * that is used to track the creation of new faces. + * \cgalParamEnd + * \cgalParamBegin{throw_on_self_intersection} if `true`, + * the set of triangles closed to the intersection of `tm` and `splitter` will be + * checked for self-intersections and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception` + * will be thrown if at least one is found. + * \cgalParamEnd + * \cgalNamedParamsEnd +*/ +template +void split(TriangleMesh& tm, + TriangleMesh& splitter, + const NamedParameters1& np_tm, + const NamedParameters2& np_s) +{ + namespace PMP = CGAL::Polygon_mesh_processing; + + using parameters::get_parameter; + using parameters::choose_parameter; + + typedef typename GetVertexPointMap::type VPM1; + typedef typename GetVertexPointMap::type VPM2; + + typedef typename boost::template property_map >::type Ecm; + + VPM1 vpm_tm = choose_parameter(get_parameter(np_tm, internal_np::vertex_point), + get_property_map(vertex_point, tm)); + VPM2 vpm_s = choose_parameter(get_parameter(np_s, internal_np::vertex_point), + get_property_map(vertex_point, splitter)); + + Ecm ecm = get(CGAL::dynamic_edge_property_t(), tm); + + // create a constrained edge map and corefine input mesh with the splitter, + // and mark edges + + PMP::corefine(tm, splitter, + CGAL::parameters::vertex_point_map(vpm_tm).edge_is_constrained_map(ecm), + CGAL::parameters::vertex_point_map(vpm_s)); + + //split mesh along marked edges + internal::split_along_edges(tm, ecm, vpm_tm); +} + +/** + * \ingroup PMP_corefinement_grp + * adds intersection edges of `plane` and `tm` in `tm` and duplicates those edges. + * + * \note In the current implementation it is not possible to set the vertex point map and the default will be used. + * \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(tm)` \endlink + * + * @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph` + * An internal property map for `CGAL::vertex_point_t` must be available. + * + * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" + * + * @param tm input triangulated surface mesh + * @param plane the plane that will be used to split `tm`. + * `Plane_3` is the plane type for the same CGAL kernel as the point of the vertex point map of `tm`. + * @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 `tm`. + * \cgalParamEnd + * \cgalParamBegin{visitor} a class model of `PMPCorefinementVisitor` + * that is used to track the creation of new faces. + * \cgalParamEnd + * \cgalParamBegin{throw_on_self_intersection} if `true`, + * the set of triangles closed to the intersection of `tm` and `plane` will be + * checked for self-intersections and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception` + * will be thrown if at least one is found. + * \cgalParamEnd + * \cgalNamedParamsEnd + */ +template +void split(TriangleMesh& tm, +#ifdef DOXYGEN_RUNNING + const Plane_3& plane, +#else + const typename GetGeomTraits::type::Plane_3& plane, +#endif + const NamedParameters& np) +{ + using parameters::get_parameter; + using parameters::choose_parameter; + namespace PMP = CGAL::Polygon_mesh_processing; + namespace params = PMP::parameters; + + // create a splitter mesh for the splitting plane using an internal CGAL function + CGAL::Bbox_3 bbox = ::CGAL::Polygon_mesh_processing::bbox(tm, np); + double xd = (std::max)(1., 0.01 * (bbox.xmax() - bbox.xmin())); + double yd = (std::max)(1., 0.01 * (bbox.ymax() - bbox.ymin())); + double zd = (std::max)(1., 0.01 * (bbox.zmax() - bbox.zmin())); + bbox = CGAL::Bbox_3(bbox.xmin()-xd, bbox.ymin()-yd, bbox.zmin()-zd, + bbox.xmax()+xd, bbox.ymax()+yd, bbox.zmax()+zd); + + TriangleMesh splitter; + CGAL::Oriented_side os = PMP::internal::clip_to_bbox(plane, bbox, splitter, PMP::parameters::all_default()); + + if(os == CGAL::ON_ORIENTED_BOUNDARY) + return split(tm, splitter, np, params::all_default()); + + //else nothing to do, no intersection. +} + +/** + * \ingroup PMP_corefinement_grp + * clips `tm` by keeping the part that is inside `iso_cuboid`. + * If `tm` is closed, the clipped part can be closed too if the named parameter `clip_volume` is set to `true`. + * See Subsection \ref coref_clip for more details. + * + * \note In the current implementation it is not possible to set the vertex point map and the default will be used. `Iso_cuboid_3` must be + * from the same %Kernel as the point of the vertex point map. + * \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(tm)` \endlink + * + * @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`. + * An internal property map for `CGAL::vertex_point_t` must be available. + * + * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" + * + * @param tm input triangulated surface mesh + * @param iso_cuboid iso-cuboid used to clip `tm`. + * @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below + * + * \cgalNamedParamsBegin + * \cgalParamBegin{visitor} a class model of `PMPCorefinementVisitor` + * that is used to track the creation of new faces. + * \cgalParamEnd + * \cgalParamBegin{throw_on_self_intersection} if `true`, + * the set of triangles closed to the intersection of `tm` and `iso_cuboid` will be + * checked for self-intersections and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception` + * will be thrown if at least one is found. + * \cgalParamEnd + * \cgalParamBegin{clip_volume} if `true` and `tm` is closed, the clipping will be done on + * the volume \link coref_def_subsec bounded \endlink by `tm` rather than on its surface + * (i.e., `tm` will be kept closed). + * \cgalParamEnd + * \cgalParamBegin{use_compact_clipper} if `false` and `clip_volume` is `false` and `tm` is open, the parts of `tm` coplanar with `is_cuboid` + * will not be part of the output. + * \cgalNamedParamsEnd + * + * @return `true` if the output surface mesh is manifold. + * If `false` is returned `tm` is only refined by the intersection with `iso_cuboid`. + */ +template +bool clip(TriangleMesh& tm, +#ifdef DOXYGEN_RUNNING + const Iso_cuboid_3& iso_cuboid, +#else + const typename GetGeomTraits::type::Iso_cuboid_3& iso_cuboid, +#endif + const NamedParameters& np) +{ + if(boost::begin(faces(tm))==boost::end(faces(tm))) return true; + TriangleMesh clipper; + + make_hexahedron(iso_cuboid[0], iso_cuboid[1], iso_cuboid[2], iso_cuboid[3], + iso_cuboid[4], iso_cuboid[5], iso_cuboid[6], iso_cuboid[7], + clipper); + triangulate_faces(clipper); + + return clip(tm, clipper, np, parameters::all_default()); } /// \cond SKIP_IN_MANUAL // convenience overloads template -bool clip( TriangleMesh& tm, +bool clip(TriangleMesh& tm, const typename GetGeomTraits::type::Plane_3& plane) { return clip(tm, plane, parameters::all_default()); } +// convenience overloads +template +bool clip(TriangleMesh& tm, + const typename GetGeomTraits::type::Iso_cuboid_3& iso_cuboid) +{ + return clip(tm, iso_cuboid, parameters::all_default()); +} + // convenience overload template bool -clip( TriangleMesh& tm, - TriangleMesh& clipper, +clip(TriangleMesh& tm, + TriangleMesh& clipper, const NamedParameters1& np_tm) { return clip(tm, clipper, np_tm, parameters::all_default()); @@ -456,11 +772,40 @@ clip( TriangleMesh& tm, // convenience overload template bool -clip( TriangleMesh& tm, - TriangleMesh& clipper) +clip(TriangleMesh& tm, + TriangleMesh& clipper) { return clip(tm, clipper, parameters::all_default()); } + + +// convenience overload +template +void +split(TriangleMesh& tm, + TriangleMesh& splitter, + const NamedParameters1& np_tm) +{ + split(tm, splitter, np_tm, parameters::all_default()); +} + +// convenience overload +template +void +split(TriangleMesh& tm, + TriangleMesh& splitter) +{ + split(tm, splitter, parameters::all_default()); +} + +template +void split(TriangleMesh& tm, + const typename GetGeomTraits::type::Plane_3& plane) +{ + split(tm, plane, parameters::all_default()); +} + /// \endcond } } //end of namespace CGAL::Polygon_mesh_processing diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/compute_normal.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/compute_normal.h index 10e022ad608..680bf2ec252 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/compute_normal.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/compute_normal.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015 GeometryFactory (France). +// Copyright (c) 2015-2019 GeometryFactory (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -6,91 +6,105 @@ // $URL$ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// +// // // Author(s) : Jane Tournois - +// Mael Rouxel-Labbé #ifndef CGAL_POLYGON_MESH_PROCESSING_COMPUTE_NORMAL_H #define CGAL_POLYGON_MESH_PROCESSING_COMPUTE_NORMAL_H #include - -#include -#include -#include -#include -#include -#include - #include #include -#include +#include +#include +#include +#include -namespace CGAL{ +#include -namespace Polygon_mesh_processing{ +#include +#include +#include +#include +#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP +# ifndef CGAL_PMP_COMPUTE_NORMAL_DEBUG +# define CGAL_PMP_COMPUTE_NORMAL_DEBUG +# endif +#endif + +#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG +#include +#include +#endif + +namespace CGAL { +namespace Polygon_mesh_processing { namespace internal { - template - void normalize(typename GT::Vector_3& v, const GT& traits) - { - typename GT::FT norm = CGAL::approximate_sqrt( - traits.compute_squared_length_3_object()(v)); - //If the vector is small enough, approx_sqrt might return 0, and then we get nan values. - //To avoid that, we check the resulted norm. If it is 0, we don't normalize. - if(norm != 0) - { - v = traits.construct_divided_vector_3_object()(v, norm ); - } - } +template +void normalize(typename GT::Vector_3& v, const GT& traits) +{ + typedef typename GT::FT FT; - template - typename GT::Vector_3 - triangle_normal(const Point& p0, const Point& p1, const Point& p2 - , const GT& traits) + //If the vector is small enough, approx_sqrt might return 0, and then we get nan values. + //To avoid that, we check the resulted norm. If it is 0, we don't normalize. + const FT norm = CGAL::approximate_sqrt(traits.compute_squared_length_3_object()(v)); + if(norm != FT(0)) { - typename GT::Vector_3 n = traits.construct_cross_product_vector_3_object()( - traits.construct_vector_3_object()(p1, p2), - traits.construct_vector_3_object()(p1, p0)); - - //cross-product(AB, AC)'s norm is the area of the parallelogram - //formed by these 2 vectors. - //the triangle's area is half of it - return traits.construct_scaled_vector_3_object()(n, 0.5); + v = traits.construct_divided_vector_3_object()(v, norm); } } -template +template +typename GT::Vector_3 +triangle_normal(const Point& p0, const Point& p1, const Point& p2, const GT& traits) +{ + typedef typename GT::FT FT; + + typename GT::Vector_3 n = traits.construct_cross_product_vector_3_object()( + traits.construct_vector_3_object()(p1, p2), + traits.construct_vector_3_object()(p1, p0)); + + //cross-product(AB, AC)'s norm is the area of the parallelogram + //formed by these 2 vectors. + //the triangle's area is half of it + return traits.construct_scaled_vector_3_object()(n, FT(1)/FT(2)); +} + +template void sum_normals(const PM& pmesh, typename boost::graph_traits::face_descriptor f, VertexPointMap vpmap, Vector& sum, const GT& traits) { - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename boost::property_traits::reference Point_ref; halfedge_descriptor he = halfedge(f, pmesh); vertex_descriptor v = source(he, pmesh); - const Point& pv = get(vpmap, v); - while (v != target(next(he, pmesh), pmesh)) - { - const Point& pvn = get(vpmap, target(he, pmesh)); - const Point& pvnn = get(vpmap, target(next(he, pmesh), pmesh)); + const Point_ref pv = get(vpmap, v); - Vector n = internal::triangle_normal(pv, pvn, pvnn, traits); + while(v != target(next(he, pmesh), pmesh)) + { + const Point_ref pvn = get(vpmap, target(he, pmesh)); + const Point_ref pvnn = get(vpmap, target(next(he, pmesh), pmesh)); + + const Vector n = internal::triangle_normal(pv, pvn, pvnn, traits); sum = traits.construct_sum_of_vectors_3_object()(sum, n); he = next(he, pmesh); } } +} // namespace internal /** * \ingroup PMP_normal_grp @@ -124,42 +138,50 @@ Vector_3 #else typename GetGeomTraits::type::Vector_3 #endif -compute_face_normal(typename boost::graph_traits::face_descriptor f - , const PolygonMesh& pmesh - , const NamedParameters& np) +compute_face_normal(typename boost::graph_traits::face_descriptor f, + const PolygonMesh& pmesh, + const NamedParameters& np) { using parameters::choose_parameter; using parameters::get_parameter; - typedef typename GetGeomTraits::type GT; - GT traits = choose_parameter(get_parameter(np, internal_np::geom_traits), GT()); + typedef typename GetGeomTraits::type GT; + GT traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); - typedef typename GetVertexPointMap::const_type VPMap; + typedef typename GetVertexPointMap::const_type VPMap; VPMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(vertex_point, pmesh)); + get_const_property_map(vertex_point, pmesh)); - typedef typename GT::Point_3 Point; - typedef typename GT::Vector_3 Vector; + typedef typename GT::Point_3 Point; + typedef typename GT::Vector_3 Vector_3; - Vector normal = traits.construct_vector_3_object()(CGAL::NULL_VECTOR); - sum_normals(pmesh, f, vpmap, normal, traits); + Vector_3 normal = traits.construct_vector_3_object()(CGAL::NULL_VECTOR); + internal::sum_normals(pmesh, f, vpmap, normal, traits); - if (!traits.equal_3_object()(normal, CGAL::NULL_VECTOR)) + if(!traits.equal_3_object()(normal, CGAL::NULL_VECTOR)) internal::normalize(normal, traits); return normal; } +template +typename GetGeomTraits::type::Vector_3 +compute_face_normal(typename boost::graph_traits::face_descriptor f, + const PolygonMesh& pmesh) +{ + return compute_face_normal(f, pmesh, CGAL::parameters::all_default()); +} + /** * \ingroup PMP_normal_grp * computes the outward unit vector normal for all faces of the polygon mesh. * @tparam PolygonMesh a model of `FaceGraph` -* @tparam FaceNormalMap a model of `WritablePropertyMap` with +* @tparam Face_normal_map a model of `WritablePropertyMap` with `boost::graph_traits::%face_descriptor` as key type and `Kernel::Vector_3` as value type. * * @param pmesh the polygon mesh -* @param fnm the property map in which the normals are written +* @param face_normals the property map in which the normals are written * @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below * * \cgalNamedParamsBegin @@ -173,22 +195,381 @@ compute_face_normal(typename boost::graph_traits::face_descriptor f * If `Kernel::FT` does not have a `sqrt()` operation, the square root computation * will be done approximately. */ -template -void -compute_face_normals(const PolygonMesh& pmesh - , FaceNormalMap fnm - , const NamedParameters& np) +template +void compute_face_normals(const PolygonMesh& pmesh, + Face_normal_map face_normals, + const NamedParameters& np) { typedef typename GetGeomTraits::type Kernel; - for(typename boost::graph_traits::face_descriptor f : faces(pmesh)){ + for(typename boost::graph_traits::face_descriptor f : faces(pmesh)) + { typename Kernel::Vector_3 vec = compute_face_normal(f, pmesh, np); - put(fnm, f, vec); + put(face_normals, f, vec); +#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG + std::cout << "normal at face " << f << " is " << get(face_normals, f) << std::endl; +#endif } } +template +void compute_face_normals(const PolygonMesh& pmesh, Face_normal_map face_normals) +{ + compute_face_normals(pmesh, face_normals, CGAL::parameters::all_default()); +} + +namespace internal { + +enum Vertex_normal_type { + NO_WEIGHT = 0, + SIN_WEIGHT, + MOST_VISIBLE +}; + +template +bool almost_equal(const typename GT::Vector_3& v1, const typename GT::Vector_3& v2, + const GT& traits) +{ + typedef typename GT::FT FT; + + // We are doing a lot of likely inexact constructions to compute min circles on the sphere and + // these degenerate cases often happen (e.g. almost flat surfaces), so we don't want to to the usual + // "switch to the exact kernel" in degenerate cases robustness trick. Rather, use a fixed tolerance + // to assimilate vectors and scalar products. + // + // Tolerance is (arbitrarily) chosen as theta := 0.01°, thus we want sp(v1,v2) >= cos(theta) + const FT cos_theta = 0.99999998476912910; + return traits.compute_scalar_product_3_object()(v1, v2) >= cos_theta; +} + +template +bool does_enclose_other_normals(const std::size_t i, const std::size_t j, const std::size_t k, + const typename K::Vector_3& nb, + const typename K::FT sp_bi, + const std::vector::face_descriptor>& incident_faces, + const FaceNormalVector& face_normals, + const K& traits) +{ + typedef typename K::FT FT; + typedef typename boost::property_traits::reference Vector_ref; + + typename K::Compute_scalar_product_3 sp = traits.compute_scalar_product_3_object(); + + const FT nbn = CGAL::approximate_sqrt(traits.compute_squared_length_3_object()(nb)); + + // check that this min circle defined by the diameter contains the other points + const std::size_t nif = incident_faces.size(); + for(std::size_t l=0; l +typename GT::Vector_3 compute_normals_bisector(const typename GT::Vector_3& ni, + const typename GT::Vector_3& nj, + const GT& traits) +{ + if(traits.equal_3_object()(ni, nj)) + return ni; + + return traits.construct_sum_of_vectors_3_object()(ni, nj); // not normalized +} + +template +typename GT::Vector_3 compute_normals_bisector(const typename GT::Vector_3& ni, + const typename GT::Vector_3& nj, + const typename GT::Vector_3& nk, + const GT& traits) +{ + typedef typename GT::FT FT; + typedef typename GT::Point_3 Point_3; + typedef typename GT::Vector_3 Vector_3; + + typename GT::Construct_scaled_vector_3 cslv_3 = traits.construct_scaled_vector_3_object(); + typename GT::Construct_sum_of_vectors_3 csv_3 = traits.construct_sum_of_vectors_3_object(); + typename GT::Construct_vector_3 cv_3 = traits.construct_vector_3_object(); + + Vector_3 nb = cv_3(CGAL::NULL_VECTOR); + + if(almost_equal(ni, nj, traits) || nk == CGAL::NULL_VECTOR) + { + if(almost_equal(nj, nk, traits)) + nb = ni; + else // ni == nj, but nij != nk + nb = compute_normals_bisector(nj, nk, traits); + } + else if(almost_equal(ni, nk, traits) || nj == CGAL::NULL_VECTOR) // ni != nj + { + nb = compute_normals_bisector(nj, nk, traits); + } + else if(almost_equal(nj, nk, traits) || ni == CGAL::NULL_VECTOR) // ni != nj, ni != nk + { + nb = compute_normals_bisector(ni, nk, traits); + } + else + { + CGAL_assertion(ni != nj); + CGAL_assertion(ni != nk); + CGAL_assertion(nj != nk); + CGAL_assertion(!traits.collinear_3_object()(CGAL::ORIGIN + ni, CGAL::ORIGIN + nj, CGAL::ORIGIN + nk)); + +#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP + std::cout << "Triplet: ni[" << ni << "] nj[" << nj << "] nk[" << nk << "]" << std::endl; +#endif + + const Point_3 c = traits.construct_circumcenter_3_object()(CGAL::ORIGIN + ni, CGAL::ORIGIN + nj, CGAL::ORIGIN + nk); + if(c == CGAL::ORIGIN) + { + // will happen if the three vectors live in the same plan, return some weighted sum + const FT third = FT(1)/FT(3); + return csv_3(csv_3(cslv_3(ni, third), cslv_3(nj, third)), cslv_3(nk, third)); + } + + nb = cv_3(CGAL::ORIGIN, c); // not normalized + } + + return nb; +} + +template +typename GT::Vector_3 +compute_most_visible_normal_2_points(std::vector::face_descriptor>& incident_faces, + const FaceNormalVector& face_normals, + const GT& traits) +{ + typedef typename GT::FT FT; + typedef typename GT::Vector_3 Vector_3; + typedef typename boost::property_traits::reference Vector_ref; + + typename GT::Compute_scalar_product_3 sp_3 = traits.compute_scalar_product_3_object(); + typename GT::Construct_vector_3 cv_3 = traits.construct_vector_3_object(); + +#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP + std::cout << "Trying to find enclosing normal with 2 normals" << std::endl; +#endif + + FT min_sp = -1; + Vector_3 n = cv_3(CGAL::NULL_VECTOR); + + const std::size_t nif = incident_faces.size(); + for(std::size_t i=0; i(i, j, -1 /*NA*/, nb, sp_bi, incident_faces, face_normals, traits)) + continue; + + min_sp = sp_bi; + n = nb; + } + } + + return n; +} + +template +typename GT::Vector_3 +compute_most_visible_normal_3_points(const std::vector::face_descriptor>& incident_faces, + const FaceNormalVector& face_normals, + const GT& traits) +{ + typedef typename GT::FT FT; + typedef typename GT::Vector_3 Vector_3; + typedef typename boost::property_traits::reference Vector_ref; + +#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP + std::cout << "Trying to find enclosing normal with 3 normals" << std::endl; +#endif + + FT min_sp = -1; + + Vector_3 n = traits.construct_vector_3_object()(CGAL::NULL_VECTOR); + + const std::size_t nif = incident_faces.size(); + for(std::size_t i=0; i(i, j, k, nb, sp_bi, incident_faces, face_normals, traits)) + continue; + + min_sp = sp_bi; + n = nb; + } + } + } + +#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP + std::cout << "Best normal from 3-normals-approach: " << n << std::endl; +#endif + + return n; +} + +// Inspired by Aubry et al. On the most 'normal' normal +template +typename GT::Vector_3 +compute_vertex_normal_most_visible_min_circle(typename boost::graph_traits::vertex_descriptor v, + const FaceNormalVector& face_normals, + const PolygonMesh& pmesh, + const GT& traits) +{ + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + typedef typename GT::Vector_3 Vector_3; + + std::vector incident_faces; + for(face_descriptor f : CGAL::faces_around_target(halfedge(v, pmesh), pmesh)) + { + if(f == boost::graph_traits::null_face()) + continue; + + incident_faces.push_back(f); + } + + if(incident_faces.size() == 1) + return get(face_normals, incident_faces.front()); + + Vector_3 res = compute_most_visible_normal_2_points(incident_faces, face_normals, traits); + + if(res != CGAL::NULL_VECTOR) // found a valid normal through 2 point min circle + return res; + + // The vertex has only two incident faces with opposite normals (fold)... + // @todo devise something based on the directions of the 2/3/4 incident edges? + if(incident_faces.size() == 2 && res == CGAL::NULL_VECTOR) + return res; + + CGAL_assertion(incident_faces.size() >= 2); + + return compute_most_visible_normal_3_points(incident_faces, face_normals, traits); +} + +template +typename GT::Vector_3 +compute_vertex_normal_as_sum_of_weighted_normals(typename boost::graph_traits::vertex_descriptor v, + const Vertex_normal_type& vn_type, + const FaceNormalVector& face_normals, + const VertexPointMap& vpmap, + const PolygonMesh& pmesh, + const GT& traits) +{ + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename GT::FT FT; + typedef typename GT::Vector_3 Vector_3; + typedef typename boost::property_traits::reference Vector_ref; + + typename GT::Construct_vector_3 cv_3 = traits.construct_vector_3_object(); + typename GT::Compute_squared_length_3 csl_3 = traits.compute_squared_length_3_object(); + + Vector_3 normal = cv_3(CGAL::NULL_VECTOR); + + halfedge_descriptor h = halfedge(v, pmesh); + if(h == boost::graph_traits::null_halfedge()) + return normal; + + halfedge_descriptor end = h; + do + { + if(!is_border(h, pmesh)) + { + if(vn_type == NO_WEIGHT) + { + const Vector_ref n = get(face_normals, face(h, pmesh)); + normal = traits.construct_sum_of_vectors_3_object()(normal, n); + } + else if(vn_type == SIN_WEIGHT) + { + const Vector_3 v1 = cv_3(get(vpmap, v), get(vpmap, source(h, pmesh))); + const Vector_3 v2 = cv_3(get(vpmap, v), get(vpmap, target(next(h, pmesh), pmesh))); + + //v(i) and v(i+1) must be seen in ccw order, from v, so we reverse v1 and v2 + Vector_3 n = traits.construct_cross_product_vector_3_object()(v2, v1); + const FT den = CGAL::approximate_sqrt(csl_3(v1) * csl_3(v2)); + + if(den == FT(0)) + return compute_vertex_normal_as_sum_of_weighted_normals(v, NO_WEIGHT, face_normals, vpmap, pmesh, traits); + + n = traits.construct_scaled_vector_3_object()(n, FT(1) / den); + normal = traits.construct_sum_of_vectors_3_object()(normal, n); + } + else + { + std::cerr << "Error: unknown vertex normal type" << std::endl; + CGAL_assertion(false); + return CGAL::NULL_VECTOR; + } + } + + h = opposite(next(h, pmesh), pmesh); + } + while(h != end); + + return normal; +} + +} // end namespace internal + /** * \ingroup PMP_normal_grp * computes the unit normal at vertex `v` as the average of the normals of incident faces. @@ -222,61 +603,101 @@ typename GetGeomTraits::type::Vector_3 #endif compute_vertex_normal(typename boost::graph_traits::vertex_descriptor v, const PolygonMesh& pmesh, - const NamedParameters& np - ) + const NamedParameters& np) { using parameters::choose_parameter; + using parameters::is_default_parameter; using parameters::get_parameter; - typedef typename GetGeomTraits::type GT; - typedef typename GT::Vector_3 Vector; - GT traits = choose_parameter(get_parameter(np, internal_np::geom_traits), GT()); + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; - typedef typename GetFaceNormalMap::NoMap DefaultMap; - typedef typename internal_np::Lookup_named_param_def < - internal_np::face_normal_t, - NamedParameters, - DefaultMap> ::type FaceNormalMap; - FaceNormalMap fnmap = choose_parameter(get_parameter(np, internal_np::face_normal), DefaultMap()); - bool fnmap_valid - = !boost::is_same::value; + typedef typename GetGeomTraits::type GT; + typedef typename GT::Vector_3 Vector_3; + GT traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename GetVertexPointMap::const_type VPMap; + VPMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_const_property_map(vertex_point, pmesh)); - Vector normal = traits.construct_vector_3_object()(CGAL::NULL_VECTOR); + typedef std::map Face_vector_map; + typedef boost::associative_property_map Default_map; + + typedef typename internal_np::Lookup_named_param_def::type Face_normal_map; + Face_vector_map default_fvmap; + Face_normal_map face_normals = choose_parameter(get_parameter(np, internal_np::face_normal), + Default_map(default_fvmap)); + const bool must_compute_face_normals = is_default_parameter(get_parameter(np, internal_np::face_normal)); + +#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP + std::cout << std::endl << std::endl; + std::cout << "----------------------------------------------------------------------" << std::endl; + std::cout << "compute vertex at " << get(vpmap, v) + << ", must compute face normals? " << must_compute_face_normals << std::endl; +#endif - halfedge_descriptor he = halfedge(v, pmesh); // handle isolated vertices - if (he==boost::graph_traits::null_halfedge()) return normal; - halfedge_descriptor end = he; - do - { - if (!is_border(he, pmesh)) - { - Vector n = fnmap_valid ? get(fnmap, face(he, pmesh)) - : compute_face_normal(face(he, pmesh), pmesh, np); - normal = traits.construct_sum_of_vectors_3_object()(normal, n); - } - he = opposite(next(he, pmesh), pmesh); - } while (he != end); + halfedge_descriptor he = halfedge(v, pmesh); + if(he == boost::graph_traits::null_halfedge()) + return CGAL::NULL_VECTOR; - if ( ! traits.equal_3_object()(normal, CGAL::NULL_VECTOR)) + if(must_compute_face_normals) + { + for(face_descriptor f : CGAL::faces_around_target(halfedge(v, pmesh), pmesh)) + { + if(f == boost::graph_traits::null_face()) + continue; + + put(face_normals, f, compute_face_normal(f, pmesh, np)); + } + } + +#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG + std::cout << "Incident face normals:" << std::endl; + for(halfedge_descriptor h : CGAL::halfedges_around_target(v, pmesh)) + { + if(!is_border(h, pmesh)) + std::cout << "get normal at f " << face(h, pmesh) << " : " << get(face_normals, face(h, pmesh)) << std::endl; + } +#endif + + Vector_3 normal = internal::compute_vertex_normal_most_visible_min_circle(v, face_normals, pmesh, traits); + if(traits.equal_3_object()(normal, CGAL::NULL_VECTOR)) // can't always find a most visible normal + { +#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP + std::cout << "Failed to find most visible normal, use weighted sum of normals" << std::endl; +#endif + normal = internal::compute_vertex_normal_as_sum_of_weighted_normals( + v, internal::SIN_WEIGHT, face_normals, vpmap, pmesh, traits); + } + + if(!traits.equal_3_object()(normal, CGAL::NULL_VECTOR)) internal::normalize(normal, traits); + return normal; } +template +typename GetGeomTraits::type::Vector_3 +compute_vertex_normal(typename boost::graph_traits::vertex_descriptor v, + const PolygonMesh& pmesh) +{ + return compute_vertex_normal(v, pmesh, CGAL::parameters::all_default()); +} + /** * \ingroup PMP_normal_grp * computes the outward unit vector normal for all vertices of the polygon mesh. +* * @tparam PolygonMesh a model of `FaceListGraph` * @tparam VertexNormalMap a model of `WritablePropertyMap` with - `boost::graph_traits::%vertex_descriptor` as key type and - the return type of `compute_vertex_normal()` as value type. +* `boost::graph_traits::%vertex_descriptor` as key type and +* the return type of `compute_vertex_normal()` as value type. * * @param pmesh the polygon mesh -* @param vnm the property map in which the normals are written +* @param vertex_normals the property map in which the normals are written * @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below * * \cgalNamedParamsBegin @@ -290,38 +711,82 @@ compute_vertex_normal(typename boost::graph_traits::vertex_descript * If `Kernel::FT` does not have a `sqrt()` operation, the square root computation * will be done approximately. */ -template -void -compute_vertex_normals(const PolygonMesh& pmesh - , VertexNormalMap vnm - , const NamedParameters& np - ) +template +void compute_vertex_normals(const PolygonMesh& pmesh, + VertexNormalMap vertex_normals, + const NamedParameters& np) { - typedef typename GetGeomTraits::type Kernel; + using parameters::choose_parameter; + using parameters::is_default_parameter; + using parameters::get_parameter; - for(typename boost::graph_traits::vertex_descriptor v : vertices(pmesh)){ - typename Kernel::Vector_3 vec = compute_vertex_normal(v, pmesh, np); - put(vnm, v, vec); + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + + typedef typename GetGeomTraits::type GT; + typedef typename GT::Vector_3 Vector_3; + + typedef CGAL::dynamic_face_property_t Face_normal_tag; + typedef typename boost::property_map::const_type Face_normal_dmap; + +#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP + GT traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); + + typedef typename GetVertexPointMap::const_type VPMap; + VPMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_const_property_map(vertex_point, pmesh)); +#endif + + typedef typename internal_np::Lookup_named_param_def::type Face_normal_map; + Face_normal_map face_normals = choose_parameter(get_parameter(np, internal_np::face_normal), + get(Face_normal_tag(), pmesh)); + const bool must_compute_face_normals = is_default_parameter(get_parameter(np, internal_np::face_normal)); + + if(must_compute_face_normals) + compute_face_normals(pmesh, face_normals, np); + +#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP + std::ofstream out("computed_normals.cgal.polylines.txt"); + const Bbox_3 bb = bbox(pmesh, np); + const typename GT::FT bbox_diagonal = CGAL::sqrt(CGAL::square(bb.xmax() - bb.xmin()) + + CGAL::square(bb.ymax() - bb.ymin()) + + CGAL::square(bb.zmax() - bb.zmin())); +#endif + + for(vertex_descriptor v : vertices(pmesh)) + { + const Vector_3 n = compute_vertex_normal(v, pmesh, np.face_normal_map(face_normals)); + put(vertex_normals, v, n); + +#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP + out << "2 " << get(vpmap, v) << " " + << get(vpmap, v) + traits.construct_scaled_vector_3_object()(n, 0.1 * bbox_diagonal) << "\n"; +#endif } } +template +void compute_vertex_normals(const PolygonMesh& pmesh, VertexNormalMap vertex_normals) +{ + compute_vertex_normals(pmesh, vertex_normals, CGAL::parameters::all_default()); +} + /** * \ingroup PMP_normal_grp * computes the outward unit vector normal for all vertices and faces of the polygon mesh. +* * @tparam PolygonMesh a model of `FaceListGraph` * @tparam VertexNormalMap a model of `WritablePropertyMap` with - `boost::graph_traits::%vertex_descriptor` as key type and - `Kernel::Vector_3` as value type. +* `boost::graph_traits::%vertex_descriptor` as key type and +* `Kernel::Vector_3` as value type. * @tparam FaceNormalMap a model of `ReadWritePropertyMap` with - `boost::graph_traits::%face_descriptor` as key type and - `Kernel::Vector_3` as value type. +* `boost::graph_traits::%face_descriptor` as key type and +* `Kernel::Vector_3` as value type. * * @param pmesh the polygon mesh -* @param vnm the property map in which the vertex normals are written -* @param fnm the property map in which the face normals are written +* @param vertex_normals the property map in which the vertex normals are written +* @param face_normals the property map in which the face normals are written * @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below * * \cgalNamedParamsBegin @@ -335,79 +800,27 @@ compute_vertex_normals(const PolygonMesh& pmesh * If `Kernel::FT` does not have a `sqrt()` operation, the square root computation * will be done approximately. */ -template -void -compute_normals(const PolygonMesh& pmesh - , VertexNormalMap vnm - , FaceNormalMap fnm - , const NamedParameters& np - ) +template +void compute_normals(const PolygonMesh& pmesh, + VertexNormalMap vertex_normals, + FaceNormalMap face_normals, + const NamedParameters& np) { - compute_face_normals(pmesh, fnm, np); - compute_vertex_normals(pmesh, vnm, np.face_normal_map(fnm)); + compute_face_normals(pmesh, face_normals, np); + compute_vertex_normals(pmesh, vertex_normals, np.face_normal_map(face_normals)); } -///\cond SKIP_IN_MANUAL -// compute_vertex_normal overloads -template -typename CGAL::Kernel_traits< typename property_map_value::type>::Kernel::Vector_3 -compute_vertex_normal( - typename boost::graph_traits::vertex_descriptor v, - const PolygonMesh& pmesh) -{ - return compute_vertex_normal(v, pmesh, - CGAL::Polygon_mesh_processing::parameters::all_default()); -} - -// compute_vertex_normals overloads -template -void -compute_vertex_normals(const PolygonMesh& pmesh, - VertexNormalMap vnm) -{ - compute_vertex_normals(pmesh, vnm, - CGAL::Polygon_mesh_processing::parameters::all_default()); -} - -// compute_face_normal overload -template -typename CGAL::Kernel_traits < typename property_map_value::type>::Kernel::Vector_3 -compute_face_normal( - typename boost::graph_traits::face_descriptor f, - const PolygonMesh& pmesh) -{ - return compute_face_normal(f, pmesh, - CGAL::Polygon_mesh_processing::parameters::all_default()); -} - -// compute_face_normals overload -template -void -compute_face_normals(const PolygonMesh& pmesh, FaceNormalMap fnm) -{ - compute_face_normals(pmesh, fnm, - CGAL::Polygon_mesh_processing::parameters::all_default()); -} - -// compute_normals overload template -void -compute_normals(const PolygonMesh& pmesh, - VertexNormalMap vnm, - FaceNormalMap fnm) +void compute_normals(const PolygonMesh& pmesh, + VertexNormalMap vertex_normals, + FaceNormalMap face_normals) { - compute_normals(pmesh, vnm, fnm, - CGAL::Polygon_mesh_processing::parameters::all_default()); + compute_normals(pmesh, vertex_normals, face_normals, CGAL::parameters::all_default()); } -/// \endcond - -} - -} // end of namespace CGAL::Polygon_mesh_processing +} // namespace Polygon_mesh_processing +} // namespace CGAL #endif // CGAL_POLYGON_MESH_PROCESSING_COMPUTE_NORMAL_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h index 5ced2e4916a..361fd938645 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h @@ -23,18 +23,22 @@ #include #include #include -#include -#include #include +#include #include #include +#include +#include #include #include + #include -#include #include +#include +#include +#include #include #include @@ -57,7 +61,7 @@ namespace internal { } }; - // A property map + // A property map template struct No_constraint { friend bool get(No_constraint, typename boost::graph_traits::edge_descriptor) @@ -87,7 +91,7 @@ namespace internal { EdgeConstraintMap ecm; }; -}// namespace internal +} // namespace internal /*! * \ingroup keep_connected_components_grp @@ -132,8 +136,7 @@ connected_component(typename boost::graph_traits::face_descriptor s internal::No_constraint//default > ::type EdgeConstraintMap; EdgeConstraintMap ecmap - = choose_parameter(get_parameter(np, internal_np::edge_is_constrained), - internal::No_constraint()); + = choose_parameter(get_parameter(np, internal_np::edge_is_constrained)); typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; @@ -147,7 +150,7 @@ connected_component(typename boost::graph_traits::face_descriptor s if (!already_processed.insert(seed_face).second) continue; *out++=seed_face; for(halfedge_descriptor hd : - CGAL::halfedges_around_face(halfedge(seed_face, pmesh), pmesh) ) + halfedges_around_face(halfedge(seed_face, pmesh), pmesh) ) { if(! get(ecmap, edge(hd, pmesh))){ face_descriptor neighbor = face( opposite(hd, pmesh), pmesh ); @@ -173,9 +176,6 @@ connected_component(typename boost::graph_traits::face_descriptor s * \ingroup keep_connected_components_grp * computes for each face the index of the corresponding connected component. * - * A property map for `CGAL::face_index_t` must be either available as an internal property map - * to `pmesh` or provided as one of the \ref pmp_namedparameters "Named Parameters". - * * \tparam PolygonMesh a model of `FaceListGraph` * \tparam FaceComponentMap a model of `WritablePropertyMap` with `boost::graph_traits::%face_descriptor` as key type and @@ -206,31 +206,52 @@ connected_components(const PolygonMesh& pmesh, using parameters::choose_parameter; using parameters::get_parameter; + typedef boost::graph_traits GT; + typedef typename GT::halfedge_descriptor halfedge_descriptor; + typedef typename GT::face_descriptor face_descriptor; + typedef typename internal_np::Lookup_named_param_def < internal_np::edge_is_constrained_t, NamedParameters, internal::No_constraint//default > ::type EdgeConstraintMap; + EdgeConstraintMap ecmap - = choose_parameter(get_parameter(np, internal_np::edge_is_constrained), - internal::No_constraint()); + = choose_parameter(get_parameter(np, internal_np::edge_is_constrained)); - typedef Dual Dual; - typedef boost::filtered_graph > FiniteDual; - Dual dual(pmesh); + typedef typename GetInitializedFaceIndexMap::const_type FaceIndexMap; + FaceIndexMap fimap = get_initialized_face_index_map(pmesh, np); - FiniteDual finite_dual(dual, - internal::No_border(pmesh, ecmap)); - - typename GetFaceIndexMap::const_type - fimap = choose_parameter(get_parameter(np, internal_np::face_index), - get_const_property_map(boost::face_index, pmesh)); - - return boost::connected_components(finite_dual, - fcm, - boost::vertex_index_map(fimap) - ); + typename boost::property_traits::value_type i=0; + std::vector handled(num_faces(pmesh), false); + for (face_descriptor f : faces(pmesh)) + { + if (handled[get(fimap,f)]) continue; + std::vector queue; + queue.push_back(f); + while(!queue.empty()) + { + face_descriptor fq = queue.back(); + queue.pop_back(); + typename boost::property_traits::value_type fq_id = get(fimap,fq); + if ( handled[fq_id]) continue; + handled[fq_id]=true; + put(fcm, fq, i); + for (halfedge_descriptor h : halfedges_around_face(halfedge(fq, pmesh), pmesh)) + { + if ( get(ecmap, edge(h, pmesh)) ) continue; + halfedge_descriptor opp = opposite(h, pmesh); + face_descriptor fqo = face(opp, pmesh); + if ( fqo != GT::null_face() ) + { + if ( !handled[get(fimap,fqo)] ) + queue.push_back(fqo); + } + } + } + ++i; + } + return i; } template @@ -238,12 +259,9 @@ typename boost::property_traits::value_type connected_components(const PolygonMesh& pmesh, FaceComponentMap fcm) { - - return CGAL::Polygon_mesh_processing::connected_components(pmesh, fcm, - CGAL::Polygon_mesh_processing::parameters::all_default()); + return CGAL::Polygon_mesh_processing::connected_components(pmesh, fcm, CGAL::parameters::all_default()); } - template +std::size_t number_of_connected_components(const PolygonMesh& pmesh, + const CGAL_PMP_NP_CLASS& np) +{ + typedef CGAL::dynamic_face_property_t Face_property_tag; + typedef typename boost::property_map::const_type Patch_ids_map; + + Patch_ids_map patch_ids_map = get(Face_property_tag(), pmesh); + + return CGAL::Polygon_mesh_processing::connected_components(pmesh, patch_ids_map, np); +} + +template +std::size_t number_of_connected_components(const PolygonMesh& pmesh) +{ + return internal::number_of_connected_components(pmesh, CGAL::parameters::all_default()); +} + +} // end namespace internal + /*! * \ingroup keep_connected_components_grp * @@ -262,15 +324,12 @@ void keep_connected_components(PolygonMesh& pmesh * By default, the size of a face is `1` (and thus the size of a connected component is the number * of faces it contains), but it is also possible to pass custom sizes, such as the area of the face. * - * Property maps for `CGAL::face_index_t` and `CGAL::vertex_index_t` - * must be either available as internal property maps - * to `pmesh` or provided as \ref pmp_namedparameters "Named Parameters". - * * \tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph` * \tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" * * \param pmesh the polygon mesh - * \param nb_components_to_keep the number of components to be kept + * \param nb_components_to_keep the number of components to be kept. If this number is larger than + * the number of components in the mesh, all components are kept. * \param np optional \ref pmp_namedparameters "Named Parameters", amongst those described below * * \cgalNamedParamsBegin @@ -282,6 +341,14 @@ void keep_connected_components(PolygonMesh& pmesh * is chosen by the user, but must be constructible from `0` and support `operator+=()` and * comparisons. * \cgalParamEnd + * \cgalParamBegin{dry_run} + * a Boolean parameter. If set to `true`, the mesh will not be altered, but the number + * of components that would be removed is returned. The default value is `false`. + * \cgalParamEnd + * \cgalParamBegin{output_iterator} a model of `OutputIterator` with value type `face_descriptor`. + * When using the "dry run" mode (see parameter `dry_run`), faces that would be removed by the + * algorithm can be collected with this output iterator. + * \cgalParamEnd * \cgalNamedParamsEnd * * \return the number of connected components removed (ignoring isolated vertices). @@ -298,10 +365,8 @@ std::size_t keep_largest_connected_components(PolygonMesh& pmesh, using parameters::choose_parameter; using parameters::get_parameter; - // FaceIndexMap - typedef typename GetFaceIndexMap::type FaceIndexMap; - FaceIndexMap fimap = choose_parameter(get_parameter(np, internal_np::face_index), - get_property_map(boost::face_index, pmesh)); + typedef typename CGAL::GetInitializedFaceIndexMap::type FaceIndexMap; + FaceIndexMap fimap = CGAL::get_initialized_face_index_map(pmesh, np); // FaceSizeMap typedef typename internal_np::Lookup_named_param_def(1)); + const bool dry_run = choose_parameter(get_parameter(np, internal_np::dry_run), false); + + typedef typename internal_np::Lookup_named_param_def::type Output_iterator; + Output_iterator out = choose_parameter(get_parameter(np, internal_np::output_iterator)); + // vector_property_map boost::vector_property_map face_cc(fimap); std::size_t num = connected_components(pmesh, face_cc, np); @@ -320,12 +392,13 @@ std::size_t keep_largest_connected_components(PolygonMesh& pmesh, // Even if we do not want to keep anything we need to first // calculate the number of existing connected_components to get the // correct return value. - if(nb_components_to_keep == 0) { + if(nb_components_to_keep == 0) + { CGAL::clear(pmesh); return num; } - if((num == 1)|| (nb_components_to_keep > num) ) + if(nb_components_to_keep >= num) return 0; std::vector > component_size(num); @@ -338,11 +411,25 @@ std::size_t keep_largest_connected_components(PolygonMesh& pmesh, // we sort the range [0, num) by component size std::sort(component_size.begin(), component_size.end(), internal::MoreSecond()); - std::vector cc_to_keep; - for(std::size_t i=0; i is_to_be_removed(num, false); + for(std::size_t i=0; i cc_to_keep; + for(std::size_t i=0; i::type FaceIndexMap; - FaceIndexMap fim = choose_parameter(get_parameter(np, internal_np::face_index), - get_property_map(boost::face_index, pmesh)); + typedef typename CGAL::GetInitializedFaceIndexMap::type FaceIndexMap; + FaceIndexMap fim = CGAL::get_initialized_face_index_map(pmesh, np); typedef typename internal_np::Lookup_named_param_def // default - >::type FaceSizeMap; + NamedParameters, + Constant_property_map // default + >::type FaceSizeMap; typedef typename boost::property_traits::value_type Face_size; CGAL_static_assertion((std::is_convertible::value)); + typedef typename internal_np::Lookup_named_param_def::type Output_iterator; + FaceSizeMap face_size_pmap = choose_parameter(get_parameter(np, internal_np::face_size_map), - Constant_property_map(1)); + Constant_property_map(1)); + const bool dry_run = choose_parameter(get_parameter(np, internal_np::dry_run), false); + Output_iterator out = choose_parameter(get_parameter(np, internal_np::output_iterator)); // vector_property_map boost::vector_property_map face_cc(fim); std::size_t num = connected_components(pmesh, face_cc, np); - std::vector component_size(num); - - for(std::size_t i=0; i component_size(num, 0); for(face_descriptor f : faces(pmesh)) component_size[face_cc[f]] += get(face_size_pmap, f); const Face_size thresh = threshold_value; + std::vector is_to_be_kept(num, false); + std::size_t res = 0; - std::vector cc_to_keep; for(std::size_t i=0; i= thresh) - cc_to_keep.push_back(i); + { + is_to_be_kept[i] = true; + ++res; + } } - keep_connected_components(pmesh, cc_to_keep, face_cc, np); + if(dry_run) + { + for(face_descriptor f : faces(pmesh)) + if(!is_to_be_kept[face_cc[f]]) + *out++ = f; + } + else + { + std::vector ccs_to_keep; + for(std::size_t i=0; i std::size_t keep_large_connected_components(PolygonMesh& pmesh, std::size_t threshold_components_to_keep) @@ -467,7 +576,6 @@ void keep_or_remove_connected_components(PolygonMesh& pmesh , bool keep , const NamedParameters& np) { - typedef PolygonMesh PM; using parameters::choose_parameter; using parameters::get_parameter; @@ -479,10 +587,8 @@ void keep_or_remove_connected_components(PolygonMesh& pmesh typedef typename boost::graph_traits::edge_descriptor edge_descriptor; typedef typename boost::graph_traits::edge_iterator edge_iterator; - //VertexIndexMap - typedef typename GetVertexIndexMap::type VertexIndexMap; - VertexIndexMap vim = choose_parameter(get_parameter(np, internal_np::vertex_index), - get_const_property_map(boost::vertex_index, pmesh)); + typedef typename GetInitializedVertexIndexMap::type VertexIndexMap; + VertexIndexMap vim = get_initialized_vertex_index_map(pmesh, np); std::set cc_to_keep; for(std::size_t i : components_to_keep) @@ -601,10 +707,6 @@ void keep_or_remove_connected_components(PolygonMesh& pmesh * \note If the removal of the connected components makes `pmesh` a non-manifold surface, * then the behavior of this function is undefined. * -* Property maps for `CGAL::vertex_index_t` -* must be either available as internal property map -* to `pmesh` or provided as \ref pmp_namedparameters "Named Parameters". -* * \tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph` * \tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" * \tparam ComponentRange a range of ids convertible to `std::size` @@ -644,11 +746,6 @@ void keep_connected_components(PolygonMesh& pmesh * \note If the removal of the connected components makes `pmesh` a non-manifold surface, * then the behavior of this function is undefined. * -* Property maps for `CGAL::vertex_index_t` -* must be either available as internal property map -* to `pmesh` or provided as \ref pmp_namedparameters "Named Parameters". -* -* * \tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph` * \tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" * \tparam ComponentRange a range of ids convertible to `std::size` @@ -685,10 +782,6 @@ void remove_connected_components(PolygonMesh& pmesh * keeps the connected components not designated by the faces in `components_to_remove`, * and removes the other connected components and all isolated vertices. * -* Property maps for `CGAL::face_index_t` and `CGAL::vertex_index_t` -* must be either available as internal property maps -* to `pmesh` or provided as \ref pmp_namedparameters "Named Parameters". -* * \note If the removal of the connected components makes `pmesh` a non-manifold surface, * then the behavior of this function is undefined. * @@ -715,20 +808,19 @@ void remove_connected_components(PolygonMesh& pmesh , const FaceRange& components_to_remove , const CGAL_PMP_NP_CLASS& np) { - if (components_to_remove.empty()) return; - typedef PolygonMesh PM; - typedef typename boost::graph_traits::face_descriptor face_descriptor; using parameters::choose_parameter; using parameters::get_parameter; - //FaceIndexMap - typedef typename GetFaceIndexMap::type FaceIndexMap; - FaceIndexMap fim = choose_parameter(get_parameter(np, internal_np::face_index), - get_property_map(boost::face_index, pmesh)); + if (components_to_remove.empty()) + return; + + typedef PolygonMesh PM; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + typedef typename CGAL::GetInitializedFaceIndexMap::type FaceIndexMap; + FaceIndexMap fim = CGAL::get_initialized_face_index_map(pmesh, np); - //vector_property_map boost::vector_property_map face_cc(fim); - connected_components(pmesh, face_cc, np); std::vector cc_to_remove; @@ -743,10 +835,6 @@ void remove_connected_components(PolygonMesh& pmesh * keeps the connected components designated by the faces in `components_to_keep`, * and removes the other connected components and all isolated vertices. * -* Property maps for `CGAL::face_index_t` and `CGAL::vertex_index_t` -* must be either available as internal property maps -* to `pmesh` or provided as \ref pmp_namedparameters "Named Parameters". -* * \note If the removal of the connected components makes `pmesh` a non-manifold surface, * then the behavior of this function is undefined. * @@ -779,14 +867,10 @@ void keep_connected_components(PolygonMesh& pmesh using parameters::choose_parameter; using parameters::get_parameter; - //FaceIndexMap - typedef typename GetFaceIndexMap::type FaceIndexMap; - FaceIndexMap fim = choose_parameter(get_parameter(np, internal_np::face_index), - get_property_map(boost::face_index, pmesh)); + typedef typename CGAL::GetInitializedFaceIndexMap::type FaceIndexMap; + FaceIndexMap fim = CGAL::get_initialized_face_index_map(pmesh, np); - //vector_property_map boost::vector_property_map face_cc(fim); - connected_components(pmesh, face_cc, np); std::vector cc_to_keep; @@ -836,8 +920,106 @@ void keep_connected_components(PolygonMesh& pmesh CGAL::Polygon_mesh_processing::parameters::all_default()); } -} // namespace Polygon_mesh_processing +namespace internal { +template +struct No_mark +{ + friend bool get(No_mark, typename boost::graph_traits::edge_descriptor) { return false; } + friend void put(No_mark, typename boost::graph_traits::edge_descriptor, bool) { } +}; + +template < class PolygonMesh, class PolygonMeshRange, + class FIMap, class VIMap, + class HIMap, class Ecm > +void split_connected_components_impl(FIMap fim, + HIMap him, + VIMap vim, + Ecm ecm, + PolygonMeshRange& range, + const PolygonMesh& tm) +{ + typename boost::template property_map< + PolygonMesh, CGAL::dynamic_face_property_t >::const_type + pidmap = get(CGAL::dynamic_face_property_t(), tm); + + int nb_patches = CGAL::Polygon_mesh_processing::connected_components( + tm, pidmap, CGAL::parameters::face_index_map(fim) + .edge_is_constrained_map(ecm)); + + for(int i=0; i + filter_graph(tm, i, pidmap, CGAL::parameters::face_index_map(fim) + .halfedge_index_map(him) + .vertex_index_map(vim)); + range.push_back(PolygonMesh()); + PolygonMesh& new_graph = range.back(); + CGAL::copy_face_graph(filter_graph, new_graph); + } +} + +}//internal + +/*! + * \ingroup keep_connected_components_grp + * identifies the connected components of `pm` and pushes back a new `PolygonMesh` for each connected component in `cc_meshes`. + * + * + * \tparam PolygonMesh a model of `FaceListGraph` + * \tparam PolygonMeshRange a model of `SequenceContainer` with `PolygonMesh` as value type. + * + * \tparam NamedParameters a sequence of Named Parameters + * + * \param pm the polygon mesh + * \param cc_meshes container that is filled with the extracted connected components. + * \param np an optional sequence of Named Parameters among the ones listed below + * + * \cgalNamedParamsBegin + * \cgalParamBegin{edge_is_constrained_map} a property map containing the constrained-or-not status of each edge of `pm` \cgalParamEnd + * \cgalParamBegin{face_index_map} + * a property map containing a unique index for each face initialized from 0 to `num_faces(pm)` + * \cgalParamEnd + * \cgalParamBegin{vertex_index_map} + * a property map containing a unique index for each vertex initialized 0 to `num_vertices(pm)` + * \cgalParamEnd + * \cgalNPBegin{halfedge_index_map} + * a property map containing a unique index for each halfedge initialized 0 to `num_halfedges(pm)` + * \cgalNPEnd + * \cgalNamedParamsEnd + * + */ +template +void split_connected_components(const PolygonMesh& pm, + PolygonMeshRange& cc_meshes, + const NamedParameters& np) +{ + typedef typename internal_np::Lookup_named_param_def < + internal_np::edge_is_constrained_t, + NamedParameters, + internal::No_mark//default + > ::type Ecm; + + using parameters::choose_parameter; + using parameters::get_parameter; + + Ecm ecm = choose_parameter(get_parameter(np, internal_np::edge_is_constrained), + internal::No_mark()); + + internal::split_connected_components_impl(CGAL::get_initialized_face_index_map(pm, np), + CGAL::get_initialized_halfedge_index_map(pm, np), + CGAL::get_initialized_vertex_index_map(pm, np), + ecm, cc_meshes, pm); +} + +template +void split_connected_components(const PolygonMesh& pm, + PolygonMeshRange& cc_meshes) +{ + split_connected_components(pm, cc_meshes, parameters::all_default()); +} + +} // namespace Polygon_mesh_processing } // namespace CGAL #include diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h index a6f2f052434..c6d7f87e1b1 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h @@ -17,11 +17,12 @@ #include +#include +#include #include #include #include #include -#include #include namespace CGAL { @@ -39,16 +40,17 @@ namespace internal { template bool recursive_does_bound_a_volume(const TriangleMesh& tm, Vpm& vpm, - Fid_map& fid_map, + Fid_map fid_map, const std::vector& xtrm_vertices, boost::dynamic_bitset<>& cc_handled, const std::vector& face_cc, std::size_t xtrm_cc_id, bool is_parent_outward_oriented) { - typedef boost::graph_traits GT; - typedef typename GT::face_descriptor face_descriptor; - typedef Side_of_triangle_mesh Side_of_tm; + typedef boost::graph_traits Graph_traits; + typedef typename Graph_traits::face_descriptor face_descriptor; + typedef Side_of_triangle_mesh Side_of_tm; + // first check that the orientation of the current cc is consistant with its // parent cc containing it bool new_is_parent_outward_oriented = internal::is_outward_oriented( @@ -170,25 +172,23 @@ enum Boolean_operation_type {UNION = 0, INTERSECTION=1, * \see `CGAL::Polygon_mesh_processing::orient_to_bound_a_volume()` */ template -bool does_bound_a_volume(const TriangleMesh& tm, const NamedParameters& np) +bool does_bound_a_volume(const TriangleMesh& tm, + const NamedParameters& np) { - typedef boost::graph_traits GT; - typedef typename GT::vertex_descriptor vertex_descriptor; - typedef typename GetVertexPointMap::const_type Vpm; - typedef typename GetFaceIndexMap::const_type Fid_map; - typedef typename Kernel_traits< - typename boost::property_traits::value_type >::Kernel Kernel; + typedef boost::graph_traits Graph_traits; + typedef typename Graph_traits::vertex_descriptor vertex_descriptor; + typedef typename GetVertexPointMap::const_type Vpm; + typedef typename boost::property_traits::value_type Point; + typedef typename Kernel_traits::Kernel Kernel; if (!is_closed(tm)) return false; if (!is_triangle_mesh(tm)) return false; Vpm vpm = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point), - get_const_property_map(boost::vertex_point, tm)); + get_const_property_map(boost::vertex_point, tm)); - Fid_map fid_map = parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), - get_const_property_map(boost::face_index, tm)); + typedef typename GetInitializedFaceIndexMap::const_type Fid_map; + Fid_map fid_map = get_initialized_face_index_map(tm, np); std::vector face_cc(num_faces(tm), std::size_t(-1)); @@ -203,11 +203,11 @@ bool does_bound_a_volume(const TriangleMesh& tm, const NamedParameters& np) boost::dynamic_bitset<> cc_handled(nb_cc, 0); // extract a vertex with max z coordinate for each connected component - std::vector xtrm_vertices(nb_cc, GT::null_vertex()); + std::vector xtrm_vertices(nb_cc, Graph_traits::null_vertex()); for(vertex_descriptor vd : vertices(tm)) { std::size_t cc_id = face_cc[get(fid_map, face(halfedge(vd, tm), tm))]; - if (xtrm_vertices[cc_id]==GT::null_vertex()) + if (xtrm_vertices[cc_id] == Graph_traits::null_vertex()) xtrm_vertices[cc_id]=vd; else if (get(vpm, vd).z()>get(vpm,xtrm_vertices[cc_id]).z()) @@ -246,9 +246,7 @@ bool does_bound_a_volume(const TriangleMesh& tm) Corefinement::No_mark \ > ::type Ecm_out_##I; \ Ecm_out_##I ecm_out_##I = \ - parameters::choose_parameter( parameters::get_parameter(std::get(nps_out), internal_np::edge_is_constrained), \ - Corefinement::No_mark() ); - + parameters::choose_parameter(parameters::get_parameter(std::get(nps_out), internal_np::edge_is_constrained)); /** * \ingroup PMP_corefinement_grp @@ -351,8 +349,11 @@ corefine_and_compute_boolean_operations( NamedParametersOut2, NamedParametersOut3>& nps_out) { + using parameters::choose_parameter; + using parameters::get_parameter; + const bool throw_on_self_intersection = - parameters::choose_parameter(parameters::get_parameter(np1, internal_np::throw_on_self_intersection), false); + choose_parameter(get_parameter(np1, internal_np::throw_on_self_intersection), false); // Vertex point maps //for input meshes @@ -365,11 +366,11 @@ corefine_and_compute_boolean_operations( static const bool same_vpm = (boost::is_same::value); ) CGAL_static_assertion(same_vpm); - Vpm vpm1 = parameters::choose_parameter(parameters::get_parameter(np1, internal_np::vertex_point), - get_property_map(boost::vertex_point, tm1)); + Vpm vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point), + get_property_map(boost::vertex_point, tm1)); - Vpm vpm2 = parameters::choose_parameter(parameters::get_parameter(np2, internal_np::vertex_point), - get_property_map(boost::vertex_point, tm2)); + Vpm vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), + get_property_map(boost::vertex_point, tm2)); typedef typename boost::property_traits::value_type Point_3; @@ -497,10 +498,8 @@ corefine_and_compute_boolean_operations( Corefinement::No_mark//default > ::type Ecm2; - Ecm1 ecm1 = parameters::choose_parameter( parameters::get_parameter(np1, internal_np::edge_is_constrained), - Corefinement::No_mark() ); - Ecm2 ecm2 = parameters::choose_parameter( parameters::get_parameter(np2, internal_np::edge_is_constrained), - Corefinement::No_mark() ); + Ecm1 ecm1 = choose_parameter(get_parameter(np1, internal_np::edge_is_constrained)); + Ecm2 ecm2 = choose_parameter(get_parameter(np2, internal_np::edge_is_constrained)); typedef Corefinement::Ecm_bind Ecm_in; @@ -514,34 +513,28 @@ corefine_and_compute_boolean_operations( typedef std::tuple Edge_mark_map_tuple; -// Face index point maps - typedef typename GetFaceIndexMap::type Fid_map; - typedef typename GetFaceIndexMap::type Fid_map2; - CGAL_USE_TYPE(Fid_map2); - CGAL_assertion_code( - static const bool same_fidmap = (boost::is_same::value);) - CGAL_static_assertion(same_fidmap); + // Face index point maps + typedef typename CGAL::GetInitializedFaceIndexMap::type FaceIndexMap1; + typedef typename CGAL::GetInitializedFaceIndexMap::type FaceIndexMap2; - Fid_map fid_map1 = parameters::choose_parameter(parameters::get_parameter(np1, internal_np::face_index), - get_property_map(boost::face_index, tm1)); - Fid_map fid_map2 = parameters::choose_parameter(parameters::get_parameter(np2, internal_np::face_index), - get_property_map(boost::face_index, tm2)); -// User visitor + FaceIndexMap1 fid_map1 = get_initialized_face_index_map(tm1, np1); + FaceIndexMap2 fid_map2 = get_initialized_face_index_map(tm2, np2); + + + // User visitor typedef typename internal_np::Lookup_named_param_def < internal_np::graph_visitor_t, NamedParameters1, Corefinement::Default_visitor//default > ::type User_visitor; - User_visitor uv( parameters::choose_parameter( parameters::get_parameter(np1, internal_np::graph_visitor), - Corefinement::Default_visitor() ) ); + User_visitor uv(choose_parameter(get_parameter(np1, internal_np::graph_visitor))); // surface intersection algorithm call typedef Corefinement::Face_graph_output_builder Algo_visitor; Ecm_in ecm_in(tm1,tm2,ecm1,ecm2); Edge_mark_map_tuple ecms_out(ecm_out_0, ecm_out_1, ecm_out_2, ecm_out_3); - Ob ob(tm1, tm2, vpm1, vpm2, fid_map1, fid_map2, ecm_in, - vpm_out_tuple, ecms_out, uv, output); + Ob ob(tm1, tm2, vpm1, vpm2, fid_map1, fid_map2, ecm_in, vpm_out_tuple, ecms_out, uv, output); // special case used for clipping open meshes - if ( parameters::choose_parameter( parameters::get_parameter(np1, internal_np::use_bool_op_to_clip_surface), - false) ) + if (choose_parameter(get_parameter(np1, internal_np::use_bool_op_to_clip_surface), false)) { CGAL_assertion(output[Corefinement::INTERSECTION] != boost::none); CGAL_assertion(output[Corefinement::UNION] == boost::none); CGAL_assertion(output[Corefinement::TM1_MINUS_TM2] == boost::none); CGAL_assertion(output[Corefinement::TM2_MINUS_TM1] == boost::none); const bool use_compact_clipper = - parameters::choose_parameter( parameters::get_parameter(np1, internal_np::use_compact_clipper), - true); + choose_parameter(get_parameter(np1, internal_np::use_compact_clipper), true); ob.setup_for_clipping_a_surface(use_compact_clipper); } @@ -822,17 +812,20 @@ corefine_and_compute_difference( TriangleMesh& tm1, * \cgalNamedParamsEnd * */ - template - void - corefine( TriangleMesh& tm1, - TriangleMesh& tm2, - const NamedParameters1& np1, - const NamedParameters2& np2) +template +void +corefine( TriangleMesh& tm1, + TriangleMesh& tm2, + const NamedParameters1& np1, + const NamedParameters2& np2) { + using parameters::choose_parameter; + using parameters::get_parameter; + const bool throw_on_self_intersection = - parameters::choose_parameter(parameters::get_parameter(np1, internal_np::throw_on_self_intersection), false); + choose_parameter(get_parameter(np1, internal_np::throw_on_self_intersection), false); // Vertex point maps typedef typename GetVertexPointMap::value);) CGAL_static_assertion(same_vpm); - Vpm vpm1 = parameters::choose_parameter(parameters::get_parameter(np1, internal_np::vertex_point), - get_property_map(boost::vertex_point, tm1)); + Vpm vpm1 = choose_parameter(get_parameter(np1, internal_np::vertex_point), + get_property_map(boost::vertex_point, tm1)); - Vpm vpm2 = parameters::choose_parameter(parameters::get_parameter(np2, internal_np::vertex_point), - get_property_map(boost::vertex_point, tm2)); + Vpm vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), + get_property_map(boost::vertex_point, tm2)); // Edge is-constrained maps typedef typename internal_np::Lookup_named_param_def < @@ -863,10 +856,8 @@ corefine_and_compute_difference( TriangleMesh& tm1, Corefinement::No_mark//default > ::type Ecm2; - Ecm1 ecm1 = parameters::choose_parameter( parameters::get_parameter(np1, internal_np::edge_is_constrained), - Corefinement::No_mark() ); - Ecm2 ecm2 = parameters::choose_parameter( parameters::get_parameter(np2, internal_np::edge_is_constrained), - Corefinement::No_mark() ); + Ecm1 ecm1 = choose_parameter(get_parameter(np1, internal_np::edge_is_constrained)); + Ecm2 ecm2 = choose_parameter(get_parameter(np2, internal_np::edge_is_constrained)); typedef Corefinement::Ecm_bind Ecm; @@ -883,8 +874,7 @@ corefine_and_compute_difference( TriangleMesh& tm1, NamedParameters1, Corefinement::Default_visitor//default > ::type User_visitor; - User_visitor uv( parameters::choose_parameter( parameters::get_parameter(np1, internal_np::graph_visitor), - Corefinement::Default_visitor() ) ); + User_visitor uv(choose_parameter(get_parameter(np1, internal_np::graph_visitor))); // surface intersection algorithm call typedef Corefinement::No_extra_output_from_corefinement Ob; @@ -926,18 +916,20 @@ namespace experimental { * \cgalNamedParamsEnd * */ - template - void - autorefine( TriangleMesh& tm, - const NamedParameters& np) +template +void +autorefine( TriangleMesh& tm, + const NamedParameters& np) { -// Vertex point maps - typedef typename GetVertexPointMap::type Vpm; + using parameters::choose_parameter; + using parameters::get_parameter; - Vpm vpm = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point), - get_property_map(boost::vertex_point, tm)); +// Vertex point maps + typedef typename GetVertexPointMap::type Vpm; + + Vpm vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_property_map(boost::vertex_point, tm)); // Edge is-constrained maps typedef typename internal_np::Lookup_named_param_def < @@ -945,10 +937,7 @@ namespace experimental { NamedParameters, Corefinement::No_mark//default > ::type Ecm; - - - Ecm ecm = parameters::choose_parameter( parameters::get_parameter(np, internal_np::edge_is_constrained), - Corefinement::No_mark() ); + Ecm ecm = choose_parameter(get_parameter(np, internal_np::edge_is_constrained)); // User visitor typedef typename internal_np::Lookup_named_param_def < @@ -956,8 +945,7 @@ namespace experimental { NamedParameters, Corefinement::Default_visitor//default > ::type User_visitor; - User_visitor uv( parameters::choose_parameter( parameters::get_parameter(np, internal_np::graph_visitor), - Corefinement::Default_visitor() ) ); + User_visitor uv(choose_parameter(get_parameter(np, internal_np::graph_visitor))); // surface intersection algorithm call @@ -1002,38 +990,40 @@ namespace experimental { * \cgalNamedParamsEnd * */ - template - bool - autorefine_and_remove_self_intersections( TriangleMesh& tm, - const NamedParameters& np) +template +bool +autorefine_and_remove_self_intersections( TriangleMesh& tm, + const NamedParameters& np) { + using parameters::choose_parameter; + using parameters::get_parameter; + // Vertex point maps - typedef typename GetVertexPointMap::type Vpm; - Vpm vpm = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point), - get_property_map(boost::vertex_point, tm)); + typedef typename GetVertexPointMap::type Vpm; + Vpm vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_property_map(boost::vertex_point, tm)); + // Face index map - typedef typename GetFaceIndexMap::type Fid_map; - Fid_map fid_map = parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), - get_property_map(boost::face_index, tm)); + typedef typename GetInitializedFaceIndexMap::type Fid_map; + Fid_map fid_map = get_initialized_face_index_map(tm, np); + + // Edge is-constrained maps typedef typename internal_np::Lookup_named_param_def < internal_np::edge_is_constrained_t, NamedParameters, Corefinement::No_mark//default > ::type Ecm; - Ecm ecm = parameters::choose_parameter( parameters::get_parameter(np, internal_np::edge_is_constrained), - Corefinement::No_mark() ); + Ecm ecm = choose_parameter(get_parameter(np, internal_np::edge_is_constrained)); + // User visitor typedef typename internal_np::Lookup_named_param_def < internal_np::graph_visitor_t, NamedParameters, Corefinement::Default_visitor//default > ::type User_visitor; - User_visitor uv( parameters::choose_parameter( parameters::get_parameter(np, internal_np::graph_visitor), - Corefinement::Default_visitor() ) ); + User_visitor uv(choose_parameter(get_parameter(np, internal_np::graph_visitor))); // surface intersection algorithm call typedef Corefinement::Output_builder_for_autorefinement::const_type - fimap = parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), - get_const_property_map(boost::face_index, p)); - int offset = static_cast( - parameters::choose_parameter(parameters::get_parameter(np, internal_np::first_index), - 1)); + parameters::choose_parameter(parameters::get_parameter(np, internal_np::first_index), 1)); internal::PatchIdMapWrapper::value_type> wrapmap(patch_id_map, offset); + return connected_components(p, wrapmap, parameters::edge_is_constrained_map(eif) - .face_index_map(fimap)); - + .face_index_map(CGAL::get_initialized_face_index_map(p, np))); } + template typename boost::graph_traits::faces_size_type detect_surface_patches(PolygonMesh& p, @@ -373,8 +368,6 @@ namespace internal * computing a * surface patch id for each face. * - * A property map for `CGAL::face_index_t` must be either available - * as an internal property map to `pmesh` or provided as one of the Named Parameters. * * \tparam PolygonMesh a model of `FaceGraph` * \tparam FT a number type. It is diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h index ee5e3c2e9bc..b5098e28c2b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/distance.h @@ -34,7 +34,7 @@ #ifdef CGAL_LINKED_WITH_TBB #include #include -#include +#include #endif // CGAL_LINKED_WITH_TBB #include @@ -78,13 +78,13 @@ struct Distance_computation{ const AABB_tree& tree; const PointRange& sample_points; Point_3 initial_hint; - tbb::atomic* distance; + std::atomic* distance; Distance_computation( const AABB_tree& tree, const Point_3& p, const PointRange& sample_points, - tbb::atomic* d) + std::atomic* d) : tree(tree) , sample_points(sample_points) , initial_hint(p) @@ -108,7 +108,8 @@ struct Distance_computation{ double current_value = *distance; while( current_value < hdist ) { - current_value = distance->compare_and_swap(hdist, current_value); + if(distance->compare_exchange_weak(current_value, hdist)) + current_value = hdist; } } }; @@ -129,7 +130,7 @@ double approximate_Hausdorff_distance_impl( #else if (boost::is_convertible::value) { - tbb::atomic distance; + std::atomic distance; distance=0; Distance_computation f(tree, hint, sample_points, &distance); tbb::parallel_for(tbb::blocked_range(0, sample_points.size()), f); @@ -342,8 +343,7 @@ sample_triangle_mesh(const TriangleMesh& tm, typedef Creator_uniform_3 Creator; - Geom_traits geomtraits = choose_parameter(get_parameter(np, internal_np::geom_traits), Geom_traits()); - + Geom_traits geomtraits = choose_parameter(get_parameter(np, internal_np::geom_traits)); bool use_rs = choose_parameter(get_parameter(np, internal_np::random_uniform_sampling), true); bool use_gs = choose_parameter(get_parameter(np, internal_np::grid_sampling), false); @@ -588,8 +588,7 @@ double approximate_Hausdorff_distance( * for more details. * * @tparam Concurrency_tag 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 the concept `FaceListGraph` * @tparam NamedParameters1 a sequence of \ref pmp_namedparameters "Named Parameters" for `tm1` * @tparam NamedParameters2 a sequence of \ref pmp_namedparameters "Named Parameters" for `tm2` diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/extrude.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/extrude.h index a12e35e711d..681adab5578 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/extrude.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/extrude.h @@ -178,9 +178,9 @@ void extrude_mesh(const InputMesh& input, using parameters::choose_parameter; VPMap output_vpm = choose_parameter(get_parameter(np_out, internal_np::vertex_point), - get_property_map(vertex_point, output)); + get_property_map(vertex_point, output)); IVPMap input_vpm = choose_parameter(get_parameter(np_in, internal_np::vertex_point), - get_const_property_map(vertex_point, input)); + get_const_property_map(vertex_point, input)); std::vector > bottom_v2v; std::vector > bottom_h2h; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/fair.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/fair.h index 04f00342cc3..9f34be87d15 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/fair.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/fair.h @@ -141,14 +141,13 @@ namespace internal { Default_Weight_calculator; VPMap vpmap_ = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_property_map(vertex_point, tmesh)); + get_property_map(vertex_point, tmesh)); return internal::fair(tmesh, vertices, - choose_parameter(get_parameter(np, internal_np::sparse_linear_solver), Default_solver()), + choose_parameter(get_parameter(np, internal_np::sparse_linear_solver)), choose_parameter(get_parameter(np, internal_np::weight_calculator), Default_Weight_calculator(tmesh, vpmap_)), choose_parameter(get_parameter(np, internal_np::fairing_continuity), 1), - vpmap_ - ); + vpmap_); } template 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/Face_graph_output_builder.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h index 2f93d176784..602ae2a2fde 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h @@ -60,7 +60,8 @@ namespace params=PMP::parameters; template + template static void fill_polylines_to_skip( Intersection_polylines& polylines, @@ -223,8 +226,8 @@ class Face_graph_output_builder const std::vector& tm2_patch_ids, const boost::dynamic_bitset<>& patches_of_tm1_used, const boost::dynamic_bitset<>& patches_of_tm2_used, - const FIM& fids1, - const FIM& fids2, + const FIM1 fids1, + const FIM2 fids2, const TM& tm1, const TM& tm2) { @@ -341,18 +344,17 @@ class Face_graph_output_builder public: - Face_graph_output_builder( TriangleMesh& tm1, - TriangleMesh& tm2, - const VertexPointMap &vpm1, - const VertexPointMap &vpm2, - const FaceIdMap& fids1, - const FaceIdMap& fids2, - EdgeMarkMapBind& marks_on_input_edges, + Face_graph_output_builder(TriangleMesh& tm1, + TriangleMesh& tm2, + const VertexPointMap vpm1, + const VertexPointMap vpm2, + FaceIdMap1 fids1, + FaceIdMap2 fids2, + EdgeMarkMapBind& marks_on_input_edges, const VpmOutTuple& output_vpms, - EdgeMarkMapTuple& out_edge_mark_maps, - UserVisitor& user_visitor, - const std::array< - boost::optional, 4 >& requested_output) + EdgeMarkMapTuple& out_edge_mark_maps, + UserVisitor& user_visitor, + const std::array, 4 >& requested_output) : tm1(tm1), tm2(tm2) , vpm1(vpm1), vpm2(vpm2) , fids1(fids1), fids2(fids2) @@ -460,9 +462,12 @@ public: Intersection_edge_map& intersection_edges1 = mesh_to_intersection_edges[&tm1]; Intersection_edge_map& intersection_edges2 = mesh_to_intersection_edges[&tm2]; - // this will initialize face indices if the face index map is writable. - helpers::init_face_indices(tm1, fids1); - helpers::init_face_indices(tm2, fids2); + // The property map must be either writable or well-initialized + if(!BGL::internal::is_index_map_valid(fids1, num_faces(tm1), faces(tm1))) + BGL::internal::initialize_face_index_map(fids1, tm1); + + if(!BGL::internal::is_index_map_valid(fids2, num_faces(tm2), faces(tm2))) + BGL::internal::initialize_face_index_map(fids2, tm2); // bitset to identify coplanar faces boost::dynamic_bitset<> tm1_coplanar_faces(num_faces(tm1), 0); @@ -620,9 +625,8 @@ public: std::size_t nb_patches_tm1 = PMP::connected_components(tm1, bind_property_maps(fids1,make_property_map(&tm1_patch_ids[0])), - params::edge_is_constrained_map( - is_marked_1) - .face_index_map(fids1)); + params::edge_is_constrained_map(is_marked_1) + .face_index_map(fids1)); std::vector tm1_patch_sizes(nb_patches_tm1, 0); for(std::size_t i : tm1_patch_ids) @@ -634,9 +638,8 @@ public: std::size_t nb_patches_tm2 = PMP::connected_components(tm2, bind_property_maps(fids2,make_property_map(&tm2_patch_ids[0])), - params::edge_is_constrained_map( - is_marked_2) - .face_index_map(fids2)); + params::edge_is_constrained_map(is_marked_2) + .face_index_map(fids2)); std::vector tm2_patch_sizes(nb_patches_tm2, 0); for(Node_id i : tm2_patch_ids) @@ -1245,9 +1248,8 @@ public: polyline_lengths.push_back(polyline_info.second+1); } - typedef Patch_container Patches; + typedef Patch_container Patches1; + typedef Patch_container Patches2; boost::unordered_set border_nm_vertices; // only used if used_to_clip_a_surface == true if (used_to_clip_a_surface) @@ -1279,8 +1281,8 @@ public: } //store the patch description in a container to avoid recomputing it several times - Patches patches_of_tm1( tm1, tm1_patch_ids, fids1, intersection_edges1, nb_patches_tm1), - patches_of_tm2( tm2, tm2_patch_ids, fids2, intersection_edges2, nb_patches_tm2); + Patches1 patches_of_tm1(tm1, tm1_patch_ids, fids1, intersection_edges1, nb_patches_tm1); + Patches2 patches_of_tm2(tm2, tm2_patch_ids, fids2, intersection_edges2, nb_patches_tm2); // for each boolean operation, define two bitsets of patches contributing // to the result @@ -1460,11 +1462,12 @@ public: // operation in tm1 with removal (and optionally inside-out) delayed // First backup the border edges of patches to be used - Patches tmp_patches_of_tm1(tm1, - patches_of_tm1.patch_ids, - patches_of_tm1.fids, - patches_of_tm1.is_intersection_edge, - patches_of_tm1.patches.size()); + Patches1 tmp_patches_of_tm1(tm1, + patches_of_tm1.patch_ids, + patches_of_tm1.fids, + patches_of_tm1.is_intersection_edge, + patches_of_tm1.patches.size()); + boost::dynamic_bitset<> patches_of_tm1_removed = ~patches_of_tm1_used[inplace_operation_tm1]; for (std::size_t i = patches_of_tm1_removed.find_first(); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Output_builder_for_autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Output_builder_for_autorefinement.h index 3656f46aea3..031d23a1c36 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Output_builder_for_autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Output_builder_for_autorefinement.h @@ -214,9 +214,6 @@ public: const boost::dynamic_bitset<>& is_node_of_degree_one, const Mesh_to_map_node&) { - // this will initialize face indices if the face index map is writable. - helpers::init_face_indices(tm, fids); - // first build an unordered_map mapping a vertex to its node id + a set // of all intersection edges typedef boost::unordered_set Intersection_edge_map; @@ -239,8 +236,9 @@ public: intersection_edges.insert(edge(p.second.h2, tm)); } - // this will initialize face indices if the face index map is writable. - helpers::init_face_indices(tm, fids); + // The property map must be either writable or well-initialized + if(!BGL::internal::is_index_map_valid(fids, num_faces(tm), faces(tm))) + BGL::internal::initialize_face_index_map(fids, tm); // bitset to identify coplanar faces boost::dynamic_bitset<> tm_coplanar_faces(num_faces(tm), 0); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Visitor.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Visitor.h index 408b45e4578..d668782b25c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Visitor.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Visitor.h @@ -256,7 +256,7 @@ public: void update_terminal_nodes(std::vector&) { - CGAL_assertion(!"This function should not be called"); + CGAL_error_msg("This function should not be called"); } // The following code was used to split polylines at certains points. diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/face_graph_utils.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/face_graph_utils.h index 3e9b5499feb..c188231238c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/face_graph_utils.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/face_graph_utils.h @@ -424,7 +424,7 @@ template void extract_patch_simplices( std::size_t patch_id, PolygonMesh& pm, - const FaceIndexMap& fids, + const FaceIndexMap fids, const std::vector& patch_ids, std::vector::face_descriptor>& patch_faces, std::set::vertex_descriptor>& interior_vertices, @@ -480,13 +480,13 @@ struct Patch_container{ // external data members PolygonMesh& pm; const std::vector& patch_ids; - const FaceIndexMap& fids; + const FaceIndexMap fids; const IsIntersectionEdge& is_intersection_edge; // constructor Patch_container( PolygonMesh& pm, const std::vector& patch_ids, - const FaceIndexMap& fids, + const FaceIndexMap fids, const IsIntersectionEdge& is_intersection_edge, std::size_t nb_patches ) : patches(nb_patches) @@ -1010,14 +1010,15 @@ template < class TriangleMesh, class EdgeMarkMap2, class EdgeMarkMapOut, class IntersectionPolylines, - class PatchContainer, + class PatchContainer1, + class PatchContainer2, class UserVisitor> void fill_new_triangle_mesh( TriangleMesh& output, const boost::dynamic_bitset<>& patches_of_tm1_to_import, const boost::dynamic_bitset<>& patches_of_tm2_to_import, - PatchContainer& patches_of_tm1, - PatchContainer& patches_of_tm2, + PatchContainer1& patches_of_tm1, + PatchContainer2& patches_of_tm2, bool reverse_orientation_of_patches_from_tm1, bool reverse_orientation_of_patches_from_tm2, const IntersectionPolylines& polylines, @@ -1256,7 +1257,8 @@ void disconnect_patches( } template & patches_of_tm1_to_keep, const boost::dynamic_bitset<>& patches_of_tm2_to_import, - PatchContainer& patches_of_tm1, - PatchContainer& patches_of_tm2, + PatchContainer1& patches_of_tm1, + PatchContainer2& patches_of_tm2, bool reverse_patch_orientation_tm2, const IntersectionPolylines& polylines, const VertexPointMap& vpm1, @@ -1416,7 +1418,8 @@ remove_patches(TriangleMesh& tm, } template & patches_of_tm1_to_keep, const boost::dynamic_bitset<>& patches_of_tm2_to_import, - PatchContainer& patches_of_tm1, - PatchContainer& patches_of_tm2, + PatchContainer1& patches_of_tm1, + PatchContainer2& patches_of_tm2, bool reverse_patch_orientation_tm1, bool reverse_patch_orientation_tm2, const VertexPointMap& vpm1, @@ -1485,14 +1488,15 @@ void compute_inplace_operation( template void compute_border_edge_map( const TriangleMesh& tm1, const TriangleMesh& tm2, const IntersectionPolylines& polylines, - PatchContainer& patches_of_tm1, - PatchContainer& patches_of_tm2, + PatchContainer1& patches_of_tm1, + PatchContainer2& patches_of_tm2, EdgeMap& tm2_edge_to_tm1_edge) { typedef boost::graph_traits GT; @@ -1520,7 +1524,8 @@ void compute_border_edge_map( template & patches_of_tm1_to_keep, const boost::dynamic_bitset<>& patches_of_tm2_to_import, - PatchContainer& patches_of_tm1, - PatchContainer& patches_of_tm2, + PatchContainer1& patches_of_tm1, + PatchContainer2& patches_of_tm2, bool reverse_patch_orientation_tm1, bool reverse_patch_orientation_tm2, const VertexPointMap& vpm1, @@ -1631,9 +1636,22 @@ void remove_unused_polylines( halfedge_descriptor h = halfedge(v, tm), start=GT::null_halfedge(); do{ + + halfedge_descriptor tmp_start = h; while ( !is_border(h, tm) || is_border(opposite(h, tm), tm) ) + { h = opposite(next(h, tm), tm); + if (tmp_start==h) break; + } + if( !is_border(h, tm) ) + { + // nothing to do: the vertex has already been updated and is now in the middle of a patch kept. + // This function can be called after the stitching of the patches kept, the vertex halfedge + // can have been updated and no border halfedge might be found + break; + } halfedge_descriptor in = h; + if (start==GT::null_halfedge()) start=in; else 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..ab52338fcab 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_impl.h @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -156,7 +155,8 @@ class Intersection_of_triangle_meshes typedef typename graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename graph_traits::vertex_descriptor vertex_descriptor; - typedef typename CGAL::Box_intersection_d::Box_with_info_d Box; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Box; typedef boost::unordered_set Face_set; typedef boost::unordered_map Edge_to_faces; @@ -250,10 +250,11 @@ class Intersection_of_triangle_meshes if (callback_si.self_intersections_found()) throw Self_intersection_exception(); } - else - CGAL::box_intersection_d( face_boxes_ptr.begin(), face_boxes_ptr.end(), - edge_boxes_ptr.begin(), edge_boxes_ptr.end(), - callback, cutoff ); + else { + CGAL::box_intersection_d( face_boxes_ptr.begin(), face_boxes_ptr.end(), + edge_boxes_ptr.begin(), edge_boxes_ptr.end(), + callback, cutoff ); + } } // for autorefinement @@ -704,7 +705,7 @@ class Intersection_of_triangle_meshes switch(type){ case COPLANAR_TRIANGLES: #ifndef DO_NOT_HANDLE_COPLANAR_FACES - assert(!"COPLANAR_TRIANGLES : this point should never be reached!"); + CGAL_error_msg("COPLANAR_TRIANGLES : this point should never be reached!"); #else //nothing needs to be done, cf. comments at the beginning of the file #endif diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/Triangulate_hole_polygon_mesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/Triangulate_hole_polygon_mesh.h index ceffb940609..fe5cf5def22 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/Triangulate_hole_polygon_mesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/Triangulate_hole_polygon_mesh.h @@ -120,7 +120,7 @@ triangulate_hole_polygon_mesh(PolygonMesh& pmesh, P_edges.push_back(*circ); if(!vertex_map.insert(std::make_pair(target(*circ,pmesh), id++)).second) { #ifndef CGAL_TEST_SUITE - CGAL_warning(!"Returning no output. Non-manifold vertex is found on boundary!"); + CGAL_warning_msg(false, "Returning no output. Non-manifold vertex is found on boundary!"); #else std::cerr << "W: Returning no output. Non-manifold vertex is found on boundary!\n"; #endif diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/Triangulate_hole_polyline.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/Triangulate_hole_polyline.h index 6ff0e02c879..32f919a55d5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/Triangulate_hole_polyline.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/Triangulate_hole_polyline.h @@ -783,7 +783,7 @@ public: boost::tuple, bool, bool> res = construct_3D_triangulation(P, range, tr, edge_exist); if(!res.template get<2>()) { #ifndef CGAL_TEST_SUITE - CGAL_warning(!"Returning no output. Dimension of 3D Triangulation is below 2!"); + CGAL_warning_msg(false, "Returning no output. Dimension of 3D Triangulation is below 2!"); #else std::cerr << "W: Returning no output. Dimension of 3D Triangulation is below 2!\n"; #endif @@ -807,7 +807,7 @@ public: if(W.get(0, n-1) == Weight::NOT_VALID()) { #ifndef CGAL_TEST_SUITE - CGAL_warning(!"Returning no output. No possible triangulation is found!"); + CGAL_warning_msg(false, "Returning no output. No possible triangulation is found!"); #else std::cerr << "W: Returning no output. No possible triangulation is found!\n"; #endif @@ -1002,7 +1002,7 @@ private: Triangulate_hole_polyline all_space; all_space.triangulate_all(P, Q, WC, std::make_pair(h.first, h.second), W, lambda); if(W.get(h.first, h.second) == Weight::NOT_VALID()) { - CGAL_warning(!"Returning no output. Filling hole with incomplete patches is not successful!"); + CGAL_warning_msg(false, "Returning no output. Filling hole with incomplete patches is not successful!"); return Weight::NOT_VALID(); } } @@ -1023,7 +1023,7 @@ private: Triangulate_hole_polyline all_space; all_space.triangulate_all(P, Q, WC, std::make_pair(h.first, h.second), W, lambda); if(W.get(h.first, h.second) == Weight::NOT_VALID()) { - CGAL_warning(!"Returning no output. Filling hole with incomplete patches is not successful!"); + CGAL_warning_msg(false, "Returning no output. Filling hole with incomplete patches is not successful!"); return Weight::NOT_VALID(); } } @@ -1038,7 +1038,7 @@ private: tr.clear(); boost::tuple, bool, bool> res = construct_3D_triangulation(P, h, tr, edge_exist); if(!boost::get<0>(res)) { - CGAL_warning(!"Returning no output. Filling hole with incomplete patches is not successful!"); + CGAL_warning_msg(false, "Returning no output. Filling hole with incomplete patches is not successful!"); return Weight::NOT_VALID(); } start_edge = *boost::get<0>(res); @@ -1099,7 +1099,7 @@ private: if(W.get(0, n-1) == Weight::NOT_VALID()) { #ifndef CGAL_TEST_SUITE - CGAL_warning(!"Returning no output using Delaunay triangulation.\n Falling back to the general Triangulation framework."); + CGAL_warning_msg(false, "Returning no output using Delaunay triangulation.\n Falling back to the general Triangulation framework."); #else std::cerr << "W: Returning no output using Delaunay triangulation.\n" << "Falling back to the general Triangulation framework.\n"; @@ -1145,7 +1145,7 @@ public: if(W.get(0,n-1) == Weight::NOT_VALID() || n <= 2) { #ifndef CGAL_TEST_SUITE - CGAL_warning(!"Returning no output. No possible triangulation is found!"); + CGAL_warning_msg(false, "Returning no output. No possible triangulation is found!"); #else std::cerr << "W: Returning no output. No possible triangulation is found!\n"; #endif diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/experimental/experimental_code.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/experimental/experimental_code.h index dd73156743d..8320003a1e0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/experimental/experimental_code.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Hole_filling/experimental/experimental_code.h @@ -163,7 +163,7 @@ triangulate_hole_polyline_incomplete(InputIterator pbegin, InputIterator pend, if(new_facets.empty()) { // if no patch facets created and also we are using brute force approach, then there is nothing to do, // leave `out` intact and return - CGAL_warning(!"Returning no output. Filling hole with incomplete patches is not successful!"); + CGAL_warning_msg(false, "Returning no output. Filling hole with incomplete patches is not successful!"); return out; } } @@ -212,7 +212,7 @@ triangulate_hole_Polyhedron_incomplete(Polyhedron& polyhedron, if(patch_facets_before == patch_facets.size()) { // if no patch facets created and also we are using brute force approach, then there is nothing to do, // leave `out` intact and return - CGAL_warning(!"Returning no output. Filling hole with incomplete patches is not successful!"); + CGAL_warning_msg(false, "Returning no output. Filling hole with incomplete patches is not successful!"); return std::make_pair(out, Weight_min_max_dihedral_and_area::NOT_VALID()); } } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h index e5ddeadf013..f5cdff44e23 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h @@ -1513,7 +1513,9 @@ private: // tag patch border halfedges for(halfedge_descriptor h : halfedges(mesh_)) { - if (status(h)==PATCH && status(opposite(h, mesh_))!=PATCH) + if (status(h) == PATCH + && ( status(opposite(h, mesh_)) != PATCH + || get_patch_id(face(h, mesh_)) != get_patch_id(face(opposite(h, mesh_), mesh_)))) { set_status(h, PATCH_BORDER); has_border_ = true; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/helper.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/helper.h new file mode 100644 index 00000000000..5352ca1a8dd --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/helper.h @@ -0,0 +1,136 @@ +// Copyright (c) 2018, 2019 GeometryFactory (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Mael Rouxel-Labbé + +#ifndef CGAL_POLYGON_MESH_PROCESSING_INTERNAL_SNAPPING_HELPER_H +#define CGAL_POLYGON_MESH_PROCESSING_INTERNAL_SNAPPING_HELPER_H + +#include + +#include +#include +#include +#include + +namespace CGAL { +namespace Polygon_mesh_processing { +namespace internal { + +template +void vertices_as_halfedges(const VertexRange& vertex_range, + const PolygonMesh& pmesh, + HalfedgeOutputIterator out) +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + + for(vertex_descriptor v : vertex_range) + *out++ = halfedge(v, pmesh); +} + +// Assigns at each vertex the 'tolerance' value as tolerance, but bounded by a percentage of the length of its shortest incident edge +template +void assign_tolerance_with_local_edge_length_bound(const HalfedgeRange& halfedge_range, + ToleranceMap& tolerance_map, + const typename GetGeomTraits::type::FT tolerance, + PolygonMesh& mesh, + const NamedParameters& np) +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename GetVertexPointMap::type VPM; + typedef typename GetGeomTraits::type GT; + typedef typename GT::FT FT; + + using parameters::get_parameter; + using parameters::choose_parameter; + + GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); + VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_property_map(vertex_point, mesh)); + + for(halfedge_descriptor hd : halfedge_range) + { + const vertex_descriptor vd = target(hd, mesh); + CGAL::Halfedge_around_target_iterator hit, hend; + boost::tie(hit, hend) = CGAL::halfedges_around_target(vd, mesh); + CGAL_assertion(hit != hend); + + FT sq_length = gt.compute_squared_distance_3_object()(get(vpm, source(*hit, mesh)), + get(vpm, target(*hit, mesh))); + FT min_sq_dist = sq_length; + ++hit; + + for(; hit!=hend; ++hit) + { + sq_length = gt.compute_squared_distance_3_object()(get(vpm, source(*hit, mesh)), + get(vpm, target(*hit, mesh))); + + if(sq_length < min_sq_dist) + min_sq_dist = sq_length; + } + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "tolerance at vd: " << vd << " [" << get(vpm, vd) << "]: min of " + << 0.9 * CGAL::approximate_sqrt(min_sq_dist) << " AND " << tolerance << std::endl; +#endif + put(tolerance_map, vd, CGAL::min(0.9 * CGAL::approximate_sqrt(min_sq_dist), tolerance)); + } +} + +template +void assign_tolerance_with_local_edge_length_bound(const HalfedgeRange& halfedge_range, + ToleranceMap& tolerance_map, + const typename GetGeomTraits::type::FT tolerance, + PolygonMesh& mesh) +{ + return assign_tolerance_with_local_edge_length_bound(halfedge_range, tolerance_map, tolerance, mesh, CGAL::parameters::all_default()); +} + +template +bool is_collinear_with_tolerance(const typename GeomTraits::Point_3& p, // va == vb + const typename GeomTraits::Point_3& pa, + const typename GeomTraits::Point_3& pb, + const GeomTraits& gt) +{ + typedef typename GeomTraits::FT FT; + typedef typename GeomTraits::Vector_3 Vector_3; + + const Vector_3 va = gt.construct_vector_3_object()(p, pa); + const Vector_3 vb = gt.construct_vector_3_object()(p, pb); + const FT sp = gt.compute_scalar_product_3_object()(va, vb); + + // To avoid junctions like: + // ----va vb----- from being locked since it could be needed in ------------- later + // | | ----va vb--- + // | | + if(sp < FT(0)) + return false; + + const FT sq_va_l = gt.compute_squared_distance_3_object()(p, pa); + const FT sq_vb_l = gt.compute_squared_distance_3_object()(p, pb); + const FT sq_cos = 0.99999228397046306; // CGAL::square(std::cos(1°)); + + return (CGAL::square(sp) >= sq_va_l * sq_vb_l * sq_cos); +} + +} // namespace internal +} // namespace Polygon_mesh_processing +} // namespace CGAL + +#endif // CGAL_POLYGON_MESH_PROCESSING_INTERNAL_SNAPPING_HELPER_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap.h index 02a0422d5d6..6601dd0317a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap.h @@ -8,38 +8,49 @@ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // -// Author(s) : Sebastien Loriot -// Mael Rouxel-Labbé +// Author(s) : Mael Rouxel-Labbé +// Sebastien Loriot -#ifndef CGAL_POLYGON_MESH_PROCESSING_INTERNAL_SNAP_H -#define CGAL_POLYGON_MESH_PROCESSING_INTERNAL_SNAP_H +#ifndef CGAL_POLYGON_MESH_PROCESSING_SNAPPING_SNAP_H +#define CGAL_POLYGON_MESH_PROCESSING_SNAPPING_SNAP_H #include +#ifdef CGAL_PMP_SNAP_DEBUG_PP + #ifndef CGAL_PMP_SNAP_DEBUG + #define CGAL_PMP_SNAP_DEBUG + #endif +#endif + +#include +#include + #include #include #include +#include #include #include #include #include -#include #include #include -#include +#include #include #include #include #include +#include +#include -#include -#include -#include +#ifdef CGAL_EIGEN3_ENABLED +#include +#endif #ifdef CGAL_LINKED_WITH_TBB -# include -# include +#include +#include #endif #include @@ -48,912 +59,635 @@ #include #include #include -#include #include +#include #include +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT +#include +#endif + namespace CGAL { namespace Polygon_mesh_processing { namespace internal { -// Assigns at each vertex the 'tolerance' value as tolerance, but bounded by a percentage of the length of its shortest incident edge -template -void assign_tolerance_with_local_edge_length_bound(const HalfedgeRange& hrange, - ToleranceMap& tol_pmap, - const typename GetGeomTraits::type::FT tolerance, - PolygonMesh& mesh, - const SourceNamedParameters& snp) +template +void simplify_range(HalfedgeRange& halfedge_range, + TriangleMesh& tm, + ToleranceMap tolerance_map, + const NamedParameters& np) { + // @todo the simplification below is too naive and will fail to treat complicated zigzaging + // with long edges. + // A real simplification would create a fuzzy area around the border (say the dilation + // of the border polyline by a sphere of radius that continuously interpolates the tolerance + // at each vertex). The border is then simplified to use the least amount of edges possible + // in that fuzzy zone. Need to look into cartography papers, probably. + + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename GetGeomTraits::type GT; + typedef typename GT::FT FT; + + typedef typename GetVertexPointMap::type VPM; + typedef typename boost::property_traits::reference Point_ref; + using parameters::get_parameter; using parameters::choose_parameter; - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + const GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); + VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), get_property_map(vertex_point, tm)); - typedef typename GetVertexPointMap::type SVPM; - typedef typename GetGeomTraits::type GT; - typedef typename GT::FT FT; + typedef CGAL::dynamic_halfedge_property_t Halfedge_bool_tag; + typedef typename boost::property_map::type Range_halfedges; - GT gt = choose_parameter(get_parameter(snp, internal_np::geom_traits), GT()); - SVPM svpm = choose_parameter(get_parameter(snp, internal_np::vertex_point), - get_property_map(vertex_point, mesh)); + Range_halfedges range_halfedges = get(Halfedge_bool_tag(), tm); + for(halfedge_descriptor h : halfedge_range) + put(range_halfedges, h, true); - for(halfedge_descriptor hd : hrange) + CGAL_postcondition_code(const std::size_t initial_n = halfedge_range.size();) + + std::set edges_to_test(halfedge_range.begin(), halfedge_range.end()); + + int collapsed_n = 0; + while(!edges_to_test.empty()) { - const vertex_descriptor vd = target(hd, mesh); - CGAL::Halfedge_around_target_iterator hit, hend; - boost::tie(hit, hend) = CGAL::halfedges_around_target(vd, mesh); - CGAL_assertion(hit != hend); + const halfedge_descriptor h = *(edges_to_test.begin()); + edges_to_test.erase(edges_to_test.begin()); - FT sq_length = gt.compute_squared_distance_3_object()(get(svpm, source(*hit, mesh)), - get(svpm, target(*hit, mesh))); - FT min_sq_dist = sq_length; - ++hit; + const vertex_descriptor vs = source(h, tm); + const vertex_descriptor vt = target(h, tm); + const Point_ref ps = get(vpm, vs); + const Point_ref pt = get(vpm, vt); - for(; hit!=hend; ++hit) + // @fixme what if the source vertex is not to be snapped? Tolerance cannot be obtained... + // and where should the post-collapse vertex be since we can't move the source vertex... + // --> simply don't collapse? + const FT min_tol = (std::min)(get(tolerance_map, vs), get(tolerance_map, vt)); + const FT max_tol = (std::max)(get(tolerance_map, vs), get(tolerance_map, vt)); + + if(gt.compare_squared_distance_3_object()(ps,pt,CGAL::square(max_tol))==SMALLER) { - sq_length = gt.compute_squared_distance_3_object()(get(svpm, source(*hit, mesh)), - get(svpm, target(*hit, mesh))); + const halfedge_descriptor prev_h = prev(h, tm); + const halfedge_descriptor next_h = next(h, tm); - if(sq_length < min_sq_dist) - min_sq_dist = sq_length; + // check that the border has at least 4 edges not to create degenerate volumes + if(border_size(h, tm) >= 4) + { + const FT h_sq_length = gt.compute_squared_distance_3_object()(ps, pt); + vertex_descriptor v = Euler::collapse_edge(edge(h, tm), tm); + + put(vpm, v, gt.construct_midpoint_3_object()(ps, pt)); + put(tolerance_map, v, min_tol + 0.5 * CGAL::approximate_sqrt(h_sq_length)); + + if(get(range_halfedges, prev_h)) + edges_to_test.insert(prev_h); + if(get(range_halfedges, next_h)) + edges_to_test.insert(next_h); + + ++collapsed_n; + } } + } #ifdef CGAL_PMP_SNAP_DEBUG - std::cout << "tolerance at vd: " /*<< vd */ << " [" << get(svpm, vd) << "]: min of " - << 0.9 * CGAL::approximate_sqrt(min_sq_dist) << " AND " << tolerance << std::endl; -#endif - put(tol_pmap, vd, CGAL::min(0.9 * CGAL::approximate_sqrt(min_sq_dist), tolerance)); - } -} - -template -void assign_tolerance_with_local_edge_length_bound(const HalfedgeRange& hrange, - ToleranceMap& tol_pmap, - const typename GetGeomTraits::type::FT tolerance, - PolygonMesh& mesh) -{ - return assign_tolerance_with_local_edge_length_bound(hrange, tol_pmap, tolerance, mesh, CGAL::parameters::all_default()); -} - -template -struct Snapping_pair -{ - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename GeomTraits::FT FT; - - Snapping_pair(const vertex_descriptor vs_, const vertex_descriptor vt_, const FT sq_dist_) - : vs(vs_), vt(vt_), sq_dist(sq_dist_) - { } - - vertex_descriptor vs; - vertex_descriptor vt; - FT sq_dist; -}; - -template -struct Vertex_proximity_report -{ - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::edge_descriptor edge_descriptor; - - typedef typename GeomTraits::FT FT; - typedef typename boost::property_traits::value_type Point; - - Vertex_proximity_report(DistanceMultiIndexContainer& snapping_pairs, - const SVPM& svpm, const PolygonMesh& smesh, - const TVPM& tvpm, const PolygonMesh& tmesh, - const ToleranceMap& tol_pmap, - const GeomTraits& gt) - : - m_snapping_pairs(snapping_pairs), - is_same_mesh((&smesh == &tmesh)), - svpm(svpm), tvpm(tvpm), - tol_pmap(tol_pmap), - gt(gt) - { } - - void operator()(const Box& a, const Box& b) - { - vertex_descriptor va = a.info(); - vertex_descriptor vb = b.info(); - - if(is_same_mesh && va == vb) - return; - - const Point sp = get(svpm, va); - const Point tp = get(tvpm, vb); - const FT tol = get(tol_pmap, va); - - // Don't reject a '0' distance, it still needs to lock the points in place - const FT sq_dist = gt.compute_squared_distance_3_object()(sp, tp); - CGAL::Comparison_result res = CGAL::compare(sq_dist, tol * tol); - -#ifdef CGAL_PMP_SNAP_DEBUG_PP - std::cout << "distance between " /*<< va*/ << " [" << sp << "] and " - /*<< vb*/ << " [" << tp << "]: " << sq_dist - << " (bound: " << tol*tol << ") larger? " << (res == CGAL::LARGER) - << std::endl; + std::cout << "collapsed " << collapsed_n << " edges" << std::endl; #endif - if(res == CGAL::LARGER) - return; + std::vector new_range; + new_range.reserve(halfedge_range.size()); - m_snapping_pairs.insert(Snapping_pair(va, vb, sq_dist)); - } + for(halfedge_descriptor h : halfedges(tm)) + if(get(range_halfedges, h)) + new_range.push_back(h); -private: - DistanceMultiIndexContainer& m_snapping_pairs; + halfedge_range = HalfedgeRange(new_range.begin(), new_range.end()); - const bool is_same_mesh; - const SVPM& svpm; - const TVPM& tvpm; - const ToleranceMap& tol_pmap; - const GeomTraits& gt; -}; - -} // namespace internal - -namespace experimental { - -// This is the function if you know what you're doing with the ranges -// -// \ingroup PMP_repairing_grp -// -// Attempts to snap the vertices in `source_hrange` onto the vertices in `target_hrange`. -// A vertex of the source range is only snapped to a vertex of the target mesh -// if its distance to the target mesh vertex is smaller than a user-chosen bound. -// If a source vertex can be snapped onto multiple vertices of the target -// range, the closest target vertex is used. -// If multiple vertices within the source range could be snapped onto the same target vertex, -// the source vertex closest to the target vertex will be snapped. Other source vertices will try to snap -// to free target vertices until they find a valid target, or until there is no more target -// to snap to (within the tolerance). -// -// @warning This function does not give any guarantee on the conformity between the source and target meshes after the snapping. -// @warning This function does not merge vertices together. -// -// @tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph` -// @tparam SourceHalfedgeRange a model of `Range` with value type `boost::graph_traits::%halfedge_descriptor` -// @tparam TargetHalfedgeRange a model of `Range` with value type `boost::graph_traits::%halfedge_descriptor` -// @tparam ToleranceMap a model of `ReadablePropertyMap` with key type `boost::graph_traits::%vertex_descriptor` -// and value type `GetGeomTraits::type::FT` -// @tparam SourceNamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" -// @tparam TargetNamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" -// -// @param source_hrange a range of vertices of the source mesh whose positions can be changed. -// the vertices must be border vertices of `smesh`. -// @param smesh the source mesh whose border vertices might be moved -// @param target_hrange a range of vertices of the target mesh which are potential new positions -// for the vertices in the source range -// @param tmesh the target mesh to which the vertices in `target_hrange` belong -// @param tol_pmap a tolerance map associating to each vertex of the source range a tolerance value: -// potential projection targets are sought in a sphere centered at the vertex and -// whose radius is the tolerance value. -// @param snp optional \ref pmp_namedparameters "Named Parameters" related to the source mesh, -// amongst those described below: -// -// \cgalNamedParamsBegin -// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of the source mesh. -// The type of this map is model of `ReadWritePropertyMap`. -// If this parameter is omitted, an internal property map for -// `CGAL::vertex_point_t` must be available in `PolygonMesh` -// \cgalParamEnd -// \cgalParamBegin{geom_traits} a geometric traits class instance. -// The traits class must provide the nested types `Point_3` and `Vector_3`, -// and the nested functors : -// - `Construct_bbox_3` to construct a bounding box of a point, -// - `Compute_squared_distance_3` to compute the distance between two points, -// -// and, for each functor `Foo`, a function `Foo foo_object()` -// \cgalParamEnd -// \cgalNamedParamsEnd -// -// @param tnp optional \ref pmp_namedparameters "Named Parameters" related to the target mesh, -// amongst those described below: -// -// \cgalNamedParamsBegin -// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of the target mesh. -// The type of this map is model of `ReadablePropertyMap`. -// If this parameter is omitted, an internal property map for -// `CGAL::vertex_point_t` must be available in `PolygonMesh` -// \cgalParamEnd -// \cgalNamedParamsEnd -// -// @return the number of snapped vertices -// -// @sa `merge_duplicated_vertices_in_boundary_cycles()` -// -template -std::size_t snap_vertex_range_onto_vertex_range(const SourceHalfedgeRange& source_hrange, - PolygonMesh& smesh, - const TargetHalfedgeRange& target_hrange, - const PolygonMesh& tmesh, - const ToleranceMap& tol_pmap, - const SourceNamedParameters& snp, - const TargetNamedParameters& tnp) -{ - using parameters::get_parameter; - using parameters::choose_parameter; - - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - - typedef CGAL::Box_intersection_d::Box_with_info_d Box; - - typedef typename GetVertexPointMap::type SVPM; - typedef typename GetVertexPointMap::const_type TVPM; - typedef typename boost::property_traits::value_type Point; - - typedef typename GetGeomTraits::type GT; - typedef typename GT::FT FT; - - if(is_empty_range(source_hrange.begin(), source_hrange.end()) || - is_empty_range(target_hrange.begin(), target_hrange.end())) - return 0; - - CGAL_static_assertion((std::is_same::value)); - - GT gt = choose_parameter(get_parameter(snp, internal_np::geom_traits), GT()); - - SVPM svpm = choose_parameter(get_parameter(snp, internal_np::vertex_point), - get_property_map(vertex_point, smesh)); - TVPM tvpm = choose_parameter(get_parameter(tnp, internal_np::vertex_point), - get_const_property_map(vertex_point, tmesh)); - -#ifdef CGAL_PMP_SNAP_DEBUG - std::cout << "Snapping vertices to vertices. Range sizes: " - << std::distance(source_hrange.begin(), source_hrange.end()) << " and " - << std::distance(target_hrange.begin(), target_hrange.end()) << std::endl; - - if(&smesh == &tmesh) - std::cout << "same mesh!" << std::endl; -#endif - - // Try to snap vertices - std::vector boxes; - std::unordered_set unique_vertices; - for(halfedge_descriptor hd : source_hrange) - { - const vertex_descriptor vd = target(hd, smesh); - if(!unique_vertices.insert(vd).second) - continue; // if 'vd' appears multiple times on the border, move it only once - - // only making the box a little larger, but the final tolerance is not changed - const double eps = 1.01 * CGAL::to_double(get(tol_pmap, vd)); - - const Bbox_3 pb = gt.construct_bbox_3_object()(get(svpm, vd)); - const Bbox_3 b(pb.xmin() - eps, pb.ymin() - eps, pb.zmin() - eps, - pb.xmax() + eps, pb.ymax() + eps, pb.zmax() + eps); - boxes.push_back(Box(b, vd)); - } - - std::vector target_boxes; - for(halfedge_descriptor hd : target_hrange) - { - const vertex_descriptor vd = target(hd, tmesh); - const Point& p = get(tvpm, vd); - target_boxes.push_back(Box(gt.construct_bbox_3_object()(p), vd)); - } - - // Use a multi index to sort easily by sources, targets, AND distance. - // Then, look up the distances in increasing order, and snap whenever the source and the target - // have both not been snapped yet. - typedef internal::Snapping_pair Snapping_pair; - typedef boost::multi_index::multi_index_container< - Snapping_pair, - boost::multi_index::indexed_by< - boost::multi_index::ordered_non_unique< - BOOST_MULTI_INDEX_MEMBER(Snapping_pair, vertex_descriptor, vs)>, - boost::multi_index::ordered_non_unique< - BOOST_MULTI_INDEX_MEMBER(Snapping_pair, vertex_descriptor, vt)>, - boost::multi_index::ordered_non_unique< - BOOST_MULTI_INDEX_MEMBER(Snapping_pair, FT, sq_dist)> - > - > Snapping_pair_container; - - typedef internal::Vertex_proximity_report Reporter; - - Snapping_pair_container snapping_pairs; - Reporter vpr(snapping_pairs, svpm, smesh, tvpm, tmesh, tol_pmap, gt); - - // Shenanigans to pass a reference as callback (which is copied by value by 'box_intersection_d') - std::function callback(std::ref(vpr)); - - CGAL::box_intersection_d(boxes.begin(), boxes.end(), - target_boxes.begin(), target_boxes.end(), - callback); - -#ifdef CGAL_PMP_SNAP_DEBUG - std::cout << snapping_pairs.size() << " snappable pair(s)!" << std::endl; -#endif - - if(snapping_pairs.empty()) - return 0; - - // Sorted views of the container - typedef typename Snapping_pair_container::template nth_index<0>::type Container_by_source; - typedef typename Snapping_pair_container::template nth_index<1>::type Container_by_target; - typedef typename Snapping_pair_container::template nth_index<2>::type Container_by_distance; - - Container_by_source& container_by_source = snapping_pairs.template get<0>(); - Container_by_target& container_by_target = snapping_pairs.template get<1>(); - Container_by_distance& container_by_dist = snapping_pairs.template get<2>(); - - std::size_t counter = 0; - - CGAL_assertion_code(FT prev = -1;) - while(!container_by_dist.empty()) - { - const Snapping_pair& sp = *(container_by_dist.begin()); - const vertex_descriptor vs = sp.vs; - const vertex_descriptor vt = sp.vt; - CGAL_assertion(sp.sq_dist >= prev); - CGAL_assertion_code(prev = sp.sq_dist;) - -#ifdef CGAL_PMP_SNAP_DEBUG_PP - std::cout << "Snapping " /*<< vs*/ << " (" << get(svpm, vs) << ") " - << " to " /*<< vt*/ << " (" << get(tvpm, vt) << ") at dist: " << sp.sq_dist << std::endl; -#endif - - // Collect all the source vertices projecting onto that target vertex - ++counter; - put(svpm, vs, get(tvpm, vt)); - - // 'vs' and 'vt' cannot be used anymore, remove them from the container - container_by_source.erase(vs); - container_by_target.erase(vt); - } - - return counter; + CGAL_postcondition(halfedge_range.size() == initial_n - collapsed_n); } -template -std::size_t snap_vertex_range_onto_vertex_range(const SourceHalfedgeRange& source_hrange, - PolygonMesh& smesh, - const TargetHalfedgeRange& target_hrange, - const PolygonMesh& tmesh, - const SourceNamedParameters& snp, - const TargetNamedParameters& tnp) -{ - typedef typename GetGeomTraits::type GT; - typedef typename GT::FT FT; - typedef CGAL::dynamic_vertex_property_t Vertex_property_tag; - typedef typename boost::property_map::type Tolerance_map; - - Tolerance_map tol_pmap = get(Vertex_property_tag(), smesh); - const FT tol_mx(std::numeric_limits::max()); - internal::assign_tolerance_with_local_edge_length_bound(source_hrange, tol_pmap, tol_mx, smesh, snp); - - return snap_vertex_range_onto_vertex_range(source_hrange, smesh, target_hrange, tmesh, tol_pmap, snp, tnp); -} - -template -std::size_t snap_vertex_range_onto_vertex_range(const SourceHalfedgeRange& source_hrange, - PolygonMesh& smesh, - const TargetHalfedgeRange& target_hrange, - const PolygonMesh& tmesh, - const ToleranceMap& tol_pmap) -{ - return snap_vertex_range_onto_vertex_range(source_hrange, smesh, target_hrange, tmesh, tol_pmap, - CGAL::parameters::all_default(), - CGAL::parameters::all_default()); -} - -template -std::size_t snap_vertex_range_onto_vertex_range(const SourceHalfedgeRange& source_hrange, - PolygonMesh& smesh, - const TargetHalfedgeRange& target_hrange, - const PolygonMesh& tmesh) -{ - return snap_vertex_range_onto_vertex_range(source_hrange, smesh, target_hrange, tmesh, - CGAL::parameters::all_default(), - CGAL::parameters::all_default()); -} - -template -std::size_t snap_vertex_range_onto_vertex_range(PolygonMesh& smesh, const PolygonMesh& tmesh) -{ - return snap_vertex_range_onto_vertex_range(halfedges(smesh), smesh, halfedges(tmesh), tmesh); -} - -template -std::size_t snap_border_vertices_onto_vertex_range(PolygonMesh& smesh, - const HalfedgeRange& target_hrange, - const PolygonMesh& tmesh, - const ToleranceMap& tol_pmap) -{ - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - - std::vector border_vertices; - border_halfedges(smesh, std::back_inserter(border_vertices)); - - return snap_vertex_range_onto_vertex_range(border_vertices, smesh, target_hrange, tmesh, tol_pmap); -} - -template -std::size_t snap_border_vertices_onto_vertex_range(PolygonMesh& smesh, - const HalfedgeRange& target_hrange, - const PolygonMesh& tmesh) -{ - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - - std::vector border_vertices; - border_halfedges(smesh, std::back_inserter(border_vertices)); - - return snap_vertex_range_onto_vertex_range(border_vertices, smesh, target_hrange, tmesh); -} - -template -std::size_t snap_border_vertices_onto_border_vertices(PolygonMesh& smesh, - const PolygonMesh& tmesh, - const ToleranceMap& tol_pmap) -{ - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - - std::vector sborder_vertices; - border_halfedges(smesh, std::back_inserter(sborder_vertices)); - - std::vector tborder_vertices; - border_halfedges(tmesh, std::back_inserter(tborder_vertices)); - - return snap_vertex_range_onto_vertex_range(sborder_vertices, smesh, tborder_vertices, tmesh, tol_pmap); -} - -// \ingroup PMP_repairing_grp -// -// Attempts to snap the border vertices of the source mesh onto the vertices of the target mesh. -// -// A vertex of the source range is only snapped to a vertex of the target mesh -// if its distance to the target mesh vertex is smaller than a user-chosen bound. -// If any source vertex can be snapped onto multiple vertices of the target -// range, the closest one is chosen. -// If multiple vertices within the source range could be snapped onto the same target vertex, -// the source vertex closest to the target vertex will be snapped. Other source vertices will try to snap -// to free target vertices until they find a valid target, or until there is no more target -// to snap to (within the tolerance). -// -// @tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph` -// @tparam ToleranceMap a model of `ReadablePropertyMap` with key type `boost::graph_traits::%vertex_descriptor` -// and value type the number type associated with the traits of the mesh. -// -// @param smesh the source mesh whose border vertices might be moved -// @param tmesh the target mesh whose vertices are potential projection targets -// @param tol_pmap a tolerance map associating to each vertex of the source range a tolerance value: -// potential projection targets are sought in a sphere centered at the vertex and -// whose radius is the tolerance value. -// -// @pre `smesh` and `tmesh` are different meshes -// -// \return the number of snapped vertices -// -template -std::size_t snap_border_vertices_onto_vertex_range(PolygonMesh& smesh, - const PolygonMesh& tmesh, - const ToleranceMap& tol_pmap) -{ - return snap_border_vertices_onto_vertex_range(smesh, halfedges(tmesh), tmesh, tol_pmap); -} - -template -std::size_t snap_border_vertices_onto_vertex_range(PolygonMesh& smesh, const PolygonMesh& tmesh) -{ - return snap_border_vertices_onto_vertex_range(smesh, halfedges(tmesh), tmesh); -} - -} // namespace experimental - -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// - -namespace internal { - // Adapted from -template +template class Projection_traits { - typedef typename AABBTraits::FT FT; - typedef typename AABBTraits::Point_3 Point; - typedef typename AABBTraits::Primitive Primitive; - typedef typename AABBTraits::Bounding_box Bounding_box; - typedef typename AABBTraits::Primitive::Id Primitive_id; - typedef typename AABBTraits::Point_and_primitive_id Point_and_primitive_id; - typedef typename AABBTraits::Object_and_primitive_id Object_and_primitive_id; + typedef typename AABBTraits::FT FT; + typedef typename AABBTraits::Point_3 Point; + typedef typename AABBTraits::Primitive Primitive; + typedef typename AABBTraits::Bounding_box Bounding_box; + typedef typename AABBTraits::Primitive::Id Primitive_id; + typedef typename AABBTraits::Point_and_primitive_id Point_and_primitive_id; + typedef typename AABBTraits::Object_and_primitive_id Object_and_primitive_id; - typedef CGAL::AABB_node Node; + typedef CGAL::AABB_node Node; + + typedef typename AABBTraits::Geom_traits Geom_traits; + typedef typename Geom_traits::Vector_3 Vector; + typedef typename Geom_traits::Plane_3 Plane; + + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + +#ifdef CGAL_PMP_SNAP_USE_ANISOTROPIC_DISTANCE + void build_metric() + { + Vector hv(get(m_vpm_S, source(m_h, m_tm_S)), get(m_vpm_S, target(m_h, m_tm_S))); + Vector n = CGAL::Polygon_mesh_processing::compute_face_normal(face(opposite(m_h, m_tm_S), m_tm_S), m_tm_S, + CGAL::parameters::geom_traits(m_gt) + .vertex_point_map(m_vpm_S)); + Vector pn = m_gt.construct_cross_product_vector_3_object()(hv, n); + Plane pl(get(m_vpm_S, target(m_h, m_tm_S)), pn); + + Vector b1 = pl.base1(); + Vector b2 = pl.base2(); + + internal::normalize(b1, m_gt); + internal::normalize(b2, m_gt); + internal::normalize(pn, m_gt); + + Eigen::Matrix3d eigen_m; + eigen_m(0,0) = b1.x(); eigen_m(0,1) = b2.x(); eigen_m(0,2) = pn.x(); + eigen_m(1,0) = b1.y(); eigen_m(1,1) = b2.y(); eigen_m(1,2) = pn.y(); + eigen_m(2,0) = b1.z(); eigen_m(2,1) = b2.z(); eigen_m(2,2) = pn.z(); + + Eigen::Matrix3d eigen_diag = Eigen::Matrix3d::Zero(); + eigen_diag(0,0) = 1; + eigen_diag(1,1) = 1; + eigen_diag(2,2) = 100; // we scale by 1/sqrt(lambda_0) in the direction of n + + Eigen::Matrix3d eigen_mtransp = eigen_m.transpose(); + m_metric = eigen_m * eigen_diag * eigen_mtransp; + } +#endif + + FT squared_anisotropic_distance(const Point& p, const Point& q) const + { +#ifdef CGAL_PMP_SNAP_USE_ANISOTROPIC_DISTANCE + Vector pq(p, q); + Eigen::Vector3d ev; + ev(0) = pq.x(); + ev(1) = pq.y(); + ev(2) = pq.z(); + + return ev.transpose() * m_metric * ev; +#else + return CGAL::squared_distance(p, q); +#endif + } + + // The idea behind this function is to give priority to projections that are parallel to the edge 'e0' + // whom the query is the target of. This is done by considering an (anisotropic) distance that + // increases the distance if we are not projecting along the vector orthogonal to both the edge 'e0' + // and to the normal of the face, and also by checking the scalar product between the edges. + // The latter is because the distance to the projection point does not entirely reflect + // the alignment of the edges. + // + // This is WIP and likely to evolve... + bool is_better_than_current_best(const FT sq_dist, + const FT scalar_product) + { +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "is_better_than_current_best()" << std::endl; + std::cout << "sq_dist: " << sq_dist << std::endl; + std::cout << "m_sq_adist: " << m_sq_adist << std::endl; + std::cout << "scalar products: " << scalar_product << " " << m_sp_with_closest_edge << std::endl; +#endif + + // Automatically accept much closer tentative targets; automatically reject much farther tentative targets + const FT lambda = 4; // comparing squared distances + if(lambda * sq_dist < m_sq_adist) + return true; + if(lambda * m_sq_adist < sq_dist) + return false; + + return (scalar_product > m_sp_with_closest_edge); + } public: - explicit Projection_traits(const AABBTraits& traits, - const FT sq_tolerance) - : m_traits(traits), + explicit Projection_traits(const halfedge_descriptor h, + const std::size_t patch_id, + const FT sq_tolerance, + const TriangleMesh& tm_S, + const VPMS vpm_S, + const TriangleMesh& tm_T, + const FacePatchMap face_patch_map_T, + const VPMT vpm_T, + const AABBTraits& aabb_traits) + : + m_h(h), + m_patch_id(patch_id), + m_sq_tol(sq_tolerance), + m_tm_S(tm_S), m_vpm_S(vpm_S), + m_tm_T(tm_T), m_face_patch_map_T(face_patch_map_T), m_vpm_T(vpm_T), + m_is_same_mesh((&tm_S == &tm_T)), + m_continue(true), m_closest_point_initialized(false), - m_sq_dist(sq_tolerance) - {} + m_traits(aabb_traits), + m_gt(Geom_traits()) // blame AABB's traits management + { + // not fully convinced that it is still useful after adding scalar product shenanigans +// #define CGAL_PMP_SNAP_USE_ANISOTROPIC_DISTANCE +#ifdef CGAL_PMP_SNAP_USE_ANISOTROPIC_DISTANCE + build_metric(); +#endif - bool go_further() const { return true; } + Vector hv(get(vpm_S, source(h, tm_S)), get(vpm_S, target(h, tm_S))); + m_direction = hv; + CGAL::Polygon_mesh_processing::internal::normalize(m_direction, m_gt); + } + + bool go_further() const { return m_continue; } void intersection(const Point& query, const Primitive& primitive) { - // skip the primitive if one of its endpoints is the query - const typename Primitive::Datum& s = primitive.datum(m_traits.shared_data()); - if(m_traits.equal_3_object()(s[0], query) || m_traits.equal_3_object()(s[1], query)) +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "~~~~ intersection with primitive: " << primitive.id() << std::endl; + std::cout << get(m_vpm_T, source(primitive.id(), m_tm_T)) << std::endl; + std::cout << get(m_vpm_T, target(primitive.id(), m_tm_T)) << std::endl; +#endif + + halfedge_descriptor h = halfedge(primitive.id(), m_tm_T); + if(is_border(h, m_tm_T)) + h = opposite(h, m_tm_T); + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "patches: " << get(m_face_patch_map_T, face(h, m_tm_T)) << " " << m_patch_id << std::endl; +#endif + + if(get(m_face_patch_map_T, face(h, m_tm_T)) != m_patch_id) return; - if(!m_closest_point_initialized) + const typename Primitive::Datum& s = primitive.datum(m_traits.shared_data()); + if(m_traits.equal_3_object()(s[0], query) || m_traits.equal_3_object()(s[1], query)) { - m_closest_point_initialized = true; - m_closest_primitive = primitive.id(); - m_closest_point = primitive.reference_point(m_traits.shared_data()); - m_sq_dist = m_traits.squared_distance_object()(query, m_closest_point); + // If we are NOT using the same mesh and the query is (geometrically) equal to one extremity + // of the target edge, we don't want to move the source point away from the target point + // (because we cannot move the target point). + if(!m_is_same_mesh) + { +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "This vertex is stuck because it is equal to a vertex on the target mesh" << std::endl; +#endif + m_closest_point_initialized = false; + m_continue = false; + } + + // skip the primitive if one of its endpoints is the query + return; } - Point new_closest_point = m_traits.closest_point_object()(query, primitive, m_closest_point); - if(!m_traits.equal_3_object()(new_closest_point, m_closest_point)) + // We are searching for a point on the target border that is close to target(h). + // To try and avoid foldings, we penalize potential matches that are roughly in the direction of 'h' + // by using an anisotropic distance that is the Euclidean on the plane orthogonal to the direction, + // and much larger when traveling in the rough direction of 'h'. + // + // Note that we apply this to points that fall within the tolerance ball, so if there is + // only a single candidate that is in a direction we don't like, we still take it. + // + // @todo should the construct_projected_point_3 be anisotropic too? + const Point new_closest_point = m_gt.construct_projected_point_3_object()( + CGAL::internal::Primitive_helper::get_datum(primitive, m_traits), query); + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "closest point to primitive: " << new_closest_point << std::endl; +#endif + + const FT sq_ad_to_tentative_closest_pt = squared_anisotropic_distance(query, new_closest_point); + + Vector tentative_dir(get(m_vpm_T, source(primitive.id(), m_tm_T)), + get(m_vpm_T, target(primitive.id(), m_tm_T))); + CGAL::Polygon_mesh_processing::internal::normalize(tentative_dir, m_gt); + const FT sp_with_tentative = CGAL::abs(tentative_dir * m_direction); + + if(!m_closest_point_initialized || + is_better_than_current_best(sq_ad_to_tentative_closest_pt, sp_with_tentative)) { +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "is better!" << std::endl; +#endif + + m_closest_point_initialized = true; + m_closest_primitive = primitive.id(); m_closest_point = new_closest_point; - m_sq_dist = m_traits.squared_distance_object()(query, m_closest_point); + m_sq_adist = sq_ad_to_tentative_closest_pt; + m_sp_with_closest_edge = sp_with_tentative; } } bool do_intersect(const Point& query, const Node& node) const { - return m_traits.compare_distance_object()(query, node.bbox(), m_sq_dist) == CGAL::SMALLER; + // This should NOT be the anisotropic distance, as we want to test all targets within the tolerance + return m_traits.compare_distance_object()(query, node.bbox(), m_sq_tol) == CGAL::SMALLER; } const Point& closest_point() const { return m_closest_point; } typename Primitive::Id closest_primitive_id() const { return m_closest_primitive; } bool closest_point_initialized() const { return m_closest_point_initialized; } + FT scalar_product_with_best() const { return m_sp_with_closest_edge; } private: - const AABBTraits& m_traits; + halfedge_descriptor m_h; + const std::size_t m_patch_id; + const FT m_sq_tol; + Vector m_direction; +#ifdef CGAL_PMP_SNAP_USE_ANISOTROPIC_DISTANCE + Eigen::Matrix3d m_metric; +#endif + + const TriangleMesh& m_tm_S; + VPMS m_vpm_S; + const TriangleMesh& m_tm_T; + FacePatchMap m_face_patch_map_T; + VPMT m_vpm_T; + const bool m_is_same_mesh; + + bool m_continue; bool m_closest_point_initialized; - Point m_closest_point; - FT m_sq_dist; - typename Primitive::Id m_closest_primitive; + Point m_closest_point; + FT m_sq_adist; + FT m_sp_with_closest_edge; // scalar product between m_h and the current best edge candidate + + const AABBTraits& m_traits; + Geom_traits m_gt; }; -template -struct Compare_points_along_edge +template +struct Edges_to_split_map_inserter // Parallel { - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename GeomTraits::Point_3 Point; - - Compare_points_along_edge(halfedge_descriptor support, - const GeomTraits& gt, const VPM& vpm, const PolygonMesh& pm) - : gt(gt), m_src(get(vpm, source(support, pm))) - { } - - bool operator()(const Point& p1, const Point& p2) const { - return gt.less_distance_to_point_3_object()(m_src, p1, p2); +#ifdef CGAL_LINKED_WITH_TBB + template + void operator()(EdgeToSplitMap& edges_to_split, + const HalfedgeDescriptor closest_h, + const HalfedgeDescriptor h, + const Point& closest_p) + { + typename EdgeToSplitMap::accessor acc; + edges_to_split.insert(acc, closest_h); + acc->second.emplace_back(h, closest_p); } - - const GeomTraits& gt; - Point m_src; +#endif }; -template -void find_splittable_edge(const std::pair::value_type, - typename GT::FT>& point_with_tolerance, - EdgeToSplitContainer& edges_to_split, +template <> +struct Edges_to_split_map_inserter +{ + template + void operator()(EdgeToSplitMap& edges_to_split, + const HalfedgeDescriptor closest_h, + const HalfedgeDescriptor h, + const Point& closest_p) + { + edges_to_split[closest_h].emplace_back(h, closest_p); + } +}; + +// The UniqueVertex is a pair of a container of vertex_descriptor and FT, representing +// vertices with the same geometric position and their associated snapping tolerance +// (defined as the minimum of the tolerances of the vertices of the bunch) +template +void find_splittable_edge(const VertexWithTolerance& vertex_with_tolerance, + EdgeToSplitMap& edges_to_split, const AABBTree* aabb_tree_ptr, - const TriangleMesh& /* pms */, - const VPM& /* vpms */, - const TriangleMesh& pmt, - const VPM& vpmt, + const TriangleMesh& tm_S, + VertexPatchMap_S vertex_patch_map_S, + VPMS vpm_S, + const TriangleMesh& tm_T, + FacePatchMap_T face_patch_map_T, + VPMT vpm_T, const GT& gt) { - CGAL_USE(vpmt); - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; - typedef typename GT::FT FT; - typedef typename boost::property_traits::value_type Point; + typedef typename GT::FT FT; + typedef typename boost::property_traits::value_type Point; + typedef typename boost::property_traits::reference Point_ref; - typedef typename AABBTree::AABB_traits AABB_traits; + typedef typename AABBTree::AABB_traits AABB_traits; - const Point& query = point_with_tolerance.first; - const FT sq_tolerance = CGAL::square(point_with_tolerance.second); + typedef internal::Projection_traits Projection_traits; - // use the current halfedge as hint - internal::Projection_traits traversal_traits(aabb_tree_ptr->traits(), sq_tolerance); + // by construction the whole range has the same position + const halfedge_descriptor h = vertex_with_tolerance.first; + const vertex_descriptor v = target(h, tm_S); + const Point_ref query = get(vpm_S, v); + const FT sq_tolerance = CGAL::square(vertex_with_tolerance.second); + const std::size_t patch_id = get(vertex_patch_map_S, v); + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "--------------------------- Query: " << v << " (" << query << ")" << std::endl; +#endif + + Projection_traits traversal_traits(h, patch_id, sq_tolerance, tm_S, vpm_S, + tm_T, face_patch_map_T, vpm_T, aabb_tree_ptr->traits()); aabb_tree_ptr->traversal(query, traversal_traits); if(!traversal_traits.closest_point_initialized()) + { +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "Couldn't find any single projection point" << std::endl; +#endif return; + } const Point& closest_p = traversal_traits.closest_point(); // The filtering in the AABB tree checks the dist query <-> node bbox, which might be smaller than // the actual distance between the query <-> closest point - const FT sq_dist_to_closest = gt.compute_squared_distance_3_object()(query, closest_p); - bool is_close_enough = (sq_dist_to_closest <= sq_tolerance); + edge_descriptor closest_e = traversal_traits.closest_primitive_id(); + bool is_close_enough = + gt.compare_squared_distance_3_object()(query, + gt.construct_segment_3_object()(get(vpm_T, source(closest_e, tm_T)), + get(vpm_T, target(closest_e, tm_T))), + sq_tolerance) != LARGER; #ifdef CGAL_PMP_SNAP_DEBUG_PP std::cout << " Closest point: (" << closest_p << ")" << std::endl - << " at distance " << gt.compute_squared_distance_3_object()(query, closest_p) - << " with a tolerance of " << point_with_tolerance.second << " at vertex (squared tol: " << sq_tolerance - << " && close enough? " << is_close_enough << ")" << std::endl; + << " on edge: " << traversal_traits.closest_primitive_id() + << " at sq distance " << gt.compute_squared_distance_3_object()(query, closest_p) + << " with squared tolerance: " << sq_tolerance + << " && close enough? " << is_close_enough << std::endl; #endif if(!is_close_enough) return; -#ifdef CGAL_PMP_SNAP_DEBUG_PP - std::cout << "\t and is thus beneath tolerance" << std::endl; -#endif - edge_descriptor closest = traversal_traits.closest_primitive_id(); - CGAL_assertion(get(vpmt, source(closest, pmt)) != query && - get(vpmt, target(closest, pmt)) != query); + CGAL_assertion(get(vpm_T, source(closest_e, tm_T)) != query && + get(vpm_T, target(closest_e, tm_T)) != query); - halfedge_descriptor clos_hd = halfedge(closest, pmt); - CGAL_assertion(is_border(edge(clos_hd, pmt), pmt)); + halfedge_descriptor closest_h = halfedge(closest_e, tm_T); + CGAL_assertion(is_border(edge(closest_h, tm_T), tm_T)); - if(!is_border(clos_hd, pmt)) - clos_hd = opposite(clos_hd, pmt); + if(!is_border(closest_h, tm_T)) + closest_h = opposite(closest_h, tm_T); -#ifdef CGAL_PMP_SNAP_DEBUG_PP - std::cout << "splitting position: " << query << std::endl; -#endif - - edges_to_split.push_back(std::make_pair(query, clos_hd)); + // Using a map because we need to know if the same halfedge is split multiple times + Edges_to_split_map_inserter()(edges_to_split, closest_h, vertex_with_tolerance.first, closest_p); } #ifdef CGAL_LINKED_WITH_TBB template + typename TriangleMesh, typename EdgeToSplitMap, typename AABBTree, + typename VertexPatchMap_S, typename FacePatchMap_T, + typename VPMS, typename VPMT, typename GT> struct Find_splittable_edge_for_parallel_for { Find_splittable_edge_for_parallel_for(const PointWithToleranceContainer& points_with_tolerance, - EdgeToSplitContainer& edges_to_split, + EdgeToSplitMap& edges_to_split, const AABBTree* aabb_tree_ptr, - const TriangleMesh& pms, - const VPM& vpms, - const TriangleMesh& pmt, - const VPM& vpmt, + const TriangleMesh& tm_S, + const VertexPatchMap_S vertex_patch_map_S, + const VPMS vpm_S, + const TriangleMesh& tm_T, + const FacePatchMap_T face_patch_map_T, + const VPMT vpm_T, const GT& gt) : m_points_with_tolerance(points_with_tolerance), m_edges_to_split(edges_to_split), m_aabb_tree_ptr(aabb_tree_ptr), - m_pms(pms), m_vpms(vpms), m_pmt(pmt), m_vpmt(vpmt), m_gt(gt) + m_tm_S(tm_S), m_vertex_patch_map_S(vertex_patch_map_S), m_vpm_S(vpm_S), + m_tm_T(tm_T), m_face_patch_map_T(face_patch_map_T), m_vpm_T(vpm_T), + m_gt(gt) { } void operator()(const tbb::blocked_range& r) const { for(std::size_t i=r.begin(); i!=r.end(); ++i) { - find_splittable_edge(m_points_with_tolerance[i], m_edges_to_split, - m_aabb_tree_ptr, - m_pms, m_vpms, m_pmt, m_vpmt, - m_gt); + find_splittable_edge(m_points_with_tolerance[i], m_edges_to_split, m_aabb_tree_ptr, + m_tm_S, m_vertex_patch_map_S, m_vpm_S, + m_tm_T, m_face_patch_map_T, m_vpm_T, m_gt); } } private: const PointWithToleranceContainer& m_points_with_tolerance; - EdgeToSplitContainer& m_edges_to_split; + EdgeToSplitMap& m_edges_to_split; const AABBTree* m_aabb_tree_ptr; - const TriangleMesh& m_pms; - const VPM m_vpms; - const TriangleMesh& m_pmt; - const VPM m_vpmt; + const TriangleMesh& m_tm_S; + const VertexPatchMap_S m_vertex_patch_map_S; + const VPMS m_vpm_S; + const TriangleMesh& m_tm_T; + const FacePatchMap_T m_face_patch_map_T; + const VPMT m_vpm_T; const GT& m_gt; }; #endif -} // namespace internal - -namespace experimental { - -// Try to merge vertices in 'hrange' (vd = target(hd, pm)) onto the edges in the 'erange', -// non-conformingly -template -std::size_t snap_vertex_range_onto_vertex_range_non_conforming(const HalfedgeRange& source_hrange, - TriangleMesh& pms, - const HalfedgeRange& target_hrange, - TriangleMesh& pmt, - const ToleranceMap& tol_pmap, - const NamedParameters& nps, - const NamedParameters& npt) +template +std::size_t split_edges(EdgesToSplitContainer& edges_to_split, + TriangleMesh& tm_S, + VPMS vpm_S, + TriangleMesh& tm_T, + VPMT vpm_T, + const GeomTraits& gt, + const bool is_source_mesh_fixed) // when snapping is B --> A and the mesh B is fixed { - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << "split " << edges_to_split.size() << " edges" << std::endl; +#endif - typedef typename GetVertexPointMap::type VPM; - typedef typename boost::property_traits::value_type Point; - typedef typename boost::property_traits::reference Point_ref; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename GetGeomTraits::type GT; - typedef typename GT::FT FT; - typedef typename GT::Vector_3 Vector; + typedef typename boost::property_traits::value_type Point; + typedef typename boost::property_traits::reference Point_ref; + typedef typename GeomTraits::Vector_3 Vector; - typedef internal::Compare_points_along_edge Point_along_edge_comparer; - - typedef CGAL::AABB_halfedge_graph_segment_primitive Primitive; - typedef CGAL::AABB_traits AABB_Traits; - typedef CGAL::AABB_tree AABB_tree; - - using parameters::get_parameter; - using parameters::choose_parameter; - - // Need to have a triangle mesh to ensure that the refinement point of a border edge 'e' has visibility - // of the third p oint of the face 'f' incident to 'e' - CGAL_precondition(is_triangle_mesh(pmt)); + typedef std::pair Vertex_with_new_position; + typedef std::vector Vertices_with_new_position; + typedef std::pair Edge_and_splitters; std::size_t snapped_n = 0; - VPM vpms = choose_parameter(get_parameter(nps, internal_np::vertex_point), get_property_map(vertex_point, pms)); - VPM vpmt = choose_parameter(get_parameter(npt, internal_np::vertex_point), get_property_map(vertex_point, pmt)); + CGAL::Real_timer timer; + timer.start(); - const GT gt = choose_parameter(get_parameter(nps, internal_np::geom_traits), GT()); - - // start by snapping vertices together to simplify things - snapped_n = snap_vertex_range_onto_vertex_range(source_hrange, pms, target_hrange, pmt, tol_pmap, nps, npt); - -#ifdef CGAL_PMP_SNAP_DEBUG - std::cout << "Snapping vertices to edges. Range sizes: " - << std::distance(source_hrange.begin(), source_hrange.end()) << " and " - << std::distance(target_hrange.begin(), target_hrange.end()) << std::endl; -#endif - - // Collect border points that can be projected onto a border edge - typedef std::map Unique_vertices_with_tolerance; // unordered map is empirically slower - - // If the point appears multiple times on the source border, use it only once to snap target edges - // use the smallest tolerance from all source vertices - -#ifdef CGAL_PMP_SNAP_DEBUG - std::cout << "gather unique points in source range" << std::endl; -#endif - - Unique_vertices_with_tolerance unique_source_vertices; - for(halfedge_descriptor hd : source_hrange) + for(Edge_and_splitters& es : edges_to_split) { - // Skip the source vertex if its two incident halfedges are geometrically identical (it means that - // the two halfedges are already stitchable and we don't want this common vertex to be used - // to split a halfedge somewhere else) - if(get(vpms, source(hd, pms)) == get(vpms, target(next(hd, pms), pms))) - continue; + halfedge_descriptor h_to_split = es.first; + CGAL_assertion(is_border(h_to_split, tm_T)); - const vertex_descriptor vd = target(hd, pms); - const Point_ref query = get(vpms, vd); - const FT tolerance = get(tol_pmap, vd); + Vertices_with_new_position& splitters = es.second; - std::pair is_insert_successful = - unique_source_vertices.insert(std::make_pair(query, tolerance)); - - // Keep the lowest tolerance out of all the source vertices with the same position - is_insert_successful.first->second = (std::min)(is_insert_successful.first->second, tolerance); - -#ifdef CGAL_PMP_SNAP_DEBUG_PP - if(is_insert_successful.second) - std::cout << "Query: " << vd << " (" << query << ")" << std::endl; -#endif - } - - // Since we're inserting primitives one by one, we can't pass this shared data in the constructor of the tree - AABB_Traits aabb_traits; - aabb_traits.set_shared_data(pmt, vpmt); - AABB_tree aabb_tree(aabb_traits); - - for(halfedge_descriptor hd : target_hrange) - { - CGAL_precondition(is_border(edge(hd, pmt), pmt)); - aabb_tree.insert(Primitive(edge(hd, pmt), pmt, vpmt)); - } - - // Now, check which edges of the target range ought to be split by source vertices -#ifdef CGAL_PMP_SNAP_DEBUG_PP - std::cout << "Collect edges to split w/ " << unique_source_vertices.size() << " unique vertices" << std::endl; -#endif - -#ifdef CGAL_LINKED_WITH_TBB -#ifdef CGAL_PMP_SNAP_DEBUG - std::cout << "Parallel find splittable edges!" << std::endl; -#endif - - typedef tbb::concurrent_vector > Concurrent_edge_to_split_container; - - // Can't parallel for a map... - std::vector > unique_vertices_with_tolerance_vector(unique_source_vertices.begin(), - unique_source_vertices.end()); - - typedef internal::Find_splittable_edge_for_parallel_for >, - TriangleMesh, - Concurrent_edge_to_split_container, - AABB_tree, VPM, GT> Functor; - - Concurrent_edge_to_split_container edges_to_split; - Functor f(unique_vertices_with_tolerance_vector, edges_to_split, &aabb_tree, pms, vpms, pmt, vpmt, gt); - tbb::parallel_for(tbb::blocked_range(0, unique_vertices_with_tolerance_vector.size()), f); -#else // CGAL_LINKED_WITH_TBB -#ifdef CGAL_PMP_SNAP_DEBUG - std::cout << "Sequential find splittable edges!" << std::endl; -#endif - typedef std::pair Point_with_tolerance; - - std::vector > edges_to_split; - for(const Point_with_tolerance& point_with_tolerance : unique_source_vertices) - { - internal::find_splittable_edge(point_with_tolerance, edges_to_split, &aabb_tree, - pms, vpms, pmt, vpmt, gt); - } -#endif - - // Sort points falling on the same edge and split the edge - std::map > points_per_edge; - typedef std::pair Pair_type; - for(const Pair_type& p : edges_to_split) - points_per_edge[p.second].push_back(p.first); - -#ifdef CGAL_PMP_SNAP_DEBUG - std::cout << "split " << points_per_edge.size() << " edges" << std::endl; -#endif - - typedef std::pair > Map_type; - for(Map_type& mt : points_per_edge) - { - const halfedge_descriptor mt_hd = mt.first; - const halfedge_descriptor mt_hd_opp = opposite(mt_hd, pmt); - CGAL_assertion(!is_border(mt_hd_opp, pmt)); - - if(mt.second.size() > 1) + if(splitters.size() > 1) { #ifdef CGAL_PMP_SNAP_DEBUG_PP - std::cout << " MUST SORT ON BORDER!" << std::endl; + std::cout << " _______ Multiple splitting points on the same halfedge" << std::endl; #endif - /// \todo Sorting the projected positions is too simple (for example, this doesn't work - /// for a zigzaging polyline). Rather, points should be sorted following - /// the order along the matching border. Note that this requires identifying - /// matching polylines because a sequence of zigzaging points might not all project - /// onto the same halfedge. - Point_along_edge_comparer cmp(mt_hd, gt, vpmt, pmt); - std::sort(mt.second.begin(), mt.second.end(), cmp); + + const Point_ref hsp = get(vpm_T, source(h_to_split, tm_T)); + std::sort(splitters.begin(), splitters.end(), + [&](const Vertex_with_new_position& l, const Vertex_with_new_position& r) -> bool + { + return gt.less_distance_to_point_3_object()(hsp, l.second, r.second); + }); } - halfedge_descriptor hd_to_split = mt_hd; - for(const Point& p : mt.second) + // Inserting new points ordered from the source to the target of (the initial) 'h' + bool first_split = true; + Point previous_split_position = get(vpm_S, *(vertices(tm_S).begin())); // dummy value to avoid "used uninitialized" warning + for(const Vertex_with_new_position& vnp : splitters) { + const halfedge_descriptor splitter_h = vnp.first; + const vertex_descriptor splitter_v = target(splitter_h, tm_S); + const Point new_position = is_source_mesh_fixed ? get(vpm_S, splitter_v) : vnp.second; + + bool do_split = true; + + // Some splits can create degenerate faces, avoid that + if((new_position == get(vpm_T, target(h_to_split, tm_T))) || + (new_position == get(vpm_T, source(h_to_split, tm_T)))) + do_split = false; + + if(!first_split && new_position == previous_split_position) + do_split = false; + #ifdef CGAL_PMP_SNAP_DEBUG_PP - std::cout << "SPLIT " << edge(hd_to_split, pmt) << " |||| " - << " vs " << source(hd_to_split, pmt) << " (" << pmt.point(source(hd_to_split, pmt)) << ")" - << " --- vt " << target(hd_to_split, pmt) << " (" << pmt.point(target(hd_to_split, pmt)) << ")" << std::endl; - std::cout << " with pos " << p << std::endl; + std::cout << " -.-.-. Splitting " << edge(h_to_split, tm_T) << " |||| " + << " Vs " << source(h_to_split, tm_T) << " (" << tm_T.point(source(h_to_split, tm_T)) << ")" + << " --- Vt " << target(h_to_split, tm_T) << " (" << tm_T.point(target(h_to_split, tm_T)) << ")" << std::endl; + std::cout << "With point: " << vnp.second << std::endl; + std::cout << "Actually split? " << do_split << std::endl; #endif - halfedge_descriptor res = CGAL::Euler::split_edge(hd_to_split, pmt); - put(vpmt, target(res, pmt), p); + // Split and update positions + vertex_descriptor new_v = boost::graph_traits::null_vertex(); + if(do_split) + { + CGAL::Euler::split_edge(h_to_split, tm_T); + new_v = source(h_to_split, tm_T); + put(vpm_T, new_v, new_position); // position of the new point on the target mesh + } + + if(!is_source_mesh_fixed) + put(vpm_S, splitter_v, new_position); + + first_split = false; + previous_split_position = new_position; ++snapped_n; - // @todo ensuring hd_to_split is safe... but is it necessary? - hd_to_split = next(res, pmt); - halfedge_descriptor hd_to_split_opp = opposite(hd_to_split, pmt); + // Everything below is choosing the diagonal to triangulate the quad formed by the edge split + // So, it's only relevant if splitting has been performed + if(!do_split) + continue; - // Look at the geometry to determine which diagonal is better to use to split this new quad face - - /* p + /* new_p * / \ - * res / \ hd_to_split + * res / \ h_to_split * / \ * / \ * left right @@ -962,22 +696,24 @@ std::size_t snap_vertex_range_onto_vertex_range_non_conforming(const HalfedgeRan * | / * | / * | / - * opp + * | / + * opp */ - const Point_ref left_pt = get(vpmt, source(res, pmt)); - const Point_ref right_pt = get(vpmt, target(hd_to_split, pmt)); - const Point_ref opp = get(vpmt, target(next(opposite(res, pmt), pmt), pmt)); + const halfedge_descriptor res = prev(h_to_split, tm_T); + const Point_ref left_pt = get(vpm_T, source(res, tm_T)); + const Point_ref right_pt = get(vpm_T, target(h_to_split, tm_T)); + const Point_ref opp = get(vpm_T, target(next(opposite(res, tm_T), tm_T), tm_T)); // Check if 'p' is "visible" from 'opp' (i.e. its projection on the plane 'Pl(left, opp, right)' // falls in the cone with apex 'opp' and sides given by 'left' and 'right') const Vector n = gt.construct_orthogonal_vector_3_object()(right_pt, left_pt, opp); - const Point trans_left_pt = gt.construct_translated_point_3_object()(left_pt, n); const Point trans_right_pt = gt.construct_translated_point_3_object()(right_pt, n); - const bool left_of_left = (gt.orientation_3_object()(trans_left_pt, left_pt, opp, p) == CGAL::POSITIVE); - const bool right_of_right = (gt.orientation_3_object()(right_pt, trans_right_pt, opp, p) == CGAL::POSITIVE); + const Point_ref new_p = get(vpm_T, new_v); + const bool left_of_left = (gt.orientation_3_object()(trans_left_pt, left_pt, opp, new_p) == CGAL::POSITIVE); + const bool right_of_right = (gt.orientation_3_object()(right_pt, trans_right_pt, opp, new_p) == CGAL::POSITIVE); const bool is_visible = (!left_of_left && !right_of_right); @@ -986,17 +722,20 @@ std::size_t snap_vertex_range_onto_vertex_range_non_conforming(const HalfedgeRan std::cout << "visible from " << opp << " ? " << is_visible << std::endl; #endif + // h_to_split is equal to 'next(res)' after splitting + const halfedge_descriptor h_to_split_opp = opposite(h_to_split, tm_T); + if(is_visible) { - halfedge_descriptor new_hd = CGAL::Euler::split_face(hd_to_split_opp, - prev(prev(mt_hd_opp, pmt), pmt), pmt); - hd_to_split = opposite(prev(new_hd, pmt), pmt); + halfedge_descriptor new_hd = CGAL::Euler::split_face(h_to_split_opp, + prev(prev(h_to_split_opp, tm_T), tm_T), tm_T); + h_to_split = opposite(prev(new_hd, tm_T), tm_T); } else { - halfedge_descriptor new_hd = CGAL::Euler::split_face(opposite(res, pmt), - prev(hd_to_split_opp, pmt), pmt); - hd_to_split = opposite(next(new_hd, pmt), pmt); + halfedge_descriptor new_hd = CGAL::Euler::split_face(opposite(res, tm_T), + prev(h_to_split_opp, tm_T), tm_T); + h_to_split = opposite(next(new_hd, tm_T), tm_T); } } } @@ -1004,27 +743,465 @@ std::size_t snap_vertex_range_onto_vertex_range_non_conforming(const HalfedgeRan return snapped_n; } -template -std::size_t snap_vertex_range_onto_vertex_range_non_conforming(const HalfedgeRange& source_hrange, - TriangleMesh& pms, - const HalfedgeRange& target_hrange, - TriangleMesh& pmt, - const ToleranceMap& tol_pmap) +// Collect border points that can be projected onto a border edge +// +// If multiple vertices on the source border have the same geometric position, they are moved +// all at once and we use the smallest tolerance from all source vertices with that position. +// This is done to solve situation such as: +// || +// || +// ____||____ +// ---------- +// (vertex-vertex snapping into non-conformal snapping) in one go. +template +std::size_t snap_non_conformal_one_way(const HalfedgeRange& halfedge_range_S, + TriangleMesh& tm_S, + ToleranceMap tolerance_map_S, + VertexPatchMap_S vertex_patch_map_S, + LockedVertexMap locked_vertices_S, + const HalfedgeRange& halfedge_range_T, + TriangleMesh& tm_T, + FacePatchMap_T face_patch_map_T, + LockedHalfedgeMap locked_halfedges_T, + const bool is_source_mesh_fixed, + const SourceNamedParameters& snp, + const TargetNamedParameters& tnp) { - return snap_vertex_range_onto_vertex_range_non_conforming(source_hrange, pms, target_hrange, pmt, - tol_pmap, parameters::all_default(), - parameters::all_default()); + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename GetGeomTraits::type GT; + typedef typename GT::FT FT; + + typedef typename GetVertexPointMap::type VPMS; + typedef typename GetVertexPointMap::type VPMT; + + typedef typename boost::property_traits::value_type Point; + + typedef CGAL::AABB_halfedge_graph_segment_primitive Primitive; + typedef CGAL::AABB_traits AABB_Traits; + typedef CGAL::AABB_tree AABB_tree; + + typedef std::pair Vertex_with_new_position; + typedef std::vector Vertices_with_new_position; + + using parameters::get_parameter; + using parameters::choose_parameter; + + VPMS vpm_S = choose_parameter(get_parameter(snp, internal_np::vertex_point), get_property_map(vertex_point, tm_S)); + VPMT vpm_T = choose_parameter(get_parameter(tnp, internal_np::vertex_point), get_property_map(vertex_point, tm_T)); + const GT gt = choose_parameter(get_parameter(snp, internal_np::geom_traits)); + +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << "Gather unique points in source range..." << std::endl; +#endif + + typedef std::pair Vertex_with_tolerance; + typedef std::vector Vertices_with_tolerance; + + Vertices_with_tolerance vertices_to_snap; + vertices_to_snap.reserve(halfedge_range_S.size()); // ensures that iterators stay valid + + // Take the min tolerance for all points that have the same coordinates + std::map point_tolerance_map; + + for(halfedge_descriptor h : halfedge_range_S) + { + if(get(locked_vertices_S, target(h, tm_S))) + continue; + + // Skip the source vertex if its two incident halfedges are geometrically identical (it means that + // the two halfedges are already stitchable and we don't want this common vertex to be used + // to split a halfedge somewhere else) + if(get(vpm_S, source(h, tm_S)) == get(vpm_S, target(next(h, tm_S), tm_S))) + continue; + + const vertex_descriptor v = target(h, tm_S); + const FT tolerance = get(tolerance_map_S, v); + + vertices_to_snap.emplace_back(h, tolerance); + + std::pair entry(get(vpm_S, v), tolerance); + std::pair::iterator, bool> is_insert_successful = + point_tolerance_map.insert(entry); + if(!is_insert_successful.second) + is_insert_successful.first->second = (std::min)(is_insert_successful.first->second, tolerance); + + #ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "Non-conformal query: " << v << " (" << get(vpm_S, v) << "), tolerance: " << tolerance << std::endl; +#endif + } + + for(auto& p : vertices_to_snap) + p.second = point_tolerance_map[get(vpm_S, target(p.first, tm_S))]; + + // Since we're inserting primitives one by one, we can't pass this shared data in the constructor of the tree + AABB_Traits aabb_traits; + aabb_traits.set_shared_data(tm_T, vpm_T); + AABB_tree aabb_tree(aabb_traits); + + for(halfedge_descriptor h : halfedge_range_T) + { + CGAL_precondition(is_border(edge(h, tm_T), tm_T)); + if(get(locked_halfedges_T, h)) + { +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << edge(h, tm_T) << " is locked and not a valid target" << std::endl; +#endif + continue; + } + + aabb_tree.insert(Primitive(edge(h, tm_T), tm_T, vpm_T)); + } + + // Now, check which edges of the target range ought to be split by source vertices +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "Collect edges to split with " << vertices_to_snap.size() << " vertices" << std::endl; +#endif + +#ifndef CGAL_LINKED_WITH_TBB + CGAL_static_assertion_msg (!(std::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable."); +#else + if(std::is_convertible::value) + { +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << "Parallel find splittable edges!" << std::endl; +#endif + + typedef tbb::concurrent_hash_map Concurrent_edge_to_split_container; + typedef internal::Find_splittable_edge_for_parallel_for< + Vertices_with_tolerance, TriangleMesh, + Concurrent_edge_to_split_container, AABB_tree, + VertexPatchMap_S, FacePatchMap_T, VPMS, VPMT, GT> Functor; + + CGAL::Real_timer timer; + timer.start(); + + Concurrent_edge_to_split_container edges_to_split; + Functor f(vertices_to_snap, edges_to_split, &aabb_tree, + tm_S, vertex_patch_map_S, vpm_S, tm_T, face_patch_map_T, vpm_T, gt); + tbb::parallel_for(tbb::blocked_range(0, vertices_to_snap.size()), f); + + std::cout << "Time to gather edges: " << timer.time() << std::endl; + + return split_edges(edges_to_split, tm_S, vpm_S, tm_T, vpm_T, gt, is_source_mesh_fixed); + } + else +#endif // CGAL_LINKED_WITH_TBB + { +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << "Sequential find splittable edges!" << std::endl; +#endif + + std::map edges_to_split; + for(const Vertex_with_tolerance& vt : vertices_to_snap) + { + internal::find_splittable_edge(vt, edges_to_split, &aabb_tree, + tm_S, vertex_patch_map_S, vpm_S, + tm_T, face_patch_map_T, vpm_T, gt); + } + + return split_edges(edges_to_split, tm_S, vpm_S, tm_T, vpm_T, gt, is_source_mesh_fixed); + } } +// \ingroup PMP_repairing_grp +// +// Attempts to snap the vertices in `halfedge_range_A` onto edges of `halfedge_range_B`, and reciprocally. +// A vertex from the first range is only snapped to an edge of the second range if the distance to +// the edge is smaller than the tolerance prescribed at the vertex. +// +// \warning This function does not give any guarantee on the conformity between the two meshes after the snapping. +// \warning This function does not merge vertices or the meshes, it is purely geometric. +// +// \tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph` +// \tparam HalfedgeRange_A a model of `Range` with value type `boost::graph_traits::%halfedge_descriptor` +// \tparam HalfedgeRange_B a model of `Range` with value type `boost::graph_traits::%halfedge_descriptor` +// \tparam ToleranceMap_A a model of `ReadablePropertyMap` with key type `boost::graph_traits::%vertex_descriptor` +// and value type `GetGeomTraits::type::FT` +// \tparam ToleranceMap_B a model of `ReadablePropertyMap` with key type `boost::graph_traits::%vertex_descriptor` +// and value type `GetGeomTraits::type::FT` +// \tparam NamedParameters_A a sequence of \ref pmp_namedparameters "Named Parameters" +// \tparam NamedParameters_B a sequence of \ref pmp_namedparameters "Named Parameters" +// +// \param halfedge_range_A a range of halfedges of the first mesh defining a set of vertices (as targets of the halfeges) +// \param tm_A the first mesh to which the vertices in `halfedge_range_A` belong +// \param tolerance_map_A a tolerance map associating to each vertex of the first range a tolerance value +// \param halfedge_range_B a range of vertices of the second mesh defining a set of vertices (as targets of the halfeges) +// \param tolerance_map_B a tolerance map associating to each vertex of the second range a tolerance value +// \param tm_B the target mesh to which the vertices in `halfedge_range_B` belong +// \param np_A optional \ref pmp_namedparameters "Named Parameters" related to the source mesh, +// amongst those described below: +// +// \cgalNamedParamsBegin +// \cgalParamBegin{vertex_point_map} +// the property map with the points associated to the vertices of the source mesh. +// The type of this map is model of `ReadWritePropertyMap`. If this parameter is omitted, +// an internal property map for `CGAL::vertex_point_t` must be available in `TriangleMesh`. +// \cgalParamEnd +// \cgalParamBegin{geom_traits} +// a geometric traits class instance, must be a model of `Kernel` +// \cgalParamEnd +// \cgalNamedParamsEnd +// +// \param np_B optional \ref pmp_namedparameters "Named Parameters" related to the target mesh, +// amongst those described below: +// +// \cgalNamedParamsBegin +// \cgalParamBegin{vertex_point_map} +// the property map with the points associated to the vertices of the target mesh. +// The type of this map is model of `ReadablePropertyMap`. If this parameter is omitted, +// an internal property map for `CGAL::vertex_point_t` must be available in `TriangleMesh`. +// \cgalParamEnd +// \cgalNamedParamsEnd +// +// \return the number of snapped vertex pairs +// +template +std::size_t snap_non_conformal(HalfedgeRange& halfedge_range_A, + TriangleMesh& tm_A, + ToleranceMap_A tolerance_map_A, + HalfedgeRange& halfedge_range_B, + TriangleMesh& tm_B, + ToleranceMap_B tolerance_map_B, + const bool is_self_snapping, // == true if range and meshes are equal + const NamedParameters_A& np_A, + const NamedParameters_B& np_B) +{ +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout.precision(17); + std::cerr.precision(17); +#endif + + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + typedef CGAL::dynamic_vertex_property_t Vertex_bool_tag; + typedef CGAL::dynamic_vertex_property_t Vertex_size_t_tag; + typedef CGAL::dynamic_halfedge_property_t Halfedge_bool_tag; + + typedef typename boost::property_map::type Locked_vertices; + typedef typename boost::property_map::type Locked_halfedges; + typedef typename boost::property_map::type Vertex_patch; + + typedef typename internal_np::Lookup_named_param_def < + internal_np::face_patch_t, NamedParameters_A, + Constant_property_map /*default*/ >::type Face_patch_map_A; + typedef typename internal_np::Lookup_named_param_def < + internal_np::face_patch_t, NamedParameters_B, + Constant_property_map /*default*/ >::type Face_patch_map_B; + + using CGAL::parameters::choose_parameter; + using CGAL::parameters::is_default_parameter; + using CGAL::parameters::get_parameter; + + const bool is_same_mesh = (&tm_A == &tm_B); + const bool simplify_first_mesh = choose_parameter(get_parameter(np_A, internal_np::do_simplify_border), false); + const bool simplify_second_mesh = choose_parameter(get_parameter(np_B, internal_np::do_simplify_border), false); + const bool is_second_mesh_fixed = choose_parameter(get_parameter(np_B, internal_np::do_lock_mesh), false); + + // vertex-vertex and vertex-edge snapping is only considered within compatible patches + Face_patch_map_A face_patch_map_A = choose_parameter(get_parameter(np_A, internal_np::face_patch), + Constant_property_map(-1)); + Face_patch_map_B face_patch_map_B = choose_parameter(get_parameter(np_B, internal_np::face_patch), + Constant_property_map(-1)); + + Vertex_patch vertex_patch_map_A = get(Vertex_size_t_tag(), tm_A); + Vertex_patch vertex_patch_map_B = get(Vertex_size_t_tag(), tm_B); + + for(const halfedge_descriptor h : halfedge_range_A) + { + CGAL_precondition(is_border(h, tm_A)); + halfedge_descriptor h_opp = opposite(h, tm_A); + for(const vertex_descriptor v : vertices_around_face(h_opp, tm_A)) + put(vertex_patch_map_A, v, get(face_patch_map_A, face(h_opp, tm_A))); + } + + // @todo avoid that when 'self_snapping' is true + for(const halfedge_descriptor h : halfedge_range_B) + { + CGAL_precondition(is_border(h, tm_B)); + halfedge_descriptor h_opp = opposite(h, tm_B); + for(const vertex_descriptor v : vertices_around_face(h_opp, tm_B)) + put(vertex_patch_map_B, v, get(face_patch_map_B, face(h_opp, tm_B))); + } + +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << "Non-conformal snapping... Range sizes: " + << std::distance(halfedge_range_A.begin(), halfedge_range_A.end()) << " and " + << std::distance(halfedge_range_B.begin(), halfedge_range_B.end()) << std::endl; +#endif + + CGAL_expensive_precondition(is_valid_polygon_mesh(tm_S) && is_triangle_mesh(tm_S)); + CGAL_expensive_precondition(is_valid_polygon_mesh(tm_T) && is_triangle_mesh(tm_T)); + + // Steps: + // - #1 Simplify the source range + // - #1bis Simplify the target range (if it's not locked) + // - #2 two-way vertex-vertex snapping + // - #3 two-way vertex-edge snapping + + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// #1 and #1bis (Simplification of borders) + ////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << "Simplify ranges (" << simplify_first_mesh << " " << simplify_second_mesh << ")..." << std::endl; +#endif + + if(simplify_first_mesh) + { + internal::simplify_range(halfedge_range_A, tm_A, tolerance_map_A, np_A); + +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT + std::ofstream("results/simplified_A.off") << std::setprecision(17) << tm_A; +#endif + } + + if(!is_self_snapping && !is_second_mesh_fixed && simplify_second_mesh) + { + internal::simplify_range(halfedge_range_B, tm_B, tolerance_map_B, np_B); + +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT + std::ofstream("results/simplified_B.off") << std::setprecision(17) << tm_B; +#endif + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// #2 (Two-way vertex-vertex snapping) + ////////////////////////////////////////////////////////////////////////////////////////////////// + + // We keep in memory pairs of source/target edges that are stitchable after vertex-vertex snapping + // --> these halfedges should not be considered as targets in non-conformal snapping + // Similarly, matching vertices whose incident edges have matching directions are also locked + Locked_vertices locked_vertices_A = get(Vertex_bool_tag(), tm_A); + Locked_vertices locked_vertices_B = get(Vertex_bool_tag(), tm_B); + Locked_halfedges locked_halfedges_A = get(Halfedge_bool_tag(), tm_A); + Locked_halfedges locked_halfedges_B = get(Halfedge_bool_tag(), tm_B); + + std::size_t snapped_n = 0; + + std::vector > locked_vertices; + std::vector locked_halfedges_A_vector, locked_halfedges_B_vector; + + snapped_n += internal::snap_vertices_two_way( + halfedge_range_A, tm_A, tolerance_map_A, vertex_patch_map_A, + halfedge_range_B, tm_B, tolerance_map_B, vertex_patch_map_B, + std::back_inserter(locked_vertices), + std::back_inserter(locked_halfedges_A_vector), + std::back_inserter(locked_halfedges_B_vector), + is_second_mesh_fixed, np_A, np_B); + + for(const auto& vpair : locked_vertices) + { + put(locked_vertices_A, vpair.first, true); + put(locked_vertices_B, vpair.second, true); + if(is_same_mesh) + { + put(locked_vertices_B, vpair.first, true); + put(locked_vertices_A, vpair.second, true); + } + } + + for(const halfedge_descriptor h : locked_halfedges_A_vector) + put(locked_halfedges_A, h, true); + for(const halfedge_descriptor h : locked_halfedges_B_vector) + put(locked_halfedges_B, h, true); + + if(is_same_mesh) + { + for(const halfedge_descriptor h : locked_halfedges_A_vector) + put(locked_halfedges_B, h, true); + for(const halfedge_descriptor h : locked_halfedges_B_vector) + put(locked_halfedges_A, h, true); + } + +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT + std::ofstream("results/vertex_vertex_A.off") << std::setprecision(17) << tm_A; + std::ofstream("results/vertex_vertex_B.off") << std::setprecision(17) << tm_B; +#endif + + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// #3 (Two one-way vertex-edge snapping) + ////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << " ///////////// Two one-way vertex-edge snapping (A --> B) " << std::endl; +#endif + + snapped_n += internal::snap_non_conformal_one_way( + halfedge_range_A, tm_A, tolerance_map_A, vertex_patch_map_A, locked_vertices_A, + halfedge_range_B, tm_B, face_patch_map_B, locked_halfedges_B, + false /*source is never fixed*/, np_A, np_B); + +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT + std::ofstream("results/vertex_edge_A.off") << std::setprecision(17) << tm_A; + std::ofstream("results/vertex_edge_B.off") << std::setprecision(17) << tm_B; +#endif + + if(!is_self_snapping) + { +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << " ///////////// Two one-way vertex-edge snapping (B --> A) " << std::endl; +#endif + + snapped_n += internal::snap_non_conformal_one_way( + halfedge_range_B, tm_B, tolerance_map_B, vertex_patch_map_B, locked_vertices_B, + halfedge_range_A, tm_A, face_patch_map_A, locked_halfedges_A, + is_second_mesh_fixed, np_B, np_A); + } + + return snapped_n; +} + +} // namespace internal + +namespace experimental { + //////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// +/// Convenience overloads //////////////////////////////////////////////////////////////////////////////////////////////////// -// Attempt to snap the vertices of the border of 'pm1' onto border edges of 'pm2'. +template +std::size_t snap_borders(TriangleMesh& tm_A, + ToleranceMap_A tolerance_map_A, + TriangleMesh& tm_B, + ToleranceMap_B tolerance_map_B, + const NamedParameters_A& np_A, + const NamedParameters_B& np_B) +{ + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; -template -std::size_t snap_border_vertices_non_conforming(TriangleMesh& pm1, - TriangleMesh& pm2) + std::vector border_vertices_1; + border_halfedges(tm_A, std::back_inserter(border_vertices_1)); + std::vector border_vertices_2; + border_halfedges(tm_B, std::back_inserter(border_vertices_2)); + + return internal::snap_non_conformal(border_vertices_1, tm_A, tolerance_map_A, + border_vertices_2, tm_B, tolerance_map_B, + false /*not self snapping*/, np_A, np_B); +} + +template +std::size_t snap_borders(TriangleMesh& tm_A, + TriangleMesh& tm_B, + const NamedParameters_A& np_A, + const NamedParameters_B& np_B) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; @@ -1034,84 +1211,109 @@ std::size_t snap_border_vertices_non_conforming(TriangleMesh& pm1, typedef CGAL::dynamic_vertex_property_t Vertex_property_tag; typedef typename boost::property_map::type Tolerance_map; - std::vector border_vertices1; - border_halfedges(pm1, std::back_inserter(border_vertices1)); + std::vector border_vertices_1; + std::vector border_vertices_2; + border_halfedges(tm_A, std::back_inserter(border_vertices_1)); + border_halfedges(tm_B, std::back_inserter(border_vertices_2)); - std::vector border_vertices2; - if(&pm1 == &pm2) - border_vertices2 = border_vertices1; - else - border_halfedges(pm2, std::back_inserter(border_vertices2)); - - Tolerance_map tol_pmap = get(Vertex_property_tag(), pm1); const FT tol_mx(std::numeric_limits::max()); - internal::assign_tolerance_with_local_edge_length_bound(border_vertices1, tol_pmap, tol_mx, pm1); + Tolerance_map tolerance_map_A = get(Vertex_property_tag(), tm_A); + internal::assign_tolerance_with_local_edge_length_bound(border_vertices_1, tolerance_map_A, tol_mx, tm_A, np_A); + Tolerance_map tolerance_map_B = get(Vertex_property_tag(), tm_A); + internal::assign_tolerance_with_local_edge_length_bound(border_vertices_2, tolerance_map_B, tol_mx, tm_B, np_B); - return snap_vertex_range_onto_vertex_range_non_conforming(border_vertices1, pm1, - border_vertices2, pm2, tol_pmap, - CGAL::parameters::all_default(), - CGAL::parameters::all_default()); + return internal::snap_non_conformal(border_vertices_1, tm_A, tolerance_map_A, + border_vertices_2, tm_B, tolerance_map_B, + false /*no self snapping*/, np_A, np_B); } -template -std::size_t snap_border_vertices_non_conforming(TriangleMesh& pm1, - TriangleMesh& pm2, - const ToleranceMap& tol_pmap, - const NamedParameters& np1, - const NamedParameters& np2) +template +std::size_t snap_borders(TriangleMesh& tm_A, + ToleranceMap_A tolerance_map_A, + TriangleMesh& tm_B, + ToleranceMap_B tolerance_map_B) +{ + return snap_borders(tm_A, tolerance_map_A, tm_B, tolerance_map_B, + CGAL::parameters::all_default(), CGAL::parameters::all_default()); +} + +template +std::size_t snap_borders(TriangleMesh& tm_A, + TriangleMesh& tm_B) +{ + return snap_borders(tm_A, tm_B, CGAL::parameters::all_default(), CGAL::parameters::all_default()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Same as above, but with a single mesh + +template +std::size_t snap_borders(TriangleMesh& tm, + ToleranceMap tolerance_map, + const CGAL_PMP_NP_CLASS& np) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - std::vector border_vertices1; - border_halfedges(pm1, std::back_inserter(border_vertices1)); + std::vector border_vertices; + border_halfedges(tm, std::back_inserter(border_vertices)); - std::vector border_vertices2; - border_halfedges(pm2, std::back_inserter(border_vertices2)); - - return snap_vertex_range_onto_vertex_range_non_conforming(border_vertices1, pm1, - border_vertices2, pm2, - tol_pmap, np1, np2); + return internal::snap_non_conformal(border_vertices, tm, tolerance_map, + border_vertices, tm, tolerance_map, + true /*self snapping*/, np, np); } -template -std::size_t snap_border_vertices_non_conforming(TriangleMesh& pm1, - TriangleMesh& pm2, - const ToleranceMap& tol_pmap) +template +std::size_t snap_borders(TriangleMesh& tm, + ToleranceMap tolerance_map) { - return snap_border_vertices_non_conforming(pm1, pm2, tol_pmap, - CGAL::parameters::all_default(), CGAL::parameters::all_default()); + return snap_borders(tm, tolerance_map, CGAL::parameters::all_default()); } -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template -std::size_t snap_border_vertices_non_conforming(TriangleMesh& pm) +template +std::size_t snap_borders(TriangleMesh& tm, + const CGAL_PMP_NP_CLASS& np) { - return snap_border_vertices_non_conforming(pm, pm); + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename GetGeomTraits::type GT; + typedef typename GT::FT FT; + + typedef CGAL::dynamic_vertex_property_t Vertex_property_tag; + typedef typename boost::property_map::type Tolerance_map; + + std::vector border_vertices; + border_halfedges(tm, std::back_inserter(border_vertices)); + + const FT tol_mx(std::numeric_limits::max()); + Tolerance_map tolerance_map = get(Vertex_property_tag(), tm); + internal::assign_tolerance_with_local_edge_length_bound(border_vertices, tolerance_map, tol_mx, tm, np); + + return internal::snap_non_conformal(border_vertices, tm, tolerance_map, + border_vertices, tm, tolerance_map, + true /*self snapping*/, np, np); } -template -std::size_t snap_border_vertices_non_conforming(TriangleMesh& pm, - const ToleranceMap& tol_pmap, - const NamedParameters& np) +template +std::size_t snap_borders(TriangleMesh& tm) { - return snap_border_vertices_non_conforming(pm, pm, tol_pmap, np, np); -} - -template -std::size_t snap_border_vertices_non_conforming(TriangleMesh& pm, - const ToleranceMap& tol_pmap) -{ - return snap_border_vertices_non_conforming(pm, pm, tol_pmap, - CGAL::parameters::all_default(), CGAL::parameters::all_default()); + return snap_borders(tm, CGAL::parameters::all_default()); } } // end namespace experimental - } // end namespace Polygon_mesh_processing - } // end namespace CGAL -#endif // CGAL_POLYGON_MESH_PROCESSING_INTERNAL_SNAP_H +#endif // CGAL_POLYGON_MESH_PROCESSING_SNAPPING_SNAP_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap_vertices.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap_vertices.h new file mode 100644 index 00000000000..d97175835b7 --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap_vertices.h @@ -0,0 +1,943 @@ +// Copyright (c) 2018, 2019 GeometryFactory (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Mael Rouxel-Labbé + +#ifndef CGAL_POLYGON_MESH_PROCESSING_SNAPPING_SNAP_VERTICES_H +#define CGAL_POLYGON_MESH_PROCESSING_SNAPPING_SNAP_VERTICES_H + +#include + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + #ifndef CGAL_PMP_SNAP_DEBUG + #define CGAL_PMP_SNAP_DEBUG + #endif +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CGAL_LINKED_WITH_TBB +# include +# include +# include +#endif + +#include +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +namespace CGAL { +namespace Polygon_mesh_processing { +namespace internal { + +// Data entry of the multi-index container +template +struct Snapping_pair +{ + typedef typename GeomTraits::FT FT; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef std::vector Vertex_container; + typedef std::pair Unique_vertex; + typedef const Unique_vertex* Unique_vertex_ptr; + + Snapping_pair(Unique_vertex_ptr uv_a_, Unique_vertex_ptr uv_b_, const FT sq_dist_) + : uv_a(uv_a_), uv_b(uv_b_), sq_dist(sq_dist_) + { } + + Unique_vertex_ptr uv_a; + Unique_vertex_ptr uv_b; + FT sq_dist; +}; + +// Functor that just forwards the pair of the two intersecting boxes +template +struct Intersecting_boxes_pairs_report +{ + Intersecting_boxes_pairs_report(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; +}; + +template +struct Vertex_proximity_report +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + + typedef typename GeomTraits::FT FT; + + typedef std::vector Vertex_container; + typedef std::pair Unique_vertex; + typedef const Unique_vertex* Unique_vertex_ptr; + typedef std::pair Unique_vertex_pair; + + Vertex_proximity_report(SnappingPairContainer& snapping_pairs, + const PolygonMesh& tm_A, + ToleranceMap_A tolerance_map_A, + VertexPatchMap_A vertex_patch_map_A, + const VPM_A& vpm_A, + const PolygonMesh& tm_B, + ToleranceMap_B tolerance_map_B, + VertexPatchMap_B vertex_patch_map_B, + const VPM_B& vpm_B, + const GeomTraits& gt +#ifdef CGAL_LINKED_WITH_TBB + , const UniqueVertexPairContainer* uv_pairs = nullptr + , ToKeepContainer* to_keep = nullptr +#endif + ) + : + m_tm_A(tm_A), + m_tolerance_map_A(tolerance_map_A), + m_vertex_patch_map_A(vertex_patch_map_A), + m_vpm_A(vpm_A), + m_tm_B(tm_B), + m_tolerance_map_B(tolerance_map_B), + m_vertex_patch_map_B(vertex_patch_map_B), + m_vpm_B(vpm_B), + m_gt(gt), + m_snapping_pairs(snapping_pairs) +#ifdef CGAL_LINKED_WITH_TBB + , m_uv_pairs(uv_pairs) + , m_to_keep(to_keep) +#endif + { } + + bool are_equal_vertices(Unique_vertex_ptr uv_a, Unique_vertex_ptr uv_b) const + { + if(&m_tm_A != &m_tm_B) // must be the same mesh + return false; + + if(uv_a->first.size() != uv_b->first.size()) + return false; + + CGAL_assertion(!uv_a->first.empty() && !uv_b->first.empty()); + const halfedge_descriptor ha = uv_a->first.front(); + return (std::find(uv_b->first.begin(), uv_b->first.end(), ha) != uv_b->first.end()); + } + + std::pair do_keep(Unique_vertex_ptr uv_a, Unique_vertex_ptr uv_b) const + { + const Vertex_container& vs_a = uv_a->first; + const Vertex_container& vs_b = uv_b->first; + const vertex_descriptor va = target(vs_a.front(), m_tm_A); + const vertex_descriptor vb = target(vs_b.front(), m_tm_B); + + // Check for patch compatibility + if(get(m_vertex_patch_map_A, va) != get(m_vertex_patch_map_B, vb)) + return std::make_pair(-1, false); // ignore + + // Reject if same mesh and already grouped together + if(are_equal_vertices(uv_a, uv_b)) + return std::make_pair(-1, false); + + const FT tol_a = uv_a->second; + const FT tol_b = uv_b->second; + CGAL_assertion(tol_a >= FT(0)); + CGAL_assertion(tol_b >= FT(0)); + + const FT upper_bound_squared = CGAL::square(0.5*(tol_a + tol_b)); + CGAL::Comparison_result res = + m_gt.compare_squared_distance_3_object()(get(m_vpm_A, va), get(m_vpm_B, vb), upper_bound_squared); + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "squared distance between " + << va << " [" << get(m_vpm_A, va) << "] and " + << vb << " [" << get(m_vpm_B, vb) << "]: " << sq_dist + << " (tol a/b: " << tol_a << " " << tol_b << ") larger? " << (res == CGAL::LARGER) + << std::endl; +#endif + + if(res == CGAL::LARGER) + return std::make_pair(-1, false); // ignore + else + { + const FT sq_dist = (min)(m_gt.compute_squared_distance_3_object()(get(m_vpm_A, va), get(m_vpm_B, vb)), + upper_bound_squared); + return std::make_pair(sq_dist, true); // keep + } + } + + // that's the sequential version + void operator()(const Box* a, const Box* b) + { + Unique_vertex_ptr uv_a = a->info(), uv_b = b->info(); + const std::pair res = do_keep(uv_a, uv_b); + if(res.second) + m_snapping_pairs.insert(Snapping_pair(uv_a, uv_b, res.first)); + } + +#ifdef CGAL_LINKED_WITH_TBB + // that's the parallel version + void operator()(const tbb::blocked_range& r) const + { + CGAL_assertion(m_uv_pairs != nullptr); + CGAL_assertion(m_to_keep != nullptr); + + for(std::size_t ri = r.begin(); ri != r.end(); ++ri) + { + const Unique_vertex_pair& hp = (*m_uv_pairs)[ri]; + m_to_keep->operator[](ri) = do_keep(hp.first, hp.second); + } + } +#endif + +private: + const PolygonMesh& m_tm_A; + ToleranceMap_A m_tolerance_map_A; + VertexPatchMap_A m_vertex_patch_map_A; + VPM_A m_vpm_A; + const PolygonMesh& m_tm_B; + ToleranceMap_B m_tolerance_map_B; + VertexPatchMap_B m_vertex_patch_map_B; + VPM_B m_vpm_B; + const GeomTraits& m_gt; + + SnappingPairContainer& m_snapping_pairs; // will only be filled here in the sequential setting + +#ifdef CGAL_LINKED_WITH_TBB + const UniqueVertexPairContainer* m_uv_pairs; + ToKeepContainer* m_to_keep; +#endif +}; + +template +std::size_t snap_vertices_two_way(const HalfedgeRange_A& halfedge_range_A, + PolygonMesh& tm_A, + ToleranceMap_A tolerance_map_A, + VertexPatchMap_A vertex_patch_map_A, + const HalfedgeRange_B& halfedge_range_B, + PolygonMesh& tm_B, + ToleranceMap_B tolerance_map_B, + VertexPatchMap_B vertex_patch_map_B, + LockableVerticesOutputIterator lockable_vps_out, + LockableHalfedgesOutputIterator lockable_ha_out, + LockableHalfedgesOutputIterator lockable_hb_out, + const bool is_second_mesh_fixed, + const NamedParameters_A& np_A, + const NamedParameters_B& np_B) +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename GetVertexPointMap::type VPM_A; + typedef typename GetVertexPointMap::type VPM_B; + + typedef typename GetGeomTraits::type GT; + typedef typename GT::FT FT; + typedef typename boost::property_traits::value_type Point; + + typedef std::vector Vertex_container; + typedef std::pair Unique_vertex; + typedef const Unique_vertex* Unique_vertex_ptr; + typedef std::map, Unique_vertex> Unique_positions; + + typedef Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Box; + + using parameters::get_parameter; + using parameters::choose_parameter; + + CGAL_static_assertion((std::is_same::value)); + + GT gt = choose_parameter(get_parameter(np_A, internal_np::geom_traits)); + VPM_A vpm_A = choose_parameter(get_parameter(np_A, internal_np::vertex_point), + get_property_map(vertex_point, tm_A)); + VPM_B vpm_B = choose_parameter(get_parameter(np_B, internal_np::vertex_point), + get_property_map(vertex_point, tm_B)); + +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << "Finding snappables vertices. Range sizes: " + << std::distance(halfedge_range_A.begin(), halfedge_range_A.end()) << " and " + << std::distance(halfedge_range_B.begin(), halfedge_range_B.end()) << std::endl; +#endif + + if(is_empty_range(halfedge_range_A.begin(), halfedge_range_A.end()) || + is_empty_range(halfedge_range_B.begin(), halfedge_range_B.end())) + return 0; + + // Vertex-Vertex snapping is performed as follows: + // - Identify points which are already equal and group them together so that they are moved together + // - Create a single box for these points + + std::vector boxes_A; + boxes_A.reserve(halfedge_range_A.size()); + std::vector boxes_B; + boxes_B.reserve(halfedge_range_B.size()); + + Unique_positions unique_positions_A; + for(halfedge_descriptor h : halfedge_range_A) + { + const vertex_descriptor v = target(h, tm_A); + const FT tolerance = get(tolerance_map_A, v); + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "Pos (A): " << v << " (" << get(vpm_A, v) << ")" << std::endl; +#endif + + Vertex_container nvc {{ h }}; + std::pair is_insert_successful = + unique_positions_A.insert(std::make_pair( + std::make_pair(get(vpm_A, v), get(vertex_patch_map_A, v)), // point and patch id + std::make_pair(nvc, tolerance))); + + if(!is_insert_successful.second) // point was already met + { + Unique_vertex& uv = is_insert_successful.first->second; + Vertex_container& vc = uv.first; // second is the tolerance + CGAL_assertion(std::find(vc.begin(), vc.end(), h) == vc.end()); + vc.push_back(h); + uv.second = (std::min)(uv.second, tolerance); + } + } + + // same for tm_B (@todo avoid all that for self snapping + use self_intersection_d) + Unique_positions unique_positions_B; + for(halfedge_descriptor h : halfedge_range_B) + { + const vertex_descriptor v = target(h, tm_B); + const FT tolerance = get(tolerance_map_B, v); + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "Pos (B): " << v << " (" << get(vpm_B, v) << ")" << std::endl; +#endif + + Vertex_container nvc {{ h }}; + std::pair is_insert_successful = + unique_positions_B.insert(std::make_pair( + std::make_pair(get(vpm_B, v), get(vertex_patch_map_B, v)), // point and patch id + std::make_pair(nvc, tolerance))); + + if(!is_insert_successful.second) // point was already met + { + Unique_vertex& uv = is_insert_successful.first->second; + Vertex_container& vc = uv.first; // second is the tolerance + CGAL_assertion(std::find(vc.begin(), vc.end(), h) == vc.end()); + vc.push_back(h); + uv.second = (std::min)(uv.second, tolerance); + } + } + + // Actually build the boxes now + for(const auto& p : unique_positions_A) + { +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "Unique_vertex (A), pos: " << p.first.first << " vertices:"; + for(const halfedge_descriptor h : p.second.first) + std::cout << " " << target(h, tm_A); + std::cout << std::endl; +#endif + + const Unique_vertex& ev = p.second; + CGAL_assertion(!ev.first.empty()); + + // this only makes the box a little larger to ease intersection computations, + // the final tolerance is not changed + const double eps = 1.01 * CGAL::to_double(ev.second); + const Bbox_3 pb = gt.construct_bbox_3_object()(p.first.first); + const Bbox_3 b(pb.xmin() - eps, pb.ymin() - eps, pb.zmin() - eps, + pb.xmax() + eps, pb.ymax() + eps, pb.zmax() + eps); + boxes_A.push_back(Box(b, &ev)); + } + + for(const auto& p : unique_positions_B) + { +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "Unique_vertex (B), pos: " << p.first.first << " vertices:"; + for(const halfedge_descriptor h : p.second.first) + std::cout << " " << target(h, tm_B); + std::cout << std::endl; +#endif + + const Unique_vertex& ev = p.second; + CGAL_assertion(!ev.first.empty()); + + const double eps = 1.01 * CGAL::to_double(ev.second); + const Bbox_3 pb = gt.construct_bbox_3_object()(p.first.first); + const Bbox_3 b(pb.xmin() - eps, pb.ymin() - eps, pb.zmin() - eps, + pb.xmax() + eps, pb.ymax() + eps, pb.zmax() + eps); + boxes_B.push_back(Box(b, &ev)); + } + + // @fixme bench and don't use ptrs if not useful + std::vector boxes_A_ptr; + boxes_A_ptr.reserve(boxes_A.size()); + for(const Box& b : boxes_A) + boxes_A_ptr.push_back(&b); + + std::vector boxes_B_ptr; + boxes_B_ptr.reserve(boxes_B.size()); + for(const Box& b : boxes_B) + boxes_B_ptr.push_back(&b); + + // Use a multi index to sort easily by sources, targets, AND distance. + // Then, look up the distances in increasing order, and snap whenever the source and the target + // have both not been snapped yet. + typedef internal::Snapping_pair Snapping_pair; + typedef boost::multi_index::multi_index_container< + Snapping_pair, + boost::multi_index::indexed_by< + boost::multi_index::ordered_non_unique< + BOOST_MULTI_INDEX_MEMBER(Snapping_pair, Unique_vertex_ptr, uv_a)>, + boost::multi_index::ordered_non_unique< + BOOST_MULTI_INDEX_MEMBER(Snapping_pair, Unique_vertex_ptr, uv_b)>, + boost::multi_index::ordered_non_unique< + BOOST_MULTI_INDEX_MEMBER(Snapping_pair, FT, sq_dist)> + > + > Snapping_pair_container; + + Snapping_pair_container snapping_pairs; + +#if !defined(CGAL_LINKED_WITH_TBB) + CGAL_static_assertion_msg (!(std::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable."); +#else + if(std::is_convertible::value) + { + typedef std::pair Unique_vertex_pair; + typedef tbb::concurrent_vector Unique_vertex_pairs; + typedef std::back_insert_iterator UVP_output_iterator; + + Unique_vertex_pairs uv_pairs; + Intersecting_boxes_pairs_report callback(std::back_inserter(uv_pairs)); + + CGAL::Real_timer timer; + timer.start(); + + // Grab the boxes that are interesecting but don't do any extra filtering (in parallel) + CGAL::box_intersection_d(boxes_A_ptr.begin(), boxes_A_ptr.end(), + boxes_B_ptr.begin(), boxes_B_ptr.end(), + callback); + + std::cout << "time for box_d: " << timer.time() << std::endl; + + // Actually filter the range of intersecting boxes now (in parallel) + typedef std::vector > Filters; + typedef Vertex_proximity_report Reporter; + + Filters to_keep(uv_pairs.size()); + Reporter proximity_filterer(snapping_pairs, tm_A, tolerance_map_A, vertex_patch_map_A, vpm_A, + tm_B, tolerance_map_B, vertex_patch_map_B, vpm_B, + gt, &uv_pairs, &to_keep); + tbb::parallel_for(tbb::blocked_range(0, uv_pairs.size()), proximity_filterer); + + // Now fill the multi index, sequentially + for(std::size_t i=0, uvps = uv_pairs.size(); i Reporter; + + Reporter vpr(snapping_pairs, tm_A, tolerance_map_A, vertex_patch_map_A, vpm_A, + tm_B, tolerance_map_B, vertex_patch_map_B, vpm_B, gt); + + // Shenanigans to pass a reference as callback (which is copied by value by 'box_intersection_d') + std::function callback(std::ref(vpr)); + + CGAL::box_intersection_d(boxes_A_ptr.begin(), boxes_A_ptr.end(), + boxes_B_ptr.begin(), boxes_B_ptr.end(), + callback); + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// Done collecting; start matching + ////////////////////////////////////////////////////////////////////////////////////////////////// + + if(snapping_pairs.empty()) + return 0; + + typedef std::pair Unique_vertex_pair; + std::vector snappable_vertices_pairs; + + // Sorted views of the container + typedef typename Snapping_pair_container::template nth_index<0>::type Container_by_source; + typedef typename Snapping_pair_container::template nth_index<1>::type Container_by_target; + typedef typename Snapping_pair_container::template nth_index<2>::type Container_by_distance; + + Container_by_source& container_by_source = snapping_pairs.template get<0>(); + Container_by_target& container_by_target = snapping_pairs.template get<1>(); + Container_by_distance& container_by_dist = snapping_pairs.template get<2>(); + + // @todo this could be a best-match algorithm rather than a greedy algorithm, + // but is the increased complexity -and thus runtime- worth it? + CGAL_assertion_code(FT prev = -1;) + while(!container_by_dist.empty()) + { + const Snapping_pair& sp = *(container_by_dist.begin()); + Unique_vertex_ptr uv_a = sp.uv_a; + Unique_vertex_ptr uv_b = sp.uv_b; + CGAL_assertion(sp.sq_dist >= prev); + CGAL_assertion_code(prev = sp.sq_dist;) + +#ifdef CGAL_PMP_SNAP_DEBUG_PP + const Point& pa = get(vpm_A, target(uv_a->first.front(), tm_A)); + const Point& pb = get(vpm_B, target(uv_b->first.front(), tm_B)); + std::cout << "Snapping (" << pa << ") to (" << pb << ") at dist: " << sp.sq_dist << std::endl; + std::cout << "#verts A: " << uv_a->first.size() << " #verts B: " << uv_b->first.size() << std::endl; +#endif + + snappable_vertices_pairs.emplace_back(uv_a, uv_b); + + // 'va' and 'vb' cannot be used anymore, remove them from the container + container_by_source.erase(uv_a); + container_by_target.erase(uv_b); + + if((&tm_A == &tm_B)) + { + container_by_source.erase(uv_b); + container_by_target.erase(uv_a); + } + } + +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << snappable_vertices_pairs.size() << " snappable pair(s)" << std::endl; +#endif + + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// Done matching; start snapping + ////////////////////////////////////////////////////////////////////////////////////////////////// + + std::size_t counter = 0; + +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT + std::ofstream out_edges("results/snappable.polylines.txt"); + out_edges.precision(17); +#endif + + for(const Unique_vertex_pair& uvp : snappable_vertices_pairs) + { + Unique_vertex_ptr uv_a = uvp.first; + Unique_vertex_ptr uv_b = uvp.second; + const Vertex_container& vs_a = uv_a->first; + const Vertex_container& vs_b = uv_b->first; + const vertex_descriptor va = target(vs_a.front(), tm_A); + const vertex_descriptor vb = target(vs_b.front(), tm_B); + +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT + out_edges << "2 " << tm_A.point(va) << " " << tm_B.point(vb) << std::endl; +#endif + + if(!gt.equal_3_object()(get(vpm_A, va), get(vpm_B, vb))) + { + if(is_second_mesh_fixed) + { + for(const halfedge_descriptor ha : vs_a) + put(vpm_A, target(ha, tm_A), get(vpm_B, vb)); + } + else + { + // Pick a point that is on the segment [va; vb], with a ratio based on the respective tolerances + const FT tol_s = uv_a->second; + const FT tol_t = uv_b->second; + CGAL_assertion(tol_s != FT(0) || tol_t != FT(0)); + + const FT lambda = tol_t / (tol_s + tol_t); + const Point new_p = get(vpm_A, va) + lambda * (get(vpm_B, vb) - get(vpm_A, va)); +#ifdef CGAL_PMP_SNAP_DEBUG_PP + std::cout << "new position of " << va << " " << vb << " --> " << new_p << std::endl; +#endif + + for(const halfedge_descriptor ha : vs_a) + put(vpm_A, target(ha, tm_A), new_p); + + for(const halfedge_descriptor hb : vs_b) + put(vpm_B, target(hb, tm_B), new_p); + } + + ++counter; + } + } + +#ifdef CGAL_PMP_SNAP_DEBUG_OUTPUT + out_edges.close(); +#endif + +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << "Snapped " << counter << " pair(s)!" << std::endl; +#endif + + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// Done snapping; start analyzing + ////////////////////////////////////////////////////////////////////////////////////////////////// + + // Below is used in non-conformal snapping + // @todo could avoid doing it if not required + // + // Now that vertex-vertex snapping has been performed, look around to see if we can already + // lock some vertices and halfedges... + // + // #1 : If a pair of edges (1 incident to va, the other to vb) are already fully matching, + // we don't want to project anything more onto any of those 2 edges + // #2 : If pairs on either side of the two matching vertices are compatible (not necessary fully matching), + // then the two vertices should be locked as no better match can be obtained + // #3 : If a pair of incident edges are not fully matching, but still have compatible directions + // (i.e. collinear and opposite directions), then we don't want to project onto the shorter + // of the two + for(const Unique_vertex_pair& uvp : snappable_vertices_pairs) + { + Unique_vertex_ptr uv_a = uvp.first; + Unique_vertex_ptr uv_b = uvp.second; + const Vertex_container& vs_a = uv_a->first; + const Vertex_container& vs_b = uv_b->first; + + // Quadratic, but all halfedges in vs_a and vs_b point to the same point. There shouldn't be many. + // @fixme this assumes compatible orientation... + for(const halfedge_descriptor ha : vs_a) + { + for(const halfedge_descriptor hb : vs_b) + { + if(!is_border(ha, tm_A) || !is_border(hb, tm_B)) + continue; + + const vertex_descriptor va = target(ha, tm_A); + const vertex_descriptor vb = target(hb, tm_B); + + // The two folloing halfedges might not be in the range to snap, but it doesn't matter + const halfedge_descriptor nha = next(ha, tm_A); + const halfedge_descriptor nhb = next(hb, tm_B); + const bool is_stitchable_left = gt.equal_3_object()(get(vpm_A, source(ha, tm_A)), + get(vpm_B, target(nhb, tm_B))); + const bool is_stitchable_right = gt.equal_3_object()(get(vpm_A, target(nha, tm_A)), + get(vpm_B, source(hb, tm_B))); + bool is_collinear_left = false; + bool is_collinear_right = false; + + if(is_stitchable_left) + { + *lockable_ha_out++ = ha; // #1 + *lockable_hb_out++ = nhb; // #1 + is_collinear_left = true; + } + else + { + const vertex_descriptor lva = source(ha, tm_A); + const vertex_descriptor lvb = target(nhb, tm_B); + + is_collinear_left = is_collinear_with_tolerance(get(vpm_A, va), get(vpm_A, lva), get(vpm_B, lvb), gt); + if(is_collinear_left) // but not stitchable + { + if(gt.less_distance_to_point_3_object()(get(vpm_A, va), get(vpm_A, lva), get(vpm_B, lvb))) + *lockable_ha_out++ = ha; // #2 + else + *lockable_hb_out++ = nhb; // #2 + } + } + + if(is_stitchable_right) + { + *lockable_ha_out++ = nha; // #1 + *lockable_hb_out++ = hb; // #1 + is_collinear_right = true; + } + else + { + const vertex_descriptor rva = target(nha, tm_A); + const vertex_descriptor rvb = source(hb, tm_B); + + is_collinear_right = is_collinear_with_tolerance(get(vpm_A, va), get(vpm_A, rva), get(vpm_B, rvb), gt); + if(is_collinear_right) // but not stitchable + { + if(gt.less_distance_to_point_3_object()(get(vpm_A, va), get(vpm_A, rva), get(vpm_B, rvb))) + *lockable_ha_out++ = nha; // #2 + else + *lockable_hb_out++ = hb; // #2 + } + } + + if(is_collinear_left && is_collinear_right) // #3 + { +#ifdef CGAL_PMP_SNAP_DEBUG + std::cout << va << " (" << get(vpm_A, va) << ") and " << vb << " (" << get(vpm_B, vb) << ") are locked vertices" << std::endl; +#endif + *lockable_vps_out++ = std::make_pair(va, vb); + } + } + } + } + + return counter; +} + +// Convenience overload for snap_borders +template +std::size_t snap_vertices_two_way(const HalfedgeRange_A& halfedge_range_A, + PolygonMesh& tm_A, + ToleranceMap_A tolerance_map_A, + const HalfedgeRange_B& halfedge_range_B, + PolygonMesh& tm_B, + ToleranceMap_B tolerance_map_B, + LockableVerticesOutputIterator lockable_vps_out, + LockableHalfedgesOutputIterator lockable_ha_out, + LockableHalfedgesOutputIterator lockable_hb_out, + const NamedParameters_A& np_A, + const NamedParameters_B& np_B) +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + + using CGAL::parameters::choose_parameter; + using CGAL::parameters::get_parameter; + + return snap_vertices_two_way(halfedge_range_A, tm_A, tolerance_map_A, + choose_parameter(get_parameter(np_A, internal_np::vertex_incident_patches), + Constant_property_map(-1)), + halfedge_range_B, tm_B, tolerance_map_B, + choose_parameter(get_parameter(np_B, internal_np::vertex_incident_patches), + Constant_property_map(-1)), + lockable_vps_out, lockable_ha_out, lockable_hb_out, + choose_parameter(get_parameter(np_B, internal_np::do_lock_mesh), false), + np_A, np_B); +} + +} // namespace internal + +namespace experimental { + +// \ingroup PMP_repairing_grp +// +// Attempts to snap the vertices in `halfedge_range_A` and `halfedge_range_B`. +// A vertex from the first range and a vertex from the second range are only snapped +// if the distance between both vertices is smaller than the sum of their user-prescribed tolerance. +// All such pairs are collected and processed in a greedy order: the two vertices are moved +// to a common vertex (more on this below), and both vertices are locked and cannot be used +// in any other matches. +// +// \warning This function does not give any guarantee on the conformity between the two meshes after the snapping. +// \warning This function does not merge vertices or the meshes, it is purely geometric. +// +// \tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph` +// \tparam HalfedgeRange_A a model of `Range` with value type `boost::graph_traits::%halfedge_descriptor` +// \tparam HalfedgeRange_B a model of `Range` with value type `boost::graph_traits::%halfedge_descriptor` +// \tparam ToleranceMap_A a model of `ReadablePropertyMap` with key type `boost::graph_traits::%vertex_descriptor` +// and value type `GetGeomTraits::type::FT` +// \tparam ToleranceMap_B a model of `ReadablePropertyMap` with key type `boost::graph_traits::%vertex_descriptor` +// and value type `GetGeomTraits::type::FT` +// \tparam NamedParameters_A a sequence of \ref pmp_namedparameters "Named Parameters" +// \tparam NamedParameters_B a sequence of \ref pmp_namedparameters "Named Parameters" +// +// \param halfedge_range_A a range of halfedges of the first mesh defining a set of vertices (as targets of the halfeges) +// \param tm_A the first mesh to which the vertices in `halfedge_range_A` belong +// \param tolerance_map_A a tolerance map associating to each vertex of the first range a tolerance value +// \param halfedge_range_B a range of vertices of the second mesh defining a set of vertices (as targets of the halfeges) +// \param tolerance_map_B a tolerance map associating to each vertex of the second range a tolerance value +// \param tm_B the target mesh to which the vertices in `halfedge_range_B` belong +// \param np_A optional \ref pmp_namedparameters "Named Parameters" related to the source mesh, +// amongst those described below: +// +// \cgalNamedParamsBegin +// \cgalParamBegin{vertex_point_map} +// the property map with the points associated to the vertices of the source mesh. +// The type of this map is model of `ReadWritePropertyMap`. If this parameter is omitted, +// an internal property map for `CGAL::vertex_point_t` must be available in `PolygonMesh`. +// \cgalParamEnd +// \cgalParamBegin{geom_traits} +// a geometric traits class instance, must be a model of `Kernel` +// \cgalParamEnd +// \cgalNamedParamsEnd +// +// \param np_B optional \ref pmp_namedparameters "Named Parameters" related to the target mesh, +// amongst those described below: +// +// \cgalNamedParamsBegin +// \cgalParamBegin{vertex_point_map} +// the property map with the points associated to the vertices of the target mesh. +// The type of this map is model of `ReadablePropertyMap`. If this parameter is omitted, +// an internal property map for `CGAL::vertex_point_t` must be available in `PolygonMesh`. +// \cgalParamEnd +// \cgalNamedParamsEnd +// +// \return the number of snapped vertex pairs +// +template +std::size_t snap_vertices(const HalfedgeRange_A& halfedge_range_A, + PolygonMesh& tm_A, + ToleranceMap_A tolerance_map_A, + const HalfedgeRange_B& halfedge_range_B, + PolygonMesh& tm_B, + ToleranceMap_B tolerance_map_B, + const NamedParameters_A& np_A, + const NamedParameters_B& np_B) +{ + CGAL::Emptyset_iterator unused_output_iterator; + + return internal::snap_vertices_two_way(halfedge_range_A, tm_A, tolerance_map_A, + halfedge_range_B, tm_B, tolerance_map_B, + unused_output_iterator, unused_output_iterator, + unused_output_iterator, np_A, np_B); +} + +template +std::size_t snap_vertices(const HalfedgeRange_A& halfedge_range_A, + PolygonMesh& tm_A, + ToleranceMap_A tolerance_map_A, + const HalfedgeRange_B& halfedge_range_B, + PolygonMesh& tm_B, + ToleranceMap_B tolerance_map_B) +{ + return snap_vertices(halfedge_range_A, tm_A, tolerance_map_A, halfedge_range_B, tm_B, tolerance_map_B, + CGAL::parameters::all_default(), CGAL::parameters::all_default()); +} + +template +std::size_t snap_vertices(const HalfedgeRange_A& halfedge_range_A, + PolygonMesh& tm_A, + const HalfedgeRange_B& halfedge_range_B, + PolygonMesh& tm_B, + const CGAL::Named_function_parameters& np_A, + const CGAL::Named_function_parameters& np_B) +{ + typedef CGAL::Named_function_parameters NamedParameters_A; + typedef typename GetGeomTraits::type GT; + typedef typename GT::FT FT; + typedef CGAL::dynamic_vertex_property_t Vertex_property_tag; + typedef typename boost::property_map::type Tolerance_map; + + const FT max_tol(std::numeric_limits::max()); + + Tolerance_map tolerance_map_A = get(Vertex_property_tag(), tm_A); + internal::assign_tolerance_with_local_edge_length_bound(halfedge_range_A, tolerance_map_A, max_tol, tm_A, np_A); + Tolerance_map tolerance_map_B = get(Vertex_property_tag(), tm_B); + internal::assign_tolerance_with_local_edge_length_bound(halfedge_range_B, tolerance_map_B, max_tol, tm_B, np_B); + + return snap_vertices(halfedge_range_A, tm_A, tolerance_map_A, halfedge_range_B, tm_B, tolerance_map_B, np_A, np_B); +} + +template +std::size_t snap_vertices(const HalfedgeRange_A& halfedge_range_A, + PolygonMesh& tm_A, + const HalfedgeRange_B& halfedge_range_B, + PolygonMesh& tm_B) +{ + return snap_vertices(halfedge_range_A, tm_A, halfedge_range_B, tm_B, + parameters::all_default(), parameters::all_default()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Border convenience overloads +/////////////////////////////////////////////////////////////////////////////////////////////////// + +template +std::size_t snap_border_vertices(PolygonMesh& tm_A, + ToleranceMap_A tolerance_map_A, + PolygonMesh& tm_B, + ToleranceMap_B tolerance_map_B) +{ + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + std::vector border_A; + border_halfedges(tm_A, std::back_inserter(border_A)); + std::vector border_B; + border_halfedges(tm_B, std::back_inserter(border_B)); + + return snap_vertices(border_A, tm_A, tolerance_map_A, + border_B, tm_B, tolerance_map_B); +} + +template +std::size_t snap_border_vertices(PolygonMesh& tm_A, + PolygonMesh& tm_B) +{ + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + std::vector border_vertices_A; + border_halfedges(tm_A, std::back_inserter(border_vertices_A)); + + std::vector border_vertices_B; + border_halfedges(tm_B, std::back_inserter(border_vertices_B)); + + return snap_vertices(border_vertices_A, tm_A, border_vertices_B, tm_B); +} + +template +std::size_t snap_border_vertices(PolygonMesh& tm, ToleranceMap tolerance_map) +{ + return snap_border_vertices(tm, tolerance_map, tm, tolerance_map); +} + +template +std::size_t snap_border_vertices(PolygonMesh& tm) +{ + return snap_border_vertices(tm, tm); +} + +} // namespace experimental +} // namespace Polygon_mesh_processing +} // namespace CGAL + +#endif // CGAL_POLYGON_MESH_PROCESSING_SNAPPING_SNAP_VERTICES_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/fair_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/fair_impl.h index 818a77f3205..fa2bf728652 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/fair_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/fair_impl.h @@ -118,7 +118,7 @@ public: { int depth = static_cast(fc) + 1; if(depth < 0 || depth > 3) { - CGAL_warning(!"Continuity should be between 0 and 2 inclusively!"); + CGAL_warning_msg(false, "Continuity should be between 0 and 2 inclusively!"); return false; } @@ -139,7 +139,7 @@ public: for(vertex_descriptor vd : interior_vertices) { if( !vertex_id_map.insert(std::make_pair(vd, id)).second ) { - CGAL_warning(!"Duplicate vertex is found!"); + CGAL_warning_msg(false, "Duplicate vertex is found!"); return false; } ++id; @@ -160,7 +160,7 @@ public: double D; bool prefactor_ok = solver.factor(A, D); if(!prefactor_ok) { - CGAL_warning(!"pre_factor failed!"); + CGAL_warning_msg(false, "pre_factor failed!"); return false; } #ifdef CGAL_PMP_FAIR_DEBUG @@ -170,7 +170,7 @@ public: // solve bool is_all_solved = solver.linear_solver(Bx, X) && solver.linear_solver(By, Y) && solver.linear_solver(Bz, Z); if(!is_all_solved) { - CGAL_warning(!"linear_solver failed!"); + CGAL_warning_msg(false, "linear_solver failed!"); return false; } #ifdef CGAL_PMP_FAIR_DEBUG diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remove_degeneracies.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remove_degeneracies.h index f6e582cf93f..b6f868bef14 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remove_degeneracies.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remove_degeneracies.h @@ -130,7 +130,7 @@ bool is_collapse_geometrically_valid(typename boost::graph_traits: VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), get_const_property_map(vertex_point, tmesh)); - Traits gt = choose_parameter(get_parameter(np, internal_np::geom_traits), Traits()); + Traits gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); /// @todo handle boundary edges @@ -356,7 +356,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, get_const_property_map(vertex_point, tmesh)); typedef typename GetGeomTraits::type Traits; - Traits gt = choose_parameter(get_parameter(np, internal_np::geom_traits), Traits()); + Traits gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); // Vertex property map that combines the VCM and the fact that extremities of a constrained edge should be constrained typedef CGAL::dynamic_vertex_property_t Vertex_property_tag; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/repair_extra.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/repair_extra.h index c1ee33318a1..f18ef7186be 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/repair_extra.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/repair_extra.h @@ -110,7 +110,8 @@ void collect_close_stitchable_boundary_edges(PM& pm, typedef boost::unordered_map Halfedge_multiplicity; typedef std::vector > Halfedge_pairs; - typedef typename Box_intersection_d::Box_with_info_d Box; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Box; typedef Union_find UF_vertices; typedef std::map Handle_map; @@ -141,7 +142,6 @@ void collect_close_stitchable_boundary_edges(PM& pm, for(Box& b : boxes) box_ptrs.push_back(&b); - Halfedge_multiplicity multiplicity; Halfedge_pairs matching_hedges; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h index 0d036f3522f..44965ebc8ec 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h @@ -17,20 +17,27 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include + +#include +#include +#include +#include + namespace CGAL { namespace Polygon_mesh_processing{ namespace internal { @@ -401,8 +408,10 @@ compute_face_face_intersection(const FaceRange& face_range1, typedef TriangleMesh TM; typedef typename boost::graph_traits::face_descriptor face_descriptor; - typedef typename CGAL::Box_intersection_d::Box_with_info_d Box; - + + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Box; + CGAL::Bbox_3 b1 = CGAL::Polygon_mesh_processing::bbox(tm1, np1), b2 = CGAL::Polygon_mesh_processing::bbox(tm2, np2); @@ -414,12 +423,8 @@ compute_face_face_intersection(const FaceRange& face_range1, // make one box per facet std::vector boxes1; std::vector boxes2; - boxes1.reserve( - std::distance( boost::begin(face_range1), boost::end(face_range1) ) - ); - boxes2.reserve( - std::distance( boost::begin(face_range2), boost::end(face_range2) ) - ); + boxes1.reserve(std::distance(boost::begin(face_range1), boost::end(face_range1))); + boxes2.reserve(std::distance(boost::begin(face_range2), boost::end(face_range2))); typedef typename GetVertexPointMap::const_type VertexPointMap1; typedef typename GetVertexPointMap::const_type VertexPointMap2; @@ -433,6 +438,7 @@ compute_face_face_intersection(const FaceRange& face_range1, typename boost::property_traits::value_type, typename boost::property_traits::value_type >::value) ); + for(face_descriptor f : face_range1) { boxes1.push_back(Box(Polygon_mesh_processing::face_bbox(f, tm1), f)); @@ -449,20 +455,16 @@ 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()); + GeomTraits gt = choose_parameter(get_parameter(np1, internal_np::geom_traits)); internal::Intersect_faces Intersect_faces(tm1, tm2, - out, - vpmap1, vpmap2, - gt); + VertexPointMap2> Intersect_faces(tm1, tm2, out, vpmap1, vpmap2, gt); std::ptrdiff_t cutoff = 2000; CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(), @@ -541,21 +543,16 @@ compute_face_polyline_intersection( const FaceRange& face_range, typename boost::range_value::type>::value)); std::vector faces; - faces.reserve(std::distance( boost::begin(face_range), boost::end(face_range) )); + faces.reserve(std::distance(boost::begin(face_range), boost::end(face_range))); - typedef typename CGAL::Box_intersection_d::Box_with_info_d Box; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Box; // make one box per facet std::vector boxes1; std::vector boxes2; - boxes1.reserve( - std::distance( boost::begin(face_range), boost::end(face_range) ) - ); - - boxes2.reserve( - std::distance( boost::begin(polyline), boost::end(polyline) ) - 1 - ); - + boxes1.reserve(std::distance(boost::begin(face_range), boost::end(face_range))); + boxes2.reserve(std::distance(boost::begin(polyline), boost::end(polyline)) - 1); for(face_descriptor f : face_range) { @@ -571,7 +568,6 @@ compute_face_polyline_intersection( const FaceRange& face_range, } // generate box pointers - std::vector box1_ptr(boost::make_counting_iterator(&boxes1[0]), boost::make_counting_iterator(&boxes1[0]+boxes1.size())); std::vector box2_ptr(boost::make_counting_iterator(&boxes2[0]), @@ -579,7 +575,7 @@ compute_face_polyline_intersection( const FaceRange& face_range, // compute intersections filtered out by boxes typedef typename GetGeomTraits::type GeomTraits; - GeomTraits gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GeomTraits()); + GeomTraits gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); internal::Intersect_face_polyline - Intersect_face_polyline(tm, - faces, - polyline, - out, - vpmap, - gt); + Intersect_face_polyline(tm, faces, polyline, out, vpmap, gt); std::ptrdiff_t cutoff = 2000; CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(), @@ -672,34 +663,32 @@ compute_face_polylines_intersection(const FaceRange& face_range, get_const_property_map(boost::vertex_point, tm)); typedef typename boost::property_traits::value_type Point; typedef typename boost::range_value::type Polyline; - CGAL_static_assertion( - (boost::is_same::type>::value)); + CGAL_static_assertion((boost::is_same::type>::value)); std::vector faces; faces.reserve(std::distance( boost::begin(face_range), boost::end(face_range) )); - typedef typename CGAL::Box_intersection_d::Box_with_info_d > Box; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d, Box_policy> Box; // make one box per facet std::vector boxes1; std::vector boxes2; - boxes1.reserve( - std::distance( boost::begin(face_range), boost::end(face_range) ) - ); + boxes1.reserve(std::distance(boost::begin(face_range), boost::end(face_range))); std::size_t polylines_size = 0; for(Polyline poly : polyline_range) { polylines_size += std::distance( boost::begin(poly), boost::end(poly) ) -1; } - boxes2.reserve( polylines_size ); + boxes2.reserve(polylines_size); for(face_descriptor f : face_range) { faces.push_back(f); boxes1.push_back(Box(Polygon_mesh_processing::face_bbox(f, tm), std::make_pair(0, faces.size()-1))); } + std::size_t range_size = std::distance( boost::begin(polyline_range), boost::end(polyline_range) ); for(std::size_t j = 0; j < range_size; ++j) { @@ -722,7 +711,7 @@ compute_face_polylines_intersection(const FaceRange& face_range, // compute intersections filtered out by boxes typedef typename GetGeomTraits::type GeomTraits; - GeomTraits gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GeomTraits()); + GeomTraits gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); internal::Intersect_face_polylines - Intersect_face_polyline(tm, - faces, - polyline_range, - out, - vpmap, - gt); + Intersect_face_polyline(tm, faces, polyline_range, out, vpmap, gt); std::ptrdiff_t cutoff = 2000; CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(), @@ -773,18 +757,15 @@ compute_polyline_polyline_intersection(const Polyline& polyline1, OutputIterator out, const Kernel& K) { - typedef typename CGAL::Box_intersection_d::Box_with_info_d Box; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Box; + typedef typename Kernel::Point_3 Point; // make one box per facet std::vector boxes1; std::vector boxes2; - boxes1.reserve( - std::distance( boost::begin(polyline1), boost::end(polyline1) ) - 1 - ); - - boxes2.reserve( - std::distance( boost::begin(polyline2), boost::end(polyline2) ) - 1 - ); + boxes1.reserve(std::distance(boost::begin(polyline1), boost::end(polyline1)) - 1); + boxes2.reserve(std::distance(boost::begin(polyline2), boost::end(polyline2)) - 1); for(std::size_t i =0; i< polyline1.size()-1; ++i) { @@ -813,10 +794,7 @@ compute_polyline_polyline_intersection(const Polyline& polyline1, Kernel, Box, OutputIterator> - intersect_polylines(polyline1, - polyline2, - out, - K); + intersect_polylines(polyline1, polyline2, out, K); std::ptrdiff_t cutoff = 2000; CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(), @@ -856,7 +834,9 @@ compute_polylines_polylines_intersection(const PolylineRange& polylines1, const Kernel& K) { //info.first is the index of the polyline in the range, info.second is the index of the point in the polyline - typedef typename CGAL::Box_intersection_d::Box_with_info_d > Box; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d, Box_policy> Box; + typedef typename Kernel::Point_3 Point; typedef typename boost::range_value::type Polyline; @@ -871,6 +851,7 @@ compute_polylines_polylines_intersection(const PolylineRange& polylines1, b1 += CGAL::bbox_3(poly.begin(), poly.end()); } boxes1.reserve( polylines_size ); + polylines_size = 0; for(Polyline poly : polylines2) { @@ -878,9 +859,10 @@ compute_polylines_polylines_intersection(const PolylineRange& polylines1, b2 += CGAL::bbox_3(poly.begin(), poly.end()); } boxes2.reserve(polylines_size); - + if(!CGAL::do_overlap(b1,b2)) return out; + std::size_t range_size = std::distance( boost::begin(polylines1), boost::end(polylines1) ); for(std::size_t j = 0; j < range_size; ++j) { @@ -915,15 +897,11 @@ compute_polylines_polylines_intersection(const PolylineRange& polylines1, // compute intersections filtered out by boxes - internal::Intersect_polyline_ranges - intersect_polylines(polylines1, - polylines2, - out, - K); + intersect_polylines(polylines1, polylines2, out, K); std::ptrdiff_t cutoff = 2000; CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(), @@ -1229,6 +1207,7 @@ bool do_intersect(const TriangleMesh& tm1, { using parameters::choose_parameter; using parameters::get_parameter; + bool test_overlap = choose_parameter(get_parameter(np1, internal_np::overlap_test),false) || choose_parameter(get_parameter(np2, internal_np::overlap_test),false); @@ -1254,7 +1233,7 @@ bool do_intersect(const TriangleMesh& tm1, VertexPointMap2 vpm2 = choose_parameter(get_parameter(np2, internal_np::vertex_point), get_const_property_map(boost::vertex_point, tm2)); typedef typename GetGeomTraits::type GeomTraits; - GeomTraits gt = choose_parameter(get_parameter(np1, internal_np::geom_traits), GeomTraits()); + GeomTraits gt = choose_parameter(get_parameter(np1, internal_np::geom_traits)); return internal::is_mesh2_in_mesh1(tm1, tm2, vpm1, vpm2, gt) || internal::is_mesh2_in_mesh1(tm2, tm1, vpm2, vpm1, gt); @@ -1595,7 +1574,9 @@ OutputIterator intersecting_meshes(const TriangleMeshRange& range, bool report_overlap = choose_parameter(get_parameter(np, internal_np::overlap_test),false); - typedef CGAL::Box_intersection_d::Box_with_info_d Mesh_box; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Mesh_box; + std::vector boxes; boxes.reserve(std::distance(range.begin(), range.end())); @@ -1604,21 +1585,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()); - + GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); //get all the pairs of meshes intersecting (no strict inclusion test) std::ptrdiff_t cutoff = 2000; internal::Mesh_callback callback(range, out, report_overlap, gt, nps); - CGAL::box_self_intersection_d(boxes_ptr.begin(), boxes_ptr.end(), - callback, cutoff); + CGAL::box_self_intersection_d(boxes_ptr.begin(), boxes_ptr.end(), callback, cutoff); return callback.m_iterator; } @@ -1634,7 +1612,7 @@ OutputIterator intersecting_meshes(const TriangleMeshRange& range, template OutputIterator intersecting_meshes(const TriangleMeshRange& range, - OutputIterator out) + OutputIterator out) { return intersecting_meshes(range, out, parameters::all_default()); } @@ -1827,9 +1805,10 @@ surface_self_intersection(const TriangleMesh& tm, CGAL::Polygon_mesh_processing::parameters::all_default() ); } -} //end of namespace experimental -} } //end of namespace CGAL::Polygon_mesh_processing +} //end of namespace experimental +} //end of namespace Polygon_mesh_processing +} //end of namespace CGAL #include diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/locate.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/locate.h index 86280d8d95d..ba96bc612ae 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/locate.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/locate.h @@ -611,7 +611,7 @@ construct_point(const std::pair::face VertexPointMap vpm = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point), get_const_property_map(boost::vertex_point, tm)); - Geom_traits gt = choose_parameter(get_parameter(np, internal_np::geom_traits), Geom_traits()); + Geom_traits gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); halfedge_descriptor hd = halfedge(loc.first, tm); const Point_reference p0 = get(vpm, source(hd, tm)); @@ -1126,7 +1126,7 @@ locate_in_face(const typename internal::Location_traits(get_parameter(np, internal_np::geom_traits)); FT snap_tolerance = choose_parameter(get_parameter(np, internal_np::snapping_tolerance), 0); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h index 37581df874c..b9e69989521 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/measure.h @@ -326,7 +326,8 @@ face_area(typename boost::graph_traits::face_descriptor f, halfedge_descriptor hd = halfedge(f, tmesh); halfedge_descriptor nhd = next(hd, tmesh); - typename GetGeomTraits::type traits; + typedef typename GetGeomTraits::type GT; + GT traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); return approximate_sqrt(traits.compute_squared_area_3_object()(get(vpm, source(hd, tmesh)), get(vpm, target(hd, tmesh)), @@ -500,7 +501,7 @@ volume(const TriangleMesh& tmesh, typename GetVertexPointMap::const_type vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(CGAL::vertex_point, tmesh)); + get_const_property_map(CGAL::vertex_point, tmesh)); typename GetGeomTraits::type::Point_3 origin(0, 0, 0); typedef typename boost::graph_traits::face_descriptor face_descriptor; @@ -577,11 +578,11 @@ face_aspect_ratio(typename boost::graph_traits::face_descriptor f, typename GetVertexPointMap::const_type vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(CGAL::vertex_point, tmesh)); + get_const_property_map(CGAL::vertex_point, tmesh)); halfedge_descriptor h = halfedge(f, tmesh); - Geom_traits gt = choose_parameter(get_parameter(np, internal_np::geom_traits), Geom_traits()); + Geom_traits gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); #if 0 const FT sq_triangle_area = gt.compute_squared_area_3_object()(get(vpm, source(h, tmesh)), @@ -679,7 +680,7 @@ centroid(const TriangleMesh& tmesh, const CGAL_PMP_NP_CLASS& np) typedef typename GetVertexPointMap::const_type Vpm; Vpm vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(CGAL::vertex_point, tmesh)); + get_const_property_map(CGAL::vertex_point, tmesh)); typedef typename GetGeomTraits::type Kernel; typedef typename Kernel::Point_3 Point_3; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/merge_border_vertices.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/merge_border_vertices.h index 891882f13d0..da6fb04d54e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/merge_border_vertices.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/merge_border_vertices.h @@ -109,7 +109,7 @@ void detect_identical_mergeable_vertices( // check that intervals are disjoint or strictly nested // if there is only one issue we drop the whole cycle. - /// \todo shall we try to be more conservative? + // @todo shall we try to be more conservative? if (hedges_with_identical_point_target.empty()) return; std::set< std::pair >::iterator it1 = intervals.begin(), end2 = intervals.end(), diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h index ec285b54926..03651b15e83 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h @@ -60,18 +60,18 @@ namespace internal{ const PolygonMesh& pmesh, const NamedParameters& np) { - + using parameters::choose_parameter; using parameters::get_parameter; CGAL_assertion(halfedge(v_max, pmesh)!=boost::graph_traits::null_halfedge()); //VertexPointMap typedef typename GetVertexPointMap::const_type VPMap; - VPMap vpmap = CGAL::parameters::choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(vertex_point, pmesh)); + VPMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_const_property_map(vertex_point, pmesh)); //Kernel typedef typename GetGeomTraits::type GT; - GT gt = CGAL::parameters::choose_parameter(get_parameter(np, internal_np::geom_traits), GT()); + GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); //among the incoming edges of `v_max`, find one edge `e` with the minimal slope typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; @@ -168,21 +168,24 @@ bool is_outward_oriented(const PolygonMesh& pmesh, CGAL_warning(CGAL::is_closed(pmesh)); CGAL_precondition(CGAL::is_valid_polygon_mesh(pmesh)); +#ifdef CGAL_PMP_DEBUG_CODE //check for empty pmesh CGAL_warning(faces(pmesh).first != faces(pmesh).second); +#endif + if (faces(pmesh).first == faces(pmesh).second) return true; - + using parameters::choose_parameter; using parameters::get_parameter; //VertexPointMap typedef typename GetVertexPointMap::const_type VPMap; - VPMap vpmap = CGAL::parameters::choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(vertex_point, pmesh)); + VPMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_const_property_map(vertex_point, pmesh)); //Kernel typedef typename GetGeomTraits::type GT; - GT gt = CGAL::parameters::choose_parameter(get_parameter(np, internal_np::geom_traits), GT()); + GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); //find the vertex with maximal z coordinate internal::Compare_vertex_points_z_3 less_z(vpmap, gt); @@ -435,8 +438,6 @@ void recursive_orient_volume_ccs( TriangleMesh& tm, * inward or outward oriented. * * @tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph` . -* If `TriangleMesh` has an internal property map for `CGAL::face_index_t`, -* as a named parameter, then it must be initialized. * @tparam NamedParameters a sequence of \ref pmp_namedparameters * * @param tm a closed triangulated surface mesh @@ -458,31 +459,29 @@ void recursive_orient_volume_ccs( TriangleMesh& tm, * \cgalNamedParamsEnd */ template -void orient(TriangleMesh& tm, const NamedParameters& np) +void orient(TriangleMesh& tm, + const NamedParameters& np) { - typedef boost::graph_traits Graph_traits; - typedef typename Graph_traits::vertex_descriptor vertex_descriptor; - typedef typename Graph_traits::face_descriptor face_descriptor; - typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename GetVertexPointMap::const_type Vpm; - typedef typename GetFaceIndexMap::const_type Fid_map; + typedef boost::graph_traits Graph_traits; + typedef typename Graph_traits::vertex_descriptor vertex_descriptor; + typedef typename Graph_traits::face_descriptor face_descriptor; + typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename GetVertexPointMap::const_type Vpm; + typedef typename GetInitializedFaceIndexMap::type FaceIndexMap; CGAL_assertion(is_triangle_mesh(tm)); CGAL_assertion(is_valid_polygon_mesh(tm)); CGAL_assertion(is_closed(tm)); + using parameters::choose_parameter; using parameters::get_parameter; - bool orient_outward = CGAL::parameters::choose_parameter( - get_parameter(np, internal_np::outward_orientation),true); + bool orient_outward = choose_parameter(get_parameter(np, internal_np::outward_orientation),true); - Vpm vpm = CGAL::parameters::choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(boost::vertex_point, tm)); + Vpm vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_const_property_map(boost::vertex_point, tm)); - Fid_map fid_map = CGAL::parameters::choose_parameter(get_parameter(np, internal_np::face_index), - get_const_property_map(boost::face_index, tm)); + FaceIndexMap fid_map = CGAL::get_initialized_face_index_map(tm, np); std::vector face_cc(num_faces(tm), std::size_t(-1)); @@ -539,8 +538,6 @@ void orient(TriangleMesh& tm) * See \ref coref_def_subsec for a precise definition. * * @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`. - * If `TriangleMesh` has an internal property map for `CGAL::face_index_t`, - * as a named parameter, then it must be initialized. * @tparam NamedParameters a sequence of \ref pmp_namedparameters * * @param tm a closed triangulated surface mesh @@ -566,30 +563,29 @@ void orient(TriangleMesh& tm) */ template void orient_to_bound_a_volume(TriangleMesh& tm, - const NamedParameters& np) + const NamedParameters& np) { - typedef boost::graph_traits Graph_traits; - typedef typename Graph_traits::vertex_descriptor vertex_descriptor; - typedef typename GetVertexPointMap::const_type Vpm; - typedef typename GetFaceIndexMap::const_type Fid_map; - typedef typename Kernel_traits< - typename boost::property_traits::value_type >::Kernel Kernel; + typedef boost::graph_traits Graph_traits; + typedef typename Graph_traits::vertex_descriptor vertex_descriptor; + + typedef typename GetVertexPointMap::const_type Vpm; + typedef typename boost::property_traits::value_type Point; + typedef typename Kernel_traits::Kernel Kernel; + + typedef typename GetInitializedFaceIndexMap::type FaceIndexMap; + if (!is_closed(tm)) return; if (!is_triangle_mesh(tm)) return; - + using parameters::choose_parameter; using parameters::get_parameter; - bool orient_outward = CGAL::parameters::choose_parameter( - get_parameter(np, internal_np::outward_orientation),true); + bool orient_outward = choose_parameter(get_parameter(np, internal_np::outward_orientation),true); - Vpm vpm = CGAL::parameters::choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(boost::vertex_point, tm)); + Vpm vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_const_property_map(boost::vertex_point, tm)); - Fid_map fid_map = CGAL::parameters::choose_parameter(get_parameter(np, internal_np::face_index), - get_const_property_map(boost::face_index, tm)); + FaceIndexMap fid_map = CGAL::get_initialized_face_index_map(tm, np); std::vector face_cc(num_faces(tm), std::size_t(-1)); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/polygon_mesh_to_polygon_soup.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/polygon_mesh_to_polygon_soup.h new file mode 100644 index 00000000000..44cc24e255b --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/polygon_mesh_to_polygon_soup.h @@ -0,0 +1,129 @@ +// Copyright (c) 2020 GeometryFactory (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Mael Rouxel-Labbé + +#ifndef CGAL_POLYGON_MESH_PROCESSING_POLYGON_MESH_TO_POLYGON_SOUP_H +#define CGAL_POLYGON_MESH_PROCESSING_POLYGON_MESH_TO_POLYGON_SOUP_H + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace CGAL { +namespace Polygon_mesh_processing { + +/// \ingroup PMP_repairing_grp +/// +/// Adds the vertices and faces of a mesh into a (possibly non-empty) polygon soup. +/// +/// \tparam PolygonMesh a model of `FaceListGraph` +/// \tparam PointRange a model of the concepts `RandomAccessContainer` and +/// `BackInsertionSequence` whose value type can be constructed from +/// the point type of the polygon mesh +/// \tparam PolygonRange a model of the concepts `RandomAccessContainer` and `BackInsertionSequence` whose +/// value type is itself a model of the concepts `RandomAccessContainer` and +/// `BackInsertionSequence` whose value type is `std::size_t` +/// \tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" +/// +/// \param mesh the mesh whose faces are being put in the polygon soup +/// \param points points making the polygons of the soup +/// \param polygons each element in the vector describes a polygon using the indices of the points in `points` +/// \param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below +/// +/// \cgalNamedParamsBegin +/// \cgalParamBegin{vertex_point_map} +/// a model of `ReadablePropertyMap`, the property map with the points associated to the vertices of `mesh`. +/// If this parameter is omitted, an internal property map for +/// `CGAL::vertex_point_t` must be available in `PolygonMesh`. +/// \cgalParamEnd +/// \cgalNamedParamsEnd +/// +/// \cgalAdvancedBegin +/// `PolygonRange` can also be a model of the concepts `RandomAccessContainer` and `BackInsertionSequence` +/// whose value type is an array, but it is the user's responsability to ensure that +/// all faces have the same number of vertices, and that this number is equal to the size of the array. +/// \cgalAdvancedEnd +/// +/// \sa `CGAL::Polygon_mesh_processing::orient_polygon_soup()` +/// \sa `CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh()` +/// \sa `CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh()` +/// +template +void polygon_mesh_to_polygon_soup(const PolygonMesh& mesh, + PointRange& points, + PolygonRange& polygons, + const NamedParameters& np) +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + using parameters::choose_parameter; + using parameters::get_parameter; + + typedef typename GetVertexPointMap::const_type VPM; + VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_const_property_map(vertex_point, mesh)); + + typedef CGAL::dynamic_vertex_property_t Vertex_index; + typedef typename boost::property_map::const_type VIM; + VIM vim = get(Vertex_index(), mesh); + + typedef typename boost::range_value::type Polygon; + + std::size_t index = points.size(); // so that multiple meshes can be put into the same soup + CGAL::internal::reserve(points, points.size() + vertices(mesh).size()); + CGAL::internal::reserve(polygons, polygons.size() + faces(mesh).size()); + + for(const vertex_descriptor v : vertices(mesh)) + { + points.emplace_back(get(vpm, v)); + put(vim, v, index++); + } + + for(const face_descriptor f : faces(mesh)) + { + CGAL::Iterator_range > incident_halfedges = + CGAL::halfedges_around_face(halfedge(f, mesh), mesh); + + Polygon polygon; + CGAL::internal::resize(polygon, incident_halfedges.size()); + + std::size_t pos = 0; + for(halfedge_descriptor h : incident_halfedges) + polygon[pos++] = get(vim, target(h, mesh)); + + polygons.push_back(polygon); + } +} + +template +void polygon_mesh_to_polygon_soup(const PolygonMesh& mesh, + PointRange& points, + PolygonRange& polygons) +{ + return polygon_mesh_to_polygon_soup(mesh, points, polygons, CGAL::parameters::all_default()); +} + +} // namespace Polygon_mesh_processing +} // namespace CGAL + +#endif // CGAL_POLYGON_MESH_PROCESSING_POLYGON_MESH_TO_POLYGON_SOUP_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h index 93e4f629576..03a615956c1 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h @@ -10,46 +10,40 @@ // // Author(s) : Laurent Rineau and Ilker O. Yaz -#ifndef CGAL_POLYGON_MESH_PROCESSING_POLYGON_SOUP_TO_POLYGON_MESH -#define CGAL_POLYGON_MESH_PROCESSING_POLYGON_SOUP_TO_POLYGON_MESH +#ifndef CGAL_POLYGON_MESH_PROCESSING_POLYGON_SOUP_TO_POLYGON_MESH_H +#define CGAL_POLYGON_MESH_PROCESSING_POLYGON_SOUP_TO_POLYGON_MESH_H #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 -{ -template -class Polygon_soup_to_polygon_mesh -{ - const PointRange& _points; - const PolygonRange& _polygons; +#include +#include +#include - typedef typename boost::property_map::type Vpmap; - typedef typename boost::property_traits::value_type Point_3; +namespace CGAL { +namespace Polygon_mesh_processing { +namespace internal { - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename boost::graph_traits::face_descriptor face_descriptor; - typedef typename PolygonRange::value_type Polygon; - typedef typename PointRange::value_type Point; +template ::const_type> +class PS_to_PM_converter +{ + typedef typename boost::range_value::type Polygon; + typedef typename boost::property_traits::value_type Point; public: /** @@ -57,178 +51,237 @@ public: * @param points points of the soup of polygons. * @param polygons each element in the range describes a polygon using the index of the points in the range. */ - Polygon_soup_to_polygon_mesh(const PointRange& points, - const PolygonRange& polygons) - : _points(points), - _polygons(polygons) + PS_to_PM_converter(const PointRange& points, + const PolygonRange& polygons, + const PointMap pm = PointMap()) + : m_points(points), + m_polygons(polygons), + m_pm(pm) { } - void operator()(PM& pmesh, const bool insert_isolated_vertices = true) + template + void operator()(PolygonMesh& pmesh, + VertexPointMap vpm, + const bool insert_isolated_vertices = true) { - reserve(pmesh, static_cast::vertices_size_type>(_points.size()), - static_cast::edges_size_type>(2*_polygons.size()), - static_cast::faces_size_type>(_polygons.size()) ); + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - Vpmap vpmap = get(CGAL::vertex_point, pmesh); + typedef typename boost::property_traits::value_type PM_Point; + + CGAL_static_assertion((std::is_convertible::value)); + + reserve(pmesh, static_cast::vertices_size_type>(m_points.size()), + static_cast::edges_size_type>(2*m_polygons.size()), + static_cast::faces_size_type>(m_polygons.size())); boost::dynamic_bitset<> not_isolated; - if (!insert_isolated_vertices) + if(!insert_isolated_vertices) { - not_isolated.resize(_points.size()); - for (std::size_t i = 0, end = _polygons.size(); i < end; ++i) + not_isolated.resize(m_points.size()); + for(std::size_t i = 0, end = m_polygons.size(); i < end; ++i) { - const Polygon& polygon = _polygons[i]; + const Polygon& polygon = m_polygons[i]; const std::size_t size = polygon.size(); - for (std::size_t j = 0; j < size; ++j) + for(std::size_t j = 0; j < size; ++j) not_isolated.set(polygon[j], true); } } - std::vector vertices(_points.size()); - for (std::size_t i = 0, end = _points.size(); i < end; ++i) + std::vector vertices(m_points.size()); + for(std::size_t i = 0, end = m_points.size(); i < end; ++i) { - if (!insert_isolated_vertices && !not_isolated.test(i)) + if(!insert_isolated_vertices && !not_isolated.test(i)) continue; - Point_3 pi(_points[i][0], _points[i][1], _points[i][2]); vertices[i] = add_vertex(pmesh); - put(vpmap, vertices[i], pi); + PM_Point pi(get(m_pm, m_points[i])); + put(vpm, vertices[i], pi); } - for (std::size_t i = 0, end = _polygons.size(); i < end; ++i) + for(std::size_t i = 0, end = m_polygons.size(); i < end; ++i) { - const Polygon& polygon = _polygons[i]; + const Polygon& polygon = m_polygons[i]; const std::size_t size = polygon.size(); std::vector vr(size); //vertex range vr.resize(size); - for (std::size_t j = 0; j < size; ++j) + for(std::size_t j = 0; j < size; ++j) vr[j] = vertices[polygon[j] ]; - CGAL_assertion_code(face_descriptor fd = ) - CGAL::Euler::add_face(vr, pmesh); - CGAL_assertion(fd != boost::graph_traits::null_face()); + CGAL_assertion_code(typename boost::graph_traits::face_descriptor fd =) + CGAL::Euler::add_face(vr, pmesh); + CGAL_assertion(fd != boost::graph_traits::null_face()); } } + + template + void operator()(PolygonMesh& pmesh, + const bool insert_isolated_vertices = true) + { + return operator()(pmesh, get(CGAL::vertex_point, pmesh), insert_isolated_vertices); + } + +private: + const PointRange& m_points; + const PolygonRange& m_polygons; + const PointMap m_pm; }; -}//end namespace internal +} // namespace internal - /** - * \ingroup PMP_repairing_grp - * - * returns `true` if the soup of polygons defines a valid polygon - * mesh that can be handled by - * `CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh()`. - * It checks that each edge has at most two incident faces and such an edge - * is visited in opposite direction along the two face boundaries, - * no polygon has twice the same vertex, - * and the polygon soup describes a manifold surface. - * This function does not require a range of points as an argument - * since the check is purely topological. To each vertex of the mesh - * is associated an index that is used in the description of the - * boundaries of the polygons provided in `polygons`. - * - * @tparam PolygonRange a model of the concept `RandomAccessContainer` - * whose value_type is a model of the concept `RandomAccessContainer` - * whose value_type is `std::size_t`. - * - * @param polygons each element in the range describes a polygon - * using the indices of the vertices. - * - * @sa `orient_polygon_soup()` - */ - template - bool is_polygon_soup_a_polygon_mesh(const PolygonRange& polygons) +/** +* \ingroup PMP_repairing_grp +* +* returns `true` if the soup of polygons defines a valid polygon +* mesh that can be handled by +* `CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh()`. +* It checks that each edge has at most two incident faces and such an edge +* is visited in opposite direction along the two face boundaries, +* no polygon has twice the same vertex, +* and the polygon soup describes a manifold surface. +* This function does not require a range of points as an argument +* since the check is purely topological. To each vertex of the mesh +* is associated an index that is used in the description of the +* boundaries of the polygons provided in `polygons`. +* +* @tparam PolygonRange a model of the concept `RandomAccessContainer` +* whose value_type is a model of the concept `RandomAccessContainer` +* whose value_type is `std::size_t`. +* +* @param polygons each element in the range describes a polygon +* using the indices of the vertices. +* +* @sa `orient_polygon_soup()` +*/ +template +bool is_polygon_soup_a_polygon_mesh(const PolygonRange& polygons) +{ + typedef typename boost::range_value::type Polygon; + typedef typename boost::range_value::type V_ID; + + if(boost::begin(polygons) == boost::end(polygons)) + return true; + + //check there is no duplicated ordered edge, and + //check there is no polygon with twice the same vertex + std::set > edge_set; + V_ID max_id = 0; + for(const Polygon& polygon : polygons) { - typedef typename boost::range_value< - typename boost::range_value< - PolygonRange>::type >::type V_ID; - typedef typename boost::range_value< - PolygonRange>::type Polygon; - - if(boost::begin(polygons) == boost::end(polygons)){ - return true; - } - //check there is no duplicated ordered edge, and - //check there is no polygon with twice the same vertex - std::set< std::pair > edge_set; - V_ID max_id=0; - for(const Polygon& polygon : polygons) - { - std::size_t nb_edges = boost::size(polygon); - if (nb_edges<3) return false; - - std::set polygon_vertices; - V_ID prev= *std::prev(boost::end(polygon)); - for(V_ID id : polygon) - { - if (max_id(prev,id)).second ) - return false; - else - prev=id; - - if (!polygon_vertices.insert(id).second) - return false;//vertex met twice in the same polygon - } - } - - //check manifoldness - typedef std::vector PointRange; - typedef internal::Polygon_soup_orienter Orienter; - typename Orienter::Edge_map edges(max_id+1); - typename Orienter::Marked_edges marked_edges; - Orienter::fill_edge_map(edges, marked_edges, polygons); - //returns false if duplication is necessary - if (!marked_edges.empty()) + std::size_t nb_edges = boost::size(polygon); + if(nb_edges < 3) return false; - return Orienter::has_singular_vertices(static_cast(max_id+1),polygons,edges,marked_edges); + + std::set polygon_vertices; + V_ID prev = *std::prev(boost::end(polygon)); + for(V_ID id : polygon) + { + if(max_id(prev,id)).second) + return false; + else + prev = id; + + if(!polygon_vertices.insert(id).second) + return false; // vertex met twice in the same polygon + } } - /** - * \ingroup PMP_repairing_grp - * builds a polygon mesh from a soup of polygons. - * @pre the input polygon soup describes a consistently oriented - * polygon mesh. - * - * @tparam PolygonMesh a model of `MutableFaceGraph` with an internal point - * property map - * @tparam PointRange a model of the concepts `RandomAccessContainer` and - * `BackInsertionSequence` whose value type is the point type - * @tparam PolygonRange a model of the concept `RandomAccessContainer` whose - * `value_type` is a model of the concept `RandomAccessContainer` whose `value_type` is `std::size_t`. + //check manifoldness + typedef std::vector PointRange; + typedef internal::Polygon_soup_orienter Orienter; - * - * @param points points of the soup of polygons - * @param polygons each element in the vector describes a polygon using the index of the points in `points` - * @param out the polygon mesh to be built - * - * @pre \link CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh() - * CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh(polygons) \endlink - * - * \sa `CGAL::Polygon_mesh_processing::orient_polygon_soup()` - * \sa `CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh()` - * - */ - template - void polygon_soup_to_polygon_mesh( - const PointRange& points, - const PolygonRange& polygons, - PolygonMesh& out) - { - CGAL_precondition_msg(is_polygon_soup_a_polygon_mesh(polygons), - "Input soup needs to be a polygon mesh!"); + typename Orienter::Edge_map edges(max_id+1); + typename Orienter::Marked_edges marked_edges; + Orienter::fill_edge_map(edges, marked_edges, polygons); - internal::Polygon_soup_to_polygon_mesh - converter(points, polygons); - converter(out); - } + //returns false if duplication is necessary + if(!marked_edges.empty()) + return false; -}//end namespace Polygon_mesh_processing + return Orienter::has_singular_vertices(static_cast(max_id+1),polygons,edges,marked_edges); +} -}// end namespace CGAL +/** +* \ingroup PMP_repairing_grp +* builds a polygon mesh from a soup of polygons. +* +* @pre the input polygon soup describes a consistently oriented +* polygon mesh. This can be checked using the function +* \link CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh() +* `CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh(polygons)` \endlink. +* +* @tparam PolygonMesh a model of `MutableFaceGraph` +* @tparam PointRange a model of the concept `RandomAccessContainer` +* whose value type is the point type +* @tparam PolygonRange a model of the concept `RandomAccessContainer` whose +* value type is a model of the concept `RandomAccessContainer` whose value type is `std::size_t` +* @tparam NamedParameters_PS a sequence of \ref pmp_namedparameters "Named Parameters" +* @tparam NamedParameters_PM a sequence of \ref pmp_namedparameters "Named Parameters" +* +* @param points points of the soup of polygons +* @param polygons each element in the vector describes a polygon using the indices of the points in `points` +* @param out the polygon mesh to be built +* @param np_ps optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below +* +* \cgalNamedParamsBegin +* \cgalParamBegin{point_map} +* a model of `ReadablePropertyMap` whose value type is a point type convertible to the point type +* of the vertex point map associated to the polygon mesh. If this parameter is omitted, `CGAL::Identity_property_map` is used. +* \cgalParamEnd +* \cgalNamedParamsEnd +* +* @param np_pm optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below +* +* \cgalNamedParamsBegin +* \cgalParamBegin{vertex_point_map} +* a model of `WritablePropertyMap`, the property map with the points associated to the vertices of `out`. +* If this parameter is omitted, an internal property map for +* `CGAL::vertex_point_t` must be available in `PolygonMesh`. +* \cgalParamEnd +* \cgalNamedParamsEnd +* +* \sa `CGAL::Polygon_mesh_processing::orient_polygon_soup()` +* \sa `CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh()` +* \sa `CGAL::Polygon_mesh_processing::polygon_mesh_to_polygon_soup()` +*/ +template +void polygon_soup_to_polygon_mesh(const PointRange& points, + const PolygonRange& polygons, + PolygonMesh& out, + const NamedParameters_PS& np_ps, + const NamedParameters_PM& np_pm) +{ + CGAL_precondition_msg(is_polygon_soup_a_polygon_mesh(polygons), + "Input soup needs to be a polygon mesh!"); -#include + using parameters::choose_parameter; + using parameters::get_parameter; -#endif // CGAL_POLYGON_MESH_PROCESSING_POLYGON_SOUP_TO_POLYGON_MESH + typedef typename CGAL::GetPointMap::const_type Point_map; + Point_map pm = choose_parameter(get_parameter(np_ps, internal_np::point_map)); + + typedef typename CGAL::GetVertexPointMap::type Vertex_point_map; + Vertex_point_map vpm = choose_parameter(get_parameter(np_pm, internal_np::vertex_point), + get_property_map(CGAL::vertex_point, out)); + + internal::PS_to_PM_converter converter(points, polygons, pm); + converter(out, vpm); +} + +template +void polygon_soup_to_polygon_mesh(const PointRange& points, + const PolygonRange& polygons, + PolygonMesh& out) +{ + return polygon_soup_to_polygon_mesh(points, polygons, out, parameters::all_default(), parameters::all_default()); +} + +} // namespace Polygon_mesh_processing +} // namespace CGAL + +#endif // CGAL_POLYGON_MESH_PROCESSING_POLYGON_SOUP_TO_POLYGON_MESH_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/random_perturbation.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/random_perturbation.h index 555b63fff70..04a1aac09a4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/random_perturbation.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/random_perturbation.h @@ -154,11 +154,11 @@ void random_perturbation(VertexRange vertices #endif typedef typename GetGeomTraits::type GT; - GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT()); + GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); typedef typename GetVertexPointMap::type VPMap; VPMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_property_map(vertex_point, tmesh)); + get_property_map(vertex_point, tmesh)); typedef typename internal_np::Lookup_named_param_def < internal_np::vertex_is_constrained_t, diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index c5a1b649f89..b49a6a47750 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -41,9 +41,7 @@ namespace Polygon_mesh_processing { * The descriptor types `boost::graph_traits::%face_descriptor` * and `boost::graph_traits::%halfedge_descriptor` must be * models of `Hashable`. -* If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, -* and no `face_index_map` is given -* as a named parameter, then the internal one must be initialized +* * @tparam FaceRange range of `boost::graph_traits::%face_descriptor`, model of `Range`. Its iterator type is `ForwardIterator`. * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" @@ -139,6 +137,7 @@ void isotropic_remeshing(const FaceRange& faces typedef PolygonMesh PM; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + using parameters::get_parameter; using parameters::choose_parameter; @@ -154,15 +153,14 @@ void isotropic_remeshing(const FaceRange& faces parameters::is_default_parameter(get_parameter(np, internal_np::projection_functor)); typedef typename GetGeomTraits::type GT; - GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT()); + GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); typedef typename GetVertexPointMap::type VPMap; VPMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_property_map(vertex_point, pmesh)); + get_property_map(vertex_point, pmesh)); - typedef typename GetFaceIndexMap::type FIMap; - FIMap fimap = choose_parameter(get_parameter(np, internal_np::face_index), - get_property_map(face_index, pmesh)); + typedef typename GetInitializedFaceIndexMap::type FIMap; + FIMap fimap = CGAL::get_initialized_face_index_map(pmesh, np); typedef typename internal_np::Lookup_named_param_def < internal_np::edge_is_constrained_t, @@ -332,15 +330,14 @@ void split_long_edges(const EdgeRange& edges using parameters::get_parameter; typedef typename GetGeomTraits::type GT; - GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT()); + GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); typedef typename GetVertexPointMap::type VPMap; VPMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_property_map(vertex_point, pmesh)); + get_property_map(vertex_point, pmesh)); - typedef typename GetFaceIndexMap::type FIMap; - FIMap fimap = choose_parameter(get_parameter(np, internal_np::face_index), - get_property_map(face_index, pmesh)); + typedef typename GetInitializedFaceIndexMap::type FIMap; + FIMap fimap = CGAL::get_initialized_face_index_map(pmesh, np); typedef typename internal_np::Lookup_named_param_def < internal_np::edge_is_constrained_t, diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h index bf8a72a4f80..db274f3d59c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h @@ -29,8 +29,10 @@ #include #include +#include #include #include +#include #include #include @@ -58,8 +60,279 @@ #define CGAL_PMP_NP_CLASS NamedParameters #endif -namespace CGAL{ +namespace CGAL { namespace Polygon_mesh_processing { + +/// \ingroup PMP_repairing_grp +/// removes the isolated vertices from any polygon mesh. +/// A vertex is considered isolated if it is not incident to any simplex +/// of higher dimension. +/// +/// @tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph` +/// +/// @param pmesh the polygon mesh to be repaired +/// +/// @return number of removed isolated vertices +/// +template +std::size_t remove_isolated_vertices(PolygonMesh& pmesh) +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + std::vector to_be_removed; + + for(vertex_descriptor v : vertices(pmesh)) + { + if (CGAL::halfedges_around_target(v, pmesh).first + == CGAL::halfedges_around_target(v, pmesh).second) + to_be_removed.push_back(v); + } + std::size_t nb_removed = to_be_removed.size(); + for(vertex_descriptor v : to_be_removed) + { + remove_vertex(v, pmesh); + } + return nb_removed; +} + +/// \ingroup PMP_repairing_grp +/// +/// removes connected components whose area or volume is under a certain threshold value. +/// +/// Thresholds are provided via \ref pmp_namedparameters "Named Parameters". (see below). +/// If thresholds are not provided by the user, default values are computed as follows: +/// - the area threshold is taken as the square of one percent of the length of the diagonal +/// of the bounding box of the mesh. +/// - the volume threshold is taken as the third power of one percent of the length of the diagonal +/// of the bounding box of the mesh. +/// +/// The area and volume of a connected component will always be positive values (regardless +/// of the orientation of the mesh). +/// +/// As a consequence of the last sentence, the area or volume criteria can be disabled +/// by passing zero (`0`) as threshold value. +/// +/// \tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph` +/// \tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" +/// +/// \param tmesh the triangulated polygon mesh +/// \param np optional \ref pmp_namedparameters "Named Parameters", amongst those described below +/// +/// \cgalNamedParamsBegin +/// \cgalParamBegin{area_threshold} a fixed value such that only connected components whose area is +/// larger than this value are kept \cgalParamEnd +/// \cgalParamBegin{volume_threshold} a fixed value such that only connected components whose volume is +/// larger than this value are kept (only applies to closed connected components) \cgalParamEnd +/// \cgalParamBegin{edge_is_constrained_map} a property map containing the constrained-or-not status of each edge of `pmesh` \cgalParamEnd +/// \cgalParamBegin{face_index_map} a property map containing the index of each face of `tmesh` \cgalParamEnd +/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tmesh`. +/// \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel` \cgalParamEnd +/// \cgalParamBegin{dry_run} a Boolean parameter. If set to `true`, the mesh will not be altered, +/// but the number of components that would be removed is returned. The default value is `false`.\cgalParamEnd +/// \cgalParamBegin{output_iterator} a model of `OutputIterator` with value type `face_descriptor`. +/// When using the "dry run" mode (see parameter `dry_run`), faces +/// that would be removed by the algorithm can be collected with this output iterator. \cgalParamEnd +/// \cgalNamedParamsEnd +/// +/// \return the number of connected components removed (ignoring isolated vertices). +/// +template +std::size_t remove_connected_components_of_negligible_size(TriangleMesh& tmesh, + const NamedParameters& np) +{ + using parameters::choose_parameter; + using parameters::is_default_parameter; + using parameters::get_parameter; + + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + typedef typename GetGeomTraits::type GT; + typedef typename GT::FT FT; + const GT traits = choose_parameter(get_parameter(np, internal_np::vertex_point)); + + typedef typename GetVertexPointMap::const_type VPM; + typedef typename boost::property_traits::value_type Point_3; + const VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_const_property_map(CGAL::vertex_point, tmesh)); + + typedef typename GetInitializedFaceIndexMap::type FaceIndexMap; + FaceIndexMap fim = CGAL::get_initialized_face_index_map(tmesh, np); + + FT area_threshold = choose_parameter(get_parameter(np, internal_np::area_threshold), FT(-1)); + FT volume_threshold = choose_parameter(get_parameter(np, internal_np::volume_threshold), FT(-1)); + + // If no threshold is provided, compute it as a % of the bbox + const bool is_default_area_threshold = is_default_parameter(get_parameter(np, internal_np::area_threshold)); + const bool is_default_volume_threshold = is_default_parameter(get_parameter(np, internal_np::volume_threshold)); + + const bool dry_run = choose_parameter(get_parameter(np, internal_np::dry_run), false); + + typedef typename internal_np::Lookup_named_param_def::type Output_iterator; + Output_iterator out = choose_parameter(get_parameter(np, internal_np::output_iterator)); + +#ifdef CGAL_PMP_DEBUG_SMALL_CC_REMOVAL + std::cout << "default threshold? " << is_default_area_threshold << " " << is_default_volume_threshold << std::endl; +#endif + + FT bbox_diagonal = FT(0), threshold_value = FT(0); + + if(is_default_area_threshold || is_default_volume_threshold) + { + if(is_empty(tmesh)) + return 0; + + const Bbox_3 bb = bbox(tmesh, np); + + bbox_diagonal = FT(CGAL::sqrt(CGAL::square(bb.xmax() - bb.xmin()) + + CGAL::square(bb.ymax() - bb.ymin()) + + CGAL::square(bb.zmax() - bb.zmin()))); + threshold_value = bbox_diagonal / FT(100); // default filter is 1% + +#ifdef CGAL_PMP_DEBUG_SMALL_CC_REMOVAL + std::cout << "bb xmin xmax: " << bb.xmin() << " " << bb.xmax() << std::endl; + std::cout << "bb ymin ymax: " << bb.ymin() << " " << bb.ymax() << std::endl; + std::cout << "bb zmin zmax: " << bb.zmin() << " " << bb.zmax() << std::endl; + std::cout << "bbox_diagonal: " << bbox_diagonal << std::endl; + std::cout << "threshold_value: " << threshold_value << std::endl; +#endif + } + + if(is_default_area_threshold) + area_threshold = CGAL::square(threshold_value); + + if(is_default_volume_threshold) + volume_threshold = CGAL::square(threshold_value); + + const bool use_areas = (is_default_area_threshold || area_threshold > 0); + const bool use_volumes = (is_default_volume_threshold || volume_threshold > 0); + + if(!use_areas && !use_volumes) + return 0; + + // Compute the connected components only once + boost::vector_property_map face_cc(fim); + std::size_t num = connected_components(tmesh, face_cc, np); + +#ifdef CGAL_PMP_DEBUG_SMALL_CC_REMOVAL + std::cout << num << " different connected components" << std::endl; +#endif + + if(!dry_run) + CGAL::Polygon_mesh_processing::remove_isolated_vertices(tmesh); + + // Compute CC-wide and total areas/volumes + FT total_area = 0; + std::vector component_areas(num, 0); + + if(use_areas) + { + for(face_descriptor f : faces(tmesh)) + { + const FT fa = face_area(f, tmesh, np); + component_areas[face_cc[f]] += fa; + total_area += fa; + } + +#ifdef CGAL_PMP_DEBUG_SMALL_CC_REMOVAL + std::cout << "area threshold: " << area_threshold << std::endl; + std::cout << "total area: " << total_area << std::endl; +#endif + } + + // Volumes make no sense for CCs that are not closed + std::vector cc_closeness(num, true); + std::vector component_volumes(num); + + if(use_volumes) + { + for(halfedge_descriptor h : halfedges(tmesh)) + { + if(is_border(h, tmesh)) + cc_closeness[face_cc[face(opposite(h, tmesh), tmesh)]] = false; + } + + typename GT::Compute_volume_3 cv3 = traits.compute_volume_3_object(); + Point_3 origin(0, 0, 0); + + for(face_descriptor f : faces(tmesh)) + { + const std::size_t i = face_cc[f]; + if(!cc_closeness[i]) + continue; + + const FT fv = cv3(origin, + get(vpm, target(halfedge(f, tmesh), tmesh)), + get(vpm, target(next(halfedge(f, tmesh), tmesh), tmesh)), + get(vpm, target(prev(halfedge(f, tmesh), tmesh), tmesh))); + + component_volumes[i] += fv; + } + + // negative volume means the CC was oriented inward + FT total_volume = 0; + for(std::size_t i=0; i is_to_be_removed(num, false); + + for(std::size_t i=0; i ccs_to_remove; + for(std::size_t i=0; i +std::size_t remove_connected_components_of_negligible_size(TriangleMesh& tmesh) +{ + return remove_connected_components_of_negligible_size(tmesh, parameters::all_default()); +} + namespace debug{ template @@ -712,7 +985,7 @@ bool remove_degenerate_edges(const EdgeRange& edge_range, vertex_descriptor vd = remove_a_border_edge(ed, tmesh, degenerate_edges_to_remove, face_set); if (vd == GT::null_vertex()) { - // TODO: if some border edges are later removed, the edge might be processable later + // @todo: if some border edges are later removed, the edge might be processable later // for example if it belongs to boundary cycle of edges where the number of non-degenerate // edges is 2. That's what happen with fused_vertices.off in the testsuite where the edges // are not processed the same way with Polyhedron and Surface_mesh. In the case of Polyhedron @@ -918,7 +1191,7 @@ bool remove_degenerate_edges(const EdgeRange& edge_range, } while(true); - /// \todo use the area criteria? this means maybe continue exploration of larger cc + // @todo use the area criteria? this means maybe continue exploration of larger cc // mark faces of completetly explored cc for (index=0; index< nb_cc; ++index) { @@ -1089,15 +1362,15 @@ bool remove_degenerate_edges(TriangleMesh& tmesh) // - `Compare_distance_3` to compute the distance between 2 points // - `Collinear_3` to check whether 3 points are collinear // - `Less_xyz_3` to compare lexicographically two points -/// - `Equal_3` to check whether 2 points are identical. -/// For each functor Foo, a function `Foo foo_object()` must be provided. +// - `Equal_3` to check whether 2 points are identical. +// For each functor Foo, a function `Foo foo_object()` must be provided. // \cgalParamEnd // \cgalNamedParamsEnd // -// \todo the function might not be able to remove all degenerate faces. +// @todo the function might not be able to remove all degenerate faces. // We should probably do something with the return type. // -/// \return `true` if all degenerate faces were successfully removed, and `false` otherwise. +// \return `true` if all degenerate faces were successfully removed, and `false` otherwise. template bool remove_degenerate_faces(const FaceRange& face_range, TriangleMesh& tmesh, @@ -1117,9 +1390,9 @@ bool remove_degenerate_faces(const FaceRange& face_range, typedef typename GetVertexPointMap::type VertexPointMap; VertexPointMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_property_map(vertex_point, tmesh)); + get_property_map(vertex_point, tmesh)); typedef typename GetGeomTraits::type Traits; - Traits traits = choose_parameter(get_parameter(np, internal_np::geom_traits), Traits()); + Traits traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); typedef typename boost::property_traits::value_type Point_3; typedef typename boost::property_traits::reference Point_ref; @@ -1198,7 +1471,7 @@ bool remove_degenerate_faces(const FaceRange& face_range, // Then, remove triangles made of 3 collinear points // start by filtering out border faces - // TODO: shall we avoid doing that in case a non-manifold vertex on the boundary or if a whole component disappear? + // @todo: shall we avoid doing that in case a non-manifold vertex on the boundary or if a whole component disappear? std::set border_deg_faces; for(face_descriptor f : degenerate_face_set) { @@ -1405,7 +1678,7 @@ bool remove_degenerate_faces(const FaceRange& face_range, all_removed=false; #ifdef CGAL_PMP_REMOVE_DEGENERATE_FACES_DEBUG std::cout << " WARNING: flip is not possible\n"; - // \todo Let p and q be the vertices opposite to `edge_to_flip`, and let + // @todo Let p and q be the vertices opposite to `edge_to_flip`, and let // r be the vertex of `edge_to_flip` that is the furthest away from // the edge `pq`. In that case I think we should remove all the triangles // so that the triangle pqr is in the mesh. @@ -1506,7 +1779,7 @@ bool remove_degenerate_faces(const FaceRange& face_range, (cc_faces.size()+boundary_hedges.size())/2 != 1) { //cc_faces does not define a topological disk - /// \todo Find to way to handle that case + // @todo Find to way to handle that case #ifdef CGAL_PMP_REMOVE_DEGENERATE_FACES_DEBUG std::cout << " WARNING: Cannot remove the component of degenerate faces: not a topological disk.\n"; #endif @@ -1652,7 +1925,7 @@ bool remove_degenerate_faces(const FaceRange& face_range, CGAL_assertion(get(vpmap,source(side_one.front(), tmesh))==side_points.front()); CGAL_assertion(get(vpmap,target(side_one.back(), tmesh))==side_points.back()); - //\todo the reordering could lead to the apparition of null edges. + // @todo the reordering could lead to the apparition of null edges. std::sort(side_points.begin(), side_points.end()); CGAL_assertion(std::unique(side_points.begin(), side_points.end())==side_points.end()); @@ -1670,7 +1943,7 @@ bool remove_degenerate_faces(const FaceRange& face_range, CGAL_assertion(get(vpmap,source(side_two.front(), tmesh))==side_points.front()); CGAL_assertion(get(vpmap,target(side_two.back(), tmesh))==side_points.back()); - //\todo the reordering could lead to the apparition of null edges. + // @todo the reordering could lead to the apparition of null edges. std::sort(side_points.begin(), side_points.end()); CGAL_assertion(std::unique(side_points.begin(), side_points.end())==side_points.end()); @@ -1856,7 +2129,7 @@ bool remove_degenerate_faces(const FaceRange& face_range, if ( target(next(opposite(h_side1, tmesh), tmesh), tmesh) == target(next(opposite(h_side2, tmesh), tmesh), tmesh) ) { - CGAL_assertion(!"Forbidden simplification"); + CGAL_error_msg("Forbidden simplification"); } h_side2 = prev(h_side2, tmesh); @@ -2344,7 +2617,7 @@ std::size_t duplicate_non_manifold_vertices(PolygonMesh& pm, Emptyset_iterator > ::type Output_iterator; - Output_iterator out = choose_parameter(get_parameter(np, internal_np::output_iterator), Emptyset_iterator()); + Output_iterator out = choose_parameter(get_parameter(np, internal_np::output_iterator)); std::vector non_manifold_cones; non_manifold_vertices(pm, std::back_inserter(non_manifold_cones)); @@ -2368,37 +2641,6 @@ std::size_t duplicate_non_manifold_vertices(PolygonMesh& pm) return duplicate_non_manifold_vertices(pm, parameters::all_default()); } -/// \ingroup PMP_repairing_grp -/// removes the isolated vertices from any polygon mesh. -/// A vertex is considered isolated if it is not incident to any simplex -/// of higher dimension. -/// -/// @tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph` -/// -/// @param pmesh the polygon mesh to be repaired -/// -/// @return number of removed isolated vertices -/// -template -std::size_t remove_isolated_vertices(PolygonMesh& pmesh) -{ - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - std::vector to_be_removed; - - for(vertex_descriptor v : vertices(pmesh)) - { - if (CGAL::halfedges_around_target(v, pmesh).first - == CGAL::halfedges_around_target(v, pmesh).second) - to_be_removed.push_back(v); - } - std::size_t nb_removed = to_be_removed.size(); - for(vertex_descriptor v : to_be_removed) - { - remove_vertex(v, pmesh); - } - return nb_removed; -} - /// \cond SKIP_IN_MANUAL template std::pair< bool, bool > @@ -2744,7 +2986,7 @@ remove_self_intersections_one_step(TriangleMesh& tm, vertex_descriptor v = source(h, tm); hole_points.push_back( get(vpmap, v) ); border_vertices.push_back(v); - third_points.push_back(get(vpmap, target(next(opposite(h, tm), tm), tm))); // TODO fix me for mesh border edges + third_points.push_back(get(vpmap, target(next(opposite(h, tm), tm), tm))); // @todo fix me for mesh border edges } CGAL_assertion(hole_points.size() >= 3); @@ -2946,7 +3188,7 @@ bool remove_self_intersections(TriangleMesh& tm, const NamedParameters& np) { typedef std::pair Face_pair; std::vector self_inter; - // TODO : possible optimization to reduce the range to check with the bbox + // @todo : possible optimization to reduce the range to check with the bbox // of the previous patches or something. self_intersections(tm, std::back_inserter(self_inter)); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_polygon_soup.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_polygon_soup.h index 096f1f60b08..1230c0a7b80 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_polygon_soup.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_polygon_soup.h @@ -513,7 +513,7 @@ std::size_t merge_duplicate_points_in_polygon_soup(PointRange& points, using parameters::choose_parameter; typedef typename internal::GetPolygonGeomTraits::type Traits; - Traits traits = choose_parameter(get_parameter(np, internal_np::geom_traits), Traits()); + Traits traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); typedef typename Traits::Less_xyz_3 Less_xyz_3; @@ -567,7 +567,8 @@ std::size_t merge_duplicate_points_in_polygon_soup(PointRange& points, const std::size_t removed_points_n = ini_points_n - points.size(); #ifdef CGAL_PMP_REPAIR_POLYGON_SOUP_VERBOSE - std::cout << "Removed (merged) " << removed_points_n << " duplicate points" << std::endl; + if(removed_points_n > 0) + std::cout << "Removed (merged) " << removed_points_n << " duplicate points" << std::endl; #endif return removed_points_n; @@ -914,7 +915,7 @@ std::size_t merge_duplicate_polygons_in_polygon_soup(const PointRange& points, #endif typedef typename internal::GetPolygonGeomTraits::type Traits; - Traits traits = choose_parameter(get_parameter(np, internal_np::geom_traits), Traits()); + Traits traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); std::vector > all_duplicate_polygons; internal::collect_duplicate_polygons(points, polygons, std::back_inserter(all_duplicate_polygons), traits, same_orientation); @@ -1061,7 +1062,7 @@ void repair_polygon_soup(PointRange& points, using parameters::choose_parameter; typedef typename internal::GetPolygonGeomTraits::type Traits; - Traits traits = choose_parameter(get_parameter(np, internal_np::geom_traits), Traits()); + Traits traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); #ifdef CGAL_PMP_REPAIR_POLYGON_SOUP_VERBOSE std::cout << "Repairing soup with " << points.size() << " points and " << polygons.size() << " polygons" << 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 409bdc4900d..46874074c03 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h @@ -21,215 +21,378 @@ #include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CGAL_LINKED_WITH_TBB +#include +#include +#include +#endif + +#include + +#include +#include +#include +#include + #ifdef DOXYGEN_RUNNING #define CGAL_PMP_NP_TEMPLATE_PARAMETERS NamedParameters #define CGAL_PMP_NP_CLASS NamedParameters #endif namespace CGAL { +namespace Polygon_mesh_processing { namespace internal { -template -struct Intersect_facets -{ - // wrapper to check whether anything is inserted to output iterator - struct Output_iterator_with_bool - { - Output_iterator_with_bool(OutputIterator* out, bool* intersected) - : m_iterator(out), m_intersected(intersected) { } - template - void operator()(const T& t) { - *m_intersected = true; - *(*m_iterator)++ = t; +// Checks for 'real' intersections, i.e. not simply a shared vertex or edge +template +bool do_faces_intersect(typename boost::graph_traits::halfedge_descriptor h, + typename boost::graph_traits::halfedge_descriptor g, + const TM& tmesh, + const VPM vpmap, + const typename GT::Construct_segment_3& construct_segment, + const typename GT::Construct_triangle_3& construct_triangle, + const typename GT::Do_intersect_3& do_intersect) +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename GT::Segment_3 Segment; + typedef typename GT::Triangle_3 Triangle; + + CGAL_assertion(!is_border(h, tmesh)); + CGAL_assertion(!is_border(g, tmesh)); + + vertex_descriptor hv[3], gv[3]; + hv[0] = target(h, tmesh); + hv[1] = target(next(h, tmesh), tmesh); + hv[2] = source(h, tmesh); + + gv[0] = target(g, tmesh); + gv[1] = target(next(g, tmesh), tmesh); + gv[2] = source(g, tmesh); + + // check for shared edge + for(unsigned int i=0; i<3; ++i) + { + halfedge_descriptor opp_h = opposite(h, tmesh); + if(face(opp_h, tmesh) == face(g, tmesh)) + { + // there is an intersection if the four points are coplanar and the triangles overlap + if(CGAL::coplanar(get(vpmap, hv[i]), + get(vpmap, hv[(i+1)%3]), + get(vpmap, hv[(i+2)%3]), + get(vpmap, target(next(opp_h, tmesh), tmesh))) && + CGAL::coplanar_orientation(get(vpmap, hv[(i+2)%3]), + get(vpmap, hv[i]), + get(vpmap, hv[(i+1)%3]), + get(vpmap, target(next(opp_h, tmesh), tmesh))) + == CGAL::POSITIVE) + { + return true; + } + else + { + // there is a shared edge but no intersection + return false; + } } - OutputIterator* m_iterator; - bool* m_intersected; - }; -// typedefs - typedef typename Kernel::Segment_3 Segment; - typedef typename Kernel::Triangle_3 Triangle; + h = next(h, tmesh); + } + + // check for shared vertex --> maybe intersection, maybe not + int i(0), j(0); + bool shared = false; + for(; i<3 && (! shared); ++i) + { + for(j=0; j<3 && (! shared); ++j) + { + if(hv[i] == gv[j]) + { + shared = true; + break; + } + } + + if(shared) + break; + } + + if(shared) + { + // found shared vertex: + CGAL_assertion(hv[i] == gv[j]); + + // geometric check if the opposite segments intersect the triangles + const Triangle t1 = construct_triangle(get(vpmap, hv[0]), get(vpmap, hv[1]), get(vpmap, hv[2])); + const Triangle t2 = construct_triangle(get(vpmap, gv[0]), get(vpmap, gv[1]), get(vpmap, gv[2])); + + const Segment s1 = construct_segment(get(vpmap, hv[(i+1)%3]), get(vpmap, hv[(i+2)%3])); + const Segment s2 = construct_segment(get(vpmap, gv[(j+1)%3]), get(vpmap, gv[(j+2)%3])); + + if(do_intersect(t1, s2)) + return true; + else if(do_intersect(t2, s1)) + return true; + + return false; + } + + // check for geometric intersection + const Triangle th = construct_triangle(get(vpmap, hv[0]), get(vpmap, hv[1]), get(vpmap, hv[2])); + const Triangle tg = construct_triangle(get(vpmap, gv[0]), get(vpmap, gv[1]), get(vpmap, gv[2])); + if(do_intersect(th, tg)) + return true; + + return false; +}; + +template +struct Strict_intersect_faces // "strict" as in "not sharing a subface" +{ typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename boost::property_map::const_type Ppmap; -// members + mutable OutputIterator m_iterator; const TM& m_tmesh; - const VertexPointMap m_vpmap; - mutable OutputIterator m_iterator; - mutable bool m_intersected; - mutable boost::function_output_iterator m_iterator_wrapper; + const VPM m_vpmap; + typename GT::Construct_segment_3 m_construct_segment; + typename GT::Construct_triangle_3 m_construct_triangle; + typename GT::Do_intersect_3 m_do_intersect; - typename Kernel::Construct_segment_3 segment_functor; - typename Kernel::Construct_triangle_3 triangle_functor; - typename Kernel::Do_intersect_3 do_intersect_3_functor; - - - Intersect_facets(const TM& tmesh, OutputIterator it, VertexPointMap vpmap, const Kernel& kernel) + Strict_intersect_faces(const TM& tmesh, VPM vpmap, const GT& gt, OutputIterator it) : - m_tmesh(tmesh), - m_vpmap(vpmap), - m_iterator(it), - m_intersected(false), - m_iterator_wrapper(Output_iterator_with_bool(&m_iterator, &m_intersected)), - segment_functor(kernel.construct_segment_3_object()), - triangle_functor(kernel.construct_triangle_3_object()), - do_intersect_3_functor(kernel.do_intersect_3_object()) - { } + m_iterator(it), + m_tmesh(tmesh), + m_vpmap(vpmap), + m_construct_segment(gt.construct_segment_3_object()), + m_construct_triangle(gt.construct_triangle_3_object()), + m_do_intersect(gt.do_intersect_3_object()) + {} void operator()(const Box* b, const Box* c) const { - halfedge_descriptor h = halfedge(b->info(), m_tmesh); - halfedge_descriptor opp_h; + const halfedge_descriptor h = halfedge(b->info(), m_tmesh); + const halfedge_descriptor g = halfedge(c->info(), m_tmesh); - // check for shared egde - for(unsigned int i=0; i<3; ++i){ - opp_h = opposite(h, m_tmesh); - if(face(opp_h, m_tmesh) == c->info()){ - // there is an intersection if the four points are coplanar and - // the triangles overlap - if(CGAL::coplanar(get(m_vpmap, target(h, m_tmesh)), - get(m_vpmap, target(next(h, m_tmesh), m_tmesh)), - get(m_vpmap, source(h, m_tmesh)), - get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) && - CGAL::coplanar_orientation(get(m_vpmap, source(h, m_tmesh)), - get(m_vpmap, target(h, m_tmesh)), - get(m_vpmap, target(next(h, m_tmesh), m_tmesh)), - get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) - == CGAL::POSITIVE){ - *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); - return; - } else { // there is a shared edge but no intersection - return; - } - } - h = next(h, m_tmesh); - } - - // check for shared vertex --> maybe intersection, maybe not - halfedge_descriptor g = halfedge(c->info(),m_tmesh); - halfedge_descriptor v; - - if(target(h,m_tmesh) == target(g,m_tmesh)) - v = g; - if(target(h,m_tmesh) == target(next(g,m_tmesh),m_tmesh)) - v = next(g,m_tmesh); - if(target(h,m_tmesh) == target(next(next(g,m_tmesh),m_tmesh),m_tmesh)) - v = next(next(g,m_tmesh),m_tmesh); - - if(v == halfedge_descriptor()){ - h = next(h,m_tmesh); - if(target(h,m_tmesh) == target(g,m_tmesh)) - v = g; - if(target(h,m_tmesh) == target(next(g,m_tmesh),m_tmesh)) - v = next(g,m_tmesh); - if(target(h,m_tmesh) == target(next(next(g,m_tmesh),m_tmesh),m_tmesh)) - v = next(next(g,m_tmesh),m_tmesh); - if(v == halfedge_descriptor()){ - h = next(h,m_tmesh); - if(target(h,m_tmesh) == target(g,m_tmesh)) - v = g; - if(target(h,m_tmesh) == target(next(g,m_tmesh),m_tmesh)) - v = next(g,m_tmesh); - if(target(h,m_tmesh) == target(next(next(g,m_tmesh),m_tmesh),m_tmesh)) - v = next(next(g,m_tmesh),m_tmesh); - } - } - - if(v != halfedge_descriptor()){ - // found shared vertex: - CGAL_assertion(target(h,m_tmesh) == target(v,m_tmesh)); - // geometric check if the opposite segments intersect the triangles - Triangle t1 = triangle_functor( get(m_vpmap,target(h,m_tmesh)), - get(m_vpmap, target(next(h,m_tmesh),m_tmesh)), - get(m_vpmap, target(next(next(h,m_tmesh),m_tmesh),m_tmesh))); - Triangle t2 = triangle_functor( get(m_vpmap, target(v,m_tmesh)), - get(m_vpmap, target(next(v,m_tmesh),m_tmesh)), - get(m_vpmap, target(next(next(v,m_tmesh),m_tmesh),m_tmesh))); - - Segment s1 = segment_functor( get(m_vpmap, target(next(h,m_tmesh),m_tmesh)), - get(m_vpmap, target(next(next(h,m_tmesh),m_tmesh),m_tmesh))); - Segment s2 = segment_functor( get(m_vpmap, target(next(v,m_tmesh),m_tmesh)), - get(m_vpmap, target(next(next(v,m_tmesh),m_tmesh),m_tmesh))); - - if(do_intersect_3_functor(t1,s2)){ - *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); - } else if(do_intersect_3_functor(t2,s1)){ - *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); - } - return; - } - - // check for geometric intersection - Triangle t1 = triangle_functor( get(m_vpmap, target(h,m_tmesh)), - get(m_vpmap, target(next(h,m_tmesh),m_tmesh)), - get(m_vpmap, target(next(next(h,m_tmesh),m_tmesh),m_tmesh))); - Triangle t2 = triangle_functor( get(m_vpmap, target(g,m_tmesh)), - get(m_vpmap, target(next(g,m_tmesh),m_tmesh)), - get(m_vpmap, target(next(next(g,m_tmesh),m_tmesh),m_tmesh))); - if(do_intersect_3_functor(t1, t2)){ - *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); - } - } // end operator () -}; // end struct Intersect_facets - -struct Throw_at_output { - class Throw_at_output_exception: public std::exception - { }; - - template - void operator()(const T& /* t */) const { - throw Throw_at_output_exception(); + if(do_faces_intersect(h, g, m_tmesh, m_vpmap, m_construct_segment, m_construct_triangle, m_do_intersect)) + *m_iterator++ = std::make_pair(b->info(), c->info()); } }; -}// namespace internal +template +FacePairOutputIterator +self_intersections_impl(const FaceRange& face_range, + const TriangleMesh& tmesh, + FacePairOutputIterator out, + const bool throw_on_SI, + const NamedParameters& np) +{ + CGAL_precondition(CGAL::is_triangle_mesh(tmesh)); -namespace Polygon_mesh_processing { + using CGAL::parameters::choose_parameter; + using CGAL::parameters::get_parameter; -#ifndef DOXYGEN_RUNNING -template -OutputIterator -self_intersections( const FaceRange& face_range, - const TriangleMesh& tmesh, - OutputIterator out, - const NamedParameters& np); + typedef TriangleMesh TM; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Box; + + typedef typename GetGeomTraits::type GT; + GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); + + typedef typename GetVertexPointMap::const_type VPM; + VPM vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_const_property_map(boost::vertex_point, tmesh)); + + const unsigned int seed = choose_parameter(get_parameter(np, internal_np::random_seed), 0); + CGAL_USE(seed); // used in the random shuffle of the range, which is only done to balance tasks in parallel + + const std::ptrdiff_t cutoff = 2000; + + // make one box per face + std::vector boxes; + boxes.reserve(std::distance(std::begin(face_range), std::end(face_range))); + + // This loop is very cheap, so there is hardly anything to gain from parallelizing it + for(face_descriptor f : face_range) + { + halfedge_descriptor h = halfedge(f, tmesh); + typename boost::property_traits::reference + p = get(vpmap, target(h,tmesh)), + q = get(vpmap, target(next(h, tmesh), tmesh)), + r = get(vpmap, target(prev(h, tmesh), tmesh)); + + // tiny fixme: if f is degenerate, we might still have a real intersection between f + // and another face f', but right now we are not creating a box for f and thus not returning those + if(collinear(p, q, r)) + { + if(throw_on_SI) + throw CGAL::internal::Throw_at_output_exception(); + else + *out++= std::make_pair(f, f); + } + else + { + boxes.push_back(Box(p.bbox() + q.bbox() + r.bbox(), f)); + } + } + + // generate box pointers + std::vector box_ptr; + box_ptr.reserve(boxes.size()); + + for(Box& b : boxes) + box_ptr.push_back(&b); + + // In case we are throwing, like in `does_self_intersect()`, we keep the geometric test to throw ASAP. + // This is obviously not optimal if there are no or few self-intersections: it would be a greater speed-up + // to do the same as for `self_intersections()`. However, doing like `self_intersections()` would + // be a major slow-down over sequential code if there are a lot of self-intersections... + typedef boost::function_output_iterator Throwing_output_iterator; + typedef internal::Strict_intersect_faces Throwing_filter; + Throwing_filter throwing_filter(tmesh, vpmap, gt, Throwing_output_iterator()); + +#if !defined(CGAL_LINKED_WITH_TBB) + CGAL_static_assertion_msg (!(std::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable."); +#else + if(std::is_convertible::value) + { + // We are going to split the range into a number of smaller ranges. To handle + // smaller trees of roughly the same size, we first apply a random shuffle to the range + CGAL::Random rng(seed); + CGAL::cpp98::random_shuffle(box_ptr.begin(), box_ptr.end(), rng); + + // Write in a concurrent vector all pairs that intersect + typedef tbb::concurrent_vector > Face_pairs; + typedef std::back_insert_iterator Face_pairs_back_inserter; + typedef internal::Strict_intersect_faces Intersecting_faces_filter; + + Face_pairs face_pairs; + Intersecting_faces_filter callback(tmesh, vpmap, gt, std::back_inserter(face_pairs)); + + if(throw_on_SI) + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), throwing_filter, cutoff); + else + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), callback, cutoff); + + // Sequentially write into the output iterator + for(std::size_t i=0; i Intersecting_faces_filter; + Intersecting_faces_filter intersect_faces(tmesh, vpmap, gt, out); + + if(throw_on_SI) + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), throwing_filter, cutoff); + else + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), intersect_faces, cutoff); + + return intersect_faces.m_iterator; +} + +} // namespace internal + +/*! + * \ingroup PMP_intersection_grp + * collects intersections between a subset of faces of a triangulated surface mesh. + * Two faces are said to intersect if the corresponding triangles intersect + * and the intersection is not an edge nor a vertex incident to both faces. + * + * This function depends on the package \ref PkgBoxIntersectionD + * + * @pre `CGAL::is_triangle_mesh(tmesh)` + * + * @tparam ConcurrencyTag enables sequential versus parallel algorithm. + * Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`. + * @tparam FaceRange a model of `ConstRange` with value type `boost::graph_traits::%face_descriptor`. + * @tparam TriangleMesh a model of `FaceListGraph` + * @tparam FacePairOutputIterator a model of `OutputIterator` holding objects of type + * `std::pair::%face_descriptor, boost::graph_traits::%face_descriptor>` + * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" + * + * @param face_range the range of faces to check for self-intersection. + * @param tmesh the triangulated surface mesh to be checked + * @param out output iterator to be filled with all pairs of non-adjacent faces that intersect + * @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below + * + * \cgalNamedParamsBegin + * \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`. + * If this parameter is omitted, an internal property map for + * `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd + * \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd + * \cgalNamedParamsEnd + */ +template < class ConcurrencyTag = Sequential_tag, + class TriangleMesh, + class FaceRange, + class FacePairOutputIterator, + class NamedParameters> +FacePairOutputIterator +self_intersections(const FaceRange& face_range, + const TriangleMesh& tmesh, + FacePairOutputIterator out, + const NamedParameters& np) +{ + return internal::self_intersections_impl(face_range, tmesh, out, false /*don't throw*/, np); +} + +/// \cond SKIP_IN_MANUAL +template +FacePairOutputIterator +self_intersections(const FaceRange& face_range, + const TriangleMesh& tmesh, + FacePairOutputIterator out) +{ + return self_intersections(face_range, tmesh, out, CGAL::parameters::all_default()); +} +/// \endcond + /** * \ingroup PMP_intersection_grp - * detects and records self-intersections of a triangulated surface mesh. + * collects intersections between all the faces of a triangulated surface mesh. + * Two faces are said to intersect if the corresponding triangles intersect + * and the intersection is not an edge nor a vertex incident to both faces. + * * This function depends on the package \ref PkgBoxIntersectionD + * * @pre `CGAL::is_triangle_mesh(tmesh)` * + * @tparam ConcurrencyTag enables sequential versus parallel algorithm. + * Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`. * @tparam TriangleMesh a model of `FaceListGraph` - * @tparam OutputIterator a model of `OutputIterator` holding objects of type + * @tparam FacePairOutputIterator a model of `OutputIterator` holding objects of type * `std::pair::%face_descriptor, boost::graph_traits::%face_descriptor>` * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" * @@ -249,181 +412,35 @@ self_intersections( const FaceRange& face_range, * * @return `out` */ -template -OutputIterator -self_intersections(const TriangleMesh& tmesh - , OutputIterator out -#ifdef DOXYGEN_RUNNING - , const NamedParameters& np) -#else - , const Named_function_parameters& np) -#endif +template +FacePairOutputIterator +self_intersections(const TriangleMesh& tmesh, + FacePairOutputIterator out, + const CGAL_PMP_NP_CLASS& np) { - return self_intersections(faces(tmesh), tmesh, out, np); + return self_intersections(faces(tmesh), tmesh, out, np); } /// \cond SKIP_IN_MANUAL -template -OutputIterator -self_intersections(const TriangleMesh& tmesh, OutputIterator out) +template +FacePairOutputIterator +self_intersections(const TriangleMesh& tmesh, FacePairOutputIterator out) { - return self_intersections(tmesh, out, - CGAL::Polygon_mesh_processing::parameters::all_default()); + return self_intersections(faces(tmesh), tmesh, out, parameters::all_default()); } /// \endcond -/*! - * \ingroup PMP_intersection_grp - * Same as above but the self-intersections reported - * are only limited to the faces in `face_range`. - * - * @pre `CGAL::is_triangle_mesh(tmesh)` - * - * @tparam FaceRange range of `boost::graph_traits::%face_descriptor`, - * model of `Range`. - * Its iterator type is `RandomAccessIterator`. - * @tparam TriangleMesh a model of `FaceListGraph` - * @tparam OutputIterator a model of `OutputIterator` holding objects of type - * `std::pair::%face_descriptor, boost::graph_traits::%face_descriptor>` - * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" - * - * @param face_range the range of faces to check for self-intersection. - * @param tmesh the triangulated surface mesh to be checked - * @param out output iterator to be filled with all pairs of non-adjacent faces that intersect - * @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below - * - * \cgalNamedParamsBegin - * \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`. - * If this parameter is omitted, an internal property map for - * `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd - * \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd - * \cgalNamedParamsEnd - - */ -template -OutputIterator -self_intersections( const FaceRange& face_range, - const TriangleMesh& tmesh, - OutputIterator out, - const NamedParameters& np) -{ - CGAL_precondition(CGAL::is_triangle_mesh(tmesh)); - - typedef TriangleMesh TM; - typedef typename boost::graph_traits::face_descriptor face_descriptor; - typedef typename CGAL::Box_intersection_d::Box_with_info_d Box; - - // make one box per facet - std::vector boxes; - boxes.reserve( - std::distance( boost::begin(face_range), boost::end(face_range) ) - ); - - typedef typename GetVertexPointMap::const_type VertexPointMap; - VertexPointMap vpmap = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point), - get_const_property_map(boost::vertex_point, tmesh)); - - for(face_descriptor f : face_range) - { - typename boost::property_traits::reference - p = get(vpmap, target(halfedge(f,tmesh),tmesh)), - q = get(vpmap, target(next(halfedge(f, tmesh), tmesh), tmesh)), - r = get(vpmap, target(next(next(halfedge(f, tmesh), tmesh), tmesh), tmesh)); - - if ( collinear(p, q, r) ) - *out++= std::make_pair(f,f); - else - boxes.push_back(Box(p.bbox() + q.bbox() + r.bbox(), f)); - } - // generate box pointers - std::vector box_ptr; - box_ptr.reserve(num_faces(tmesh)); - - for(Box& b : boxes) - box_ptr.push_back(&b); - - // compute self-intersections filtered out by boxes - typedef typename GetGeomTraits::type GeomTraits; - CGAL::internal::Intersect_facets - intersect_facets(tmesh, out, vpmap, - parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); - - std::ptrdiff_t cutoff = 2000; - CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),intersect_facets,cutoff); - return intersect_facets.m_iterator; -} - -/// \cond SKIP_IN_MANUAL -template -OutputIterator self_intersections(const FaceRange& face_range, - const TriangleMesh& tmesh, - OutputIterator out) -{ - return self_intersections(face_range, tmesh, out, - CGAL::Polygon_mesh_processing::parameters::all_default()); -} -/// \endcond - -/** - * \ingroup PMP_intersection_grp - * tests if a triangulated surface mesh self-intersects. - * This function depends on the package \ref PkgBoxIntersectionD - * @pre `CGAL::is_triangle_mesh(tmesh)` - * - * @tparam TriangleMesh a model of `FaceListGraph` - * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" - * - * @param tmesh the triangulated surface mesh to be tested - * @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below - * - * \cgalNamedParamsBegin - * \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tmesh`. - * If this parameter is omitted, an internal property map for - * `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd - * \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd - * \cgalNamedParamsEnd - * - * @return true if `tmesh` self-intersects - */ -template -bool does_self_intersect(const TriangleMesh& tmesh - , const CGAL_PMP_NP_CLASS& np) -{ - CGAL_precondition(CGAL::is_triangle_mesh(tmesh)); - - try - { - typedef boost::function_output_iterator OutputIterator; - self_intersections(tmesh, OutputIterator(), np); - } - catch( CGAL::internal::Throw_at_output::Throw_at_output_exception& ) - { return true; } - - return false; -} - /** * \ingroup PMP_intersection_grp * tests if a set of faces of a triangulated surface mesh self-intersects. * This function depends on the package \ref PkgBoxIntersectionD * @pre `CGAL::is_triangle_mesh(tmesh)` * + * @tparam ConcurrencyTag enables sequential versus parallel algorithm. + * Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`. * @tparam FaceRange a range of `face_descriptor` * @tparam TriangleMesh a model of `FaceListGraph` * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" @@ -439,12 +456,12 @@ bool does_self_intersect(const TriangleMesh& tmesh * \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `SelfIntersectionTraits` \cgalParamEnd * \cgalNamedParamsEnd * - * @return true if the faces in `face_range` self-intersect + * @return `true` if the faces in `face_range` self-intersect */ -template + class NamedParameters> bool does_self_intersect(const FaceRange& face_range, const TriangleMesh& tmesh, const NamedParameters& np) @@ -453,35 +470,65 @@ bool does_self_intersect(const FaceRange& face_range, try { - typedef boost::function_output_iterator OutputIterator; - self_intersections(face_range, tmesh, OutputIterator(), np); + CGAL::Emptyset_iterator unused_out; + internal::self_intersections_impl(face_range, tmesh, unused_out, true /*throw*/, np); + } + catch(CGAL::internal::Throw_at_output_exception&) + { + return true; } - catch( CGAL::internal::Throw_at_output::Throw_at_output_exception& ) - { return true; } return false; } -/// \cond SKIP_IN_MANUAL -template -bool does_self_intersect(const TriangleMesh& tmesh) +/** + * \ingroup PMP_intersection_grp + * tests if a triangulated surface mesh self-intersects. + * This function depends on the package \ref PkgBoxIntersectionD + * @pre `CGAL::is_triangle_mesh(tmesh)` + * + * @tparam ConcurrencyTag enables sequential versus parallel algorithm. + * Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`. + * @tparam TriangleMesh a model of `FaceListGraph` + * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" + * + * @param tmesh the triangulated surface mesh to be tested + * @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below + * + * \cgalNamedParamsBegin + * \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tmesh`. + * If this parameter is omitted, an internal property map for + * `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd + * \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd + * \cgalNamedParamsEnd + * + * @return `true` if `tmesh` self-intersects + */ +template +bool does_self_intersect(const TriangleMesh& tmesh, + const CGAL_PMP_NP_CLASS& np) { - return does_self_intersect(tmesh, - CGAL::Polygon_mesh_processing::parameters::all_default()); + return does_self_intersect(faces(tmesh), tmesh, np); } -template +/// \cond SKIP_IN_MANUAL +template +bool does_self_intersect(const TriangleMesh& tmesh) +{ + return does_self_intersect(faces(tmesh), tmesh, CGAL::parameters::all_default()); +} + +template bool does_self_intersect(const FaceRange& face_range, const TriangleMesh& tmesh) { - return does_self_intersect(face_range, tmesh, - CGAL::Polygon_mesh_processing::parameters::all_default()); + return does_self_intersect(face_range, tmesh, CGAL::parameters::all_default()); } - /// \endcond -}// end namespace Polygon_mesh_processing - +}// namespace Polygon_mesh_processing }// namespace CGAL #include diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/shape_predicates.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/shape_predicates.h index 6cc49495ad5..8004766c805 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/shape_predicates.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/shape_predicates.h @@ -70,10 +70,10 @@ bool is_degenerate_edge(typename boost::graph_traits::edge_descript typedef typename GetVertexPointMap::const_type VertexPointMap; VertexPointMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(vertex_point, pm)); + get_const_property_map(vertex_point, pm)); typedef typename GetGeomTraits::type Traits; - Traits traits = choose_parameter(get_parameter(np, internal_np::geom_traits), Traits()); + Traits traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); return traits.equal_3_object()(get(vpmap, source(e, pm)), get(vpmap, target(e, pm))); } @@ -123,10 +123,10 @@ bool is_degenerate_triangle_face(typename boost::graph_traits::fac typedef typename GetVertexPointMap::const_type VertexPointMap; VertexPointMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(vertex_point, tm)); + get_const_property_map(vertex_point, tm)); typedef typename GetGeomTraits::type Traits; - Traits traits = choose_parameter(get_parameter(np, internal_np::geom_traits), Traits()); + Traits traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); typename boost::graph_traits::halfedge_descriptor h = halfedge(f, tm); @@ -184,10 +184,10 @@ is_needle_triangle_face(typename boost::graph_traits::face_descrip typedef typename GetVertexPointMap::const_type VertexPointMap; VertexPointMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(vertex_point, tm)); + get_const_property_map(vertex_point, tm)); typedef typename GetGeomTraits::type Traits; - Traits traits = choose_parameter(get_parameter(np, internal_np::geom_traits), Traits()); + Traits traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); typedef typename Traits::FT FT; @@ -287,10 +287,10 @@ is_cap_triangle_face(typename boost::graph_traits::face_descriptor typedef typename GetVertexPointMap::const_type VertexPointMap; VertexPointMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(vertex_point, tm)); + get_const_property_map(vertex_point, tm)); typedef typename GetGeomTraits::type Traits; - Traits traits = choose_parameter(get_parameter(np, internal_np::geom_traits), Traits()); + Traits traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); typedef typename Traits::FT FT; typedef typename Traits::Vector_3 Vector_3; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smooth_mesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smooth_mesh.h index bbe02cfda6b..865d4332268 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smooth_mesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smooth_mesh.h @@ -150,10 +150,9 @@ void smooth_mesh(const FaceRange& faces, using parameters::get_parameter; // named parameters - GeomTraits gt = choose_parameter(get_parameter(np, internal_np::geom_traits), - GeomTraits()); + GeomTraits gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); VertexPointMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_property_map(CGAL::vertex_point, tmesh)); + get_property_map(CGAL::vertex_point, tmesh)); const bool use_angle_smoothing = choose_parameter(get_parameter(np, internal_np::use_angle_smoothing), true); bool use_area_smoothing = choose_parameter(get_parameter(np, internal_np::use_area_smoothing), true); @@ -173,7 +172,7 @@ void smooth_mesh(const FaceRange& faces, const bool use_Delaunay_flips = choose_parameter(get_parameter(np, internal_np::use_Delaunay_flips), true); VCMap vcmap = choose_parameter(get_parameter(np, internal_np::vertex_is_constrained), - get(Vertex_property_tag(), tmesh)); + get(Vertex_property_tag(), tmesh)); // If it's the default vcmap, manually set everything to false because the dynamic pmap has no default initialization if((std::is_same::value)) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smooth_shape.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smooth_shape.h index 63b8dd6e172..27f3a34a868 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smooth_shape.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smooth_shape.h @@ -97,11 +97,11 @@ void smooth_shape(const FaceRange& faces, using parameters::choose_parameter; using parameters::get_parameter; - GeomTraits gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GeomTraits()); + GeomTraits gt = choose_parameter(get_parameter(np, internal_np::geom_traits)); VertexPointMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_property_map(CGAL::vertex_point, tmesh)); + get_property_map(CGAL::vertex_point, tmesh)); VCMap vcmap = choose_parameter(get_parameter(np, internal_np::vertex_is_constrained), - Constant_property_map(false)); + Constant_property_map(false)); const unsigned int nb_iterations = choose_parameter(get_parameter(np, internal_np::number_of_iterations), 1); #if defined(CGAL_EIGEN3_ENABLED) @@ -132,7 +132,7 @@ void smooth_shape(const FaceRange& faces, typedef typename Sparse_solver::Matrix Eigen_matrix; typedef typename Sparse_solver::Vector Eigen_vector; - Sparse_solver solver = choose_parameter(get_parameter(np, internal_np::sparse_linear_solver), Default_solver()); + Sparse_solver solver = choose_parameter(get_parameter(np, internal_np::sparse_linear_solver)); std::size_t n = vertices(tmesh).size(); Eigen_matrix A(n, n); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/stitch_borders.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/stitch_borders.h index 6a2a519fca4..a19e0906c21 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/stitch_borders.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/stitch_borders.h @@ -185,10 +185,8 @@ collect_duplicated_stitchable_boundary_edges if(per_cc) { cc = get(Face_property_tag(), pmesh); - typedef typename GetFaceIndexMap::const_type FIMap; - FIMap fim = parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), - get_const_property_map(face_index, pmesh)); - num_component = num_component_wrapper(pmesh, cc, fim); + + num_component = num_component_wrapper(pmesh, cc, CGAL::get_initialized_face_index_map(pmesh, np)); border_edges_per_cc.resize(num_component); } @@ -606,7 +604,7 @@ std::size_t stitch_boundary_cycle(const typename boost::graph_traits::const_type VPMap; VPMap vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(vertex_point, pm)); + get_const_property_map(vertex_point, pm)); std::size_t stitched_boundary_cycles_n = 0; @@ -862,16 +860,18 @@ std::size_t stitch_borders(PolygonMesh& pmesh, /// @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 `PolygonMesh`.\cgalParamEnd -/// \cgalParamBegin{apply_per_connected_component} -/// specifies if the borders should only be stitched inside their own connected component. -/// In that case, a property map for `CGAL::face_index_t` should be either available as an internal property map -/// to `pmesh` or provided as the \ref pmp_namedparameters "Named Parameter" `face_index_map`. If this is not the case, -/// a default map will be created on the fly. -/// Default value is `false`.\cgalParamEnd -/// \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh` \cgalParamEnd +/// \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 `PolygonMesh`. +/// \cgalParamEnd +/// \cgalParamBegin{apply_per_connected_component} +/// specifies if the borders should only be stitched inside their own connected component. +/// Default value is `false`. +/// \cgalParamEnd +/// \cgalParamBegin{face_index_map} +/// a property map containing for each face of `pmesh` a unique index between `0` and `num_faces(pmesh)-1` +/// \cgalParamEnd /// \cgalNamedParamsEnd /// /// @return the number of pairs of halfedges that were stitched. @@ -892,7 +892,7 @@ std::size_t stitch_borders(PolygonMesh& pmesh, typedef typename GetVertexPointMap::const_type VPMap; VPMap vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(vertex_point, pmesh)); + get_const_property_map(vertex_point, pmesh)); #ifdef CGAL_PMP_STITCHING_DEBUG std::cout << "------- Stitch cycles..." << std::endl; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/triangulate_faces.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/triangulate_faces.h index 04407f132ba..8284c79d118 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/triangulate_faces.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/triangulate_faces.h @@ -431,7 +431,7 @@ bool triangulate_face(typename boost::graph_traits::face_descriptor //Kernel typedef typename GetGeomTraits::type Kernel; - Kernel traits = choose_parameter(get_parameter(np, internal_np::geom_traits), Kernel()); + Kernel traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); //Option bool use_cdt = choose_parameter(get_parameter(np, internal_np::use_delaunay_triangulation), true); @@ -486,7 +486,7 @@ bool triangulate_faces(FaceRange face_range, //Kernel typedef typename GetGeomTraits::type Kernel; - Kernel traits = choose_parameter(get_parameter(np, internal_np::geom_traits), Kernel()); + Kernel traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); //Option bool use_cdt = choose_parameter(get_parameter(np, internal_np::use_delaunay_triangulation), true); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/triangulate_hole.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/triangulate_hole.h index a6b59162a2e..8f354ed49fb 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/triangulate_hole.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/triangulate_hole.h @@ -89,6 +89,8 @@ namespace Polygon_mesh_processing { using parameters::choose_parameter; using parameters::get_parameter; + typedef typename GetGeomTraits::type GeomTraits; + bool use_dt3 = #ifdef CGAL_HOLE_FILLING_DO_NOT_USE_DT3 false; @@ -103,8 +105,7 @@ namespace Polygon_mesh_processing { out, choose_parameter(get_parameter(np, internal_np::vertex_point), get_property_map(vertex_point, pmesh)), use_dt3, - choose_parameter(get_parameter(np, internal_np::geom_traits), typename GetGeomTraits::type())) - .first; + choose_parameter(get_parameter(np, internal_np::geom_traits))).first; } template @@ -363,11 +364,11 @@ namespace Polygon_mesh_processing { typedef typename PointRange1::iterator InIterator; typedef typename std::iterator_traits::value_type Point; + typedef typename CGAL::Kernel_traits::Kernel Kernel; triangulate_hole_polyline(points, third_points, tracer, WC(), - use_dt3, - choose_parameter(get_parameter(np, internal_np::geom_traits), - typename CGAL::Kernel_traits::Kernel())); + use_dt3, + choose_parameter(get_parameter(np, internal_np::geom_traits))); CGAL_assertion(holes.empty()); return tracer.out; diff --git a/Polygon_mesh_processing/include/CGAL/Rigid_triangle_mesh_collision_detection.h b/Polygon_mesh_processing/include/CGAL/Rigid_triangle_mesh_collision_detection.h index ec20752cf83..7da366e8c09 100644 --- a/Polygon_mesh_processing/include/CGAL/Rigid_triangle_mesh_collision_detection.h +++ b/Polygon_mesh_processing/include/CGAL/Rigid_triangle_mesh_collision_detection.h @@ -225,7 +225,7 @@ public: Vpm vpm = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point), - get_const_property_map(boost::vertex_point, tm) ); + get_const_property_map(boost::vertex_point, tm) ); // now add the mesh std::size_t id = get_id_for_new_mesh(); CGAL_assertion( m_aabb_trees[id] == nullptr ); @@ -529,7 +529,7 @@ public: Vpm vpm = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point), - get_const_property_map(boost::vertex_point, tm) ); + get_const_property_map(boost::vertex_point, tm) ); if (maybe_several_cc) { @@ -537,11 +537,8 @@ public: std::vector cc_ids(num_faces(tm)); // face index map - typedef typename CGAL::GetFaceIndexMap::type Fid_map; - - Fid_map fid_map = - parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_index), - get_const_property_map(boost::face_index, tm)); + typedef typename GetInitializedFaceIndexMap::const_type FaceIndexMap; + FaceIndexMap fid_map = CGAL::get_initialized_face_index_map(tm, np); std::size_t nb_cc = Polygon_mesh_processing::connected_components( diff --git a/Polygon_mesh_processing/include/CGAL/polygon_mesh_processing.h b/Polygon_mesh_processing/include/CGAL/polygon_mesh_processing.h index 82f712fdc16..1de4072170b 100644 --- a/Polygon_mesh_processing/include/CGAL/polygon_mesh_processing.h +++ b/Polygon_mesh_processing/include/CGAL/polygon_mesh_processing.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index 02f55be25dd..6e480fbbdd2 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.1...3.15) project( Polygon_mesh_processing_Tests ) # CGAL and its components -find_package( CGAL QUIET COMPONENTS ) +find_package( CGAL QUIET COMPONENTS Core) if ( NOT CGAL_FOUND ) @@ -14,6 +14,8 @@ if ( NOT CGAL_FOUND ) endif() +include(${CGAL_USE_FILE}) + # Boost and its components find_package( Boost REQUIRED ) @@ -33,14 +35,16 @@ find_package(Eigen3 3.2.0) #(requires 3.2.0 or greater) find_package( TBB ) if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - # Creating entries for all .cpp/.C files with "main" routine # ########################################################## create_single_source_cgal_program("fairing_test.cpp") + CGAL_target_use_Eigen(fairing_test) create_single_source_cgal_program("triangulate_hole_Polyhedron_3_no_delaunay_test.cpp" ) + CGAL_target_use_Eigen(triangulate_hole_Polyhedron_3_no_delaunay_test) create_single_source_cgal_program("triangulate_hole_Polyhedron_3_test.cpp") + CGAL_target_use_Eigen(triangulate_hole_Polyhedron_3_test) create_single_source_cgal_program("test_shape_smoothing.cpp") + CGAL_target_use_Eigen(test_shape_smoothing) endif(EIGEN3_FOUND) @@ -99,6 +103,7 @@ endif() if( TBB_FOUND ) CGAL_target_use_TBB(test_pmp_distance) + CGAL_target_use_TBB(self_intersection_surface_mesh_test) else() message( STATUS "NOTICE: Intel TBB was not found. test_pmp_distance will use sequential code." ) endif() diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/connected_component_polyhedron.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/connected_component_polyhedron.cpp index ce954aa9789..35a7e3a75f0 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/connected_component_polyhedron.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/connected_component_polyhedron.cpp @@ -37,14 +37,27 @@ void mesh_with_id(const char* argv1, const bool save_output) std::cerr << cc.size() << " faces in the CC of " << &*fd << std::endl; boost::vector_property_map::type> - fccmap(get(boost::face_index,sm)); + boost::property_map::type> + fccmap(get(CGAL::face_index,sm)); std::size_t num = PMP::connected_components(sm, fccmap); if (strcmp(argv1, "data/blobby_3cc.off") == 0) assert(num == 3); std::cerr << "The graph has " << num << " connected components (face connectivity)" << std::endl; + std::size_t nb_faces = num_faces(sm); + std::vector faces_to_remove; // faces that would be removed but are not because we're doing a dry run + std::size_t nb_to_remove = PMP::keep_large_connected_components(sm, 1000, + CGAL::parameters::face_size_map( + CGAL::Constant_property_map(1)) + .dry_run(true) + .output_iterator(std::back_inserter(faces_to_remove))); + assert(!faces_to_remove.empty()); + if (strcmp(argv1, "data/blobby_3cc.off") == 0) + { + assert(nb_to_remove == 1); + assert(num_faces(sm) == nb_faces); + } PMP::keep_largest_connected_components(sm, 2, CGAL::parameters::face_size_map( @@ -71,17 +84,17 @@ void mesh_no_id(const char* argv1, const bool save_output) PMP::connected_component(fd, sm, std::back_inserter(cc)); std::cerr << cc.size() << " faces in the CC of " << &*fd << std::endl; - boost::property_map::type vim + boost::property_map::type vim = get(boost::vertex_external_index,sm); - boost::property_map::type fim + boost::property_map::type fim = get(boost::face_external_index,sm); boost::vector_property_map::type> fccmap(fim); - std::size_t num = PMP::connected_components(sm, fccmap, PMP::parameters::face_index_map(fim)); + std::size_t num = PMP::connected_components(sm, fccmap); if (strcmp(argv1, "data/blobby_3cc.off") == 0) assert(num == 3); @@ -91,8 +104,7 @@ void mesh_no_id(const char* argv1, const bool save_output) // std::cout << &*f << " in connected component " << fccmap[f] << std::endl; //} - PMP::keep_largest_connected_components(sm, 2, PMP::parameters::vertex_index_map(vim) - .face_index_map(fim)); + PMP::keep_largest_connected_components(sm, 2, PMP::parameters::vertex_index_map(vim)); if (save_output) return; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/connected_component_surface_mesh.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/connected_component_surface_mesh.cpp index 4092a5c2fb9..c22d400cda4 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/connected_component_surface_mesh.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/connected_component_surface_mesh.cpp @@ -161,8 +161,26 @@ void test_CC_with_area_size_map(Mesh sm, typedef boost::graph_traits::face_descriptor face_descriptor; Face_descriptor_area_functor f(sm, k); + std::vector faces_to_remove; // faces that would be removed but are not because we're doing a dry run + std::size_t nv = num_vertices(sm); + std::size_t num = PMP::internal::number_of_connected_components(sm); std::cout << "We keep the " << 2 << " largest components" << std::endl; + std::size_t res = PMP::keep_largest_connected_components(sm, 2, + PMP::parameters::face_size_map(CGAL::internal::boost_::make_function_property_map(f)) + .dry_run(true) + .output_iterator(std::back_inserter(faces_to_remove))); + + // didn't actually remove anything + assert(PMP::internal::number_of_connected_components(sm) == num); + assert(num_vertices(sm) == nv); + + if(num > 2) + { + assert(res == num - 2); + assert(!faces_to_remove.empty()); + } + PMP::keep_largest_connected_components(sm, 2, PMP::parameters::face_size_map( CGAL::internal::boost_::make_function_property_map(f))); @@ -183,6 +201,12 @@ void test_CC_with_area_size_map(Mesh sm, CGAL::parameters::face_size_map( CGAL::internal::boost_::make_function_property_map(f))); assert(vertices(m).size() == 3); + + PMP::keep_largest_connected_components(m, 1); + assert(PMP::internal::number_of_connected_components(m) == 1); + PMP::keep_largest_connected_components(m, 0); + assert(is_empty(m)); + assert(PMP::internal::number_of_connected_components(m) == 0); } } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data-clip/split_A.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data-clip/split_A.off new file mode 100644 index 00000000000..faf270e85f8 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data-clip/split_A.off @@ -0,0 +1,1512 @@ +OFF +530 980 0 +2.8486808788918765 2.5043163121807623 0 +2.5475286463854583 2.6188276403927899 0 +2.5510265470601881 2.3816052735350346 0 +0.8125 1.5550213675213673 0 +1.0020254629629628 1.3641922313797312 0 +1.0893994855366564 1.592974935873462 0 +1.1925065220090512 1.8151115711366583 0 +1.2930291957623206 1.4569209509645806 0 +1.5201006944080693 1.6856972520019426 0 +0.5446428571428571 0.54464285714285721 0 +0.8771239256512402 0.35896827173266904 0 +0.95724839114866822 0.62264098006762081 0 +1.8691630437000928 2.3892824195828677 0 +1.5586299649456712 2.4710078390863073 0 +1.7639521203744837 2.1779694267030822 0 +1.125 1.125 0 +1.5145581212946517 1.0184625019462896 0 +1.4486139867578269 1.2603369718073796 0 +0.64407296686733151 4.4995238325831322 0 +0.69441989836440043 4.7809809738883926 0 +0.43798153451522653 4.5756185438876074 0 +1.2288092040255898 5.273525645756405 0 +1.5803571428571428 5.3258928571428568 0 +1.3148866555594461 5.4856279015063762 0 +4.875 0.42439516129032262 0 +5.1306181160867661 0.65380674687542095 0 +4.8855189413832507 0.66978955282907049 0 +3.7153898486509025 0.89114304382715626 0 +3.4152754660102587 0.79710758331017084 0 +3.6176092608805002 0.61242500280090695 0 +2.6768606487577546 0.98231464716415562 0 +2.4091690730106867 1.0838528310682156 0 +2.320665131767655 0.88009034795436225 0 +4.3935630813088542 4.9195441669738029 0 +4.0728453809680438 4.7845165234836404 0 +4.3062517113692165 4.6941153599153047 0 +4.0145830917411676 5.5989185389216596 0 +3.9425822947521376 5.1891940982507121 0 +4.2129308160421601 5.3528743681354669 0 +4.7501268942863861 4.3438134471431935 0 +4.8130177311489755 3.9677363687196441 0 +4.9801820010716691 4.1889881246527336 0 +5.5632635388266793 3.8140270776533578 0 +5.3412188413301047 3.5689885832563615 0 +5.5861405375272142 3.5945135388266789 0 +5.0518361869124169 2.8909207951932414 0 +4.8207575763511183 2.9835230056549267 0 +4.7522300107475504 2.7778617204335907 0 +4.4203310387931163 4.1331443823965044 0 +4.2189403414295796 4.4686865528568065 0 +4.0905194676388978 4.1634010808128377 0 +2.721551512787618 2.8140642524709163 0 +2.5193505611520051 3.0809358271987541 0 +2.3564898837727535 2.7974487027174084 0 +2.8224841339642248 4.4913277277092858 0 +2.7451446589074111 4.8822419313373704 0 +2.5245109568185629 4.6354835677264958 0 +3.701427442033566 2.7727119800616817 0 +3.4501693490295069 2.5425134118142001 0 +3.7545593086017175 2.4624979892583112 0 +3.6091674756975678 1.3124208472459651 0 +3.3161764705882355 1.0955882352941178 0 +3.5175126919137787 0.99674284019169945 0 +4.5952849933178479 2.9273971777353065 0 +4.4481083951106246 2.7475999497268981 0 +4.937901885089369 2.6659754095424049 0 +1.5624595953442308 3.7661977967106379 0 +1.8671964830711714 3.7892354369530077 0 +1.5767672696902792 4.0389016407805549 0 +1.7267848286520362 3.1335728643263407 0 +2.0566352597802404 2.9277397402197591 0 +2.0173405474323838 3.2135847817849883 0 +2.591581488670601 4.3940834220111498 0 +2.528159645294386 4.1516991065592865 0 +2.7611219622593182 4.2202321867096053 0 +0.26837458261070074 0.63685370667558527 0 +0.52232142857142849 0.8348214285714286 0 +1.125 5.6134549432355723 0 +0.88820260757712477 5.3649363788898388 0 +3.2037843379675315 0.89258143306253601 0 +5.4726301280274416 1.6691869210990167 0 +5.1830797481752633 1.8882575926413225 0 +5.2032119269449622 1.613978930106402 0 +4.1578500269725112 0.81767095295055836 0 +4.2275215111463327 1.1230961387324576 0 +3.963359288525381 1.0249956984120794 0 +3.7018567389809158 4.1638675133867329 0 +3.9018178394257332 4.4224333812513112 0 +3.5346366942942455 4.4421579995565654 0 +3.4740126367024717 2.0699261579220254 0 +3.4071817807794265 2.3034494686378437 0 +3.2599637430186621 2.1349932347577196 0 +3.8532596907195464 4.9371375228307288 0 +4.1563033614258948 5.0346853146181223 0 +2.4984875619153772 1.3565288927111723 0 +2.25 1.5 0 +2.1490586095360271 1.2962479665668845 0 +2.4243507596839167 1.9077534820708062 0 +2.1304755083711222 1.999172179565972 0 +2.2159028778557444 1.7557314860707725 0 +2.7456285499246751 3.3838821021397898 0 +2.5500416712709231 3.7074928970804661 0 +2.4633635014612558 3.3587333546062967 0 +2.1999407445271171 3.7756512213396931 0 +2.0299973509443787 3.6127928493063712 0 +4.1357598895121237 0.52315264428142871 0 +3.8467529089166486 0.46229236592657674 0 +3.9375 0.2020290944667571 0 +2.3314566164630106 2.4714703514255945 0 +3.1503356452009239 2.697703245028094 0 +3.4000173898955759 2.8128585665966646 0 +5.0199977785149423 3.6475044429701158 0 +5.0933161181804119 3.3920318591678114 0 +5.2365989018546708 3.837313067484085 0 +2.1751148382733052 0.46071276219032947 0 +1.8772130357641226 0.43565984710740474 0 +2.0625 0.20596575200359124 0 +5.8044266230805706 3.9375 0 +5.625 4.3125 0 +5.5100355206340907 4.0736789587318176 0 +4.7617403719663702 3.7075874058207607 0 +4.5814386707720054 3.9667890714039196 0 +0 1.125 0 +0 0.75 0 +0.25 0.9375 0 +0.8125 0.8571428571428571 0 +6 4.875 0 +5.63671875 5.05078125 0 +5.6361860795454541 4.8148082386363633 0 +5.4375 4.6875 0 +5.71875 4.59375 0 +5.34375 5.34375 0 +5.294921875 5.001953125 0 +5.6156249999999996 5.6156249999999996 0 +5.7162623786726128 5.336567500655824 0 +1.5209517045454546 3.463423295454545 0 +1.1739357040886622 3.4636872214645544 0 +1.3473145185058597 3.2936987766512686 0 +1.8772507152609377 1.711198424621968 0 +1.8741731587389678 1.9692259428558145 0 +2.1115069827538266 2.3135587539133478 0 +3.7340486239852266 3.8602850349907252 0 +4.0383920379665259 3.8363324773944987 0 +3.8960288807892685 4.0309594737737591 0 +3.9507410846437594 0.68511743080021825 0 +2.3241733267046736 0.65796473099729624 0 +2.5636733416770965 0.71933667083854835 0 +0.96875 5.03125 0 +0.64724582278873588 5.1249730596288376 0 +5.1959071203296006 0.33007750644708866 0 +5.445148141654979 0.55313829005112436 0 +4.5498162352189198 2.3516299137104504 0 +4.8439397571108982 2.0516389022051773 0 +4.8617386210911269 2.3632705429250094 0 +6 1.5 0 +6 1.875 0 +5.7201304783786249 1.8135644054471147 0 +0.18814810503268317 2.8125 0 +0 2.625 0 +0.24608002923971012 2.5662186054712324 0 +0.87026515151515171 3.6316287878787876 0 +0.6540113488019127 3.8407323196951957 0 +0.63673929879123614 3.4930335387486746 0 +0.36929533772556877 3.7436406761680248 0 +0 3.75 0 +0.19608815989052669 3.5478595301185054 0 +2.1935194954050821 4.6317994150809625 0 +2.4276964946318431 4.9440647738441825 0 +6 0.375 0 +6 0.75 0 +5.7541758469226743 0.5625 0 +5.03125 0.96875 0 +0 5.625 0 +0 5.25 0 +0.24582415307732569 5.4375 0 +0.8066140242673685 5.6797507064495045 0 +3.375 6 0 +3.1875 5.8122182235829865 0 +3.5625 5.8045965324474684 0 +3.0114909002971655 5.613625569196862 0 +3.1950251882373371 5.2734309091588436 0 +3.3043494029140681 5.5520165949799125 0 +1.1162169187394466 2.1011800714689106 0 +1.3464303603136556 2.0093672606590625 0 +1.4694040418586791 5.6545097296823021 0 +1.7064759346739216 5.5515145370118422 0 +3.3782130927641938 4.9031250938870095 0 +3.5901837833439698 5.1846806101754161 0 +2.25 5.2142857142857144 0 +2.6225354298310588 5.0985960359512212 0 +2.12639693023183 4.1004505160196416 0 +2.3459822857345278 3.9794450419944631 0 +0.26405865027226982 4.1605774892178804 0 +0.48980655866005129 4.0927775162383933 0 +0.55731321408031953 4.2998017292061981 0 +0.7651723094668359 3.253768144801553 0 +1.0065388203710688 3.2867092739718369 0 +1.7263368776823338 3.6254802080150279 0 +4.9196428571428568 1.6383928571428572 0 +3.9360780518081273 1.6378359373269351 0 +3.9736207782170272 1.3065983938544377 0 +4.2855652862754638 1.4309428213289239 0 +4.1690835404790825 2.4253851380234743 0 +4.2049382670370665 2.0871410330664428 0 +4.3369097342695255 2.2721527389064931 0 +5.2142857142857144 2.25 0 +2.7741755961166694 3.1265801925364327 0 +3.9404820837997914 3.5444944043435904 0 +4.041666666666667 2.7916666666666665 0 +3.8571133246200784 3.0412767519381942 0 +3.1597886725526778 2.3602202461105048 0 +3.7937017264994148 1.4539525585118738 0 +3.7498766597953774 1.1238691931858937 0 +3.6050161260140277 1.6768970151590978 0 +3.0644156312283748 4.8097193808095158 0 +3.0054061064237967 5.0765896639090631 0 +3.3667608881164761 3.8891914618875614 0 +3.300530569898859 4.2070530052175634 0 +3.0203644238666199 3.8992523585011294 0 +0 1.875 0 +0 1.5 0 +0.20109245672461662 1.6875 0 +0.36657329931145871 1.4679310657486115 0 +0.6229745370370372 1.3641922313797312 0 +0.57125379323017711 1.6050895545044788 0 +1.2567073428908708 0.84110728922359934 0 +1.4785097839092358 0.65500541548837865 0 +1.7495961849530872 1.1442297501101726 0 +1.8598489664508855 0.9407302021576216 0 +2.0143398975139459 1.1130679347183192 0 +4.875 6 0 +4.6430027050094624 5.6978257245979504 0 +4.8535318026513208 5.7515521822523752 0 +4.5274177950050305 5.3841392650016768 0 +4.7285161654511469 5.488178171141711 0 +5.25 6 0 +5.0625 5.81106122108541 0 +3.1236976871625619 0.29190952625957928 0 +3.375 0.48519542045005926 0 +3.0249507312159922 0.51486244453274865 0 +2.8199681453324263 0.38279767042654395 0 +2.6113889690124217 2.1521645084936276 0 +2.8058816673469309 1.9777365059782417 0 +2.7665540872168641 1.2542040908979364 0 +4.0538591263235721 3.2813938488760717 0 +4.2263146355994143 3.5638853401248234 0 +4.2951599951837238 3.2347099734179356 0 +4.5182187464899499 1.9574316462498531 0 +3.8755413216224803 2.1719483930434595 0 +4.5362290613295801 1.2303685340311203 0 +0.27941238576091793 5.1385683681551981 0 +0.42439516129032256 4.875 0 +5.3732969083833542 0.87034060307917471 0 +5.2194497995682436 1.3394421915145882 0 +5.2513506851119658 1.090125709849642 0 +5.4441246281201501 1.429004459429049 0 +4.650761711528272 0.48786240354584109 0 +4.3602183909275043 0.68284963033680013 0 +4.4212427017226092 0.44746531213967311 0 +1.0415984273838255 4.3228484273838257 0 +0.95887950220850904 4.6722885001953305 0 +0.84701711025942017 4.420594446776442 0 +1.3909207591302153 4.2389845501665153 0 +1.2855693327030244 3.8955310332120208 0 +1.4405734661053811 4.7218234661053815 0 +1.5833272087817321 4.4780685577805119 0 +1.6786187133866248 4.7719997721591652 0 +2.1384392742705454 4.9473868935960983 0 +5.3629111671816645 2.0549615134629917 0 +5.5011918318620738 1.8858002112433634 0 +5.25 4.125 0 +5.0445349092867469 3.9665915925538537 0 +4.5316805184277147 4.6068039899756679 0 +4.8045999383541789 4.6112788117664385 0 +2.8073716231483017 5.2649622082277672 0 +2.298177083333333 5.6705813717532463 0 +2.625 5.6071428571428577 0 +2.53125 5.8035714285714288 0 +0.39217631978105333 3.375 0 +0.623774457496725 3.0566402008920055 0 +5.1266741071428568 3.1283482142857144 0 +5.3461938492013221 3.2940159317687412 0 +6 3.375 0 +5.804508768113875 3.5625 0 +5.804508768113875 3.195294135081634 0 +2.9856681388206252 4.1277809087722073 0 +3.1036431267833593 4.3241339392994913 0 +3.7361128506885102 4.6967468768514067 0 +3.4224393827962487 4.6611089751910342 0 +3.6547619047619051 3.5654761904761902 0 +3.7014130953224291 3.2823289211714943 0 +3.5191831954913391 3.0606512874260687 0 +3.469674416289017 3.371546740619507 0 +4.25 1.75 0 +0.76800518889031932 2.8615754041360661 0 +1.2566577454080283 2.3618171076975001 0 +1.4791383738904771 2.2186909431289177 0 +0.31628749077049334 2.135081684016042 0 +0.45007949344498027 1.8263039384014434 0 +0.57653339949828097 2.1952912290782165 0 +3.7642360721058963 5.354565570314902 0 +4.3162425042949604 5.7281126859006726 0 +1.1768505743358493 4.1167641643398349 0 +0 3.375 0 +0 3 0 +0.19608815989052664 3.1875 0 +0.4638922275641027 2.4375 0 +0.51643108105936664 2.7209037846255137 0 +0.23630657181984216 1.9170517049727196 0 +0.8549199714190221 2.4781666255747341 0 +1.1461510770699521 2.731999318304672 0 +1.8568389981184201 3.4533569963423587 0 +1.8411086509276826 2.7009143200649368 0 +2.0763733598790743 2.5650150858722065 0 +3.0931867709236607 1.3069061007373635 0 +2.8607416552522578 1.5192749482135823 0 +2.6774843723381134 1.7327008736055054 0 +2.9679562332347205 1.7728356205257128 0 +2.3341045543347829 2.1914318548911833 0 +3 3 0 +2.9253192327280648 2.7167335970249051 0 +5.3403108669307837 2.5112559625350972 0 +5.2816970834093331 2.7953359538063123 0 +5.0895030007196373 2.466897092784766 0 +4.6286588968463116 4.8365020995860029 0 +4.2688178470975897 2.9903504334472952 0 +1.0057043401329289 2.9386947214760744 0 +2.5203177631539528 5.3316609663400589 0 +2.1154149430120146 5.4140747562628961 0 +1.875 6 0 +1.9713541666666663 5.6071428571428577 0 +2.1015359268707483 5.810055070797258 0 +5.2886718749999995 5.6707031250000002 0 +4.9450105158464046 5.5544717970331465 0 +2.7703116411199131 3.673371744379077 0 +3.0614876385336744 2.0317561807331632 0 +5.1095902602669154 5.2028152306761548 0 +5.1333761532893432 5.4282883207526469 0 +1.5451495907400812 5.0158321018192327 0 +1.8491692562395028 4.9454809347532063 0 +1.7272522892942421 5.1521835454736742 0 +2.0007373571017935 4.7607530765533062 0 +2.7892480652398124 3.8954629970670158 0 +2.5644592082117943 3.9308451884283389 0 +1.8839918989066573 4.0387942615494596 0 +0.96062129092331561 1.7877460991517338 0 +3.6032343924818324 5.5368663055385712 0 +3.7886718821083756 5.7020440165488351 0 +4.4208196655128607 0.91834321683073017 0 +4.2392548153795166 3.9720077130054943 0 +4.125 0 0 +4.3125 0.19766217173385192 0 +3.2198275862068964 4.5215517241379306 0 +2.2988964857201388 4.3485736103214165 0 +0.729666337739866 1.8220890613517717 0 +3.3627859868388281 3.5956839716117739 0 +3.1897458784300174 3.7628103369594781 0 +2.9931786382657397 3.6697091957925521 0 +1.5416666666666667 2.7916666666666665 0 +2.7855026071719533 0.77970725504876803 0 +3.014417665538299 0.75847693425506735 0 +3.0099614685648812 1.0660783086701517 0 +2.4843623622075257 0.31268000236296645 0 +2.1166021608985246 0.79228145853912257 0 +2.6803450446201849 0.21286126505274977 0 +2.625 0 0 +6 3.75 0 +6 4.5 0 +6 4.125 0 +5.625 6 0 +5.8033482142857142 5.8033482142857142 0 +6 5.625 0 +4.5 6 0 +4.8787338860542837 1.279302629417036 0 +5.575604838709677 1.125 0 +5.685989339673454 1.4277239423275883 0 +3.3248590262633071 1.8018632013008169 0 +0.5 1.125 0 +1.125 0 0 +1.5 0 0 +1.3134791738345228 0.24132411048958213 0 +4.8369819428785732 5.2222599782170285 0 +5.0802314915337483 4.9541201145422162 0 +3.2237460556110134 3.3371683159691745 0 +2.9910498711591882 3.2487628208235857 0 +4.7349944063383242 1.8181239575429744 0 +4.7637311357785226 1.4742795643545414 0 +4.5667610456228562 1.5858341308799953 0 +3.75 0 0 +6 5.25 0 +3.6169221521918544 4.9035699663657066 0 +5.6071428571428568 2.625 0 +5.4726303874961628 2.2933944077710824 0 +2.0126271736422114 4.3625528011399393 0 +1.75 4.25 0 +6 0 0 +5.8125 0 0 +5.6074691085968826 0.30010825325938173 0 +0.39253089140311737 5.6998917467406187 0 +0 5.8125 0 +0.39313071559063012 2.9814322017740804 0 +0.82051282051282048 2.0865384615384612 0 +1.1810517043295179 3.1167440895674963 0 +1.3275136317613345 2.8705117462011649 0 +1.6875 0 0 +1.875 0 0 +1.78125 0.21831176935135141 0 +1.7875730183583651 0.72085767278612178 0 +1.5826119573518038 0.38483330787177289 0 +1.2170284895979453 0.53067616319931521 0 +0.375 0 0 +0.30709251369039114 0.34818794476844345 0 +0.1875 0 0 +0.60086898992005056 0.25480657465369588 0 +5.34375 4.40625 0 +1.6172294710267177 1.9930505701329313 0 +1.6599126855671806 1.3952619432984579 0 +1.4559540366064896 3.0591413603373829 0 +1.7396514067626401 2.9055391849955239 0 +3.2544967072437294 3.073938593144653 0 +3 6 0 +2.8125 5.8035714285714288 0 +6 2.625 0 +6 3 0 +5.8035714285714279 2.8037244048451413 0 +1.6875 5.8092954633416971 0 +2.25 6 0 +0.9375 6 0 +0.75 6 0 +0.99554231531315773 5.7894068753208758 0 +1.3125 6 0 +1.125 6 0 +1.2801608109298375 5.7769391536769827 0 +5.6246336516460804 2.999958623445603 0 +2.625 6 0 +6 2.25 0 +5.7209459527497026 2.3509399777105733 0 +6 2.0625 0 +5.0625 0 0 +5.25 0 0 +4.9896626205160981 0.22143688567127601 0 +4.5 0 0 +5.7205876142390819 0.86143163184480231 0 +3 0 0 +1.0768865140309449 0.23184278027051047 0 +0.75 0 0 +0.25 1.2251528540697914 0 +0 4.5 0 +0.32195464522250283 4.3890660190092028 0 +0.23557785887594232 4.661040061464627 0 +4.5 3.75 0 +0 4.125 0 +0.1879312026484084 3.9375 0 +0.93957255214797974 3.9812935874921038 0 +1.0716714134186609 3.7734089999752505 0 +1.2150125513419341 4.5484093421472727 0 +1.2550737966006709 4.9534066583863519 0 +1.8419445047331062 4.5917003342137379 0 +4.5255165590109883 3.1490283123570637 0 +4.5044549784904824 3.4491616076730165 0 +4.6980170086786508 2.5653984855658685 0 +4.3790092681171364 2.4894752285116319 0 +3.8792725670152164 2.6435153112929046 0 +4.2322035942604197 2.6526452163973393 0 +5.3697425548990863 3.0374594273589133 0 +4.7666744743980285 1.0315413515081673 0 +3.3401750124248357 1.3695262647808701 0 +3.3549663624069979 1.5864900243949778 0 +4.875 4.875 0 +4.584384813747528 5.1161464487676591 0 +3.7221978210530042 1.9343031730300799 0 +4.0225566578644294 1.8911822417370203 0 +1.5 6 0 +4.505689073686364 4.3629961382215576 0 +3.4447672838159145 5.3664038202569397 0 +2.1927083333333335 3.442708333333333 0 +1.3400467912826461 3.6510975461536148 0 +5.1985855615748902 4.7687225100619068 0 +5.4375 6 0 +2.3789628428106471 3.5648606361904625 0 +2.4375 6 0 +2.25 0 0 +3.5598944977519267 3.9953157849090219 0 +5.6090175362277499 3.375 0 +2.2560633372915508 3.1007782500781507 0 +4.8329701851364524 3.3385359233091245 0 +4.125 6 0 +3.6430962161274061 2.2456231844279153 0 +0.8125 1.1733630952380951 0 +1.033982964920978 0.83193064656032434 0 +0.26397089209591124 2.3478471564087711 0 +3.375 0 0 +3.6011030653209328 0.27243341947785382 0 +3.3607560112102535 0.24186420209387777 0 +3.2122614756061783 0.64499607881104337 0 +1.3650724475166021 2.6215464818513077 0 +3.1394433019240151 1.5574750727280944 0 +2.4730101229318815 1.5993247244857371 0 +0.55485185834502104 5.4468617099488759 0 +0.60538420136153093 5.8093058675066125 0 +3.5252947989871397 3.7402638145969345 0 +1.9595279088775039 1.4218750693147353 0 +0.76025735747240808 4.2208723433995079 0 +1.9806771266785792 0.62486566951580402 0 +5.0781567235715963 4.5469701707147898 0 +0 4.875 0 +0.21219758064516128 4.871967470907328 0 +6 1.125 0 +6 1.3125 0 +5.7876118043694511 1.2191814457464947 0 +0 0.375 0 +5.625 0 0 +5.4375 0 0 +0.375 6 0 +1.9189292412731747 5.2747113181924501 0 +4.875 0 0 +4.6389283067137388 0.25511603647055087 0 +5.6071428571428577 2.0768799554211461 0 +4.6655695481684196 0.77911164552274448 0 +0.95956178702399419 2.271647611832198 0 +2.2718184342235856 0.26569838191880579 0 +4.3855416802146578 5.2139296477436234 0 +0 4.3125 0 +6 6 0 +2.9210733349820464 2.2527201967314192 0 +3.75 6 0 +3.9375 6 0 +0 6 0 +0 0 0 +0 2.25 0 +3 0 1 2 +3 3 4 5 +3 6 7 8 +3 9 10 11 +3 12 13 14 +3 15 16 17 +3 18 19 20 +3 21 22 23 +3 24 25 26 +3 27 28 29 +3 30 31 32 +3 33 34 35 +3 36 37 38 +3 39 40 41 +3 42 43 44 +3 45 46 47 +3 48 49 50 +3 51 52 53 +3 54 55 56 +3 57 58 59 +3 60 61 62 +3 63 64 47 +3 65 45 47 +3 66 67 68 +3 69 70 71 +3 72 73 74 +3 75 9 76 +3 21 77 78 +3 28 61 79 +3 80 81 82 +3 83 84 85 +3 86 87 88 +3 89 90 91 +3 37 92 93 +3 94 95 96 +3 97 98 99 +3 100 101 102 +3 103 67 104 +3 105 106 107 +3 51 53 1 +3 1 108 2 +3 109 58 110 +3 43 111 112 +3 111 43 113 +3 114 115 116 +3 117 118 119 +3 120 40 121 +3 122 123 124 +3 125 9 11 +3 126 127 128 +3 129 118 130 +3 127 131 132 +3 133 131 134 +3 135 136 137 +3 138 98 139 +3 140 12 14 +3 34 49 35 +3 141 142 143 +3 27 29 144 +3 145 146 32 +3 147 78 148 +3 147 21 78 +3 149 150 25 +3 151 152 153 +3 154 155 156 +3 157 158 159 +3 160 161 162 +3 163 164 165 +3 166 56 167 +3 168 169 170 +3 25 171 26 +3 172 173 174 +3 78 77 175 +3 176 177 178 +3 179 180 181 +3 43 42 113 +3 182 6 183 +3 184 22 185 +3 180 186 187 +3 188 167 189 +3 190 103 191 +3 192 193 194 +3 195 160 162 +3 136 160 196 +3 67 66 197 +3 77 21 23 +3 81 198 82 +3 199 200 201 +3 202 203 204 +3 152 205 153 +3 100 52 206 +3 142 141 207 +3 57 208 209 +3 210 58 109 +3 211 60 212 +3 199 213 211 +3 55 214 215 +3 216 217 218 +3 219 220 221 +3 222 223 224 +3 16 225 226 +3 15 7 4 +3 227 16 228 +3 229 227 228 +3 230 231 232 +3 231 233 234 +3 235 230 236 +3 237 238 239 +3 240 237 239 +3 241 97 242 +3 31 243 94 +3 244 245 207 +3 245 244 246 +3 152 151 247 +3 248 202 59 +3 249 201 84 +3 83 85 144 +3 250 251 148 +3 148 251 19 +3 171 25 252 +3 253 254 255 +3 24 26 256 +3 257 258 256 +3 259 260 261 +3 262 263 68 +3 264 265 266 +3 166 167 267 +3 268 81 269 +3 270 41 271 +3 272 39 273 +3 180 179 274 +3 275 276 277 +3 195 278 279 +3 278 195 162 +3 280 281 112 +3 282 283 284 +3 285 217 286 +3 86 141 143 +3 37 187 92 +3 88 287 288 +3 207 289 290 +3 291 290 292 +3 201 200 84 +3 293 199 201 +3 4 7 5 +3 223 3 224 +3 294 195 279 +3 13 295 296 +3 297 298 299 +3 222 298 221 +3 113 42 119 +3 111 40 120 +3 187 37 300 +3 233 301 38 +3 66 135 197 +3 263 262 302 +3 303 304 305 +3 306 307 159 +3 298 297 308 +3 294 309 310 +3 135 69 311 +3 70 312 313 +3 243 314 315 +3 316 315 317 +3 53 108 1 +3 97 241 318 +3 109 319 320 +3 0 109 320 +3 321 322 323 +3 46 63 47 +3 272 273 324 +3 33 272 324 +3 244 209 325 +3 291 57 209 +3 294 310 326 +3 309 295 310 +3 188 327 328 +3 329 330 331 +3 332 235 236 +3 333 332 236 +3 52 100 102 +3 101 100 334 +3 200 199 211 +3 317 335 242 +3 131 133 332 +3 336 131 337 +3 338 339 340 +3 339 266 341 +3 101 342 343 +3 67 103 344 +3 295 182 183 +3 6 182 345 +3 179 276 274 +3 177 181 178 +3 37 36 300 +3 178 346 347 +3 84 83 348 +3 31 94 96 +3 229 31 96 +3 245 142 207 +3 50 142 349 +3 107 350 351 +3 258 105 351 +3 85 27 144 +3 84 200 85 +3 217 352 286 +3 353 73 72 +3 298 222 224 +3 298 354 299 +3 355 216 356 +3 357 355 356 +3 108 53 313 +3 358 13 312 +3 30 146 359 +3 360 361 359 +3 361 30 359 +3 240 146 362 +3 363 114 145 +3 240 362 364 +3 362 365 364 +3 282 366 283 +3 367 118 368 +3 270 113 119 +3 369 133 370 +3 133 371 370 +3 103 190 344 +3 103 101 191 +3 230 372 231 +3 231 372 301 +3 18 20 194 +3 260 18 261 +3 253 198 373 +3 374 375 255 +3 210 335 91 +3 213 89 376 +3 16 15 225 +3 222 377 223 +3 378 379 380 +3 336 381 382 +3 132 131 336 +3 98 97 318 +3 316 317 242 +3 357 383 355 +3 206 319 384 +3 198 385 386 +3 205 81 268 +3 24 149 25 +3 387 249 386 +3 105 107 351 +3 388 350 107 +3 209 208 325 +3 203 247 204 +3 389 127 126 +3 74 73 343 +3 54 56 72 +3 214 186 215 +3 187 186 390 +3 391 321 392 +3 205 321 323 +3 353 166 393 +3 262 394 265 +3 395 168 396 +3 168 170 397 +3 172 398 399 +3 172 174 398 +3 307 157 159 +3 278 400 279 +3 307 400 157 +3 354 401 299 +3 402 326 403 +3 402 137 196 +3 404 405 406 +3 407 408 115 +3 225 409 226 +3 407 16 226 +3 48 50 349 +3 39 48 121 +3 410 411 412 +3 410 413 411 +3 413 9 411 +3 118 129 414 +3 132 336 382 +3 415 138 139 +3 7 416 8 +3 363 145 32 +3 361 243 30 +3 13 12 312 +3 137 136 196 +3 402 417 137 +3 70 69 418 +3 100 206 384 +3 419 383 384 +3 179 181 177 +3 420 421 177 +3 391 322 321 +3 422 423 424 +3 425 184 185 +3 426 329 331 +3 427 428 429 +3 430 431 432 +3 433 423 284 +3 423 282 284 +3 274 276 327 +3 420 434 421 +3 80 375 156 +3 375 154 156 +3 391 422 424 +3 435 436 437 +3 438 439 440 +3 350 441 351 +3 254 374 255 +3 170 169 442 +3 28 238 29 +3 240 443 237 +3 380 409 444 +3 410 445 413 +3 220 122 446 +3 220 222 221 +3 164 303 165 +3 278 163 165 +3 193 163 161 +3 447 448 449 +3 19 251 20 +3 174 173 250 +3 368 118 117 +3 366 368 117 +3 367 126 130 +3 118 367 130 +3 40 39 121 +3 450 120 121 +3 56 55 167 +3 167 55 189 +3 451 164 452 +3 164 163 452 +3 389 371 134 +3 371 133 134 +3 263 453 454 +3 262 259 302 +3 259 262 455 +3 260 259 455 +3 264 456 455 +3 21 147 456 +3 409 10 444 +3 378 380 444 +3 222 220 446 +3 377 222 446 +3 166 457 393 +3 190 353 393 +3 458 459 246 +3 280 46 45 +3 151 460 461 +3 208 462 463 +3 391 433 322 +3 281 280 464 +3 287 34 92 +3 49 34 87 +3 7 15 17 +3 416 7 17 +3 171 465 26 +3 171 373 465 +3 466 60 467 +3 61 60 466 +3 273 468 324 +3 468 381 469 +3 202 248 203 +3 470 199 471 +3 329 472 425 +3 472 184 425 +3 205 152 81 +3 152 198 81 +3 22 21 338 +3 22 338 340 +3 293 387 247 +3 203 293 247 +3 272 49 473 +3 39 272 473 +3 167 188 267 +3 275 330 328 +3 92 34 93 +3 346 181 474 +3 311 69 71 +3 475 311 71 +3 263 66 68 +3 66 263 476 +3 16 407 228 +3 405 116 406 +3 247 387 385 +3 152 247 385 +3 0 51 1 +3 0 210 109 +3 381 468 382 +3 129 132 477 +3 235 332 478 +3 475 103 104 +3 102 101 479 +3 50 49 87 +3 142 50 143 +3 426 275 480 +3 405 481 116 +3 481 365 362 +3 141 86 482 +3 352 88 288 +3 213 199 470 +3 89 213 470 +3 281 43 112 +3 483 43 281 +3 459 245 246 +3 450 245 459 +3 267 339 341 +3 166 267 341 +3 451 452 192 +3 163 193 452 +3 90 210 91 +3 58 210 90 +3 291 419 110 +3 319 419 384 +3 59 202 462 +3 57 59 462 +3 274 327 189 +3 327 188 189 +3 34 287 87 +3 87 287 88 +3 71 70 484 +3 53 70 313 +3 280 485 46 +3 485 458 46 +3 55 54 214 +3 54 352 214 +3 301 36 38 +3 233 231 301 +3 372 486 301 +3 486 36 301 +3 416 138 8 +3 138 415 8 +3 59 58 487 +3 248 59 487 +3 411 9 75 +3 377 124 76 +3 377 125 488 +3 225 15 489 +3 322 65 323 +3 64 463 461 +3 338 21 456 +3 264 338 456 +3 209 244 290 +3 291 209 290 +3 306 297 299 +3 159 158 490 +3 34 33 93 +3 381 233 469 +3 443 491 237 +3 492 238 493 +3 238 28 494 +3 28 79 494 +3 491 492 493 +3 491 388 492 +3 310 295 495 +3 295 13 495 +3 315 496 317 +3 376 496 467 +3 315 316 497 +3 316 97 497 +3 100 357 334 +3 217 285 218 +3 498 78 175 +3 78 498 148 +3 398 498 499 +3 174 498 398 +3 460 64 461 +3 46 458 63 +3 458 485 459 +3 450 459 120 +3 379 408 380 +3 408 409 380 +3 409 225 489 +3 10 409 11 +3 352 217 88 +3 217 86 88 +3 216 500 482 +3 289 141 500 +3 98 138 99 +3 138 416 501 +3 160 453 161 +3 193 161 502 +3 161 453 502 +3 453 259 502 +3 115 114 503 +3 407 115 503 +3 187 300 474 +3 300 346 474 +3 249 387 201 +3 387 293 201 +3 373 249 465 +3 249 84 348 +3 468 504 477 +3 270 414 41 +3 130 126 128 +3 129 130 128 +3 136 135 476 +3 135 66 476 +3 498 250 148 +3 498 174 250 +3 173 505 250 +3 449 251 506 +3 25 150 252 +3 150 170 442 +3 169 507 442 +3 507 508 509 +3 260 147 19 +3 147 148 19 +3 150 149 397 +3 170 150 397 +3 252 374 254 +3 171 252 254 +3 150 442 252 +3 442 374 252 +3 56 353 72 +3 56 166 353 +3 445 10 413 +3 10 9 413 +3 123 510 75 +3 510 411 75 +3 124 75 76 +3 124 123 75 +3 9 125 76 +3 125 377 76 +3 511 397 512 +3 428 513 499 +3 513 398 499 +3 188 514 267 +3 514 339 267 +3 147 260 456 +3 456 260 455 +3 348 83 257 +3 29 106 144 +3 496 466 467 +3 466 496 314 +3 243 31 30 +3 146 30 32 +3 97 316 242 +3 95 94 497 +3 251 449 20 +3 18 260 19 +3 141 289 207 +3 244 207 290 +3 290 289 292 +3 500 141 482 +3 312 70 418 +3 358 312 418 +3 457 394 393 +3 190 393 344 +3 154 375 508 +3 441 515 516 +3 515 438 440 +3 505 449 506 +3 505 447 449 +3 436 517 437 +3 81 80 269 +3 131 127 134 +3 127 389 134 +3 394 457 265 +3 265 457 266 +3 262 265 455 +3 265 264 455 +3 203 248 471 +3 248 470 471 +3 113 270 271 +3 41 40 271 +3 52 102 484 +3 475 102 479 +3 85 200 212 +3 27 85 212 +3 383 419 292 +3 419 291 292 +3 409 408 226 +3 408 407 226 +3 276 275 327 +3 327 275 328 +3 518 257 256 +3 518 348 257 +3 475 71 484 +3 102 475 484 +3 182 295 519 +3 401 182 519 +3 198 253 82 +3 375 80 255 +3 116 481 520 +3 114 116 520 +3 517 436 392 +3 436 391 392 +3 306 309 307 +3 309 294 307 +3 435 422 436 +3 422 391 436 +3 221 298 308 +3 219 221 308 +3 238 492 29 +3 492 106 29 +3 417 402 403 +3 358 417 403 +3 414 504 41 +3 504 39 41 +3 39 504 273 +3 504 468 273 +3 249 348 465 +3 348 518 465 +3 276 179 421 +3 421 179 177 +3 400 305 157 +3 400 278 305 +3 161 163 162 +3 163 278 162 +3 433 281 464 +3 433 483 281 +3 42 117 119 +3 43 483 44 +3 312 12 313 +3 318 108 140 +3 106 492 107 +3 492 388 107 +3 33 469 521 +3 93 33 521 +3 441 516 351 +3 516 258 351 +3 42 283 117 +3 283 366 117 +3 92 187 390 +3 287 92 390 +3 330 425 185 +3 330 329 425 +3 7 6 5 +3 5 6 345 +3 377 488 223 +3 3 223 4 +3 223 488 4 +3 488 15 4 +3 451 192 522 +3 305 304 157 +3 304 158 157 +3 283 483 284 +3 483 433 284 +3 423 433 424 +3 433 391 424 +3 181 346 178 +3 176 420 177 +3 371 523 370 +3 523 369 370 +3 459 485 120 +3 485 111 120 +3 111 485 112 +3 485 280 112 +3 361 61 314 +3 61 466 314 +3 236 230 232 +3 333 236 232 +3 38 93 521 +3 38 37 93 +3 199 293 471 +3 293 203 471 +3 186 180 215 +3 180 274 215 +3 319 109 419 +3 419 109 110 +3 58 57 110 +3 57 291 110 +3 303 305 165 +3 305 278 165 +3 333 381 337 +3 381 336 337 +3 11 409 489 +3 125 11 489 +3 70 53 484 +3 53 52 484 +3 241 524 2 +3 524 0 2 +3 393 394 344 +3 394 262 68 +3 335 210 524 +3 210 0 524 +3 525 178 347 +3 525 176 178 +3 296 295 183 +3 415 296 183 +3 139 140 14 +3 139 98 140 +3 138 501 99 +3 501 95 99 +3 98 318 140 +3 415 139 14 +3 385 387 386 +3 198 152 385 +3 321 205 392 +3 517 268 269 +3 229 501 227 +3 501 416 227 +3 314 496 315 +3 243 361 314 +3 295 309 519 +3 309 306 299 +3 108 313 140 +3 313 12 140 +3 504 414 477 +3 414 129 477 +3 65 322 45 +3 322 433 464 +3 118 414 119 +3 414 270 119 +3 122 124 446 +3 124 377 446 +3 297 306 490 +3 306 159 490 +3 151 153 460 +3 153 65 460 +3 65 153 323 +3 153 205 323 +3 73 353 191 +3 353 190 191 +3 322 464 45 +3 464 280 45 +3 55 215 189 +3 215 274 189 +3 525 347 526 +3 22 514 185 +3 514 330 185 +3 6 8 183 +3 8 415 183 +3 168 397 396 +3 397 511 396 +3 398 513 399 +3 513 527 399 +3 94 315 497 +3 94 243 315 +3 496 376 317 +3 376 335 317 +3 335 524 242 +3 524 241 242 +3 253 373 254 +3 373 171 254 +3 453 160 454 +3 160 136 454 +3 136 476 454 +3 476 263 454 +3 259 453 302 +3 453 263 302 +3 16 227 17 +3 227 416 17 +3 244 325 246 +3 325 458 246 +3 354 3 345 +3 3 5 345 +3 13 358 495 +3 326 310 403 +3 184 472 432 +3 472 430 432 +3 52 51 206 +3 51 319 206 +3 383 357 384 +3 357 100 384 +3 186 214 288 +3 214 352 288 +3 97 99 497 +3 99 95 497 +3 49 48 473 +3 48 39 473 +3 36 347 300 +3 347 346 300 +3 417 69 137 +3 69 135 137 +3 160 195 196 +3 195 294 326 +3 352 54 286 +3 54 72 74 +3 142 245 349 +3 245 450 349 +3 49 272 35 +3 272 33 35 +3 468 469 324 +3 469 33 324 +3 408 379 406 +3 379 404 406 +3 89 470 487 +3 470 248 487 +3 330 514 328 +3 514 188 328 +3 330 275 331 +3 275 426 331 +3 465 518 26 +3 26 518 256 +3 289 355 292 +3 355 383 292 +3 79 360 494 +3 146 240 359 +3 238 237 493 +3 237 491 493 +3 186 288 390 +3 288 287 390 +3 342 74 343 +3 342 285 74 +3 394 68 344 +3 68 67 344 +3 116 115 406 +3 115 408 406 +3 80 82 255 +3 82 253 255 +3 89 487 90 +3 487 58 90 +3 106 105 144 +3 105 83 144 +3 452 193 192 +3 448 192 194 +3 108 318 2 +3 318 241 2 +3 83 105 257 +3 105 258 257 +3 135 311 197 +3 311 475 104 +3 332 133 478 +3 133 369 478 +3 13 296 14 +3 296 415 14 +3 50 87 143 +3 87 86 143 +3 114 362 145 +3 362 146 145 +3 397 149 512 +3 149 439 512 +3 498 175 499 +3 175 428 499 +3 339 338 266 +3 338 264 266 +3 181 180 474 +3 180 187 474 +3 127 132 128 +3 132 129 128 +3 411 510 412 +3 510 528 412 +3 517 392 268 +3 392 205 268 +3 480 275 277 +3 434 480 277 +3 266 457 341 +3 457 166 341 +3 182 401 345 +3 401 354 345 +3 297 529 308 +3 529 219 308 +3 213 60 211 +3 200 211 212 +3 400 307 279 +3 307 294 279 +3 24 516 440 +3 516 515 440 +3 439 149 440 +3 149 24 440 +3 195 326 196 +3 326 402 196 +3 309 299 519 +3 299 401 519 +3 285 342 218 +3 342 357 218 +3 54 74 286 +3 74 285 286 +3 212 60 62 +3 27 212 62 +3 339 514 340 +3 514 22 340 +3 3 354 224 +3 354 298 224 +3 258 516 256 +3 516 24 256 +3 114 363 503 +3 363 229 228 +3 95 501 96 +3 501 229 96 +3 240 239 359 +3 239 360 359 +3 61 361 79 +3 361 360 79 +3 360 239 494 +3 239 238 494 +3 10 445 444 +3 445 378 444 +3 431 429 432 +3 431 427 429 +3 131 332 337 +3 332 333 337 +3 233 381 234 +3 381 333 234 +3 22 184 23 +3 429 77 432 +3 310 495 403 +3 495 358 403 +3 347 36 526 +3 36 486 526 +3 61 28 62 +3 28 27 62 +3 69 417 418 +3 417 358 418 +3 357 342 334 +3 342 101 334 +3 73 191 343 +3 191 101 343 +3 101 103 479 +3 103 475 479 +3 15 488 489 +3 488 125 489 +3 319 51 320 +3 51 0 320 +3 40 111 271 +3 111 113 271 +3 517 156 437 +3 156 155 437 +3 483 283 44 +3 283 42 44 +3 458 325 63 +3 325 64 63 +3 469 233 521 +3 233 38 521 +3 335 376 91 +3 376 89 91 +3 449 448 20 +3 20 448 194 +3 468 477 382 +3 477 132 382 +3 249 373 386 +3 373 198 386 +3 158 529 490 +3 529 297 490 +3 462 202 463 +3 208 57 462 +3 374 442 509 +3 442 507 509 +3 508 375 509 +3 375 374 509 +3 276 421 277 +3 421 434 277 +3 481 362 520 +3 362 114 520 +3 18 502 261 +3 502 259 261 +3 193 502 194 +3 502 18 194 +3 247 151 204 +3 463 202 461 +3 231 234 232 +3 234 333 232 +3 31 229 32 +3 229 363 32 +3 216 218 356 +3 218 357 356 +3 216 355 500 +3 355 289 500 +3 86 217 482 +3 217 216 482 +3 60 213 467 +3 213 376 467 +3 64 460 47 +3 460 65 47 +3 192 448 522 +3 448 447 522 +3 428 175 429 +3 175 77 429 +3 77 23 432 +3 23 184 432 +3 365 443 364 +3 443 240 364 +3 311 104 197 +3 104 67 197 +3 363 228 503 +3 228 407 503 +3 80 156 269 +3 156 517 269 +3 64 325 463 +3 325 208 463 +3 202 204 461 +3 204 151 461 +3 48 349 121 +3 349 450 121 +3 251 250 506 +3 250 505 506 diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data-clip/splitter.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data-clip/splitter.off new file mode 100644 index 00000000000..3aab929df71 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data-clip/splitter.off @@ -0,0 +1,16 @@ +OFF +8 6 0 +2 0 2 +3 0 -2 +3 0 2 +2 0 -2 +2 2 2 +4 2 -2 +4 2 2 +2 2 -2 +3 0 7 4 +3 0 3 7 +3 6 1 5 +3 1 6 2 +3 7 1 4 +3 2 4 1 diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data/folded_star.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/folded_star.off new file mode 100644 index 00000000000..68c8a887da2 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/folded_star.off @@ -0,0 +1,15 @@ +OFF +7 6 0 +0.50085999554530469 0.98935974982034269 0.054777016186685679 +0.51086414037695982 0.0074532224578913869 0.0098759303387234813 +0.23667027533904861 -0.19236191791372245 0.078118737677961653 +0.49890739640011506 0.47147692553082188 0.51901846156493603 +0.5 0.5 0 +0.8400145559724278 0.28990007922508693 -0.53104077094013602 +-0.011501240589425327 0.99837637926383715 0.011228717925938695 +3 4 5 0 +3 1 4 3 +3 3 4 6 +3 4 0 6 +3 1 2 4 +3 2 5 4 diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/deg_on_border.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/deg_on_border.off new file mode 100644 index 00000000000..d8518b7cdfb --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/deg_on_border.off @@ -0,0 +1,10 @@ +OFF +5 3 0 +0 0 0 +1 0 0 +2 -1 0 +3 -1 0 +4 0 0 +3 0 1 4 +3 1 2 3 +3 1 3 4 diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/existing_flip.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/existing_flip.off new file mode 100644 index 00000000000..cca5987fabe --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/existing_flip.off @@ -0,0 +1,19 @@ +OFF +7 10 0 +0.314482809221655 -0.012877345839067217 -0.24601469358849659 +-0.081905665816609866 0.11959178909305103 0.59582950965713732 +1 1 0 +0.5 0.5 1 +0.75 0.75 0.5 +0.67302179212919955 0.77012616600142381 -0.44072953863256931 +0.14300722468117555 0.12954038296069673 0.88891433254868446 +3 0 5 2 +3 0 3 6 +3 5 0 4 +3 2 4 3 +3 4 0 1 +3 4 1 6 +3 4 2 5 +3 3 0 2 +3 6 3 4 +3 6 1 0 diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/small_ccs.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/small_ccs.off new file mode 100644 index 00000000000..1762f2e41a0 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/small_ccs.off @@ -0,0 +1,371 @@ +OFF +141 228 0 +-1 -1 1 +1 -1 1 +1 -1 -1 +-1 -1 -1 +-1 1 -1 +-1 1 1 +1 1 1 +1 1 -1 +-2 1 0 +-2 0 -1.0000000000000001e-05 +-2.0000100000000001 0 -1.2246467991473532e-21 +-2 0 1.0000000000000001e-05 +-1.9999899999999999 0 0 +-2 0 0 +0.066195740892434629 9.7645929666223047e-06 3.4984150593572543 +6.123233995736766e-17 0 2 +-1 0 3 +-1.8369701987210297e-16 0 4 +1 0 3 +0 0 3 +0 4 0 +0 4.0000001000000003 0 +0 4.0000001999999997 0 +1.0000000000000002e-06 4.0000001000000003 0 +0 4.0000003 0 +1.0000000000000002e-06 4.0000001999999997 0 +0 4.0000004000000002 0 +1.0000000000000002e-06 4.0000003 0 +0 4.0000005000000005 0 +1.0000000000000002e-06 4.0000004000000002 0 +0 4.0000005999999999 0 +1.0000000000000002e-06 4.0000005000000005 0 +0 4.0000007000000002 0 +1.0000000000000002e-06 4.0000005999999999 0 +0 4.0000008000000005 0 +1.0000000000000002e-06 4.0000007000000002 0 +0 4.0000008999999999 0 +1.0000000000000002e-06 4.0000008000000005 0 +0 4.0000010000000001 0 +1.0000000000000002e-06 4.0000008999999999 0 +1.0000000000000002e-06 4.0000010000000001 0 +1.0000000000000002e-06 4 0 +2.0000000000000003e-06 4.0000001000000003 0 +2.0000000000000003e-06 4.0000001999999997 0 +2.0000000000000003e-06 4.0000003 0 +2.0000000000000003e-06 4.0000004000000002 0 +2.0000000000000003e-06 4.0000005000000005 0 +2.0000000000000003e-06 4.0000005999999999 0 +2.0000000000000003e-06 4.0000007000000002 0 +2.0000000000000003e-06 4.0000008000000005 0 +2.0000000000000003e-06 4.0000008999999999 0 +2.0000000000000003e-06 4.0000010000000001 0 +2.0000000000000003e-06 4 0 +3.0000000000000005e-06 4.0000001000000003 0 +3.0000000000000005e-06 4.0000001999999997 0 +3.0000000000000005e-06 4.0000003 0 +3.0000000000000005e-06 4.0000004000000002 0 +3.0000000000000005e-06 4.0000005000000005 0 +3.0000000000000005e-06 4.0000005999999999 0 +3.0000000000000005e-06 4.0000007000000002 0 +3.0000000000000005e-06 4.0000008000000005 0 +3.0000000000000005e-06 4.0000008999999999 0 +3.0000000000000005e-06 4.0000010000000001 0 +3.0000000000000005e-06 4 0 +4.0000000000000007e-06 4.0000001000000003 0 +4.0000000000000007e-06 4.0000001999999997 0 +4.0000000000000007e-06 4.0000003 0 +4.0000000000000007e-06 4.0000004000000002 0 +4.0000000000000007e-06 4.0000005000000005 0 +4.0000000000000007e-06 4.0000005999999999 0 +4.0000000000000007e-06 4.0000007000000002 0 +4.0000000000000007e-06 4.0000008000000005 0 +4.0000000000000007e-06 4.0000008999999999 0 +4.0000000000000007e-06 4.0000010000000001 0 +4.0000000000000007e-06 4 0 +5.0000000000000004e-06 4.0000001000000003 0 +5.0000000000000004e-06 4.0000001999999997 0 +5.0000000000000004e-06 4.0000003 0 +5.0000000000000004e-06 4.0000004000000002 0 +5.0000000000000004e-06 4.0000005000000005 0 +5.0000000000000004e-06 4.0000005999999999 0 +5.0000000000000004e-06 4.0000007000000002 0 +5.0000000000000004e-06 4.0000008000000005 0 +5.0000000000000004e-06 4.0000008999999999 0 +5.0000000000000004e-06 4.0000010000000001 0 +5.0000000000000004e-06 4 0 +6.000000000000001e-06 4.0000001000000003 0 +6.000000000000001e-06 4.0000001999999997 0 +6.000000000000001e-06 4.0000003 0 +6.000000000000001e-06 4.0000004000000002 0 +6.000000000000001e-06 4.0000005000000005 0 +6.000000000000001e-06 4.0000005999999999 0 +6.000000000000001e-06 4.0000007000000002 0 +6.000000000000001e-06 4.0000008000000005 0 +6.000000000000001e-06 4.0000008999999999 0 +6.000000000000001e-06 4.0000010000000001 0 +6.000000000000001e-06 4 0 +7.0000000000000007e-06 4.0000001000000003 0 +7.0000000000000007e-06 4.0000001999999997 0 +7.0000000000000007e-06 4.0000003 0 +7.0000000000000007e-06 4.0000004000000002 0 +7.0000000000000007e-06 4.0000005000000005 0 +7.0000000000000007e-06 4.0000005999999999 0 +7.0000000000000007e-06 4.0000007000000002 0 +7.0000000000000007e-06 4.0000008000000005 0 +7.0000000000000007e-06 4.0000008999999999 0 +7.0000000000000007e-06 4.0000010000000001 0 +7.0000000000000007e-06 4 0 +8.0000000000000013e-06 4.0000001000000003 0 +8.0000000000000013e-06 4.0000001999999997 0 +8.0000000000000013e-06 4.0000003 0 +8.0000000000000013e-06 4.0000004000000002 0 +8.0000000000000013e-06 4.0000005000000005 0 +8.0000000000000013e-06 4.0000005999999999 0 +8.0000000000000013e-06 4.0000007000000002 0 +8.0000000000000013e-06 4.0000008000000005 0 +8.0000000000000013e-06 4.0000008999999999 0 +8.0000000000000013e-06 4.0000010000000001 0 +8.0000000000000013e-06 4 0 +9.0000000000000002e-06 4.0000001000000003 0 +9.0000000000000002e-06 4.0000001999999997 0 +9.0000000000000002e-06 4.0000003 0 +9.0000000000000002e-06 4.0000004000000002 0 +9.0000000000000002e-06 4.0000005000000005 0 +9.0000000000000002e-06 4.0000005999999999 0 +9.0000000000000002e-06 4.0000007000000002 0 +9.0000000000000002e-06 4.0000008000000005 0 +9.0000000000000002e-06 4.0000008999999999 0 +9.0000000000000002e-06 4.0000010000000001 0 +9.0000000000000002e-06 4 0 +1.0000000000000001e-05 4 0 +1.0000000000000001e-05 4.0000001000000003 0 +1.0000000000000001e-05 4.0000001999999997 0 +1.0000000000000001e-05 4.0000003 0 +1.0000000000000001e-05 4.0000004000000002 0 +1.0000000000000001e-05 4.0000005000000005 0 +1.0000000000000001e-05 4.0000005999999999 0 +1.0000000000000001e-05 4.0000007000000002 0 +1.0000000000000001e-05 4.0000008000000005 0 +1.0000000000000001e-05 4.0000008999999999 0 +1.0000000000000001e-05 4.0000010000000001 0 +3 4 5 6 +3 0 3 2 +3 1 2 7 +3 0 1 6 +3 3 0 5 +3 2 3 4 +3 6 7 4 +3 2 1 0 +3 7 6 1 +3 6 5 0 +3 5 4 3 +3 4 7 2 +3 9 8 12 +3 10 8 9 +3 11 8 10 +3 12 8 11 +3 12 13 9 +3 9 13 10 +3 10 13 11 +3 11 13 12 +3 15 14 18 +3 16 14 15 +3 17 14 16 +3 18 14 17 +3 18 19 15 +3 15 19 16 +3 16 19 17 +3 17 19 18 +3 21 20 41 +3 21 41 23 +3 22 21 23 +3 22 23 25 +3 24 22 25 +3 24 25 27 +3 26 24 27 +3 26 27 29 +3 28 26 29 +3 28 29 31 +3 30 28 31 +3 30 31 33 +3 32 30 33 +3 32 33 35 +3 34 32 35 +3 34 35 37 +3 36 34 37 +3 36 37 39 +3 38 36 39 +3 38 39 40 +3 23 41 52 +3 23 52 42 +3 25 23 42 +3 25 42 43 +3 27 25 43 +3 27 43 44 +3 29 27 44 +3 29 44 45 +3 31 29 45 +3 31 45 46 +3 33 31 46 +3 33 46 47 +3 35 33 47 +3 35 47 48 +3 37 35 48 +3 37 48 49 +3 39 37 49 +3 39 49 50 +3 40 39 50 +3 40 50 51 +3 42 52 63 +3 42 63 53 +3 43 42 53 +3 43 53 54 +3 44 43 54 +3 44 54 55 +3 45 44 55 +3 45 55 56 +3 46 45 56 +3 46 56 57 +3 47 46 57 +3 47 57 58 +3 48 47 58 +3 48 58 59 +3 49 48 59 +3 49 59 60 +3 50 49 60 +3 50 60 61 +3 51 50 61 +3 51 61 62 +3 53 63 74 +3 53 74 64 +3 54 53 64 +3 54 64 65 +3 55 54 65 +3 55 65 66 +3 56 55 66 +3 56 66 67 +3 57 56 67 +3 57 67 68 +3 58 57 68 +3 58 68 69 +3 59 58 69 +3 59 69 70 +3 60 59 70 +3 60 70 71 +3 61 60 71 +3 61 71 72 +3 62 61 72 +3 62 72 73 +3 64 74 85 +3 64 85 75 +3 65 64 75 +3 65 75 76 +3 66 65 76 +3 66 76 77 +3 67 66 77 +3 67 77 78 +3 68 67 78 +3 68 78 79 +3 69 68 79 +3 69 79 80 +3 70 69 80 +3 70 80 81 +3 71 70 81 +3 71 81 82 +3 72 71 82 +3 72 82 83 +3 73 72 83 +3 73 83 84 +3 75 85 96 +3 75 96 86 +3 76 75 86 +3 76 86 87 +3 77 76 87 +3 77 87 88 +3 78 77 88 +3 78 88 89 +3 79 78 89 +3 79 89 90 +3 80 79 90 +3 80 90 91 +3 81 80 91 +3 81 91 92 +3 82 81 92 +3 82 92 93 +3 83 82 93 +3 83 93 94 +3 84 83 94 +3 84 94 95 +3 86 96 107 +3 86 107 97 +3 87 86 97 +3 87 97 98 +3 88 87 98 +3 88 98 99 +3 89 88 99 +3 89 99 100 +3 90 89 100 +3 90 100 101 +3 91 90 101 +3 91 101 102 +3 92 91 102 +3 92 102 103 +3 93 92 103 +3 93 103 104 +3 94 93 104 +3 94 104 105 +3 95 94 105 +3 95 105 106 +3 97 107 118 +3 97 118 108 +3 98 97 108 +3 98 108 109 +3 99 98 109 +3 99 109 110 +3 100 99 110 +3 100 110 111 +3 101 100 111 +3 101 111 112 +3 102 101 112 +3 102 112 113 +3 103 102 113 +3 103 113 114 +3 104 103 114 +3 104 114 115 +3 105 104 115 +3 105 115 116 +3 106 105 116 +3 106 116 117 +3 108 118 129 +3 108 129 119 +3 109 108 119 +3 109 119 120 +3 110 109 120 +3 110 120 121 +3 111 110 121 +3 111 121 122 +3 112 111 122 +3 112 122 123 +3 113 112 123 +3 113 123 124 +3 114 113 124 +3 114 124 125 +3 115 114 125 +3 115 125 126 +3 116 115 126 +3 116 126 127 +3 117 116 127 +3 117 127 128 +3 119 129 130 +3 119 130 131 +3 120 119 131 +3 120 131 132 +3 121 120 132 +3 121 132 133 +3 122 121 133 +3 122 133 134 +3 123 122 134 +3 123 134 135 +3 124 123 135 +3 124 135 136 +3 125 124 136 +3 125 136 137 +3 126 125 137 +3 126 137 138 +3 127 126 138 +3 127 138 139 +3 128 127 139 +3 128 139 140 diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/pmp_compute_normals_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/pmp_compute_normals_test.cpp index 364df9d3cfa..a243df48db2 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/pmp_compute_normals_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/pmp_compute_normals_test.cpp @@ -1,62 +1,226 @@ -#include -#include -#include -#include +// #define CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP -#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; +typedef CGAL::Exact_predicates_inexact_constructions_kernel EPICK; +typedef CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt EPECK; -template -void test_normals(const char* file_name) +typedef CGAL::Surface_mesh EPICK_SM; +typedef CGAL::Surface_mesh EPECK_SM; + +namespace PMP = CGAL::Polygon_mesh_processing; + +template +void test(const Mesh& mesh, + const VertexNormalPmap& vnormals, + const FaceNormalPmap& fnormals) { - typedef typename K::Point_3 Point; - typedef typename K::Vector_3 Vector; - typedef CGAL::Surface_mesh Surface_mesh; - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::face_descriptor face_descriptor; - - Surface_mesh mesh; + typedef typename K::Vector_3 Vector; + + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + typedef typename CGAL::GetVertexPointMap::const_type VPMap; + VPMap vpmap = get_const_property_map(CGAL::vertex_point, mesh); + + assert(!is_empty(mesh)); + + const vertex_descriptor first_vertex = *(vertices(mesh).begin()); + const face_descriptor first_face = *(faces(mesh).begin()); + + PMP::compute_face_normals(mesh, fnormals); + PMP::compute_face_normals(mesh, fnormals, PMP::parameters::vertex_point_map(vpmap)); + PMP::compute_face_normals(mesh, fnormals, CGAL::parameters::vertex_point_map(vpmap) + .geom_traits(K())); + + Vector f0n = PMP::compute_face_normal(first_face, mesh); + assert(f0n == get(fnormals, first_face)); + PMP::compute_face_normal(first_face, mesh, PMP::parameters::vertex_point_map(vpmap)); + + PMP::compute_vertex_normals(mesh, vnormals); + PMP::compute_vertex_normals(mesh, vnormals, PMP::parameters::vertex_point_map(vpmap)); + PMP::compute_vertex_normals(mesh, vnormals, CGAL::parameters::vertex_point_map(vpmap) + .geom_traits(K())); + + Vector v0n = PMP::compute_vertex_normal(first_vertex, mesh); + assert(v0n == get(vnormals, first_vertex)); + v0n = PMP::compute_vertex_normal(first_vertex, mesh, PMP::parameters::vertex_point_map(vpmap) + .face_normal_map(fnormals)); + std::cout.precision(17); + assert(v0n == get(vnormals, first_vertex)); + + PMP::compute_normals(mesh, vnormals, fnormals); + PMP::compute_normals(mesh, vnormals, fnormals, PMP::parameters::vertex_point_map(vpmap)); + PMP::compute_normals(mesh, vnormals, fnormals, CGAL::parameters::vertex_point_map(vpmap) + .geom_traits(K())); + +#if 1//def CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP + std::ofstream vn_out("vertex_normals.cgal.polylines.txt"); + std::ofstream fn_out("face_normals.cgal.polylines.txt"); + + const CGAL::Bbox_3 bb = PMP::bbox(mesh); + const auto bbox_diagonal = CGAL::sqrt(CGAL::square(bb.xmax() - bb.xmin()) + + CGAL::square(bb.ymax() - bb.ymin()) + + CGAL::square(bb.zmax() - bb.zmin())); + + for(vertex_descriptor v : vertices(mesh)) + vn_out << "2 " << get(vpmap, v) << " " << get(vpmap, v) + 0.1 * bbox_diagonal * get(vnormals, v) << "\n"; + vn_out.close(); + + for(face_descriptor f : faces(mesh)) + { + std::list vertices; + for(halfedge_descriptor h : CGAL::halfedges_around_face(halfedge(f, mesh), mesh)) + vertices.push_back(get(vpmap, target(h, mesh))); + + const typename K::Point_3& c = CGAL::centroid(vertices.begin(), vertices.end()); + fn_out << "2 " << c << " " << c + 0.1 * bbox_diagonal * get(fnormals, f) << "\n"; + } + fn_out.close(); +#endif + + // Check sanity of output + for(const face_descriptor f : faces(mesh)) + { + // tests on non triangular meshes are @todo + if(CGAL::is_triangle(halfedge(f, mesh), mesh)) + { + if(PMP::is_degenerate_triangle_face(f, mesh)) + assert(get(fnormals, f) == CGAL::NULL_VECTOR); + else + assert(get(fnormals, f) != CGAL::NULL_VECTOR); + } + } + + for(const vertex_descriptor v : vertices(mesh)) + { + if(get(vnormals, v) == CGAL::NULL_VECTOR) + { + for(halfedge_descriptor h : CGAL::halfedges_around_face(halfedge(v, mesh), mesh)) + { + if(!is_border(h, mesh)) + { + // There are other cases where a vertex normal can be null without the face normals being null, + // (only two incident faces with opposite normals, for example), but they are not tested for now. + assert(get(fnormals, face(h, mesh)) == CGAL::NULL_VECTOR); + } + } + } + } +} + +template +void test_SM(const char* file_name) +{ + typedef CGAL::Surface_mesh SM; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + typedef typename K::Vector_3 Vector; + + std::cout << "Test with Surface_mesh, and kernel: " << typeid(K).name() << std::endl; + + SM mesh; std::ifstream input(file_name); - if (!(input >> mesh)){ - std::cerr << "Error: cannot read Surface_mesh : " << file_name << "\n"; + if(!(input >> mesh)) + { + std::cerr << "Error: cannot read " << file_name << " as a Surface_mesh\n"; assert(false); } - - typename Surface_mesh::template Property_map fnormals; - bool created; - boost::tie(fnormals, created) = mesh.template add_property_map("f:normals",Vector(0,0,0)); - CGAL::Polygon_mesh_processing::compute_face_normals(mesh, fnormals); - CGAL::Polygon_mesh_processing::compute_face_normals(mesh, fnormals, - CGAL::Polygon_mesh_processing::parameters::vertex_point_map(mesh.points())); - CGAL::Polygon_mesh_processing::compute_face_normals(mesh, fnormals, - CGAL::Polygon_mesh_processing::parameters::vertex_point_map(mesh.points()).geom_traits(K())); - typename Surface_mesh:: template Property_map vnormals; + typename SM::template Property_map vnormals; + vnormals = mesh.template add_property_map("v:normals", CGAL::NULL_VECTOR).first; + typename SM::template Property_map fnormals; + fnormals = mesh.template add_property_map("f:normals", CGAL::NULL_VECTOR).first; - boost::tie(vnormals, created) = mesh.template add_property_map("v:normals",Vector(0,0,0)); - CGAL::Polygon_mesh_processing::compute_vertex_normals(mesh, vnormals); - CGAL::Polygon_mesh_processing::compute_vertex_normals(mesh, vnormals, - CGAL::Polygon_mesh_processing::parameters::vertex_point_map(mesh.points())); - CGAL::Polygon_mesh_processing::compute_vertex_normals(mesh, vnormals, - CGAL::Polygon_mesh_processing::parameters::vertex_point_map(mesh.points()).geom_traits(K())); + test(mesh, vnormals, fnormals); +} - CGAL::Polygon_mesh_processing::compute_normals(mesh, vnormals, fnormals); - CGAL::Polygon_mesh_processing::compute_normals(mesh, vnormals, fnormals, - CGAL::Polygon_mesh_processing::parameters::vertex_point_map(mesh.points())); - CGAL::Polygon_mesh_processing::compute_normals(mesh, vnormals, fnormals, - CGAL::Polygon_mesh_processing::parameters::vertex_point_map(mesh.points()).geom_traits(K())); +template +void test_Polyhedron(const char* file_name) +{ + typedef CGAL::Polyhedron_3 Polyhedron; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename K::Vector_3 Vector; + + std::cout << "Test with Polyhedron, and kernel: " << typeid(K).name() << std::endl; + + Polyhedron mesh; + std::ifstream input(file_name); + if(!(input >> mesh)) + { + std::cerr << "Error: cannot read " << file_name << " as a Polyhedron\n"; + assert(false); + } + + typedef std::map VertexNormalMap; + typedef boost::associative_property_map VertexNormalPMap; + typedef std::map FaceNormalMap; + typedef boost::associative_property_map FaceNormalPMap; + + VertexNormalMap vn_map; + FaceNormalMap fn_map; + + for(vertex_descriptor v : vertices(mesh)) + vn_map[v] = CGAL::NULL_VECTOR; + for(face_descriptor f : faces(mesh)) + fn_map[f] = CGAL::NULL_VECTOR; + + VertexNormalPMap vnormals(vn_map); + FaceNormalPMap fnormals(fn_map); + + test(mesh, vnormals, fnormals); +} + +void test(const char* filename) +{ + std::cout << "test " << filename << "..." << std::endl; + + // EPECK disabled because it takes too long for the testsuite due to sq roots comparisons, + // but it passed. + test_SM(filename); +// test_SM(filename); + test_Polyhedron(filename); +// test_Polyhedron(filename); } int main() { - test_normals("data/elephant.off"); - test_normals("data/elephant.off"); + std::cout.precision(17); + + CGAL::Set_ieee_double_precision pfr; + + test("data/elephant.off"); + test("data/folded_star.off"); + test("data/joint_refined.off"); + test("data/mannequin-devil.off"); + test("data/U.off"); + + test("data_degeneracies/deg_on_border.off"); + test("data_degeneracies/degtri_edge.off"); + test("data_degeneracies/degtri_three.off"); + test("data_degeneracies/degtri_four.off"); + test("data_degeneracies/degtri_nullface.off"); + test("data_degeneracies/degtri_single.off"); + test("data_degeneracies/existing_flip.off"); + test("data_degeneracies/fused_vertices.off"); + test("data_degeneracies/small_ccs.off"); + test("data_degeneracies/trihole.off"); std::cerr << "All done." << std::endl; return EXIT_SUCCESS; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test_P_SM_OM.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test_P_SM_OM.cpp index 1769df9e09c..bed1ad1c583 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test_P_SM_OM.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test_P_SM_OM.cpp @@ -31,15 +31,21 @@ int main() } { - typedef CGAL::Polyhedron_3 P; - std::map::face_descriptor, std::size_t> fim; - P p; - std::ifstream in("data/elephant.off"); - in >> p; - PMP::isotropic_remeshing(faces(p), + typedef CGAL::Polyhedron_3 P; + + std::ifstream in("data/elephant.off"); + P p; + in >> p; + + std::map::face_descriptor, std::size_t> fim; + std::size_t fid = 0; + for(const boost::graph_traits

    ::face_descriptor f : faces(p)) + fim[f] = fid++; + + PMP::isotropic_remeshing(faces(p), 0.02, - p, - PMP::parameters::face_index_map(boost::make_assoc_property_map(fim))); + p, + PMP::parameters::face_index_map(boost::make_assoc_property_map(fim))); std::ofstream out("p.off"); out << p << std::endl; } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remove_degeneracies_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remove_degeneracies_test.cpp index ab5778ec5f8..f18dda38b1e 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remove_degeneracies_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remove_degeneracies_test.cpp @@ -1,8 +1,12 @@ +#define CGAL_PMP_DEBUG_SMALL_CC_REMOVAL + #include #include #include +#include +#include #include #include @@ -14,11 +18,9 @@ // namespace PMP = CGAL::Polygon_mesh_processing; +namespace CP = CGAL::parameters; -typedef CGAL::Exact_predicates_inexact_constructions_kernel EPICK; - -typedef CGAL::Surface_mesh Surface_mesh; -typedef CGAL::Polyhedron_3 Polyhedron; +typedef CGAL::Exact_predicates_inexact_constructions_kernel EPICK; template void detect_degeneracies(const EdgeRange& edge_range, @@ -34,10 +36,10 @@ void detect_degeneracies(const EdgeRange& edge_range, std::set dedges; PMP::degenerate_edges(mesh, std::inserter(dedges, dedges.end())); PMP::degenerate_edges(edge_range, mesh, std::inserter(dedges, dedges.begin())); - PMP::degenerate_edges(mesh, std::inserter(dedges, dedges.end()), CGAL::parameters::all_default()); + PMP::degenerate_edges(mesh, std::inserter(dedges, dedges.end()), CP::all_default()); dedges.clear(); - PMP::degenerate_edges(edge_range, mesh, std::inserter(dedges, dedges.begin()), CGAL::parameters::all_default()); + PMP::degenerate_edges(edge_range, mesh, std::inserter(dedges, dedges.begin()), CP::all_default()); std::cout << "\t" << dedges.size() << " degenerate edges vs " << expected_dedges_n << std::endl; assert(dedges.size() == expected_dedges_n); @@ -45,10 +47,10 @@ void detect_degeneracies(const EdgeRange& edge_range, std::vector dfaces; PMP::degenerate_faces(mesh, std::back_inserter(dfaces)); PMP::degenerate_faces(face_range, mesh, std::back_inserter(dfaces)); - PMP::degenerate_faces(mesh, std::back_inserter(dfaces), CGAL::parameters::all_default()); + PMP::degenerate_faces(mesh, std::back_inserter(dfaces), CP::all_default()); dfaces.clear(); - PMP::degenerate_faces(face_range, mesh, std::back_inserter(dfaces), CGAL::parameters::all_default()); + PMP::degenerate_faces(face_range, mesh, std::back_inserter(dfaces), CP::all_default()); std::cout << "\t" << dfaces.size() << " degenerate faces vs " << expected_dfaces_n << std::endl; assert(dfaces.size() == expected_dfaces_n); } @@ -99,7 +101,7 @@ bool remove_dedges(const std::vector& edges_selection_ids, for(std::size_t edge_id : edges_selection_ids) edge_range.push_back(all_edges[edge_id]); - return CGAL::Polygon_mesh_processing::remove_degenerate_edges(edge_range, mesh, CGAL::parameters::all_default()); + return CGAL::Polygon_mesh_processing::remove_degenerate_edges(edge_range, mesh, CP::all_default()); } template @@ -115,21 +117,21 @@ bool remove_dfaces(const std::vector& faces_selection_ids, for(std::size_t face_id : faces_selection_ids) face_range.push_back(all_faces[face_id]); - return CGAL::Polygon_mesh_processing::remove_degenerate_faces(face_range, mesh, CGAL::parameters::all_default()); + return CGAL::Polygon_mesh_processing::remove_degenerate_faces(face_range, mesh, CP::all_default()); } template -void test(const char* filename, - const std::vector& edges_selection_ids, - const std::vector& faces_selection_ids, - const std::size_t expected_all_degen_edges_n, - const std::size_t expected_all_degen_faces_n, - const std::size_t expected_partial_degen_edges_n, - const std::size_t expected_partial_degen_faces_n, - const std::size_t expected_post_removal_degen_edges_n, - const std::size_t expected_post_removal_degen_faces_n) +void remove_degeneracies(const char* filename, + const std::vector& edges_selection_ids, + const std::vector& faces_selection_ids, + const std::size_t expected_all_degen_edges_n, + const std::size_t expected_all_degen_faces_n, + const std::size_t expected_partial_degen_edges_n, + const std::size_t expected_partial_degen_faces_n, + const std::size_t expected_post_removal_degen_edges_n, + const std::size_t expected_post_removal_degen_faces_n) { - std::cout << " test file: " << filename << std::endl; + std::cout << " remove_degeneracies, file: " << filename << std::endl; std::ifstream input(filename); Mesh mesh; @@ -149,12 +151,12 @@ void test(const char* filename, // Complete remove std::cout << " Remove all..." << std::endl; mesh = mesh_cpy; - /* bool all_removed = */ CGAL::Polygon_mesh_processing::remove_degenerate_edges(mesh, CGAL::parameters::all_default()); + /* bool all_removed = */ CGAL::Polygon_mesh_processing::remove_degenerate_edges(mesh, CP::all_default()); //assert(all_removed); assert(CGAL::is_valid_polygon_mesh(mesh)); mesh = mesh_cpy; - /* all_removed = */ CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh, CGAL::parameters::all_default()); + /* all_removed = */ CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh, CP::all_default()); // assert(all_removed); assert(CGAL::is_valid_polygon_mesh(mesh)); @@ -179,69 +181,177 @@ void test(const char* filename, std::cout << " Done" << std::endl; } +template +void initialize_IDs(const Mesh&) { } + +template +void initialize_IDs(const CGAL::Polyhedron_3& mesh) +{ + typedef CGAL::Polyhedron_3 Mesh; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + int i=0; + for(vertex_descriptor v : vertices(mesh)) + v->id() = i++; + + i=0; + for(face_descriptor f : faces(mesh)) + f->id() = i++; +} + +template +void remove_negligible_connected_components(const char* filename) +{ + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + std::cout << " remove negligible CCs, file: " << filename << std::endl; + + std::ifstream input(filename); + Mesh mesh, mesh_cpy; + if (!input || !(input >> mesh) || mesh.is_empty()) + { + std::cerr << filename << " is not a valid off file.\n"; + exit(1); + } + + mesh_cpy = mesh; + + initialize_IDs(mesh); + initialize_IDs(mesh_cpy); + + std::size_t ini_nv = num_vertices(mesh); + std::size_t ini_nf = num_faces(mesh); + + std::cout << "before: " << ini_nv << " nv & " << ini_nf << " nf" << std::endl; + + // negative thresholds --> doesn't remove anything + std::cout << "---------\nnull or negative threshold, nothing happens..." << std::endl; + std::size_t res = PMP::remove_connected_components_of_negligible_size(mesh, CP::area_threshold(-1e15) + .volume_threshold(0)); + assert(PMP::internal::number_of_connected_components(mesh) == 4); + assert(num_vertices(mesh) == ini_nv); + assert(num_faces(mesh) == ini_nf); + + // threshold too small, doesn't remove anything + std::cout << "---------\ntiny threshold, nothing happens..." << std::endl; + PMP::remove_connected_components_of_negligible_size(mesh, CP::area_threshold(1e-15) + .volume_threshold(1e-15)); + assert(PMP::internal::number_of_connected_components(mesh) == 4); + assert(num_vertices(mesh) == ini_nv); + assert(num_faces(mesh) == ini_nf); + + // that removes the CCs with small volumes + std::cout << "---------\nremove small volumes..." << std::endl; + res = PMP::remove_connected_components_of_negligible_size(mesh, CP::area_threshold(1e-15) + .volume_threshold(0.1)); + std::cout << "res: " << res << std::endl; + initialize_IDs(mesh); + assert(PMP::internal::number_of_connected_components(mesh) == 2); + + // that removes the open CC with a small area + std::cout << "---------\nremove small areas..." << std::endl; + PMP::remove_connected_components_of_negligible_size(mesh, CP::area_threshold(20)); + initialize_IDs(mesh); + assert(PMP::internal::number_of_connected_components(mesh) == 1); + + // Remove everything with a too-large value + std::cout << "---------\nremove everything..." << std::endl; + PMP::remove_connected_components_of_negligible_size(mesh, CP::area_threshold(1e15)); + assert(is_empty(mesh)); + + // Could also have used default paramaters, which does the job by itself + std::cout << "---------\ndefault values..." << std::endl; + + std::vector faces_to_be_removed; + std::size_t nb_to_be_rm = PMP::remove_connected_components_of_negligible_size( + mesh_cpy, CP::dry_run(true) + .output_iterator(std::back_inserter(faces_to_be_removed))); + assert(nb_to_be_rm == 3); + assert(PMP::internal::number_of_connected_components(mesh_cpy) == 4); // a dry run does not remove anything + assert(faces_to_be_removed.size() == 216); // sum of #faces of the small CCs + + assert(nb_to_be_rm == PMP::remove_connected_components_of_negligible_size(mesh_cpy)); + assert(PMP::internal::number_of_connected_components(mesh_cpy) == 1); +} + template void test() { - test("data_degeneracies/degtri_2dt_1edge_split_twice.off", - std::initializer_list({0, 1, 4, 3}), // edge selection - std::initializer_list({0}), // face selection - 0, 2, // expected number of degenerate edges/faces in the complete mesh - 0, 1, // expected number of degenerate edges/faces in the selection - 0, 0); // expected number of degenerate edges/faces in the mesh after partial removal + remove_degeneracies("data_degeneracies/degtri_2dt_1edge_split_twice.off", + std::initializer_list({0, 1, 4, 3}), // edge selection + std::initializer_list({0}), // face selection + 0, 2, // expected number of degenerate edges/faces in the complete mesh + 0, 1, // expected number of degenerate edges/faces in the selection + 0, 0); // expected number of degenerate edges/faces in the mesh after partial removal - test("data_degeneracies/degtri_four.off", - std::initializer_list({1}), - std::initializer_list({3}), - 0, 1, 0, 0, 0, 1); + remove_degeneracies("data_degeneracies/degtri_four.off", + std::initializer_list({1}), + std::initializer_list({3}), + 0, 1, 0, 0, 0, 1); - test("data_degeneracies/degtri_four-2.off", - std::initializer_list({2}), - std::initializer_list({3}), - 0, 1, 0, 0, 0, 1); + remove_degeneracies("data_degeneracies/degtri_four-2.off", + std::initializer_list({2}), + std::initializer_list({3}), + 0, 1, 0, 0, 0, 1); - test("data_degeneracies/degtri_on_border.off", - std::initializer_list({2}), - std::initializer_list({0}), - 0, 1, 0, 1, 0, 0); + remove_degeneracies("data_degeneracies/degtri_on_border.off", + std::initializer_list({2}), + std::initializer_list({0}), + 0, 1, 0, 1, 0, 0); - test("data_degeneracies/degtri_three.off", - std::initializer_list({2}), - std::initializer_list({1}), - 0, 1, 0, 0, 0, 1); + remove_degeneracies("data_degeneracies/degtri_three.off", + std::initializer_list({2}), + std::initializer_list({1}), + 0, 1, 0, 0, 0, 1); - test("data_degeneracies/degtri_single.off", - std::initializer_list({0, 1, 2}), - std::initializer_list({0}), - 0, 1, 0, 1, 0, 0); + remove_degeneracies("data_degeneracies/degtri_single.off", + std::initializer_list({0, 1, 2}), + std::initializer_list({0}), + 0, 1, 0, 1, 0, 0); - test("data_degeneracies/degtri_nullface.off", - std::initializer_list({3, 6, 7}), - std::initializer_list({0, 1, 2}), - 3, 4, 1, 2, 0, 0); + remove_degeneracies("data_degeneracies/degtri_nullface.off", + std::initializer_list({3, 6, 7}), + std::initializer_list({0, 1, 2}), + 3, 4, 1, 2, 0, 0); - test("data_degeneracies/trihole.off", - std::initializer_list({12}), - std::initializer_list({4, 5}), - 1, 3, 1, 2, 0, 0); + remove_degeneracies("data_degeneracies/trihole.off", + std::initializer_list({12}), + std::initializer_list({4, 5}), + 1, 3, 1, 2, 0, 0); - test("data_degeneracies/degtri_sliding.off", - std::initializer_list({2}), - std::initializer_list({2, 4}), - 0, 4, 0, 2, 0, 0); + remove_degeneracies("data_degeneracies/degtri_sliding.off", + std::initializer_list({2}), + std::initializer_list({2, 4}), + 0, 4, 0, 2, 0, 0); - test("data_degeneracies/fused_vertices.off", - std::initializer_list({5, 10, 13, 15, 27, 45}), - std::initializer_list({1, 3, 5, 10, 19}), - 6, 7, 2, 4, 3, 3); + remove_degeneracies("data_degeneracies/fused_vertices.off", + std::initializer_list({5, 10, 13, 15, 27, 45}), + std::initializer_list({1, 3, 5, 10, 19}), + 6, 7, 2, 4, 3, 3); + + remove_negligible_connected_components("data_degeneracies/small_ccs.off"); } -int main() +template +void test() { + typedef typename Kernel::Point_3 Point_3; + typedef CGAL::Surface_mesh Surface_mesh; + typedef CGAL::Polyhedron_3 Polyhedron_with_ID; + std::cout << "EPICK SM TESTS" << std::endl; - test(); + test(); std::cout << "EPICK POLYHEDRON TESTS" << std::endl; - test(); + test(); +} + +int main(int /*argc*/, char** /*argv*/) +{ + test(); + + std::cout << "Done" << std::endl; return EXIT_SUCCESS; } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/self_intersection_surface_mesh_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/self_intersection_surface_mesh_test.cpp index 3addd6c9323..11cb16b40a7 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/self_intersection_surface_mesh_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/self_intersection_surface_mesh_test.cpp @@ -1,22 +1,25 @@ -#include -#include -#include -#include - #include #include #include #include - +#include #include -typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic; -typedef CGAL::Exact_predicates_exact_constructions_kernel Epec; +#include +#include +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel EPICK; +typedef CGAL::Exact_predicates_exact_constructions_kernel EPECK; + +namespace PMP = ::CGAL::Polygon_mesh_processing; +namespace CP = ::CGAL::parameters; template -int -test_self_intersections(const char* filename, const bool expected) +int test_self_intersections(const char* filename, + const bool expected) { typedef CGAL::Surface_mesh Mesh; typedef typename boost::graph_traits::face_descriptor face_descriptor; @@ -35,18 +38,36 @@ test_self_intersections(const char* filename, const bool expected) timer.start(); std::vector > intersected_tris; - CGAL::Polygon_mesh_processing::self_intersections( - m, - std::back_inserter(intersected_tris), - CGAL::Polygon_mesh_processing::parameters::vertex_index_map(get(CGAL::vertex_point, m))); + + if(std::is_same::value) // EPECK isn't threadsafe + { + PMP::self_intersections( + m, std::back_inserter(intersected_tris), CP::vertex_index_map(get(CGAL::vertex_point, m))); + } + else + { + PMP::self_intersections( + m, std::back_inserter(intersected_tris), CP::vertex_index_map(get(CGAL::vertex_point, m))); + } bool intersecting_1 = !intersected_tris.empty(); std::cout << "self_intersections test took " << timer.time() << " sec." << std::endl; std::cout << intersected_tris.size() << " pairs of triangles are intersecting." << std::endl; timer.reset(); - bool intersecting_2 = CGAL::Polygon_mesh_processing::does_self_intersect(m, - CGAL::Polygon_mesh_processing::parameters::vertex_index_map(get(CGAL::vertex_point, m))); + + bool intersecting_2; + + if(std::is_same::value) // EPECK isn't threadsafe + { + intersecting_2 = PMP::does_self_intersect( + m, CP::vertex_index_map(get(CGAL::vertex_point, m))); + } + else + { + intersecting_2 = PMP::does_self_intersect( + m, CP::vertex_index_map(get(CGAL::vertex_point, m))); + } std::cout << "does_self_intersect test took " << timer.time() << " sec." << std::endl; std::cout << (intersecting_2 ? "There is a self-intersection." : @@ -77,11 +98,11 @@ int main(int argc, char** argv) assert(!ss.fail()); // make sure that argv[2] is either 'true' or 'false' } - std::cout << "First test (Epic):" << std::endl; - int r = test_self_intersections(filename, expected); + std::cout << "First test (EPICK):" << std::endl; + int r = test_self_intersections(filename, expected); - std::cout << "First test (Epec):" << std::endl; - r += test_self_intersections(filename, expected); + std::cout << "First test (EPECK):" << std::endl; + r += test_self_intersections(filename, expected); // Second test --------------------------------------------------------------- expected = true; @@ -93,11 +114,11 @@ int main(int argc, char** argv) assert(!ss.fail()); } - std::cout << "Second test (Epic):" << std::endl; - r += test_self_intersections(filename, expected); + std::cout << "Second test (EPICK):" << std::endl; + r += test_self_intersections(filename, expected); - std::cout << "Second test (Epec):" << std::endl; - r += test_self_intersections(filename, expected); + std::cout << "Second test (EPECK):" << std::endl; + r += test_self_intersections(filename, expected); // Third test ---------------------------------------------------------------- expected = true; @@ -109,11 +130,11 @@ int main(int argc, char** argv) assert(!ss.fail()); } - std::cout << "Third test (Epic):" << std::endl; - r += test_self_intersections(filename, expected); + std::cout << "Third test (EPICK):" << std::endl; + r += test_self_intersections(filename, expected); - std::cout << "Third test (Epec):" << std::endl; - r += test_self_intersections(filename, expected); + std::cout << "Third test (EPECK):" << std::endl; + r += test_self_intersections(filename, expected); // Fourth test ---------------------------------------------------------------- expected = true; @@ -125,11 +146,11 @@ int main(int argc, char** argv) assert(!ss.fail()); } - std::cout << "Fourth test (Epic):" << std::endl; - r += test_self_intersections(filename, expected); + std::cout << "Fourth test (EPICK):" << std::endl; + r += test_self_intersections(filename, expected); - std::cout << "Fourth test (Epec):" << std::endl; - r += test_self_intersections(filename, expected); + std::cout << "Fourth test (EPECK):" << std::endl; + r += test_self_intersections(filename, expected); return r; } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_does_bound_a_volume.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_does_bound_a_volume.cpp index ae04cdbc95a..37182215932 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_does_bound_a_volume.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_does_bound_a_volume.cpp @@ -26,10 +26,10 @@ int main(int argc, char** argv) Surface_mesh sm; input >> sm; bool res = atoi(argv[2*(i+1)])>0; - assert(!"Result is not as expected (input orientation)" || - CGAL::Polygon_mesh_processing::does_bound_a_volume(sm)==res); + if (CGAL::Polygon_mesh_processing::does_bound_a_volume(sm)!=res) + CGAL_error_msg("Result is not as expected (input orientation)"); CGAL::Polygon_mesh_processing::reverse_face_orientations(sm); - assert(!"Result is not as expected (reversed orientation)" || - CGAL::Polygon_mesh_processing::does_bound_a_volume(sm)==res); + if (CGAL::Polygon_mesh_processing::does_bound_a_volume(sm)!=res) + CGAL_error_msg("Result is not as expected (reversed orientation)"); } } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_is_polygon_soup_a_polygon_mesh.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_is_polygon_soup_a_polygon_mesh.cpp index edfc4802110..051c47d6051 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_is_polygon_soup_a_polygon_mesh.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_is_polygon_soup_a_polygon_mesh.cpp @@ -1,11 +1,19 @@ -#include #include #include +#include +#include +#include + +#include +#include +#include #include +#include #include #include +#include #include #include #include @@ -17,8 +25,12 @@ typedef CGAL::Exact_predicates_exact_constructions_kernel Epec; template void test_polygon_soup(std::string fname, bool expected) { - typedef CGAL::Polyhedron_3 Polyhedron; - std::vector points; + typedef typename K::Point_3 Point; + + typedef CGAL::Polyhedron_3 Polyhedron; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + + std::vector points; std::vector< std::vector > polygons; std::ifstream input(fname.c_str()); @@ -34,28 +46,81 @@ void test_polygon_soup(std::string fname, bool expected) exit(EXIT_FAILURE); } - bool is_mesh = CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh(polygons); std::cout << "is_polygon_soup_a_polygon_mesh(" << fname << ") == " << std::boolalpha << is_mesh << ";" << std::endl; assert(is_mesh == expected); - if(is_mesh) { + if(is_mesh) + { Polyhedron p; - CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, polygons, p); - assert(p.is_valid()); + + // just to test the named paramers + typedef std::pair Point_with_Boolean; + std::vector points_with_pairs; + for(const Point& pt : points) + points_with_pairs.emplace_back(pt, false); + + typedef CGAL::dynamic_vertex_property_t Point_property; + typedef typename boost::property_map::type Custom_VPM; + + Custom_VPM vpm = get(Point_property(), p); + + CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh( + points_with_pairs, polygons, p, + CGAL::parameters::point_map(CGAL::First_of_pair_property_map()), + CGAL::parameters::vertex_point_map(vpm)); + + std::cout << num_vertices(p) << " nv and " << num_faces(p) << " nf" << std::endl; + assert(!CGAL::is_empty(p) && CGAL::is_valid_polygon_mesh(p)); + + std::set ppts; + for(const vertex_descriptor v : vertices(p)) + ppts.insert(get(vpm, v)); + + assert(ppts.size() == num_vertices(p)); + + // twice to check if adds correctly + std::deque soup_points; + std::vector > soup_polygons; + + CGAL::Polygon_mesh_processing::polygon_mesh_to_polygon_soup(p, soup_points, soup_polygons); + CGAL::Polygon_mesh_processing::polygon_mesh_to_polygon_soup(p, soup_points, soup_polygons); + + std::size_t nv = static_cast(num_vertices(p)); + std::size_t nf = static_cast(num_faces(p)); + + assert(soup_points.size() == 2 * nv); + assert(soup_polygons.size() == 2 * nf); + + // check sanity of the polygons + for(std::size_t fi=0; fi #include + +#include #include #include @@ -12,13 +14,13 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef CGAL::Surface_mesh SMesh; template -bool test_orientation(TriangleMesh& tm, bool is_positive, const NamedParameters& np) +bool test_orientation(const TriangleMesh& tm, bool is_positive, const NamedParameters& np) { typedef boost::graph_traits Graph_traits; typedef typename Graph_traits::vertex_descriptor vertex_descriptor; typedef typename Graph_traits::face_descriptor face_descriptor; typedef typename CGAL::GetVertexPointMap::const_type Vpm; - typedef typename CGAL::GetFaceIndexMap::const_type Fid_map; + typedef typename CGAL::GetInitializedFaceIndexMap::const_type Fid_map; using CGAL::parameters::choose_parameter; using CGAL::parameters::get_parameter; @@ -26,8 +28,7 @@ bool test_orientation(TriangleMesh& tm, bool is_positive, const NamedParameters& Vpm vpm = choose_parameter(get_parameter(np, CGAL::internal_np::vertex_point), CGAL::get_const_property_map(boost::vertex_point, tm)); - Fid_map fid_map = choose_parameter(get_parameter(np, CGAL::internal_np::face_index), - CGAL::get_const_property_map(boost::face_index, tm)); + Fid_map fid_map = CGAL::get_initialized_face_index_map(tm, np); std::vector face_cc(num_faces(tm), std::size_t(-1)); @@ -127,5 +128,6 @@ int main() return 1; } + std::cout << "Done!" << std::endl; return 0; } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_clip.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_clip.cpp index f330133421e..aa63899f127 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_clip.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_clip.cpp @@ -4,6 +4,9 @@ #include #include +#include +#include + #include #include #include @@ -19,320 +22,593 @@ template void test() { // test with a clipper mesh - TriangleMesh tm1, tm2; + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/elephant.off") >> tm1; + std::ifstream("data-coref/sphere.off") >> tm2; - std::ifstream input("data-coref/elephant.off"); - input >> tm1; - input.close(); - input.open("data-coref/sphere.off"); - input >> tm2; - input.close(); + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); - PMP::clip(tm1, tm2, - params::clip_volume(false) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2)) - ); - assert(!CGAL::is_closed(tm1)); - CGAL::clear(tm1); - CGAL::clear(tm2); + PMP::clip(tm1, tm2, + params::clip_volume(false).face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(!CGAL::is_closed(tm1)); + } - input.open("data-coref/elephant.off"); - input >> tm1; - input.close(); - input.open("data-coref/sphere.off"); - input >> tm2; - input.close(); + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/elephant.off") >> tm1; + std::ifstream("data-coref/sphere.off") >> tm2; - PMP::clip(tm1, tm2, params::clip_volume(true) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(CGAL::is_closed(tm1)); - CGAL::clear(tm1); - CGAL::clear(tm2); + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::clip(tm1, tm2, + params::clip_volume(true).face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(CGAL::is_closed(tm1)); + } + + // test with a iso-cuboid + { + TriangleMesh tm1; + std::ifstream("data-coref/elephant.off") >> tm1; + K::Iso_cuboid_3 iso_cuboid(K::Point_3(0,0,0), K::Point_3(0.4, 0.6, 0.4)); + + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + + PMP::clip(tm1, iso_cuboid, params::clip_volume(true).face_index_map(custom_face_index_map_1)); + assert(CGAL::is_closed(tm1)); + } // test with a plane - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); + { + TriangleMesh tm1; + std::ifstream("data-coref/cube.off") >> tm1; + K::Plane_3 plane(0, 0, 1, -1); - K::Plane_3 plane(0, 0, 1, -1); + PMP::clip(tm1, plane, params::clip_volume(true)); + assert(CGAL::is_closed(tm1)); + } - PMP::clip(tm1, plane, params::clip_volume(true)); - assert(CGAL::is_closed(tm1)); - CGAL::clear(tm1); + { + TriangleMesh tm1; + std::ifstream("data-coref/cube.off") >> tm1; + K::Plane_3 plane(0, 0, 1, -1); - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - PMP::clip(tm1, plane, params::clip_volume(false) - .use_compact_clipper(false)); - assert(!CGAL::is_closed(tm1)); - CGAL::clear(tm1); + PMP::clip(tm1, plane, params::clip_volume(false).use_compact_clipper(false)); + assert(!CGAL::is_closed(tm1)); + } - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - PMP::clip(tm1, plane, params::clip_volume(false) - .use_compact_clipper(true)); - assert(CGAL::is_closed(tm1)); - CGAL::clear(tm1); + { + TriangleMesh tm1; + std::ifstream("data-coref/cube.off") >> tm1; + K::Plane_3 plane(0, 0, 1, -1); - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - PMP::clip(tm1, K::Plane_3(-0.236474, 0.437732, 0.867451, -0.838791), params::clip_volume(true)); - assert(CGAL::is_closed(tm1)); - assert(!CGAL::is_empty(tm1)); - CGAL::clear(tm1); + PMP::clip(tm1, plane, params::clip_volume(false).use_compact_clipper(true)); + assert(CGAL::is_closed(tm1)); + } - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - PMP::clip(tm1, K::Plane_3(0, 0, 1, 2)); - assert(CGAL::is_empty(tm1)); - CGAL::clear(tm1); + { + TriangleMesh tm1; + std::ifstream("data-coref/cube.off") >> tm1; - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - PMP::clip(tm1, K::Plane_3(0, 0, 1, -2)); - assert(!CGAL::is_empty(tm1)); - CGAL::clear(tm1); + PMP::clip(tm1, K::Plane_3(-0.236474, 0.437732, 0.867451, -0.838791), params::clip_volume(true)); + assert(CGAL::is_closed(tm1)); + assert(!CGAL::is_empty(tm1)); + } + + { + TriangleMesh tm1; + std::ifstream("data-coref/cube.off") >> tm1; + + PMP::clip(tm1, K::Plane_3(0, 0, 1, 2)); + assert(CGAL::is_empty(tm1)); + } + + { + TriangleMesh tm1; + std::ifstream("data-coref/cube.off") >> tm1; + + PMP::clip(tm1, K::Plane_3(0, 0, 1, -2)); + assert(!CGAL::is_empty(tm1)); + } // clipping with identity - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - input.open("data-coref/cube.off"); - input >> tm2; - input.close(); - PMP::clip(tm1, tm2,params::clip_volume(true) - .use_compact_clipper(true) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(num_vertices(tm1)==8); - CGAL::clear(tm1); - CGAL::clear(tm2); + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/cube.off") >> tm1; + std::ifstream("data-coref/cube.off") >> tm2; - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - input.open("data-coref/cube.off"); - input >> tm2; - input.close(); - PMP::clip(tm1, tm2,params::clip_volume(false) - .use_compact_clipper(false) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(CGAL::is_empty(tm1)); - CGAL::clear(tm1); - CGAL::clear(tm2); + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - input.open("data-coref/cube.off"); - input >> tm2; - input.close(); - PMP::clip(tm1, tm2,params::clip_volume(false) - .use_compact_clipper(true) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(num_vertices(tm1)==8); - CGAL::clear(tm1); - CGAL::clear(tm2); + PMP::clip(tm1, tm2, + params::clip_volume(true) + .use_compact_clipper(true) + .face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(num_vertices(tm1) == 8); + } - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - input.open("data-coref/cube.off"); - input >> tm2; - input.close(); - PMP::transform(K::Aff_transformation_3(CGAL::TRANSLATION, K::Vector_3(1,0,0)), tm2); - PMP::clip(tm1, tm2,params::clip_volume(false) - .use_compact_clipper(false) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(CGAL::is_empty(tm1)); - CGAL::clear(tm1); - CGAL::clear(tm2); + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/cube.off") >> tm1; + std::ifstream("data-coref/cube.off") >> tm2; - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - input.open("data-coref/cube.off"); - input >> tm2; - input.close(); - PMP::transform(K::Aff_transformation_3(CGAL::TRANSLATION, K::Vector_3(1,0,0)), tm2); - PMP::clip(tm1, tm2,params::clip_volume(false) - .use_compact_clipper(true) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(vertices(tm1).size()==4); - CGAL::clear(tm1); - CGAL::clear(tm2); + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::clip(tm1, tm2, + params::clip_volume(false) + .use_compact_clipper(false) + .face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(CGAL::is_empty(tm1)); + } + + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/cube.off") >> tm1; + std::ifstream("data-coref/cube.off") >> tm2; + + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::clip(tm1, tm2, + params::clip_volume(false) + .use_compact_clipper(true) + .face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(num_vertices(tm1) == 8); + } + + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/cube.off") >> tm1; + std::ifstream("data-coref/cube.off") >> tm2; + + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::transform(K::Aff_transformation_3(CGAL::TRANSLATION, K::Vector_3(1,0,0)), tm2); + PMP::clip(tm1, tm2, + params::clip_volume(false) + .use_compact_clipper(false) + .face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(CGAL::is_empty(tm1)); + } + + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/cube.off") >> tm1; + std::ifstream("data-coref/cube.off") >> tm2; + + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::transform(K::Aff_transformation_3(CGAL::TRANSLATION, K::Vector_3(1,0,0)), tm2); + PMP::clip(tm1, tm2, + params::clip_volume(false) + .use_compact_clipper(true) + .face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(vertices(tm1).size() == 4); + } // test orientation + patch without input vertex - CGAL::make_tetrahedron( - K::Point_3(0.53, -1.3, 0.2), - K::Point_3(0.53, 1.1, 0.2), - K::Point_3(0.53, -1.3, 0.4), - K::Point_3(0.73, -1.3, 0.2), - tm2); - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - PMP::clip(tm1, tm2,params::clip_volume(false) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(vertices(tm1).size()==6); - CGAL::clear(tm1); - CGAL::clear(tm2); + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/cube.off") >> tm1; - CGAL::make_tetrahedron( - K::Point_3(0.53, -1.3, 0.2), - K::Point_3(0.53, 1.1, 0.2), - K::Point_3(0.53, -1.3, 0.4), - K::Point_3(0.73, -1.3, 0.2), - tm2); - PMP::reverse_face_orientations(tm2); - input.open("data-coref/cube.off"); - input >> tm1; - input.close(); - PMP::clip(tm1, tm2,params::clip_volume(false) - .face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(vertices(tm1).size()==6+8); - CGAL::clear(tm1); - CGAL::clear(tm2); + CGAL::make_tetrahedron(K::Point_3(0.53, -1.3, 0.2), + K::Point_3(0.53, 1.1, 0.2), + K::Point_3(0.53, -1.3, 0.4), + K::Point_3(0.73, -1.3, 0.2), + tm2); + + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::clip(tm1, tm2, + params::clip_volume(false) + .face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(vertices(tm1).size() == 6); + } + + { + TriangleMesh tm1, tm2; + std::ifstream("data-coref/cube.off") >> tm1; + + CGAL::make_tetrahedron(K::Point_3(0.53, -1.3, 0.2), + K::Point_3(0.53, 1.1, 0.2), + K::Point_3(0.53, -1.3, 0.4), + K::Point_3(0.73, -1.3, 0.2), + tm2); + PMP::reverse_face_orientations(tm2); + + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::clip(tm1, tm2, + params::clip_volume(false) + .face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(vertices(tm1).size() == 6+8); + } // clip meshes with intersection polyline opened - make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 4, 0), K::Point_3(4, 0, 0), tm1 ); - PMP::clip(tm1, K::Plane_3(1, 0, 0, -2)); - assert(vertices(tm1).size()==4); - CGAL::clear(tm1); + { + TriangleMesh tm1; + make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 4, 0), K::Point_3(4, 0, 0), tm1 ); + PMP::clip(tm1, K::Plane_3(1, 0, 0, -2)); + assert(vertices(tm1).size() == 4); + } - make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 4, 0), K::Point_3(4, 0, 0), tm1 ); - PMP::clip(tm1, K::Plane_3(-1, 0, 0, 2)); - assert(vertices(tm1).size()==3); - CGAL::clear(tm1); + { + TriangleMesh tm1; + make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 4, 0), K::Point_3(4, 0, 0), tm1 ); + PMP::clip(tm1, K::Plane_3(-1, 0, 0, 2)); + assert(vertices(tm1).size() == 3); + } // test with clipper on border edge - make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 1, 0), K::Point_3(1, 0, 0), tm1 ); - PMP::clip(tm1, K::Plane_3(0, 1, 0 , 0)); - assert(vertices(tm1).size()==0); - CGAL::clear(tm1); + { + TriangleMesh tm1; + make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 1, 0), K::Point_3(1, 0, 0), tm1 ); + PMP::clip(tm1, K::Plane_3(0, 1, 0 , 0)); + assert(vertices(tm1).size() == 0); + } - make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 1, 0), K::Point_3(1, 0, 0), tm1 ); - PMP::clip(tm1, K::Plane_3(0, -1, 0 , 0)); - assert(vertices(tm1).size()==4); - CGAL::clear(tm1); + { + TriangleMesh tm1; + make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 1, 0), K::Point_3(1, 0, 0), tm1 ); + PMP::clip(tm1, K::Plane_3(0, -1, 0 , 0)); + assert(vertices(tm1).size() == 4); + } // test with clipper on border edge: full triangle - make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 4, 0), K::Point_3(4, 0, 0), tm1 ); - PMP::clip(tm1, K::Plane_3(0, 0, 1, 0), params::use_compact_clipper(true)); - assert(vertices(tm1).size()!=0); - CGAL::clear(tm1); + { + TriangleMesh tm1; + make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 4, 0), K::Point_3(4, 0, 0), tm1 ); + PMP::clip(tm1, K::Plane_3(0, 0, 1, 0), params::use_compact_clipper(true)); + assert(vertices(tm1).size()!=0); + } - make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 4, 0), K::Point_3(4, 0, 0), tm1 ); - PMP::clip(tm1, K::Plane_3(0, 0, 1, 0), params::use_compact_clipper(false)); - assert(vertices(tm1).size()==0); - CGAL::clear(tm1); + { + TriangleMesh tm1; + make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 4, 0), K::Point_3(4, 0, 0), tm1 ); + PMP::clip(tm1, K::Plane_3(0, 0, 1, 0), params::use_compact_clipper(false)); + assert(vertices(tm1).size() == 0); + } // test tangencies - make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 2, 0), K::Point_3(1, 1, 0), tm1 ); - PMP::clip(tm1, K::Plane_3(1, 0, 0, -1)); - assert(vertices(tm1).size()==3); - CGAL::clear(tm1); + { + TriangleMesh tm1; + make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 2, 0), K::Point_3(1, 1, 0), tm1 ); + PMP::clip(tm1, K::Plane_3(1, 0, 0, -1)); + assert(vertices(tm1).size() == 3); + } - make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 2, 0), K::Point_3(1, 1, 0), tm1 ); - PMP::clip(tm1, K::Plane_3(-1, 0, 0, 1)); - assert(vertices(tm1).size()==0); - CGAL::clear(tm1); + { + TriangleMesh tm1; + make_triangle( K::Point_3(0, 0, 0), K::Point_3(0, 2, 0), K::Point_3(1, 1, 0), tm1 ); + PMP::clip(tm1, K::Plane_3(-1, 0, 0, 1)); + assert(vertices(tm1).size() == 0); + } - make_triangle( K::Point_3(0.5, 0, 0.5), K::Point_3(1, 0.5, 0.5), K::Point_3(0.5, 1, 0.5), tm1 ); - input.open("data-coref/cube.off"); - input >> tm2; - input.close(); - PMP::clip(tm1, tm2, params::face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(vertices(tm1).size()==3); - CGAL::clear(tm1); - CGAL::clear(tm2); + { + TriangleMesh tm1, tm2; + make_triangle( K::Point_3(0.5, 0, 0.5), K::Point_3(1, 0.5, 0.5), K::Point_3(0.5, 1, 0.5), tm1 ); + std::ifstream("data-coref/cube.off") >> tm2; - make_triangle( K::Point_3(0.5, 0, 0.5), K::Point_3(1, 0.5, 0.5), K::Point_3(0.5, 1, 0.5), tm1 ); - input.open("data-coref/cube.off"); - input >> tm2; - input.close(); - PMP::reverse_face_orientations(tm2); - PMP::clip(tm1, tm2, params::face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(vertices(tm1).size()==0); - CGAL::clear(tm1); - CGAL::clear(tm2); + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::clip(tm1, tm2, + params::face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(vertices(tm1).size() == 3); + } + + { + TriangleMesh tm1, tm2; + make_triangle( K::Point_3(0.5, 0, 0.5), K::Point_3(1, 0.5, 0.5), K::Point_3(0.5, 1, 0.5), tm1 ); + std::ifstream("data-coref/cube.off") >> tm2; + + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::reverse_face_orientations(tm2); + PMP::clip(tm1, tm2, + params::face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(vertices(tm1).size() == 0); + } + + // test combinaison of use_compact_clipper and clip_volume + { + TriangleMesh tm1; + std::ifstream("data-coref/cube.off") >> tm1; + + // -> closed mesh, true/true + PMP::clip(tm1, K::Plane_3(-1,0,0,0), params::use_compact_clipper(true).clip_volume(true)); + assert(faces(tm1).size() == 12); + assert(CGAL::is_closed(tm1)); + + // -> closed mesh, false/true + PMP::clip(tm1, K::Plane_3(-1,0,0,0), params::use_compact_clipper(false).clip_volume(true)); + assert(faces(tm1).size() == 12); + assert(CGAL::is_closed(tm1)); + + // -> closed mesh, true/false + PMP::clip(tm1, K::Plane_3(-1,0,0,0), params::use_compact_clipper(true).clip_volume(false)); + assert(faces(tm1).size() == 12); + assert(CGAL::is_closed(tm1)); + + // -> closed mesh, false/false + PMP::clip(tm1, K::Plane_3(1,0,0,-1), params::use_compact_clipper(false).clip_volume(false)); + assert(faces(tm1).size() == 10); + assert(!CGAL::is_closed(tm1)); + + // -> open mesh true/true + PMP::clip(tm1, K::Plane_3(-1,0,0,0), params::use_compact_clipper(true).clip_volume(true)); + assert(faces(tm1).size() == 10); + + // -> open mesh true/false + PMP::clip(tm1, K::Plane_3(-1,0,0,0), params::use_compact_clipper(true).clip_volume(false)); + assert(faces(tm1).size() == 10); + + // -> open mesh false/false + PMP::clip(tm1, K::Plane_3(-1,0,0,0), params::use_compact_clipper(false).clip_volume(false)); + assert(faces(tm1).size() == 8); + + // -> open mesh false/true + PMP::clip(tm1, K::Plane_3(0,-1,0,0), params::use_compact_clipper(false).clip_volume(true)); + assert(faces(tm1).size() == 6); + } // test special case - input.open("data-clip/tm_1.off"); - input >> tm1; - input.close(); - input.open("data-clip/clipper_1.off"); - input >> tm2; - input.close(); - PMP::clip(tm1, tm2, params::face_index_map(get(CGAL::dynamic_face_property_t(), tm1)), - params::face_index_map(get(CGAL::dynamic_face_property_t(), tm2))); - assert(is_valid_polygon_mesh(tm1)); - CGAL::clear(tm1); - CGAL::clear(tm2); + { + TriangleMesh tm1, tm2; + std::ifstream("data-clip/tm_1.off") >> tm2; + std::ifstream("data-clip/clipper_1.off") >> tm2; + + auto custom_face_index_map_1 = get(CGAL::dynamic_face_property_t(), tm1); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_1, tm1); + auto custom_face_index_map_2 = get(CGAL::dynamic_face_property_t(), tm2); + CGAL::BGL::internal::initialize_face_index_map(custom_face_index_map_2, tm2); + + PMP::clip(tm1, tm2, + params::face_index_map(custom_face_index_map_1), + params::face_index_map(custom_face_index_map_2)); + assert(is_valid_polygon_mesh(tm1)); + } // non-manifold border vertices - std::stringstream ss; - ss << "OFF\n 5 2 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 0 1 4\n3 1 2 3\n"; - ss >> tm1; - PMP::clip(tm1, K::Plane_3(-1,0,0,2)); - assert(vertices(tm1).size()==3); - CGAL::clear(tm1); + { + TriangleMesh tm1; + std::stringstream ss; + ss << "OFF\n 5 2 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 0 1 4\n3 1 2 3\n"; + ss >> tm1; + PMP::clip(tm1, K::Plane_3(-1,0,0,2)); + assert(vertices(tm1).size() == 3); + } - ss.str(std::string()); - ss << "OFF\n 7 4 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 1 0\n 1 1 0\n3 0 1 4\n3 1 2 3\n3 1 5 6\n3 1 3 5\n"; - ss >> tm1; - CGAL::Euler::remove_face(halfedge(*std::prev(faces(tm1).end()),tm1),tm1); - PMP::clip(tm1, K::Plane_3(-1,0,0,2)); - assert(vertices(tm1).size()==6); - CGAL::clear(tm1); - - ss.str(std::string()); - ss << "OFF\n 9 7 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 1 0\n 1 1 0\n3 -1 0\n1 -1 0\n3 0 1 4\n3 1 2 3\n3 1 5 6\n3 1 8 7\n3 1 3 5\n3 1 6 4\n3 1 0 8\n"; - ss >> tm1; - for (int i=0;i<3;++i) + { + TriangleMesh tm1; + std::stringstream ss; + ss << "OFF\n 7 4 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 1 0\n 1 1 0\n3 0 1 4\n3 1 2 3\n3 1 5 6\n3 1 3 5\n"; + ss >> tm1; CGAL::Euler::remove_face(halfedge(*std::prev(faces(tm1).end()),tm1),tm1); - PMP::clip(tm1, K::Plane_3(-1,0,0,2)); - assert(vertices(tm1).size()==7); - CGAL::clear(tm1); + PMP::clip(tm1, K::Plane_3(-1,0,0,2)); + assert(vertices(tm1).size() == 6); + } - ss.str(std::string()); - ss << "OFF\n 9 7 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 1 0\n 1 1 0\n3 -1 0\n1 -1 0\n3 0 1 4\n3 1 2 3\n3 1 5 6\n3 1 8 7\n3 1 3 5\n3 1 6 4\n3 1 0 8\n"; - ss >> tm1; - for (int i=0;i<3;++i) - CGAL::Euler::remove_face(halfedge(*std::prev(faces(tm1).end()),tm1),tm1); - PMP::clip(tm1, K::Plane_3(0,1,0,0)); - assert(vertices(tm1).size()==3); - CGAL::clear(tm1); + { + TriangleMesh tm1; + std::stringstream ss; + ss << "OFF\n 9 7 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 1 0\n 1 1 0\n3 -1 0\n1 -1 0\n3 0 1 4\n3 1 2 3\n3 1 5 6\n3 1 8 7\n3 1 3 5\n3 1 6 4\n3 1 0 8\n"; + ss >> tm1; + for (int i=0;i<3;++i) + CGAL::Euler::remove_face(halfedge(*std::prev(faces(tm1).end()),tm1),tm1); + PMP::clip(tm1, K::Plane_3(-1,0,0,2)); + assert(vertices(tm1).size() == 7); + } + + { + TriangleMesh tm1; + std::stringstream ss; + ss << "OFF\n 9 7 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 1 0\n 1 1 0\n3 -1 0\n1 -1 0\n3 0 1 4\n3 1 2 3\n3 1 5 6\n3 1 8 7\n3 1 3 5\n3 1 6 4\n3 1 0 8\n"; + ss >> tm1; + for (int i=0;i<3;++i) + CGAL::Euler::remove_face(halfedge(*std::prev(faces(tm1).end()),tm1),tm1); + PMP::clip(tm1, K::Plane_3(0,1,0,0)); + assert(vertices(tm1).size() == 3); + } + + { + TriangleMesh tm1; + std::stringstream ss; + ss << "OFF\n 9 7 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 1 0\n 1 1 0\n3 -1 0\n1 -1 0\n3 0 1 4\n3 1 2 3\n3 1 5 6\n3 1 8 7\n3 1 3 5\n3 1 6 4\n3 1 0 8\n"; + ss >> tm1; + for (int i=0;i<3;++i) + CGAL::Euler::remove_face(halfedge(*std::prev(faces(tm1).end()),tm1),tm1); + PMP::clip(tm1, K::Plane_3(0,-1,0,0)); + assert(vertices(tm1).size() == 7); + } +} + +template +void test_split_plane() +{ + // test with a clipper mesh + Mesh tm1; + std::ifstream input("data-coref/elephant.off"); + input >> tm1; + + if(!input) + { + std::cerr<<"File not found. Aborting."< meshes; + PMP::split_connected_components(tm1, meshes, params::all_default()); + CGAL_assertion(meshes.size() == 3); + //if the order is not deterministc, put the num_vertices in a list and check + //if the list does contain all those numbers. + CGAL_assertion(num_vertices(meshes[2]) == 48); + CGAL_assertion(num_vertices(meshes[0]) == 1527); + CGAL_assertion(num_vertices(meshes[1]) == 1674); - ss.str(std::string()); - ss << "OFF\n 9 7 0\n 0 0 0\n2 0 0\n4 0 0\n4 1 0\n0 1 0\n3 1 0\n 1 1 0\n3 -1 0\n1 -1 0\n3 0 1 4\n3 1 2 3\n3 1 5 6\n3 1 8 7\n3 1 3 5\n3 1 6 4\n3 1 0 8\n"; - ss >> tm1; - for (int i=0;i<3;++i) - CGAL::Euler::remove_face(halfedge(*std::prev(faces(tm1).end()),tm1),tm1); - PMP::clip(tm1, K::Plane_3(0,-1,0,0)); - assert(vertices(tm1).size()==7); CGAL::clear(tm1); } +template +void test_split() +{ + // test with a clipper mesh + TriangleMesh tm1, tm2; + //closed intersection curves + std::ifstream input("data-coref/elephant.off"); + input >> tm1; + + if(!input) + { + std::cerr<<"File not found. Aborting."<> tm2; + + if(!input) + { + std::cerr<<"File not found. Aborting."< meshes; + + PMP::split(tm1, tm2); + PMP::split_connected_components(tm1, + meshes, + params::all_default()); + + CGAL_assertion(meshes.size() == 5); + //if the order is not deterministc, put the num_vertices in a list and check + //if the list does contain all those numbers. + CGAL_assertion(num_vertices(meshes[0]) == 2641); + CGAL_assertion(num_vertices(meshes[1]) == 159); + CGAL_assertion(num_vertices(meshes[2]) == 142); + CGAL_assertion(num_vertices(meshes[3]) == 83); + CGAL_assertion(num_vertices(meshes[4]) == 104); + + CGAL::clear(tm1); + CGAL::clear(tm2); + meshes.clear(); + + // open intersection curve + input.open("data-clip/split_A.off"); + input >> tm1; + + if(!input) + { + std::cerr<<"File not found. Aborting."<> tm2; + + if(!input) + { + std::cerr<<"File not found. Aborting."<(); - test(); - return 0; + std::cout << "Polyhedron" << std::endl; + test(); + + std::cout << "running test_split with Surface_mesh\n"; + test_split(); + + std::cout << "running test_split_plane with Surface_mesh\n"; + test_split_plane(); + + std::cout << "running test_split with Polyhedron\n"; + test_split(); + + std::cout << "running test_split_plane with Polyhedron\n"; + test_split_plane(); + + std::cout << "Done!" << std::endl; + + return EXIT_SUCCESS; } + + diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_non_conforming_snapping.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_non_conforming_snapping.cpp index 7bdf106c1fa..5a5964ae604 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_non_conforming_snapping.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_non_conforming_snapping.cpp @@ -1,3 +1,6 @@ +//#define CGAL_PMP_SNAP_DEBUG_PP +//#define CGAL_PMP_SNAP_DEBUG_OUTPUT + #include #include @@ -68,6 +71,7 @@ void read_mesh(const char* filename, template void test(const char* filename, const double large_tolerance, + const double good_tolerance, const double small_tolerance) { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; @@ -84,19 +88,19 @@ void test(const char* filename, // zero tolerance, just to test the API CGAL::Constant_property_map tol_pmap_zero(0); - PMP::experimental::snap_border_vertices_non_conforming(sm_cpy, sm_cpy); - PMP::experimental::snap_border_vertices_non_conforming(sm_cpy, sm_cpy, tol_pmap_zero); - PMP::experimental::snap_border_vertices_non_conforming(sm_cpy, sm_cpy, tol_pmap_zero, - CGAL::parameters::geom_traits(Kernel()), - CGAL::parameters::geom_traits(Kernel())); + PMP::experimental::snap_borders(sm_cpy, sm_cpy); + PMP::experimental::snap_borders(sm_cpy, tol_pmap_zero, sm_cpy, tol_pmap_zero); + PMP::experimental::snap_borders(sm_cpy, tol_pmap_zero, sm_cpy, tol_pmap_zero, + CGAL::parameters::geom_traits(Kernel()), + CGAL::parameters::geom_traits(Kernel())); // too big, creates wrong snaps sm_cpy = sm; CGAL::Constant_property_map tol_pmap_large(large_tolerance); - res = PMP::experimental::snap_border_vertices_non_conforming(sm_cpy, tol_pmap_large); + res = PMP::experimental::snap_borders(sm_cpy, tol_pmap_large); std::cout << "snapped: " << res << std::endl; - std::ofstream out1("out1.off"); + std::ofstream out1("too_large.off"); out1.precision(17); out1 << sm_cpy; out1.close(); @@ -104,53 +108,64 @@ void test(const char* filename, // too small sm_cpy = sm; CGAL::Constant_property_map tol_pmap_small(small_tolerance); - res = PMP::experimental::snap_border_vertices_non_conforming(sm_cpy, tol_pmap_small, - CGAL::parameters::geom_traits(Kernel())); + res = PMP::experimental::snap_borders(sm_cpy, tol_pmap_small, + CGAL::parameters::geom_traits(Kernel())); std::cout << "snapped: " << res << std::endl; - std::ofstream out2("out2.off"); + std::ofstream out2("too_small.off"); out2.precision(17); out2 << sm_cpy; out2.close(); - // automatically computed, custom tolerance at each vertex sm_cpy = sm; - res = PMP::experimental::snap_border_vertices_non_conforming(sm_cpy); + CGAL::Constant_property_map tol_pmap_good(good_tolerance); + res = PMP::experimental::snap_borders(sm_cpy, tol_pmap_good); std::cout << "snapped: " << res << std::endl; - std::ofstream out3("out3.off"); + std::ofstream out3("good.off"); out3.precision(17); out3 << sm_cpy; out3.close(); + + // automatically computed, custom tolerance at each vertex + sm_cpy = sm; + res = PMP::experimental::snap_borders(sm_cpy); + std::cout << "snapped: " << res << std::endl; + + std::ofstream out4("custom.off"); + out4.precision(17); + out4 << sm_cpy; + out4.close(); } void test(const char* filename, const double large_tolerance, + const double good_tolerance, const double small_tolerance) { std::cout << "######################## TEST FILE: " << filename << " ################## " << std::endl; std::cout << "~~~~~~~~~~~ TEST EPECK POLYHEDRON ~~~~~~~~~~~" << std::endl; - test(filename, large_tolerance, small_tolerance); + test(filename, large_tolerance, good_tolerance, small_tolerance); std::cout << std::endl << "~~~~~~~~~~~ TEST EPICK POLYHEDRON ~~~~~~~~~~~" << std::endl; - test(filename, large_tolerance, small_tolerance); + test(filename, large_tolerance, good_tolerance, small_tolerance); std::cout << std::endl << "~~~~~~~~~~~ TEST EPICK SURFACE MESH ~~~~~~~~~~~" << std::endl; - test(filename, large_tolerance, small_tolerance); + test(filename, large_tolerance, good_tolerance, small_tolerance); } int main(int, char**) { - test("data_snapping/non_conform_snapping.off", 0.02, 0.001); - test("data_snapping/non-conform_snapping-hole.off", 0.02, 0.001); - test("data_snapping/non_conform_snapping-multiple_ccs.off", 0.02, 0.001); - test("data_snapping/non-conform_snapping-overlap.off", 0.02, 0.001); + test("data_snapping/non_conform_snapping.off", 0.2, 0.01, 0.0001); + test("data_snapping/non-conform_snapping-hole.off", 0.2, 0.01, 0.0001); + test("data_snapping/non_conform_snapping-multiple_ccs.off", 0.02, 0.01, 0.0001); + test("data_snapping/non-conform_snapping-overlap.off", 0.2, 0.01, 0.0001); - test("data_snapping/real_data.off", 1., 0.05); - test("data_snapping/real_data_2.off", 2, 0.1); + test("data_snapping/real_data.off", 1., 0.05, 0.0008); + test("data_snapping/real_data_2.off", 2, 0.05, 0.000001); - test("data_snapping/pig.stl", 20, 0.01); + test("data_snapping/pig.stl", 20, 0.3, 0.001); return EXIT_SUCCESS; } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_snapping.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_snapping.cpp index 3ae3d761799..5a9a535275d 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_snapping.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_snapping.cpp @@ -1,3 +1,5 @@ +// #define CGAL_PMP_SNAP_DEBUG_PP + #include #include @@ -6,6 +8,7 @@ #include #include +#include #include #include @@ -37,7 +40,9 @@ void test_1() Mesh fg_source, fg_target; // empty meshes - std::size_t res = PMP::experimental::snap_border_vertices_onto_vertex_range(fg_source, fg_target); + std::cout << "Empty meshes tests..." << std::endl; + + std::size_t res = PMP::experimental::snap_border_vertices(fg_source, fg_target); assert(res == 0); std::ifstream source_input("data_snapping/border_snapping_source.off"); @@ -47,17 +52,12 @@ void test_1() return; } - std::vector border_vertices; - PMP::border_halfedges(fg_source, std::back_inserter(border_vertices)); - std::cout << border_vertices.size() << " border vertices" << std::endl; - // one empty mesh - std::cout << "Empty meshes tests..." << std::endl; - res = PMP::experimental::snap_border_vertices_onto_vertex_range(fg_source, fg_target); + res = PMP::experimental::snap_border_vertices(fg_source, fg_target); std::cout << "res: " << res << " (expected 0)" << std::endl; assert(res == 0); - res = PMP::experimental::snap_border_vertices_onto_vertex_range(fg_target, halfedges(fg_source), fg_source); + res = PMP::experimental::snap_border_vertices(fg_target, fg_source); std::cout << "res: " << res << " (expected 0)" << std::endl; assert(res == 0); @@ -72,23 +72,35 @@ void test_1() // this epsilon value is too small, nothing happens std::cout << "*********************** EPS = 0.000000001 *************** " << std::endl; + CGAL::Constant_property_map tol_map_small(0.000000001); - res = PMP::experimental::snap_border_vertices_onto_vertex_range(fg_source_cpy, fg_target, tol_map_small); - res = PMP::experimental::snap_border_vertices_onto_vertex_range(fg_source_cpy, halfedges(fg_target), fg_target, tol_map_small); + res = PMP::experimental::snap_border_vertices(fg_source_cpy, tol_map_small, fg_target, tol_map_small); + std::cout << "res: " << res << " (expected 0)" << std::endl; + assert(res == 0); + + std::vector source_halfedge_range; + PMP::internal::vertices_as_halfedges(vertices(fg_source_cpy), fg_source_cpy, std::back_inserter(source_halfedge_range)); + std::vector target_halfedge_range; + PMP::internal::vertices_as_halfedges(vertices(fg_target), fg_target, std::back_inserter(target_halfedge_range)); + + res = PMP::experimental::snap_vertices(source_halfedge_range, fg_source_cpy, tol_map_small, + target_halfedge_range, fg_target, tol_map_small); + std::cout << "res: " << res << " (expected 0)" << std::endl; assert(res == 0); // this epsilon value is too big; everything gets snapped! std::cout << "*********************** EPS = 0.1 *************** " << std::endl; - CGAL::Constant_property_map tol_map_big(0.1); - fg_source_cpy = fg_source; - border_vertices.clear(); + fg_source_cpy = fg_source; + std::vector border_vertices; PMP::border_halfedges(fg_source_cpy, std::back_inserter(border_vertices)); - res = PMP::experimental::snap_vertex_range_onto_vertex_range(border_vertices, fg_source_cpy, - halfedges(fg_target), fg_target, tol_map_big, - params::geom_traits(Kernel()), params::all_default()); + CGAL::Constant_property_map tol_map_big(0.1); + res = PMP::experimental::snap_vertices(border_vertices, fg_source_cpy, tol_map_big, + target_halfedge_range, fg_target, tol_map_big, + params::geom_traits(Kernel()), + params::do_lock_mesh(true)); std::cout << "res: " << res << " (expected 154)" << std::endl; assert(res == 154); @@ -96,24 +108,28 @@ void test_1() // this is a good value of 'epsilon', but not all expected vertices are projected // because the sampling of the border of the source mesh is not uniform std::cout << "*********************** EPS = 0.001 *************** " << std::endl; - CGAL::Constant_property_map tol_map_good(0.001); - fg_source_cpy = fg_source; + fg_source_cpy = fg_source; border_vertices.clear(); PMP::border_halfedges(fg_source_cpy, std::back_inserter(border_vertices)); - res = PMP::experimental::snap_vertex_range_onto_vertex_range(border_vertices, fg_source_cpy, - halfedges(fg_target), fg_target, tol_map_good); + CGAL::Constant_property_map tol_map_good(0.001); + res = PMP::experimental::snap_vertices(border_vertices, fg_source_cpy, tol_map_good, + target_halfedge_range, fg_target, tol_map_good, + params::all_default(), params::do_lock_mesh(true)); std::cout << "res: " << res << " vertices" << std::endl; assert(res == 76); - std::ofstream partial_snap_out("partially_snapped_mesh.off"); - partial_snap_out << std::setprecision(17) << fg_source_cpy; - // this one automatically computes an epsilon bound at each vertex std::cout << "*********************** EPS = LOCALLY COMPUTED *************** " << std::endl; + fg_source_cpy = fg_source; - res = PMP::experimental::snap_border_vertices_onto_vertex_range(fg_source_cpy, fg_target); + border_vertices.clear(); + PMP::border_halfedges(fg_source_cpy, std::back_inserter(border_vertices)); + + res = PMP::experimental::snap_vertices(border_vertices, fg_source_cpy, + target_halfedge_range, fg_target, + params::all_default(), params::do_lock_mesh(true)); std::cout << "res: " << res << " vertices" << std::endl; assert(res == 77); @@ -147,9 +163,11 @@ void test_2() // if a target vertex is already occupied, the source vertex will go to the next one that is // within tolerance and is available CGAL::Constant_property_map tol_map(0.5); - std::size_t res = PMP::experimental::snap_border_vertices_onto_vertex_range(fg_source, fg_target, tol_map); + std::size_t res = PMP::experimental::snap_border_vertices(fg_source, tol_map, fg_target, tol_map); std::cout << "res: " << res << " vertices" << std::endl; assert(res == 3); + + std::ofstream("out.off") << fg_source; } template diff --git a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/CMakeLists.txt b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/CMakeLists.txt index 5572052eb2e..20d0abef1c2 100644 --- a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/CMakeLists.txt +++ b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/CMakeLists.txt @@ -36,58 +36,35 @@ endif() include( CGAL_CreateSingleSourceCGALProgram ) +find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) +if(NOT EIGEN3_FOUND) + message(STATUS "NOTICE: This project requires Eigen 3.1 (or greater) and will not be compiled.") + return() +endif() + +find_package(SCIP QUIET) +if (NOT SCIP_FOUND ) + find_package( GLPK QUIET) + if ( NOT GLPK_FOUND ) + message( STATUS "NOTICE: This project requires either SCIP or GLPK, and will not be compiled.") + return() + endif() +endif() + create_single_source_cgal_program( "polyfit_example_without_input_planes.cpp" ) create_single_source_cgal_program( "polyfit_example_user_provided_planes.cpp" ) create_single_source_cgal_program( "polyfit_example_model_complexty_control.cpp" ) create_single_source_cgal_program( "polyfit_example_with_region_growing.cpp" ) -find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) -if(EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - - find_package( SCIP QUIET) - - if ( NOT SCIP_FOUND ) - find_package( GLPK QUIET) - - if ( NOT GLPK_FOUND ) - message( STATUS "NOTICE: This project requires either SCIP or GLPK, and will not be compiled. " - "Please provide either 'SCIP_DIR' or 'GLPK_INCLUDE_DIR' and 'GLPK_LIBRARIES'") - else() - - - include_directories( BEFORE ${GLPK_INCLUDE_DIR} ) - - target_link_libraries( polyfit_example_without_input_planes PRIVATE ${GLPK_LIBRARIES} ) - target_compile_definitions(polyfit_example_without_input_planes PRIVATE -DCGAL_USE_GLPK) - target_link_libraries( polyfit_example_user_provided_planes PRIVATE ${GLPK_LIBRARIES} ) - target_compile_definitions(polyfit_example_user_provided_planes PRIVATE -DCGAL_USE_GLPK) - target_link_libraries( polyfit_example_model_complexty_control PRIVATE ${GLPK_LIBRARIES} ) - target_compile_definitions(polyfit_example_model_complexty_control PRIVATE -DCGAL_USE_GLPK) - target_link_libraries( polyfit_example_with_region_growing PRIVATE ${GLPK_LIBRARIES} ) - target_compile_definitions(polyfit_example_with_region_growing PRIVATE -DCGAL_USE_GLPK) - - message("GLPK found and used") - - endif() - +foreach(target + polyfit_example_without_input_planes + polyfit_example_user_provided_planes + polyfit_example_model_complexty_control + polyfit_example_with_region_growing) + CGAL_target_use_Eigen(${target}) + if (SCIP_FOUND) + CGAL_target_use_SCIP(${target}) else() - - include_directories( BEFORE ${SCIP_INCLUDE_DIRS} ) - - target_link_libraries( polyfit_example_without_input_planes PRIVATE ${SCIP_LIBRARIES} ) - target_compile_definitions(polyfit_example_without_input_planes PRIVATE -DCGAL_USE_SCIP) - target_link_libraries( polyfit_example_user_provided_planes PRIVATE ${SCIP_LIBRARIES} ) - target_compile_definitions(polyfit_example_user_provided_planes PRIVATE -DCGAL_USE_SCIP) - target_link_libraries( polyfit_example_model_complexty_control PRIVATE ${SCIP_LIBRARIES} ) - target_compile_definitions(polyfit_example_model_complexty_control PRIVATE -DCGAL_USE_SCIP) - target_link_libraries( polyfit_example_with_region_growing PRIVATE ${SCIP_LIBRARIES} ) - target_compile_definitions(polyfit_example_with_region_growing PRIVATE -DCGAL_USE_SCIP) - - message("SCIP found and used") - + CGAL_target_use_GLPK(${target}) endif() - -else() - message(STATUS "NOTICE: Some of the executables in this directory need Eigen 3.1 (or greater) and will not be compiled.") -endif() +endforeach() diff --git a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_model_complexty_control.cpp b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_model_complexty_control.cpp index 53d0a4ad1c3..5e48efa5552 100644 --- a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_model_complexty_control.cpp +++ b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_model_complexty_control.cpp @@ -5,10 +5,10 @@ #include #include -#ifdef CGAL_USE_SCIP +#ifdef CGAL_USE_SCIP // defined (or not) by CMake scripts, do not define by hand #include typedef CGAL::SCIP_mixed_integer_program_traits MIP_Solver; -#elif defined(CGAL_USE_GLPK) +#elif defined(CGAL_USE_GLPK) // defined (or not) by CMake scripts, do not define by hand #include typedef CGAL::GLPK_mixed_integer_program_traits MIP_Solver; #endif diff --git a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_user_provided_planes.cpp b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_user_provided_planes.cpp index 8b56101a76f..e997b671ade 100644 --- a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_user_provided_planes.cpp +++ b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_user_provided_planes.cpp @@ -5,10 +5,10 @@ #include #include -#ifdef CGAL_USE_SCIP +#ifdef CGAL_USE_SCIP // defined (or not) by CMake scripts, do not define by hand #include typedef CGAL::SCIP_mixed_integer_program_traits MIP_Solver; -#elif defined(CGAL_USE_GLPK) +#elif defined(CGAL_USE_GLPK) // defined (or not) by CMake scripts, do not define by hand #include typedef CGAL::GLPK_mixed_integer_program_traits MIP_Solver; #endif diff --git a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_with_region_growing.cpp b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_with_region_growing.cpp index 0cfe1cd02ff..4cc561a8ae6 100644 --- a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_with_region_growing.cpp +++ b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_with_region_growing.cpp @@ -7,12 +7,12 @@ #include #include -#ifdef CGAL_USE_SCIP +#ifdef CGAL_USE_SCIP // defined (or not) by CMake scripts, do not define by hand #include typedef CGAL::SCIP_mixed_integer_program_traits MIP_Solver; -#elif defined(CGAL_USE_GLPK) +#elif defined(CGAL_USE_GLPK) // defined (or not) by CMake scripts, do not define by hand #include typedef CGAL::GLPK_mixed_integer_program_traits MIP_Solver; @@ -196,4 +196,4 @@ int main(int, char**) return EXIT_SUCCESS; } -#endif // defined(CGAL_USE_GLPK) || defined(CGAL_USE_SCIP) \ No newline at end of file +#endif // defined(CGAL_USE_GLPK) || defined(CGAL_USE_SCIP) diff --git a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_without_input_planes.cpp b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_without_input_planes.cpp index 76531b62ed8..cd37cc996f1 100644 --- a/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_without_input_planes.cpp +++ b/Polygonal_surface_reconstruction/examples/Polygonal_surface_reconstruction/polyfit_example_without_input_planes.cpp @@ -6,12 +6,12 @@ #include #include -#ifdef CGAL_USE_SCIP +#ifdef CGAL_USE_SCIP // defined (or not) by CMake scripts, do not define by hand #include typedef CGAL::SCIP_mixed_integer_program_traits MIP_Solver; -#elif defined(CGAL_USE_GLPK) +#elif defined(CGAL_USE_GLPK) // defined (or not) by CMake scripts, do not define by hand #include typedef CGAL::GLPK_mixed_integer_program_traits MIP_Solver; diff --git a/Polygonal_surface_reconstruction/include/CGAL/internal/compute_confidences.h b/Polygonal_surface_reconstruction/include/CGAL/internal/compute_confidences.h index 0c2ceafce8d..51eadd3ce7c 100644 --- a/Polygonal_surface_reconstruction/include/CGAL/internal/compute_confidences.h +++ b/Polygonal_surface_reconstruction/include/CGAL/internal/compute_confidences.h @@ -24,17 +24,10 @@ // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif - +typedef CGAL::Parallel_if_available_tag Concurrency_tag; namespace CGAL { - - - namespace internal { +namespace internal { /** * Computes the confidences of the candidate faces. diff --git a/Polygonal_surface_reconstruction/test/Polygonal_surface_reconstruction/CMakeLists.txt b/Polygonal_surface_reconstruction/test/Polygonal_surface_reconstruction/CMakeLists.txt index e5f6f23675a..9a88f8a5dc6 100644 --- a/Polygonal_surface_reconstruction/test/Polygonal_surface_reconstruction/CMakeLists.txt +++ b/Polygonal_surface_reconstruction/test/Polygonal_surface_reconstruction/CMakeLists.txt @@ -11,7 +11,7 @@ find_package( CGAL QUIET COMPONENTS ) if ( NOT CGAL_FOUND ) - message(STATUS "This project requires the CGAL library, and will not be compiled.") + message(STATUS "NOTICE: This project requires the CGAL library, and will not be compiled.") return() endif() @@ -24,8 +24,11 @@ include( ${CGAL_USE_FILE} ) find_package( Boost REQUIRED ) if ( NOT Boost_FOUND ) - message(STATUS "This project requires the Boost library, and will not be compiled.") + + message(STATUS "NOTICE: This project requires the Boost library, and will not be compiled.") + return() + endif() # Creating entries for all C++ files with "main" routine @@ -33,49 +36,26 @@ endif() include( CGAL_CreateSingleSourceCGALProgram ) -create_single_source_cgal_program( "polygonal_surface_reconstruction_test.cpp" ) find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) -if(EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) - - # Executables that require Eigen 3.1 - find_package( SCIP QUIET) - - if (SCIP_FOUND) - - include_directories( BEFORE ${SCIP_INCLUDE_DIRS} ) - - target_link_libraries( polygonal_surface_reconstruction_test PRIVATE ${SCIP_LIBRARIES} ) - - target_compile_definitions(polygonal_surface_reconstruction_test PRIVATE -DCGAL_USE_SCIP) - - message("SCIP found and used") - - endif() - - - find_package( GLPK QUIET) - - if (GLPK_FOUND) - - include_directories( BEFORE ${GLPK_INCLUDE_DIR} ) - - target_link_libraries( polygonal_surface_reconstruction_test PRIVATE ${GLPK_LIBRARIES} ) - - target_compile_definitions(polygonal_surface_reconstruction_test PRIVATE -DCGAL_USE_GLPK) - - message("GLPK found and used") - - endif() - - - if (NOT SCIP_FOUND AND NOT GLPK_FOUND) - - message(STATUS "NOTICE: This project requires either SCIP or GLPK, some functions will not be tested. " - "Please provide either 'SCIP_DIR' or 'GLPK_INCLUDE_DIR' and 'GLPK_LIBRARIES'") - - endif() -else() - message(STATUS "NOTICE: Some of the executables in this directory need Eigen 3.1 (or greater) and will not be compiled.") +if(NOT EIGEN3_FOUND) + message(STATUS "NOTICE: This project requires Eigen 3.1 (or greater) and will not be compiled.") + return() +endif() + +find_package(SCIP QUIET) +if (NOT SCIP_FOUND ) + find_package( GLPK QUIET) + if ( NOT GLPK_FOUND ) + message( STATUS "NOTICE : This project requires either SCIP or GLPK, and will not be compiled.") + return() + endif() +endif() + +create_single_source_cgal_program( "polygonal_surface_reconstruction_test.cpp") +CGAL_target_use_Eigen(polygonal_surface_reconstruction_test) +if (SCIP_FOUND) + CGAL_target_use_SCIP(polygonal_surface_reconstruction_test) +else() + CGAL_target_use_GLPK(polygonal_surface_reconstruction_test) endif() diff --git a/Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp b/Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp index 07c630b7828..50b969ed1bc 100644 --- a/Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp +++ b/Polyhedron/demo/Polyhedron/CGAL_double_edit.cpp @@ -1,5 +1,5 @@ #include "CGAL_double_edit.h" - +#include #include class DoubleValidator : public QDoubleValidator @@ -59,7 +59,7 @@ public: void DoubleEdit::setRange(double min, double max) { - this->validator->setRange(min, max); + this->validator->setRange(min, max, this->validator->decimals()); } double DoubleEdit::getValue() diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index 6427dc55d7d..6d3f9dc346f 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -64,7 +64,7 @@ include(${CGAL_USE_FILE}) find_package(Qt5 QUIET COMPONENTS OpenGL Script - OPTIONAL_COMPONENTS ScriptTools) + OPTIONAL_COMPONENTS ScriptTools WebSockets) if(Qt5_FOUND) @@ -73,9 +73,6 @@ if(Qt5_FOUND) endif(Qt5_FOUND) find_package(Eigen3 3.2.0) #(requires 3.2.0 or greater) -if (EIGEN3_FOUND) - include( ${EIGEN3_USE_FILE} ) -endif(EIGEN3_FOUND) find_package( METIS ) @@ -95,6 +92,11 @@ if( POLYHEDRON_DEMO_ACTIVATE_CONCURRENCY ) endif() endif() +#find libssh for scene sharing +find_package(LibSSH) +if( NOT LIBSSH_FOUND ) + message("NOTICE : The SSH features will be disabled.") +endif() # Activate concurrency ? (turned OFF by default) option(CGAL_ACTIVATE_CONCURRENT_MESH_3 @@ -131,7 +133,7 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) qt5_wrap_ui( statisticsUI_FILES Statistics_on_item_dialog.ui) qt5_wrap_ui( FileLoaderDialogUI_files FileLoaderDialog.ui ) qt5_wrap_ui( Show_point_dialogUI_FILES Show_point_dialog.ui ) - qt5_wrap_ui( PreferencesUI_FILES Preferences.ui Details.ui) + qt5_wrap_ui( PreferencesUI_FILES Preferences.ui Details.ui SSH_dialog.ui) qt5_wrap_ui( Show_point_dialogUI_FILES Show_point_dialog.ui ) qt5_wrap_ui( ViewerUI_FILES LightingDialog.ui) qt5_generate_moc( "File_loader_dialog.h" "${CMAKE_CURRENT_BINARY_DIR}/File_loader_dialog_moc.cpp" ) @@ -195,6 +197,11 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) target_link_libraries(demo_framework PUBLIC Qt5::OpenGL Qt5::Widgets Qt5::Gui Qt5::Script ) + if(TARGET Qt5::WebSockets) + target_link_libraries(demo_framework PUBLIC Qt5::WebSockets) + message(STATUS "Qt5WebSockets was found. Using WebSockets is therefore possible.") + endif() + cgal_add_compilation_test(demo_framework) # Let's define `three_EXPORT` during the compilation of `demo_framework`, # in addition of `demo_framework_EXPORT` (defined automatically by @@ -251,7 +258,10 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) add_item(scene_edit_box_item Plugins/PCA/Scene_edit_box_item.cpp ) add_item(scene_image_item Scene_image_item.cpp) add_item(scene_surface_mesh_item Scene_surface_mesh_item.cpp) - + + if(TBB_FOUND) + CGAL_target_use_TBB(scene_surface_mesh_item) + endif() # special add_item(scene_item_decorator Scene_polyhedron_item_decorator.cpp ) @@ -262,6 +272,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) @@ -270,12 +283,15 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) if(EIGEN3_FOUND ) add_item(scene_textured_item Scene_textured_surface_mesh_item.cpp texture.cpp) + CGAL_target_use_Eigen(scene_textured_item) qt5_wrap_ui( editionUI_FILES Plugins/Surface_mesh_deformation/Deform_mesh.ui ) add_item(scene_edit_item Plugins/Surface_mesh_deformation/Scene_edit_polyhedron_item.cpp ${editionUI_FILES}) + CGAL_target_use_Eigen(scene_edit_item) target_link_libraries(scene_edit_item PUBLIC scene_surface_mesh_item scene_k_ring_selection scene_basic_objects) add_item(scene_mcf_item Plugins/PMP/Scene_mcf_item.cpp) + CGAL_target_use_Eigen(scene_mcf_item) endif() add_item(scene_implicit_function_item Scene_implicit_function_item.cpp ) @@ -287,19 +303,19 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) add_item(scene_nef_polyhedron_item Scene_nef_polyhedron_item.cpp) target_link_libraries(scene_nef_polyhedron_item PUBLIC scene_surface_mesh_item) + add_item(scene_points_with_normal_item Scene_points_with_normal_item.cpp) + if (EIGEN3_FOUND) + CGAL_target_use_Eigen(scene_points_with_normal_item) + endif() + find_package(LASLIB) if (LASLIB_FOUND) - include(${LASLIB_USE_FILE}) - include_directories(${LASLIB_INCLUDE_DIR}) - include_directories(${LASZIP_INCLUDE_DIR}) - add_item(scene_points_with_normal_item Scene_points_with_normal_item.cpp) + CGAL_target_use_LASLIB(scene_points_with_normal_item) if (MSVC) target_compile_definitions( scene_points_with_normal_item PUBLIC "-D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS") endif() - target_link_libraries( scene_points_with_normal_item PUBLIC ${LASLIB_LIBRARIES}) - else() - add_item(scene_points_with_normal_item Scene_points_with_normal_item.cpp) endif() + if(TBB_FOUND) CGAL_target_use_TBB(scene_points_with_normal_item) endif() @@ -323,11 +339,20 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) MainWindow.cpp Polyhedron_demo.cpp File_loader_dialog_moc.cpp + Use_ssh.cpp ${CGAL_Qt5_RESOURCE_FILES} ${CGAL_Qt5_MOC_FILES} ${FileLoaderDialogUI_files} ${MainWindowUI_files} ${PreferencesUI_FILES} ${statisticsUI_FILES} ${SubViewerUI_files}) target_link_libraries(polyhedron_demo PUBLIC demo_framework point_dialog Qt5::Gui Qt5::OpenGL Qt5::Widgets Qt5::Script) + if(LIBSSH_FOUND) + add_definitions(-DCGAL_USE_SSH) + target_link_libraries(polyhedron_demo PUBLIC ${LIBSSH_LIBRARIES}) + endif() #libssh + if(TARGET Qt5::WebSockets) + add_definitions(-DCGAL_USE_WEBSOCKETS) + target_link_libraries(polyhedron_demo PUBLIC Qt5::WebSockets) + endif() add_executable ( Polyhedron_3 Polyhedron_3.cpp ) target_link_libraries( Polyhedron_3 PRIVATE polyhedron_demo ) add_to_cached_list( CGAL_EXECUTABLE_TARGETS Polyhedron_3 ) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index 04e48f8668e..e4d325c567c 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -1,3 +1,6 @@ +#ifdef CGAL_USE_SSH +# include "CGAL/Use_ssh.h" +#endif #include #include "config.h" @@ -7,6 +10,7 @@ #include #include #include +#include #include #include @@ -38,10 +42,11 @@ #include #include #include -#include +#include #include #include #include +#include #ifdef QT_SCRIPT_LIB # include # ifdef QT_SCRIPTTOOLS_LIB @@ -58,6 +63,7 @@ #include "ui_Preferences.h" #include "ui_Details.h" #include "ui_Statistics_on_item_dialog.h" +#include "ui_SSH_dialog.h" #include "Show_point_dialog.h" #include "File_loader_dialog.h" #include "Viewer.h" @@ -69,6 +75,14 @@ # include # include #include "Color_map.h" + + +#ifdef CGAL_USE_WEBSOCKETS +#include +#include +#include +#endif + using namespace CGAL::Three; QScriptValue myScene_itemToScriptValue(QScriptEngine *engine, @@ -150,6 +164,7 @@ MainWindow::MainWindow(const QStringList &keywords, bool verbose, QWidget* paren // remove the Load Script menu entry, when the demo has not been compiled with QT_SCRIPT_LIB #if !defined(QT_SCRIPT_LIB) ui->menuBar->removeAction(ui->actionLoadScript); + ui->menuBar->removeAction(ui->on_actionLoad_a_Scene_from_a_Script_File); #endif // Save some pointers from ui, for latter use. sceneView = ui->sceneView; @@ -158,9 +173,9 @@ MainWindow::MainWindow(const QStringList &keywords, bool verbose, QWidget* paren CGAL::Three::Three::s_mainviewer = viewer; viewer->setObjectName("mainViewer"); viewer_window->showMaximized(); - viewer_window->setWindowFlags( + viewer_window->setWindowFlags( Qt::SubWindow - | Qt::CustomizeWindowHint + | Qt::CustomizeWindowHint | Qt::WindowMaximizeButtonHint | Qt::WindowSystemMenuHint | Qt::WindowTitleHint @@ -353,7 +368,7 @@ MainWindow::MainWindow(const QStringList &keywords, bool verbose, QWidget* paren // Load plugins, and re-enable actions that need it. operationSearchBar.setPlaceholderText("Filter..."); - searchAction->setDefaultWidget(&operationSearchBar); + searchAction->setDefaultWidget(&operationSearchBar); connect(&operationSearchBar, &QLineEdit::textChanged, this, [=](){filterOperations(true);}); loadPlugins(); @@ -451,7 +466,7 @@ void filterMenuOperations(QMenu* menu, QString filter, bool keep_from_here) action->setVisible(!(submenu->isEmpty())); } - else if(action->text().contains(filter, Qt::CaseInsensitive)){ + else if(action->text().remove("&").contains(filter, Qt::CaseInsensitive)){ //menu->addAction(action); addActionToMenu(action, menu); } @@ -491,7 +506,7 @@ void MainWindow::filterOperations(bool) Q_FOREACH(const PluginNamePair& p, plugins) { Q_FOREACH(QAction* action, p.first->actions()) { action->setVisible( p.first->applicable(action) - && (action->text().contains(filter, Qt::CaseInsensitive) + && (action->text().remove("&").contains(filter, Qt::CaseInsensitive) || action->property("subMenuName") .toString().contains(filter, Qt::CaseInsensitive))); } @@ -689,7 +704,7 @@ bool MainWindow::load_plugin(QString fileName, bool blacklisted) else{ //qdebug << "error: " << qPrintable(loader.errorString()); pluginsStatus_map[name] = loader.errorString(); - + } PathNames_map[name].push_back(fileinfo.absoluteDir().absolutePath()); return true; @@ -933,7 +948,7 @@ void MainWindow::viewerShow(float xmin, } void MainWindow::viewerShow(Viewer_interface* vi, float x, float y, float z) { - + CGAL::qglviewer::ManipulatedCameraFrame backup_frame(*vi->camera()->frame()); vi->camera()->fitSphere(CGAL::qglviewer::Vec(x, y, z), vi->camera()->sceneRadius()/100); @@ -1000,20 +1015,25 @@ void MainWindow::computeViewerBBox(CGAL::qglviewer::Vec& min, CGAL::qglviewer::V const double xmax = bbox.xmax(); const double ymax = bbox.ymax(); const double zmax = bbox.zmax(); - - - + + + min = CGAL::qglviewer::Vec(xmin, ymin, zmin); max= CGAL::qglviewer::Vec(xmax, ymax, zmax); - + CGAL::qglviewer::Vec bbox_center((xmin+xmax)/2, (ymin+ymax)/2, (zmin+zmax)/2); - CGAL::qglviewer::Vec offset(0,0,0); + double bbox_diag = CGAL::approximate_sqrt( + CGAL::square(xmax - xmin) + + CGAL::square(ymax - ymin) + + CGAL::square(zmax - zmin)); + CGAL::qglviewer::Vec offset(0,0,0); + double l_dist = (std::max)((std::abs)(bbox_center.x - viewer->offset().x), (std::max)((std::abs)(bbox_center.y - viewer->offset().y), (std::abs)(bbox_center.z - viewer->offset().z))); - if((std::log2)(l_dist) > 13.0 ) + if((std::log2)(l_dist/bbox_diag) > 13.0 ) for(int i=0; i<3; ++i) { offset[i] = -bbox_center[i]; @@ -1197,6 +1217,10 @@ void MainWindow::open(QString filename) selected_items << io_plugin->name(); } } + //if no plugin is correct, offer them all. + for(CGAL::Three::Polyhedron_demo_io_plugin_interface* io_plugin : io_plugins) { + all_items << io_plugin->name(); + } } else selected_items << *dfs_it; @@ -1231,7 +1255,7 @@ void MainWindow::open(QString filename) settings.setValue("OFF open directory", fileinfo.absoluteDir().absolutePath()); loadItem(fileinfo, findLoader(load_pair.first), ok); - + if(!ok) return; this->addToRecentFiles(fileinfo.absoluteFilePath()); @@ -1418,7 +1442,7 @@ void MainWindow::selectionChanged() { if(vi == NULL) continue; - + if(item != NULL && item->manipulatable()) { vi->setManipulatedFrame(item->manipulatedFrame()); } else { @@ -1477,11 +1501,11 @@ void MainWindow::showSceneContextMenu(int selectedItemIndex, this, SLOT(reloadItem())); } QAction* saveas = menu->addAction(tr("&Save as...")); - saveas->setData(qVariantFromValue((void*)item)); + saveas->setData(QVariant::fromValue((void*)item)); connect(saveas, SIGNAL(triggered()), this, SLOT(on_actionSaveAs_triggered())); QAction* showobject = menu->addAction(tr("&Zoom to this Object")); - showobject->setData(qVariantFromValue((void*)item)); + showobject->setData(QVariant::fromValue((void*)item)); connect(showobject, SIGNAL(triggered()), this, SLOT(viewerShowObject())); @@ -1489,6 +1513,7 @@ void MainWindow::showSceneContextMenu(int selectedItemIndex, } } menu->addMenu(ui->menuOperations); + if(menu) menu->exec(global_pos); } @@ -1552,7 +1577,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { menu_actions["line width"] = action->menu()->actions().last(); } } - + } Q_FOREACH(Scene::Item_id index, scene->selectionIndices()) { @@ -1585,7 +1610,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { )->value()); slider->setOrientation(Qt::Horizontal); sliderAction->setDefaultWidget(slider); - + connect(slider, &QSlider::valueChanged, [this, slider]() { Q_FOREACH(Scene::Item_id id, scene->selectionIndices()) @@ -1620,7 +1645,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { )->value()); slider->setOrientation(Qt::Horizontal); sliderAction->setDefaultWidget(slider); - + connect(slider, &QSlider::valueChanged, [this, slider]() { Q_FOREACH(Scene::Item_id id, scene->selectionIndices()) @@ -1655,7 +1680,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { )->value()); slider->setOrientation(Qt::Horizontal); sliderAction->setDefaultWidget(slider); - + connect(slider, &QSlider::valueChanged, [this, slider]() { Q_FOREACH(Scene::Item_id id, scene->selectionIndices()) @@ -1698,7 +1723,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { )->value()); slider->setOrientation(Qt::Horizontal); sliderAction->setDefaultWidget(slider); - + connect(slider, &QSlider::valueChanged, [this, slider]() { Q_FOREACH(Scene::Item_id id, scene->selectionIndices()) @@ -1751,6 +1776,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { QAction* saveas = menu.addAction(tr("&Save as...")); connect(saveas, SIGNAL(triggered()), this, SLOT(on_actionSaveAs_triggered())); + menu.addMenu(ui->menuOperations); menu.exec(sender->mapToGlobal(p)); return; } @@ -1804,7 +1830,12 @@ void MainWindow::readSettings() viewer->setFastDrawing(settings.value("quick_camera_mode", true).toBool()); scene->enableVisibilityRecentering(settings.value("offset_update", false).toBool()); viewer->textRenderer()->setMax(settings.value("max_text_items", 10000).toInt()); - viewer->setTotalPass(settings.value("transparency_pass_number", 4).toInt()); + int val = settings.value("transparency_pass_number", 4).toInt(); + if (val < 4 ) { + val = 4; + settings.setValue("transparency_pass_number", 4); + } + viewer->setTotalPass(val); CGAL::Three::Three::s_defaultSMRM = CGAL::Three::Three::modeFromName( settings.value("default_sm_rm", "flat+edges").toString()); CGAL::Three::Three::s_defaultPSRM = CGAL::Three::Three::modeFromName( @@ -1816,6 +1847,7 @@ void MainWindow::readSettings() this->default_point_size = settings.value("points_size").toInt(); this->default_normal_length = settings.value("normals_length").toInt(); this->default_lines_width = settings.value("lines_width").toInt(); + setProperty("ws_url", settings.value("ws_server_url").toString()); } void MainWindow::writeSettings() @@ -1890,14 +1922,7 @@ void MainWindow::throw_exception() { void MainWindow::on_actionLoadScript_triggered() { #if defined(QT_SCRIPT_LIB) - QString filename = QFileDialog::getOpenFileName( - this, - tr("Select a script to run..."), - ".", - "QTScripts (*.js);;All Files (*)"); - if(filename.isEmpty()) - return; - loadScript(QFileInfo(filename)); + #endif } @@ -1927,7 +1952,7 @@ void MainWindow::on_actionLoad_triggered() filters << filter; } } - + QString directory = settings.value("OFF open directory", QDir::current().dirName()).toString(); @@ -1955,7 +1980,7 @@ void MainWindow::on_actionLoad_triggered() static_cast(nb_files), std::back_inserter(colors_)); std::size_t nb_item = -1; - + Q_FOREACH(const QString& filename, dialog.selectedFiles()) { CGAL::Three::Scene_item* item = NULL; @@ -2180,7 +2205,7 @@ void MainWindow::on_actionShowHide_triggered() item->redraw(); } scene->setUpdatesEnabled(true); - updateViewersBboxes(false); +// updateViewersBboxes(false); //Not usable :when the scene changes scale, smaller items disappear. } void MainWindow::on_actionSetPolyhedronA_triggered() @@ -2200,7 +2225,6 @@ void MainWindow::on_actionPreferences_triggered() QDialog dialog(this); Ui::PreferencesDialog prefdiag; prefdiag.setupUi(&dialog); - float lineWidth[2]; if(!viewer->isOpenGL_4_3()) viewer->glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidth); @@ -2211,22 +2235,22 @@ void MainWindow::on_actionPreferences_triggered() } prefdiag.linesHorizontalSlider->setMinimum(lineWidth[0]); prefdiag.linesHorizontalSlider->setMaximum(lineWidth[1]); - + prefdiag.offset_updateCheckBox->setChecked( settings.value("offset_update", false).toBool()); connect(prefdiag.offset_updateCheckBox, SIGNAL(toggled(bool)), scene, SLOT(enableVisibilityRecentering(bool))); - + prefdiag.antialiasingCheckBox->setChecked(settings.value("antialiasing", false).toBool()); connect(prefdiag.antialiasingCheckBox, SIGNAL(toggled(bool)), viewer, SLOT(setAntiAliasing(bool))); - + prefdiag.quick_cameraCheckBox->setChecked( settings.value("quick_camera_mode", true).toBool()); connect(prefdiag.quick_cameraCheckBox, SIGNAL(toggled(bool)), viewer, SLOT(setFastDrawing(bool))); prefdiag.max_itemsSpinBox->setValue(viewer->textRenderer()->getMax_textItems()); - + connect(prefdiag.max_itemsSpinBox,static_cast(&QSpinBox::valueChanged), this, [this](int i){ setMaxTextItemsDisplayed(i); @@ -2257,20 +2281,20 @@ void MainWindow::on_actionPreferences_triggered() }); connect(prefdiag.background_colorPushButton, &QPushButton::clicked, this, &MainWindow::setBackgroundColor); - + connect(prefdiag.default_save_asPushButton, &QPushButton::clicked, this, &MainWindow::setDefaultSaveDir); - + connect(prefdiag.lightingPushButton, &QPushButton::clicked, this, &MainWindow::setLighting_triggered); - + prefdiag.surface_meshComboBox->setCurrentText(CGAL::Three::Three::modeName( CGAL::Three::Three::s_defaultSMRM)); connect(prefdiag.surface_meshComboBox, &QComboBox::currentTextChanged, this, [this](const QString& text){ this->s_defaultSMRM = CGAL::Three::Three::modeFromName(text); }); - + prefdiag.point_setComboBox->setCurrentText(CGAL::Three::Three::modeName( CGAL::Three::Three::s_defaultPSRM)); connect(prefdiag.point_setComboBox, &QComboBox::currentTextChanged, @@ -2344,6 +2368,70 @@ void MainWindow::on_actionPreferences_triggered() }); dialog.exec(); }); + connect(prefdiag.sshButton, &QPushButton::clicked, + this, [this](){ + QDialog dialog(this); + Ui::SSHDialog sshdiag; + sshdiag.setupUi(&dialog); + +#ifdef CGAL_USE_SSH + sshdiag.userBox->setEnabled(true); + sshdiag.serverBox->setEnabled(true); + sshdiag.pkBox->setEnabled(true); + sshdiag.privkBox->setEnabled(true); + sshdiag.userEdit->setText(settings.value("ssh_user", QString()).toString()); + sshdiag.serverEdit->setText(settings.value("ssh_server", QString()).toString()); + sshdiag.publicEdit->setText(settings.value("ssh_public_key", QString()).toString()); + sshdiag.privkEdit->setText(settings.value("ssh_priv_key", QString()).toString()); + connect(sshdiag.pubButton, &QPushButton::clicked, + this, [this, sshdiag](){ + QFileDialog diag(this, + "Public Key", + "", + "All Files (*)"); + diag.setFilter(QDir::Hidden|QDir::Files|QDir::Dirs|QDir::NoDotAndDotDot); + if(!diag.exec()) + return; + sshdiag.publicEdit->setText(diag.selectedFiles().front()); + }); + connect(sshdiag.privButton, &QPushButton::clicked, + this, [this, sshdiag](){ + QFileDialog diag(this, + "Private Key", + "", + "All Files (*)"); + diag.setFilter(QDir::Hidden|QDir::Files|QDir::Dirs|QDir::NoDotAndDotDot); + if(!diag.exec()) + return; + sshdiag.privkEdit->setText(diag.selectedFiles().front()); + }); +#else + sshdiag.userBox->setEnabled(false); + sshdiag.serverBox->setEnabled(false); + sshdiag.pkBox->setEnabled(false); + sshdiag.privkBox->setEnabled(false); +#endif + sshdiag.wsEdit->setText(settings.value("ws_server_url", QString()).toString()); + + dialog.exec(); + if ( dialog.result() ) + { +#ifdef CGAL_USE_SSH + settings.setValue("ssh_user", + sshdiag.userEdit->text()); + settings.setValue("ssh_server", + sshdiag.serverEdit->text()); + settings.setValue("ssh_public_key", + sshdiag.publicEdit->text()); + settings.setValue("ssh_priv_key", + sshdiag.privkEdit->text()); +#endif + settings.setValue("ws_server_url", + sshdiag.wsEdit->text()); + setProperty("ws_url", sshdiag.wsEdit->text()); + } + }); + dialog.exec(); if ( dialog.result() ) @@ -2356,7 +2444,7 @@ void MainWindow::on_actionPreferences_triggered() if (item->checkState(0)==Qt::Unchecked) plugin_blacklist.insert(item->text(1)); } - + //write settings settings.setValue("antialiasing", prefdiag.antialiasingCheckBox->isChecked()); @@ -2376,7 +2464,7 @@ void MainWindow::on_actionPreferences_triggered() settings.setValue("points_size", this->default_point_size); settings.setValue("normals_length", this->default_normal_length); settings.setValue("lines_width", this->default_lines_width); - + } else { @@ -2396,7 +2484,7 @@ void MainWindow::setBackgroundColor() v->update(); } } - + } void MainWindow::setLighting_triggered() @@ -2558,7 +2646,7 @@ QString MainWindow::get_item_stats() Q_FOREACH(int id, scene->selectionIndices()) { Scene_item* item = scene->item(id); - QString classname = item->property("classname").toString(); + QString classname = item->property("classname").toString(); if(classname.isEmpty()) classname = item->metaObject()->className(); if(!classnames.contains(classname)) @@ -2785,53 +2873,183 @@ void MainWindow::propagate_action() } } +QString make_fullpath(const QString& filename, bool duplicate = false) +{ + QString fullpath = QString("%1/%2").arg(QDir::tempPath()).arg(filename); + QString tmp_fullpath = fullpath; + if(duplicate) + { + int i=0; + while(QFileInfo(tmp_fullpath).exists()) + { + QString basename = QFileInfo(tmp_fullpath).baseName(); + QString dir = QFileInfo(tmp_fullpath).dir().path(); + QString suffix= QFileInfo(fullpath).completeSuffix(); + tmp_fullpath=QString("%1/%2%3.%4").arg(dir).arg(basename).arg(++i).arg(suffix); + } + } + return tmp_fullpath; +} +/* + The two following functions allow to create files from string and strings from files. + This is used as a workaround of the absence of stream management in our IO system. + The whole to/from Base64 is used to avoid problems with binary formats. Everything is written + as a base64 binary string, and converted back to what it was. +*/ +QByteArray file_to_string(const char* filename) +{ + std::ifstream f(filename, std::ifstream::binary); + // get size of file + f.seekg (0,f.end); + long size = f.tellg(); + f.seekg (0); + std::ostringstream ss; + // allocate memory for file content + char* buffer = new char[size]; + + // read content of infile + f.read(buffer,size); + + // write to outfile + ss.write(buffer,size); + // release dynamically-allocated memory + delete[] buffer; + //ss.write( << f.rdbuf(); // reading data + f.close(); + std::string st = ss.str(); + QByteArray ba(st.c_str(), static_cast(st.size())); + return ba; +} + +QString MainWindow::write_string_to_file(const QString& str, const QString &filename) +{ + QString fullpath = make_fullpath(filename); + std::ofstream f(fullpath.toStdString().c_str(), std::ofstream::binary); + QByteArray compressed_item(str.toStdString().c_str()); + QByteArray item = qUncompress(QByteArray::fromBase64(compressed_item)); + QByteArray bb = item; + f.write(bb.constData(),bb.toStdString().size()); + f.close(); + return fullpath; +} + void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() { - QString filename = - QFileDialog::getSaveFileName(this, - "Save the Scene as a Script File", - last_saved_dir, - "Qt Script files (*.js)"); - std::ofstream os(filename.toUtf8()); + if(scene->numberOfEntries() == 0) + return; + bool do_upload = false; +#ifdef CGAL_USE_SSH + QString user = settings.value("ssh_user", QString()).toString(); + QString pass; + if(!user.isEmpty()) + { + QMessageBox::StandardButton doyou = + QMessageBox::question(this, tr("Upload ?"), tr("Do you wish to upload the scene" + " using the SSH preferences ?")); + bool ok; + do_upload = (doyou == QMessageBox::Yes); + if(do_upload) + { + pass = QInputDialog::getText(this, "SSH Password", + "Enter ssh key password:", + QLineEdit::Password, + tr(""), + &ok); + if(!ok) + return; + pass = pass.trimmed(); + } + } +#endif + + QString filename; + + if(do_upload){ + filename = QString("%1/save_scene.js").arg(QDir::tempPath()); + }else{ + filename = QFileDialog::getSaveFileName(this, + "Save the Scene as a Script File", + last_saved_dir, + "Qt Script files (*.js)"); + } + std::ofstream os(filename.toUtf8(), std::ofstream::binary); if(!os) return; - std::vector names; - std::vector loaders; + CGAL::Three::Three::CursorScopeGuard cs(Qt::WaitCursor); + std::vector > names; + std::vector > loaders; std::vector colors; std::vector rendering_modes; QStringList not_saved; for(int i = 0; i < scene->numberOfEntries(); ++i) { Scene_item* item = scene->item(i); - QString loader = item->property("loader_name").toString(); - QString source = item->property("source filename").toString(); + QString loader;// = item->property("loader_name").toString(); + QString ext; + for(Polyhedron_demo_io_plugin_interface* iop : io_plugins) + { + if(iop->isDefaultLoader(item)) + { + QString sf = iop->saveNameFilters().split(";;").first(); + //OFF Files (*.off) + QRegularExpression re("\\(\\*\\.(.*)\\)"); + QRegularExpressionMatch rem = re.match(sf); + if(!rem.hasMatch()) + continue; + ext = rem.captured(1); + QListto_save; + to_save.append(item); + QString savename(tr("%1.%2").arg(item->name()).arg(ext)); + QString fullpath = make_fullpath(savename, true); + savename = QFileInfo(fullpath).fileName(); + iop->save(QFileInfo(fullpath), to_save); + names.push_back(std::make_pair(savename, item->name())); + loader=iop->name(); + break; + } + } if(loader.isEmpty()) { - not_saved.push_back(item->name()); + QMessageBox::warning(this, "", tr("No plugin found for %1. Not saved.").arg(item->name())); continue; } - names.push_back(source); - loaders.push_back(loader); + loaders.push_back(std::make_pair(loader, ext)); colors.push_back(item->color()); rendering_modes.push_back(item->renderingMode()); } + if(loaders.empty()) + return; //path os << "var camera = \""<dumpCameraCoordinates().toStdString()<<"\";\n"; os << "var items = ["; for(std::size_t i = 0; i< names.size() -1; ++i) { - os << "\'" << names[i].toStdString() << "\', "; + QString fullpath = make_fullpath(names[i].first); + + QByteArray item = file_to_string(fullpath.toStdString().c_str()); + os<<"[\'"; + os<show(); } visibleDockWidgets.clear(); - + } } @@ -2914,7 +3191,7 @@ void MainWindow::setupViewer(Viewer* viewer, SubViewer* subviewer) viewer, SLOT(update())); connect(scene, SIGNAL(updated()), viewer, SLOT(update())); - + QAction* action = subviewer->findChild("actionRecenter"); connect(action, SIGNAL(triggered()), viewer, SLOT(update())); @@ -2976,16 +3253,43 @@ void MainWindow::setupViewer(Viewer* viewer, SubViewer* subviewer) this, SLOT(selectSceneItem(int))); connect(viewer, SIGNAL(selectedPoint(double, double, double)), this, SLOT(showSelectedPoint(double, double, double))); - + connect(viewer, SIGNAL(selectionRay(double, double, double, double, double, double)), scene, SIGNAL(selectionRay(double, double, double, double, double, double))); - + connect(viewer, &Viewer::sendMessage, this, [](QString s){ information(s); }); + +#ifdef CGAL_USE_WEBSOCKETS + action= subviewer->viewer->findChild("actionShareCamera"); + connect(action, &QAction::toggled, + this, [this, viewer](bool b) + { + if(!viewer){ + return; + } + QString session; + if(b){ + bool ok; + session = QInputDialog::getText( + this,"Session", + "Please enter the session name.\n" + "Only the machines that enter the same session name will be connected.\n" + "Several sessions can run simultaneously on a same server. ", + QLineEdit::Normal, QString(), &ok); + if(session.isEmpty() || !ok) + { + viewer->setShareCam(false, session); + return; + } + } + viewer->setShareCam(b, session); + }); +#endif } @@ -3005,7 +3309,7 @@ void MainWindow::on_actionAdd_Viewer_triggered() scene->removeViewer(viewer2); viewerDestroyed(viewer2); }); - + setupViewer(viewer2, subviewer); viewer2->camera()->interpolateToFitScene(); subviewer->show(); @@ -3138,11 +3442,20 @@ SubViewer::SubViewer(QWidget *parent, MainWindow* mw, Viewer* mainviewer) QAction* actionTotalPass = new QAction("Set Transparency Pass &Number...",this); actionTotalPass->setObjectName("actionTotalPass"); viewMenu->addAction(actionTotalPass); +#ifdef CGAL_USE_WEBSOCKETS + QAction* actionShareCamera= new QAction("Join &WS Server",viewer); + actionShareCamera->setObjectName("actionShareCamera"); + actionShareCamera->setCheckable(true); + actionShareCamera->setChecked(false); + viewMenu->addAction(actionShareCamera); +#endif + QAction* actionBackFrontShading = new QAction("Activate Back/Front shading.",this); actionBackFrontShading->setObjectName("actionBackFrontShading"); actionBackFrontShading->setCheckable(true); actionBackFrontShading->setChecked(false); viewMenu->addAction(actionBackFrontShading); + if(mainviewer) setAttribute(Qt::WA_DeleteOnClose); setWindowIcon(QIcon(":/cgal/icons/resources/menu.png")); @@ -3173,9 +3486,9 @@ void SubViewer::lookat() if (viewer->camera()->frame()->isSpinning()) viewer->camera()->frame()->stopSpinning(); mw->viewerShow(viewer, - (float)dialog.get_x(), - (float)dialog.get_y(), - (float)dialog.get_z()); + (float)dialog.get_x() + viewer->offset().x, + (float)dialog.get_y() + viewer->offset().y, + (float)dialog.get_z() + viewer->offset().z); } } @@ -3190,7 +3503,7 @@ void SubViewer::color() void SubViewer::closeEvent(QCloseEvent *closeEvent) { - + if(is_main) { QMessageBox::information(mw, "", "This is the main viewer. It cannot be closed."); @@ -3211,9 +3524,9 @@ void SubViewer::changeEvent(QEvent *event) { menu->addAction(action); } - setWindowFlags( + setWindowFlags( Qt::SubWindow - | Qt::CustomizeWindowHint + | Qt::CustomizeWindowHint | Qt::WindowMaximizeButtonHint //| Qt::WindowSystemMenuHint | Qt::WindowTitleHint @@ -3229,9 +3542,9 @@ void SubViewer::changeEvent(QEvent *event) { menu->removeAction(action); } - setWindowFlags( + setWindowFlags( Qt::SubWindow - | Qt::CustomizeWindowHint + | Qt::CustomizeWindowHint | Qt::WindowMaximizeButtonHint | Qt::WindowSystemMenuHint | Qt::WindowTitleHint @@ -3253,7 +3566,7 @@ void MainWindow::invalidate_bbox(bool do_recenter) void MainWindow::on_action_Save_triggered() { - if(QMessageBox::question(this, "Save", "Are you sure you want to override these files ?") + if(QMessageBox::question(this, "Save", "Are you sure you want to override these files ?") == QMessageBox::No) return; QList to_save; @@ -3269,3 +3582,189 @@ void MainWindow::on_action_Save_triggered() } } } + +void MainWindow::on_actionLoad_a_Scene_from_a_Script_File_triggered() +{ + bool do_download = false; + QString filename; + +#ifdef CGAL_USE_SSH + QString user = settings.value("ssh_user", QString()).toString(); + QString pass; + if(!user.isEmpty()) + { + QMessageBox::StandardButton doyou = + QMessageBox::question(this, tr("Download ?"), tr("Do you wish to download the scene" + " using the SSH preferences ?")); + bool ok; + do_download= (doyou == QMessageBox::Yes); + if(do_download) + { + pass = QInputDialog::getText(this, "SSH Password", + "Enter ssh key password:", + QLineEdit::Password, + tr(""), + &ok); + if(!ok) + return; + pass = pass.trimmed(); + } + } +#endif + + if(do_download) + { + #ifdef CGAL_USE_SSH + using namespace CGAL::ssh_internal; + QString server = settings.value("ssh_server", QString()).toString(); + QString pk = settings.value("ssh_public_key", QString()).toString(); + QString privK = settings.value("ssh_priv_key", QString()).toString(); + user = user.trimmed(); + server = server.trimmed(); + pk = pk.trimmed(); + privK=privK.trimmed(); + QString path; + path = QInputDialog::getText(this, + "", + tr("Enter the name of the scene file.")); + if(path.isEmpty()) + return; + if(!path.contains("Polyhedron_demo_")) + path.prepend("Polyhedron_demo_"); + try{ + ssh_session session; + bool res = establish_ssh_session(session, + user.toStdString().c_str(), + server.toStdString().c_str(), + pk.toStdString().c_str(), + privK.toStdString().c_str(), + pass.toStdString().c_str()); + if(!res) + { + QMessageBox::warning(this, + "Error", + "The SSH session could not be started."); + return; + } + filename = QString("%1/load_scene.js").arg(QDir::tempPath()); + path = tr("/tmp/%2").arg(path); + res = pull_file(session,path.toStdString().c_str(), filename.toStdString().c_str()); + if(!res) + { + QMessageBox::warning(this, + "Error", + "The file could not be fetched. Check your console for more info."); + close_connection(session); + return; + } + close_connection(session); + } catch( ssh::SshException e ) + { + std::cout << "Error during connection : "; + std::cout << e.getError() << std::endl; + } + #endif + } + else + { + filename = QFileDialog::getOpenFileName( + this, + tr("Select a Whole Scene file..."), + ".", + "Whole Scene files (*.js)"); + if(filename.isEmpty()) + return; + } + loadScript(QFileInfo(filename)); + if(do_download){ + QFile tmp_file(filename); + tmp_file.remove(); + } +} + +#ifdef CGAL_USE_WEBSOCKETS +void MainWindow::on_action_Start_a_Session_triggered() +{ + QAction * action= findChild("action_Start_a_Session"); + static EchoServer *server =nullptr; + if(action->isChecked()){ + server = new EchoServer(1234); + QObject::connect(server, &EchoServer::closed, server,&EchoServer::deleteLater); + } + else + { + server->deleteLater(); + } +} + +EchoServer::EchoServer(quint16 port) : + QObject(CGAL::Three::Three::mainWindow()), + m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Echo Server"), + QWebSocketServer::NonSecureMode, this)) +{ + if (m_pWebSocketServer->listen(QHostAddress::Any, port)) { + connect(m_pWebSocketServer, &QWebSocketServer::newConnection, + this, &EchoServer::onNewConnection); + connect(m_pWebSocketServer, &QWebSocketServer::closed, this, &EchoServer::closed); + } + QHostAddress local_host("0.0.0.0"); + + //to avoid printing 127.0.0.1. Not realy sure it won't ever print the external ipv4 though. + const QHostAddress &localhost = QHostAddress(QHostAddress::LocalHost); + for (const QHostAddress &address: QNetworkInterface::allAddresses()) { + if (address.protocol() == QAbstractSocket::IPv4Protocol && address != localhost) + { + local_host= address; + break; + } + } + QMessageBox mb(QMessageBox::NoIcon, "WS Server", + tr("WebSockets Server started.\nEnter the following address in\nyour Network Preferences to be able to join it :\n" + "ws://%1:%2").arg(local_host.toString()).arg(port), QMessageBox::Ok, CGAL::Three::Three::mainWindow()); + mb.setTextInteractionFlags(Qt::TextSelectableByMouse); + mb.exec(); +} + +EchoServer::~EchoServer() +{ + m_pWebSocketServer->close(); + qDeleteAll(m_clients.begin(), m_clients.end()); +} + +void EchoServer::onNewConnection() +{ + QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection(); + + connect(pSocket, &QWebSocket::textMessageReceived, this, &EchoServer::processTextMessage); + connect(pSocket, &QWebSocket::binaryMessageReceived, this, &EchoServer::processBinaryMessage); + connect(pSocket, &QWebSocket::disconnected, this, &EchoServer::socketDisconnected); + + m_clients << pSocket; +} + +void EchoServer::processTextMessage(QString message) +{ + QWebSocket *pClient = qobject_cast(sender()); + for(auto *client : m_clients) { + if(client != pClient) + client->sendTextMessage(message); + } +} + +void EchoServer::processBinaryMessage(QByteArray message) +{ + QWebSocket *pClient = qobject_cast(sender()); + if (pClient) { + pClient->sendBinaryMessage(message); + } +} + +void EchoServer::socketDisconnected() +{ + QWebSocket *pClient = qobject_cast(sender()); + if (pClient) { + m_clients.removeAll(pClient); + pClient->deleteLater(); + } +} +#endif diff --git a/Polyhedron/demo/Polyhedron/MainWindow.h b/Polyhedron/demo/Polyhedron/MainWindow.h index e4bd6d5b3b1..b7650b52b34 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.h +++ b/Polyhedron/demo/Polyhedron/MainWindow.h @@ -138,6 +138,8 @@ public Q_SLOTS: This slot is for use by scripts.*/ bool open(QString filename, QString loader_name); + QString write_string_to_file(const QString &str, const QString& filename); + /*! Reloads an item. Expects to be called by a QAction with the index of the item to be reloaded as data attached to the action. The index must identify a valid `Scene_item`.*/ @@ -352,6 +354,10 @@ protected Q_SLOTS: void save(QString filename, QList& to_save); //!Calls the function saveSnapShot of the viewer. void on_actionSaveSnapshot_triggered(); +#ifdef CGAL_USE_WEBSOCKETS + //!Starts a new WS server if none is already exist. Else, does nothing. + void on_action_Start_a_Session_triggered(); +#endif //!Opens a Dialog to choose a color and make it the background color. void setBackgroundColor(); //!Opens a Dialog to change the lighting settings @@ -447,6 +453,7 @@ public: #endif public Q_SLOTS: void on_actionSa_ve_Scene_as_Script_triggered(); + void on_actionLoad_a_Scene_from_a_Script_File_triggered(); void toggleFullScreen(); void setDefaultSaveDir(); void invalidate_bbox(bool do_recenter); @@ -494,4 +501,30 @@ protected: private: bool is_main; }; +#ifdef CGAL_USE_WEBSOCKETS +QT_FORWARD_DECLARE_CLASS(QWebSocketServer) +QT_FORWARD_DECLARE_CLASS(QWebSocket) + +class EchoServer : public QObject +{ + Q_OBJECT +public: + explicit EchoServer(quint16 port); + ~EchoServer(); + + +Q_SIGNALS: + void closed(); + +private Q_SLOTS: + void onNewConnection(); + void processTextMessage(QString message); + void processBinaryMessage(QByteArray message); + void socketDisconnected(); + +private: + QWebSocketServer *m_pWebSocketServer; + QList m_clients; +}; +#endif #endif // ifndef MAINWINDOW_H diff --git a/Polyhedron/demo/Polyhedron/MainWindow.ui b/Polyhedron/demo/Polyhedron/MainWindow.ui index a011dedab64..6273a37bd16 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.ui +++ b/Polyhedron/demo/Polyhedron/MainWindow.ui @@ -58,6 +58,7 @@ + @@ -96,6 +97,7 @@ + @@ -463,6 +465,22 @@ &Save + + + Load a Scene &from a Script File... + + + + + true + + + &Start a Session + + + Start a WebSocket Server to Share your Camera with Others on your Network. + + diff --git a/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp index d7a3863ce3a..d23ff947d9a 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp @@ -27,7 +27,7 @@ #include -#include +#include #include #include @@ -860,6 +860,12 @@ public: return ok; } + bool isDefaultLoader(const Scene_item* item) const Q_DECL_OVERRIDE{ + if(qobject_cast(item)) + return true; + return false; + } + using Polyhedron_demo_io_plugin_interface::init; void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface* m) override; @@ -1241,7 +1247,7 @@ void Polyhedron_demo_cut_plugin::computeIntersection() Simple_kernel::Plane_3 plane(n[0], n[1], n[2], - n * pos); //std::cerr << plane << std::endl; edges_item->edges.clear(); - QTime time; + QElapsedTimer time; time.start(); bool does_intersect = false; for(Facet_sm_trees::iterator it = facet_sm_trees.begin(); it != facet_sm_trees.end(); ++it) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/Classification/CMakeLists.txt index c0b3eded9c2..f272d98b4cd 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/CMakeLists.txt @@ -2,73 +2,51 @@ include( polyhedron_demo_macros ) if(EIGEN3_FOUND) - set(classification_linked_libraries) - set(classification_compile_definitions) - - find_package(Boost OPTIONAL_COMPONENTS serialization iostreams) + set(Classification_dependencies_met TRUE) - if( WIN32 ) -# to avoid a warning with old cmake - set(_Boost_BZIP2_HEADERS "boost/iostreams/filter/bzip2.hpp") - set(_Boost_ZLIB_HEADERS "boost/iostreams/filter/zlib.hpp") - find_package( Boost OPTIONAL_COMPONENTS serialization iostreams bzip2 zlib) - if( Boost_ZLIB_FOUND AND Boost_BZIP2_FOUND) - if(TARGET Boost::bzip2 AND TARGET Boost::zlib) - set(classification_linked_libraries ${classification_linked_libraries} - Boost::bzip2 Boost::zlib) - else() - set(classification_linked_libraries ${classification_linked_libraries} - ${Boost_ZLIB_LIBRARY} ${Boost_BZIP2_LIBRARY}) - endif() - endif() + find_package( Boost OPTIONAL_COMPONENTS serialization iostreams ) + if (NOT Boost_SERIALIZATION_FOUND) + message(STATUS "NOTICE: Boost Serialization not found. Classification plugin won't be available.") + set(Classification_dependencies_met FALSE) + endif() + + if (NOT Boost_IOSTREAMS_FOUND) + message(STATUS "NOTICE: Boost IOStreams not found. Classification plugin won't be available.") + set(Classification_dependencies_met FALSE) endif() - if (Boost_SERIALIZATION_FOUND AND Boost_IOSTREAMS_FOUND AND (NOT WIN32 OR Boost_ZLIB_FOUND)) + find_package(OpenCV QUIET COMPONENTS core ml) # Need core + machine learning + if (NOT OpenCV_FOUND) + message(STATUS "NOTICE: OpenCV was not found. OpenCV random forest predicate for classification won't be available.") + endif() + + find_package(TensorFlow QUIET) + if (NOT TensorFlow_FOUND) + message(STATUS "NOTICE: TensorFlow not found, Neural Network predicate for classification won't be available.") + endif() + + if (Classification_dependencies_met) qt5_wrap_ui( classificationUI_FILES Classification_widget.ui Classification_advanced_widget.ui ) polyhedron_demo_plugin(classification_plugin Classification_plugin Point_set_item_classification Cluster_classification Surface_mesh_item_classification ${classificationUI_FILES} KEYWORDS Classification) - - if(TARGET Boost::serialization AND TARGET Boost::iostreams) - set(classification_linked_libraries ${classification_linked_libraries} - Boost::serialization Boost::iostreams) - else() - set(classification_linked_libraries ${classification_linked_libraries} - ${Boost_SERIALIZATION_LIBRARY} - ${Boost_IOSTREAMS_LIBRARY}) + target_link_libraries(classification_plugin PUBLIC scene_points_with_normal_item + scene_polylines_item scene_polygon_soup_item scene_surface_mesh_item scene_selection_item scene_color_ramp) + + CGAL_target_use_Eigen(classification_plugin) + CGAL_target_use_Boost_IOStreams(classification_plugin) + CGAL_target_use_Boost_Serialization(classification_plugin) + if(OpenCV_FOUND) + CGAL_target_use_OpenCV(classification_plugin) endif() - - find_package(OpenCV QUIET COMPONENTS core ml) # Need core + machine learning - if (OpenCV_FOUND) - message(STATUS "Found OpenCV ${OpenCV_VERSION}") - include_directories(${OpenCV_INCLUDE_DIRS}) - set(classification_linked_libraries ${classification_linked_libraries} - ${OpenCV_LIBS}) - set(classification_compile_definitions ${classification_compile_definitions} - "-DCGAL_LINKED_WITH_OPENCV") - else() - message(STATUS "NOTICE: OpenCV was not found. OpenCV random forest predicate for classification won't be available.") + if(TensorFlow_FOUND) + CGAL_target_use_TensorFlow(classification_plugin) endif() - - find_package(TensorFlow QUIET) - if (TensorFlow_FOUND) - message(STATUS "Found TensorFlow") - set(classification_linked_libraries ${classification_linked_libraries} - ${TensorFlow_LIBRARY}) - set(classification_compile_definitions ${classification_compile_definitions} - "-DCGAL_LINKED_WITH_TENSORFLOW") - include_directories( ${TensorFlow_INCLUDE_DIR} ) - else() - message(STATUS "NOTICE: TensorFlow not found, Neural Network predicate for classification won't be available.") + if(TBB_FOUND) + CGAL_target_use_TBB(classification_plugin) endif() - target_link_libraries(classification_plugin PUBLIC scene_points_with_normal_item - scene_polylines_item scene_polygon_soup_item scene_surface_mesh_item scene_selection_item scene_color_ramp ${classification_linked_libraries}) add_dependencies(classification_plugin point_set_selection_plugin selection_plugin) - target_compile_definitions(classification_plugin PUBLIC ${classification_compile_definitions}) - else() - message(STATUS "NOTICE: Boost Serialization or IO Streams or ZLIB not found. Classification plugin won't be available.") endif() - else(EIGEN3_FOUND) message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Classification plugin will not be available.") endif() diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.h b/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.h index fd88c9e7507..090827a4c89 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.h @@ -15,12 +15,7 @@ #include -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif - +typedef CGAL::Parallel_if_available_tag Concurrency_tag; class Cluster_classification : public Item_classification_base { diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.h b/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.h index 3ddee5310c3..3eb2b503a4c 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.h @@ -16,13 +16,7 @@ #include -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif - - +typedef CGAL::Parallel_if_available_tag Concurrency_tag; // This class represents a point set in the OpenGL scene class Point_set_item_classification : public Item_classification_base diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.h b/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.h index e690a208951..0fcc827b04a 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.h @@ -16,11 +16,7 @@ #include -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; class Surface_mesh_item_classification : public Item_classification_base { diff --git a/Polyhedron/demo/Polyhedron/Plugins/Convex_decomposition/Nef_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Convex_decomposition/Nef_plugin.cpp index 2d932bed12c..f93d72df11d 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Convex_decomposition/Nef_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Convex_decomposition/Nef_plugin.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include using namespace CGAL::Three; class Polyhedron_demo_nef_plugin : @@ -115,7 +115,7 @@ Polyhedron_demo_nef_plugin::on_actionToNef_triggered() } QApplication::setOverrideCursor(Qt::WaitCursor); - QTime time; + QElapsedTimer time; time.start(); std::cerr << "Convert facegraph to nef polyhedron..."; @@ -146,7 +146,7 @@ Polyhedron_demo_nef_plugin::on_actionConvexDecomposition_triggered() : qobject_cast(scene->item(index)); QApplication::restoreOverrideCursor(); if(item) { - QTime time; + QElapsedTimer time; time.start(); std::cerr << "Convex decomposition..."; @@ -188,7 +188,7 @@ Polyhedron_demo_nef_plugin::on_actionToPoly_triggered() if(item) { QApplication::setOverrideCursor(Qt::WaitCursor); - QTime time; + QElapsedTimer time; time.start(); std::cerr << "Convert nef polyhedron to facegraph..."; @@ -277,7 +277,7 @@ void Polyhedron_demo_nef_plugin::boolean_operation(const Boolean_operation opera // perform Boolean operation std::cout << "Boolean operation..."; - QTime time; + QElapsedTimer time; time.start(); switch(operation) { diff --git a/Polyhedron/demo/Polyhedron/Plugins/Convex_hull/Convex_hull_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Convex_hull/Convex_hull_plugin.cpp index 860b88e4461..b973eeae32f 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Convex_hull/Convex_hull_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Convex_hull/Convex_hull_plugin.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -74,34 +74,21 @@ void Polyhedron_demo_convex_hull_plugin::on_actionConvexHull_triggered() // wait cursor QApplication::setOverrideCursor(Qt::WaitCursor); - QTime time; + QElapsedTimer time; time.start(); std::cout << "Convex hull..."; // add convex hull as new polyhedron SMesh *pConvex_hull = new SMesh; - typedef boost::property_map::type Vpmap; - typedef CGAL::Property_map_to_unary_function Vpmap_fct; if(selection_item) { SMesh* pMesh = selection_item->polyhedron(); - Vpmap vpm = get(CGAL::vertex_point,*pMesh); - - Vpmap_fct v2p(vpm); CGAL::convex_hull_3( - boost::make_transform_iterator(selection_item->selected_vertices.begin(), v2p), - boost::make_transform_iterator(selection_item->selected_vertices.end(), v2p), - *pConvex_hull); + *pMesh, + *pConvex_hull); } else if ( sm_item ){ SMesh* pMesh = sm_item->polyhedron(); - Vpmap vpm = get(CGAL::vertex_point,*pMesh); - - Vpmap_fct v2p(vpm); - boost::graph_traits::vertex_iterator b,e; - boost::tie(b,e) = vertices(*pMesh); - - CGAL::convex_hull_3(boost::make_transform_iterator(b,v2p), - boost::make_transform_iterator(e,v2p), + CGAL::convex_hull_3(*pMesh, *pConvex_hull); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/Display/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/Display/CMakeLists.txt index 88145266135..c783cd751ac 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Display/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/Display/CMakeLists.txt @@ -3,4 +3,5 @@ if(EIGEN3_FOUND) qt5_wrap_ui( display_propertyUI_FILES Display_property.ui ) polyhedron_demo_plugin(display_property_plugin Display_property_plugin ${display_propertyUI_FILES}) target_link_libraries(display_property_plugin PUBLIC scene_surface_mesh_item scene_points_with_normal_item scene_color_ramp) + CGAL_target_use_Eigen(display_property_plugin) endif(EIGEN3_FOUND) diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/3mf_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/3mf_io_plugin.cpp index d2e34e4e00e..90f036e8cea 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/3mf_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/3mf_io_plugin.cpp @@ -78,61 +78,6 @@ class Io_3mf_plugin: std::vector names; QList result; std::vector > all_colors; - int nb_polylines = - CGAL::read_polylines_from_3mf(fileinfo.filePath().toUtf8().toStdString(), - all_points, all_colors, names); - if(nb_polylines < 0 ) - { - ok = false; - std::cerr << "Error in reading of meshes."<polylines; - polylines.push_back(all_points[i]); - pol_item->setName(names[i].data()); - pol_item->invalidateOpenGLBuffers(); - CGAL::Color c = all_colors[i].front(); - pol_item->setColor(QColor(c.red(), c.green(), c.blue())); - pol_item->setProperty("already_colord", true); - result << pol_item; - if(add_to_scene) - CGAL::Three::Three::scene()->addItem(pol_item); - } - all_points.clear(); - all_colors.clear(); - names.clear(); - int nb_point_sets = - CGAL::read_point_clouds_from_3mf(fileinfo.filePath().toUtf8().toStdString(), - all_points, all_colors, names); - if(nb_point_sets < 0 ) - { - ok = false; - std::cerr << "Error in reading of meshes."<point_set()->insert(all_points[i][j]); - } - pts_item->setName(names[i].data()); - pts_item->invalidateOpenGLBuffers(); - CGAL::Color c = all_colors[i].front(); - pts_item->setColor(QColor(c.red(), c.green(), c.blue())); - pts_item->setProperty("already_colord", true); - result << pts_item; - if(add_to_scene) - CGAL::Three::Three::scene()->addItem(pts_item); - } - all_points.clear(); - names.clear(); - all_colors.clear(); int nb_meshes = CGAL::read_triangle_soups_from_3mf(fileinfo.filePath().toUtf8().toStdString(), all_points, all_polygons, all_colors, names); diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/IO/CMakeLists.txt index 616414c3f4d..c4487f3b768 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/CMakeLists.txt @@ -71,8 +71,9 @@ else() if (LASLIB_FOUND) polyhedron_demo_plugin(las_plugin LAS_io_plugin KEYWORDS IO PointSetProcessing Classification) - target_link_libraries(las_plugin PUBLIC scene_points_with_normal_item ${LASLIB_LIBRARIES}) + target_link_libraries(las_plugin PUBLIC scene_points_with_normal_item) target_compile_features(las_plugin PRIVATE ${needed_cxx_features}) + CGAL_target_use_LASLIB(las_plugin) else() message(STATUS "NOTICE : the LAS IO plugin needs LAS libraries and will not be compiled.") endif() @@ -80,14 +81,15 @@ endif() find_path(3MF_INCLUDE_DIR NAMES Model/COM/NMR_DLLInterfaces.h + PATH_SUFFIXES lib3mf DOC "Path to lib3MF headers" ) find_library(3MF_LIBRARIES NAMES 3MF DOC "Path to the lib3MF library") -if(3MF_LIBRARIES AND 3MF_INCLUDE_DIR) +if(3MF_LIBRARIES AND 3MF_INCLUDE_DIR AND EXISTS "${3MF_INCLUDE_DIR}/Model/COM/NMR_DLLInterfaces.h") include_directories(${3MF_INCLUDE_DIR}) polyhedron_demo_plugin(3mf_io_plugin 3mf_io_plugin KEYWORDS IO PMP) target_link_libraries(3mf_io_plugin PRIVATE scene_surface_mesh_item scene_points_with_normal_item scene_polylines_item ${3MF_LIBRARIES}) else() - message(STATUS "NOTICE : The 3mf_io_plugin requires the lib3MF library, and will not be compiled.") + message(STATUS "NOTICE : The 3mf_io_plugin requires the lib3MF library in a version < 2.0, and will not be compiled.") endif() diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp index 4aab33b4e0a..22b2ed695d4 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp @@ -15,13 +15,18 @@ class Polyhedron_demo_io_nef_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0" FILE "nef_io_plugin.json") public: - QString nameFilters() const; - QString name() const { return "io_nef_plugin"; } - bool canLoad(QFileInfo) const; - QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true); + QString nameFilters() const override; + QString name() const override { return "io_nef_plugin"; } + bool canLoad(QFileInfo) const override; + QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override; - bool canSave(const CGAL::Three::Scene_item*); - bool save(QFileInfo fileinfo,QList& items); + bool canSave(const CGAL::Three::Scene_item*) override; + bool save(QFileInfo fileinfo,QList& items) override; + bool isDefaultLoader(const Scene_item* item) const override{ + if(qobject_cast(item)) + return true; + return false; + } }; QString Polyhedron_demo_io_nef_plugin::nameFilters() const { diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp index 580023022f7..6b195e276c4 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, @@ -26,28 +29,28 @@ class Polyhedron_demo_off_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90" FILE "off_io_plugin.json") public: - bool isDefaultLoader(const Scene_item *item) const + bool isDefaultLoader(const Scene_item *item) const override { if(qobject_cast(item) || qobject_cast(item)) return true; return false; } - bool isDefaultLoader(const QString& name) const + bool isDefaultLoader(const QString& name) const override { if(name == QString("off")) return true; return false; } - QString name() const { return "off_plugin"; } - QString nameFilters() const { return "OFF files (*.off);;Wavefront OBJ (*.obj)"; } - bool canLoad(QFileInfo fileinfo) const; - QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true); + QString name() const override{ return "off_plugin"; } + QString nameFilters() const override { return "OFF files (*.off);;Wavefront OBJ (*.obj)"; } + bool canLoad(QFileInfo fileinfo) const override; + QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override; CGAL::Three::Scene_item* load_off(QFileInfo fileinfo); CGAL::Three::Scene_item* load_obj(QFileInfo fileinfo); - bool canSave(const CGAL::Three::Scene_item*); - bool save(QFileInfo fileinfo,QList& ); + bool canSave(const CGAL::Three::Scene_item*) override; + bool save(QFileInfo fileinfo,QList& ) override; }; bool Polyhedron_demo_off_plugin::canLoad(QFileInfo) const { @@ -133,7 +136,10 @@ Polyhedron_demo_off_plugin::load_off(QFileInfo fileinfo) { // Try to read .off in a surface_mesh SMesh *surface_mesh = new SMesh(); try{ - in >> *surface_mesh; + if(!(in >> *surface_mesh)) + { + surface_mesh->clear(); + } } catch(...) { surface_mesh->clear(); @@ -186,7 +192,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/Plugins/IO/PLY_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/PLY_io_plugin.cpp index 6ce2fdeb793..75c2e1d9845 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/PLY_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/PLY_io_plugin.cpp @@ -23,19 +23,19 @@ class Polyhedron_demo_ply_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90" FILE "ply_io_plugin.json") public: - bool isDefaultLoader(const CGAL::Three::Scene_item *item) const + bool isDefaultLoader(const CGAL::Three::Scene_item *item) const override { if(qobject_cast(item)) return true; return false; } - QString name() const { return "ply_plugin"; } - QString nameFilters() const { return "PLY files (*.ply)"; } - bool canLoad(QFileInfo fileinfo) const; - QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true); + QString name() const override{ return "ply_plugin"; } + QString nameFilters() const override{ return "PLY files (*.ply)"; } + bool canLoad(QFileInfo fileinfo) const override; + QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true)override; - bool canSave(const CGAL::Three::Scene_item*); - bool save(QFileInfo fileinfo,QList&); + bool canSave(const CGAL::Three::Scene_item*)override; + bool save(QFileInfo fileinfo,QList&)override; }; diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp index d86309749f8..d9fe0b44e0d 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp @@ -75,6 +75,12 @@ public: return QList()<(item)) + return true; + return false; + } protected Q_SLOTS: //!Splits the selected Scene_polylines_item in multiple items all containing a single polyline. void split(); diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/STL_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/STL_io_plugin.cpp index 66d08020a49..1e9ac373d86 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/STL_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/STL_io_plugin.cpp @@ -6,19 +6,24 @@ #include #include -#include #include #include #include +#include #include #include #include #include #include + #include +#include +#include +#include +#include using namespace CGAL::Three; class Polyhedron_demo_stl_plugin : @@ -79,11 +84,19 @@ load(QFileInfo fileinfo, bool& ok, bool add_to_scene){ return QList(); } - try{ + try + { // Try building a surface_mesh SMesh* SM = new SMesh(); if (CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh(triangles)) - CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, triangles, *SM); + { + auto pmap = CGAL::internal::boost_::make_function_property_map, Point_3>( + [](const std::array& a) { return Point_3(a[0], a[1], a[2]); }); + CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, triangles, *SM, + CGAL::parameters::point_map(pmap), + CGAL::parameters::all_default()); + } + if(!SM->is_valid() || SM->is_empty()){ std::cerr << "Error: Invalid facegraph" << std::endl; } diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/VTK_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/VTK_io_plugin.cpp index 1c340b8f2ad..362709853c6 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/VTK_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/VTK_io_plugin.cpp @@ -290,10 +290,11 @@ public: QString nameFilters() const { - return "VTK PolyData files (*.vtk);; VTK XML PolyData (*.vtp);; VTK XML UnstructuredGrid (*.vtu)"; } + return "VTK XML UnstructuredGrid (*.vtu);;VTK PolyData files (*.vtk);; VTK XML PolyData (*.vtp)"; } QString name() const { return "vtk_plugin"; } bool canSave(const CGAL::Three::Scene_item* item) { + return (qobject_cast(item) || qobject_cast(item)); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/lcc_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/lcc_io_plugin.cpp index 71c47452676..55a3a7e1b14 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/lcc_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/lcc_io_plugin.cpp @@ -17,24 +17,24 @@ class LCC_io_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90" FILE "lcc_io_plugin.json") public: - bool isDefaultLoader(const CGAL::Three::Scene_item *item) const + bool isDefaultLoader(const CGAL::Three::Scene_item *item) const override { if(qobject_cast(item)) return true; return false; } - QString name() const { return "lcc_plugin"; } - QString nameFilters() const { return + QString name() const override{ return "lcc_plugin"; } + QString nameFilters() const override{ return "OFF files (*.off);;" "3-map files (*.3map)"; } - QString saveNameFilters() const { + QString saveNameFilters() const override{ return "3-map files (*.3map)"; } - bool canLoad(QFileInfo) const { return true; } - QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true){ + bool canLoad(QFileInfo) const override{ return true; } + QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override{ // Open file std::ifstream ifs(fileinfo.filePath().toUtf8()); if(!ifs) { @@ -67,8 +67,8 @@ public: } - bool canSave(const CGAL::Three::Scene_item*){return false;} - bool save(QFileInfo, QList& ){ + bool canSave(const CGAL::Three::Scene_item*)override{return false;} + bool save(QFileInfo, QList& )override{ return false; } diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_2/Mesh_2_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_2/Mesh_2_plugin.cpp index c552ae91eb0..c746fdd3752 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_2/Mesh_2_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_2/Mesh_2_plugin.cpp @@ -35,7 +35,7 @@ #include -#include +#include #include #include #include @@ -264,14 +264,14 @@ private: typedef CGAL::Delaunay_mesh_size_criteria_2 Criteria; typedef CGAL::Delaunay_mesher_2 Mesher; - QTime time; // global timer + QElapsedTimer time; // global timer time.start(); std::cout << " Building Constrained_Delaunay_triangulation_2..." << std::flush; CDT cdt; - QTime ltime; //local timer + QElapsedTimer ltime; //local timer ltime.start(); double constant_coordinate = polylines_items.back()->polylines.back().back()[constant_coordinate_index]; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp index 4a7c004be2b..21a0d5c6207 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp @@ -18,15 +18,20 @@ class Polyhedron_demo_c3t3_binary_io_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90" FILE "c3t3_io_plugin.json") public: - QString name() const { return "C3t3_io_plugin"; } - QString nameFilters() const { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma)"; } - QString saveNameFilters() const { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma);;avizo (*.am);;OFF files (*.off)"; } - QString loadNameFilters() const { return "binary files (*.cgal);;ascii (*.mesh)"; } - bool canLoad(QFileInfo) const; - QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true); + QString name() const override { return "C3t3_io_plugin"; } + QString nameFilters() const override { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma)"; } + QString saveNameFilters() const override { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma);;avizo (*.am);;OFF files (*.off)"; } + QString loadNameFilters() const override { return "binary files (*.cgal);;ascii (*.mesh)"; } + bool canLoad(QFileInfo) const override; + QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override; - bool canSave(const CGAL::Three::Scene_item*); - bool save(QFileInfo fileinfo,QList& ); + bool canSave(const CGAL::Three::Scene_item*) override; + bool save(QFileInfo fileinfo,QList& ) override; + bool isDefaultLoader(const Scene_item* item) const override{ + if(qobject_cast(item)) + return true; + return false; + } private: bool try_load_other_binary_format(std::istream& in, C3t3& c3t3); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/CMakeLists.txt index 9db4d61b2e1..7dd9fbd4fce 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/CMakeLists.txt @@ -51,7 +51,14 @@ polyhedron_demo_plugin(mesh_3_optimization_plugin Optimization_plugin ${meshingUI_FILES} KEYWORDS IO Mesh_3) target_link_libraries(mesh_3_optimization_plugin PUBLIC scene_c3t3_item scene_surface_mesh_item scene_image_item scene_implicit_function_item ) - +# Use Eigen + find_package(Eigen3 3.1.0 REQUIRED) #(3.1.0 or greater) + + if (EIGEN3_FOUND) + CGAL_target_use_Eigen(mesh_3_optimization_plugin) + else() #eigen + message(STATUS "The Mesh_3_optimization_plugin requires Eigen, which was not found, and will use a deprecated class to replace it. Warnings are to be expected.") + endif()#eigen polyhedron_demo_plugin(c3t3_io_plugin C3t3_io_plugin KEYWORDS IO Mesh_3) target_link_libraries(c3t3_io_plugin PUBLIC scene_c3t3_item) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp index 08d5b1eee01..d9b4fff0ef8 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp @@ -296,6 +296,11 @@ public: items.pop_front(); return ok; } + bool isDefaultLoader(const Scene_item* item) const override{ + if(qobject_cast(item)) + return true; + return false; + } QString name() const override{ return "segmented images"; } @@ -708,9 +713,9 @@ private: Volume_plane *y_item = new Volume_plane(img->image()->tx,img->image()->ty, img->image()->tz); Volume_plane *z_item = new Volume_plane(img->image()->tx,img->image()->ty, img->image()->tz); - x_item->setProperty("img",qVariantFromValue((void*)seg_img)); - y_item->setProperty("img",qVariantFromValue((void*)seg_img)); - z_item->setProperty("img",qVariantFromValue((void*)seg_img)); + x_item->setProperty("img",QVariant::fromValue((void*)seg_img)); + y_item->setProperty("img",QVariant::fromValue((void*)seg_img)); + z_item->setProperty("img",QVariant::fromValue((void*)seg_img)); x_item->setColor(QColor("red")); y_item->setColor(QColor("green")); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Meshing_dialog.ui b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Meshing_dialog.ui index a29054048fa..cc9a9b224bd 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Meshing_dialog.ui +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Meshing_dialog.ui @@ -100,9 +100,23 @@ Sharp features - - - + + + + + 60.00 + + + + + + + + + + true + + @@ -115,15 +129,8 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - Edge &size - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + sharpEdgesAngle @@ -134,6 +141,9 @@ + + + @@ -147,23 +157,6 @@ - - - - - - - true - - - - - - - 60.00 - - - @@ -171,6 +164,19 @@ + + + + Edge &size + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + edgeSizing + + + @@ -201,6 +207,9 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + approx + @@ -224,6 +233,9 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + facetAngle + @@ -315,17 +327,17 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 0.00 + + facetSizing - + + + 0.065 + + @@ -337,6 +349,13 @@ + + + + 0.0017 + + + @@ -390,6 +409,9 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + tetSizing + @@ -532,7 +554,7 @@ DoubleEdit QLineEdit -

    CGAL_double_edit.h
    +
    CGAL_double_edit.h
    diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Meshing_thread.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Meshing_thread.cpp index 766613e9dbf..75503a8feec 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Meshing_thread.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Meshing_thread.cpp @@ -16,7 +16,7 @@ #include "config.h" -#include +#include #include #include "Meshing_thread.h" @@ -52,7 +52,7 @@ void Meshing_thread:: run() { - QTime timer; + QElapsedTimer timer; timer.start(); CGAL::Three::Three::CursorScopeGuard guard(Qt::BusyCursor); f_->launch(); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Optimizer_thread.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Optimizer_thread.cpp index c0c01f0061f..dad540812fa 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Optimizer_thread.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Optimizer_thread.cpp @@ -16,7 +16,7 @@ #include "config_mesh_3.h" -#include +#include #include #include "Optimizer_thread.h" #include "Scene_c3t3_item.h" @@ -47,7 +47,7 @@ void Optimizer_thread:: run() { - QTime timer; + QElapsedTimer timer; timer.start(); //SEGFAULT rc_ = f_->launch(); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Clip_polyhedron_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Clip_polyhedron_plugin.cpp index 1585e3c0fad..4750f6ef4a5 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Clip_polyhedron_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Clip_polyhedron_plugin.cpp @@ -91,7 +91,8 @@ public : //get the references this->scene = scene_interface; this->messages = mi; - plane = NULL; + plane = nullptr; + clipper_item = nullptr; //creates and link the actions actionClipPolyhedra = new QAction("Clip Polyhedra With Plane", mw); actionClipPolyhedra->setProperty("subMenuName","Polygon Mesh Processing/Corefinement"); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Partition_graph_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Partition_graph_plugin.cpp index c2b390a14bd..4d89a8a8316 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Partition_graph_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Operations_on_polyhedra/Partition_graph_plugin.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include typedef Scene_surface_mesh_item Scene_facegraph_item; diff --git a/Polyhedron/demo/Polyhedron/Plugins/PCA/Affine_transform_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PCA/Affine_transform_plugin.cpp index 98851af36e8..d09466be0ff 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PCA/Affine_transform_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PCA/Affine_transform_plugin.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include "ui_Transformation_widget.h" diff --git a/Polyhedron/demo/Polyhedron/Plugins/PCA/Basic_generator_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PCA/Basic_generator_plugin.cpp index 269eb121ae4..4d92aeb7867 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PCA/Basic_generator_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PCA/Basic_generator_plugin.cpp @@ -766,7 +766,7 @@ struct Point_generator { return Point(bl.x() + i*(ur.x()-bl.x())/(w-1), bl.y() + j*(ur.y()-bl.y())/(h-1), - 0); + bl.z() + j*(ur.z()-bl.z())/(h-1)); } }; template diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt index b97c86f9879..3dc0a808de7 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt @@ -3,24 +3,31 @@ if(EIGEN3_FOUND) polyhedron_demo_plugin(jet_fitting_plugin Jet_fitting_plugin) target_link_libraries(jet_fitting_plugin PUBLIC scene_surface_mesh_item scene_polylines_item) + CGAL_target_use_Eigen(jet_fitting_plugin) else(EIGEN3_FOUND) message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Jet fitting plugin will not be available.") endif(EIGEN3_FOUND) +polyhedron_demo_plugin(extrude_plugin Extrude_plugin KEYWORDS PMP) +target_link_libraries(extrude_plugin PUBLIC scene_surface_mesh_item scene_selection_item) + if(EIGEN3_FOUND) if("${EIGEN3_VERSION}" VERSION_GREATER "3.1.90") qt5_wrap_ui( hole_fillingUI_FILES Hole_filling_widget.ui) polyhedron_demo_plugin(hole_filling_plugin Hole_filling_plugin ${hole_fillingUI_FILES} KEYWORDS PMP) target_link_libraries(hole_filling_plugin PUBLIC scene_surface_mesh_item scene_polylines_item scene_selection_item) + CGAL_target_use_Eigen(hole_filling_plugin) qt5_wrap_ui( fairingUI_FILES Fairing_widget.ui) polyhedron_demo_plugin(fairing_plugin Fairing_plugin ${fairingUI_FILES} KEYWORDS PMP) target_link_libraries(fairing_plugin PUBLIC scene_selection_item) + CGAL_target_use_Eigen(fairing_plugin) polyhedron_demo_plugin(hole_filling_polyline_plugin Hole_filling_polyline_plugin ) target_link_libraries(hole_filling_polyline_plugin PUBLIC scene_surface_mesh_item scene_polylines_item) + CGAL_target_use_Eigen(hole_filling_polyline_plugin) qt5_wrap_ui( Mean_curvature_flow_skeleton_pluginUI_FILES Mean_curvature_flow_skeleton_plugin.ui) polyhedron_demo_plugin(mean_curvature_flow_skeleton_plugin Mean_curvature_flow_skeleton_plugin ${Mean_curvature_flow_skeleton_pluginUI_FILES}) @@ -31,6 +38,19 @@ if(EIGEN3_FOUND) scene_polylines_item scene_mcf_item demo_framework) + CGAL_target_use_Eigen(mean_curvature_flow_skeleton_plugin) + # The smoothing plugin can still do some things, even if Ceres is not found + qt5_wrap_ui( smoothingUI_FILES Smoothing_plugin.ui) + polyhedron_demo_plugin(smoothing_plugin Smoothing_plugin ${smoothingUI_FILES}) + target_link_libraries(smoothing_plugin PUBLIC scene_surface_mesh_item scene_selection_item) + CGAL_target_use_Eigen(smoothing_plugin) + find_package(Ceres QUIET) + if(TARGET ceres) + target_compile_definitions( smoothing_plugin PRIVATE CGAL_PMP_USE_CERES_SOLVER ) + target_link_libraries(smoothing_plugin PUBLIC ceres) + endif() + + CGAL_target_use_Eigen(extrude_plugin) else() message(STATUS "NOTICE: The hole filling and fairing plugins require Eigen 3.2 (or higher) and will not be available.") endif() @@ -111,16 +131,3 @@ qt5_wrap_ui( engravUI_FILES Engrave_dock_widget.ui ) polyhedron_demo_plugin(engrave_text_plugin Engrave_text_plugin ${engravUI_FILES}) target_link_libraries(engrave_text_plugin PUBLIC scene_surface_mesh_item scene_selection_item scene_polylines_item) -polyhedron_demo_plugin(extrude_plugin Extrude_plugin KEYWORDS PMP) -target_link_libraries(extrude_plugin PUBLIC scene_surface_mesh_item scene_selection_item) - -# The smoothing plugin can still do some things, even if Ceres is not found -qt5_wrap_ui( smoothingUI_FILES Smoothing_plugin.ui) -polyhedron_demo_plugin(smoothing_plugin Smoothing_plugin ${smoothingUI_FILES}) -target_link_libraries(smoothing_plugin PUBLIC scene_surface_mesh_item scene_selection_item) - -find_package(Ceres QUIET) -if(TARGET ceres) - target_compile_definitions( smoothing_plugin PRIVATE CGAL_PMP_USE_CERES_SOLVER ) - target_link_libraries(smoothing_plugin PUBLIC ceres) -endif() diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Fairing_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Fairing_plugin.cpp index f496b01bcd2..862305a886e 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Fairing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Fairing_plugin.cpp @@ -14,7 +14,7 @@ typedef Scene_surface_mesh_item Scene_facegraph_item; #include #include -#include +#include #include #include #include diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Hole_filling_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Hole_filling_plugin.cpp index fcdb9f65551..bc1b95091c2 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Hole_filling_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Hole_filling_plugin.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Isotropic_remeshing_plugin.cpp index 66c8db3bef5..2049f788572 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Isotropic_remeshing_plugin.cpp @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include @@ -341,7 +341,7 @@ public Q_SLOTS: // wait cursor QApplication::setOverrideCursor(Qt::WaitCursor); - QTime time; + QElapsedTimer time; time.start(); typedef boost::graph_traits::edge_descriptor edge_descriptor; @@ -612,7 +612,6 @@ public Q_SLOTS: } if (fpmap_valid) { - PMP::connected_components(pmesh, fpmap, PMP::parameters::edge_is_constrained_map(eif)); poly_item->setItemIsMulticolor(true); poly_item->show_feature_edges(true); } @@ -699,7 +698,7 @@ public Q_SLOTS: detect_and_split_duplicates(selection, edges_to_protect, target_length); #ifdef CGAL_LINKED_WITH_TBB - QTime time; + QElapsedTimer time; time.start(); tbb::parallel_for( @@ -715,7 +714,7 @@ public Q_SLOTS: target_length, nb_iter, protect, smooth_features); for(Scene_facegraph_item* poly_item : selection) { - QTime time; + QElapsedTimer time; time.start(); remesher(poly_item, edges_to_protect[poly_item->polyhedron()]); diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Join_and_split_polyhedra_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Join_and_split_polyhedra_plugin.cpp index c9c412f98f7..1c1e7f3bd70 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Join_and_split_polyhedra_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Join_and_split_polyhedra_plugin.cpp @@ -51,7 +51,7 @@ public: actionJoinPolyhedra->setObjectName("actionJoinPolyhedra"); actionSplitPolyhedra= new QAction(tr("Split Selected Polyhedra"), mainWindow); - actionSplitPolyhedra->setProperty("subMenuName", "Operations on Polyhedra"); + actionSplitPolyhedra->setProperty("subMenuName", "Polygon Mesh Processing"); actionSplitPolyhedra->setObjectName("actionSplitPolyhedra"); actionColorConnectedComponents = new QAction(tr("Color Each Connected Component"), mainWindow); @@ -130,9 +130,9 @@ struct Polyhedron_appender{ }; struct Compare{ -bool operator()(FaceGraph* mesh1, FaceGraph* mesh2) +bool operator()(const FaceGraph& mesh1, const FaceGraph& mesh2) { - return num_faces(*mesh1) < num_faces(*mesh2); + return num_faces(mesh1) < num_faces(mesh2); } }; @@ -144,28 +144,15 @@ void Polyhedron_demo_join_and_split_polyhedra_plugin::on_actionSplitPolyhedra_tr if(item) { QApplication::setOverrideCursor(Qt::WaitCursor); - std::list new_polyhedra; - typedef boost::property_map >::type PatchIDMap; - PatchIDMap pidmap = get(CGAL::face_patch_id_t(), *item->face_graph()); - int nb_patches = item->property("NbPatchIds").toInt(); - if(nb_patches == 0) - nb_patches = CGAL::Polygon_mesh_processing::connected_components(*item->face_graph(), - pidmap); - - for(int i=0; i filter_graph(*item->face_graph(), i, pidmap); - FaceGraph* new_graph = new FaceGraph(); - CGAL::copy_face_graph(filter_graph, *new_graph); - new_polyhedra.push_back(new_graph); - } + std::vector new_polyhedra; + CGAL::Polygon_mesh_processing::split_connected_components(*item->face_graph(), + new_polyhedra); //sort polyhedra by number of faces - new_polyhedra.sort(Compare()); + std::sort(new_polyhedra.begin(), new_polyhedra.end(), Compare()); if (new_polyhedra.size()==1) { - delete new_polyhedra.front(); CGAL::Three::Three::information( tr("%1 has only one connected component").arg(item->name()) ); QApplication::restoreOverrideCursor(); continue; @@ -179,21 +166,15 @@ void Polyhedron_demo_join_and_split_polyhedra_plugin::on_actionSplitPolyhedra_tr compute_color_map(item->color(), new_polyhedra.size(), std::back_inserter(color_map)); Scene_group_item *group = new Scene_group_item("CC"); scene->addItem(group); - for(FaceGraph* polyhedron_ptr : new_polyhedra) + for(FaceGraph& poly : new_polyhedra) { - Scene_facegraph_item* new_item=new Scene_facegraph_item(polyhedron_ptr); + Scene_facegraph_item* new_item=new Scene_facegraph_item(poly); new_item->setName(tr("%1 - CC %2").arg(item->name()).arg(cc)); new_item->setColor(color_map[cc]); ++cc; scene->addItem(new_item); scene->changeGroup(new_item, group); } - - if(!item->hasPatchIds())//still valid bc the item has not been invalidated. - { - //remove f:patch_id map to avoid tricking the isMulticolor system. - item->face_graph()->remove_property_map(pidmap); - } item->setVisible(false); QApplication::restoreOverrideCursor(); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Mean_curvature_flow_skeleton_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Mean_curvature_flow_skeleton_plugin.cpp index f31f81bcdba..ec78f541cf3 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Mean_curvature_flow_skeleton_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Mean_curvature_flow_skeleton_plugin.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include @@ -360,7 +360,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionSegment() if (num_vertices(item->skeleton_curve)==0 ) { QApplication::restoreOverrideCursor(); return;} QApplication::setOverrideCursor(Qt::WaitCursor); - QTime time; + QElapsedTimer time; time.start(); // init the polyhedron simplex indices @@ -453,7 +453,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionConvert_to_me if ( !is_mesh_valid(pMesh) ) return; - QTime time; + QElapsedTimer time; time.start(); QApplication::setOverrideCursor(Qt::WaitCursor); @@ -491,7 +491,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionContract() return; } - QTime time; + QElapsedTimer time; time.start(); std::cout << "Contract...\n"; QApplication::setOverrideCursor(Qt::WaitCursor); @@ -516,7 +516,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionCollapse() return; } - QTime time; + QElapsedTimer time; time.start(); std::cout << "Collapse...\n"; QApplication::setOverrideCursor(Qt::WaitCursor); @@ -542,7 +542,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionSplit() return; } - QTime time; + QElapsedTimer time; time.start(); std::cout << "Split...\n"; QApplication::setOverrideCursor(Qt::WaitCursor); @@ -567,7 +567,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionDegeneracy() return; } - QTime time; + QElapsedTimer time; time.start(); std::cout << "Detect degeneracy...\n"; QApplication::setOverrideCursor(Qt::WaitCursor); @@ -618,7 +618,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionRun() return; } - QTime time; + QElapsedTimer time; time.start(); QApplication::setOverrideCursor(Qt::WaitCursor); @@ -741,7 +741,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionSkeletonize() return; } - QTime time; + QElapsedTimer time; time.start(); QApplication::setOverrideCursor(Qt::WaitCursor); @@ -802,7 +802,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionConverge() return; } - QTime time; + QElapsedTimer time; time.start(); QApplication::setOverrideCursor(Qt::WaitCursor); diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Orient_soup_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Orient_soup_plugin.cpp index 265507b8a9c..6d2d062e002 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Orient_soup_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Orient_soup_plugin.cpp @@ -223,8 +223,8 @@ void Polyhedron_demo_orient_soup_plugin::apply_shuffle( Item* root_item, item->load(root_item); item->shuffle_orientations(); item->setColor(root_item->color()); - scene->replaceItem(index, item); - delete root_item; + scene->replaceItem(index, item, true); + root_item->deleteLater(); QApplication::restoreOverrideCursor(); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Point_inside_polyhedron_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Point_inside_polyhedron_plugin.cpp index 96364990da4..0829e2810f0 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Point_inside_polyhedron_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Point_inside_polyhedron_plugin.cpp @@ -142,39 +142,27 @@ public Q_SLOTS: QString("Constructing with %1 items is done in %2 sec.").arg(inside_smesh_testers.size()).arg(timer.time())); timer.reset(); - std::size_t nb_query = 0, nb_selected = 0;// for print message - for(std::vector::iterator point_set_it = point_sets.begin(); - point_set_it != point_sets.end(); ++point_set_it) - { - Point_set* point_set = *point_set_it; - for (std::size_t pt = 0; - pt < point_set->size() - point_set->nb_selected_points(); - ++ pt, ++ nb_query) - { - bool selected = false; - Point_set::iterator point_it = point_set->begin() + pt; - if(! selected){ - // now the same for the smeshs - point_it = point_set->begin() + pt; - for (std::size_t i = 0; i < inside_smesh_testers.size(); ++i) + std::size_t nb_selected = 0; + for (Point_set* point_set : point_sets) + point_set->set_first_selected + (std::partition + (point_set->begin(), point_set->end(), + [&](const Point_set::Index& idx) -> bool + { + for (const Point_inside_smesh* tester : inside_smesh_testers) { - CGAL::Bounded_side res = (*inside_smesh_testers[i])(point_set->point(*point_it)); - - if( (inside && res == CGAL::ON_BOUNDED_SIDE) || - (on_boundary && res == CGAL::ON_BOUNDARY) || - (outside && res == CGAL::ON_UNBOUNDED_SIDE) ) - { - point_set->select(*point_it); ++nb_selected; - -- pt; // Selection replaces current point with unselected one - selected = true; - break;//loop on i - } + CGAL::Bounded_side res = (*tester)(point_set->point(idx)); + if ( (inside && res == CGAL::ON_BOUNDED_SIDE) || + (on_boundary && res == CGAL::ON_BOUNDARY) || + (outside && res == CGAL::ON_UNBOUNDED_SIDE) ) + { + ++ nb_selected; + return false; + } } - } - } // loop on points in point_set - }// loop on selected point sets + return true; + })); - print_message(QString("Querying with %1 points is done in %2 sec.").arg(nb_query).arg(timer.time())); print_message(QString("%1 points are selected. All Done!").arg(nb_selected)); // delete testers diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Polyhedron_slicer_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Polyhedron_slicer_plugin.cpp index 7adfa335f0f..50d907332eb 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Polyhedron_slicer_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Polyhedron_slicer_plugin.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include #include @@ -287,7 +287,7 @@ void Polyhedron_demo_polyhedron_slicer_plugin::on_Generate_button_clicked() if(!new_polyline_item_for_polylines) { Scene_polylines_item* new_polylines_item = new Scene_polylines_item(); - QTime time; time.start(); + QElapsedTimer time; time.start(); // call algorithm and fill polylines in polylines_item intersection_of_plane_Polyhedra_3_using_AABB_wrapper(*smesh, planes, plane_positions, new_polylines_item->polylines); // set names etc and print timing @@ -301,7 +301,7 @@ void Polyhedron_demo_polyhedron_slicer_plugin::on_Generate_button_clicked() scene->addItem(new_polylines_item); } else { - QTime time; time.start(); + QElapsedTimer time; time.start(); std::list > polylines; // call algorithm and fill polylines in polylines_item intersection_of_plane_Polyhedra_3_using_AABB_wrapper(*smesh, planes, plane_positions, polylines); diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Random_perturbation_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Random_perturbation_plugin.cpp index f5ee0e486c8..49063e703b7 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Random_perturbation_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Random_perturbation_plugin.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include #include @@ -94,7 +94,7 @@ public Q_SLOTS: // wait cursor QApplication::setOverrideCursor(Qt::WaitCursor); - QTime time; + QElapsedTimer time; time.start(); std::cout << "Perturbation..." << std::endl; diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp index 1e8fb6578ef..92da2e43934 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp @@ -182,10 +182,10 @@ void Polyhedron_demo_repair_polyhedron_plugin::on_actionRemoveDegenerateFaces_tr qobject_cast(scene->item(index)); if (poly_item) { - std::size_t nbv = num_faces(*poly_item->polyhedron()); + std::size_t nbv = faces(*poly_item->polyhedron()).size(); CGAL::Polygon_mesh_processing::remove_degenerate_faces( *poly_item->polyhedron()); - nbv -= num_faces(*poly_item->polyhedron()); + nbv -= faces(*poly_item->polyhedron()).size(); poly_item->invalidateOpenGLBuffers(); Q_EMIT poly_item->itemChanged(); CGAL::Three::Three::information(tr(" %1 degenerate faces have been removed.") diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp index b4864357dd3..be80490894e 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp @@ -127,6 +127,12 @@ public: return res; } + bool isDefaultLoader(const Scene_item* item) const override{ + if(qobject_cast(item)) + return true; + return false; + } + bool applicable(QAction* action) const override { if(action == actionSelfIntersection) return qobject_cast(scene->item(scene->mainSelectionIndex())); diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp index 3f463f6ce60..15e41fe939b 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp @@ -17,7 +17,7 @@ #include "ui_Smoothing_plugin.h" -#include +#include #include #include #include diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Surface_intersection_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Surface_intersection_plugin.cpp index 7095bc1bc26..88de2f26dab 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Surface_intersection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Surface_intersection_plugin.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include typedef Scene_surface_mesh_item Scene_face_graph_item; @@ -130,7 +130,7 @@ void Polyhedron_demo_intersection_plugin::intersectionSurfaces() Scene_polylines_item* new_item = new Scene_polylines_item(); // perform Boolean operation - QTime time; + QElapsedTimer time; time.start(); try{ @@ -193,7 +193,7 @@ void Polyhedron_demo_intersection_plugin::intersectionPolylines() Scene_points_with_normal_item* new_point_item = new Scene_points_with_normal_item(); Scene_polylines_item* new_pol_item = new Scene_polylines_item(); // perform Boolean operation - QTime time; + QElapsedTimer time; time.start(); std::vector polyA, polyB; Q_FOREACH(const Polyline_3& poly, itemA->polylines) @@ -289,7 +289,7 @@ void Polyhedron_demo_intersection_plugin::intersectionSurfacePolyline() Scene_points_with_normal_item* new_point_item = new Scene_points_with_normal_item(); Scene_polylines_item* new_pol_item = new Scene_polylines_item(); // perform Boolean operation - QTime time; + QElapsedTimer time; time.start(); Scene_face_graph_item::Face_graph tm = *itemA->face_graph(); std::vector Afaces; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/Point_set/CMakeLists.txt index 12b2e9f9056..eaf6ddfaf9f 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/CMakeLists.txt @@ -1,20 +1,9 @@ include( polyhedron_demo_macros ) if(EIGEN3_FOUND) - set(polyfit_linked_libraries) - set(polyfit_compile_definitions) - find_package(SCIP QUIET) - if(SCIP_FOUND) - include_directories(BEFORE ${SCIP_INCLUDE_DIRS}) - set(polyfit_linked_libraries ${polyfit_linked_libraries} ${SCIP_LIBRARIES}) - set(polyfit_compile_definitions ${polyfit_compile_definitions} "-DCGAL_USE_SCIP") - endif() - find_package(GLPK QUIET) - if(GLPK_FOUND) - include_directories(BEFORE ${GLPK_INCLUDE_DIR}) - set(polyfit_linked_libraries ${polyfit_linked_libraries} ${GLPK_LIBRARIES}) - set(polyfit_compile_definitions ${polyfit_compile_definitions} "-DCGAL_USE_GLPK") + if(NOT SCIP_FOUND) + find_package(GLPK QUIET) endif() if(NOT SCIP_FOUND AND NOT GLPK_FOUND) @@ -23,26 +12,53 @@ if(EIGEN3_FOUND) qt5_wrap_ui( surface_reconstructionUI_FILES Surface_reconstruction_plugin.ui) polyhedron_demo_plugin(surface_reconstruction_plugin Surface_reconstruction_plugin Surface_reconstruction_poisson_impl Surface_reconstruction_advancing_front_impl Surface_reconstruction_scale_space_impl Surface_reconstruction_polygonal_impl ${surface_reconstructionUI_FILES} KEYWORDS PointSetProcessing) - target_link_libraries(surface_reconstruction_plugin PUBLIC scene_polygon_soup_item scene_surface_mesh_item scene_points_with_normal_item ${polyfit_linked_libraries}) - target_compile_definitions(surface_reconstruction_plugin PRIVATE ${polyfit_compile_definitions}) + target_link_libraries(surface_reconstruction_plugin PUBLIC scene_polygon_soup_item scene_surface_mesh_item scene_points_with_normal_item) + CGAL_target_use_Eigen(surface_reconstruction_plugin) + + if (SCIP_FOUND) + CGAL_target_use_SCIP(surface_reconstruction_plugin) + elseif(GLPK_FOUND) + CGAL_target_use_GLPK(surface_reconstruction_plugin) + endif() qt5_wrap_ui( point_set_normal_estimationUI_FILES Point_set_normal_estimation_plugin.ui) polyhedron_demo_plugin(point_set_normal_estimation_plugin Point_set_normal_estimation_plugin ${point_set_normal_estimationUI_FILES} KEYWORDS PointSetProcessing Classification) target_link_libraries(point_set_normal_estimation_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler) + CGAL_target_use_Eigen(point_set_normal_estimation_plugin) qt5_wrap_ui( features_detection_pluginUI_FILES Features_detection_plugin.ui) polyhedron_demo_plugin(features_detection_plugin Features_detection_plugin ${features_detection_pluginUI_FILES} KEYWORDS PointSetProcessing) target_link_libraries(features_detection_plugin PUBLIC scene_points_with_normal_item) + CGAL_target_use_Eigen(features_detection_plugin) polyhedron_demo_plugin(point_set_smoothing_plugin Point_set_smoothing_plugin KEYWORDS PointSetProcessing) target_link_libraries(point_set_smoothing_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler) + CGAL_target_use_Eigen(point_set_smoothing_plugin) polyhedron_demo_plugin(point_set_average_spacing_plugin Point_set_average_spacing_plugin KEYWORDS PointSetProcessing Classification) target_link_libraries(point_set_average_spacing_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler) + CGAL_target_use_Eigen(point_set_average_spacing_plugin) qt5_wrap_ui(point_set_shape_detectionUI_FILES Point_set_shape_detection_plugin.ui) polyhedron_demo_plugin(point_set_shape_detection_plugin Point_set_shape_detection_plugin ${point_set_shape_detectionUI_FILES} KEYWORDS PointSetProcessing Classification) target_link_libraries(point_set_shape_detection_plugin PUBLIC scene_surface_mesh_item scene_points_with_normal_item scene_polygon_soup_item scene_callback_signaler) + CGAL_target_use_Eigen(point_set_shape_detection_plugin) + + find_package(OpenGR QUIET) + find_package(libpointmatcher QUIET) + + if (OpenGR_FOUND OR libpointmatcher_FOUND) + qt5_wrap_ui(register_point_setsUI_FILES Register_point_sets_plugin.ui) + polyhedron_demo_plugin(register_point_sets_plugin Register_point_sets_plugin ${register_point_setsUI_FILES} KEYWORDS PointSetProcessing) + if (OpenGR_FOUND) + CGAL_target_use_OpenGR(register_point_sets_plugin) + endif() + if (libpointmatcher_FOUND) + CGAL_target_use_pointmatcher(register_point_sets_plugin) + endif() + else() + message(STATUS "NOTICE: OpenGR and libpointmatcher were not found. Registrationp plugin will not be available.") + endif() else(EIGEN3_FOUND) message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Surface reconstruction plugin will not be available.") @@ -50,7 +66,6 @@ else(EIGEN3_FOUND) message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Smoothing plugin will not be available.") message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Average spacing plugin will not be available.") message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Feature detection plugin will not be available.") - endif() qt5_wrap_ui(point_set_bilateral_smoothingUI_FILES Point_set_bilateral_smoothing_plugin.ui) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_average_spacing_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_average_spacing_plugin.cpp index 13e9e0fa7db..037c7b5123d 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_average_spacing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_average_spacing_plugin.cpp @@ -20,11 +20,7 @@ #include "run_with_qprogressdialog.h" // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; struct Compute_average_spacing_functor : public Functor_with_signal_callback diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_bilateral_smoothing_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_bilateral_smoothing_plugin.cpp index 14c45d7391b..2da04eef9d3 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_bilateral_smoothing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_bilateral_smoothing_plugin.cpp @@ -21,11 +21,7 @@ #include "ui_Point_set_bilateral_smoothing_plugin.h" // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; struct Bilateral_smoothing_functor : public Functor_with_signal_callback diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_interference_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_interference_plugin.cpp index c20a2096421..5860a4c7239 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_interference_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_interference_plugin.cpp @@ -16,11 +16,8 @@ #include using namespace CGAL::Three; -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif + +typedef CGAL::Parallel_if_available_tag Concurrency_tag; class Point_set_interference_plugin: public QObject, diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_normal_estimation_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_normal_estimation_plugin.cpp index ff215dfa0e3..d9cb4ee90d5 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_normal_estimation_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_normal_estimation_plugin.cpp @@ -25,11 +25,7 @@ #include "ui_Point_set_normal_estimation_plugin.h" // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; struct PCA_estimate_normals_functor : public Functor_with_signal_callback diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_selection_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_selection_plugin.cpp index 9ed293d1f51..64fb5826792 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_selection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_selection_plugin.cpp @@ -43,7 +43,7 @@ //#undef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB #include -#include +#include #include #include #endif // CGAL_LINKED_WITH_TBB diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_simplification_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_simplification_plugin.cpp index c027c4275da..6bd189a6b2c 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_simplification_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_simplification_plugin.cpp @@ -22,11 +22,7 @@ #include "ui_Point_set_simplification_plugin.h" // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; struct Compute_average_spacing_functor : public Functor_with_signal_callback diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_smoothing_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_smoothing_plugin.cpp index 1436a2b4ae5..ac883acf29f 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_smoothing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_smoothing_plugin.cpp @@ -15,11 +15,7 @@ #include "run_with_qprogressdialog.h" // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; struct Jet_smoothing_functor : public Functor_with_signal_callback diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_to_mesh_distance_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_to_mesh_distance_plugin.cpp index e0d8c395e8a..eedb3999051 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_to_mesh_distance_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_to_mesh_distance_plugin.cpp @@ -22,7 +22,7 @@ #ifdef CGAL_LINKED_WITH_TBB #include #include -#include +#include #endif // CGAL_LINKED_WITH_TBB #if defined(CGAL_LINKED_WITH_TBB) @@ -31,13 +31,13 @@ struct Distance_computation{ const AABB_tree& tree; const Point_set & point_set; Point_3 initial_hint; - tbb::atomic* distance; + std::atomic* distance; std::vector& output; Distance_computation(const AABB_tree& tree, const Point_3 p, const Point_set & point_set, - tbb::atomic* d, + std::atomic* d, std::vector& out ) : tree(tree) , point_set(point_set) @@ -95,7 +95,7 @@ double compute_distances(const Mesh& m, } return hdist; #else - tbb::atomic distance; + std::atomic distance; distance.store(0); Distance_computation f(tree, hint, point_set, &distance, out); tbb::parallel_for(tbb::blocked_range(point_set.begin(), point_set.end()), f); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_upsampling_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_upsampling_plugin.cpp index c3740307ffa..b7d64382b03 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_upsampling_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_upsampling_plugin.cpp @@ -19,12 +19,8 @@ #include "ui_Point_set_upsampling_plugin.h" // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif - +typedef CGAL::Parallel_if_available_tag Concurrency_tag; + using namespace CGAL::Three; class Polyhedron_demo_point_set_upsampling_plugin : public QObject, diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_wlop_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_wlop_plugin.cpp index 561b849c4f0..f9ab5c60215 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_wlop_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_wlop_plugin.cpp @@ -20,11 +20,7 @@ #include "ui_Point_set_wlop_plugin.h" // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; struct Compute_average_spacing_functor : public Functor_with_signal_callback diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Register_point_sets_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Register_point_sets_plugin.cpp new file mode 100644 index 00000000000..e399d256c7d --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Register_point_sets_plugin.cpp @@ -0,0 +1,228 @@ +#include "config.h" +#include "Scene_points_with_normal_item.h" +#include +#include + +#ifdef CGAL_LINKED_WITH_OPENGR +#define CGAL_OPENGR_VERBOSE +#include +#endif + +#ifdef CGAL_LINKED_WITH_POINTMATCHER +#include +#endif + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ui_Register_point_sets_plugin.h" + + +using namespace CGAL::Three; + + +class Point_set_demo_register_dialog : public QDialog, private Ui::RegisterPointSetsDialog +{ + Q_OBJECT +public: + Point_set_demo_register_dialog(const std::vector& items, + QWidget* /*parent*/ = 0) + { + setupUi(this); + + for (std::size_t i = 0; i < items.size(); ++ i) + { + QRadioButton* button = new QRadioButton(items[i]->name().toStdString().c_str(), this); + buttons.push_back (button); + pointSets->addRow (button); + if (i == 0) + button->setChecked(true); + } + +#ifndef CGAL_LINKED_WITH_OPENGR + coarseRegistration->setText("Coarse registration (disabled, requires OpenGR)"); + coarseRegistration->setChecked(false); + coarseRegistration->setEnabled(false); + opengr_frame->setEnabled(false); +#endif +#ifndef CGAL_LINKED_WITH_POINTMATCHER + fineRegistration->setText("Fine registration (disabled, requires libpointmatcher)"); + fineRegistration->setChecked(false); + fineRegistration->setEnabled(false); + pointmatcher_frame->setEnabled(false); +#endif + } + + std::size_t ref_index() const + { + for (std::size_t i = 0; i < buttons.size(); ++ i) + if (buttons[i]->isChecked()) + return i; + return std::size_t(-1); + } + + bool coarse_registration() const { return coarseRegistration->isChecked(); } + bool fine_registration() const { return fineRegistration->isChecked(); } + + int nb_samples() const { return numberOfSamplesSpinBox->value(); } + double accuracy() const { return accuracyDoubleSpinBox->value(); } + double overlap() const { return double(overlapSpinBox->value()) / 100.0; } + int max_time() const { return maximumRunningTimeSpinBox->value(); } + + std::string pointmatcher_config() const { return config->toPlainText().toStdString(); } + +private: + + std::vector buttons; + +}; + + + +class Polyhedron_demo_register_point_sets_plugin : + public QObject, + public Polyhedron_demo_plugin_helper +{ + Q_OBJECT + Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface) + Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0") + +private: + QAction* actionRegisterPointSets; + +public: + void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) { + scene = scene_interface; + mw = mainWindow; + actionRegisterPointSets = new QAction(tr("Register point sets"), mainWindow); + actionRegisterPointSets->setObjectName("actionRegisterPointSets"); + connect(actionRegisterPointSets, SIGNAL(triggered()), this, SLOT(on_actionRegisterPointSets_triggered())); + } + + QList actions() const { + return QList() << actionRegisterPointSets; + } + + bool applicable(QAction*) const { + return get_point_set_items().size() >= 2; + } + + std::vector get_point_set_items() const + { + std::vector items; + + Q_FOREACH(int index, scene->selectionIndices()) + { + Scene_points_with_normal_item* item = + qobject_cast(scene->item(index)); + if(item && item->point_set()->has_normal_map()) + items.push_back (item); + } + + return items; + } + +public Q_SLOTS: + void on_actionRegisterPointSets_triggered(); +private : + Scene_interface *scene; +}; // end Polyhedron_demo_register_point_sets_plugin + +void Polyhedron_demo_register_point_sets_plugin::on_actionRegisterPointSets_triggered() +{ + std::vector items = get_point_set_items(); + + Point_set_demo_register_dialog dialog(items); + if(!dialog.exec()) + return; + + QApplication::setOverrideCursor(Qt::WaitCursor); + + std::size_t ref = dialog.ref_index(); + + for (std::size_t i = 0; i < items.size(); ++ i) + { + if (i == ref) + continue; + + std::cerr << "Registering " << items[i]->name().toStdString() << " with " << items[ref]->name().toStdString() << std::endl; + + Point_set& ps1 = *(items[ref]->point_set()); + Point_set& ps2 = *(items[i]->point_set()); + +#ifdef CGAL_LINKED_WITH_OPENGR + if (dialog.coarse_registration()) + { + std::cerr << "* Coarse registration:" << std::endl; + CGAL::Timer task_timer; task_timer.start(); + double score = + CGAL::OpenGR::register_point_sets(ps1, ps2, + CGAL::parameters::point_map(ps1.point_map()) + .normal_map(ps1.normal_map()) + .number_of_samples(dialog.nb_samples()) + .maximum_running_time(dialog.max_time()) + .accuracy(dialog.accuracy()) + .overlap(dialog.overlap()), + CGAL::parameters::point_map(ps2.point_map()) + .normal_map(ps2.normal_map())); + + std::size_t memory = CGAL::Memory_sizer().virtual_size(); + std::cerr << " -> Registration score = " << score << " (" + << task_timer.time() << " seconds, " + << (memory>>20) << " Mb allocated)" + << std::endl; + } +#endif +#ifdef CGAL_LINKED_WITH_POINTMATCHER + if (dialog.fine_registration()) + { + std::cerr << "* Fine registration: " << std::endl; + + std::istringstream ss (dialog.pointmatcher_config()); + + CGAL::Timer task_timer; task_timer.start(); + if (CGAL::pointmatcher::register_point_sets(ps1, ps2, + CGAL::parameters::point_map(ps1.point_map()) + .normal_map(ps1.normal_map()) + .pointmatcher_config(&ss), + CGAL::parameters::point_map(ps2.point_map()) + .normal_map(ps2.normal_map()))) + std::cerr << " -> Success"; + else + std::cerr << " -> Failure"; + + std::size_t memory = CGAL::Memory_sizer().virtual_size(); + std::cerr << " (" + << task_timer.time() << " seconds, " + << (memory>>20) << " Mb allocated)" + << std::endl; + } +#endif + + } + + for (std::size_t i = 0; i < items.size(); ++ i) + { + items[i]->invalidateOpenGLBuffers(); + scene->itemChanged(items[i]); + } + + QApplication::restoreOverrideCursor(); +} + + +#include "Register_point_sets_plugin.moc" diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Register_point_sets_plugin.ui b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Register_point_sets_plugin.ui new file mode 100644 index 00000000000..9cc5d979842 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Register_point_sets_plugin.ui @@ -0,0 +1,320 @@ + + + RegisterPointSetsDialog + + + + 0 + 0 + 418 + 515 + + + + Register point sets + + + + + + Which point set is the reference? (others will be altered) + + + + + + + + + + + + Coarse registration using OpenGR + + + true + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + Number of samples: + + + + + + + 3 + + + 10000000 + + + 200 + + + + + + + Accuracy: + + + + + + + 5 + + + 0.000010000000000 + + + 100000.000000000000000 + + + 0.100000000000000 + + + 5.000000000000000 + + + + + + + Overlap: + + + + + + + Maximum running time: + + + + + + + s + + + 1 + + + 36000 + + + 60 + + + + + + + % + + + 1 + + + 100 + + + 10 + + + 20 + + + + + + + + + + + + Fine registration using libpointmatcher + + + true + + + + + + + + 0 + 0 + + + + + 400 + 200 + + + + true + + + + + 0 + 0 + 398 + 198 + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Noto Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">readingDataPointsFilters:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> - RandomSamplingDataPointsFilter:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> prob: 0.5</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">referenceDataPointsFilters:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> - SamplingSurfaceNormalDataPointsFilter:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> knn: 10</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">matcher:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> KDTreeMatcher:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> knn: 1</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> epsilon: 0 </span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">outlierFilters:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> - TrimmedDistOutlierFilter:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> ratio: 0.75</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">errorMinimizer:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> PointToPlaneErrorMinimizer</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">transformationCheckers:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> - CounterTransformationChecker:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> maxIterationCount: 40</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> - DifferentialTransformationChecker:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> minDiffRotErr: 0.001</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> minDiffTransErr: 0.01</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> smoothLength: 4 </span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">inspector:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> VTKFileInspector:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> baseFileName: pointmatcher-run1</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> dumpPerfOnExit: 0</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> dumpStats: 0</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> dumpIterationInfo: 1 </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> dumpDataLinks: 0 </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> dumpReading: 0 </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> dumpReference: 0 </span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';">logger:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier';"> NullLogger</span></p></body></html> + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + RegisterPointSetsDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + RegisterPointSetsDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + coarseRegistration + toggled(bool) + opengr_frame + setEnabled(bool) + + + 208 + 63 + + + 208 + 158 + + + + + fineRegistration + toggled(bool) + pointmatcher_frame + setEnabled(bool) + + + 208 + 253 + + + 208 + 370 + + + + + diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_plugin.cpp index 8ab870f06fa..715c4a8fb06 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_plugin.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_poisson_impl.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_poisson_impl.cpp index a6987e4f759..4979471b987 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_poisson_impl.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_poisson_impl.cpp @@ -25,14 +25,8 @@ #include "SMesh_type.h" #include "Scene_points_with_normal_item.h" - - // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; template class Marching_tets diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_scale_space_impl.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_scale_space_impl.cpp index 582bad37820..7f15fb61174 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_scale_space_impl.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_scale_space_impl.cpp @@ -13,11 +13,7 @@ // Concurrency -#ifdef CGAL_LINKED_WITH_TBB -typedef CGAL::Parallel_tag Concurrency_tag; -#else -typedef CGAL::Sequential_tag Concurrency_tag; -#endif +typedef CGAL::Parallel_if_available_tag Concurrency_tag; typedef CGAL::Scale_space_surface_reconstruction_3 ScaleSpace; typedef CGAL::Scale_space_reconstruction_3::Advancing_front_mesher ScaleSpaceAFM; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Subdivision_methods/Subdivision_methods_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Subdivision_methods/Subdivision_methods_plugin.cpp index 0d00de8eb16..cdb67ae214c 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Subdivision_methods/Subdivision_methods_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Subdivision_methods/Subdivision_methods_plugin.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -81,7 +81,7 @@ template void Polyhedron_demo_subdivision_methods_plugin::apply_loop(FaceGraphItem* item, int nb_steps) { typename FaceGraphItem::Face_graph* graph = item->face_graph(); - QTime time; + QElapsedTimer time; time.start(); CGAL::Three::Three::information("Loop subdivision..."); QApplication::setOverrideCursor(Qt::WaitCursor); @@ -113,7 +113,7 @@ void Polyhedron_demo_subdivision_methods_plugin::apply_catmullclark(FaceGraphIte { typename FaceGraphItem::Face_graph* graph = item->face_graph(); if(!graph) return; - QTime time; + QElapsedTimer time; time.start(); CGAL::Three::Three::information("Catmull-Clark subdivision..."); QApplication::setOverrideCursor(Qt::WaitCursor); @@ -143,7 +143,7 @@ void Polyhedron_demo_subdivision_methods_plugin::apply_sqrt3(FaceGraphItem* item { typename FaceGraphItem::Face_graph* graph = item->face_graph(); if(!graph) return; - QTime time; + QElapsedTimer time; time.start(); CGAL::Three::Three::information("Sqrt-3 subdivision..."); QApplication::setOverrideCursor(Qt::WaitCursor); @@ -175,7 +175,7 @@ void Polyhedron_demo_subdivision_methods_plugin::apply_doosabin(FaceGraphItem* i { typename FaceGraphItem::Face_graph* graph = item->face_graph(); if(!graph) return; - QTime time; + QElapsedTimer time; time.start(); CGAL::Three::Three::information("Doo-Sabin subdivision..."); QApplication::setOverrideCursor(Qt::WaitCursor); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/CMakeLists.txt index 8ab1462de67..99c7d6e618b 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/CMakeLists.txt @@ -12,6 +12,7 @@ if(EIGEN3_FOUND) qt5_wrap_ui(parameterizationUI_FILES Parameterization_widget.ui OTE_dialog.ui) polyhedron_demo_plugin(parameterization_plugin Parameterization_plugin ${parameterizationUI_FILES}) target_link_libraries(parameterization_plugin PUBLIC scene_surface_mesh_item scene_textured_item scene_selection_item) + CGAL_target_use_Eigen(parameterization_plugin) else(EIGEN3_FOUND) message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. The Parameterization plugin will not be available.") endif(EIGEN3_FOUND) @@ -31,7 +32,9 @@ target_link_libraries(mesh_simplification_plugin PUBLIC scene_surface_mesh_item qt5_wrap_ui( remeshingUI_FILES Remeshing_dialog.ui) polyhedron_demo_plugin(offset_meshing_plugin Offset_meshing_plugin ${remeshingUI_FILES}) target_link_libraries(offset_meshing_plugin PUBLIC scene_surface_mesh_item scene_polygon_soup_item) - +if(EIGEN3_FOUND) + CGAL_target_use_Eigen(offset_meshing_plugin) +endif() if(TBB_FOUND) CGAL_target_use_TBB(offset_meshing_plugin) endif() diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_plane_detection_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_plane_detection_plugin.cpp index 989131b3ec3..c2a0a1c3d94 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_plane_detection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_plane_detection_plugin.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include @@ -196,7 +196,7 @@ void Polyhedron_demo_mesh_plane_detection_plugin::on_actionPlaneDetection_trigge if(dialog.exec() == QDialog::Rejected) return; - QTime time; + QElapsedTimer time; time.start(); std::cerr << "Detecting planes... "; QApplication::setOverrideCursor(Qt::WaitCursor); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_segmentation_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_segmentation_plugin.cpp index 66ac1b6dd68..336d233b693 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_segmentation_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_segmentation_plugin.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -211,7 +211,7 @@ void Polyhedron_demo_mesh_segmentation_plugin::apply_SDF_button_clicked(Facegrap typename boost::property_map::type fidmap = get(CGAL::face_index, *pair->first->face_graph()); FaceGraph_with_id_to_vector_property_map sdf_pmap(&pair->second, fidmap); - QTime time; + QElapsedTimer time; time.start(); std::pair min_max_sdf = sdf_values(*(pair->first->face_graph()), sdf_pmap, cone_angle, number_of_rays); std::cout << "ok (" << time.elapsed() << " ms)" << std::endl; @@ -284,7 +284,7 @@ void Polyhedron_demo_mesh_segmentation_plugin::apply_Partition_button_clicked(Fa QApplication::setOverrideCursor(Qt::WaitCursor); } check_and_set_ids(pair->first->face_graph()); - QTime time; + QElapsedTimer time; time.start(); typename boost::property_map::type fidmap = get(CGAL::face_index, *pair->first->face_graph()); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_simplification_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_simplification_plugin.cpp index f7156813ea0..29d9759b73b 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_simplification_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_simplification_plugin.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include @@ -136,7 +136,7 @@ void Polyhedron_demo_mesh_simplification_plugin::on_actionSimplify_triggered() return; // simplify - QTime time; + QElapsedTimer time; time.start(); std::cout << "Simplify..."; QApplication::setOverrideCursor(Qt::WaitCursor); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Parameterization_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Parameterization_plugin.cpp index 7ef01c4e953..b20bd58304e 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Parameterization_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Parameterization_plugin.cpp @@ -11,7 +11,7 @@ #include #include #include "Scene.h" -#include +#include #include #include #include @@ -602,7 +602,7 @@ void Polyhedron_demo_parameterization_plugin::parameterize(const Parameterizatio ////////// PARAMETERIZE /////////// /////////////////////////////////// - QTime time; + QElapsedTimer time; time.start(); // add textured polyhedon to the scene diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Scene_polyhedron_shortest_path_item.cpp b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Scene_polyhedron_shortest_path_item.cpp index 3010a710635..a752130873e 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Scene_polyhedron_shortest_path_item.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Scene_polyhedron_shortest_path_item.cpp @@ -472,7 +472,7 @@ bool Scene_polyhedron_shortest_path_item_priv::run_point_select(const Ray_3& ray CGAL::Three::Three::information(QObject::tr("Computing shortest path polyline...")); - QTime time; + QElapsedTimer time; time.start(); //~ m_shortestPaths->m_debugOutput=true; m_shortestPaths->shortest_path_points_to_source_points( diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Shortest_path_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Shortest_path_plugin.cpp index b411c8c6a17..c54a1d7d8db 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Shortest_path_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Shortest_path_plugin.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Surface_mesh_approximation_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Surface_mesh_approximation_plugin.cpp index cebffa08e4d..bba6d446aa6 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Surface_mesh_approximation_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Surface_mesh_approximation_plugin.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include @@ -305,7 +305,7 @@ void Polyhedron_demo_surface_mesh_approximation_plugin::on_buttonSeeding_clicked approx.set_metric(static_cast( ui_widget.comboMetric->currentIndex())); - QTime time; + QElapsedTimer time; time.start(); approx.initialize_seeds(CGAL::parameters::seeding_method( static_cast(ui_widget.comboMethod->currentIndex())) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/VSA_wrapper.h b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/VSA_wrapper.h index f43b6c94d48..c876ba84680 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/VSA_wrapper.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/VSA_wrapper.h @@ -38,23 +38,13 @@ class VSA_WRAPPER_EXPORT VSA_wrapper { typedef boost::property_map::type Face_center_map; typedef boost::property_map::type Face_area_map; -#ifdef CGAL_LINKED_WITH_TBB typedef CGAL::Variational_shape_approximation L21_approx; -#else - typedef CGAL::Variational_shape_approximation L21_approx; -#endif + CGAL::Default, EPICK, CGAL::Parallel_if_available_tag> L21_approx; typedef L21_approx::Error_metric L21_metric; typedef VSA::L2_metric_plane_proxy L2_metric; -#ifdef CGAL_LINKED_WITH_TBB typedef CGAL::Variational_shape_approximation L2_approx; -#else - typedef CGAL::Variational_shape_approximation L2_approx; -#endif + L2_metric, EPICK, CGAL::Parallel_if_available_tag> L2_approx; // user defined point-wise compact metric struct Compact_metric_point_proxy { @@ -89,14 +79,8 @@ class VSA_WRAPPER_EXPORT VSA_wrapper { }; typedef Compact_metric_point_proxy Compact_metric; -#ifdef CGAL_LINKED_WITH_TBB typedef CGAL::Variational_shape_approximation Compact_approx; -#else - typedef CGAL::Variational_shape_approximation Compact_approx; -#endif - + Compact_metric, EPICK, CGAL::Parallel_if_available_tag> Compact_approx; public: enum Metric { L21, L2, Compact }; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh_deformation/Edit_polyhedron_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh_deformation/Edit_polyhedron_plugin.cpp index 72bd09b3bd3..8d15fb0cbde 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh_deformation/Edit_polyhedron_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh_deformation/Edit_polyhedron_plugin.cpp @@ -175,7 +175,8 @@ void Polyhedron_demo_edit_polyhedron_plugin::on_actionDeformation_triggered() // what they do is simply transmitting required 'action' to selected scene_edit_polyhedron_item object void Polyhedron_demo_edit_polyhedron_plugin::on_AddCtrlVertPushButton_clicked() { - int item_id = scene->mainSelectionIndex(); + + int item_id = scene->selectionIndices().front(); Scene_edit_polyhedron_item* edit_item = qobject_cast(scene->item(item_id)); if(!edit_item) return; // the selected item is not of the right type @@ -183,7 +184,7 @@ void Polyhedron_demo_edit_polyhedron_plugin::on_AddCtrlVertPushButton_clicked() } void Polyhedron_demo_edit_polyhedron_plugin::on_PrevCtrlVertPushButton_clicked() { - int item_id = scene->mainSelectionIndex(); + int item_id = scene->selectionIndices().front(); Scene_edit_polyhedron_item* edit_item = qobject_cast(scene->item(item_id)); if(!edit_item) return; // the selected item is not of the right type @@ -193,7 +194,7 @@ void Polyhedron_demo_edit_polyhedron_plugin::on_PrevCtrlVertPushButton_clicked() } void Polyhedron_demo_edit_polyhedron_plugin::on_NextCtrlVertPushButton_clicked() { - int item_id = scene->mainSelectionIndex(); + int item_id = scene->selectionIndices().front(); Scene_edit_polyhedron_item* edit_item = qobject_cast(scene->item(item_id)); if(!edit_item) return; // the selected item is not of the right type @@ -203,7 +204,7 @@ void Polyhedron_demo_edit_polyhedron_plugin::on_NextCtrlVertPushButton_clicked() } void Polyhedron_demo_edit_polyhedron_plugin::on_SelectAllVerticesPushButton_clicked() { - int item_id = scene->mainSelectionIndex(); + int item_id = scene->selectionIndices().front(); Scene_edit_polyhedron_item* edit_item = qobject_cast(scene->item(item_id)); if(!edit_item) return; // the selected item is not of the right type @@ -213,7 +214,7 @@ void Polyhedron_demo_edit_polyhedron_plugin::on_SelectAllVerticesPushButton_clic } void Polyhedron_demo_edit_polyhedron_plugin::on_DeleteCtrlVertPushButton_clicked() { - int item_id = scene->mainSelectionIndex(); + int item_id = scene->selectionIndices().front(); Scene_edit_polyhedron_item* edit_item = qobject_cast(scene->item(item_id)); if(!edit_item) return; // the selected item is not of the right type @@ -224,7 +225,7 @@ void Polyhedron_demo_edit_polyhedron_plugin::on_DeleteCtrlVertPushButton_clicked } void Polyhedron_demo_edit_polyhedron_plugin::on_ClearROIPushButton_clicked() { - int item_id = scene->mainSelectionIndex(); + int item_id = scene->selectionIndices().front(); Scene_edit_polyhedron_item* edit_item = qobject_cast(scene->item(item_id)); if(!edit_item) return; // the selected item is not of the right type @@ -238,7 +239,7 @@ void Polyhedron_demo_edit_polyhedron_plugin::on_ApplyAndClosePushButton_clicked( } void Polyhedron_demo_edit_polyhedron_plugin::on_DiscardChangesPushButton_clicked() { - int item_id = scene->mainSelectionIndex(); + int item_id = scene->selectionIndices().front(); Scene_edit_polyhedron_item* edit_item = qobject_cast(scene->item(item_id)); if (!edit_item) return; // the selected item is not of the right type @@ -297,14 +298,14 @@ void Polyhedron_demo_edit_polyhedron_plugin::on_ActivateFixedPlaneCheckBox_state } void Polyhedron_demo_edit_polyhedron_plugin::on_OverwritePushButton_clicked() { - int item_id = scene->mainSelectionIndex(); + int item_id = scene->selectionIndices().front(); Scene_edit_polyhedron_item* edit_item = qobject_cast(scene->item(item_id)); if(!edit_item) return; // the selected item is not of the right type edit_item->overwrite_deform_object(); } void Polyhedron_demo_edit_polyhedron_plugin::on_Select_isolated_components_button_clicked() { - int item_id = scene->mainSelectionIndex(); + int item_id = scene->selectionIndices().front(); Scene_edit_polyhedron_item* edit_item = qobject_cast(scene->item(item_id)); if(!edit_item) return; // the selected item is not of the right type @@ -316,7 +317,7 @@ void Polyhedron_demo_edit_polyhedron_plugin::on_Select_isolated_components_butto } void Polyhedron_demo_edit_polyhedron_plugin::on_Get_minimum_button_clicked() { - int item_id = scene->mainSelectionIndex(); + int item_id = scene->selectionIndices().front(); Scene_edit_polyhedron_item* edit_item = qobject_cast(scene->item(item_id)); if(!edit_item) return; // the selected item is not of the right type @@ -328,7 +329,7 @@ void Polyhedron_demo_edit_polyhedron_plugin::on_Get_minimum_button_clicked() { void Polyhedron_demo_edit_polyhedron_plugin::on_SaveROIPushButton_clicked() { - int item_id = scene->mainSelectionIndex(); + int item_id = scene->selectionIndices().front(); Scene_edit_polyhedron_item* edit_item = qobject_cast(scene->item(item_id)); if(!edit_item) return; @@ -340,7 +341,7 @@ void Polyhedron_demo_edit_polyhedron_plugin::on_SaveROIPushButton_clicked() } void Polyhedron_demo_edit_polyhedron_plugin::on_ReadROIPushButton_clicked() { - int item_id = scene->mainSelectionIndex(); + int item_id = scene->selectionIndices().front(); Scene_edit_polyhedron_item* edit_item = qobject_cast(scene->item(item_id)); if(!edit_item) return; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh_deformation/Scene_edit_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh_deformation/Scene_edit_polyhedron_item.cpp index e15b5185976..495d2b73342 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh_deformation/Scene_edit_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh_deformation/Scene_edit_polyhedron_item.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include @@ -99,7 +99,6 @@ struct Scene_edit_polyhedron_item_priv mutable std::vector color_lines; mutable std::vector ROI_points; mutable std::vector control_points; - mutable std::vector ROI_color; mutable std::vector control_color; mutable std::vector normals; mutable std::vector pos_bbox; @@ -360,15 +359,12 @@ void Scene_edit_polyhedron_item_priv::compute_normals_and_vertices(Mesh* mesh) { CGAL::Color c(0,255,0); EPICK::Point_3 point(p.x()+offset.x, p.y()+offset.y, p.z()+offset.z); - spheres->add_sphere(EPICK::Sphere_3(point, length_of_axis/15.0*length_of_axis/15.0), c); + spheres->add_sphere(EPICK::Sphere_3(point, length_of_axis/15.0*length_of_axis/15.0), 0, c); } } } - ROI_color.assign(ROI_points.size(),0); - for(std::size_t i=0; i >::const_iterator hgb_data = fs.get_ctrl_vertex_frame_map(mesh).begin(); hgb_data != fs.get_ctrl_vertex_frame_map(mesh).end(); ++hgb_data) { if(hgb_data->frame == Three::mainViewer()->manipulatedFrame()) @@ -400,7 +396,7 @@ void Scene_edit_polyhedron_item_priv::compute_normals_and_vertices(Mesh* mesh) EPICK::Point_3 center(p.x()+offset.x, p.y()+offset.y, p.z()+offset.z); - spheres_ctrl->add_sphere(EPICK::Sphere_3(center, length_of_axis/15.0*length_of_axis/15.0), c); + spheres_ctrl->add_sphere(EPICK::Sphere_3(center, length_of_axis/15.0*length_of_axis/15.0), 0, c); } } } @@ -909,6 +905,8 @@ bool Scene_edit_polyhedron_item::eventFilter(QObject* /*target*/, QEvent *event) // check state changes between old and current state bool ctrl_pressed_now = d->state.ctrl_pressing && !old_state.ctrl_pressing; bool ctrl_released_now = !d->state.ctrl_pressing && old_state.ctrl_pressing; + if(ctrl_released_now) //to avoid moving the control vertices next time ctrl is pressed + d->state.left_button_pressing = false; if(ctrl_pressed_now || ctrl_released_now || event->type() == QEvent::HoverMove) {// activate a handle manipulated frame CGAL::QGLViewer* viewer = Three::mainViewer(); @@ -1271,7 +1269,7 @@ void Scene_edit_polyhedron_item::ShowAsSphere(bool b) { if(!d->spheres) { - d->spheres = new Scene_spheres_item(this, false); + d->spheres = new Scene_spheres_item(this, 0, false, false); d->spheres->setName("ROI spheres"); d->spheres->setRenderingMode(Gouraud); connect(d->spheres, SIGNAL(destroyed()), this, SLOT(reset_spheres())); @@ -1283,7 +1281,7 @@ void Scene_edit_polyhedron_item::ShowAsSphere(bool b) } if(!d->spheres_ctrl) { - d->spheres_ctrl = new Scene_spheres_item(this, false); + d->spheres_ctrl = new Scene_spheres_item(this, false, false); d->spheres_ctrl->setName("Control spheres"); d->spheres_ctrl->setRenderingMode(Gouraud); connect(d->spheres_ctrl, &QObject::destroyed, this, Reset_spheres_ctrl(d) ); @@ -1776,6 +1774,10 @@ Scene_surface_mesh_item* Scene_edit_polyhedron_item::sm_item()const void Scene_edit_polyhedron_item::computeElements() const { d->compute_normals_and_vertices(sm_item()->face_graph()); + if(d->spheres) + d->spheres->computeElements(); + if(d->spheres_ctrl) + d->spheres_ctrl->computeElements(); std::vector vertices; std::vector *vertices_ptr; const CGAL::qglviewer::Vec offset = Three::mainViewer()->offset(); diff --git a/Polyhedron/demo/Polyhedron/Preferences.ui b/Polyhedron/demo/Polyhedron/Preferences.ui index 10a7f773f85..358bf1ffbb8 100644 --- a/Polyhedron/demo/Polyhedron/Preferences.ui +++ b/Polyhedron/demo/Polyhedron/Preferences.ui @@ -7,7 +7,7 @@ 0 0 631 - 526 + 628 @@ -58,9 +58,9 @@ 0 - -96 + 0 275 - 528 + 534 @@ -285,6 +285,16 @@ + + + + true + + + Network Settings + + + diff --git a/Polyhedron/demo/Polyhedron/SSH_dialog.ui b/Polyhedron/demo/Polyhedron/SSH_dialog.ui new file mode 100644 index 00000000000..0f18f927cb8 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/SSH_dialog.ui @@ -0,0 +1,151 @@ + + + SSHDialog + + + + 0 + 0 + 415 + 441 + + + + SSH Settings + + + + + + + + SSH Preferences + + + + + + User + + + + + + + + + + + + Server + + + + + + + + + + + + Public Key + + + + + + + + + Browse... + + + + + + + + + + Private Key + + + + + + + + + Browse... + + + + + + + + + + + + + Camera Synchronization Server + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SSHDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SSHDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Polyhedron/demo/Polyhedron/Scene.cpp b/Polyhedron/demo/Polyhedron/Scene.cpp index 05998239946..4730d595adb 100644 --- a/Polyhedron/demo/Polyhedron/Scene.cpp +++ b/Polyhedron/demo/Polyhedron/Scene.cpp @@ -84,9 +84,12 @@ Scene::addItem(CGAL::Three::Scene_item* item) addGroup(group); //init the item for the mainViewer to avoid using unexisting //VAOs if the mainViewer is not the first to be drawn. + QOpenGLFramebufferObject* fbo = CGAL::Three::Three::mainViewer()->depthPeelingFbo(); + CGAL::Three::Three::mainViewer()->setDepthPeelingFbo(nullptr);//to prevent crashing as the fbo is not initialized in this call. item->draw(CGAL::Three::Three::mainViewer()); item->drawEdges(CGAL::Three::Three::mainViewer()); item->drawPoints(CGAL::Three::Three::mainViewer()); + CGAL::Three::Three::mainViewer()->setDepthPeelingFbo(fbo); return id; } @@ -140,6 +143,7 @@ Scene::replaceItem(Scene::Item_id index, CGAL::Three::Scene_item* item, bool emi if(emit_item_about_to_be_destroyed) { Q_EMIT itemAboutToBeDestroyed(item); + item->aboutToBeDestroyed(); } Q_EMIT updated(); diff --git a/Polyhedron/demo/Polyhedron/Scene_c3t3_item.cpp b/Polyhedron/demo/Polyhedron/Scene_c3t3_item.cpp index 9ad4cfa9dc2..0b98891d35c 100644 --- a/Polyhedron/demo/Polyhedron/Scene_c3t3_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_c3t3_item.cpp @@ -441,6 +441,7 @@ struct Scene_c3t3_item_priv { return false; } Scene_spheres_item *spheres; + std::vector tr_vertices; Scene_intersection_item *intersection; bool spheres_are_shown; const Scene_item* data_item_; @@ -1390,7 +1391,7 @@ void Scene_c3t3_item_priv::computeSpheres() if(!spheres) return; - + int s_id = 0; for(Tr::Finite_vertices_iterator vit = c3t3.triangulation().finite_vertices_begin(), end = c3t3.triangulation().finite_vertices_end(); @@ -1436,8 +1437,10 @@ void Scene_c3t3_item_priv::computeSpheres() wp2p(vit->point()).z() + offset.z); float radius = vit->point().weight() ; typedef unsigned char UC; - spheres->add_sphere(Geom_traits::Sphere_3(center, radius), + tr_vertices.push_back(*vit); + spheres->add_sphere(Geom_traits::Sphere_3(center, radius),s_id++, CGAL::Color(UC(c.red()), UC(c.green()), UC(c.blue()))); + } spheres->invalidateOpenGLBuffers(); } @@ -1453,6 +1456,7 @@ void Scene_c3t3_item_priv::computeElements() } positions_poly.clear(); + positions_grid.clear(); normals.clear(); f_colors.clear(); positions_lines.clear(); @@ -1602,7 +1606,17 @@ void Scene_c3t3_item::show_spheres(bool b) contextMenu()->findChild("actionShowSpheres")->setChecked(b); if(b && !d->spheres) { - d->spheres = new Scene_spheres_item(this, true); + d->spheres = new Scene_spheres_item(this, d->c3t3.number_of_vertices_in_complex(), true); + connect(d->spheres, &Scene_spheres_item::picked, + this, [this](std::size_t id) + { + if(id == (std::size_t)(-1)) + return; + QString msg = QString("Vertex's index : %1; Vertex's in dimension: %2.").arg(d->tr_vertices[id].index()).arg(d->tr_vertices[id].in_dimension()); + CGAL::Three::Three::information(msg); + CGAL::Three::Three::mainViewer()->displayMessage(msg, 5000); + + }); d->spheres->setName("Protecting spheres"); d->spheres->setRenderingMode(Gouraud); connect(d->spheres, SIGNAL(destroyed()), this, SLOT(reset_spheres())); @@ -1619,7 +1633,6 @@ void Scene_c3t3_item::show_spheres(bool b) } Q_EMIT redraw(); } - } void Scene_c3t3_item::show_intersection(bool b) { diff --git a/Polyhedron/demo/Polyhedron/Scene_item_rendering_helper.cpp b/Polyhedron/demo/Polyhedron/Scene_item_rendering_helper.cpp index 5413cd0616f..bffe5e847b5 100644 --- a/Polyhedron/demo/Polyhedron/Scene_item_rendering_helper.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_item_rendering_helper.cpp @@ -78,9 +78,9 @@ void PRIV::compute_diag_bbox() { const Scene_item::Bbox& b_box = item->bbox(); _diag_bbox = CGAL::approximate_sqrt( - (b_box.xmax() - b_box.xmin())*(b_box.xmax() - b_box.xmin()) - + (b_box.ymax() - b_box.ymin())*(b_box.ymax() - b_box.ymin()) - + (b_box.zmax() - b_box.zmin())*(b_box.zmax() - b_box.zmin()) + CGAL::square(b_box.xmax() - b_box.xmin()) + + CGAL::square(b_box.ymax() - b_box.ymin()) + + CGAL::square(b_box.zmax() - b_box.zmin()) ); } diff --git a/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp index 7a84ee2d911..f7dd9a977c0 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp @@ -1,6 +1,3 @@ -#include -#include - #include "Scene_polygon_soup_item.h" #include "Scene_surface_mesh_item.h" #include @@ -13,9 +10,6 @@ #include #include -#include -#include -#include #include #include @@ -23,6 +17,7 @@ #include #include +#include #include #include #include @@ -43,8 +38,14 @@ #include #include +#include +#include #include +#include +#include +#include #include +#include using namespace CGAL::Three; typedef Viewer_interface Vi; @@ -366,40 +367,14 @@ void Scene_polygon_soup_item::init_polygon_soup(std::size_t nb_pts, std::size_t d->oriented = false; } - -#include template void polygon_mesh_to_soup(PolygonMesh& mesh, Polygon_soup& soup) { soup.clear(); - typedef typename boost::property_map::type VPMap; - VPMap vpmap = get(boost::vertex_point, mesh); - std::map::vertex_descriptor, int> vim; - int index=0; - //fill points - for(typename boost::graph_traits::vertex_iterator vit = - vertices(mesh).begin(); vit != vertices(mesh).end(); ++vit) - { - soup.points.push_back(get(vpmap, *vit)); - vim.insert(std::make_pair(*vit, index++)); - } - //fill triangles - for(typename boost::graph_traits::face_iterator fit = - faces(mesh).begin(); fit != faces(mesh).end(); ++fit) - { - Polygon_soup::Polygon_3 polygon; - for(typename boost::graph_traits::halfedge_descriptor hd : - CGAL::halfedges_around_face(halfedge(*fit, mesh), mesh)) - { - polygon.push_back(vim[target(hd, mesh)]); - } - soup.polygons.push_back(polygon); - } + CGAL::Polygon_mesh_processing::polygon_mesh_to_polygon_soup(mesh, soup.points, soup.polygons); soup.fill_edges(); - } - void Scene_polygon_soup_item::load(Scene_surface_mesh_item* sm_item) { if(!sm_item) return; if(!sm_item->face_graph()) return; 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_polylines_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polylines_item.cpp index cb9b43c6162..8802aeec8e1 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polylines_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polylines_item.cpp @@ -218,6 +218,7 @@ Scene_polylines_item_private::computeSpheres() // At this point, 'corner_polyline_nb' gives the multiplicity of all // corners. //Finds the centers of the spheres and their color + int s_id = 0; for(iterator p_it = corner_polyline_nb.begin(), end = corner_polyline_nb.end(); @@ -253,7 +254,7 @@ Scene_polylines_item_private::computeSpheres() } CGAL::Color c(colors[0], colors[1], colors[2]); - spheres->add_sphere(K::Sphere_3(center+offset, spheres_drawn_square_radius), c); + spheres->add_sphere(K::Sphere_3(center+offset, spheres_drawn_square_radius),s_id++, c); } spheres->setToolTip( QString("

    Legend of endpoints colors: