diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp index 76d53b4014b..580023022f7 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp @@ -2,6 +2,7 @@ #include "Scene_polygon_soup_item.h" #include "Scene_points_with_normal_item.h" #include +#include #include @@ -25,17 +26,17 @@ class Polyhedron_demo_off_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90" FILE "off_io_plugin.json") public: - bool isDefaultLoader(const Scene_item *item) const - { + bool isDefaultLoader(const Scene_item *item) const + { if(qobject_cast(item) - || qobject_cast(item)) - return true; + || qobject_cast(item)) + return true; return false; } - bool isDefaultLoader(const QString& name) const - { - if(name == QString("off")) - return true; + bool isDefaultLoader(const QString& name) const + { + if(name == QString("off")) + return true; return false; } QString name() const { return "off_plugin"; } @@ -44,7 +45,7 @@ public: QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true); CGAL::Three::Scene_item* load_off(QFileInfo fileinfo); CGAL::Three::Scene_item* load_obj(QFileInfo fileinfo); - + bool canSave(const CGAL::Three::Scene_item*); bool save(QFileInfo fileinfo,QList& ); }; @@ -55,7 +56,7 @@ bool Polyhedron_demo_off_plugin::canLoad(QFileInfo) const { QList Polyhedron_demo_off_plugin:: load(QFileInfo fileinfo, bool& ok, bool add_to_scene) { - + if(fileinfo.size() == 0) { CGAL::Three::Three::warning( tr("The file you are trying to load is empty.")); @@ -108,10 +109,10 @@ Polyhedron_demo_off_plugin::load_off(QFileInfo fileinfo) { std::cerr << "Error! Cannot open file " << (const char*)fileinfo.filePath().toUtf8() << std::endl; return NULL; } - - + + CGAL::File_scanner_OFF scanner( in, false); - + // Try to read .off in a point set if (scanner.size_of_facets() == 0) { @@ -124,10 +125,10 @@ Polyhedron_demo_off_plugin::load_off(QFileInfo fileinfo) { delete item; return 0; } - + return item; } - + in.seekg(0); // Try to read .off in a surface_mesh SMesh *surface_mesh = new SMesh(); @@ -181,6 +182,19 @@ Polyhedron_demo_off_plugin::load_off(QFileInfo fileinfo) { tr("%1 isolated vertices found") .arg(item->getNbIsolatedvertices())); } + typedef boost::function_output_iterator OutputIterator; + try{ + CGAL::Polygon_mesh_processing::non_manifold_vertices(*surface_mesh, OutputIterator()); + } + catch( CGAL::internal::Throw_at_output::Throw_at_output_exception& ) + { + + QApplication::restoreOverrideCursor(); + QMessageBox::warning((QWidget*)NULL, + tr("Non Manifold Vertices"), + tr("Non-manifold vertices have been found")); + } + if(item->isItemMulticolor()) item->computeItemColorVectorAutomatically(true); return item; @@ -218,9 +232,9 @@ save(QFileInfo fileinfo,QList& items) // This plugin supports point sets, surface_meshes and polygon soups const Scene_points_with_normal_item* points_item = qobject_cast(item); - const Scene_surface_mesh_item* sm_item = + const Scene_surface_mesh_item* sm_item = qobject_cast(item); - const Scene_polygon_soup_item* soup_item = + const Scene_polygon_soup_item* soup_item = qobject_cast(item); if(!sm_item && !soup_item && !points_item) diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Polyhedron_stitching_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Polyhedron_stitching_plugin.cpp index 011d5e9dc79..79cb4dbec8c 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Polyhedron_stitching_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Polyhedron_stitching_plugin.cpp @@ -14,25 +14,6 @@ #include #include -template -struct Is_border { - const G& g; - Is_border(const G& g) - : g(g) - {} - - template - bool operator()(const Descriptor& d) const { - return is_border(d,g); - } - - bool operator()(typename boost::graph_traits::vertex_descriptor d) const { - return is_border(d,g) != boost::none; - } - -}; - - using namespace CGAL::Three; class Polyhedron_demo_polyhedron_stitching_plugin : public QObject, @@ -90,30 +71,6 @@ public Q_SLOTS: }; // end Polyhedron_demo_polyhedron_stitching_plugin -template -struct Polyline_visitor -{ - Scene_polylines_item* new_item; - typename boost::property_map::const_type vpm; - - Polyline_visitor(const Poly& poly, Scene_polylines_item* new_item) - : new_item(new_item), vpm(get(CGAL::vertex_point,poly)) - {} - - void start_new_polyline() - { - new_item->polylines.push_back( Scene_polylines_item::Polyline() ); - } - - void add_node(typename boost::graph_traits::vertex_descriptor vd) - { - - new_item->polylines.back().push_back(get(vpm,vd)); - } - - void end_polyline(){} -}; - template void Polyhedron_demo_polyhedron_stitching_plugin::on_actionDetectBorders_triggered(Scene_interface::Item_id index) @@ -127,18 +84,16 @@ void Polyhedron_demo_polyhedron_stitching_plugin::on_actionDetectBorders_trigger FaceGraph* pMesh = item->polyhedron(); normalize_border(*pMesh); + for(auto ed : edges(*pMesh)) + { + if(pMesh->is_border(ed)) + { + new_item->polylines.push_back(Scene_polylines_item::Polyline()); + new_item->polylines.back().push_back(pMesh->point(pMesh->source(pMesh->halfedge(ed)))); + new_item->polylines.back().push_back(pMesh->point(pMesh->target(pMesh->halfedge(ed)))); + } + } - - typedef boost::filtered_graph, Is_border > BorderGraph; - - Is_border ib(*pMesh); - BorderGraph bg(*pMesh,ib,ib); - Polyline_visitor polyline_visitor(*pMesh, new_item); - CGAL::split_graph_into_polylines( bg, - polyline_visitor, - CGAL::internal::IsTerminalDefault() ); - - if (new_item->polylines.empty()) { delete new_item; diff --git a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp index 4b80cdaee92..09dd204eff6 100644 --- a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp @@ -260,6 +260,7 @@ struct Scene_surface_mesh_item_priv{ double volume, area; unsigned int number_of_null_length_edges; unsigned int number_of_degenerated_faces; + bool has_nm_vertices; int genus; bool self_intersect; mutable QSlider* alphaSlider; @@ -1515,6 +1516,7 @@ invalidate_stats() { number_of_degenerated_faces = (unsigned int)(-1); number_of_null_length_edges = (unsigned int)(-1); + has_nm_vertices = false; volume = -std::numeric_limits::infinity(); area = -std::numeric_limits::infinity(); self_intersect = false; @@ -1568,11 +1570,30 @@ QString Scene_surface_mesh_item::computeStats(int type) } faces_aspect_ratio(d->smesh_, min_altitude, min_ar, max_ar, mean_ar); } + if(type == HAS_NM_VERTICES) + { + d->has_nm_vertices = false; + typedef boost::function_output_iterator OutputIterator; + try{ + CGAL::Polygon_mesh_processing::non_manifold_vertices(*d->smesh_, OutputIterator()); + } + catch( CGAL::internal::Throw_at_output::Throw_at_output_exception& ) + { + d->has_nm_vertices = true; + } + + } switch(type) { case NB_VERTICES: return QString::number(num_vertices(*d->smesh_)); + case HAS_NM_VERTICES: + { + if(d->has_nm_vertices) + return QString("Yes"); + return QString("No"); + } case NB_FACETS: return QString::number(num_faces(*d->smesh_)); @@ -1721,14 +1742,15 @@ CGAL::Three::Scene_item::Header_data Scene_surface_mesh_item::header() const CGAL::Three::Scene_item::Header_data data; //categories - data.categories.append(std::pair(QString("Properties"),9)); + data.categories.append(std::pair(QString("Properties"),11)); data.categories.append(std::pair(QString("Faces"),10)); - data.categories.append(std::pair(QString("Edges"),7)); - data.categories.append(std::pair(QString("Angles"),2)); + data.categories.append(std::pair(QString("Edges"),6)); + data.categories.append(std::pair(QString("Angles"),3)); //titles data.titles.append(QString("#Vertices")); + data.titles.append(QString("Has Non-manifold Vertices")); data.titles.append(QString("#Connected Components")); data.titles.append(QString("#Border Edges")); data.titles.append(QString("Pure Triangle")); diff --git a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.h b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.h index 0306acce865..ddd39a9f616 100644 --- a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.h @@ -106,6 +106,7 @@ public: //statistics enum STATS { NB_VERTICES = 0, + HAS_NM_VERTICES, NB_CONNECTED_COMPOS, NB_BORDER_EDGES, IS_PURE_TRIANGLE, diff --git a/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h b/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h index 63e3eeb4a63..daf7f836b56 100644 --- a/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h +++ b/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h @@ -1758,6 +1758,8 @@ public: /// With `check_all_incident_halfedges == false` the function returns `true`, if the incident /// halfedge associated to vertex `v` is a border halfedge, or if the vertex is isolated. /// \cgalAdvancedEnd + /// \attention If the data contained in the `Surface_mesh` is not a 2-manifold, then + /// this operation is not guaranteed to return the right result. bool is_border(Vertex_index v, bool check_all_incident_halfedges = true) const { Halfedge_index h(halfedge(v));