bglize hole_filling_plugin ; Does not yet work with Surface_mesh as there is also a selection

This commit is contained in:
Andreas Fabri 2017-03-15 14:56:23 +01:00 committed by Maxime Gimeno
parent 00f35fc70e
commit 97990e001f
2 changed files with 113 additions and 77 deletions

View File

@ -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)

View File

@ -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 <CGAL/boost/graph/Euler_operations.h>
#include "Kernel_type.h"
#include <boost/unordered_set.hpp>
#include <boost/function_output_iterator.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <QMap>
#include <QVector>
#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<Face_graph>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<Face_graph>::halfedge_descriptor halfedge_descriptor;
typedef boost::graph_traits<Face_graph>::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<Polyline_data_list::const_iterator, List_iterator_comparator> 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<qglviewer::Vec> 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<halfedge_descriptor> visited;
boost::property_map<Face_graph,CGAL::vertex_point_t>::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<Face_graph,CGAL::vertex_point_t>::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_polyhedron_item*>(scene->item(scene->mainSelectionIndex())) ||
bool applicable(QAction*) const { return qobject_cast<Scene_face_graph_item*>(scene->item(scene->mainSelectionIndex())) ||
qobject_cast<Scene_polyhedron_selection_item*>(scene->item(scene->mainSelectionIndex())); }
void print_message(QString message) { messages->information(message); }
QList<QAction*> actions() const { return QList<QAction*>() << 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<Scene_polyhedron_item*, Scene_hole_visualizer*> visualizers;
QMap<Scene_face_graph_item*, Scene_hole_visualizer*> visualizers;
// hold created facet for accept reject functionality
std::vector<Polyhedron::Facet_handle> new_facets;
Scene_polyhedron_item* last_active_item; // always keep it NULL while not active-reject state
std::vector<face_descriptor> 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_polyhedron_item*>(scene_item);
Scene_face_graph_item* poly_item = qobject_cast<Scene_face_graph_item*>(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_polyhedron_item>();
Scene_face_graph_item* poly_item = getSelectedItem<Scene_face_graph_item>();
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<Polyhedron::Facet_handle>::iterator it = new_facets.begin(); it != new_facets.end(); ++it) {
for(std::vector<face_descriptor>::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<Polyhedron::Facet_handle> patch;
std::vector<face_descriptor> 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<Polyhedron>(poly)).
(CGAL::internal::Uniform_weight_fairing<Face_graph>(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<Polyhedron>(poly)).
CGAL::Polygon_mesh_processing::parameters::weight_calculator(CGAL::internal::Cotangent_weight_with_voronoi_area_fairing<Face_graph>(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<std::pair<Polyhedron::Facet_const_handle, Polyhedron::Facet_const_handle> > Intersected_facets;
typedef std::vector<std::pair<face_descriptor, face_descriptor> > 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<Polyhedron::Facet_handle>::iterator it_patch = patch.begin();
for(std::vector<face_descriptor>::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<Polyhedron::Facet_handle>::iterator it = patch.begin(); it != patch.end(); ++it) {
for(std::vector<face_descriptor>::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<Polyhedron::Vertex_handle> vertices;
std::vector<Polyhedron::Point_3> points;
Face_graph *poly = edge_selection->polyhedron();
QVector<vertex_descriptor> vertices;
std::vector<Point_3> points;
bool use_DT = ui_widget.Use_delaunay_triangulation_check_box->isChecked();
poly->normalize_border();
normalize_border(*poly);
// fill hole
boost::unordered_set<Polyhedron::Halfedge_handle, CGAL::Handle_hash_function> buffer;
boost::unordered_set<halfedge_descriptor> buffer;
//check if all selected edges are boder
//to do check that the seection is closed
BOOST_FOREACH(boost::graph_traits<Polyhedron>::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<Polyhedron::Halfedge_handle> b_edges;
Polyhedron::Halfedge_handle c_e = *buffer.begin();
QVector<halfedge_descriptor> b_edges;
halfedge_descriptor c_e = *buffer.begin();
b_edges.reserve(static_cast<int>(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; i<b_edges.size()-1; ++i)
{
Polyhedron::Vertex_handle shared_vertex;
Polyhedron::Vertex_handle other_vertex;
if(b_edges[i]->vertex() == 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<Face_graph,CGAL::vertex_point_t>::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<CGAL::Triple<int, int, int> > patch;
@ -814,14 +845,14 @@ void Polyhedron_demo_hole_filling_plugin::on_Fill_from_selection_button() {
for(std::size_t i=0; i<patch.size(); ++i)
{
CGAL::Triple<int, int, int> indices = patch[i];
std::vector<Polyhedron::Vertex_handle> face;
std::vector<vertex_descriptor> 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<Polyhedron>::null_face())
{
new_fh = CGAL::Euler::add_face(std::vector<Polyhedron::Vertex_handle>(face.rbegin(), face.rend()), *poly);
new_fh = CGAL::Euler::add_face(std::vector<vertex_descriptor>(face.rbegin(), face.rend()), *poly);
if( new_fh == boost::graph_traits<Polyhedron>::null_face())
print_message("The facet could not be added. Please try again.");
}