diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPOrientationVisitor.h b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPOrientationVisitor.h index e1a9797f9c6..c0b20d83c34 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPOrientationVisitor.h +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPOrientationVisitor.h @@ -17,11 +17,23 @@ public: /// called each time an edge appears in more than two polygons. /// `id1` and `id2` are the vertex ids of the endpoints of the edge. -void non_manifold_edge(std::size_t id1, std::size_t id2); +/// `nb_polygons` indicates the number of polygons containing that edge. +void non_manifold_edge(std::size_t id1, std::size_t id2, std::size_t nb_polygons); /// called each time a non-manifold vertex is detected. -/// `id` is the id of the vertex has is non-manifold. -void non_manifold_vertex(std::size_t id); +/// `vid` is the id of the vertex that is non-manifold. +/// `nb_link_ccs` is the number of edge connected components of vertices +/// in the link of the corresponding vertex. +void non_manifold_vertex(std::size_t vid, std::size_t nb_link_ccs); + +/// called during the detection of a non-manifold vertex, one time +/// per incident edge connected component of vertices in the link of the vertex with id `vid`. +/// `id` is the id of the vertex that is non-manifold. +/// `polygon_ids` contains the ids of the polygon in such a connected component. +/// This function is called a number of times exactly equal to the parameter `nb_link_ccs` +/// for the same vertex in `non_manifold_vertex()`. Note that the aforementioned function is +/// called after all the calls to this function are done. +void link_connected_polygons(std::size_t vid, const std::vector& polygon_ids){} /// @} diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/orient_polygon_soup_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/orient_polygon_soup_example.cpp index 7416b4aabbd..67b13a79a8b 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/orient_polygon_soup_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/orient_polygon_soup_example.cpp @@ -16,26 +16,27 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Polyhedron_3 Polyhedron; -//Optional visitor for orientation to demonstrate usage +// Optional visitor for orientating a polygon soup to demonstrate usage for some functions. +// inherits from the default class as some functions are not overloaded struct Visitor : public CGAL::Polygon_mesh_processing::Default_orientation_visitor { - void non_manifold_edge(std::size_t id1, std::size_t id2) final + void non_manifold_edge(std::size_t id1, std::size_t id2, std::size_t nb_poly) { - std::cout << "The edge " << id1 << ", " << id2 << " is not manifold." << std::endl; + std::cout << "The edge " << id1 << ", " << id2 << " is not manifold: " << nb_poly << " incident polygons." << std::endl; } - void non_manifold_vertex(const std::size_t & id) final + void non_manifold_vertex(std::size_t id, std::size_t nb_cycles) { - std::cout << "The vertex " << id << " is not manifold." << std::endl; + std::cout << "The vertex " << id << " is not manifold: " << nb_lcc<< " connected components of vertices in the link." << std::endl; } - void duplicated_vertex(std::size_t v1, std::size_t v2) final + void duplicated_vertex(std::size_t v1, std::size_t v2) { std::cout << "The vertex " << v1 << " has been duplicated, its new id is " << v2 << "." << std::endl; } - void vertex_id_in_polygon_replaced(std::size_t p_id, std::size_t i1, std::size_t i2) final + void vertex_id_in_polygon_replaced(std::size_t p_id, std::size_t i1, std::size_t i2) { std::cout << "In the polygon " << p_id << ", the index " << i1 << " has been replaced by " << i2 << "." << std::endl; } - void polygon_orientation_reversed(std::size_t p_id) final + void polygon_orientation_reversed(std::size_t p_id) { std::cout << "The polygon " << p_id << " has been reversed." << std::endl; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orient_polygon_soup.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orient_polygon_soup.h index 39ad97d39ea..bcc364ea1a3 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orient_polygon_soup.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orient_polygon_soup.h @@ -45,11 +45,12 @@ namespace Polygon_mesh_processing { * overridden. */ struct Default_orientation_visitor{ - inline virtual void non_manifold_edge(std::size_t, std::size_t){} - inline virtual void non_manifold_vertex(std::size_t){} - inline virtual void duplicated_vertex(std::size_t, std::size_t){} - inline virtual void vertex_id_in_polygon_replaced(std::size_t, std::size_t, std::size_t){} - inline virtual void polygon_orientation_reversed(std::size_t) {} + void non_manifold_edge(std::size_t, std::size_t, std::size_t){} + void non_manifold_vertex(std::size_t,std::size_t){} + void duplicated_vertex(std::size_t, std::size_t){} + void vertex_id_in_polygon_replaced(std::size_t, std::size_t, std::size_t){} + void polygon_orientation_reversed(std::size_t) {} + void link_connected_polygons(std::size_t, const std::vector&){} }; namespace internal { @@ -80,7 +81,7 @@ struct Polygon_soup_orienter Edge_map edges; //< the set of edges of the input polygons Marked_edges marked_edges; //< the set of singular edges or edges incident //< to non-compatible orientation polygons - Visitor visitor; + Visitor& visitor; /// for each polygon referenced by its position in `polygons`, indicates /// the connected component it belongs too after orientation. @@ -168,18 +169,12 @@ struct Polygon_soup_orienter } } - Polygon_soup_orienter(Points& points, Polygons& polygons, Visitor visitor) + Polygon_soup_orienter(Points& points, Polygons& polygons, Visitor& visitor) : points(points), polygons(polygons), edges(points.size()), visitor(visitor) {} - Polygon_soup_orienter(Points& points, Polygons& polygons) - : points(points), polygons(polygons), edges(points.size()) - { - } - - //filling containers - static void fill_edge_map(Edge_map& edges, Marked_edges& marked_edges, const Polygons& polygons, Visitor visitor) { + static void fill_edge_map(Edge_map& edges, Marked_edges& marked_edges, const Polygons& polygons, Visitor& visitor) { // Fill edges for (P_ID i = 0; i < polygons.size(); ++i) { @@ -208,7 +203,7 @@ struct Polygon_soup_orienter if (nb_edges > 2) { - visitor.non_manifold_edge(i0, i1); + visitor.non_manifold_edge(i0, i1, nb_edges); set_edge_marked(i0, i1, marked_edges); } } @@ -357,24 +352,31 @@ struct Polygon_soup_orienter if ( incident_polygons.empty() ) continue; //isolated vertex std::set visited_polygons; - bool first_pass = true; - bool is_nm = false; + std::size_t nb_link_ccs=0; for(P_ID p_id : incident_polygons) { if ( !visited_polygons.insert(p_id).second ) continue; // already visited - if (!first_pass) + if (++nb_link_ccs != 1) { + // the vertex is non-manifold vertices_to_duplicate.push_back(std::pair >()); vertices_to_duplicate.back().first=v_id; - is_nm = true; + + // call the visitor only if the function has been overridden + if (nb_link_ccs==2 && &Visitor::link_connected_polygons != &Default_orientation_visitor::link_connected_polygons) + { + std::vector tmp(visited_polygons.begin(), visited_polygons.end()); + tmp.erase(std::remove(tmp.begin(), tmp.end(), p_id), tmp.end()); + visitor.link_connected_polygons(v_id, tmp); + } } const std::array& neighbors = get_neighbor_vertices(v_id,p_id,polygons); V_ID next = neighbors[2]; - if( !first_pass) + if(nb_link_ccs != 1) vertices_to_duplicate.back().second.push_back(p_id); do{ @@ -382,7 +384,7 @@ struct Polygon_soup_orienter std::tie(next, other_p_id) = next_cw_vertex_around_source(v_id, next, polygons, edges, marked_edges); if (next==v_id) break; visited_polygons.insert(other_p_id); - if( !first_pass) + if(nb_link_ccs != 1) vertices_to_duplicate.back().second.push_back(other_p_id); } while(next!=neighbors[0]); @@ -395,17 +397,15 @@ struct Polygon_soup_orienter std::tie(next, other_p_id) = next_ccw_vertex_around_target(next, v_id, polygons, edges, marked_edges); if (next==v_id) break; visited_polygons.insert(other_p_id); - if( !first_pass) + if(nb_link_ccs != 1) vertices_to_duplicate.back().second.push_back(other_p_id); } while(true); } - first_pass=false; - } - if (is_nm) - { - visitor.non_manifold_vertex(v_id); + if (nb_link_ccs != 1) + visitor.link_connected_polygons(v_id, vertices_to_duplicate.back().second); } + if (nb_link_ccs != 1) visitor.non_manifold_vertex(v_id, nb_link_ccs); } /// now duplicate the vertices diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orient_polygon_soup_extension.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orient_polygon_soup_extension.h index 91712ccfda8..2a9b8e05099 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orient_polygon_soup_extension.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orient_polygon_soup_extension.h @@ -64,7 +64,8 @@ duplicate_non_manifold_edges_in_polygon_soup(PointRange& points, typedef CGAL::Polygon_mesh_processing::internal:: Polygon_soup_orienter Orienter; - Orienter orienter(points, polygons); + Default_orientation_visitor visitor; + Orienter orienter(points, polygons, visitor); orienter.fill_edge_map(); // make edges to duplicate for(std::size_t i1=0;i1 check_set; - for(Scene_polygon_soup_item::Edge edge : item->non_manifold_edges()) - { - check_set.insert(edge[0]); - check_set.insert(edge[1]); - } - - std::set nm_vertices; - for(const auto& v : nm_points) - { - if(check_set.insert(v).second) - { - nm_vertices.insert(v); - } - } bool items_created = false; - if(nm_vertices.empty() && warn) + if(nm_points.empty() && warn) { delete points; CGAL::Three::Three::information(tr("There is no non-manifold vertex in this soup.")); @@ -281,7 +264,7 @@ void Polyhedron_demo_orient_soup_plugin::createPointsAndPolyline(std::vectorpoint_set()->insert(item->points()[id]); } diff --git a/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp index 9e5037a1105..116ff34f6b1 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp @@ -424,14 +424,45 @@ Scene_polygon_soup_item::orient(std::vector& non_manifold_vertices) { struct Visitor : public CGAL::Polygon_mesh_processing::Default_orientation_visitor { - std::vector& nm_vertices; + const Polygon_soup::Polygons& polygons; + std::set& nm_vertices; + std::set< std::pair > nm_edges; - Visitor(std::vector& nm_vertices) - :nm_vertices(nm_vertices){} + Visitor(const Polygon_soup::Polygons& polygons, + std::set& nm_vertices) + : polygons(polygons) + , nm_vertices(nm_vertices) + {} - void non_manifold_vertex(std::size_t v) final + void non_manifold_edge(std::size_t v1, std::size_t v2, std::size_t) { - nm_vertices.push_back(v); + nm_edges.insert(CGAL::make_sorted_pair(v1, v2)); + } + + void link_connected_polygons(std::size_t v, const std::vector& polygons_in_current_cycle) + { + // check if the current components of polygon incident to the link of the vertex contains + // a non-manifold edge. If no, then it is a "pure" non-manifold vertex in this component + if (!nm_edges.empty()) + for(std::size_t pid : polygons_in_current_cycle) + { + for (std::size_t i=0; ioriented) @@ -460,10 +491,12 @@ Scene_polygon_soup_item::orient(std::vector& non_manifold_vertices) d->soup->polygons.swap(valid_polygons); bool res; - Visitor visitor(non_manifold_vertices); + std::set nm_v_set; + Visitor visitor(valid_polygons, nm_v_set); QApplication::setOverrideCursor(Qt::WaitCursor); res = CGAL::Polygon_mesh_processing:: orient_polygon_soup(d->soup->points, d->soup->polygons, CGAL::parameters::visitor(visitor)); + non_manifold_vertices.assign(nm_v_set.begin(), nm_v_set.end()); QApplication::restoreOverrideCursor(); return res; }