diff --git a/Mesh_3/include/CGAL/Labeled_mesh_domain_3.h b/Mesh_3/include/CGAL/Labeled_mesh_domain_3.h index d40ec36318b..4bdf2fbb1c3 100644 --- a/Mesh_3/include/CGAL/Labeled_mesh_domain_3.h +++ b/Mesh_3/include/CGAL/Labeled_mesh_domain_3.h @@ -7,13 +7,8 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// // Author(s) : Stéphane Tayeb, Aymeric PELLE -// -//****************************************************************************** -// File Description : -// class Labeled_mesh_domain_3. See class description. -//****************************************************************************** + #ifndef CGAL_LABELED_MESH_DOMAIN_3_H #define CGAL_LABELED_MESH_DOMAIN_3_H @@ -875,17 +870,15 @@ public: * function. The domain to be discretized is assumed to be the domain where * the function has negative values. * - * The method takes as argument a bounding sphere which is required to - * circumscribe the surface and to have its center inside the domain. - * * \tparam Function a type compatible with the signature `FT(Point_3)`: it takes a point as argument, * and returns a scalar value. That object must be model of `CopyConstructible` * \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" * \tparam Bounding_object either a bounding sphere (of type `Sphere_3`), a bounding box (type `Bbox_3`), - * or a bounding `Iso_cuboid_3` + * or a bounding `Iso_cuboid_3` which is required to circumscribe + * the surface and to have its center inside the domain. * * \param function the implicit function - * \param bounding_object object boundint the meshable domain and its center is inside the domain. + * \param bounding_object object bounding the meshable domain and its center is inside the domain. * \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below: * * \cgalNamedParamsBegin @@ -1196,7 +1189,7 @@ public: // If both extremities are in the same subdomain, // there is no intersection. - // Should only happen during initial point generation. + // Should only be able to happen during initial point generation. if( value_at_p1 == value_at_p2 ) { return Intersection(); diff --git a/Poisson_surface_reconstruction_3/doc/Poisson_surface_reconstruction_3/Poisson_surface_reconstruction_3.txt b/Poisson_surface_reconstruction_3/doc/Poisson_surface_reconstruction_3/Poisson_surface_reconstruction_3.txt index 22d533a0e67..9ff2ad918a7 100644 --- a/Poisson_surface_reconstruction_3/doc/Poisson_surface_reconstruction_3/Poisson_surface_reconstruction_3.txt +++ b/Poisson_surface_reconstruction_3/doc/Poisson_surface_reconstruction_3/Poisson_surface_reconstruction_3.txt @@ -13,8 +13,7 @@ This \cgal component implements a surface reconstruction method which takes as input point sets with oriented normals and computes an implicit function. We assume that the input points contain no outliers and little noise. The output surface mesh is generated by extracting -an isosurface of this function with the \ref Chapter_3D_Mesh_Generation or \cgal Surface Mesh Generator -\cgalCite{cgal:ry-gsddrm-06} or potentially with any other surface +an isosurface of this function with the \ref 3D Mesh Generator or potentially with any other surface contouring algorithm. \cgalFigureBegin{Poisson_surface_reconstruction_3figintroduction,introduction.jpg} @@ -76,7 +75,7 @@ indicator function \f$ f\f$ represented as a piecewise linear function over the refined triangulation. More specifically, it solves for the Poisson equation \f$ \Delta f = div(\mathbf{n})\f$ at each vertex of the triangulation using a sparse linear solver. Eventually, the \cgal -surface mesh generator extracts an isosurface with function value set +3D mesh generator extracts an isosurface with function value set by default to be the median value of \f$ f\f$ at all input points. \section Poisson_surface_reconstruction_3Function Reconstruction Function @@ -86,9 +85,7 @@ provided. It takes points with normals as input and handles the whole reconstruction pipeline : - it computes the implicit function -- it reconstructs the surface with a given precision using the \cgal -surface mesh generator based on Delaunay refinement -\cgalCite{cgal:ry-gsddrm-06} \cgalCite{cgal:bo-pgsms-05} +- it reconstructs the surface with a given precision using the \cgal 3D mesh generator - it outputs the result in a polygon mesh. This function aims at providing a quick and user-friendly API for @@ -120,14 +117,11 @@ The following example reads a point set, creates a Poisson implicit function and The computed implicit functions can be iso-contoured to reconstruct a -surface by using the \ref Chapter_3D_Mesh_Generation or the \cgal surface mesh generator -\cgalCite{cgal:ry-gsddrm-06} \cgalCite{cgal:bo-pgsms-05} : +surface by using the \cgal 3D mesh generator : -`make_mesh_3()` for using parallel Mesh_3 +`make_mesh_3()` with the `surface_only()` parameter for using parallel Mesh_3 -`make_surface_mesh()` of using the deprecated 3D Surface Mesh Generation - -The parameter `Tag` affects the behavior of `make_surface_mesh()`: +The parameter `Tag` affects the behavior of `make_mesh_3()`: - `Manifold_tag`: the output mesh is guaranteed to be a manifold surface without boundary. - `Manifold_with_boundary_tag`: the output mesh is guaranteed to be manifold and may have boundaries. - `Non_manifold_tag`: the output mesh has no guarantee and hence is outputted as a polygon soup. @@ -137,13 +131,6 @@ The parameter `Tag` affects the behavior of `make_surface_mesh()`: The surface reconstructed by `make_mesh_3()` is required to be a model of the concept `MeshComplex_3InTriangulation_3`, a data structure devised to represent a three dimensional complex embedded into a three dimensional triangulation. The surface facets can then be extracted into a face graph by `facets_in_complex_3_to_triangle_mesh()`. -The surface reconstructed by `make_surface_mesh()` instead is required to be a -model of the concept `SurfaceMeshComplex_2InTriangulation_3`, a data -structure devised to represent a two dimensional complex embedded into -a three dimensional triangulation. - -`SurfaceMeshComplex_2InTriangulation_3` defines the methods to traverse the reconstructed surface, and e.g. convert it to a triangle soup. - Other \cgal components provide functions to write the reconstructed surface mesh to the %Object File Format (OFF) \cgalCite{cgal:p-gmgv16-96} and to convert it to a polyhedron (when it is manifold): @@ -223,7 +210,7 @@ function over the tetrahedra of a 3D Delaunay triangulation constructed from the input points then refined through Delaunay refinement. For this reason, any iso-surface is also piecewise linear and hence may contain sharp creases. As the contouring algorithm -`make_surface_mesh()` expects a smooth implicit function these +`make_mesh_3()` expects a smooth implicit function these sharp creases may create spurious clusters of vertices in the final reconstructed surface mesh when setting a small mesh sizing or surface approximation error parameter (see @@ -352,12 +339,13 @@ with the 03 option which maximizes speed. All measurements were done using the The point set chosen for benchmarking the Poisson implicit function is the Lucy statue point set from the The Stanford 3D Scanning Repository -(originally 14 million points, here downscaled to 2.9 million points) depicted by \cgalFigureRef{Poisson_surface_reconstruction_3-fig-simplification_bench}. +(originally 14 million points, here downsampled to 2.9 million points) depicted by \cgalFigureRef{Poisson_surface_reconstruction_3-fig-contouring_bench}. We measure the Poisson implicit function computation (i.e., the call to `Poisson_reconstruction_function::compute_implicit_function()` denoted by Poisson solve hereafter) for this point set as well as for simplified versions obtained through random simplification. The following table provides Poisson solve computation times in seconds for an increasing number of points. +
@@ -408,19 +396,20 @@ Poisson solve duration (in s) 2,900

486 -

+

- +
\subsection SurfReconstPerfCont Contouring The point set chosen for benchmarking the contouring stage is the Lucy point -set simplified to 2.9M points. We measure the contouring (i.e.\ the calls to `make_mesh_3()` and `facets_in_complex_3_to_triangle_mesh()`) +set simplified to 2.9M points. We measure the contouring (i.e., the calls to `make_mesh_3()` and `facets_in_complex_3_to_triangle_mesh()`) duration and the reconstruction error for a range of approximation distances. The reconstruction error is expressed as the average distance from input points to the reconstructed surface in mm (the Lucy statue is 1597 mm tall). +
- -

+

Approx. distance (*average spacing) @@ -430,7 +419,7 @@ Contouring duration single-thread (in s) Contouring duration parallel (in s) Reconstruction error (mm) -

+

@@ -552,8 +541,9 @@ Reconstruction error (mm) 1.50

+

+
\cgalFigureAnchor{Poisson_surface_reconstruction_3-fig-contouring_bench}
@@ -572,6 +562,7 @@ set (2.9 millions points) as well as for further simplified versions.\n The Poisson implicit function computation has a memory peak when solving the Poisson linear system using the sparse linear solver. +
@@ -622,6 +613,7 @@ Memory occupancy (MBytes) 6,868


+
\subsection SurfReconstPerfPSS Point Set Simplification @@ -633,6 +625,7 @@ simplified versions. All reconstructions use the recommended contouring paramete The reconstruction error is expressed as the average distance from input points to the reconstructed surface in mm (the Lucy statue is 1597 mm tall). +
@@ -698,6 +691,7 @@ Reconstruction error (mm) 0.150947


+
\cgalFigureBegin{Poisson_surface_reconstruction_3-fig-simplification_bench,simplification_bench.jpg} diff --git a/Poisson_surface_reconstruction_3/include/CGAL/Poisson_mesh_domain_3.h b/Poisson_surface_reconstruction_3/include/CGAL/Poisson_mesh_domain_3.h index 44e89efd100..3eabdf979c7 100644 --- a/Poisson_surface_reconstruction_3/include/CGAL/Poisson_mesh_domain_3.h +++ b/Poisson_surface_reconstruction_3/include/CGAL/Poisson_mesh_domain_3.h @@ -7,13 +7,7 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// // Author(s) : Sven Oesau -// -//****************************************************************************** -// File Description : -// class Poisson_mesh_domain_3. See class description. -//****************************************************************************** #ifndef CGAL_POISSON_MESH_DOMAIN_3_H #define CGAL_POISSON_MESH_DOMAIN_3_H @@ -38,7 +32,6 @@ namespace CGAL { the basic operations to implement intersection tests and intersection computations through a bisection method.This parameter must be instantiated with a model of the concept `BisectionGeometricTraits_3`. - This class is a model of concept `MeshDomain_3`. \cgalModels{MeshDomain_3} \sa `CGAL::Labeled_mesh_domain_3` @@ -111,16 +104,15 @@ public: typedef CGAL::Poisson_reconstruction_function Function; #endif - Function poisson_function; + /// \name Creation /// @{ /*! \brief Construction from a function, a bounding object and a relative error bound. * * \tparam Bounding_object either a bounding sphere (of type `Sphere_3`), a bounding box (type `Bbox_3`), * or a bounding `Iso_cuboid_3` - * \tparam NamedParameters - * a sequence of \ref bgl_namedparameters "Named Parameters" + * \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" * * \param function the Poisson reconstruction function * \param bounding_object the bounding object bounding the meshable space. @@ -144,7 +136,7 @@ public: #endif // DOXYGEN_RUNNING ) : Base(make_implicit_to_labeling_function_wrapper(function), bounding_object, np), - poisson_function(function) + poisson_function(function) {} /*! \brief Construction from a function, a bounding object and a relative error bound. @@ -171,14 +163,14 @@ public: #endif // DOXYGEN_RUNNING ) : Base(make_implicit_to_labeling_function_wrapper(function), function.bounding_sphere(), np), - poisson_function(function) + poisson_function(function) {} ///@} #ifndef DOXYGEN_RUNNING template Poisson_mesh_domain_3(const CGAL_NP_CLASS& np) - : Base(np) + : Base(np) {} // Overload handling parameters passed with operator= @@ -188,11 +180,11 @@ public: typename ... NP> Poisson_mesh_domain_3(const Function& function, const CGAL_NP_CLASS_1& np1, - const CGAL_NP_CLASS_2& np2, + const CGAL_NP_CLASS_2& np2, const NP& ... nps) - : Base(internal_np::combine_named_parameters( - CGAL::parameters::function(make_implicit_to_labeling_function_wrapper(function)), np1, np2, nps...)), - poisson_function(function) + : Base(internal_np::combine_named_parameters( + CGAL::parameters::function(make_implicit_to_labeling_function_wrapper(function)), np1, np2, nps...)), + poisson_function(function) {} #endif @@ -205,12 +197,10 @@ public: * function. The domain to be discretized is assumed to be the domain where * the function has negative values. * - * The method takes as argument a bounding sphere which is required to - * circumscribe the surface and to have its center inside the domain. - * * \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" * \tparam Bounding_object either a bounding sphere (of type `Sphere_3`), a bounding box (type `Bbox_3`), - * or a bounding `Iso_cuboid_3` + * or a bounding `Iso_cuboid_3` which is required to circumscribe + * the surface and to have its center inside the domain. * * \param function the Poisson reconstruction function * \param bounding_object object bounding the meshable domain and its center is inside the domain. @@ -236,33 +226,32 @@ public: { using parameters::get_parameter; using parameters::choose_parameter; + FT relative_error_bound_ = choose_parameter(get_parameter(np, internal_np::error_bound), FT(1e-3)); CGAL::Random* p_rng_ = choose_parameter(get_parameter(np, internal_np::rng), nullptr); - auto null_subdomain_index_ = choose_parameter(get_parameter(np, internal_np::null_subdomain_index_param), -Null_functor()); auto construct_surface_patch_index_ = choose_parameter(get_parameter(np, -internal_np::surface_patch_index), Null_functor()); - namespace p = CGAL::parameters; - return Poisson_mesh_domain_3 - (function, + auto null_subdomain_index_ = choose_parameter(get_parameter(np, internal_np::null_subdomain_index_param), Null_functor()); + auto construct_surface_patch_index_ = choose_parameter(get_parameter(np, internal_np::surface_patch_index), Null_functor()); + + return Poisson_mesh_domain_3(function, bounding_object, - CGAL::parameters::relative_error_bound(relative_error_bound_) - .function(make_implicit_to_labeling_function_wrapper(function)) - .p_rng(p_rng_) - .null_subdomain_index(Base::create_null_subdomain_index(null_subdomain_index_)) - .construct_surface_patch_index(Base::create_construct_surface_patch_index(construct_surface_patch_index_))); + CGAL::parameters::relative_error_bound(relative_error_bound_) + .function(make_implicit_to_labeling_function_wrapper(function)) + .p_rng(p_rng_) + .null_subdomain_index(Base::create_null_subdomain_index(null_subdomain_index_)) + .construct_surface_patch_index(Base::create_construct_surface_patch_index(construct_surface_patch_index_))); } /// @} #ifndef DOXYGEN_RUNNING template static Poisson_mesh_domain_3 create_Poisson_mesh_domain(const CGAL_NP_CLASS& np = parameters::default_values()) { - static_assert(!parameters::is_default_parameter::value, - "Value for required parameter not found"); static_assert(!parameters::is_default_parameter::value, "Value for required parameter not found"); - using parameters::get_parameter; - return create_Poisson_mesh_domain(parameters::get_parameter(np, internal_np::function_param), - parameters::get_parameter(np, internal_np::bounding_object_param), + + static_assert(!parameters::is_default_parameter::value, "Value for required parameter not found"); + static_assert(!parameters::is_default_parameter::value, "Value for required parameter not found"); + + return create_Poisson_mesh_domain(get_parameter(np, internal_np::function_param), + get_parameter(np, internal_np::bounding_object_param), np); } @@ -271,8 +260,8 @@ internal_np::bounding_object_param_t>::value, "Value for required parameter not typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT_2, typename ... NP> static Poisson_mesh_domain_3 create_Poisson_mesh_domain(const CGAL_NP_CLASS_1& np1, - const CGAL_NP_CLASS_2& np2, - const NP& ... nps) + const CGAL_NP_CLASS_2& np2, + const NP& ... nps) { return create_Poisson_mesh_domain(internal_np::combine_named_parameters(np1, np2, nps...)); } @@ -343,12 +332,12 @@ internal_np::bounding_object_param_t>::value, "Value for required parameter not // If both extremities are in the same subdomain, // there is no intersection. - // Should only happen during initial point generation. + // Should only be able to happen during initial point generation. if(label_at_p1 == label_at_p2) return Intersection(); // Else lets find a point (by bisection) - // Bisection ends when the point is near than error bound from surface + // Bisection ends when the point is nearer from surface than the error bound while(true) { if(c1 == c2) { if(c1_is_inf) {