remove return_empty_on_invalid_input

and show in an example how to check preconditions
This commit is contained in:
Jane Tournois 2025-06-13 14:30:05 +02:00
parent 1323411457
commit fb898e9ab1
4 changed files with 57 additions and 51 deletions

View File

@ -1,11 +1,18 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/IO/polygon_mesh_io.h>
#include <CGAL/IO/write_MEDIT.h>
#include <CGAL/Surface_mesh/Surface_mesh.h> #include <CGAL/Surface_mesh/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
#include <CGAL/boost/graph/copy_face_graph.h>
#include <CGAL/Polygon_mesh_processing/polygon_mesh_to_polygon_soup.h>
#include <CGAL/make_conforming_constrained_Delaunay_triangulation_3.h> #include <CGAL/make_conforming_constrained_Delaunay_triangulation_3.h>
#include <CGAL/draw_constrained_triangulation_3.h> #include <CGAL/draw_constrained_triangulation_3.h>
#include <CGAL/IO/polygon_mesh_io.h>
#include <CGAL/IO/write_MEDIT.h>
#include <vector>
using K = CGAL::Exact_predicates_inexact_constructions_kernel; using K = CGAL::Exact_predicates_inexact_constructions_kernel;
using Point = K::Point_3; using Point = K::Point_3;
@ -13,13 +20,36 @@ using Surface_mesh = CGAL::Surface_mesh<Point>;
namespace PMP = CGAL::Polygon_mesh_processing; namespace PMP = CGAL::Polygon_mesh_processing;
// Function to verify preconditions for a mesh input
bool verify_preconditions_mesh(const Surface_mesh& mesh)
{
if(CGAL::is_triangle_mesh(mesh))
return !CGAL::Polygon_mesh_processing::does_self_intersect(mesh);
Surface_mesh triangle_mesh;
CGAL::copy_face_graph(mesh, triangle_mesh);
bool tri_ok = CGAL::Polygon_mesh_processing::triangulate_faces(triangle_mesh);
if(!tri_ok)
return false;
return !CGAL::Polygon_mesh_processing::does_self_intersect(triangle_mesh);
}
// Function to verify preconditions for a polygon soup input
template <typename PointRange, typename PolygonRange>
bool verify_preconditions_soup(const PointRange& points, const PolygonRange& polygons)
{
return !CGAL::Polygon_mesh_processing::does_polygon_soup_self_intersect(points, polygons);
}
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
const auto filename = (argc > 1) ? argv[1] const auto filename = (argc > 1) ? argv[1]
: CGAL::data_file_path("meshes/mpi_and_sphere.off"); : CGAL::data_file_path("meshes/mpi_and_sphere.off");
CGAL::Surface_mesh<K::Point_3> mesh; CGAL::Surface_mesh<K::Point_3> mesh;
if(!CGAL::IO::read_polygon_mesh(filename, mesh)) { if(!CGAL::IO::read_polygon_mesh(filename, mesh))
{
std::cerr << "Error: cannot read file " << filename << std::endl; std::cerr << "Error: cannot read file " << filename << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -27,8 +57,25 @@ int main(int argc, char* argv[])
std::cout << "Number of facets in " << filename << ": " std::cout << "Number of facets in " << filename << ": "
<< mesh.number_of_faces() << "\n"; << mesh.number_of_faces() << "\n";
auto ccdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3(mesh, // Verify preconditions for the mesh input
CGAL::parameters::return_empty_on_invalid_input(true)); if(!verify_preconditions_mesh(mesh))
{
// If the mesh is not a valid triangle mesh or has self-intersections,
// convert it to a polygon soup and verify the preconditions for the soup
std::vector<K::Point_3> points;
std::vector<std::vector<std::size_t>> polygons;
CGAL::Polygon_mesh_processing::polygon_mesh_to_polygon_soup(mesh, points, polygons);
if(!verify_preconditions_soup(points, polygons))
{
std::cerr << "Error: input polygon soup is not a valid input for CCDT_3\n";
return EXIT_FAILURE;
}
std::cerr << "Error: input mesh is not a valid input for CCDT_3\n";
return EXIT_FAILURE;
}
auto ccdt = CGAL::make_conforming_constrained_Delaunay_triangulation_3(mesh);
if(ccdt.number_of_constrained_facets() == 0) if(ccdt.number_of_constrained_facets() == 0)
{ {

View File

@ -638,18 +638,6 @@ public:
// ---------------------------------- // ----------------------------------
using parameters::choose_parameter; using parameters::choose_parameter;
using parameters::get_parameter; using parameters::get_parameter;
#ifndef CGAL_CDT_3_DISABLE_INPUT_CHECKS
const bool return_empty_on_invalid_input =
choose_parameter(get_parameter(np, internal_np::return_empty_on_invalid_input), false);
if (choose_parameter(get_parameter(np, internal_np::do_self_intersection_tests), true))
{
CGAL_precondition_msg(return_empty_on_invalid_input || preconditions_verified_mesh(mesh, np),
"Conforming_constrained_Delaunay_triangulation_3: mesh self-intersects");
}
if(return_empty_on_invalid_input && !preconditions_verified_mesh(mesh, np)) return;
#endif
auto mesh_vp_map = choose_parameter(get_parameter(np, internal_np::vertex_point), get(CGAL::vertex_point, mesh)); auto mesh_vp_map = choose_parameter(get_parameter(np, internal_np::vertex_point), get(CGAL::vertex_point, mesh));
@ -777,15 +765,6 @@ public:
// ---------------------------------- // ----------------------------------
using parameters::choose_parameter; using parameters::choose_parameter;
using parameters::get_parameter; using parameters::get_parameter;
#ifndef CGAL_CDT_3_DISABLE_INPUT_CHECKS
const bool return_empty_on_invalid_input =
choose_parameter(get_parameter(np, internal_np::return_empty_on_invalid_input), false);
CGAL_precondition_msg(return_empty_on_invalid_input || preconditions_verified_soup(points, polygons, np),
"Conforming_constrained_Delaunay_triangulation_3: polygon soup self-intersects");
if(return_empty_on_invalid_input && !preconditions_verified_soup(points, polygons, np)) return;
#endif
using PointRange_const_iterator = typename PointRange::const_iterator; using PointRange_const_iterator = typename PointRange::const_iterator;
using PointRange_value_type = typename std::iterator_traits<PointRange_const_iterator>::value_type; using PointRange_value_type = typename std::iterator_traits<PointRange_const_iterator>::value_type;

View File

@ -43,16 +43,19 @@ namespace CGAL {
By default, each face of the input is considered a polygonal constraint for the triangulation. The By default, each face of the input is considered a polygonal constraint for the triangulation. The
named parameter `plc_face_id` can be used to describe larger polygonal constraints, possibly with holes. If named parameter `plc_face_id` can be used to describe larger polygonal constraints, possibly with holes. If
used, this parameter must be a property map that associates each face of the input with a patch used, this parameter must be a property map that associates each face of the input with a PLC face
identifier. Faces with the same patch identifier are considered part of the same surface patch. Each of these identifier. Faces with the same face identifier are considered part of the same surface patch. Each of these
surface patches (defined as the union of the input faces with a given patch identifier) is expected to be a polygon or surface patches (defined as the union of the input faces with a given patch identifier) is expected to be a polygon or
a polygon with holes, with coplanar vertices (or nearly coplanar up to the precision of the number type used). a polygon with holes, with coplanar vertices (or nearly coplanar up to the precision of the number type used).
The generated triangulation will conform to the faces of the input, or to the surface patches The generated triangulation will conform to the faces of the input, or to the surface patches
described by the `plc_face_id` property map if provided. described by the `plc_face_id` property map if provided.
In the case where the input contains a non-planar PLC face, building the triangulation may fail with an exception
of type `CGAL::Non_planar_plc_facet_exception`.
\pre The input data must not be coplanar. \pre The input data must not be coplanar.
\pre The input data must not have self-intersections.
Template Parameters {#make_conforming_constrained_Delaunay_triangulation_3_template_parameters} Template Parameters {#make_conforming_constrained_Delaunay_triangulation_3_template_parameters}
------------------- -------------------
@ -121,16 +124,6 @@ namespace CGAL {
* Faces of `mesh` with the same patch identifier are considered part of the same PLC face.} * Faces of `mesh` with the same patch identifier are considered part of the same PLC face.}
* \cgalParamNEnd * \cgalParamNEnd
* *
* \cgalParamNBegin{return_empty_on_invalid_input}
* \cgalParamDescription{a Boolean activating the check of preconditions on the input
* before starting to construct the triangulation.
* If the check is activated and the preconditions are not satisfied,
* an empty triangulation is immediately returned.}
* \cgalParamType{Boolean}
* \cgalParamDefault{`false`}
* \cgalParamExtra{If this parameter is set to `false` and the preconditions are not satisfied, the algorithm may throw an exception or crash.}
* \cgalParamNEnd
*
* \cgalParamNBegin{geom_traits} * \cgalParamNBegin{geom_traits}
* \cgalParamDescription{an instance of a geometric traits class} * \cgalParamDescription{an instance of a geometric traits class}
* \cgalParamType{`Traits` as defined above in the section \ref make_conforming_constrained_Delaunay_triangulation_3_returned_type} * \cgalParamType{`Traits` as defined above in the section \ref make_conforming_constrained_Delaunay_triangulation_3_returned_type}
@ -199,16 +192,6 @@ auto make_conforming_constrained_Delaunay_triangulation_3(const PolygonMesh &mes
* \cgalParamExtra{Otherwise facets with the same patch identifier are considered part of the same PLC face.} * \cgalParamExtra{Otherwise facets with the same patch identifier are considered part of the same PLC face.}
* \cgalParamNEnd * \cgalParamNEnd
* *
* \cgalParamNBegin{return_empty_on_invalid_input}
* \cgalParamDescription{a Boolean activating the check of preconditions on the input
* before starting to construct the triangulation.
* If the check is activated and the preconditions are not satisfied,
* an empty triangulation is immediately returned.}
* \cgalParamType{Boolean}
* \cgalParamDefault{`false`}
* \cgalParamExtra{If this parameter is set to `false` and the preconditions are not satisfied, the algorithm may throw an exception or crash.}
* \cgalParamNEnd
*
* \cgalParamNBegin{geom_traits} * \cgalParamNBegin{geom_traits}
* \cgalParamDescription{an instance of a geometric traits class} * \cgalParamDescription{an instance of a geometric traits class}
* \cgalParamType{`Traits` as defined above in the section \ref make_conforming_constrained_Delaunay_triangulation_3_returned_type} * \cgalParamType{`Traits` as defined above in the section \ref make_conforming_constrained_Delaunay_triangulation_3_returned_type}

View File

@ -325,9 +325,6 @@ CGAL_add_named_parameter(preserve_order_t, preserve_order, preserve_order)
CGAL_add_named_parameter(adjust_directions_t, adjust_directions, adjust_directions) CGAL_add_named_parameter(adjust_directions_t, adjust_directions, adjust_directions)
CGAL_add_named_parameter(segment_t, segment_map, segment_map) CGAL_add_named_parameter(segment_t, segment_map, segment_map)
// List of named parameters using in Constrained_triangulation_3
CGAL_add_named_parameter(return_empty_on_invalid_input_t, return_empty_on_invalid_input, return_empty_on_invalid_input)
// List of named parameters used in Mesh_2 package // List of named parameters used in Mesh_2 package
CGAL_add_named_parameter_with_compatibility(seeds_t, seeds, seeds) CGAL_add_named_parameter_with_compatibility(seeds_t, seeds, seeds)
CGAL_add_named_parameter_with_compatibility(domain_is_initialized_t, domain_is_initialized, domain_is_initialized) CGAL_add_named_parameter_with_compatibility(domain_is_initialized_t, domain_is_initialized, domain_is_initialized)