Merge pull request #4203 from maxGimeno/Demo-Fix_detect_boundaries-GF

Polyhedron Demo: Fix  stitching plugin
This commit is contained in:
Laurent Rineau 2019-10-15 16:34:14 +02:00
commit 8d7932cdc2
5 changed files with 68 additions and 74 deletions

View File

@ -2,6 +2,7 @@
#include "Scene_polygon_soup_item.h" #include "Scene_polygon_soup_item.h"
#include "Scene_points_with_normal_item.h" #include "Scene_points_with_normal_item.h"
#include <CGAL/Three/Three.h> #include <CGAL/Three/Three.h>
#include <CGAL/Polygon_mesh_processing/repair.h>
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h> #include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
@ -25,17 +26,17 @@ class Polyhedron_demo_off_plugin :
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90" FILE "off_io_plugin.json") Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90" FILE "off_io_plugin.json")
public: public:
bool isDefaultLoader(const Scene_item *item) const bool isDefaultLoader(const Scene_item *item) const
{ {
if(qobject_cast<const Scene_surface_mesh_item*>(item) if(qobject_cast<const Scene_surface_mesh_item*>(item)
|| qobject_cast<const Scene_polygon_soup_item*>(item)) || qobject_cast<const Scene_polygon_soup_item*>(item))
return true; return true;
return false; return false;
} }
bool isDefaultLoader(const QString& name) const bool isDefaultLoader(const QString& name) const
{ {
if(name == QString("off")) if(name == QString("off"))
return true; return true;
return false; return false;
} }
QString name() const { return "off_plugin"; } QString name() const { return "off_plugin"; }
@ -44,7 +45,7 @@ public:
QList<Scene_item*> load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true); QList<Scene_item*> load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true);
CGAL::Three::Scene_item* load_off(QFileInfo fileinfo); CGAL::Three::Scene_item* load_off(QFileInfo fileinfo);
CGAL::Three::Scene_item* load_obj(QFileInfo fileinfo); CGAL::Three::Scene_item* load_obj(QFileInfo fileinfo);
bool canSave(const CGAL::Three::Scene_item*); bool canSave(const CGAL::Three::Scene_item*);
bool save(QFileInfo fileinfo,QList<CGAL::Three::Scene_item*>& ); bool save(QFileInfo fileinfo,QList<CGAL::Three::Scene_item*>& );
}; };
@ -55,7 +56,7 @@ bool Polyhedron_demo_off_plugin::canLoad(QFileInfo) const {
QList<Scene_item*> Polyhedron_demo_off_plugin:: QList<Scene_item*> Polyhedron_demo_off_plugin::
load(QFileInfo fileinfo, bool& ok, bool add_to_scene) { load(QFileInfo fileinfo, bool& ok, bool add_to_scene) {
if(fileinfo.size() == 0) if(fileinfo.size() == 0)
{ {
CGAL::Three::Three::warning( tr("The file you are trying to load is empty.")); 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; std::cerr << "Error! Cannot open file " << (const char*)fileinfo.filePath().toUtf8() << std::endl;
return NULL; return NULL;
} }
CGAL::File_scanner_OFF scanner( in, false); CGAL::File_scanner_OFF scanner( in, false);
// Try to read .off in a point set // Try to read .off in a point set
if (scanner.size_of_facets() == 0) if (scanner.size_of_facets() == 0)
{ {
@ -124,10 +125,10 @@ Polyhedron_demo_off_plugin::load_off(QFileInfo fileinfo) {
delete item; delete item;
return 0; return 0;
} }
return item; return item;
} }
in.seekg(0); in.seekg(0);
// Try to read .off in a surface_mesh // Try to read .off in a surface_mesh
SMesh *surface_mesh = new SMesh(); SMesh *surface_mesh = new SMesh();
@ -181,6 +182,19 @@ Polyhedron_demo_off_plugin::load_off(QFileInfo fileinfo) {
tr("%1 isolated vertices found") tr("%1 isolated vertices found")
.arg(item->getNbIsolatedvertices())); .arg(item->getNbIsolatedvertices()));
} }
typedef boost::function_output_iterator<CGAL::internal::Throw_at_output> 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()) if(item->isItemMulticolor())
item->computeItemColorVectorAutomatically(true); item->computeItemColorVectorAutomatically(true);
return item; return item;
@ -218,9 +232,9 @@ save(QFileInfo fileinfo,QList<CGAL::Three::Scene_item*>& items)
// This plugin supports point sets, surface_meshes and polygon soups // This plugin supports point sets, surface_meshes and polygon soups
const Scene_points_with_normal_item* points_item = const Scene_points_with_normal_item* points_item =
qobject_cast<const Scene_points_with_normal_item*>(item); qobject_cast<const Scene_points_with_normal_item*>(item);
const Scene_surface_mesh_item* sm_item = const Scene_surface_mesh_item* sm_item =
qobject_cast<const Scene_surface_mesh_item*>(item); qobject_cast<const Scene_surface_mesh_item*>(item);
const Scene_polygon_soup_item* soup_item = const Scene_polygon_soup_item* soup_item =
qobject_cast<const Scene_polygon_soup_item*>(item); qobject_cast<const Scene_polygon_soup_item*>(item);
if(!sm_item && !soup_item && !points_item) if(!sm_item && !soup_item && !points_item)

View File

@ -14,25 +14,6 @@
#include <CGAL/boost/graph/helpers.h> #include <CGAL/boost/graph/helpers.h>
#include <boost/graph/filtered_graph.hpp> #include <boost/graph/filtered_graph.hpp>
template <typename G>
struct Is_border {
const G& g;
Is_border(const G& g)
: g(g)
{}
template <typename Descriptor>
bool operator()(const Descriptor& d) const {
return is_border(d,g);
}
bool operator()(typename boost::graph_traits<G>::vertex_descriptor d) const {
return is_border(d,g) != boost::none;
}
};
using namespace CGAL::Three; using namespace CGAL::Three;
class Polyhedron_demo_polyhedron_stitching_plugin : class Polyhedron_demo_polyhedron_stitching_plugin :
public QObject, public QObject,
@ -90,30 +71,6 @@ public Q_SLOTS:
}; // end Polyhedron_demo_polyhedron_stitching_plugin }; // end Polyhedron_demo_polyhedron_stitching_plugin
template <typename Poly>
struct Polyline_visitor
{
Scene_polylines_item* new_item;
typename boost::property_map<Poly, CGAL::vertex_point_t>::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<Poly>::vertex_descriptor vd)
{
new_item->polylines.back().push_back(get(vpm,vd));
}
void end_polyline(){}
};
template <typename Item> template <typename Item>
void Polyhedron_demo_polyhedron_stitching_plugin::on_actionDetectBorders_triggered(Scene_interface::Item_id index) 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(); FaceGraph* pMesh = item->polyhedron();
normalize_border(*pMesh); 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<FaceGraph,Is_border<FaceGraph>, Is_border<FaceGraph> > BorderGraph;
Is_border<FaceGraph> ib(*pMesh);
BorderGraph bg(*pMesh,ib,ib);
Polyline_visitor<FaceGraph> polyline_visitor(*pMesh, new_item);
CGAL::split_graph_into_polylines( bg,
polyline_visitor,
CGAL::internal::IsTerminalDefault() );
if (new_item->polylines.empty()) if (new_item->polylines.empty())
{ {
delete new_item; delete new_item;

View File

@ -260,6 +260,7 @@ struct Scene_surface_mesh_item_priv{
double volume, area; double volume, area;
unsigned int number_of_null_length_edges; unsigned int number_of_null_length_edges;
unsigned int number_of_degenerated_faces; unsigned int number_of_degenerated_faces;
bool has_nm_vertices;
int genus; int genus;
bool self_intersect; bool self_intersect;
mutable QSlider* alphaSlider; mutable QSlider* alphaSlider;
@ -1515,6 +1516,7 @@ invalidate_stats()
{ {
number_of_degenerated_faces = (unsigned int)(-1); number_of_degenerated_faces = (unsigned int)(-1);
number_of_null_length_edges = (unsigned int)(-1); number_of_null_length_edges = (unsigned int)(-1);
has_nm_vertices = false;
volume = -std::numeric_limits<double>::infinity(); volume = -std::numeric_limits<double>::infinity();
area = -std::numeric_limits<double>::infinity(); area = -std::numeric_limits<double>::infinity();
self_intersect = false; 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); 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<CGAL::internal::Throw_at_output> 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) switch(type)
{ {
case NB_VERTICES: case NB_VERTICES:
return QString::number(num_vertices(*d->smesh_)); 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: case NB_FACETS:
return QString::number(num_faces(*d->smesh_)); 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; CGAL::Three::Scene_item::Header_data data;
//categories //categories
data.categories.append(std::pair<QString,int>(QString("Properties"),9)); data.categories.append(std::pair<QString,int>(QString("Properties"),11));
data.categories.append(std::pair<QString,int>(QString("Faces"),10)); data.categories.append(std::pair<QString,int>(QString("Faces"),10));
data.categories.append(std::pair<QString,int>(QString("Edges"),7)); data.categories.append(std::pair<QString,int>(QString("Edges"),6));
data.categories.append(std::pair<QString,int>(QString("Angles"),2)); data.categories.append(std::pair<QString,int>(QString("Angles"),3));
//titles //titles
data.titles.append(QString("#Vertices")); data.titles.append(QString("#Vertices"));
data.titles.append(QString("Has Non-manifold Vertices"));
data.titles.append(QString("#Connected Components")); data.titles.append(QString("#Connected Components"));
data.titles.append(QString("#Border Edges")); data.titles.append(QString("#Border Edges"));
data.titles.append(QString("Pure Triangle")); data.titles.append(QString("Pure Triangle"));

View File

@ -106,6 +106,7 @@ public:
//statistics //statistics
enum STATS { enum STATS {
NB_VERTICES = 0, NB_VERTICES = 0,
HAS_NM_VERTICES,
NB_CONNECTED_COMPOS, NB_CONNECTED_COMPOS,
NB_BORDER_EDGES, NB_BORDER_EDGES,
IS_PURE_TRIANGLE, IS_PURE_TRIANGLE,

View File

@ -1758,6 +1758,8 @@ public:
/// With `check_all_incident_halfedges == false` the function returns `true`, if the incident /// 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. /// halfedge associated to vertex `v` is a border halfedge, or if the vertex is isolated.
/// \cgalAdvancedEnd /// \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 bool is_border(Vertex_index v, bool check_all_incident_halfedges = true) const
{ {
Halfedge_index h(halfedge(v)); Halfedge_index h(halfedge(v));