mirror of https://github.com/CGAL/cgal
Merge pull request #4203 from maxGimeno/Demo-Fix_detect_boundaries-GF
Polyhedron Demo: Fix stitching plugin
This commit is contained in:
commit
8d7932cdc2
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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"));
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue