diff --git a/Kernel_23/doc/Kernel_23/CGAL/Kernel/global_functions.h b/Kernel_23/doc/Kernel_23/CGAL/Kernel/global_functions.h index 8b5624b408d..6be2530b49b 100644 --- a/Kernel_23/doc/Kernel_23/CGAL/Kernel/global_functions.h +++ b/Kernel_23/doc/Kernel_23/CGAL/Kernel/global_functions.h @@ -622,7 +622,7 @@ const CGAL::Point_3&r); /// \ingroup kernel_global_function /*! compares the angles \f$ \theta_1\f$ and \f$ \theta_2\f$, where -\f$ \theta_1\f$ is the angle, in \f$ [0, \pi]\f$, of the triangle +\f$ \theta_1\f$ is the angle in \f$ [0, \pi]\f$ of the triangle \f$ (a, b, c)\f$ at the vertex `b`, and \f$ \theta_2\f$ is the angle in \f$ [0, \pi]\f$ such that \f$ cos(\theta_2) = cosine\f$. \pre `a!=b && c!=b`. diff --git a/Kernel_23/doc/Kernel_23/Concepts/FunctionObjectConcepts.h b/Kernel_23/doc/Kernel_23/Concepts/FunctionObjectConcepts.h index 9bccd5a57ea..9084a652c93 100644 --- a/Kernel_23/doc/Kernel_23/Concepts/FunctionObjectConcepts.h +++ b/Kernel_23/doc/Kernel_23/Concepts/FunctionObjectConcepts.h @@ -759,7 +759,7 @@ public: /*! compares the angles \f$ \theta_1\f$ and \f$ \theta_2\f$, where - \f$ \theta_1\f$ is the angle, in \f$ [0, \pi]\f$, of the triangle + \f$ \theta_1\f$ is the angle in \f$ [0, \pi]\f$ of the triangle \f$ (a, b, c)\f$ at the vertex `b`, and \f$ \theta_2\f$ is the angle in \f$ [0, \pi]\f$ such that \f$ cos(\theta_2) = cosine\f$. \pre `a!=b && c!=b`. 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 b8552b601ab..ce5450b1089 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 @@ -153,18 +153,22 @@ algorithm while preserving the detected sharp edges is given in \ref Polygon_mesh_processing/delaunay_remeshing_example.cpp \paragraph Decimate Remeshing of (Almost) Planar Patches -If a triangulated surface mesh uses a lot of triangles to describe some planar regions of a model, it is possible to simplify -those parts using the function `CGAL::Polygon_mesh_processing::remesh_planar_patches()`. -For simply connected patches, it is even possible to not retriangulate them. -The coplanarity and collinearty tests being exact, almost coplanar patches will not be detected by default. It is possible to specify a -threshold on the angle between adjacent faces (resp. segments) so that they are considered coplanar (resp. collinear). However, this -coplanarity and collinearity tolerance is only local and there is no global control (think of the classical example of a circle arc -densely sampled: 3 consecutive points are seen as almost collinear while all the points on the arc are not). To circumvent this situation, -we also provide the function `CGAL::Polygon_mesh_processing::remesh_almost_planar_patches()` that expects the segmentation into -planar patches and corners to be provided. The function `CGAL::Polygon_mesh_processing::region_growing_of_planes_on_faces()` -uses the region growing algorithm to detect planar regions in a mesh with global and local criteria. Similarly, the function -`CGAL::Polygon_mesh_processing::detect_corners_of_regions()` can be used to detect corner vertices on the border of the planar -regions detected by running the region growing algorithm on border segments of the patch. +When many triangles are used to describe a planar region of a model, one might wish to simplify the mesh +in this region to use few elements, or even a single large polygonal face when the region makes up a simply connected patch. +This can be achieved using the function `CGAL::Polygon_mesh_processing::remesh_planar_patches()`. +This function performs the detection of the planar regions, using geometric predicates for coplanarity and +collinearity checks. If these tests are performed exactly, the planar regions can be unexpectedly small due to the +input in fact not being perfectly planar. To palliate this, it is possible to specify a threshold on the angle +between adjacent faces (resp. segments) such that they are considered coplanar (resp. collinear). +However, this tolerance threshold is only local and there is no global control, which can have undesired effects, such as in the classic example of a densely sampled circle arc where all points are eventually found +to be almost collinear). To circumvent this situation, we provide the function + `CGAL::Polygon_mesh_processing::remesh_almost_planar_patches()` , which expects the segmentation into +planar patches and corners to be provided by the user. Such segmentation can be obtained using the function + `CGAL::Polygon_mesh_processing::region_growing_of_planes_on_faces()`, which +uses the region growing algorithm to detect planar regions in a mesh with global and local criteria. +Similarly, the function `CGAL::Polygon_mesh_processing::detect_corners_of_regions()` can be used +to detect corner vertices on the border of the planar regions detected by running the region growing +algorithm on border segments of the patch. \cgalFigureBegin{decimate_cheese, decimate_cheese.png, decimate_colors.png} diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/remesh_planar_patches.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/remesh_planar_patches.cpp index 0356ced84ea..9f591e6a269 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/remesh_planar_patches.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/remesh_planar_patches.cpp @@ -22,6 +22,7 @@ int main() // triangulate faces; PMP::triangulate_faces(sm); + std::cout << "Input mesh has " << faces(sm).size() << " faces" << std::endl; assert(faces(sm).size()==12); Surface_mesh::Property_map ecm = @@ -32,16 +33,17 @@ int main() // create a remeshed version of the cube with many elements PMP::isotropic_remeshing(faces(sm), 0.1, sm, CGAL::parameters::edge_is_constrained_map(ecm)); - std::ofstream("cube_remeshed.off") << sm; + CGAL::IO::write_polygon_mesh("cube_remeshed.off", sm, CGAL::parameters::stream_precision(17)); assert(faces(sm).size()>100); // decimate the mesh Surface_mesh out; PMP::remesh_planar_patches(sm, out); - std::ofstream("cube_decimated.off") << out; + CGAL::IO::write_polygon_mesh("cube_decimated.off", out, CGAL::parameters::stream_precision(17)); // we should be back to 12 faces + std::cout << "Output mesh has " << faces(out).size() << " faces" << std::endl; assert(faces(out).size()==12); - return 0; + return EXIT_SUCCESS; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh_planar_patches.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh_planar_patches.h index ffff67985c0..a0d4eb02747 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh_planar_patches.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh_planar_patches.h @@ -27,12 +27,13 @@ #include #include -#include + #include #include #include #include +#include namespace CGAL{ @@ -1290,8 +1291,8 @@ bool decimate_meshes_with_common_interfaces_impl(TriangleMeshRange& meshes, * \ingroup PMP_meshing_grp * generates a new triangle mesh `tm_out` with the minimal number of triangles while preserving the shape as `tm_in`. * In practice, this means that connected components of edge incident faces belonging to the same plane are - * first extracted (each such connected component is called a *patch*). Then the connected components of vertex - * connected patch border edges belonging to the same line are extracted. Endpoints of such components and + * first extracted (each such connected component is called a *patch*). Then, the connected components of + * vertex-connected patch border edges belonging to the same line are extracted. Endpoints of such components and * vertices incident to more than two patches (or two patches + one mesh boundary) are called *corners*. * `tm_out` contains the 2D constrained Delaunay triangulation of each patch using only corner vertices * on the boundary of the patch.