diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index 8d3d837034b..b886add0ff6 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -727,7 +727,7 @@ private: std::cout << "> Extract possibly non-manifold wrap... ()" << std::endl; #endif - clear(output_mesh); + remove_all_elements(output_mesh); CGAL_assertion_code(for(auto cit=m_tr.finite_cells_begin(), cend=m_tr.finite_cells_end(); cit!=cend; ++cit)) CGAL_assertion(cit->tds_data().is_clear()); @@ -814,7 +814,7 @@ private: CGAL_assertion_code(for(Vertex_handle v : m_tr.finite_vertex_handles())) CGAL_assertion(!is_non_manifold(v)); - clear(output_mesh); + remove_all_elements(output_mesh); std::vector points; std::vector > faces; diff --git a/BGL/doc/BGL/PackageDescription.txt b/BGL/doc/BGL/PackageDescription.txt index 89497261a96..883c1b3ad46 100644 --- a/BGL/doc/BGL/PackageDescription.txt +++ b/BGL/doc/BGL/PackageDescription.txt @@ -690,6 +690,7 @@ user might encounter. - `CGAL::make_grid()` - `CGAL::clear()` +- `CGAL::remove_all_elements()` - `CGAL::copy_face_graph()` - `CGAL::set_triangulation_ids()` diff --git a/BGL/include/CGAL/IO/polygon_mesh_io.h b/BGL/include/CGAL/IO/polygon_mesh_io.h index b8b86d45f8f..21f61087ab6 100644 --- a/BGL/include/CGAL/IO/polygon_mesh_io.h +++ b/BGL/include/CGAL/IO/polygon_mesh_io.h @@ -45,25 +45,25 @@ bool read_polygon_mesh(std::istream& is, ok = read_OFF(is, g, np, false); if(ok) return true; - g.clear(); + clear(g); is.clear();//reset the error state is.seekg (0, is.beg); ok = read_OBJ(is, g, np, false); if(ok) return true; - g.clear(); + clear(g); is.clear(); is.seekg (0, is.beg); ok = read_PLY(is, g, np, false); if(ok) return true; - g.clear(); + clear(g); is.clear(); is.seekg (0, is.beg); ok = read_STL(is, g, np, false); if(ok) return true; - g.clear(); + clear(g); is.clear(); is.seekg (0, is.beg); ok = read_GOCAD(is, g, np, false); diff --git a/BGL/include/CGAL/boost/graph/IO/STL.h b/BGL/include/CGAL/boost/graph/IO/STL.h index d2cb78c4524..9796b462917 100644 --- a/BGL/include/CGAL/boost/graph/IO/STL.h +++ b/BGL/include/CGAL/boost/graph/IO/STL.h @@ -172,7 +172,7 @@ bool read_STL(const std::string& fname, { return true; } - g.clear(); + clear(g); } std::ifstream is(fname); CGAL::IO::set_mode(is, CGAL::IO::ASCII); diff --git a/BGL/include/CGAL/boost/graph/IO/polygon_mesh_io.h b/BGL/include/CGAL/boost/graph/IO/polygon_mesh_io.h index 84189cf7373..edb858a160f 100644 --- a/BGL/include/CGAL/boost/graph/IO/polygon_mesh_io.h +++ b/BGL/include/CGAL/boost/graph/IO/polygon_mesh_io.h @@ -11,6 +11,8 @@ #ifndef CGAL_BOOST_GRAPH_POLYGON_MESH_IO_H #define CGAL_BOOST_GRAPH_POLYGON_MESH_IO_H + #include + #endif // CGAL_BOOST_GRAPH_POLYGON_MESH_IO_H diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index 32b99ba397d..75673493e0d 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -837,25 +837,6 @@ bool is_hexahedron(typename boost::graph_traits::halfedge_descriptor namespace internal { -template -inline -std::enable_if_t::value, void> -clear_impl(FaceGraph& g) -{ g.clear(); } - -template -inline -std::enable_if_t::value, void> -clear_impl(FaceGraph& g) -{ - while(std::begin(edges(g))!=std::end(edges(g))) - remove_edge(*std::begin(edges(g)), g); - while(std::begin(faces(g))!=std::end(faces(g))) - remove_face(*std::begin(faces(g)), g); - while(std::begin(vertices(g))!=std::end(vertices(g))) - remove_vertex(*std::begin(vertices(g)), g); -} - template void swap_vertices(typename boost::graph_traits::vertex_descriptor& p, typename boost::graph_traits::vertex_descriptor& q, @@ -965,24 +946,86 @@ void collect_garbage(Graph&) * \ingroup PkgBGLHelperFct * * removes all vertices, faces and halfedges from a graph. Calls - * `remove_edge()`, `remove_vertex()`, and `remove_face()` for each - * edge, vertex or face. + * \link MutableHalfedgeGraph `remove_vertex()`\endlink, + * \link MutableHalfedgeGraph `remove_edge()`\endlink, and + * \link MutableFaceGraph `remove_face()`\endlink, for each vertex, edge, and face. + * + * Note that some graphs have a specialized version of this function to improve + * complexity. + * + * @warning This function does not perform anything more than what is advertised above. It is + * up to the user to e.g. clean garbage or remove internal property maps (if relevant, and desired). + * + * @tparam FaceGraph model of `MutableHalfedgeGraph` and `MutableFaceGraph` + * + * @param g the graph whose elements will be removed + * + * @sa `CGAL::clear()` + **/ +template +void remove_all_elements(FaceGraph& g) +{ + while(std::begin(edges(g)) != std::end(edges(g))) + remove_edge(*std::begin(edges(g)), g); + while(std::begin(faces(g)) != std::end(faces(g))) + remove_face(*std::begin(faces(g)), g); + while(std::begin(vertices(g)) != std::end(vertices(g))) + remove_vertex(*std::begin(vertices(g)), g); + + CGAL_postcondition(std::distance(std::cbegin(vertices(g)), std::cend(vertices(g))) == 0); + CGAL_postcondition(std::distance(std::cbegin(edges(g)), std::cend(edges(g))) == 0); + CGAL_postcondition(std::distance(std::cbegin(faces(g)), std::cend(faces(g))) == 0); +} + +namespace internal { + +template +inline +std::enable_if_t::value, void> +clear_impl(FaceGraph& g) +{ + g.clear(); +} + +template +inline +std::enable_if_t::value, void> +clear_impl(FaceGraph& g) +{ + remove_all_elements(g); +} + +} // namespace internal + +/** + * \ingroup PkgBGLHelperFct + * + * removes all vertices, faces and halfedges from a graph. Calls + * \link MutableHalfedgeGraph `remove_vertex()`\endlink, + * \link MutableHalfedgeGraph `remove_edge()`\endlink, and + * \link MutableFaceGraph `remove_face()`\endlink, for each vertex, edge, and face. * * If the graph has a member function `clear()`, it will be called * instead. * + * @warning If it exists, the `clear()` function of a graph might do more than + * simply remove elements. For example, `CGAL::Surface_mesh::clear()` collects garbage + * and removes *all* property maps added by a call to `CGAL::Surface_mesh::add_property_map()` for all simplex types. + * * @tparam FaceGraph model of `MutableHalfedgeGraph` and `MutableFaceGraph` * * @param g the graph to clear * + * @sa `CGAL::remove_all_elements()` **/ template void clear(FaceGraph& g) { internal::clear_impl(g); - CGAL_postcondition(std::distance(std::begin(edges(g)),std::end(edges(g))) == 0); - CGAL_postcondition(std::distance(std::begin(vertices(g)),std::end(vertices(g))) == 0); - CGAL_postcondition(std::distance(std::begin(faces(g)),std::end(faces(g))) == 0); + + CGAL_postcondition(std::distance(std::cbegin(vertices(g)), std::cend(vertices(g))) == 0); + CGAL_postcondition(std::distance(std::cbegin(edges(g)), std::cend(edges(g))) == 0); + CGAL_postcondition(std::distance(std::cbegin(faces(g)), std::cend(faces(g))) == 0); } /** diff --git a/BGL/test/BGL/test_Face_filtered_graph.cpp b/BGL/test/BGL/test_Face_filtered_graph.cpp index 9917b7d06a5..d83de2bbdc6 100644 --- a/BGL/test/BGL/test_Face_filtered_graph.cpp +++ b/BGL/test/BGL/test_Face_filtered_graph.cpp @@ -513,7 +513,7 @@ void test_invalid_selections() assert(pinched_fg.is_selection_valid()); // this creates a non-manifold vertex (multiple umbrellas) - clear(mesh); + CGAL::clear(mesh); read_a_mesh(mesh, "data/genus3.off"); assert(is_valid_polygon_mesh(mesh)); diff --git a/BGL/test/BGL/test_bgl_read_write.cpp b/BGL/test/BGL/test_bgl_read_write.cpp index 694c8a9933f..962a53ba541 100644 --- a/BGL/test/BGL/test_bgl_read_write.cpp +++ b/BGL/test/BGL/test_bgl_read_write.cpp @@ -122,7 +122,7 @@ void test_bgl_OFF(const std::string filename) assert(ok); assert(num_vertices(fg) != 0 && num_faces(fg) != 0); is.close(); - fg.clear(); + CGAL::clear(fg); is.open(filename, std::ios::binary); ok = CGAL::IO::read_OFF(is, fg); @@ -286,7 +286,7 @@ void test_bgl_OFF(const std::string filename) for(auto f : faces(fg)) assert(get(fcm2, f) != CGAL::IO::Color()); - fg.clear(); + CGAL::clear(fg); is.close(); is.open("data/full.off"); @@ -478,7 +478,7 @@ void test_bgl_PLY(const std::string filename, assert(filename != CGAL::data_file_path("meshes/colored_tetra.ply") || (num_vertices(fg) == 4 && num_faces(fg) == 4)); if(!binary) { - fg.clear(); + CGAL::clear(fg); is.open(filename, std::ios::binary); bool ok = CGAL::IO::read_PLY(is, fg, CGAL::parameters::use_binary_mode(false)); is.close(); @@ -711,7 +711,6 @@ void test_bgl_GOCAD(const char* filename) assert(num_vertices(fg) != 0 && num_faces(fg) != 0); is.seekg(0); - fg.clear(); CGAL::clear(fg); std::pair name_and_color; ok = CGAL::IO::read_GOCAD(is, name_and_color, fg); diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index c46826b1d5f..c6940c7ae72 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -105,6 +105,12 @@ Release date: October 2023 only affects custom point types where not all points in the same position are equivalent. +### [CGAL and the Boost Graph Library (BGL)](https://doc.cgal.org/6.0/Manual/packages.html#PkgBGL) + +- Added the function `remove_all_elements()`, which removes vertices, halfedges, and faces + without collecting garbage and without removing properties. + + [Release 5.6](https://github.com/CGAL/cgal/releases/tag/v5.6) ----------- diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/cc_compatible_orientations.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/cc_compatible_orientations.cpp index 646e94e9468..2c1b55c183c 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/cc_compatible_orientations.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/cc_compatible_orientations.cpp @@ -43,7 +43,7 @@ void create_mesh_with_cc_to_orient(Mesh& mesh) } // load the soup into the mesh; - mesh.clear(); + CGAL::clear(mesh); PMP::polygon_soup_to_polygon_mesh(points, triangles, mesh); } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h index 9cf0e4b43a5..5926bab0020 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h @@ -738,7 +738,7 @@ bool clip(TriangleMesh& tm, case ON_NEGATIVE_SIDE: return true; // nothing to clip, the full mesh is on the negative side case ON_POSITIVE_SIDE: - clear(tm); // clear the mesh that is fully on the positive side + remove_all_elements(tm); // clear the mesh that is fully on the positive side return true; default: break; 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 bffa8e6dca1..bdca099e32c 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 @@ -423,7 +423,7 @@ std::size_t keep_largest_connected_components(PolygonMesh& pmesh, if(nb_components_to_keep == 0) { - CGAL::clear(pmesh); + remove_all_elements(pmesh); return num; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h index c955aa8bdc3..105a74f51b9 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h @@ -266,11 +266,11 @@ corefine_and_compute_boolean_operations( if (output[Corefinement::TM1_MINUS_TM2] != std::nullopt) if (&tm1 == *output[Corefinement::TM1_MINUS_TM2]) - clear(tm1); + remove_all_elements(tm1); if (output[Corefinement::TM2_MINUS_TM1] != std::nullopt) if (&tm1 == *output[Corefinement::TM2_MINUS_TM1]) - clear(tm1); + remove_all_elements(tm1); return CGAL::make_array(true, true, true, true); } @@ -282,7 +282,7 @@ corefine_and_compute_boolean_operations( { for (int i=0; i<4; ++i) if (output[i] != std::nullopt) - clear(*(*output[i])); + remove_all_elements(*(*output[i])); return CGAL::make_array(true, true, true, true); } // tm2 is not empty @@ -293,9 +293,9 @@ corefine_and_compute_boolean_operations( parameters::vertex_point_map(vpm2), parameters::vertex_point_map(*std::get(vpm_out_tuple))); if (output[Corefinement::INTERSECTION] != std::nullopt) - clear(*(*output[Corefinement::INTERSECTION])); + remove_all_elements(*(*output[Corefinement::INTERSECTION])); if (output[Corefinement::TM1_MINUS_TM2] != std::nullopt) - clear(*(*output[Corefinement::TM1_MINUS_TM2])); + remove_all_elements(*(*output[Corefinement::TM1_MINUS_TM2])); if (output[Corefinement::TM2_MINUS_TM1] != std::nullopt) if (&tm2 != *output[Corefinement::TM2_MINUS_TM1]) copy_face_graph(tm2, @@ -315,9 +315,9 @@ corefine_and_compute_boolean_operations( parameters::vertex_point_map(vpm1), parameters::vertex_point_map(*std::get(vpm_out_tuple))); if (output[Corefinement::INTERSECTION] != std::nullopt) - clear(*(*output[Corefinement::INTERSECTION])); + remove_all_elements(*(*output[Corefinement::INTERSECTION])); if (output[Corefinement::TM2_MINUS_TM1] != std::nullopt) - clear(*(*output[Corefinement::TM2_MINUS_TM1])); + remove_all_elements(*(*output[Corefinement::TM2_MINUS_TM1])); if (output[Corefinement::TM1_MINUS_TM2] != std::nullopt) if (&tm1 != *output[Corefinement::TM1_MINUS_TM2]) copy_face_graph(tm1, 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 33514d6f2de..69ef710f616 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 @@ -1263,8 +1263,7 @@ bool decimate_meshes_with_common_interfaces_impl(TriangleMeshRange& meshes, } CGAL_assertion(is_polygon_soup_a_polygon_mesh(all_faces[mesh_id])); - //clear(tm); - tm.clear_without_removing_property_maps(); + remove_all_elements(tm); polygon_soup_to_polygon_mesh(all_corners[mesh_id], all_faces[mesh_id], tm, parameters::default_values(), parameters::vertex_point_map(vpms[mesh_id])); } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h index 1dde0a5b20d..19adcd48319 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h @@ -1934,7 +1934,7 @@ bool remove_degenerate_faces(const FaceRange& face_range, if(degenerate_face_set.size() == faces_size) { - clear(tmesh); + remove_all_elements(tmesh); return true; } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/all_degen.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/all_degen.off new file mode 100644 index 00000000000..f579551770c --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data_degeneracies/all_degen.off @@ -0,0 +1,16 @@ +OFF +7 7 0 +0 0 0 +1 1 0 +1 1 0 +2 2 0 +1 1 0 +2 2 0 +0.5 1 0 +3 0 2 1 +3 0 3 2 +3 4 3 5 +3 1 4 5 +3 1 2 6 +3 6 2 4 +3 6 4 1 diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_repair_degeneracies.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_repair_degeneracies.cpp index 847e9dbf615..dfbeee6f1ba 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_repair_degeneracies.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_repair_degeneracies.cpp @@ -287,6 +287,11 @@ void test() 0, 1, // expected number of degenerate edges/faces in the selection 0, 0); // expected number of degenerate edges/faces in the mesh after partial removal + remove_degeneracies("data_degeneracies/all_degen.off", + std::initializer_list({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}), // edge selection + std::initializer_list({0, 1, 2, 3, 4, 5, 6}), // face selection + 4, 7, 4, 7, 0, 0); + remove_degeneracies("data_degeneracies/degtri_four.off", std::initializer_list({1}), std::initializer_list({3}), diff --git a/Polyhedron/include/CGAL/boost/graph/graph_traits_Polyhedron_3.h b/Polyhedron/include/CGAL/boost/graph/graph_traits_Polyhedron_3.h index f8e6e9a21ca..7626c554fe1 100644 --- a/Polyhedron/include/CGAL/boost/graph/graph_traits_Polyhedron_3.h +++ b/Polyhedron/include/CGAL/boost/graph/graph_traits_Polyhedron_3.h @@ -313,6 +313,12 @@ set_halfedge(typename boost::graph_traits< CGAL::Polyhedron_3 >::ver static_cast(*v).set_halfedge(h); } +template +void +remove_all_elements(CGAL::Polyhedron_3& g) +{ + g.clear(); +} // // HalfedgeGraph diff --git a/Surface_mesh/include/CGAL/boost/graph/graph_traits_Surface_mesh.h b/Surface_mesh/include/CGAL/boost/graph/graph_traits_Surface_mesh.h index b46df17715b..29699dc1ddc 100644 --- a/Surface_mesh/include/CGAL/boost/graph/graph_traits_Surface_mesh.h +++ b/Surface_mesh/include/CGAL/boost/graph/graph_traits_Surface_mesh.h @@ -472,7 +472,6 @@ remove_vertex(typename boost::graph_traits >::vertex_descr sm.remove_vertex(v); } - template void remove_edge(typename boost::graph_traits >::vertex_descriptor u, @@ -491,7 +490,6 @@ remove_edge(typename boost::graph_traits >::edge_descripto sm.remove_edge(e); } - template void remove_edge(typename boost::graph_traits >::edge_iterator eiter, @@ -508,6 +506,13 @@ remove_face(typename boost::graph_traits >::face_descripto sm.remove_face(f); } +template +void +remove_all_elements(CGAL::Surface_mesh

& sm) +{ + sm.clear_without_removing_property_maps(); +} + template typename boost::graph_traits >::face_descriptor add_face(CGAL::Surface_mesh

& sm)