diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt index bde2ed1888e..21bfd1ae77b 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt @@ -39,7 +39,7 @@ endif() polyhedron_demo_plugin(orient_soup_plugin Orient_soup_plugin) -target_link_libraries(orient_soup_plugin PUBLIC scene_polygon_soup_item scene_polyhedron_item scene_surface_mesh_item) +target_link_libraries(orient_soup_plugin PUBLIC scene_polygon_soup_item scene_polyhedron_item scene_surface_mesh_item scene_polylines_item scene_points_with_normal_item) polyhedron_demo_plugin(inside_out_plugin Inside_out_plugin) diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Orient_soup_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Orient_soup_plugin.cpp index a41e9b55b26..80209f19efd 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Orient_soup_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Orient_soup_plugin.cpp @@ -3,13 +3,18 @@ #include #include #include +#include #include #include "Scene_polygon_soup_item.h" #include "Scene_polyhedron_item.h" +#include "Scene_polylines_item.h" #include "Scene_surface_mesh_item.h" +#include "Scene_points_with_normal_item.h" #include +#include +#include #include "Messages_interface.h" using namespace CGAL::Three; class Polyhedron_demo_orient_soup_plugin : @@ -45,17 +50,22 @@ public Q_SLOTS: void orientSM(); void shuffle(); void displayNonManifoldEdges(); + void createPointsAndPolyline(); private: template void apply_shuffle(Item* item, const CGAL::Three::Scene_interface::Item_id& index); + void getNMPoints(std::vector &vertices_to_duplicate, + Scene_polygon_soup_item* item); + CGAL::Three::Scene_interface* scene; Messages_interface* messages; QMainWindow* mw; QAction* actionOrientPoly; QAction* actionOrientSM; QAction* actionShuffle; + QAction* actionNMToPolyline; QAction* actionDisplayNonManifoldEdges; }; // end Polyhedron_demo_orient_soup_plugin @@ -88,6 +98,10 @@ void Polyhedron_demo_orient_soup_plugin::init(QMainWindow* mainWindow, actionDisplayNonManifoldEdges->setProperty("subMenuName", "View"); connect(actionDisplayNonManifoldEdges, SIGNAL(triggered()), this, SLOT(displayNonManifoldEdges())); + actionNMToPolyline = new QAction(tr("Extract Non Manifold Simplices"), mainWindow); + actionNMToPolyline->setProperty("subMenuName", "Polygon Mesh Processing"); + connect(actionNMToPolyline, &QAction::triggered, + this, &Polyhedron_demo_orient_soup_plugin::createPointsAndPolyline); } QList Polyhedron_demo_orient_soup_plugin::actions() const { @@ -95,6 +109,7 @@ QList Polyhedron_demo_orient_soup_plugin::actions() const { << actionOrientPoly << actionOrientSM << actionShuffle + << actionNMToPolyline << actionDisplayNonManifoldEdges; } @@ -135,6 +150,11 @@ void Polyhedron_demo_orient_soup_plugin::orientPoly() if(item) { + int create_items = QMessageBox::question(mw, "Orient Mesh", "Do you wish to extract the eventual non manifold simplicies ?"); + if(create_items == QMessageBox::Yes) + { + createPointsAndPolyline(); + } if(!item->orient()) { QMessageBox::information(mw, tr("Not orientable without self-intersections"), tr("The polygon soup \"%1\" is not directly orientable." @@ -175,7 +195,11 @@ void Polyhedron_demo_orient_soup_plugin::orientSM() if(item) { - // qDebug() << tr("I have the item %1\n").arg(item->name()); + int create_items = QMessageBox::question(mw, "Orient Mesh", "Do you wish to extract the potential non manifold simplicies ?"); + if(create_items == QMessageBox::Yes) + { + createPointsAndPolyline(); + } if(!item->orient()) { QMessageBox::information(mw, tr("Not orientable without self-intersections"), tr("The polygon soup \"%1\" is not directly orientable." @@ -271,5 +295,143 @@ void Polyhedron_demo_orient_soup_plugin::displayNonManifoldEdges() QApplication::restoreOverrideCursor(); } } +void Polyhedron_demo_orient_soup_plugin::createPointsAndPolyline() +{ + + const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex(); + + Scene_polygon_soup_item* item = + qobject_cast(scene->item(index)); + if(item) + { + QApplication::setOverrideCursor(Qt::WaitCursor); + Scene_points_with_normal_item* points = new Scene_points_with_normal_item(); + std::vector nm_vertices; + getNMPoints(nm_vertices, item); + bool items_created = false; + if(nm_vertices.empty()) + { + delete points; + messages->information(tr("There is no non-manifold vertex in this soup.")); + } + else + { + items_created = true; + BOOST_FOREACH(std::size_t id, nm_vertices) + { + points->point_set()->insert(item->points()[id]); + } + points->setName(QString("Non Manifold Vertices of %1").arg(item->name())); + points->setColor(QColor(Qt::red)); + + scene->addItem(points); + } + Polygon_soup::Edges nm_edges = item->non_manifold_edges(); + if(!nm_edges.empty()) + { + Scene_polylines_item* poly = + new Scene_polylines_item(); + BOOST_FOREACH(Polygon_soup::Edge edge, nm_edges) + { + Point_3 a(item->points()[edge[0]]), b(item->points()[edge[1]]); + Scene_polylines_item::Polyline new_edge; + new_edge.push_back(a); + new_edge.push_back(b); + poly->polylines.push_back(new_edge); + } + poly->setName(QString("Non Manifold Edges of %1").arg(item->name())); + poly->setColor(QColor(Qt::red)); + + scene->addItem(poly); + items_created = true; + } + else + { + messages->information(tr("There is no non-manifold edge in this soup.")); + } + QApplication::restoreOverrideCursor(); + if(!items_created) + QMessageBox::information(mw, "Nothing Non-manifold", "No non-manifold edge nor vertex was found."); + } +} + +void Polyhedron_demo_orient_soup_plugin::getNMPoints( + std::vector &vertices_to_duplicate, + Scene_polygon_soup_item* item) +{ + typedef std::pair V_ID_pair; + typedef std::map > Edge_map; + typedef std::set Marked_edges; + typedef CGAL::Polygon_mesh_processing::internal::Polygon_soup_orienter PSO; + + Edge_map edges; + Marked_edges m_edges; + PSO::fill_edge_map(edges, m_edges, item->polygons()); + + // for each vertex, indicates the list of polygon containing it + std::vector< std::vector > incident_polygons_per_vertex(item->points().size()); + std::size_t nb_polygons=item->polygons().size(); + for(std::size_t ip=0; ippolygons()[ip]) + incident_polygons_per_vertex[iv].push_back(ip); + } + + std::size_t nbv = item->points().size(); + + for (std::size_t v_id = 0; v_id < nbv; ++v_id) + { + const std::vector< std::size_t >& incident_polygons = incident_polygons_per_vertex[v_id]; + + if ( incident_polygons.empty() ) continue; //isolated vertex + std::set visited_polygons; + + bool first_pass = true; + BOOST_FOREACH(std::size_t p_id, incident_polygons) + { + if ( !visited_polygons.insert(p_id).second ) continue; // already visited + + if (!first_pass) + { + vertices_to_duplicate.push_back(v_id); + } + + + std::size_t nbv = item->polygons()[p_id].size(), pvid=0; + for (; pvid!=nbv; ++pvid) + if (v_id==item->polygons()[p_id][pvid]) break; + CGAL_assertion( pvid!=nbv ); + std::size_t p = item->polygons()[p_id][ (pvid+nbv-1)%nbv ]; + std::size_t n = item->polygons()[p_id][ (pvid+1)%nbv ]; + const CGAL::cpp11::array& neighbors = CGAL::make_array(p,v_id,n); + + std::size_t next = neighbors[2]; + + do{ + std::size_t other_p_id; + CGAL::cpp11::tie(next, other_p_id) = PSO::next_cw_vertex_around_source(v_id, next, item->polygons(), edges, m_edges); + if (next==v_id) break; + visited_polygons.insert(other_p_id); + } + while(next!=neighbors[0]); + + if (next==v_id){ + /// turn the otherway round + next = neighbors[0]; + do{ + std::size_t other_p_id; + CGAL::cpp11::tie(next, other_p_id) = PSO::next_ccw_vertex_around_target(next, v_id, item->polygons(), edges, m_edges); + if (next==v_id) break; + visited_polygons.insert(other_p_id); + } + while(true); + } + first_pass=false; + } + } + +} #include "Orient_soup_plugin.moc" + diff --git a/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp index fc648cfd220..456c6660080 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp @@ -920,3 +920,9 @@ void Scene_polygon_soup_item::itemAboutToBeDestroyed(Scene_item *item) } } } + +const Polygon_soup::Edges& +Scene_polygon_soup_item::non_manifold_edges() const +{ + return d->soup->non_manifold_edges; +} \ No newline at end of file diff --git a/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.h b/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.h index beb3945bc73..62881741c53 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.h @@ -108,6 +108,7 @@ public: typedef Kernel::Point_3 Point_3; typedef Polygon_soup::Points Points; typedef Polygon_soup::Polygons Polygons; + typedef Polygon_soup::Edges Edges; Scene_polygon_soup_item(); ~Scene_polygon_soup_item(); @@ -151,6 +152,7 @@ public: const Points& points() const; const Polygons& polygons() const; + const Edges& non_manifold_edges() const; public Q_SLOTS: void shuffle_orientations();