mirror of https://github.com/CGAL/cgal
extend the visitor to report non-manifold vertex in an umbrella without nm edge
This commit is contained in:
parent
bc1fe892d8
commit
b539d4a301
|
|
@ -17,11 +17,23 @@ public:
|
||||||
|
|
||||||
/// called each time an edge appears in more than two polygons.
|
/// called each time an edge appears in more than two polygons.
|
||||||
/// `id1` and `id2` are the vertex ids of the endpoints of the edge.
|
/// `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.
|
/// called each time a non-manifold vertex is detected.
|
||||||
/// `id` is the id of the vertex has is non-manifold.
|
/// `vid` is the id of the vertex that is non-manifold.
|
||||||
void non_manifold_vertex(std::size_t id);
|
/// `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){}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,26 +16,27 @@
|
||||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||||
typedef CGAL::Polyhedron_3<K, CGAL::Polyhedron_items_with_id_3> Polyhedron;
|
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
|
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;
|
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;
|
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;
|
std::cout << "The polygon " << p_id << " has been reversed." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,12 @@ namespace Polygon_mesh_processing {
|
||||||
* overridden.
|
* overridden.
|
||||||
*/
|
*/
|
||||||
struct Default_orientation_visitor{
|
struct Default_orientation_visitor{
|
||||||
inline virtual void non_manifold_edge(std::size_t, std::size_t){}
|
void non_manifold_edge(std::size_t, std::size_t, std::size_t){}
|
||||||
inline virtual void non_manifold_vertex(std::size_t){}
|
void non_manifold_vertex(std::size_t,std::size_t){}
|
||||||
inline virtual void duplicated_vertex(std::size_t, std::size_t){}
|
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){}
|
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 polygon_orientation_reversed(std::size_t) {}
|
||||||
|
void link_connected_polygons(std::size_t, const std::vector<std::size_t>&){}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
@ -80,7 +81,7 @@ struct Polygon_soup_orienter
|
||||||
Edge_map edges; //< the set of edges of the input polygons
|
Edge_map edges; //< the set of edges of the input polygons
|
||||||
Marked_edges marked_edges; //< the set of singular edges or edges incident
|
Marked_edges marked_edges; //< the set of singular edges or edges incident
|
||||||
//< to non-compatible orientation polygons
|
//< to non-compatible orientation polygons
|
||||||
Visitor visitor;
|
Visitor& visitor;
|
||||||
|
|
||||||
/// for each polygon referenced by its position in `polygons`, indicates
|
/// for each polygon referenced by its position in `polygons`, indicates
|
||||||
/// the connected component it belongs too after orientation.
|
/// 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)
|
: 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
|
//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
|
// Fill edges
|
||||||
for (P_ID i = 0; i < polygons.size(); ++i)
|
for (P_ID i = 0; i < polygons.size(); ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -208,7 +203,7 @@ struct Polygon_soup_orienter
|
||||||
|
|
||||||
if (nb_edges > 2)
|
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);
|
set_edge_marked(i0, i1, marked_edges);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -357,24 +352,31 @@ struct Polygon_soup_orienter
|
||||||
if ( incident_polygons.empty() ) continue; //isolated vertex
|
if ( incident_polygons.empty() ) continue; //isolated vertex
|
||||||
std::set<P_ID> visited_polygons;
|
std::set<P_ID> visited_polygons;
|
||||||
|
|
||||||
bool first_pass = true;
|
std::size_t nb_link_ccs=0;
|
||||||
bool is_nm = false;
|
|
||||||
for(P_ID p_id : incident_polygons)
|
for(P_ID p_id : incident_polygons)
|
||||||
{
|
{
|
||||||
if ( !visited_polygons.insert(p_id).second ) continue; // already visited
|
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.push_back(std::pair<V_ID, std::vector<P_ID> >());
|
||||||
vertices_to_duplicate.back().first=v_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);
|
const std::array<V_ID,3>& neighbors = get_neighbor_vertices(v_id,p_id,polygons);
|
||||||
|
|
||||||
V_ID next = neighbors[2];
|
V_ID next = neighbors[2];
|
||||||
|
|
||||||
if( !first_pass)
|
if(nb_link_ccs != 1)
|
||||||
vertices_to_duplicate.back().second.push_back(p_id);
|
vertices_to_duplicate.back().second.push_back(p_id);
|
||||||
|
|
||||||
do{
|
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);
|
std::tie(next, other_p_id) = next_cw_vertex_around_source(v_id, next, polygons, edges, marked_edges);
|
||||||
if (next==v_id) break;
|
if (next==v_id) break;
|
||||||
visited_polygons.insert(other_p_id);
|
visited_polygons.insert(other_p_id);
|
||||||
if( !first_pass)
|
if(nb_link_ccs != 1)
|
||||||
vertices_to_duplicate.back().second.push_back(other_p_id);
|
vertices_to_duplicate.back().second.push_back(other_p_id);
|
||||||
}
|
}
|
||||||
while(next!=neighbors[0]);
|
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);
|
std::tie(next, other_p_id) = next_ccw_vertex_around_target(next, v_id, polygons, edges, marked_edges);
|
||||||
if (next==v_id) break;
|
if (next==v_id) break;
|
||||||
visited_polygons.insert(other_p_id);
|
visited_polygons.insert(other_p_id);
|
||||||
if( !first_pass)
|
if(nb_link_ccs != 1)
|
||||||
vertices_to_duplicate.back().second.push_back(other_p_id);
|
vertices_to_duplicate.back().second.push_back(other_p_id);
|
||||||
}
|
}
|
||||||
while(true);
|
while(true);
|
||||||
}
|
}
|
||||||
first_pass=false;
|
if (nb_link_ccs != 1)
|
||||||
}
|
visitor.link_connected_polygons(v_id, vertices_to_duplicate.back().second);
|
||||||
if (is_nm)
|
|
||||||
{
|
|
||||||
visitor.non_manifold_vertex(v_id);
|
|
||||||
}
|
}
|
||||||
|
if (nb_link_ccs != 1) visitor.non_manifold_vertex(v_id, nb_link_ccs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// now duplicate the vertices
|
/// now duplicate the vertices
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,8 @@ duplicate_non_manifold_edges_in_polygon_soup(PointRange& points,
|
||||||
typedef CGAL::Polygon_mesh_processing::internal::
|
typedef CGAL::Polygon_mesh_processing::internal::
|
||||||
Polygon_soup_orienter<PointRange, PolygonRange> Orienter;
|
Polygon_soup_orienter<PointRange, PolygonRange> Orienter;
|
||||||
|
|
||||||
Orienter orienter(points, polygons);
|
Default_orientation_visitor visitor;
|
||||||
|
Orienter orienter(points, polygons, visitor);
|
||||||
orienter.fill_edge_map();
|
orienter.fill_edge_map();
|
||||||
// make edges to duplicate
|
// make edges to duplicate
|
||||||
for(std::size_t i1=0;i1<points.size();++i1)
|
for(std::size_t i1=0;i1<points.size();++i1)
|
||||||
|
|
|
||||||
|
|
@ -254,25 +254,8 @@ void Polyhedron_demo_orient_soup_plugin::createPointsAndPolyline(std::vector<std
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
Scene_points_with_normal_item* points = nullptr;
|
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;
|
bool items_created = false;
|
||||||
if(nm_vertices.empty() && warn)
|
if(nm_points.empty() && warn)
|
||||||
{
|
{
|
||||||
delete points;
|
delete points;
|
||||||
CGAL::Three::Three::information(tr("There is no non-manifold vertex in this soup."));
|
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();
|
points = new Scene_points_with_normal_item();
|
||||||
items_created = true;
|
items_created = true;
|
||||||
for(std::size_t id : nm_vertices)
|
for(std::size_t id : nm_points)
|
||||||
{
|
{
|
||||||
points->point_set()->insert(item->points()[id]);
|
points->point_set()->insert(item->points()[id]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
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)
|
Visitor(const Polygon_soup::Polygons& polygons,
|
||||||
:nm_vertices(nm_vertices){}
|
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)
|
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);
|
d->soup->polygons.swap(valid_polygons);
|
||||||
|
|
||||||
bool res;
|
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);
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
res = CGAL::Polygon_mesh_processing::
|
res = CGAL::Polygon_mesh_processing::
|
||||||
orient_polygon_soup(d->soup->points, d->soup->polygons, CGAL::parameters::visitor(visitor));
|
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();
|
QApplication::restoreOverrideCursor();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue