Add stats to the selection_item

This commit is contained in:
Maxime Gimeno 2019-03-04 17:21:51 +01:00
parent bd2b055f1e
commit bd8b39d162
5 changed files with 428 additions and 17 deletions

View File

@ -2435,7 +2435,10 @@ QString MainWindow::get_item_stats()
QList<QString> classnames;
Q_FOREACH(int id, scene->selectionIndices())
{
QString classname = scene->item(id)->metaObject()->className();
Scene_item* item = scene->item(id);
QString classname = item->property("classname").toString();
if(classname.isEmpty())
classname = item->metaObject()->className();
if(!classnames.contains(classname))
classnames << classname;
}
@ -2446,12 +2449,18 @@ QString MainWindow::get_item_stats()
{
Scene_item* s_item = scene->item(id);
for(int i=0; i<items.size(); i++)
if(classnames.at(i).contains(s_item->metaObject()->className()))
{
Scene_item* item = scene->item(id);
QString classname = item->property("classname").toString();
if(classname.isEmpty())
classname = item->metaObject()->className();
if(classnames.at(i).contains(classname))
{
items[i] << s_item;
break;
}
}
}
//last step :: making tables for each type of item
QString str;
for(int i=0; i< classnames.size(); i++)

View File

@ -8,6 +8,7 @@
#include <CGAL/property_map.h>
#include <CGAL/Handle_hash_function.h>
#include <CGAL/Unique_hash_map.h>
#include <CGAL/statistics_helpers.h>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
@ -21,6 +22,9 @@
#include <vector>
#include "triangulate_primitive.h"
#include <CGAL/boost/graph/Face_filtered_graph.h>
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <CGAL/boost/graph/properties.h>
typedef Scene_surface_mesh_item Scene_face_graph_item;
@ -50,7 +54,8 @@ struct Scene_polyhedron_selection_item_priv{
Scene_polyhedron_selection_item_priv(Scene_polyhedron_selection_item* parent):
item(parent)
{
filtered_graph = nullptr;
item->setProperty("classname", QString("surface_mesh"));
}
void initializeBuffers(CGAL::Three::Viewer_interface *viewer) const;
@ -162,6 +167,7 @@ struct Scene_polyhedron_selection_item_priv{
mutable QOpenGLShaderProgram *program;
mutable bool are_HL_buffers_filled;
Scene_polyhedron_selection_item* item;
CGAL::Face_filtered_graph<SMesh> *filtered_graph;
};
@ -1970,6 +1976,11 @@ void Scene_polyhedron_selection_item::invalidateOpenGLBuffers() {
d->are_temp_buffers_filled = false;
d->poly = polyhedron();
compute_bbox();
if(d->filtered_graph)
{
delete d->filtered_graph;
d->filtered_graph = nullptr;
}
}
void Scene_polyhedron_selection_item::add_to_selection()
@ -2317,3 +2328,287 @@ Scene_polyhedron_selection_item::toolTip() const
.arg(this->renderingModeName())
.arg(this->color().name());
}
QString Scene_polyhedron_selection_item::computeStats(int type)
{
if(!d->filtered_graph)
{
d->filtered_graph = new CGAL::Face_filtered_graph<SMesh>(*d->poly, selected_facets);
}
double minl, maxl, meanl, midl;
unsigned int number_of_null_length_edges;
switch (type)
{
case MIN_LENGTH:
case MAX_LENGTH:
case MID_LENGTH:
case MEAN_LENGTH:
case NB_NULL_LENGTH:
if(selected_edges.size() == 0)
return QString("n/a");
else
edges_length(d->poly, selected_edges, minl, maxl, meanl, midl, number_of_null_length_edges);
}
double mini, maxi, ave;
switch (type)
{
case MIN_ANGLE:
case MAX_ANGLE:
case MEAN_ANGLE:
if(selected_facets.size() == 0)
return QString("n/a");
else
angles(d->poly, selected_facets, mini, maxi, ave);
}
double min_area, max_area, med_area, mean_area;
switch (type)
{
case MIN_AREA:
case MAX_AREA:
case MEAN_AREA:
case MED_AREA:
if(selected_facets.size() == 0)
return QString("n/a");
else{
if(!is_triangle_mesh(*d->poly))
{
return QString("n/a");
}
faces_area(d->poly, selected_facets, min_area, max_area, mean_area, med_area);
}
}
double min_altitude, min_ar, max_ar, mean_ar;
switch (type)
{
case MIN_ALTITUDE:
case MIN_ASPECT_RATIO:
case MAX_ASPECT_RATIO:
case MEAN_ASPECT_RATIO:
if(selected_facets.size() == 0)
return QString("n/a");
else
{
if(!is_triangle_mesh(*d->poly))
{
return QString("n/a");
}
faces_aspect_ratio(d->poly, selected_facets,min_altitude, min_ar, max_ar, mean_ar);
}
}
switch(type)
{
case NB_VERTICES:
{
std::set<fg_vertex_descriptor> total_vertices;
for(auto v : selected_vertices)
{
total_vertices.insert(v);
}
for(auto e : selected_edges)
{
total_vertices.insert(target(e, *d->poly));
total_vertices.insert(source(e, *d->poly));
}
for(auto f : selected_facets)
{
for (auto v : CGAL::vertices_around_face(halfedge(f, *d->poly), *d->poly))
{
total_vertices.insert(v);
}
}
return QString::number(total_vertices.size());
}
case NB_FACETS:
return QString::number(selected_facets.size());
case NB_CONNECTED_COMPOS:
{
// Extract the part n°0 of the partition into a new, independent mesh
if(selected_facets.size() == 0)
return QString("n/a");
boost::vector_property_map<int,
boost::property_map<SMesh, boost::face_index_t>::type>
fccmap(get(boost::face_index, *d->filtered_graph));
return QString::number(CGAL::Polygon_mesh_processing::connected_components(*d->filtered_graph, fccmap));
}
case NB_BORDER_EDGES:
{
int i=0;
BOOST_FOREACH(halfedge_descriptor hd, halfedges(*d->poly))
{
if(is_border(hd, *d->poly)
&& selected_edges.find(edge(hd, *d->poly)) != selected_edges.end())
++i;
}
return QString::number(i);
}
case NB_EDGES:{
std::set<fg_edge_descriptor> total_edges;
for(auto e : selected_edges)
{
total_edges.insert(e);
}
for(auto f : selected_facets)
{
for (auto e : CGAL::edges_around_face(halfedge(f, *d->poly), *d->poly))
{
total_edges.insert(e);
}
}
return QString::number(total_edges.size());
}
case VOLUME:
return QString("n/a");
break;
case GENUS:
return QString("n/a");
break;
case NB_DEGENERATED_FACES:
{
if(is_triangle_mesh(*d->poly))
{
if(selected_facets.size() == 0)
return QString("n/a");
return QString::number(nb_degenerate_faces(d->filtered_graph));
}
else
return QString("n/a");
}
case AREA:
{
if(is_triangle_mesh(*d->poly))
{
if(selected_facets.size() == 0)
return QString("n/a");
return QString::number(CGAL::Polygon_mesh_processing::area(*d->filtered_graph));
}
else
return QString("n/a");
}
case SELFINTER:
{
if(selected_facets.size() == 0)
return QString("n/a");
if(is_triangle_mesh(*d->poly)){
bool self_intersect
= CGAL::Polygon_mesh_processing::does_self_intersect(*(d->poly));
if (self_intersect)
return QString("Yes");
else
return QString("No");
}
return QString("n/a");
}
case MIN_LENGTH:
return QString::number(minl);
case MAX_LENGTH:
return QString::number(maxl);
case MID_LENGTH:
return QString::number(midl);
case MEAN_LENGTH:
return QString::number(meanl);
case NB_NULL_LENGTH:
return QString::number(number_of_null_length_edges);
case MIN_ANGLE:
return QString::number(mini);
case MAX_ANGLE:
return QString::number(maxi);
case MEAN_ANGLE:
return QString::number(ave);
case HOLES:
{
return QString("n/a");
}
case MIN_AREA:
return QString::number(min_area);
case MAX_AREA:
return QString::number(max_area);
case MED_AREA:
return QString::number(med_area);
case MEAN_AREA:
return QString::number(mean_area);
case MIN_ALTITUDE:
return QString::number(min_altitude);
case MIN_ASPECT_RATIO:
return QString::number(min_ar);
case MAX_ASPECT_RATIO:
return QString::number(max_ar);
case MEAN_ASPECT_RATIO:
return QString::number(mean_ar);
case IS_PURE_TRIANGLE:
if(selected_facets.size() == 0)
return QString("n/a");
else
{
if(is_triangle_mesh(*d->poly))
return QString("yes");
else
return QString("no");
}
case IS_PURE_QUAD:
{
if(selected_facets.size() == 0)
return QString("n/a");
if (is_quad_mesh(*d->filtered_graph))
return QString("yes");
else
return QString("no");
}
}//end switch
return QString();
}
CGAL::Three::Scene_item::Header_data Scene_polyhedron_selection_item::header() const
{
CGAL::Three::Scene_item::Header_data data;
//categories
data.categories.append(std::pair<QString,int>(QString("Properties"),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("Angles"),2));
//titles
data.titles.append(QString("#Vertices"));
data.titles.append(QString("#Connected Components"));
data.titles.append(QString("#Border Edges"));
data.titles.append(QString("Pure Triangle"));
data.titles.append(QString("Pure Quad"));
data.titles.append(QString("#Degenerate Faces"));
data.titles.append(QString("Connected Components of the Boundary"));
data.titles.append(QString("Area"));
data.titles.append(QString("Volume"));
data.titles.append(QString("Self-Intersecting"));
data.titles.append(QString("#Faces"));
data.titles.append(QString("Min Area"));
data.titles.append(QString("Max Area"));
data.titles.append(QString("Median Area"));
data.titles.append(QString("Mean Area"));
data.titles.append(QString("Min Altitude"));
data.titles.append(QString("Min Aspect-Ratio"));
data.titles.append(QString("Max Aspect-Ratio"));
data.titles.append(QString("Mean Aspect-Ratio"));
data.titles.append(QString("Genus"));
data.titles.append(QString("#Edges"));
data.titles.append(QString("Minimum Length"));
data.titles.append(QString("Maximum Length"));
data.titles.append(QString("Median Length"));
data.titles.append(QString("Mean Length"));
data.titles.append(QString("#Degenerate Edges"));
data.titles.append(QString("Minimum"));
data.titles.append(QString("Maximum"));
data.titles.append(QString("Average"));
return data;
}

View File

@ -996,6 +996,44 @@ public:
protected :
friend struct Scene_polyhedron_selection_item_priv;
Scene_polyhedron_selection_item_priv *d;
public:
//statistics
enum STATS {
NB_VERTICES = 0,
NB_CONNECTED_COMPOS,
NB_BORDER_EDGES,
IS_PURE_TRIANGLE,
IS_PURE_QUAD,
NB_DEGENERATED_FACES,
HOLES,
AREA,
VOLUME,
SELFINTER,
NB_FACETS,
MIN_AREA,
MAX_AREA,
MED_AREA,
MEAN_AREA,
MIN_ALTITUDE,
MIN_ASPECT_RATIO,
MAX_ASPECT_RATIO,
MEAN_ASPECT_RATIO,
GENUS,
NB_EDGES,
MIN_LENGTH,
MAX_LENGTH,
MID_LENGTH,
MEAN_LENGTH,
NB_NULL_LENGTH,
MIN_ANGLE,
MAX_ANGLE,
MEAN_ANGLE
};
bool has_stats()const Q_DECL_OVERRIDE{return true;}
QString computeStats(int type)Q_DECL_OVERRIDE;
CGAL::Three::Scene_item::Header_data header() const Q_DECL_OVERRIDE;
};
#endif

View File

@ -125,6 +125,7 @@ struct Scene_surface_mesh_item_priv{
alphaSlider = NULL;
has_vcolors = false;
has_fcolors = false;
item->setProperty("classname", QString("surface_mesh"));
}
Scene_surface_mesh_item_priv(SMesh* sm, Scene_surface_mesh_item *parent):
@ -151,6 +152,7 @@ struct Scene_surface_mesh_item_priv{
alphaSlider = NULL;
has_vcolors = false;
has_fcolors = false;
item->setProperty("classname", QString("surface_mesh"));
}
~Scene_surface_mesh_item_priv()

View File

@ -18,11 +18,35 @@
#include <map>
#include <vector>
template<typename Mesh>
void angles(Mesh* poly, double& mini, double& maxi, double& ave)
template<typename Set>
struct Angles_test_with_set
{
const Set& set;
typedef typename Set::value_type value_type;
Angles_test_with_set(const Set& set):set(set) {}
bool operator()(const value_type& f)
{
return (set.find(f) == set.end());
}
};
struct Angles_test
{
Angles_test() {}
template<typename T>
bool operator()(const T&)
{
return false;
}
};
template<typename Mesh, typename Tester>
void compute_angles(Mesh* poly,Tester tester , double& mini, double& maxi, double& ave)
{
using namespace boost::accumulators;
typedef typename boost::graph_traits<Mesh>::halfedge_descriptor halfedge_descriptor;
typedef typename boost::graph_traits<Mesh>::face_descriptor face_descriptor;
typedef typename boost::property_map<Mesh, CGAL::vertex_point_t>::type VPMap;
typedef typename CGAL::Kernel_traits< typename boost::property_traits<VPMap>::value_type >::Kernel Traits;
double rad_to_deg = 180. / CGAL_PI;
@ -33,7 +57,9 @@ void angles(Mesh* poly, double& mini, double& maxi, double& ave)
VPMap vpmap = get(CGAL::vertex_point, *poly);
BOOST_FOREACH(halfedge_descriptor h, halfedges(*poly))
{
if (face(h, *poly) == boost::graph_traits<Mesh>::null_face())
face_descriptor f = face(h, *poly);
if (f == boost::graph_traits<Mesh>::null_face()
|| tester(f))
continue;
typename Traits::Point_3 a = get(vpmap, source(h, *poly));
@ -54,7 +80,22 @@ void angles(Mesh* poly, double& mini, double& maxi, double& ave)
}
template<typename Mesh>
void edges_length(Mesh* poly,
void angles(Mesh* poly, double& mini, double& maxi, double& ave)
{
compute_angles(poly, Angles_test(), mini, maxi, ave);
}
template<typename Mesh, typename Face_set>
void angles(Mesh* poly, const Face_set& faces, double& mini, double& maxi, double& ave)
{
Angles_test_with_set<Face_set> tester(faces);
compute_angles(poly, tester, mini, maxi, ave);
}
template<typename Mesh, typename Edge_range>
void edges_length(Mesh* poly, const Edge_range& range,
double& mini, double& maxi, double& mean, double& mid,
unsigned int& nb_degen)
{
@ -69,7 +110,7 @@ void edges_length(Mesh* poly,
VPMap vpmap = get(CGAL::vertex_point, *poly);
nb_degen = 0;
BOOST_FOREACH(edge_descriptor e, edges(*poly))
BOOST_FOREACH(edge_descriptor e, range)
{
halfedge_descriptor h = halfedge(e, *poly);
Point a = get(vpmap, source(h, *poly));
@ -85,6 +126,13 @@ void edges_length(Mesh* poly,
mid = extract_result< tag::median >(acc);
}
template<typename Mesh>
void edges_length(Mesh* poly,
double& mini, double& maxi, double& mean, double& mid,
unsigned int& nb_degen)
{
edges_length(poly, edges(*poly), mini, maxi, mean, mid, nb_degen);
}
template<typename Mesh>
unsigned int nb_degenerate_faces(Mesh* poly)
{
@ -96,11 +144,9 @@ unsigned int nb_degenerate_faces(Mesh* poly)
return static_cast<unsigned int>(degenerate_faces.size());
}
template<typename Mesh>
unsigned int nb_holes(Mesh* poly)
template<typename Mesh, typename IDMap>
unsigned int nb_holes(Mesh* poly, IDMap idmap)
{
typedef typename boost::property_map<Mesh, boost::halfedge_index_t>::type IDMap;
IDMap idmap = get(boost::halfedge_index, *poly);
//gets the number of holes
//if is_closed is false, then there are borders (= holes)
@ -138,9 +184,15 @@ unsigned int nb_holes(Mesh* poly)
//}
return n;
}
template<typename Mesh>
void faces_area(Mesh* poly,
unsigned int nb_holes(Mesh* poly)
{
typedef typename boost::property_map<Mesh, boost::halfedge_index_t>::type IDMap;
IDMap idmap = get(boost::halfedge_index, *poly);
return nb_holes(poly, idmap);
}
template<typename Mesh, typename Face_range>
void faces_area(Mesh* poly, const Face_range& range,
double& mini, double& maxi, double& mean, double& mid)
{
using namespace boost::accumulators;
@ -153,7 +205,7 @@ void faces_area(Mesh* poly,
features< tag::min, tag::max, tag::mean , tag::median> > acc;
VPMap vpmap = get(CGAL::vertex_point, *poly);
BOOST_FOREACH(face_descriptor f, faces(*poly))
BOOST_FOREACH(face_descriptor f, range)
{
halfedge_descriptor h = halfedge(f, *poly);
Point a = get(vpmap, target(h, *poly));
@ -169,7 +221,14 @@ void faces_area(Mesh* poly,
}
template<typename Mesh>
void faces_aspect_ratio(Mesh* poly,
void faces_area(Mesh* poly,
double& mini, double& maxi, double& mean, double& mid)
{
faces_area(poly, faces(*poly), mini, maxi, mean, mid);
}
template<typename Mesh, typename Face_range>
void faces_aspect_ratio(Mesh* poly, const Face_range& range,
double& min_altitude, double& mini, double& maxi, double& mean)
{
using namespace boost::accumulators;
@ -185,7 +244,7 @@ void faces_aspect_ratio(Mesh* poly,
min_altitude = std::numeric_limits<double>::infinity();
typename boost::property_map<Mesh, CGAL::vertex_point_t>::type
vpmap = get(CGAL::vertex_point, *poly);
BOOST_FOREACH(face_descriptor f, faces(*poly))
BOOST_FOREACH(face_descriptor f, range)
{
halfedge_descriptor h = halfedge(f, *poly);
typename Traits::Point_3 points[3];
@ -212,5 +271,13 @@ void faces_aspect_ratio(Mesh* poly,
maxi = extract_result< tag::max >(acc);
mean = extract_result< tag::mean >(acc);
}
template<typename Mesh>
void faces_aspect_ratio(Mesh* poly,
double& min_altitude, double& mini, double& maxi, double& mean)
{
faces_aspect_ratio(poly, faces(*poly), min_altitude, mini, maxi, mean);
}
#endif // POLYHEDRON_DEMO_STATISTICS_HELPERS_H