From 97990e001f33f47c52c4a574d23a2afcd73f69da Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Wed, 15 Mar 2017 14:56:23 +0100 Subject: [PATCH] bglize hole_filling_plugin ; Does not yet work with Surface_mesh as there is also a selection --- .../Polyhedron/Plugins/PMP/CMakeLists.txt | 5 + .../Plugins/PMP/Hole_filling_plugin.cpp | 185 ++++++++++-------- 2 files changed, 113 insertions(+), 77 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt index 09376d7ecf7..94a0f409b6c 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt @@ -15,6 +15,11 @@ if(EIGEN3_FOUND) polyhedron_demo_plugin(hole_filling_plugin Hole_filling_plugin ${hole_fillingUI_FILES}) target_link_libraries(hole_filling_plugin scene_polyhedron_item scene_polylines_item scene_polyhedron_selection_item) + qt5_wrap_ui( hole_fillingUI_FILES Hole_filling_widget.ui) + polyhedron_demo_plugin(hole_filling_sm_plugin Hole_filling_plugin ${hole_fillingUI_FILES}) + target_link_libraries(hole_filling_sm_plugin scene_surface_mesh_item scene_polylines_item scene_polyhedron_selection_item) +target_compile_definitions(hole_filling_sm_plugin PUBLIC "-DUSE_SURFACE_MESH" ) + qt5_wrap_ui( fairingUI_FILES Fairing_widget.ui) polyhedron_demo_plugin(fairing_plugin Fairing_plugin ${fairingUI_FILES}) target_link_libraries(fairing_plugin scene_polyhedron_selection_item) diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Hole_filling_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Hole_filling_plugin.cpp index eba7256d482..512c33c8584 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Hole_filling_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Hole_filling_plugin.cpp @@ -4,6 +4,7 @@ #include "Messages_interface.h" #include "Scene_polyhedron_item.h" +#include "Scene_surface_mesh_item.h" #include "Scene_polylines_item.h" #include "Scene_polyhedron_selection_item.h" #include "Scene.h" @@ -35,11 +36,35 @@ #include #include "Kernel_type.h" +#include #include #include #include #include +#ifdef USE_SURFACE_MESH +typedef Scene_surface_mesh_item Scene_face_graph_item; + +void normalize_border(Scene_face_graph_item::FaceGraph&) +{} + +#else +typedef Scene_polyhedron_item Scene_face_graph_item; + +void normalize_border(Scene_face_graph_item::FaceGraph& polyhedron) +{ + polyhedron.normalize_border(); +} + +#endif + +typedef Scene_face_graph_item::FaceGraph Face_graph; + +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; +typedef boost::graph_traits::face_descriptor face_descriptor; +typedef Kernel::Point_3 Point_3; + // Class for visualizing holes in a polyhedron // provides mouse selection functionality class Q_DECL_EXPORT Scene_hole_visualizer : public CGAL::Three::Scene_item @@ -49,7 +74,7 @@ public: // structs struct Polyline_data { Scene_polylines_item* polyline; - Polyhedron::Halfedge_handle halfedge; + halfedge_descriptor halfedge; qglviewer::Vec position; }; struct Mouse_keyboard_state @@ -66,7 +91,7 @@ private: public: typedef std::set Selected_holes_set; - Scene_hole_visualizer(Scene_polyhedron_item* poly_item, QMainWindow* mainWindow) + Scene_hole_visualizer(Scene_face_graph_item* poly_item, QMainWindow* mainWindow) : poly_item(poly_item), block_poly_item_changed(false) { get_holes(); @@ -78,9 +103,11 @@ public: connect(poly_item, SIGNAL(item_is_about_to_be_changed()), this, SLOT(poly_item_changed())); } + ~Scene_hole_visualizer() { clear(); } + bool isFinite() const { return true; } bool isEmpty() const { return polyline_data_list.empty(); } void compute_bbox() const { @@ -91,6 +118,7 @@ public: } _bbox = bbox; } + Scene_hole_visualizer* clone() const { return 0; } @@ -175,8 +203,6 @@ public: private: // find holes in polyhedron and construct a internal polyline for each void get_holes() { - typedef Polyhedron::Halfedge_iterator Halfedge_iterator; - typedef Polyhedron::Halfedge_around_facet_circulator Halfedge_around_facet_circulator; // save selected hole positions to keep selected holes selected // we just use center position of holes for identification which might not work good for advanced cases... std::vector selected_hole_positions; @@ -185,31 +211,33 @@ private: } clear(); + + Face_graph& poly = *poly_item->polyhedron(); - Polyhedron& poly = *poly_item->polyhedron(); - for(Halfedge_iterator it = poly.halfedges_begin(); it != poly.halfedges_end(); ++it) - { it->id() = 0; } + boost::unordered_set visited; + boost::property_map::type vpm = get(CGAL::vertex_point,poly); - for(Halfedge_iterator it = poly.halfedges_begin(); it != poly.halfedges_end(); ++it){ - if(it->is_border() && it->id() == 0){ + BOOST_FOREACH(halfedge_descriptor hd, halfedges(poly)){ + if(hd->is_border() && visited.find(hd) == visited.end()){ polyline_data_list.push_back(Polyline_data()); Polyline_data& polyline_data = polyline_data_list.back(); polyline_data.polyline = new Scene_polylines_item(); polyline_data.polyline->polylines.push_back(Scene_polylines_item::Polyline()); - polyline_data.halfedge = it; + polyline_data.halfedge = hd; qglviewer::Vec center; int counter = 0; - Halfedge_around_facet_circulator hf_around_facet = it->facet_begin(); - do { - CGAL_assertion(hf_around_facet->id() == 0); - hf_around_facet->id() = 1; - const Polyhedron::Traits::Point_3& p = hf_around_facet->vertex()->point(); + halfedge_descriptor hf_around_facet; + BOOST_FOREACH(hf_around_facet, halfedges_around_face(hd,poly)){ + CGAL_assertion(visited.find(hf_around_facet) == visited.end()); + visited.insert(hf_around_facet); + const Point_3& p = get(vpm,target(hf_around_facet, poly)); polyline_data.polyline->polylines.front().push_back(p); center += qglviewer::Vec(p.x(), p.y(), p.z()); ++counter; - } while(++hf_around_facet != it->facet_begin()); - polyline_data.polyline->polylines.front().push_back(hf_around_facet->vertex()->point()); + } + hf_around_facet = *halfedges_around_face(hd,poly).first; + polyline_data.polyline->polylines.front().push_back(get(vpm,target(hf_around_facet,poly))); polyline_data.position = center / counter; } } @@ -220,11 +248,14 @@ private: } } } + + // finds closest polyline from polyline_data_list and makes it active_hole bool activate_closest_hole(int x, int y) { - typedef Polyhedron::Halfedge_around_facet_circulator Halfedge_around_facet_circulator; if(polyline_data_list.empty()) { return false; } + Face_graph& poly = *poly_item->polyhedron(); + QGLViewer* viewer = *QGLViewer::QGLViewerPool().begin(); qglviewer::Camera* camera = viewer->camera(); @@ -242,13 +273,12 @@ private: min_it = it; } #else + boost::property_map::type vpm = get(CGAL::vertex_point,poly); /* use polyline points to measure distance - might hurt performance for large holes */ - Halfedge_around_facet_circulator hf_around_facet = it->halfedge->facet_begin(); - do { - - const Polyhedron::Traits::Point_3& p_1 = hf_around_facet->vertex()->point(); + BOOST_FOREACH(halfedge_descriptor hf_around_facet, halfedges_around_face(it->halfedge,poly)){ + const Point_3& p_1 = get(vpm,target(hf_around_facet,poly)); const qglviewer::Vec& pos_it_1 = camera->projectedCoordinatesOf(qglviewer::Vec(p_1.x(), p_1.y(), p_1.z())); - const Polyhedron::Traits::Point_3& p_2 = hf_around_facet->opposite()->vertex()->point(); + const Point_3& p_2 = get(vpm,target(opposite(hf_around_facet,poly),poly)); const qglviewer::Vec& pos_it_2 = camera->projectedCoordinatesOf(qglviewer::Vec(p_2.x(), p_2.y(), p_2.z())); Kernel::Segment_2 s(Kernel::Point_2(pos_it_1.x, pos_it_1.y), Kernel::Point_2(pos_it_2.x, pos_it_2.y)); @@ -257,7 +287,7 @@ private: min_dist = dist; min_it = it; } - } while(++hf_around_facet != it->halfedge->facet_begin()); + } #endif } @@ -281,7 +311,7 @@ private: Mouse_keyboard_state state; public: Selected_holes_set selected_holes; - Scene_polyhedron_item* poly_item; + Scene_face_graph_item* poly_item; Polyline_data_list polyline_data_list; bool block_poly_item_changed; @@ -303,7 +333,7 @@ class Polyhedron_demo_hole_filling_plugin : Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface) Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0") public: - bool applicable(QAction*) const { return qobject_cast(scene->item(scene->mainSelectionIndex())) || + bool applicable(QAction*) const { return qobject_cast(scene->item(scene->mainSelectionIndex())) || qobject_cast(scene->item(scene->mainSelectionIndex())); } void print_message(QString message) { messages->information(message); } QList actions() const { return QList() << actionHoleFilling; } @@ -315,7 +345,7 @@ public: { dock_widget->hide(); } - Scene_hole_visualizer* get_hole_visualizer(Scene_polyhedron_item* poly_item) { + Scene_hole_visualizer* get_hole_visualizer(Scene_face_graph_item* poly_item) { return visualizers[poly_item]; } @@ -345,7 +375,7 @@ protected: return false; } - void change_poly_item_by_blocking(Scene_polyhedron_item* poly_item, Scene_hole_visualizer* collection) { + void change_poly_item_by_blocking(Scene_face_graph_item* poly_item, Scene_hole_visualizer* collection) { if(collection) collection->block_poly_item_changed = true; poly_item->invalidateOpenGLBuffers(); scene->itemChanged(poly_item); @@ -360,13 +390,13 @@ private: //Maintains a reference between all the visualizers and their poly_item // to ease the management of the visualizers - QMap visualizers; + QMap visualizers; // hold created facet for accept reject functionality - std::vector new_facets; - Scene_polyhedron_item* last_active_item; // always keep it NULL while not active-reject state + std::vector new_facets; + Scene_face_graph_item* last_active_item; // always keep it NULL while not active-reject state - bool fill(Polyhedron& polyhedron, Polyhedron::Halfedge_handle halfedge); - bool self_intersecting(Polyhedron& polyhedron); + bool fill(Face_graph& polyhedron, halfedge_descriptor halfedge); + bool self_intersecting(Face_graph& polyhedron); void accept_reject_toggle(bool activate_accept_reject) { if(activate_accept_reject) { ui_widget.Accept_button->setVisible(true); @@ -433,7 +463,7 @@ void Polyhedron_demo_hole_filling_plugin::init(QMainWindow* mainWindow, } void Polyhedron_demo_hole_filling_plugin::item_about_to_be_destroyed(CGAL::Three::Scene_item* scene_item) { - Scene_polyhedron_item* poly_item = qobject_cast(scene_item); + Scene_face_graph_item* poly_item = qobject_cast(scene_item); if(poly_item) { // erase assoc polylines item if(Scene_hole_visualizer* hole_visualizer = get_hole_visualizer(poly_item)) @@ -464,9 +494,9 @@ void Polyhedron_demo_hole_filling_plugin::dock_widget_closed() { } on_Accept_button(); } -// creates a Scene_hole_visualizer and associate it with active Scene_polyhedron_item +// creates a Scene_hole_visualizer and associate it with active Scene_face_graph_item void Polyhedron_demo_hole_filling_plugin::on_Visualize_holes_button() { - Scene_polyhedron_item* poly_item = getSelectedItem(); + Scene_face_graph_item* poly_item = getSelectedItem(); if(!poly_item) { print_message("Error: please select a polyhedron item from Geometric Objects list!"); return; @@ -597,7 +627,7 @@ void Polyhedron_demo_hole_filling_plugin::on_Reject_button() { if(last_active_item == NULL) { return; } accept_reject_toggle(false); - for(std::vector::iterator it = new_facets.begin(); it != new_facets.end(); ++it) { + for(std::vector::iterator it = new_facets.begin(); it != new_facets.end(); ++it) { last_active_item->polyhedron()->erase_facet((*it)->halfedge()); } change_poly_item_by_blocking(last_active_item, get_hole_visualizer(last_active_item)); @@ -615,7 +645,7 @@ void Polyhedron_demo_hole_filling_plugin::hole_visualizer_changed() { } // helper function for filling holes bool Polyhedron_demo_hole_filling_plugin::fill - (Polyhedron& poly, Polyhedron::Halfedge_handle it) { + (Face_graph& poly, halfedge_descriptor it) { int action_index = ui_widget.action_combo_box->currentIndex(); double alpha = ui_widget.Density_control_factor_spin_box->value(); @@ -623,7 +653,7 @@ bool Polyhedron_demo_hole_filling_plugin::fill unsigned int continuity = ui_widget.Continuity_spin_box->value(); CGAL::Timer timer; timer.start(); - std::vector patch; + std::vector patch; if(action_index == 0) { CGAL::Polygon_mesh_processing::triangulate_hole(poly, it, std::back_inserter(patch), @@ -643,7 +673,7 @@ bool Polyhedron_demo_hole_filling_plugin::fill success = CGAL::cpp11::get<0>(CGAL::Polygon_mesh_processing::triangulate_refine_and_fair_hole(poly, it, std::back_inserter(patch), CGAL::Emptyset_iterator(), CGAL::Polygon_mesh_processing::parameters::weight_calculator - (CGAL::internal::Uniform_weight_fairing(poly)). + (CGAL::internal::Uniform_weight_fairing(poly)). density_control_factor(alpha). fairing_continuity(continuity). use_delaunay_triangulation(use_DT))); @@ -651,7 +681,7 @@ bool Polyhedron_demo_hole_filling_plugin::fill else { success = CGAL::cpp11::get<0>(CGAL::Polygon_mesh_processing::triangulate_refine_and_fair_hole(poly, it, std::back_inserter(patch), CGAL::Emptyset_iterator(), - CGAL::Polygon_mesh_processing::parameters::weight_calculator(CGAL::internal::Cotangent_weight_with_voronoi_area_fairing(poly)). + CGAL::Polygon_mesh_processing::parameters::weight_calculator(CGAL::internal::Cotangent_weight_with_voronoi_area_fairing(poly)). density_control_factor(alpha). fairing_continuity(continuity). use_delaunay_triangulation(use_DT))); @@ -671,7 +701,7 @@ bool Polyhedron_demo_hole_filling_plugin::fill if(ui_widget.Skip_self_intersection_check_box->checkState() == Qt::Checked) { timer.reset(); - typedef std::vector > Intersected_facets; + typedef std::vector > Intersected_facets; Intersected_facets intersected_facets; CGAL::Polygon_mesh_processing::self_intersections(poly, std::back_inserter(intersected_facets), @@ -683,7 +713,7 @@ bool Polyhedron_demo_hole_filling_plugin::fill bool intersected = false; for(Intersected_facets::iterator it = intersected_facets.begin(); it != intersected_facets.end() && !intersected; ++it) { - for(std::vector::iterator it_patch = patch.begin(); + for(std::vector::iterator it_patch = patch.begin(); it_patch != patch.end() && !intersected; ++it_patch) { if(it->first == (*it_patch) || it->second == (*it_patch)) { intersected = true; @@ -692,7 +722,7 @@ bool Polyhedron_demo_hole_filling_plugin::fill } print_message(QString("Self intersecting test: iterate on patch in %1 sec.").arg(timer.time())); if(intersected) { - for(std::vector::iterator it = patch.begin(); it != patch.end(); ++it) { + for(std::vector::iterator it = patch.begin(); it != patch.end(); ++it) { poly.erase_facet((*it)->halfedge()); } print_message("Self intersecting patch is generated, and it is removed."); @@ -715,23 +745,23 @@ void Polyhedron_demo_hole_filling_plugin::on_Fill_from_selection_button() { print_message("No edge selection found in the current item selection."); return; } - Polyhedron *poly = edge_selection->polyhedron(); - QVector vertices; - std::vector points; + Face_graph *poly = edge_selection->polyhedron(); + QVector vertices; + std::vector points; bool use_DT = ui_widget.Use_delaunay_triangulation_check_box->isChecked(); - poly->normalize_border(); + normalize_border(*poly); // fill hole - boost::unordered_set buffer; + boost::unordered_set buffer; //check if all selected edges are boder //to do check that the seection is closed - BOOST_FOREACH(boost::graph_traits::edge_descriptor ed, edge_selection->selected_edges) + BOOST_FOREACH(edge_descriptor ed, edge_selection->selected_edges) { - Polyhedron::Halfedge_handle h(halfedge(ed, *poly)); - if(!h->is_border()) + halfedge_descriptor h(halfedge(ed, *poly)); + if(! is_border(h,*poly)) { - h = h->opposite(); - if(!h->is_border()) + h = opposite(h,*poly); + if(! is_border(h,*poly)) { print_message("A selected_border is not a border edge. Cannot fill something that is not a hole."); return; @@ -741,21 +771,21 @@ void Polyhedron_demo_hole_filling_plugin::on_Fill_from_selection_button() { } //fill the points //order edges - QVector b_edges; - Polyhedron::Halfedge_handle c_e = *buffer.begin(); + QVector b_edges; + halfedge_descriptor c_e = *buffer.begin(); b_edges.reserve(static_cast(buffer.size())); b_edges.push_back(c_e); buffer.erase(c_e); while(!buffer.empty()) { bool found = false; - BOOST_FOREACH(Polyhedron::Halfedge_handle h, buffer) + BOOST_FOREACH(halfedge_descriptor h, buffer) { //if h and c_e share a point - if(h->vertex() == c_e->vertex() || - h->vertex() == c_e->opposite()->vertex() || - h->opposite()->vertex() == c_e->vertex() || - h->opposite()->vertex() == c_e->opposite()->vertex()) + if(target(h, *poly) == target(c_e,*poly) || + target(h, *poly) == target(opposite(c_e,*poly), *poly) || + target(opposite(h, *poly), *poly) == target(c_e,*poly) || + target(opposite(h, *poly),*poly) == target(opposite(c_e,*poly),*poly)) { c_e = h; b_edges.push_back(c_e); @@ -775,19 +805,19 @@ void Polyhedron_demo_hole_filling_plugin::on_Fill_from_selection_button() { // else add the shared point. for(int i=0; ivertex() == b_edges[i+1]->vertex() || - b_edges[i]->vertex() == b_edges[i+1]->opposite()->vertex() + vertex_descriptor shared_vertex; + vertex_descriptor other_vertex; + if(target(b_edges[i], *poly) == target(b_edges[i+1], *poly) || + target(b_edges[i], *poly) == target(b_edges[i+1]->opposite(), *poly) ) { - shared_vertex = b_edges[i]->vertex(); - other_vertex = b_edges[i]->opposite()->vertex(); + shared_vertex = target(b_edges[i], *poly); + other_vertex = target(opposite(b_edges[i],*poly), *poly); } else { - shared_vertex = b_edges[i]->opposite()->vertex(); - other_vertex = b_edges[i]->vertex(); + shared_vertex = target(opposite(b_edges[i],*poly), *poly); + other_vertex = target(b_edges[i], *poly); } if(!vertices.contains(shared_vertex)) vertices.push_back(shared_vertex); @@ -795,14 +825,15 @@ void Polyhedron_demo_hole_filling_plugin::on_Fill_from_selection_button() { vertices.push_back(other_vertex); } //close the loop - if(!vertices.contains(b_edges.back()->vertex())) - vertices.push_back(b_edges.back()->vertex()); + if(!vertices.contains(target(b_edges.back(), *poly))) + vertices.push_back(target(b_edges.back(), *poly)); else - vertices.push_back(b_edges.back()->opposite()->vertex()); + vertices.push_back(target(opposite(b_edges.back(),*poly), *poly)); - Q_FOREACH(Polyhedron::Vertex_handle vh, vertices) + boost::property_map::type vpm = get(CGAL::vertex_point,*poly); + Q_FOREACH(vertex_descriptor vh, vertices) { - points.push_back(vh->point()); + points.push_back(get(vpm,vh)); } std::vector > patch; @@ -814,14 +845,14 @@ void Polyhedron_demo_hole_filling_plugin::on_Fill_from_selection_button() { for(std::size_t i=0; i indices = patch[i]; - std::vector face; + std::vector face; face.push_back(vertices[indices.first]); face.push_back(vertices[indices.second]); face.push_back(vertices[indices.third]); - Polyhedron::Facet_handle new_fh = CGAL::Euler::add_face(face, *poly); + face_descriptor new_fh = CGAL::Euler::add_face(face, *poly); if(new_fh == boost::graph_traits::null_face()) { - new_fh = CGAL::Euler::add_face(std::vector(face.rbegin(), face.rend()), *poly); + new_fh = CGAL::Euler::add_face(std::vector(face.rbegin(), face.rend()), *poly); if( new_fh == boost::graph_traits::null_face()) print_message("The facet could not be added. Please try again."); }