From 8460df09c370ce6ccd0533bf73c6da59f6f59ecb Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 29 Jun 2017 13:17:23 +0200 Subject: [PATCH 1/5] Add a function to make a removal of faces manifold. --- BGL/include/CGAL/boost/graph/helpers.h | 93 +++++++++++++++++++++ BGL/test/BGL/CMakeLists.txt | 2 + BGL/test/BGL/test_Manifold_face_removal.cpp | 56 +++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 BGL/test/BGL/test_Manifold_face_removal.cpp diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index d1c6d3e78f0..f655a51c6cd 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -27,6 +27,7 @@ #include #include #include +#include namespace CGAL { @@ -1174,7 +1175,99 @@ bool is_empty(const FaceGraph& g) return boost::empty(vertices(g)); } +/** + * \ingroup PkgBGLHelperFct + * + * Expands a selection of faces so that when they are removed, + * `tm` stays manifold. + * + * @tparam TriangleMesh a model of `MutableFaceGraph` that is triangulated. + * @tparam FaceRange a range of `boost::graph_traits::%face_descriptor` + * @tparam IsSelectedPropertyMap a a model of `ReadWritePropertyMap` with + * `boost::graph_traits::%face_descriptor` as key and `bool` as value. + * + * @param tm the mesh of interest. + * @param faces_to_be_deleted a range of faces that will be deleted + * @param is_selected a property map containing the selected-or-not status of each face of pmesh. + * It will be modified if the face selection must be expanded. + * + **/ +template +void expand_face_selection_for_removal(TriangleMesh& tm, + const FaceRange& faces_to_be_deleted, + IsSelectedPropertyMap is_selected) +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + boost::unordered_set vertices_to_be_deleted; + + // collect vertices belonging to at least a triangle that will be removed + BOOST_FOREACH(face_descriptor fd, faces_to_be_deleted) + { + halfedge_descriptor h = halfedge(fd, tm); + vertices_to_be_deleted.insert( target(h, tm) ); + vertices_to_be_deleted.insert( target(next(h, tm), tm) ); + vertices_to_be_deleted.insert( target(prev(h, tm), tm) ); + } + + while (!vertices_to_be_deleted.empty()) + { + vertex_descriptor vd = *vertices_to_be_deleted.begin(); + vertices_to_be_deleted.erase( vertices_to_be_deleted.begin() ); + + // set hd to the last selected face of a connected component + // of selected faces around a vertex + halfedge_descriptor hd = halfedge(vd, tm); + while( !get(is_selected, face(hd, tm)) ) + { + hd = opposite( next(hd, tm), tm); + CGAL_assertion( hd != halfedge(vd, tm) ); + } + halfedge_descriptor start = hd; + halfedge_descriptor next_around_vertex = opposite( next(hd, tm), tm); + while( get(is_selected, face(next_around_vertex, tm) ) ) + { + hd = next_around_vertex; + next_around_vertex = opposite( next(hd, tm), tm); + if (hd==start) break; + } + if ( get(is_selected, face(next_around_vertex, tm) ) ) continue; //all incident faces will be removed + + while( true ) + { + // collect non-selected faces + std::vector faces_traversed; + do + { + faces_traversed.push_back(face(next_around_vertex, tm)); + next_around_vertex = opposite( next(next_around_vertex, tm), tm); + } + while( !get(is_selected, face(next_around_vertex, tm) ) ); + + // go over the connected components of faces to remove + do{ + if (next_around_vertex==start) + break; + next_around_vertex = opposite( next(next_around_vertex, tm), tm); + } + while( get(is_selected, face(next_around_vertex, tm) ) ); + + if (next_around_vertex==start) + break; + + BOOST_FOREACH(face_descriptor fd, faces_traversed) + { + put(is_selected, fd, true); + halfedge_descriptor f_hd = halfedge(fd, tm); + vertices_to_be_deleted.insert( target(f_hd, tm) ); + vertices_to_be_deleted.insert( target( next(f_hd, tm), tm) ); + vertices_to_be_deleted.insert( target( prev(f_hd, tm), tm) ); + } + } + } +} } // namespace CGAL // Include "Euler_operations.h" at the end, because its implementation diff --git a/BGL/test/BGL/CMakeLists.txt b/BGL/test/BGL/CMakeLists.txt index e15afcf3ac8..6f81059c200 100644 --- a/BGL/test/BGL/CMakeLists.txt +++ b/BGL/test/BGL/CMakeLists.txt @@ -95,6 +95,8 @@ create_single_source_cgal_program( "test_bgl_read_write.cpp" ) create_single_source_cgal_program( "graph_concept_Face_filtered_graph.cpp" ) +create_single_source_cgal_program( "test_Manifold_face_removal.cpp") + create_single_source_cgal_program( "test_Face_filtered_graph.cpp" ) create_single_source_cgal_program( "test_Euler_operations.cpp" ) diff --git a/BGL/test/BGL/test_Manifold_face_removal.cpp b/BGL/test/BGL/test_Manifold_face_removal.cpp new file mode 100644 index 00000000000..f883aaf7a34 --- /dev/null +++ b/BGL/test/BGL/test_Manifold_face_removal.cpp @@ -0,0 +1,56 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +typedef CGAL::Polyhedron_3 Polyhedron; + +int main() +{ + Polyhedron poly; + std::ifstream input("data/head.off"); + input >> poly; + +// define my selection of faces to remove + boost::unordered_map is_selected_map; + + const int selection_indices[] = {501, 652, 646, 322, 328, 212, 347, 345, 352, 353, 696, 697, 698, 706, 714, 2892}; + std::set index_set(&selection_indices[0], &selection_indices[0]+16); + + std::vector faces_to_remove; + int index = 0; + BOOST_FOREACH(Polyhedron::Face_handle fh, faces(poly)) + { + if(index_set.count(index)==0) + is_selected_map[fh]=false; + else + { + faces_to_remove.push_back(fh); + is_selected_map[fh]=true; + } + ++index; + } + + expand_face_selection_for_removal(poly, + faces_to_remove, + boost::make_assoc_property_map(is_selected_map)); + + index = 0; + BOOST_FOREACH(Polyhedron::Face_handle fh, faces(poly)) + { + if (is_selected_map[fh]) + std::cout << " " << index; + CGAL::Euler::remove_face(fh->halfedge(), poly); + ++index; + } + std::cout << "\n"; + return 0; +} From f1a3ea95a386b246fd715af82cf5527d07f3bd90 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 29 Jun 2017 14:24:10 +0200 Subject: [PATCH 2/5] Add face selection expansion to the selection_plugin --- BGL/include/CGAL/boost/graph/helpers.h | 15 ++++--- BGL/test/BGL/test_Manifold_face_removal.cpp | 4 -- .../Plugins/PMP/Selection_plugin.cpp | 45 +++++++++++++++++-- .../Plugins/PMP/Selection_widget.ui | 14 +++++- 4 files changed, 62 insertions(+), 16 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index f655a51c6cd..ad6b25dde94 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -1178,24 +1178,25 @@ bool is_empty(const FaceGraph& g) /** * \ingroup PkgBGLHelperFct * - * Expands a selection of faces so that when they are removed, - * `tm` stays manifold. + * Expands a selection of faces so that their removal does not create non manifold vertex. * * @tparam TriangleMesh a model of `MutableFaceGraph` that is triangulated. - * @tparam FaceRange a range of `boost::graph_traits::%face_descriptor` - * @tparam IsSelectedPropertyMap a a model of `ReadWritePropertyMap` with + * @tparam FaceRange a range of `boost::graph_traits::%face_descriptor`, + * with an iterator type model of `ForwardIterator`. + * + * @tparam IsSelectedMap a a model of `ReadWritePropertyMap` with * `boost::graph_traits::%face_descriptor` as key and `bool` as value. * * @param tm the mesh of interest. * @param faces_to_be_deleted a range of faces that will be deleted - * @param is_selected a property map containing the selected-or-not status of each face of pmesh. + * @param is_selected a property map containing the selected-or-not status of each face of `tm`. * It will be modified if the face selection must be expanded. * **/ -template +template void expand_face_selection_for_removal(TriangleMesh& tm, const FaceRange& faces_to_be_deleted, - IsSelectedPropertyMap is_selected) + IsSelectedMap is_selected) { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; diff --git a/BGL/test/BGL/test_Manifold_face_removal.cpp b/BGL/test/BGL/test_Manifold_face_removal.cpp index f883aaf7a34..e6de27989ca 100644 --- a/BGL/test/BGL/test_Manifold_face_removal.cpp +++ b/BGL/test/BGL/test_Manifold_face_removal.cpp @@ -43,14 +43,10 @@ int main() faces_to_remove, boost::make_assoc_property_map(is_selected_map)); - index = 0; BOOST_FOREACH(Polyhedron::Face_handle fh, faces(poly)) { if (is_selected_map[fh]) - std::cout << " " << index; CGAL::Euler::remove_face(fh->halfedge(), poly); - ++index; } - std::cout << "\n"; return 0; } diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp index 1bc73047db5..bdcf5609e06 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #ifdef USE_SURFACE_MESH @@ -491,8 +492,44 @@ public Q_SLOTS: selection_item->keep_connected_components(); break; } - //Convert from Edge Selection to Facet Selection + //Expand face selection case 5: + { + Scene_polyhedron_selection_item* selection_item = getSelectedItem(); + if (!selection_item || + selection_item->selected_facets.empty()) + { + print_message("Error: Please select a selection item with a selection of faces."); + return; + } + boost::unordered_map is_selected_map; + int index = 0; + BOOST_FOREACH(fg_face_descriptor fh, faces(*selection_item->polyhedron())) + { + if(selection_item->selected_facets.find(fh) + == selection_item->selected_facets.end()) + is_selected_map[fh]=false; + else + { + is_selected_map[fh]=true; + } + ++index; + } + CGAL::expand_face_selection_for_removal(*selection_item->polyhedron(), + selection_item->selected_facets, + boost::make_assoc_property_map(is_selected_map)); + + BOOST_FOREACH(fg_face_descriptor fh, faces(*selection_item->polyhedron())) + { + if (is_selected_map[fh]) + selection_item->selected_facets.insert(fh); + } + selection_item->invalidateOpenGLBuffers(); + selection_item->itemChanged(); + break; + } + //Convert from Edge Selection to Facet Selection + case 6: { Scene_polyhedron_selection_item* selection_item = getSelectedItem(); if(!selection_item) { @@ -514,7 +551,7 @@ public Q_SLOTS: break; } //Convert from Edge Selection to Point Selection - case 6: + case 7: { Scene_polyhedron_selection_item* selection_item = getSelectedItem(); if(!selection_item) { @@ -537,7 +574,7 @@ public Q_SLOTS: break; } //Convert from Facet Selection to Bounding Edge Selection - case 7: + case 8: { Scene_polyhedron_selection_item* selection_item = getSelectedItem(); if(!selection_item) { @@ -560,7 +597,7 @@ public Q_SLOTS: break; } //Convert from Facet Selection to Points Selection - case 8: + case 9: { Scene_polyhedron_selection_item* selection_item = getSelectedItem(); if(!selection_item) { diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_widget.ui b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_widget.ui index 2cc148be005..c9dd4fec2b2 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_widget.ui +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_widget.ui @@ -6,7 +6,7 @@ 0 0 - 597 + 613 334 @@ -429,6 +429,13 @@ + + + + PushButton + + + @@ -475,6 +482,11 @@ Keep Connected Components of Selected Facets + + + Expand Face Selection to Stay Manifold After Removal + + Convert from Edge Selection to Facets Selection From 8288fe2ca295dae375841caced53d22792f816f2 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 29 Jun 2017 14:46:01 +0200 Subject: [PATCH 3/5] changes.html --- BGL/include/CGAL/boost/graph/selection.h | 95 +++++++++++++++++++ BGL/test/BGL/test_Manifold_face_removal.cpp | 12 ++- Installation/changes.html | 11 ++- .../Plugins/PMP/Selection_plugin.cpp | 1 - 4 files changed, 114 insertions(+), 5 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/selection.h b/BGL/include/CGAL/boost/graph/selection.h index ff32f390abf..19c093308c7 100644 --- a/BGL/include/CGAL/boost/graph/selection.h +++ b/BGL/include/CGAL/boost/graph/selection.h @@ -23,6 +23,7 @@ #include #include #include +#include namespace CGAL { @@ -521,6 +522,100 @@ reduce_vertex_selection( return out; } +/** + * \ingroup PkgBGLSelectionFct + * + * Expands a selection of faces so that their removal does not create non manifold vertex. + * + * @tparam TriangleMesh a model of `FaceGraph` that is triangulated. + * @tparam FaceRange a range of `boost::graph_traits::%face_descriptor`, + * with an iterator type model of `ForwardIterator`. + * @tparam IsSelectedMap a model of `ReadWritePropertyMap` with + * `boost::graph_traits::%face_descriptor` as key and `bool` as value. + + * @param tm the triangle mesh. + * @param faces_to_be_deleted the range of selected faces. + * @param is_selected a property map containing the selected-or-not status of each face of `tm`. + * It must associate `true` to each face of `faces_to_be_deleted` and `false` to any other face of `tm`. + * It will be modified if the face selection must be expanded. + * + **/ +template +void expand_face_selection_for_removal(TriangleMesh& tm, + const FaceRange& faces_to_be_deleted, + IsSelectedMap is_selected) +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + boost::unordered_set vertices_to_be_deleted; + + // collect vertices belonging to at least a triangle that will be removed + BOOST_FOREACH(face_descriptor fd, faces_to_be_deleted) + { + halfedge_descriptor h = halfedge(fd, tm); + vertices_to_be_deleted.insert( target(h, tm) ); + vertices_to_be_deleted.insert( target(next(h, tm), tm) ); + vertices_to_be_deleted.insert( target(prev(h, tm), tm) ); + } + + while (!vertices_to_be_deleted.empty()) + { + vertex_descriptor vd = *vertices_to_be_deleted.begin(); + vertices_to_be_deleted.erase( vertices_to_be_deleted.begin() ); + + // set hd to the last selected face of a connected component + // of selected faces around a vertex + halfedge_descriptor hd = halfedge(vd, tm); + while( !get(is_selected, face(hd, tm)) ) + { + hd = opposite( next(hd, tm), tm); + CGAL_assertion( hd != halfedge(vd, tm) ); + } + halfedge_descriptor start = hd; + halfedge_descriptor next_around_vertex = opposite( next(hd, tm), tm); + while( get(is_selected, face(next_around_vertex, tm) ) ) + { + hd = next_around_vertex; + next_around_vertex = opposite( next(hd, tm), tm); + if (hd==start) break; + } + if ( get(is_selected, face(next_around_vertex, tm) ) ) continue; //all incident faces will be removed + + while( true ) + { + // collect non-selected faces + std::vector faces_traversed; + do + { + faces_traversed.push_back(face(next_around_vertex, tm)); + next_around_vertex = opposite( next(next_around_vertex, tm), tm); + } + while( !get(is_selected, face(next_around_vertex, tm) ) ); + + // go over the connected components of faces to remove + do{ + if (next_around_vertex==start) + break; + next_around_vertex = opposite( next(next_around_vertex, tm), tm); + } + while( get(is_selected, face(next_around_vertex, tm) ) ); + + if (next_around_vertex==start) + break; + + BOOST_FOREACH(face_descriptor fd, faces_traversed) + { + put(is_selected, fd, true); + halfedge_descriptor f_hd = halfedge(fd, tm); + vertices_to_be_deleted.insert( target(f_hd, tm) ); + vertices_to_be_deleted.insert( target( next(f_hd, tm), tm) ); + vertices_to_be_deleted.insert( target( prev(f_hd, tm), tm) ); + } + } + } +} } //end of namespace CGAL #endif //CGAL_BOOST_GRAPH_KTH_SIMPLICIAL_NEIGHBORHOOD_H diff --git a/BGL/test/BGL/test_Manifold_face_removal.cpp b/BGL/test/BGL/test_Manifold_face_removal.cpp index e6de27989ca..54007002c24 100644 --- a/BGL/test/BGL/test_Manifold_face_removal.cpp +++ b/BGL/test/BGL/test_Manifold_face_removal.cpp @@ -8,8 +8,8 @@ #include #include +#include #include - typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef CGAL::Polyhedron_3 Polyhedron; @@ -43,10 +43,18 @@ int main() faces_to_remove, boost::make_assoc_property_map(is_selected_map)); + index=0; BOOST_FOREACH(Polyhedron::Face_handle fh, faces(poly)) { if (is_selected_map[fh]) - CGAL::Euler::remove_face(fh->halfedge(), poly); + { + CGAL::Euler::remove_face(fh->halfedge(), poly); + ++index; + } } + + CGAL_assertion(index == 25); + CGAL_assertion(is_valid(poly)); return 0; } + diff --git a/Installation/changes.html b/Installation/changes.html index 10166ce3997..2300cfb2aca 100644 --- a/Installation/changes.html +++ b/Installation/changes.html @@ -155,8 +155,15 @@ and src/ directories). - - + +

CGAL and the Boost Graph Library (BGL)

+
    +
  • + Add helper function CGAL::expand_face_selection_for_removal that + expands a face selection to avoid creating a non manifold mesh when removing the selected faces. +
  • +
+ diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp index bdcf5609e06..d8782d4f8d9 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #ifdef USE_SURFACE_MESH From 9381041e18c151bb173dd6bd7774588c0d608d84 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 30 Jun 2017 10:40:13 +0200 Subject: [PATCH 4/5] Doc fixes and enhancement --- BGL/include/CGAL/boost/graph/helpers.h | 94 --------------------- BGL/include/CGAL/boost/graph/selection.h | 34 ++++---- BGL/test/BGL/test_Manifold_face_removal.cpp | 29 ++++--- 3 files changed, 33 insertions(+), 124 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index ad6b25dde94..b1e9068afea 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -1175,100 +1175,6 @@ bool is_empty(const FaceGraph& g) return boost::empty(vertices(g)); } -/** - * \ingroup PkgBGLHelperFct - * - * Expands a selection of faces so that their removal does not create non manifold vertex. - * - * @tparam TriangleMesh a model of `MutableFaceGraph` that is triangulated. - * @tparam FaceRange a range of `boost::graph_traits::%face_descriptor`, - * with an iterator type model of `ForwardIterator`. - * - * @tparam IsSelectedMap a a model of `ReadWritePropertyMap` with - * `boost::graph_traits::%face_descriptor` as key and `bool` as value. - * - * @param tm the mesh of interest. - * @param faces_to_be_deleted a range of faces that will be deleted - * @param is_selected a property map containing the selected-or-not status of each face of `tm`. - * It will be modified if the face selection must be expanded. - * - **/ -template -void expand_face_selection_for_removal(TriangleMesh& tm, - const FaceRange& faces_to_be_deleted, - IsSelectedMap is_selected) -{ - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::face_descriptor face_descriptor; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - - boost::unordered_set vertices_to_be_deleted; - - // collect vertices belonging to at least a triangle that will be removed - BOOST_FOREACH(face_descriptor fd, faces_to_be_deleted) - { - halfedge_descriptor h = halfedge(fd, tm); - vertices_to_be_deleted.insert( target(h, tm) ); - vertices_to_be_deleted.insert( target(next(h, tm), tm) ); - vertices_to_be_deleted.insert( target(prev(h, tm), tm) ); - } - - while (!vertices_to_be_deleted.empty()) - { - vertex_descriptor vd = *vertices_to_be_deleted.begin(); - vertices_to_be_deleted.erase( vertices_to_be_deleted.begin() ); - - // set hd to the last selected face of a connected component - // of selected faces around a vertex - halfedge_descriptor hd = halfedge(vd, tm); - while( !get(is_selected, face(hd, tm)) ) - { - hd = opposite( next(hd, tm), tm); - CGAL_assertion( hd != halfedge(vd, tm) ); - } - halfedge_descriptor start = hd; - halfedge_descriptor next_around_vertex = opposite( next(hd, tm), tm); - while( get(is_selected, face(next_around_vertex, tm) ) ) - { - hd = next_around_vertex; - next_around_vertex = opposite( next(hd, tm), tm); - if (hd==start) break; - } - if ( get(is_selected, face(next_around_vertex, tm) ) ) continue; //all incident faces will be removed - - while( true ) - { - // collect non-selected faces - std::vector faces_traversed; - do - { - faces_traversed.push_back(face(next_around_vertex, tm)); - next_around_vertex = opposite( next(next_around_vertex, tm), tm); - } - while( !get(is_selected, face(next_around_vertex, tm) ) ); - - // go over the connected components of faces to remove - do{ - if (next_around_vertex==start) - break; - next_around_vertex = opposite( next(next_around_vertex, tm), tm); - } - while( get(is_selected, face(next_around_vertex, tm) ) ); - - if (next_around_vertex==start) - break; - - BOOST_FOREACH(face_descriptor fd, faces_traversed) - { - put(is_selected, fd, true); - halfedge_descriptor f_hd = halfedge(fd, tm); - vertices_to_be_deleted.insert( target(f_hd, tm) ); - vertices_to_be_deleted.insert( target( next(f_hd, tm), tm) ); - vertices_to_be_deleted.insert( target( prev(f_hd, tm), tm) ); - } - } - } -} } // namespace CGAL // Include "Euler_operations.h" at the end, because its implementation diff --git a/BGL/include/CGAL/boost/graph/selection.h b/BGL/include/CGAL/boost/graph/selection.h index 19c093308c7..89945046ac4 100644 --- a/BGL/include/CGAL/boost/graph/selection.h +++ b/BGL/include/CGAL/boost/graph/selection.h @@ -525,7 +525,10 @@ reduce_vertex_selection( /** * \ingroup PkgBGLSelectionFct * - * Expands a selection of faces so that their removal does not create non manifold vertex. + * Expands a selection of faces so that their removal does not create any non manifold vertex. + * For each vertex that is incident to a selected face, we turn around that vertex and check + * if there is exactly one set of consecutive selected faces. If not, additional faces around + * that vertex are selected to match this condition. * * @tparam TriangleMesh a model of `FaceGraph` that is triangulated. * @tparam FaceRange a range of `boost::graph_traits::%face_descriptor`, @@ -549,21 +552,21 @@ void expand_face_selection_for_removal(TriangleMesh& tm, typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - boost::unordered_set vertices_to_be_deleted; + boost::unordered_set vertices_queue; // collect vertices belonging to at least a triangle that will be removed BOOST_FOREACH(face_descriptor fd, faces_to_be_deleted) { halfedge_descriptor h = halfedge(fd, tm); - vertices_to_be_deleted.insert( target(h, tm) ); - vertices_to_be_deleted.insert( target(next(h, tm), tm) ); - vertices_to_be_deleted.insert( target(prev(h, tm), tm) ); + vertices_queue.insert( target(h, tm) ); + vertices_queue.insert( target(next(h, tm), tm) ); + vertices_queue.insert( target(prev(h, tm), tm) ); } - while (!vertices_to_be_deleted.empty()) + while (!vertices_queue.empty()) { - vertex_descriptor vd = *vertices_to_be_deleted.begin(); - vertices_to_be_deleted.erase( vertices_to_be_deleted.begin() ); + vertex_descriptor vd = *vertices_queue.begin(); + vertices_queue.erase( vertices_queue.begin() ); // set hd to the last selected face of a connected component // of selected faces around a vertex @@ -586,10 +589,10 @@ void expand_face_selection_for_removal(TriangleMesh& tm, while( true ) { // collect non-selected faces - std::vector faces_traversed; + std::vector faces_traversed; do { - faces_traversed.push_back(face(next_around_vertex, tm)); + faces_traversed.push_back(next_around_vertex); next_around_vertex = opposite( next(next_around_vertex, tm), tm); } while( !get(is_selected, face(next_around_vertex, tm) ) ); @@ -605,13 +608,12 @@ void expand_face_selection_for_removal(TriangleMesh& tm, if (next_around_vertex==start) break; - BOOST_FOREACH(face_descriptor fd, faces_traversed) + BOOST_FOREACH(halfedge_descriptor f_hd, faces_traversed) { - put(is_selected, fd, true); - halfedge_descriptor f_hd = halfedge(fd, tm); - vertices_to_be_deleted.insert( target(f_hd, tm) ); - vertices_to_be_deleted.insert( target( next(f_hd, tm), tm) ); - vertices_to_be_deleted.insert( target( prev(f_hd, tm), tm) ); + assert(target(f_hd, tm) == vd); + put(is_selected, face(f_hd, tm), true); + vertices_queue.insert( target( next(f_hd, tm), tm) ); + vertices_queue.insert( source(f_hd, tm) ); } } } diff --git a/BGL/test/BGL/test_Manifold_face_removal.cpp b/BGL/test/BGL/test_Manifold_face_removal.cpp index 54007002c24..965ab4143aa 100644 --- a/BGL/test/BGL/test_Manifold_face_removal.cpp +++ b/BGL/test/BGL/test_Manifold_face_removal.cpp @@ -1,7 +1,7 @@ #include -#include -#include -#include +#include +#include +#include #include #include @@ -11,23 +11,24 @@ #include #include typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; -typedef CGAL::Polyhedron_3 Polyhedron; +typedef CGAL::Surface_mesh SM; +typedef boost::graph_traits::face_descriptor face_descriptor; int main() { - Polyhedron poly; + SM sm; std::ifstream input("data/head.off"); - input >> poly; + input >> sm; // define my selection of faces to remove - boost::unordered_map is_selected_map; + boost::unordered_map is_selected_map; const int selection_indices[] = {501, 652, 646, 322, 328, 212, 347, 345, 352, 353, 696, 697, 698, 706, 714, 2892}; std::set index_set(&selection_indices[0], &selection_indices[0]+16); - std::vector faces_to_remove; + std::vector faces_to_remove; int index = 0; - BOOST_FOREACH(Polyhedron::Face_handle fh, faces(poly)) + BOOST_FOREACH(face_descriptor fh, faces(sm)) { if(index_set.count(index)==0) is_selected_map[fh]=false; @@ -39,22 +40,22 @@ int main() ++index; } - expand_face_selection_for_removal(poly, + expand_face_selection_for_removal(sm, faces_to_remove, boost::make_assoc_property_map(is_selected_map)); index=0; - BOOST_FOREACH(Polyhedron::Face_handle fh, faces(poly)) + BOOST_FOREACH(face_descriptor fh, faces(sm)) { if (is_selected_map[fh]) { - CGAL::Euler::remove_face(fh->halfedge(), poly); + CGAL::Euler::remove_face(halfedge(fh, sm), sm); ++index; } } - CGAL_assertion(index == 25); - CGAL_assertion(is_valid(poly)); + assert(index == 25); + assert(is_valid(sm)); return 0; } From 0a64b2740838ac7bf49def2c162240c06028d84f Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 2 Aug 2017 11:10:31 +0200 Subject: [PATCH 5/5] add missing header --- BGL/test/BGL/test_Manifold_face_removal.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/BGL/test/BGL/test_Manifold_face_removal.cpp b/BGL/test/BGL/test_Manifold_face_removal.cpp index 965ab4143aa..42b1e98fe63 100644 --- a/BGL/test/BGL/test_Manifold_face_removal.cpp +++ b/BGL/test/BGL/test_Manifold_face_removal.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;