From bd8b39d1628fdc4d01345de92b721228c2bb749f Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 4 Mar 2019 17:21:51 +0100 Subject: [PATCH 1/3] Add stats to the selection_item --- Polyhedron/demo/Polyhedron/MainWindow.cpp | 13 +- .../Scene_polyhedron_selection_item.cpp | 297 +++++++++++++++++- .../Scene_polyhedron_selection_item.h | 38 +++ .../Polyhedron/Scene_surface_mesh_item.cpp | 2 + .../include/CGAL/statistics_helpers.h | 95 +++++- 5 files changed, 428 insertions(+), 17 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index ee2414849d6..358d6a1ac93 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -2435,7 +2435,10 @@ QString MainWindow::get_item_stats() QList 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,11 +2449,17 @@ QString MainWindow::get_item_stats() { Scene_item* s_item = scene->item(id); for(int i=0; imetaObject()->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; diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp index 0216c02db64..b0b4de4f500 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -21,6 +22,9 @@ #include #include "triangulate_primitive.h" +#include +#include +#include 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 *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(*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 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::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 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("Properties"),10)); + data.categories.append(std::pair(QString("Faces"),10)); + data.categories.append(std::pair(QString("Edges"),7)); + data.categories.append(std::pair(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; +} diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index bafac0bc5d1..e42a92ae669 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -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 diff --git a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp index 3043d169ddd..39d1cdb9c31 100644 --- a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp @@ -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() diff --git a/Polyhedron/demo/Polyhedron/include/CGAL/statistics_helpers.h b/Polyhedron/demo/Polyhedron/include/CGAL/statistics_helpers.h index d0449e819b5..4fa11428707 100644 --- a/Polyhedron/demo/Polyhedron/include/CGAL/statistics_helpers.h +++ b/Polyhedron/demo/Polyhedron/include/CGAL/statistics_helpers.h @@ -18,11 +18,35 @@ #include #include -template -void angles(Mesh* poly, double& mini, double& maxi, double& ave) +template +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 + bool operator()(const T&) + { + return false; + } +}; + +template +void compute_angles(Mesh* poly,Tester tester , double& mini, double& maxi, double& ave) { using namespace boost::accumulators; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename boost::property_map::type VPMap; typedef typename CGAL::Kernel_traits< typename boost::property_traits::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::null_face()) + face_descriptor f = face(h, *poly); + if (f == boost::graph_traits::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 -void edges_length(Mesh* poly, +void angles(Mesh* poly, double& mini, double& maxi, double& ave) +{ + compute_angles(poly, Angles_test(), mini, maxi, ave); +} + +template +void angles(Mesh* poly, const Face_set& faces, double& mini, double& maxi, double& ave) +{ + Angles_test_with_set tester(faces); + compute_angles(poly, tester, mini, maxi, ave); +} + + + +template +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 +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 unsigned int nb_degenerate_faces(Mesh* poly) { @@ -96,11 +144,9 @@ unsigned int nb_degenerate_faces(Mesh* poly) return static_cast(degenerate_faces.size()); } -template -unsigned int nb_holes(Mesh* poly) +template +unsigned int nb_holes(Mesh* poly, IDMap idmap) { - typedef typename boost::property_map::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 -void faces_area(Mesh* poly, +unsigned int nb_holes(Mesh* poly) +{ + typedef typename boost::property_map::type IDMap; + IDMap idmap = get(boost::halfedge_index, *poly); + return nb_holes(poly, idmap); +} +template +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 -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 +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::infinity(); typename boost::property_map::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 +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 From 8d6c35f1b5778368c7d7b08dff059a2e45c9f098 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 6 Mar 2019 15:53:06 +0100 Subject: [PATCH 2/3] Fix warning --- .../demo/Polyhedron/Scene_polyhedron_selection_item.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index e42a92ae669..e4eaa3b00c5 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -1031,9 +1031,9 @@ public: 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; + bool has_stats()const {return true;} + QString computeStats(int type); + CGAL::Three::Scene_item::Header_data header() const ; }; #endif From d7baf67a434c7743569da3b1735a885c980d7c5e Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 7 Mar 2019 12:54:12 +0100 Subject: [PATCH 3/3] Add initialization --- Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp index 39d1cdb9c31..a83fc03437d 100644 --- a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp @@ -1512,7 +1512,7 @@ QString Scene_surface_mesh_item::computeStats(int type) edges_length(d->smesh_, minl, maxl, meanl, midl, d->number_of_null_length_edges); } - double mini, maxi, ave; + double mini(0), maxi(0), ave(0); switch (type) { case MIN_ANGLE: