diff --git a/BGL/include/CGAL/boost/graph/Seam_mesh.h b/BGL/include/CGAL/boost/graph/Seam_mesh.h
index 8df36e3ff4c..429e38c98ee 100644
--- a/BGL/include/CGAL/boost/graph/Seam_mesh.h
+++ b/BGL/include/CGAL/boost/graph/Seam_mesh.h
@@ -1017,7 +1017,7 @@ public:
/// of a vertex of the underlying mesh is given by its position
/// in the container `tm_vds`.
///
- /// \tparam VdContainer must be a model of SequenceContainer (that is, provide
+ /// \tparam VdContainer must be a model of `SequenceContainer` (that is, provide
/// the functions: `operator[]` and `at()`).
///
/// \returns one of the halfedges of the seam mesh that is on a seam.
@@ -1062,7 +1062,7 @@ public:
///
/// \returns one of the halfedges of the seam mesh that is on a seam.
///
- /// \tparam VdContainer must be a model of SequenceContainer (that is, provide
+ /// \tparam VdContainer must be a model of `SequenceContainer` (that is, provide
/// the functions: `operator[]` and `at()`).
///
/// \pre filename should be the name of a CGAL selection file: edges are
diff --git a/BGL/include/CGAL/boost/graph/parameters_interface.h b/BGL/include/CGAL/boost/graph/parameters_interface.h
index 01c9796e813..3272be27bfe 100644
--- a/BGL/include/CGAL/boost/graph/parameters_interface.h
+++ b/BGL/include/CGAL/boost/graph/parameters_interface.h
@@ -79,6 +79,8 @@ CGAL_add_named_parameter(throw_on_self_intersection_t, throw_on_self_intersectio
CGAL_add_named_parameter(clip_volume_t, clip_volume, clip_volume)
CGAL_add_named_parameter(use_compact_clipper_t, use_compact_clipper, use_compact_clipper)
CGAL_add_named_parameter(output_iterator_t, output_iterator, output_iterator)
+CGAL_add_named_parameter(erase_all_duplicates_t, erase_all_duplicates, erase_all_duplicates)
+CGAL_add_named_parameter(require_same_orientation_t, require_same_orientation, require_same_orientation)
// 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)
diff --git a/BGL/test/BGL/test_cgal_bgl_named_params.cpp b/BGL/test/BGL/test_cgal_bgl_named_params.cpp
index 22252abdd36..db322900b15 100644
--- a/BGL/test/BGL/test_cgal_bgl_named_params.cpp
+++ b/BGL/test/BGL/test_cgal_bgl_named_params.cpp
@@ -85,6 +85,8 @@ void test(const NamedParameters& np)
assert(get_param(np, CGAL::internal_np::throw_on_self_intersection).v == 43);
assert(get_param(np, CGAL::internal_np::clip_volume).v == 44);
assert(get_param(np, CGAL::internal_np::use_compact_clipper).v == 45);
+ assert(get_param(np, CGAL::internal_np::erase_all_duplicates).v == 48);
+ assert(get_param(np, CGAL::internal_np::require_same_orientation).v == 49);
// Named parameters that we use in the package 'Surface Mesh Simplification'
assert(get_param(np, CGAL::internal_np::get_cost_policy).v == 34);
@@ -162,6 +164,8 @@ void test(const NamedParameters& np)
check_same_type<43>(get_param(np, CGAL::internal_np::throw_on_self_intersection));
check_same_type<44>(get_param(np, CGAL::internal_np::clip_volume));
check_same_type<45>(get_param(np, CGAL::internal_np::use_compact_clipper));
+ check_same_type<48>(get_param(np, CGAL::internal_np::erase_all_duplicates));
+ check_same_type<49>(get_param(np, CGAL::internal_np::require_same_orientation));
// Named parameters that we use in the package 'Surface Mesh Simplification'
check_same_type<34>(get_param(np, CGAL::internal_np::get_cost_policy));
@@ -241,6 +245,8 @@ int main()
.use_compact_clipper(A<45>(45))
.apply_per_connected_component(A<46>(46))
.output_iterator(A<47>(47))
+ .erase_all_duplicates(A<48>(48))
+ .require_same_orientation(A<49>(49))
);
return EXIT_SUCCESS;
diff --git a/Barycentric_coordinates_2/doc/Barycentric_coordinates_2/Barycentric_coordinates_2.txt b/Barycentric_coordinates_2/doc/Barycentric_coordinates_2/Barycentric_coordinates_2.txt
index da226aedf29..855db161ee9 100644
--- a/Barycentric_coordinates_2/doc/Barycentric_coordinates_2/Barycentric_coordinates_2.txt
+++ b/Barycentric_coordinates_2/doc/Barycentric_coordinates_2/Barycentric_coordinates_2.txt
@@ -223,7 +223,7 @@ From the figure above it is easy to see that the \f$O(n^2)\f$ algorithm is as fa
The generic design of the package was developed in 2013 by Dmitry Anisimov and David Bommes with many useful comments by Kai Hormann and Pierre Alliez. The package consists of 6 classes, 2 enumerations, and one namespace. Appropriate iterators are used to provide an efficient access to data and to pass them to one of the generic algorithms for computing coordinates. Once instantiated for a polygon (triangle, segment), the coordinates can be computed multiple times for different query points with respect to all the vertices of the provided polygon (triangle, segment). All the classes are fully templated and have a simple and similar design. In particular, we follow the same naming convention for all functions. Yet, the number of functions can differ from one class to another.
-The implemented algorithms for computing coordinates do not depend on a particular kernel, and all the coordinates can be computed exactly, if an exact kernel is used, apart from mean value coordinates. The latter coordinates involve a square root operation, which results in a slightly worse precision with exact data types due to temporal conversion into a floating point type. The computed coordinates can be stored in an arbitrary container if an appropriate output iterator is provided.
+The implemented algorithms for computing coordinates do not depend on a particular kernel, and all the coordinates can be computed exactly, if an exact kernel is used, apart from mean value coordinates. The latter coordinates involve a square root operation, which results in a slightly worse precision with exact data types due to temporal conversion into a floating point type. The computed coordinates can be stored in an arbitrary container if an appropriate output iterator is provided.
It is worth noting that the class `CGAL::Barycentric_coordinates::Segment_coordinates_2` is used to compute generalized barycentric coordinates along the polygon's boundary. Hence, one can use the trick for segment coordinates from Section \ref gbc_degeneracies if one is convinced that a point must lie exactly on the polygon's boundary but due to some numerical instabilities it does not.
diff --git a/Documentation/doc/Documentation/General.txt b/Documentation/doc/Documentation/General.txt
index 275c0e03963..ccb1c7e89e6 100644
--- a/Documentation/doc/Documentation/General.txt
+++ b/Documentation/doc/Documentation/General.txt
@@ -94,11 +94,37 @@ class RandomAccessIterator {};
/// See https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator
class BidirectionalIterator {};
+/// \cgalConcept
+/// Concept from the \cpp standard.
+/// See https://en.cppreference.com/w/cpp/named_req/Swappable
+class Swappable {};
+
+/// \cgalConcept
+/// Concept from the \cpp standard.
+/// See https://en.cppreference.com/w/cpp/named_req/Container
+class Container {};
+
+/// \cgalConcept
+/// Concept from the \cpp standard.
+/// See https://en.cppreference.com/w/cpp/named_req/ReversibleContainer
+class ReversibleContainer {};
+
+/// \cgalConcept
+/// Concept from the \cpp standard.
+/// See https://en.cppreference.com/w/cpp/named_req/AssociativeContainer
+class AssociativeContainer {};
+
+/// \cgalConcept
+/// Concept from the \cpp standard.
+/// See https://en.cppreference.com/w/cpp/named_req/SequenceContainer
+class SequenceContainer {};
+
/// \cgalConcept
/// This container concept refines
/// ReversibleContainer and its iterator type is a model of
-/// RandomAccessIterator.
+/// RandomAccessIterator./// \cgalConcept
class RandomAccessContainer {};
+
/// \cgalConcept
/// This container concepts refines
/// SequenceContainer and
diff --git a/Mesh_3/include/CGAL/IO/facets_in_complex_3_to_triangle_mesh.h b/Mesh_3/include/CGAL/IO/facets_in_complex_3_to_triangle_mesh.h
index dd4f88ab26d..7fd025f7a73 100644
--- a/Mesh_3/include/CGAL/IO/facets_in_complex_3_to_triangle_mesh.h
+++ b/Mesh_3/include/CGAL/IO/facets_in_complex_3_to_triangle_mesh.h
@@ -54,7 +54,7 @@ void resize(Polygon& p, std::size_t size)
template
void resize(CGAL::cpp11::array&, std::size_t CGAL_assertion_code(size))
{
- CGAL_assertion(size >= N);
+ CGAL_assertion(size == N);
}
template
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 5b8f04688b4..43f75dc2091 100644
--- a/Mesh_3/include/CGAL/Polyhedral_complex_mesh_domain_3.h
+++ b/Mesh_3/include/CGAL/Polyhedral_complex_mesh_domain_3.h
@@ -414,9 +414,9 @@ public:
needed_vertices_on_patch[i] = (std::min)(nb_of_extra_vertices_per_patch,
needed_vertices_on_patch[i]);
}
+
// Then a second path to fill `several_vertices_on_patch`...
// The algorithm is adapted from SGI `random_sample_n`:
- // https://www.sgi.com/tech/stl/random_sample_n.html
BOOST_FOREACH(const Polyhedron& p, this->stored_polyhedra)
{
for (typename Polyhedron::Vertex_const_iterator
diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt
index a2c5456db34..fa8022005e1 100644
--- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt
+++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt
@@ -329,15 +329,15 @@ Parameter used in `isotropic_remeshing()` to specify an alternative vertex proje
\cgalNPBegin{apply_per_connected_component} \anchor PMP_apply_per_connected_component
Parameter used to indicate whether an algorithm should consider each connected component
of a mesh independently.\n
-\b Type : `bool` \n
-\b Default value is `false`
+Type: `bool` \n
+Default: `false`
\cgalNPEnd
\cgalNPBegin{visitor} \anchor PMP_visitor
Parameter used to pass a visitor class to a function. Its type and behavior depend on the visited function.
\n
-\b Type : `A class` \n
-\b Default : Specific to the function visited
+Type: `A class` \n
+Default: Specific to the function visited
\cgalNPEnd
\cgalNPBegin{throw_on_self_intersection} \anchor PMP_throw_on_self_intersection
@@ -345,23 +345,23 @@ Parameter used in corefinement-related functions to make the functions throw an
case some faces involved in the intersection of the input are self-intersecting
and make the operation impossible with the current version of the code.
\n
-\b Type : `bool` \n
-\b Default value is `false`
+Type: `bool` \n
+Default: `false`
\cgalNPEnd
\cgalNPBegin{clip_volume} \anchor PMP_clip_volume
Parameter used in `clip()` functions to clip a volume rather than a surface.
\n
-\b Type : `bool` \n
-\b Default value is `false`
+Type: `bool` \n
+Default: `false`
\cgalNPEnd
\cgalNPBegin{use_compact_clipper} \anchor PMP_use_compact_clipper
Parameter used in `clip()` functions to indicate whether the boundary of the clipper
should be considered as part of the clipping volume or not.
\n
-\b Type : `bool` \n
-\b Default value is `true`
+Type: `bool` \n
+Default: `true`
\cgalNPEnd
\cgalNPBegin{output_iterator} \anchor PMP_output_iterator
@@ -371,6 +371,23 @@ Parameter to pass an output iterator.
\b Default : `Emptyset_iterator`
\cgalNPEnd
+\cgalNPBegin{erase_all_duplicates} \anchor PMP_erase_all_duplicates
+Parameter used in the function `merge_duplicate_polygons_in_polygon_soup()` to indicate,
+when multiple faces are duplicates, whether all the duplicate faces should be removed
+or if one (arbitrarily chosen) face should be kept.
+\n
+Type: `bool` \n
+Default: `false`
+\cgalNPEnd
+
+\cgalNPBegin{require_same_orientation} \anchor PMP_require_same_orientation
+Parameter used in the function `merge_duplicate_polygons_in_polygon_soup()` to indicate
+if orientation should matter when determining whether two faces are duplicates.
+\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 e2a59d63cf9..f5025dcb442 100644
--- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt
+++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt
@@ -36,7 +36,7 @@
/// \ingroup PkgPolygonMeshProcessing
/// \defgroup PMP_repairing_grp Combinatorial Repairing
-/// Functions to orient polygon soups and to stitch geometrically identical boundaries.
+/// Functions to repair polygon soups and polygon meshes.
/// \ingroup PkgPolygonMeshProcessing
/// \defgroup PMP_distance_grp Distance Functions
@@ -128,7 +128,11 @@ and provides a list of the parameters that are used in this package.
- `CGAL::Polygon_mesh_processing::reverse_face_orientations()`
## Combinatorial Repairing Functions ##
-- \link PMP_repairing_grp `CGAL::Polygon_mesh_processing::stitch_borders()` \endlink
+- `CGAL::Polygon_mesh_processing::merge_duplicate_points_in_polygon_soup()`
+- `CGAL::Polygon_mesh_processing::merge_duplicate_polygons_in_polygon_soup()`
+- `CGAL::Polygon_mesh_processing::remove_isolated_points_in_polygon_soup()`
+- `CGAL::Polygon_mesh_processing::repair_polygon_soup()`
+- `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::remove_isolated_vertices()`
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 e09b5620d85..d6a0b0e5e03 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
@@ -531,7 +531,20 @@ Section \ref PMPOrientation.
****************************************
\section PMPRepairing Combinatorial Repairing
+
*******************
+\subsection PSRepairing Polygon Soup Repairing
+To ensure that a polygon soup can be oriented (see Section \ref PolygonSoups) and transformed
+into a workable polygon mesh, it might be necessary to preprocess the data to remove combinatorial
+and geometrical errors. This package offers the following functions:
+- `CGAL::Polygon_mesh_processing::merge_duplicate_points_in_polygon_soup()`,
+- `CGAL::Polygon_mesh_processing::merge_duplicate_polygons_in_polygon_soup()`,
+- `CGAL::Polygon_mesh_processing::remove_isolated_points_in_polygon_soup()`,
+
+as well as the function `CGAL::Polygon_mesh_processing::repair_polygon_soup()`,
+which bundles the previous functions and an additional handful of repairing techniques
+to obtain an as-clean-as-possible polygon soup.
+
\subsection Stitching
It happens that a polygon mesh has several edges and vertices that are duplicated.
@@ -575,6 +588,8 @@ is output.
\endif
\subsection PMPManifoldness Polygon Mesh Manifoldness
+This package offers repairing methods to clean ill-formed polygon soups,
+see Section \ref PMPRepairing.
Non-manifold vertices can be detected using the function `CGAL::Polygon_mesh_processing::is_non_manifold_vertex()`.
The function `CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices()` can be used
diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt
index cb09da7d83f..f5aa23b864b 100644
--- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt
+++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt
@@ -22,4 +22,5 @@
\example Polygon_mesh_processing/corefinement_consecutive_bool_op.cpp
\example Polygon_mesh_processing/detect_features_example.cpp
\example Polygon_mesh_processing/manifoldness_repair_example.cpp
+\example Polygon_mesh_processing/repair_polygon_soup_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 2a3bc719826..31283d2708f 100644
--- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt
+++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt
@@ -105,6 +105,7 @@ 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" )
if(OpenMesh_FOUND)
create_single_source_cgal_program( "compute_normals_example_OM.cpp" )
diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/repair_polygon_soup_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/repair_polygon_soup_example.cpp
new file mode 100644
index 00000000000..e44be56106e
--- /dev/null
+++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/repair_polygon_soup_example.cpp
@@ -0,0 +1,82 @@
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+
+typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
+typedef K::Point_3 Point_3;
+
+typedef std::vector Polygon;
+typedef CGAL::Surface_mesh Mesh;
+
+namespace PMP = CGAL::Polygon_mesh_processing;
+
+int main(int, char**)
+{
+ // First, construct a polygon soup with some problems
+ std::vector points;
+ std::vector polygons;
+
+ points.push_back(Point_3(0,0,0));
+ points.push_back(Point_3(1,0,0));
+ points.push_back(Point_3(0,1,0));
+ points.push_back(Point_3(-1,0,0));
+ points.push_back(Point_3(0,-1,0));
+ points.push_back(Point_3(0,1,0)); // duplicate point
+ points.push_back(Point_3(0,-2,0)); // unused point
+
+ Polygon p;
+ p.push_back(0); p.push_back(1); p.push_back(2);
+ polygons.push_back(p);
+
+ // degenerate face
+ p.clear();
+ p.push_back(0); p.push_back(0); p.push_back(0);
+ polygons.push_back(p);
+
+ p.clear();
+ p.push_back(0); p.push_back(1); p.push_back(4);
+ polygons.push_back(p);
+
+ // duplicate face with different orientation
+ p.clear();
+ p.push_back(0); p.push_back(4); p.push_back(1);
+ polygons.push_back(p);
+
+ p.clear();
+ p.push_back(0); p.push_back(3); p.push_back(5);
+ polygons.push_back(p);
+
+ // degenerate face
+ p.clear();
+ p.push_back(0); p.push_back(3); p.push_back(0);
+ polygons.push_back(p);
+
+ p.clear();
+ p.push_back(0); p.push_back(3); p.push_back(4);
+ polygons.push_back(p);
+
+ // pinched and degenerate face
+ p.clear();
+ p.push_back(0); p.push_back(1); p.push_back(2); p.push_back(3);
+ p.push_back(4); p.push_back(3); p.push_back(2); p.push_back(1);
+ polygons.push_back(p);
+
+ PMP::repair_polygon_soup(points, polygons);
+ PMP::orient_polygon_soup(points, polygons);
+
+ Mesh mesh;
+ PMP::polygon_soup_to_polygon_mesh(points, polygons, mesh);
+
+ std::cout << "Mesh has " << num_vertices(mesh) << " vertices and " << num_faces(mesh) << " faces" << std::endl;
+
+ assert(num_vertices(mesh) == 5);
+ assert(num_faces(mesh) == 4);
+
+ return 0;
+}
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 c72b3d54d98..df4a7fd80ab 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
@@ -277,7 +277,7 @@ void keep_connected_components(PolygonMesh& pmesh
*
* \param pmesh the polygon mesh
* \param nb_components_to_keep the number of components to be kept
- * \param np optional \ref pmp_namedparameters "Named Parameters" described below
+ * \param np optional \ref pmp_namedparameters "Named Parameters", amongst those described below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{edge_is_constrained_map} a property map containing the constrained-or-not status of each edge of `pmesh` \cgalParamEnd
@@ -360,7 +360,7 @@ std::size_t keep_largest_connected_components(PolygonMesh& pmesh,
*
* \param pmesh the polygon mesh
* \param threshold_components_to_keep the number of faces a component must have so that it is kept
- * \param np optional \ref pmp_namedparameters "Named Parameters" described below
+ * \param np optional \ref pmp_namedparameters "Named Parameters", amongst those described below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{edge_is_constrained_map} a property map containing the constrained-or-not status of each edge of `pmesh` \cgalParamEnd
@@ -664,7 +664,7 @@ void remove_connected_components(PolygonMesh& pmesh
*
* \param components_to_remove a face range, including one face or more on each component to be removed
* \param pmesh the polygon mesh
-* \param np optional \ref pmp_namedparameters "Named Parameters" described below
+* \param np optional \ref pmp_namedparameters "Named Parameters", amongst those described below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{edge_is_constrained_map} a property map containing the constrained-or-not status of each edge of `pmesh` \cgalParamEnd
@@ -722,7 +722,7 @@ void remove_connected_components(PolygonMesh& pmesh
*
* \param pmesh the polygon mesh
* \param components_to_keep a face range, including one face or more on each component to be kept
-* \param np optional \ref pmp_namedparameters "Named Parameters" described below
+* \param np optional \ref pmp_namedparameters "Named Parameters", amongst those described below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{edge_is_constrained_map} a property map containing the constrained-or-not status of each edge of `pmesh` \cgalParamEnd
diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/detect_features.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/detect_features.h
index 330e348277b..787c812650c 100644
--- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/detect_features.h
+++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/detect_features.h
@@ -258,7 +258,7 @@ template
+
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include