extend the visitor to report non-manifold vertex in an umbrella without nm edge

This commit is contained in:
Sébastien Loriot 2021-08-05 18:06:50 +02:00
parent bc1fe892d8
commit b539d4a301
6 changed files with 94 additions and 64 deletions

View File

@ -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<std::size_t>& polygon_ids){}
/// @}

View File

@ -16,26 +16,27 @@
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Polyhedron_3<K, CGAL::Polyhedron_items_with_id_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;
}

View File

@ -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<std::size_t>&){}
};
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<P_ID> 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<V_ID, std::vector<P_ID> >());
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<std::size_t> 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<V_ID,3>& 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

View File

@ -64,7 +64,8 @@ duplicate_non_manifold_edges_in_polygon_soup(PointRange& points,
typedef CGAL::Polygon_mesh_processing::internal::
Polygon_soup_orienter<PointRange, PolygonRange> 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<points.size();++i1)

View File

@ -254,25 +254,8 @@ void Polyhedron_demo_orient_soup_plugin::createPointsAndPolyline(std::vector<std
QApplication::setOverrideCursor(Qt::WaitCursor);
Scene_points_with_normal_item* points = nullptr;
//remove vertices already in NM edges
std::unordered_set<std::size_t> 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<std::size_t> 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::vector<std
{
points = new Scene_points_with_normal_item();
items_created = true;
for(std::size_t id : nm_vertices)
for(std::size_t id : nm_points)
{
points->point_set()->insert(item->points()[id]);
}

View File

@ -424,14 +424,45 @@ Scene_polygon_soup_item::orient(std::vector<std::size_t>& non_manifold_vertices)
{
struct Visitor : public CGAL::Polygon_mesh_processing::Default_orientation_visitor
{
std::vector<std::size_t>& nm_vertices;
const Polygon_soup::Polygons& polygons;
std::set<std::size_t>& nm_vertices;
std::set< std::pair<std::size_t, std::size_t> > nm_edges;
Visitor(std::vector<std::size_t>& nm_vertices)
:nm_vertices(nm_vertices){}
Visitor(const Polygon_soup::Polygons& polygons,
std::set<std::size_t>& 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<std::size_t>& 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; i<polygons[pid].size(); ++i)
{
if (polygons[pid][i]==v)
{
std::size_t vn1 = i==0?(polygons[pid].size()-1):(i-1);
std::size_t vn2 = i+1;
if (vn2==polygons[pid].size()) vn2=0;
if (nm_edges.count(CGAL::make_sorted_pair(polygons[pid][i], polygons[pid][vn1]))==1) return;
if (nm_edges.count(CGAL::make_sorted_pair(polygons[pid][i], polygons[pid][vn2]))==1) return;
break;
}
else
CGAL_assertion(i!=polygons[pid].size()-1); // the vertex is incident to the polygon
}
}
nm_vertices.insert(v);
}
};
if(isEmpty() || d->oriented)
@ -460,10 +491,12 @@ Scene_polygon_soup_item::orient(std::vector<std::size_t>& non_manifold_vertices)
d->soup->polygons.swap(valid_polygons);
bool res;
Visitor visitor(non_manifold_vertices);
std::set<std::size_t> 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;
}