pass on code and doc following reviews

This commit is contained in:
Sven Oesau 2025-04-02 11:47:12 +02:00
parent 675c10766d
commit 25443ddc54
3 changed files with 57 additions and 81 deletions

View File

@ -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();

View File

@ -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
<a href="https://graphics.stanford.edu/data/3Dscanrep/">The Stanford 3D Scanning Repository</a>
(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.
<CENTER>
<TABLE CELLSPACING=5 >
<TR><TD ALIGN=LEFT NOWRAP COLSPAN=2><HR>
<TR>
@ -408,19 +396,20 @@ Poisson solve duration (in s)
2,900
<TD class="math" ALIGN=CENTER NOWRAP>
486
<TR><TD ALIGN=LEFT NOWRAP COLSPAN=2><HR>
<TR><TD ALIGN=CENTER NOWRAP COLSPAN=2><HR>
</TABLE>
</CENTER>
\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).
<CENTER>
<TABLE CELLSPACING=5 >
<TR><TD ALIGN=LEFT NOWRAP COLSPAN=4><HR>
<TR><TD ALIGN=CENTER NOWRAP COLSPAN=4><HR>
<TR>
<TD class="math" ALIGN=CENTER NOWRAP>
Approx. distance (*average spacing)
@ -430,7 +419,7 @@ Contouring duration single-thread (in s)
Contouring duration parallel (in s)
<TD class="math" ALIGN=CENTER NOWRAP>
Reconstruction error (mm)
<TR><TD ALIGN=LEFT NOWRAP COLSPAN=4><HR>
<TR><TD ALIGN=CENTER NOWRAP COLSPAN=4><HR>
<TR>
<TD class="math" ALIGN=CENTER NOWRAP>
@ -552,8 +541,9 @@ Reconstruction error (mm)
<TD class="math" ALIGN=CENTER NOWRAP>
1.50
<TR>
<TD ALIGN=LEFT NOWRAP COLSPAN=3><HR>
<TD ALIGN=CENTER NOWRAP COLSPAN=4><HR>
</TABLE>
</CENTER>
\cgalFigureAnchor{Poisson_surface_reconstruction_3-fig-contouring_bench}
<center>
@ -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.
<CENTER>
<TABLE CELLSPACING=5 >
<TR><TD ALIGN=LEFT NOWRAP COLSPAN=2><HR>
<TR>
@ -622,6 +613,7 @@ Memory occupancy (MBytes)
6,868
<TR><TD ALIGN=LEFT NOWRAP COLSPAN=2><HR>
</TABLE>
</CENTER>
\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).
<CENTER>
<TABLE CELLSPACING=5 >
<TR><TD ALIGN=LEFT NOWRAP COLSPAN=2><HR>
<TR>
@ -698,6 +691,7 @@ Reconstruction error (mm)
0.150947
<TR><TD ALIGN=LEFT NOWRAP COLSPAN=2><HR>
</TABLE>
</CENTER>
\cgalFigureBegin{Poisson_surface_reconstruction_3-fig-simplification_bench,simplification_bench.jpg}

View File

@ -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<BGT> 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<BGT>(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<BGT>(function), function.bounding_sphere(), np),
poisson_function(function)
poisson_function(function)
{}
///@}
#ifndef DOXYGEN_RUNNING
template<typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT>
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<BGT>(function)), np1, np2, nps...)),
poisson_function(function)
: Base(internal_np::combine_named_parameters(
CGAL::parameters::function(make_implicit_to_labeling_function_wrapper<BGT>(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<BGT>(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<BGT>(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<typename CGAL_NP_TEMPLATE_PARAMETERS>
static Poisson_mesh_domain_3 create_Poisson_mesh_domain(const CGAL_NP_CLASS& np = parameters::default_values())
{
static_assert(!parameters::is_default_parameter<CGAL_NP_CLASS, internal_np::function_param_t>::value,
"Value for required parameter not found"); static_assert(!parameters::is_default_parameter<CGAL_NP_CLASS,
internal_np::bounding_object_param_t>::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<CGAL_NP_CLASS, internal_np::function_param_t>::value, "Value for required parameter not found");
static_assert(!parameters::is_default_parameter<CGAL_NP_CLASS, internal_np::bounding_object_param_t>::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) {