Skip to content

Commit

Permalink
Mesh 3 : initial_points_generator parameter for make_mesh_3 point ini…
Browse files Browse the repository at this point in the history
…tialization (#7798)

## Summary of Changes

Added a `initial_points_generator` parameter in make_mesh_3.
With this parameter, we can use a custom functor when initializing the
C3t3 complex.
This functor must follow the
[Initial_points_generator](https://cgal.github.io/7798/v0/Mesh_3/classInitialPointsGenerator.html)
concept.

Tasks:
 - [x] Add `initial_points_generator` parameter in `make_mesh_3`
 - [x] Make an example
 - [x] Write `Construct_initial_points_labeled_image` into a header
- [x] Make `initialize_triangulation_from_labeled_image` use
`Construct_initial_points_labeled_image`
- [x] Change definition of concept `InitialPointsGenerator` to output
`std::tuple<MeshDomain::Point_3, int dimension, MeshDomain::Index>`
(instead of `std::pair<MeshDomain::Point_3, MeshDomain::Index>`)
 - [x] Make it pass checks
 - [x] Document `initial_points_generator` parameter in `make_mesh_3`
 - [x] Document `Construct_initial_points_labeled_image` header
 - [x] Document example
- [x] Delete `initialize_triangulation_from_labeled_image` and
`initialize_triangulation_from_gray_image`
- [x] Make an example of labelled and gray image initialisation with the
parameter or the old custom initialization.
 - [x] Make small feature page
- [x] add `Construct_initial_points_gray_image.h`, similar to
`Construct_initial_points_labeled_image.h`
 - [x] Maybe add a test ?
- [x] announce in `CHANGES.md`, see
#7798 (comment)

## Release Management

* Affected package(s): Mesh_3
* Issue(s) solved (if any): 
  * fix #922
  * fix #7469 
  * discussion #7537
  * previous closed PR #7757
* Feature/Small Feature (if any):
[Mesh_3_initial_points_generator_parameter](https://cgal.geometryfactory.com/CGAL/Members/wiki/Features/Small_Features/Mesh_3_initial_points_generator_parameter)
* Link to compiled documentation
[*here*](https://cgal.github.io/7798/v4/Manual/index.html):
*
[make_mesh_3](https://cgal.github.io/7798/v4/Mesh_3/group__PkgMesh3Functions.html#gac8599a0c967075f740bf8e2e92c4770e)
has been modified to receive the parameters :
*
[initial_points_generator](https://cgal.github.io/7798/v4/Mesh_3/group__PkgMesh3Parameters.html#gaf53777b83f1b2f3e7d49275dbab6e46b)
*
[initial_points](https://cgal.github.io/7798/v4/Mesh_3/group__PkgMesh3Parameters.html#gae94f38c6cd23cce45a55608e881a546a)
* The
[InitialPointsGenerator](https://cgal.github.io/7798/v4/Mesh_3/classInitialPointsGenerator.html)
concept that the functor must be a model of.
* A model of this concept :
[Construct_initial_points_labeled_image](https://cgal.github.io/7798/v4/Mesh_3/structCGAL_1_1Construct__initial__points__labeled__image.html)
* License and copyright ownership:
  • Loading branch information
sloriot authored Feb 5, 2025
2 parents f72e69f + 1d6e305 commit 54bfdfe
Show file tree
Hide file tree
Showing 25 changed files with 1,389 additions and 600 deletions.
7 changes: 7 additions & 0 deletions Installation/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@
- Introduces two traits decorators, namely `Arr_tracing_traits_2` and `Arr_counting_traits_2`, which can be used to extract debugging and informative metadata about the traits in use while a program is being executed.
- Fixed the Landmark point-location strategy so that it can be applied to arrangements on a sphere.

### [3D Mesh Generation](https://doc.cgal.org/6.1/Manual/packages.html#PkgMesh3)

- Added two new meshing parameters that enable mesh initialization customization :
- `initial_points_generator` : enables the user to specify a functor that generates initial points,
- `initial_points` : enables the user to specify a `Range` of initial points.


## [Release 6.0.1](https://github.com/CGAL/cgal/releases/tag/v6.0.1)

### [Poisson Surface Reconstruction](https://doc.cgal.org/6.0.1/Manual/packages.html#PkgPoissonSurfaceReconstruction3)
Expand Down
2 changes: 1 addition & 1 deletion Lab/demo/Lab/Plugins/Mesh_3/Mesh_3_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type,
ui.protect->setChecked(features_protection_available);

ui.facegraphCheckBox->setVisible(mesh_type == Mesh_type::SURFACE_ONLY);
ui.initializationGroup->setVisible(input_is_labeled_img);
ui.initializationGroup->setVisible(input_is_labeled_img || input_is_gray_img);
ui.grayImgGroup->setVisible(input_is_gray_img);

if(input_is_gray_img)
Expand Down
15 changes: 2 additions & 13 deletions Lab/demo/Lab/Plugins/Mesh_3/Mesh_3_plugin_cgal_code.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,6 @@ using namespace CGAL::Three;

typedef Tr::Bare_point Bare_point;

struct Compare_to_isovalue {
double iso_value;
bool less;
typedef bool result_type;

Compare_to_isovalue(double iso_value, bool less)
: iso_value(iso_value), less(less) {}

bool operator()(double x) const {
return (x < iso_value) == less;
}
};

Meshing_thread* cgal_code_mesh_3(QList<const SMesh*> pMeshes,
const Polylines_container& polylines,
const SMesh* pBoundingMesh,
Expand Down Expand Up @@ -355,6 +342,8 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage,
param.protect_features
= protect_features || protect_borders || !polylines.empty();
param.detect_connected_components = detect_connected_components;
param.iso_value = iso_value;
param.inside_is_less = inside_is_less;
param.facet_angle = facet_angle;
param.facet_sizing = facet_sizing;
param.facet_min_sizing = facet_min_sizing;
Expand Down
87 changes: 74 additions & 13 deletions Lab/demo/Lab/Plugins/Mesh_3/Mesh_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
#include <CGAL/Mesh_3/Mesher_3.h>
#include <CGAL/Mesh_criteria_3.h>
#include <CGAL/Mesh_3/Protect_edges_sizing_field.h>
#include <CGAL/Mesh_3/initialize_triangulation_from_labeled_image.h>
#include <CGAL/Mesh_3/Construct_initial_points_labeled_image.h>
#include <CGAL/Mesh_3/Construct_initial_points_gray_image.h>

#include "C3t3_type.h"
#include "Meshing_thread.h"
Expand All @@ -40,6 +41,19 @@ namespace CGAL {
class Image_3;
}

struct Compare_to_isovalue {
double iso_value;
bool less;
typedef bool result_type;

Compare_to_isovalue(double iso_value, bool less)
: iso_value(iso_value), less(less) {}

bool operator()(double x) const {
return (x < iso_value) == less;
}
};

struct Mesh_parameters
{
double facet_angle;
Expand All @@ -55,6 +69,8 @@ struct Mesh_parameters
double edge_distance;
bool protect_features;
bool detect_connected_components;
float iso_value;
bool inside_is_less;
int manifold;
const CGAL::Image_3* image_3_ptr;
const CGAL::Image_3* weights_ptr;
Expand Down Expand Up @@ -111,6 +127,7 @@ class Mesh_function

void initialize(const Mesh_criteria& criteria, Mesh_fnt::Domain_tag);
void initialize(const Mesh_criteria& criteria, Mesh_fnt::Labeled_image_domain_tag);
void initialize(const Mesh_criteria& criteria, Mesh_fnt::Gray_image_domain_tag);

Edge_criteria edge_criteria(double b, double minb, double d, Mesh_fnt::Domain_tag);
Edge_criteria edge_criteria(double b, double minb, double d, Mesh_fnt::Polyhedral_domain_tag);
Expand Down Expand Up @@ -231,16 +248,61 @@ Mesh_function<D_,Tag>::
initialize(const Mesh_criteria& criteria, Mesh_fnt::Labeled_image_domain_tag)
// for a labeled image
{
if(p_.detect_connected_components) {
CGAL_IMAGE_IO_CASE(p_.image_3_ptr->image(),
initialize_triangulation_from_labeled_image(c3t3_
, *domain_
, *p_.image_3_ptr
, criteria
, Word()
, p_.protect_features);
);
} else {
namespace p = CGAL::parameters;
// Initialization of the labeled image, either with the protection of sharp
// features, or with the initial points (or both).
if (p_.detect_connected_components)
{
CGAL::Mesh_3::internal::C3t3_initializer<
C3t3,
Domain,
Mesh_criteria,
CGAL::internal::has_Has_features<Domain>::value >()
(c3t3_,
*domain_,
criteria,
p_.protect_features,
p::mesh_3_options(p::pointer_to_stop_atomic_boolean = &stop_,
p::nonlinear_growth_of_balls = true).v,
CGAL::Construct_initial_points_labeled_image<C3t3, Domain>(*p_.image_3_ptr, *domain_));
}
else
{
initialize(criteria, Mesh_fnt::Domain_tag());
}
}

template < typename D_, typename Tag >
void
Mesh_function<D_,Tag>::
initialize(const Mesh_criteria& criteria, Mesh_fnt::Gray_image_domain_tag)
// for a gray image
{
namespace p = CGAL::parameters;
// Initialization of the gray image, either with the protection of sharp
// features, or with the initial points (or both).
if (p_.detect_connected_components)
{
CGAL::Construct_initial_points_gray_image<C3t3, Domain, Compare_to_isovalue> generator
(*p_.image_3_ptr,
*domain_,
p_.iso_value,
Compare_to_isovalue(p_.iso_value, p_.inside_is_less));
CGAL::Mesh_3::internal::C3t3_initializer<
C3t3,
Domain,
Mesh_criteria,
CGAL::internal::has_Has_features<Domain>::value >()
(c3t3_,
*domain_,
criteria,
p_.protect_features,
p::mesh_3_options(p::pointer_to_stop_atomic_boolean = &stop_,
p::nonlinear_growth_of_balls = true).v,
generator);
}
else
{
initialize(criteria, Mesh_fnt::Domain_tag());
}
}
Expand All @@ -254,8 +316,7 @@ initialize(const Mesh_criteria& criteria, Mesh_fnt::Domain_tag)
namespace p = CGAL::parameters;
// Initialization of the mesh, either with the protection of sharp
// features, or with the initial points (or both).
// If `detect_connected_components==true`, the initialization is
// already done.

CGAL::Mesh_3::internal::C3t3_initializer<
C3t3,
Domain,
Expand Down
84 changes: 84 additions & 0 deletions Mesh_3/doc/Mesh_3/CGAL/Mesh_3/parameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,90 @@ unspecified_type odt(const Named_function_parameters& np = parameters::default_v
template <class NamedParameters = parameters::Default_named_parameters>
unspecified_type perturb(const Named_function_parameters& np = parameters::default_values());

/*!
* \ingroup PkgMesh3Parameters
*
* The function `parameters::initial_points_generator()` enables the user to specify a functor that follows
* the `InitialPointsGenerator_3` concept to the mesh generation function `make_mesh_3()`. This functor is called
* for the initialization of the meshing process, by inserting well-distributed surface vertices.
* If this parameter is not specified, the default behavior
* is executed, which calls the domain's `construct_initial_points_object()` for the initialization of the meshing process.
*
* Initialization is considered to be complete if the triangulation is a 3D triangulation
* with at least one facet in the restricted Delaunay triangulation (i.e., its dual intersects the
* input surface).
*
* If one dimensional features are requested, their initialization is performed first.
* If provided, the points of `parameters::initial_points()` are inserted next.
* Then, `parameters::initial_points_generator()` is used to generate more initial points
* and complete the initialization.
* If the generator does not generate enough points for the initialization to be complete,
* the domain's `construct_initial_points_object()` will be called to generate enough input points.
*
* \tparam InitialPointsGenerator a model of the `InitialPointsGenerator_3` concept
*
* @param generator an instance of `InitialPointsGenerator`
*
* \cgalHeading{Example}
*
* \snippet mesh_3D_image_with_image_initialization.cpp Meshing
*
* \sa `CGAL::make_mesh_3()`
* \sa `CGAL::parameters::initial_points()`
* \sa `MeshDomain_3::Construct_initial_points`
*
*/
template <typename InitialPointsGenerator>
unspecified_type initial_points_generator(const InitialPointsGenerator& generator);

/*!
* \ingroup PkgMesh3Parameters
*
* The function `parameters::initial_points()` enables the user to specify a container, model of `Range`, that contains
* initial points constructed on surfaces,
* to be used in the `make_mesh_3()` function for mesh generation. Items in the container are
* tuple-like objects containing a `Weighted_point_3`, an `int`, and a `MeshDomain::Index`,
* where `Weighted_point_3` represents the position and the weight of the point,
* `int` the dimension of the minimal subcomplex on which the point lies,
* and `MeshDomain::Index` the corresponding subcomplex index.
* These initial points are inserted after one dimensional features initialization.
*
* Initialization is considered to be complete if the triangulation is a 3D triangulation
* with at least one facet in the restricted Delaunay triangulation (i.e., its dual intersects the
* input surface).
*
* If the parameter `parameters::initial_points_generator()` is set,
* the points from this parameter will be inserted before calling the initial points generator.
*
* If after the insertion of initial points (possibly together with the input generator),
* the initialization is not complete,
* the domain's `construct_initial_points_object()` will be called.
*
* \tparam MeshDomain a model of `MeshDomain_3`
* \tparam C3t3 a model of `MeshComplex_3InTriangulation_3`
* \tparam InitialPointsRange a model of `Range` containing tuple-like objects of
* `C3t3::Triangulation::Geom_traits::Weighted_point_3, int, MeshDomain::Index`.
*
* @param initial_points an instance of `InitialPointsRange`
*
* \cgalHeading{Example}
*
* \code{.cpp}
* // Create the initial_points vector
* std::vector<std::tuple<K::Weighted_point_3, int, Mesh_domain::Index>> initial_points;
* // Perform mesh generation from a labeled image with initial points
* C3t3 c3t3 = make_mesh_3<c3t3>(domain,
* criteria,
* parameters::initial_points(std::cref(initial_points))); // Use std::cref to avoid a copy
* \endcode
*
* \sa `CGAL::make_mesh_3()`
* \sa `CGAL::parameters::initial_points_generator()`
* \sa `MeshDomain_3::Construct_initial_points`
*
*/
template <typename MeshDomain, typename C3t3, typename InitialPointsRange>
unspecified_type initial_points(const InitialPointsRange& initial_points);
} /* namespace parameters */

} /* namespace CGAL */
64 changes: 64 additions & 0 deletions Mesh_3/doc/Mesh_3/Concepts/InitialPointsGenerator_3.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*!
\ingroup PkgMesh3SecondaryConcepts
\cgalConcept
The function object concept `InitialPointsGenerator_3` is designed to construct
a set of initial points on the surface of the domain.
\cgalHasModelsBegin
\cgalHasModels{CGAL::Construct_initial_points_labeled_image<C3t3, Mesh_domain>}
\cgalHasModels{CGAL::Construct_initial_points_gray_image<C3t3, Mesh_domain>}
\cgalHasModelsEnd
*/

class InitialPointsGenerator_3 {
public:

/// \name Types (exposition only)
/// @{
/// These types are used in the concept's description but are not part of the concept itself.

/*!
* Mesh domain type to be meshed, model of `MeshDomain_3`
*/
typedef unspecified_type MeshDomain;

/*!
* Type of the output mesh complex, model of `MeshComplex_3InTriangulation_3`
*/
typedef unspecified_type C3t3;
/// @}

/// \name Operations
/// @{
/// Initial points generators are designed to output, via their operators `operator(OutputIterator)`,
/// a set of surface points for mesh initialization to an output iterator.

/*!
outputs a set of surface points for mesh initialization.
If, after insertion of these points, the triangulation is still not 3D,
or does not have any facets
in the restricted Delaunay triangulation, then more points will be added automatically
by the mesh generator.
@tparam OutputIterator model of `OutputIterator` whose value type is a tuple-like object made of 3 elements:
- a `C3t3::Triangulation::Point` : the point `p`,
- an `int` : the minimal dimension of the subcomplexes on which `p` lies,
- a `MeshDomain_3::Index` : the index of the corresponding subcomplex.
@param pts an output iterator for the points
@param n a lower bound on the number of points to construct for initialization.
When `n` is set to its default value `0`, the functor must provide enough
points to initialize the mesh generation process, i.e., to have a 3D triangulation
with at least one facet in the restricted Delaunay triangulation.
If these conditions are not satisfied, then more points will be added automatically
by the mesh generator.
*/
template <typename OutputIterator>
OutputIterator operator()(OutputIterator pts, const int n = 0);

/// @}

}; /* end InitialPointsGenerator_3 */
4 changes: 3 additions & 1 deletion Mesh_3/doc/Mesh_3/Doxyfile.in
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ INPUT += \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Compact_mesh_cell_base_3.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_3/Detect_features_in_image.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_3/Detect_features_on_image_bbox.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_edge_criteria_3.h
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_edge_criteria_3.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_3/Construct_initial_points_labeled_image.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_3/Construct_initial_points_gray_image.h

PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 3D Mesh Generation"
HTML_EXTRA_FILES = ${CGAL_PACKAGE_DOC_DIR}/fig/implicit_domain_3.jpg \
Expand Down
Loading

0 comments on commit 54bfdfe

Please sign in to comment.