From 22732a9ae3078b3c6c21353032010d90bf141910 Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Thu, 27 Jun 2024 10:55:33 +0200 Subject: [PATCH 1/9] using proper triangulated polygonal faces for linear_least_squares --- .../Least_squares_plane_fit_region.h | 58 +++++++++------- .../Region_growing/internal/utils.h | 68 +++++++++++++++++-- 2 files changed, 94 insertions(+), 32 deletions(-) diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polygon_mesh/Least_squares_plane_fit_region.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polygon_mesh/Least_squares_plane_fit_region.h index 74fa797fee41..4ad508662910 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polygon_mesh/Least_squares_plane_fit_region.h +++ b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polygon_mesh/Least_squares_plane_fit_region.h @@ -19,6 +19,7 @@ // Internal includes. #include #include +#include namespace CGAL { namespace Shape_detection { @@ -83,12 +84,16 @@ namespace Polygon_mesh { using Point_3 = typename GeomTraits::Point_3; using Vector_3 = typename GeomTraits::Vector_3; using Plane_3 = typename GeomTraits::Plane_3; + using Triangle_3 = typename GeomTraits::Triangle_3; using Squared_length_3 = typename GeomTraits::Compute_squared_length_3; using Squared_distance_3 = typename GeomTraits::Compute_squared_distance_3; using Scalar_product_3 = typename GeomTraits::Compute_scalar_product_3; using Cross_product_3 = typename GeomTraits::Construct_cross_product_vector_3; + std::unordered_map > m_face_normals; + std::unordered_map, internal::hash_item > m_face_triangulations; + public: /// \name Initialization /// @{ @@ -158,6 +163,28 @@ namespace Polygon_mesh { m_scalar_product_3(m_traits.compute_scalar_product_3_object()), m_cross_product_3(m_traits.construct_cross_product_vector_3_object()) { + for (const Item &i : faces(pmesh)) { + m_face_normals[i] = Polygon_mesh_processing::compute_face_normal(i, pmesh); + std::vector pts; + auto h = halfedge(i, pmesh); + auto s = h; + + do { + pts.push_back(get(m_vertex_to_point_map, target(h, pmesh))); + h = next(h, pmesh); + } while (h != s); + + std::vector> output; + + Polygon_mesh_processing::triangulate_hole_polyline(pts, std::back_inserter(output), parameters::use_2d_constrained_delaunay_triangulation(true)); + + std::vector& tris = m_face_triangulations[i]; + tris.reserve(output.size()); + assert(!output.empty()); + for (const auto& t : output) + tris.push_back(Triangle_3(pts[t.first], pts[t.second], pts[t.third])); + } + CGAL_precondition(faces(m_face_graph).size() > 0); const FT max_distance = parameters::choose_parameter( parameters::get_parameter(np, internal_np::maximum_distance), FT(1)); @@ -234,7 +261,7 @@ namespace Polygon_mesh { const FT squared_distance_threshold = m_distance_threshold * m_distance_threshold; - const Vector_3 face_normal = get_face_normal(query); + const Vector_3 face_normal = m_face_normals.at(query); const FT cos_value = m_scalar_product_3(face_normal, m_normal_of_best_fit); const FT squared_cos_value = cos_value * cos_value; @@ -284,7 +311,7 @@ namespace Polygon_mesh { // The best fit plane will be a plane through this face centroid with // its normal being the face's normal. const Point_3 face_centroid = get_face_centroid(face); - const Vector_3 face_normal = get_face_normal(face); + const Vector_3 face_normal = m_face_normals.at(face); if (face_normal == CGAL::NULL_VECTOR) return false; CGAL_precondition(face_normal != CGAL::NULL_VECTOR); @@ -308,15 +335,15 @@ namespace Polygon_mesh { // The best fit plane will be a plane fitted to all vertices of all // region faces with its normal being perpendicular to the plane. // Given that the points, and no normals, are used in estimating - // the plane, the estimated normal will point into an arbitray + // the plane, the estimated normal will point into an arbitrary // one of the two possible directions. // We flip it into the correct direction (the one that the majority // of faces agree with) below. // This fix is proposed by nh2: // https://github.com/CGAL/cgal/pull/4563 const Plane_3 unoriented_plane_of_best_fit = - internal::create_plane_from_faces( - m_face_graph, region, m_vertex_to_point_map, m_traits).first; + internal::create_plane_from_triangulated_faces( + m_face_graph, region, m_face_triangulations, m_traits).first; const Vector_3 unoriented_normal_of_best_fit = unoriented_plane_of_best_fit.orthogonal_vector(); @@ -325,7 +352,7 @@ namespace Polygon_mesh { // Approach: each face gets one vote to keep or flip the current plane normal. long votes_to_keep_normal = 0; for (const auto &face : region) { - const Vector_3 face_normal = get_face_normal(face); + const Vector_3 face_normal = m_face_normals.at(face); const bool agrees = m_scalar_product_3(face_normal, unoriented_normal_of_best_fit) > FT(0); votes_to_keep_normal += (agrees ? 1 : -1); @@ -383,25 +410,6 @@ namespace Polygon_mesh { return Point_3(x, y, z); } - // Compute normal of the face. - template - Vector_3 get_face_normal(const Face& face) const { - - const auto hedge = halfedge(face, m_face_graph); - const auto vertices = vertices_around_face(hedge, m_face_graph); - CGAL_precondition(vertices.size() >= 3); - - auto vertex = vertices.begin(); - const Point_3& point1 = get(m_vertex_to_point_map, *vertex); ++vertex; - const Point_3& point2 = get(m_vertex_to_point_map, *vertex); ++vertex; - const Point_3& point3 = get(m_vertex_to_point_map, *vertex); - - const Vector_3 u = point2 - point1; - const Vector_3 v = point3 - point1; - const Vector_3 face_normal = m_cross_product_3(u, v); - return face_normal; - } - // The maximum squared distance from the vertices of the face // to the best fit plane. template diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h index b539bf56e5c2..17d927e544f0 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h +++ b/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h @@ -46,6 +46,7 @@ #include #include #include +#include namespace CGAL { namespace Shape_detection { @@ -61,7 +62,7 @@ namespace internal { mutable T it; }; - // TODO: this should be customisable in named function parameters + // TODO: this should be customizable in named function parameters template::value> struct hash_item {}; @@ -370,12 +371,13 @@ namespace internal { triangles.push_back(ITriangle_3(points[0], points[1], points[2])); else { - //use a triangulation using the centroid - std::size_t nb_edges = points.size(); - IPoint_3 c = CGAL::centroid(points.begin(), points.end()); - points.push_back(points.front()); - for (std::size_t i=0; i> output; + + Polygon_mesh_processing::triangulate_hole_polyline(points, std::back_inserter(output), parameters::use_2d_constrained_delaunay_triangulation(true)); + + assert(!output.empty()); + for (const auto& t : output) + triangles.push_back(ITriangle_3(points[t.first], points[t.second], points[t.third])); } } CGAL_precondition(triangles.size() >= region.size()); @@ -395,6 +397,58 @@ namespace internal { return std::make_pair(plane, static_cast(score)); } + template< + typename Traits, + typename FaceGraph, + typename Region, + typename FaceToTrianglesMap> + std::pair + create_plane_from_triangulated_faces( + const FaceGraph& face_graph, + const Region& region, + const FaceToTrianglesMap &face_to_triangles_map, const Traits&) { + + using FT = typename Traits::FT; + using Plane_3 = typename Traits::Plane_3; + using Triangle_3 = typename Traits::Triangle_3; + + using ITraits = CGAL::Exact_predicates_inexact_constructions_kernel; + using IConverter = CGAL::Cartesian_converter; + + using IFT = typename ITraits::FT; + using IPoint_3 = typename ITraits::Point_3; + using ITriangle_3 = typename ITraits::Triangle_3; + using IPlane_3 = typename ITraits::Plane_3; + + std::vector triangles; + CGAL_precondition(region.size() > 0); + triangles.reserve(region.size()); + const IConverter iconverter = IConverter(); + + for (const typename Region::value_type face : region) { + const std::vector& tris = face_to_triangles_map.at(face); + CGAL_precondition(tris.size() > 0); + + for (const auto tri : tris) + triangles.push_back(iconverter(tri)); + } + CGAL_precondition(triangles.size() >= region.size()); + IPlane_3 fitted_plane; + IPoint_3 fitted_centroid; + const IFT score = CGAL::linear_least_squares_fitting_3( + triangles.begin(), triangles.end(), + fitted_plane, fitted_centroid, + CGAL::Dimension_tag<2>(), ITraits(), + CGAL::Eigen_diagonalize_traits()); + + const Plane_3 plane( + static_cast(fitted_plane.a()), + static_cast(fitted_plane.b()), + static_cast(fitted_plane.c()), + static_cast(fitted_plane.d())); + return std::make_pair(plane, static_cast(score)); + } + template< typename Traits, typename Region, From 05ba6a264449bfaf4348c8db114611dc996ae78b Mon Sep 17 00:00:00 2001 From: Sven Oesau Date: Wed, 3 Jul 2024 10:12:07 +0200 Subject: [PATCH 2/9] fixed warnings handling of degenerate faces --- .../Polygon_mesh/Least_squares_plane_fit_region.h | 9 +++++++-- .../Shape_detection/Region_growing/internal/utils.h | 11 ++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polygon_mesh/Least_squares_plane_fit_region.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polygon_mesh/Least_squares_plane_fit_region.h index 4ad508662910..601444031149 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polygon_mesh/Least_squares_plane_fit_region.h +++ b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polygon_mesh/Least_squares_plane_fit_region.h @@ -178,9 +178,14 @@ namespace Polygon_mesh { Polygon_mesh_processing::triangulate_hole_polyline(pts, std::back_inserter(output), parameters::use_2d_constrained_delaunay_triangulation(true)); + // Create entry in map. In case of degenerate polygonal faces, the list stays empty. std::vector& tris = m_face_triangulations[i]; + + // If the output is empty, the polygon is degenerate. + if (output.empty()) + continue; + tris.reserve(output.size()); - assert(!output.empty()); for (const auto& t : output) tris.push_back(Triangle_3(pts[t.first], pts[t.second], pts[t.third])); } @@ -343,7 +348,7 @@ namespace Polygon_mesh { // https://github.com/CGAL/cgal/pull/4563 const Plane_3 unoriented_plane_of_best_fit = internal::create_plane_from_triangulated_faces( - m_face_graph, region, m_face_triangulations, m_traits).first; + region, m_face_triangulations, m_traits).first; const Vector_3 unoriented_normal_of_best_fit = unoriented_plane_of_best_fit.orthogonal_vector(); diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h index 17d927e544f0..328c49031b2a 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h +++ b/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h @@ -399,12 +399,10 @@ namespace internal { template< typename Traits, - typename FaceGraph, typename Region, typename FaceToTrianglesMap> std::pair create_plane_from_triangulated_faces( - const FaceGraph& face_graph, const Region& region, const FaceToTrianglesMap &face_to_triangles_map, const Traits&) { @@ -427,12 +425,15 @@ namespace internal { for (const typename Region::value_type face : region) { const std::vector& tris = face_to_triangles_map.at(face); - CGAL_precondition(tris.size() > 0); - for (const auto tri : tris) + // Degenerate polygons are omitted. + if (tris.empty()) + continue; + + for (const auto &tri : tris) triangles.push_back(iconverter(tri)); } - CGAL_precondition(triangles.size() >= region.size()); + CGAL_precondition(!triangles.empty()); IPlane_3 fitted_plane; IPoint_3 fitted_centroid; const IFT score = CGAL::linear_least_squares_fitting_3( From eeffa4b752baeb49d68244024cd80500695f897b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 26 Jul 2024 06:03:37 +0200 Subject: [PATCH 3/9] speed up copy_face_graph mostly when tm is not empty and almost make it less dependent on tm size --- BGL/include/CGAL/boost/graph/copy_face_graph.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/copy_face_graph.h b/BGL/include/CGAL/boost/graph/copy_face_graph.h index 2a4850647ce6..9d9e9359c4cb 100644 --- a/BGL/include/CGAL/boost/graph/copy_face_graph.h +++ b/BGL/include/CGAL/boost/graph/copy_face_graph.h @@ -64,13 +64,15 @@ void copy_face_graph_impl(const SourceMesh& sm, TargetMesh& tm, const tm_face_descriptor tm_null_face = boost::graph_traits::null_face(); const tm_vertex_descriptor tm_null_vertex = boost::graph_traits::null_vertex(); - reserve(tm, static_cast::vertices_size_type>(vertices(tm).size()+vertices(sm).size()), - static_cast::edges_size_type>(edges(tm).size()+edges(sm).size()), - static_cast::faces_size_type>(faces(tm).size()+faces(sm).size()) ); + reserve(tm, static_cast::vertices_size_type>(internal::exact_num_vertices(tm)+internal::exact_num_vertices(sm)), + static_cast::edges_size_type>(internal::exact_num_edges(tm)+internal::exact_num_edges(sm)), + static_cast::faces_size_type>(internal::exact_num_faces(tm)+internal::exact_num_faces(sm)) ); //insert halfedges and create each vertex when encountering its halfedge std::vector new_edges; - new_edges.reserve(edges(sm).size()); + std::vector new_vertices; + new_edges.reserve(internal::exact_num_edges(sm)); + new_vertices.reserve(internal::exact_num_vertices(sm)); for(sm_edge_descriptor sm_e : edges(sm)) { tm_edge_descriptor tm_e = add_edge(tm); @@ -108,6 +110,7 @@ void copy_face_graph_impl(const SourceMesh& sm, TargetMesh& tm, tm_vertex_descriptor tm_h_tgt = add_vertex(tm); *v2v++=std::make_pair(sm_h_tgt, tm_h_tgt); set_halfedge(tm_h_tgt, tm_h, tm); + new_vertices.push_back(tm_h); set_target(tm_h, tm_h_tgt, tm); put(tm_vpm, tm_h_tgt, conv(get(sm_vpm, sm_h_tgt))); } @@ -118,6 +121,7 @@ void copy_face_graph_impl(const SourceMesh& sm, TargetMesh& tm, tm_vertex_descriptor tm_h_src = add_vertex(tm); *v2v++=std::make_pair(sm_h_src, tm_h_src); set_halfedge(tm_h_src, tm_h_opp, tm); + new_vertices.push_back(tm_h_opp); set_target(tm_h_opp, tm_h_src, tm); put(tm_vpm, tm_h_src, conv(get(sm_vpm, sm_h_src))); } @@ -165,11 +169,9 @@ void copy_face_graph_impl(const SourceMesh& sm, TargetMesh& tm, } } // update halfedge vertex of all but the vertex halfedge - for(tm_vertex_descriptor v : vertices(tm)) + for(tm_halfedge_descriptor h : new_vertices) { - tm_halfedge_descriptor h = halfedge(v, tm); - if (h==boost::graph_traits::null_halfedge()) - continue; + tm_vertex_descriptor v = target(h, tm); tm_halfedge_descriptor next_around_vertex=h; do{ next_around_vertex=opposite(next(next_around_vertex, tm), tm); From 2c31defc6528bef74194e135fe3736b9f55d282b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 13 Aug 2024 16:14:23 +0200 Subject: [PATCH 4/9] backport f7a48360395d819bbd15b48071bd89fc0bdd9648 to the deprecated test --- Mesh_3/test/Mesh_3/test_meshing_3D_gray_image_deprecated.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Mesh_3/test/Mesh_3/test_meshing_3D_gray_image_deprecated.cpp b/Mesh_3/test/Mesh_3/test_meshing_3D_gray_image_deprecated.cpp index b2ba365111f8..b20e573cf670 100644 --- a/Mesh_3/test/Mesh_3/test_meshing_3D_gray_image_deprecated.cpp +++ b/Mesh_3/test/Mesh_3/test_meshing_3D_gray_image_deprecated.cpp @@ -68,7 +68,6 @@ struct Image_tester : public Tester Mesh_criteria criteria(facet_angle = 30, facet_size = 6, facet_distance = 2, - facet_topology = CGAL::MANIFOLD, cell_radius_edge_ratio = 3, cell_size = 8); From 5b731118f9c2f7ad6d5e756ef5a47ca8559c2adf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 13 Aug 2024 16:22:36 +0200 Subject: [PATCH 5/9] add validation for the range case --- .../CGAL/Boolean_set_operations_2/Gps_on_surface_base_2.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_on_surface_base_2.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_on_surface_base_2.h index 81c6f421171d..d1b75253aefb 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_on_surface_base_2.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_on_surface_base_2.h @@ -642,6 +642,7 @@ class Gps_on_surface_base_2 unsigned int i = 1; for (InputIterator itr = begin; itr != end; ++itr, ++i) { + ValidationPolicy::is_valid((*itr), *m_traits); arr_vec[i].first = new Aos_2(m_traits); _insert(*itr, *(arr_vec[i].first)); } @@ -666,6 +667,7 @@ class Gps_on_surface_base_2 unsigned int i = 1; for (InputIterator itr = begin; itr!=end; ++itr, ++i) { + ValidationPolicy::is_valid((*itr), *m_traits); arr_vec[i].first = new Aos_2(m_traits); _insert(*itr, *(arr_vec[i].first)); } From 8c70d6120f71282183037973d0607f98af652006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 14 Aug 2024 14:37:24 +0200 Subject: [PATCH 6/9] hide PMP usage behind a macro --- .../Least_squares_plane_fit_region.h | 47 +++++++++++++------ .../Region_growing/internal/utils.h | 36 ++++++++++---- 2 files changed, 59 insertions(+), 24 deletions(-) diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polygon_mesh/Least_squares_plane_fit_region.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polygon_mesh/Least_squares_plane_fit_region.h index 601444031149..0ab7463a08ec 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polygon_mesh/Least_squares_plane_fit_region.h +++ b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polygon_mesh/Least_squares_plane_fit_region.h @@ -19,7 +19,9 @@ // Internal includes. #include #include +#ifdef CGAL_SD_RG_USE_PMP #include +#endif namespace CGAL { namespace Shape_detection { @@ -163,8 +165,36 @@ namespace Polygon_mesh { m_scalar_product_3(m_traits.compute_scalar_product_3_object()), m_cross_product_3(m_traits.construct_cross_product_vector_3_object()) { +#ifdef CGAL_SD_RG_USE_PMP + auto get_face_normal = [this](Item face, const PolygonMesh& pmesh) + { + return Polygon_mesh_processing::compute_face_normal(face, pmesh, parameters::vertex_point_map(m_vertex_to_point_map)); + }; +#else + auto get_face_normal = [this](Item face, const PolygonMesh& pmesh) -> Vector_3 + { + const auto hedge = halfedge(face, pmesh); + const auto vertices = vertices_around_face(hedge, pmesh); + CGAL_precondition(vertices.size() >= 3); + + auto vertex = vertices.begin(); + const Point_3& p1 = get(m_vertex_to_point_map, *vertex); ++vertex; + const Point_3& p2 = get(m_vertex_to_point_map, *vertex); ++vertex; + Point_3 p3 = get(m_vertex_to_point_map, *vertex); + while(collinear(p1, p2, p3)) + { + if (++vertex == vertices.end()) return NULL_VECTOR; + p3 = get(m_vertex_to_point_map, *vertex); + } + + const Vector_3 u = p2 - p1; + const Vector_3 v = p3 - p1; + return m_cross_product_3(u, v); + }; +#endif + for (const Item &i : faces(pmesh)) { - m_face_normals[i] = Polygon_mesh_processing::compute_face_normal(i, pmesh); + m_face_normals[i] = get_face_normal(i, pmesh); std::vector pts; auto h = halfedge(i, pmesh); auto s = h; @@ -174,20 +204,7 @@ namespace Polygon_mesh { h = next(h, pmesh); } while (h != s); - std::vector> output; - - Polygon_mesh_processing::triangulate_hole_polyline(pts, std::back_inserter(output), parameters::use_2d_constrained_delaunay_triangulation(true)); - - // Create entry in map. In case of degenerate polygonal faces, the list stays empty. - std::vector& tris = m_face_triangulations[i]; - - // If the output is empty, the polygon is degenerate. - if (output.empty()) - continue; - - tris.reserve(output.size()); - for (const auto& t : output) - tris.push_back(Triangle_3(pts[t.first], pts[t.second], pts[t.third])); + internal::triangulate_face(pts, m_face_triangulations[i]); } CGAL_precondition(faces(m_face_graph).size() > 0); diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h index 328c49031b2a..8a0d8690893e 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h +++ b/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h @@ -46,7 +46,9 @@ #include #include #include +#ifdef CGAL_SD_RG_USE_PMP #include +#endif namespace CGAL { namespace Shape_detection { @@ -330,6 +332,30 @@ namespace internal { return create_plane(tmp, item_map, traits); } + template + void + triangulate_face(const std::vector& points, + std::vector& triangles) + { +#ifdef CGAL_SD_RG_USE_PMP + std::vector> output; + + Polygon_mesh_processing::triangulate_hole_polyline(points, std::back_inserter(output), parameters::use_2d_constrained_delaunay_triangulation(true)); + + triangles.reserve(output.size()); + for (const auto& t : output) + triangles.emplace_back(points[t.first], points[t.second], points[t.third]); +#else + //use a triangulation using the centroid + std::size_t nb_edges = points.size(); + Point_3 c = CGAL::centroid(points.begin(), points.end()); + triangles.reserve(nb_edges); + for (std::size_t i=0; i> output; - - Polygon_mesh_processing::triangulate_hole_polyline(points, std::back_inserter(output), parameters::use_2d_constrained_delaunay_triangulation(true)); - - assert(!output.empty()); - for (const auto& t : output) - triangles.push_back(ITriangle_3(points[t.first], points[t.second], points[t.third])); - } + triangulate_face(points, triangles); } CGAL_precondition(triangles.size() >= region.size()); IPlane_3 fitted_plane; From 7d0969d15f3b1547b6bb0dd96ccef23acfa5c76c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 14 Aug 2024 15:47:16 +0200 Subject: [PATCH 7/9] use dynamic property maps --- .../Least_squares_plane_fit_region.h | 23 +++++++++++-------- .../Region_growing/internal/utils.h | 2 +- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polygon_mesh/Least_squares_plane_fit_region.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polygon_mesh/Least_squares_plane_fit_region.h index 0ab7463a08ec..2c8801ea5e6a 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polygon_mesh/Least_squares_plane_fit_region.h +++ b/Shape_detection/include/CGAL/Shape_detection/Region_growing/Polygon_mesh/Least_squares_plane_fit_region.h @@ -93,9 +93,6 @@ namespace Polygon_mesh { using Scalar_product_3 = typename GeomTraits::Compute_scalar_product_3; using Cross_product_3 = typename GeomTraits::Construct_cross_product_vector_3; - std::unordered_map > m_face_normals; - std::unordered_map, internal::hash_item > m_face_triangulations; - public: /// \name Initialization /// @{ @@ -163,7 +160,10 @@ namespace Polygon_mesh { m_squared_length_3(m_traits.compute_squared_length_3_object()), m_squared_distance_3(m_traits.compute_squared_distance_3_object()), m_scalar_product_3(m_traits.compute_scalar_product_3_object()), - m_cross_product_3(m_traits.construct_cross_product_vector_3_object()) { + m_cross_product_3(m_traits.construct_cross_product_vector_3_object()), + m_face_normals( get(CGAL::dynamic_face_property_t(), pmesh) ), + m_face_triangulations( get(CGAL::dynamic_face_property_t>(), pmesh) ) + { #ifdef CGAL_SD_RG_USE_PMP auto get_face_normal = [this](Item face, const PolygonMesh& pmesh) @@ -194,7 +194,7 @@ namespace Polygon_mesh { #endif for (const Item &i : faces(pmesh)) { - m_face_normals[i] = get_face_normal(i, pmesh); + put(m_face_normals, i, get_face_normal(i, pmesh)); std::vector pts; auto h = halfedge(i, pmesh); auto s = h; @@ -204,7 +204,9 @@ namespace Polygon_mesh { h = next(h, pmesh); } while (h != s); - internal::triangulate_face(pts, m_face_triangulations[i]); + std::vector face_triangulation; + internal::triangulate_face(pts, face_triangulation); + put(m_face_triangulations, i, face_triangulation); } CGAL_precondition(faces(m_face_graph).size() > 0); @@ -283,7 +285,7 @@ namespace Polygon_mesh { const FT squared_distance_threshold = m_distance_threshold * m_distance_threshold; - const Vector_3 face_normal = m_face_normals.at(query); + const Vector_3 face_normal = get(m_face_normals, query); const FT cos_value = m_scalar_product_3(face_normal, m_normal_of_best_fit); const FT squared_cos_value = cos_value * cos_value; @@ -333,7 +335,7 @@ namespace Polygon_mesh { // The best fit plane will be a plane through this face centroid with // its normal being the face's normal. const Point_3 face_centroid = get_face_centroid(face); - const Vector_3 face_normal = m_face_normals.at(face); + const Vector_3 face_normal = get(m_face_normals, face); if (face_normal == CGAL::NULL_VECTOR) return false; CGAL_precondition(face_normal != CGAL::NULL_VECTOR); @@ -374,7 +376,7 @@ namespace Polygon_mesh { // Approach: each face gets one vote to keep or flip the current plane normal. long votes_to_keep_normal = 0; for (const auto &face : region) { - const Vector_3 face_normal = m_face_normals.at(face); + const Vector_3 face_normal = get(m_face_normals, face); const bool agrees = m_scalar_product_3(face_normal, unoriented_normal_of_best_fit) > FT(0); votes_to_keep_normal += (agrees ? 1 : -1); @@ -406,6 +408,9 @@ namespace Polygon_mesh { const Scalar_product_3 m_scalar_product_3; const Cross_product_3 m_cross_product_3; + typename boost::property_map >::const_type m_face_normals; + typename boost::property_map> >::const_type m_face_triangulations; + Plane_3 m_plane_of_best_fit; Vector_3 m_normal_of_best_fit; diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h index 8a0d8690893e..09f87c109a8f 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h +++ b/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h @@ -442,7 +442,7 @@ namespace internal { const IConverter iconverter = IConverter(); for (const typename Region::value_type face : region) { - const std::vector& tris = face_to_triangles_map.at(face); + const std::vector& tris = get(face_to_triangles_map, face); // Degenerate polygons are omitted. if (tris.empty()) From e931d1258b5647d84ca32401102c0cacce0f859a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 14 Aug 2024 16:52:42 +0200 Subject: [PATCH 8/9] add missing include --- .../CGAL/Shape_detection/Region_growing/internal/utils.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h index 09f87c109a8f..3cd71111d2c7 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h +++ b/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h @@ -48,6 +48,8 @@ #include #ifdef CGAL_SD_RG_USE_PMP #include +#else +#include #endif namespace CGAL { From 6e5f37474fcd35c05c38c13f20673d97b2b2b4e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 14 Aug 2024 17:20:06 +0200 Subject: [PATCH 9/9] bad type --- .../CGAL/Shape_detection/Region_growing/internal/utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h b/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h index 3cd71111d2c7..de1827fa3769 100644 --- a/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h +++ b/Shape_detection/include/CGAL/Shape_detection/Region_growing/internal/utils.h @@ -350,7 +350,7 @@ namespace internal { #else //use a triangulation using the centroid std::size_t nb_edges = points.size(); - Point_3 c = CGAL::centroid(points.begin(), points.end()); + typename Traits::Point_3 c = CGAL::centroid(points.begin(), points.end()); triangles.reserve(nb_edges); for (std::size_t i=0; i