cgal/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp

399 lines
14 KiB
C++

#include <QtCore/qglobal.h>
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
#include <CGAL/iterator.h>
#include <CGAL/utility.h>
#include <CGAL/property_map.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/angle_and_area_smoothing.h>
#include <CGAL/Polygon_mesh_processing/smooth_shape.h>
#include <CGAL/Polygon_mesh_processing/tangential_relaxation.h>
#include "Scene.h"
#include "Scene_surface_mesh_item.h"
#include "Scene_polyhedron_selection_item.h"
#include "ui_Smoothing_plugin.h"
#include "ui_Smoothing_tangential_relaxation.h"
#include <QElapsedTimer>
#include <QAction>
#include <QMainWindow>
#include <QApplication>
#include <QDockWidget>
#include <QString>
#include <QInputDialog>
#include <QtPlugin>
#include <QMessageBox>
using namespace CGAL::Polygon_mesh_processing;
using namespace CGAL::Three;
typedef Scene_surface_mesh_item Scene_face_graph_item;
typedef Scene_face_graph_item::Face_graph Face_graph;
typedef boost::graph_traits<Face_graph>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<Face_graph>::edge_descriptor edge_descriptor;
typedef boost::graph_traits<Face_graph>::face_descriptor face_descriptor;
typedef CGAL::dynamic_vertex_property_t<bool> Vertex_bool_property;
typedef typename boost::property_map<Face_graph, Vertex_bool_property>::type VCMap;
class Polyhedron_demo_smothing_plugin
: public QObject, public Polyhedron_demo_plugin_helper
{
Q_OBJECT
Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
public:
void init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*)
{
scene = scene_interface;
mw = mainWindow;
actionSmoothing_ = new QAction(tr("Mesh and Shape Smoothing"), mw);
actionSmoothing_->setProperty("subMenuName", "Polygon Mesh Processing");
connect(actionSmoothing_, SIGNAL(triggered()), this, SLOT(smoothing_action()));
dock_widget = new QDockWidget("Smoothing", mw);
dock_widget->setVisible(false);
ui_widget.setupUi(dock_widget);
addDockWidget(dock_widget);
connect(ui_widget.area_smoothing_checkBox, SIGNAL(toggled(bool)),
ui_widget.flip_checkBox, SLOT(setEnabled(bool)));
connect(ui_widget.mesh_smoothing_button, SIGNAL(clicked()), this, SLOT(on_mesh_smoothing_clicked()));
connect(ui_widget.shape_smoothing_button, SIGNAL(clicked()), this, SLOT(on_shape_smoothing_clicked()));
actionRelax_ = new QAction(tr("Tangential Relaxation"), mw);
actionRelax_->setProperty("subMenuName", "Polygon Mesh Processing");
connect(actionRelax_, SIGNAL(triggered()), this, SLOT(tangential_relaxation_action()));
}
QList<QAction*> actions() const
{
return QList<QAction*>() << actionSmoothing_ << actionRelax_;
}
bool applicable(QAction*) const
{
const Scene_interface::Item_id index = scene->mainSelectionIndex();
if(qobject_cast<Scene_face_graph_item*>(scene->item(index)))
return true;
else if(qobject_cast<Scene_polyhedron_selection_item*>(scene->item(index)))
return true;
else
return false;
}
virtual void closure()
{
dock_widget->hide();
}
void init_ui()
{
ui_widget.time_step_spinBox->setValue(0.00001);
ui_widget.time_step_spinBox->setMinimum(1e-6);
ui_widget.smooth_iter_spinBox->setValue(1);
ui_widget.projection_checkBox->setChecked(true);
ui_widget.area_smoothing_checkBox->setChecked(false);
#ifndef CGAL_PMP_USE_CERES_SOLVER
ui_widget.area_smoothing_checkBox->setDisabled(true);
#endif
ui_widget.flip_checkBox->setChecked(true);
ui_widget.flip_checkBox->setDisabled(true);
}
void mark_border_vertices(const VCMap vcmap, const Face_graph& pmesh) const
{
for(halfedge_descriptor h : halfedges(pmesh))
{
if(CGAL::is_border(h, pmesh))
put(vcmap, target(h, pmesh), true);
}
}
void mark_selected_vertices(const VCMap vcmap,
const Face_graph& pmesh,
Scene_polyhedron_selection_item* selection_item) const
{
for(vertex_descriptor v : selection_item->selected_vertices)
put(vcmap, v, true);
for(edge_descriptor e : selection_item->selected_edges)
{
put(vcmap, source(e, pmesh), true);
put(vcmap, target(e, pmesh), true);
}
}
Ui::Tangential_relaxation_dialog
relaxation_dialog(QDialog* dialog)
{
Ui::Tangential_relaxation_dialog ui;
ui.setupUi(dialog);
connect(ui.buttonBox, SIGNAL(accepted()), dialog, SLOT(accept()));
connect(ui.buttonBox, SIGNAL(rejected()), dialog, SLOT(reject()));
ui.nbIterations_spinbox->setSingleStep(1);
ui.nbIterations_spinbox->setRange(1/*min*/, 1000/*max*/);
ui.nbIterations_spinbox->setValue(1);
ui.smooth1D_checkbox->setChecked(true);
return ui;
}
public Q_SLOTS:
void smoothing_action()
{
dock_widget->show();
dock_widget->raise();
const Scene_interface::Item_id index = scene->mainSelectionIndex();
Scene_face_graph_item* poly_item = qobject_cast<Scene_face_graph_item*>(scene->item(index));
Scene_polyhedron_selection_item* selection_item =
qobject_cast<Scene_polyhedron_selection_item*>(scene->item(index));
if(poly_item || selection_item)
{
init_ui();
}
}
void tangential_relaxation_action()
{
const Scene_interface::Item_id index = scene->mainSelectionIndex();
Scene_facegraph_item* poly_item =
qobject_cast<Scene_facegraph_item*>(scene->item(index));
Scene_polyhedron_selection_item* selection_item =
qobject_cast<Scene_polyhedron_selection_item*>(scene->item(index));
if (poly_item || selection_item)
{
if (selection_item && selection_item->selected_facets.empty())
{
QMessageBox::warning(mw, "Empty Facets", "There are no selected facets. Aborting.");
return;
}
// Create dialog box
QDialog dialog(mw);
Ui::Tangential_relaxation_dialog ui = relaxation_dialog(&dialog);
// Get values
int i = dialog.exec();
if (i == QDialog::Rejected)
{
std::cout << "Tangential relaxation aborted" << std::endl;
return;
}
unsigned int nb_iter = ui.nbIterations_spinbox->value();
bool smooth_features = ui.smooth1D_checkbox->isChecked();
// wait cursor
QApplication::setOverrideCursor(Qt::WaitCursor);
QElapsedTimer time;
time.start();
FaceGraph& pmesh = (poly_item != nullptr)
? *poly_item->polyhedron()
: *selection_item->polyhedron();
if (selection_item)
{
boost::unordered_set<vertex_descriptor> vset;
for (face_descriptor f : selection_item->selected_facets)
{
for(vertex_descriptor fv : CGAL::vertices_around_face(halfedge(f, pmesh), pmesh))
vset.insert(fv);
}
CGAL::Polygon_mesh_processing::tangential_relaxation(
vset,
pmesh,
CGAL::parameters::number_of_iterations(nb_iter)
.edge_is_constrained_map(selection_item->constrained_edges_pmap())
.vertex_is_constrained_map(selection_item->constrained_vertices_pmap())
.relax_constraints(smooth_features));
selection_item->polyhedron_item()->invalidateOpenGLBuffers();
Q_EMIT selection_item->polyhedron_item()->itemChanged();
selection_item->invalidateOpenGLBuffers();
selection_item->setKeepSelectionValid(Scene_polyhedron_selection_item::None);
}
else if (poly_item)
{
CGAL::Polygon_mesh_processing::tangential_relaxation(
vertices(pmesh),
pmesh,
CGAL::parameters::number_of_iterations(nb_iter));
poly_item->invalidateOpenGLBuffers();
Q_EMIT poly_item->itemChanged();
}
std::cout << "ok (" << time.elapsed() << " ms)" << std::endl;
}
// default cursor
QApplication::restoreOverrideCursor();
}
void on_mesh_smoothing_clicked()
{
const Scene_interface::Item_id index = scene->mainSelectionIndex();
Scene_face_graph_item* poly_item = qobject_cast<Scene_face_graph_item*>(scene->item(index));
Scene_polyhedron_selection_item* selection_item = qobject_cast<Scene_polyhedron_selection_item*>(scene->item(index));
if(!poly_item && !selection_item)
return;
Face_graph& pmesh = (poly_item != nullptr) ? * poly_item->polyhedron() : * selection_item->polyhedron();
const unsigned int nb_iter = ui_widget.smooth_iter_spinBox->value();
const bool projection = ui_widget.projection_checkBox->isChecked();
const bool use_safety_measures = ui_widget.sanity_checkBox->isChecked();
const bool constrain_border_vertices = ui_widget.border_button->isChecked() && !CGAL::is_closed(pmesh);
const bool use_angle_smoothing = ui_widget.angle_smoothing_checkBox->isChecked();
const bool use_area_smoothing = ui_widget.area_smoothing_checkBox->isChecked();
const bool use_Delaunay_flips = ui_widget.flip_checkBox->isChecked();
QApplication::setOverrideCursor(Qt::WaitCursor);
VCMap vcmap = get(Vertex_bool_property(), pmesh);
for(vertex_descriptor v : vertices(pmesh))
put(vcmap, v, false);
if(constrain_border_vertices)
mark_border_vertices(vcmap, pmesh);
if(poly_item)
{
angle_and_area_smoothing(pmesh, CGAL::parameters::do_project(projection)
.number_of_iterations(nb_iter)
.vertex_is_constrained_map(vcmap)
.use_safety_constraints(use_safety_measures)
.use_angle_smoothing(use_angle_smoothing)
.use_area_smoothing(use_area_smoothing)
.use_Delaunay_flips(use_Delaunay_flips));
poly_item->invalidateOpenGLBuffers();
poly_item->itemChanged();
}
else if(selection_item)
{
mark_selected_vertices(vcmap, pmesh, selection_item);
// No faces selected --> use all faces
if(std::begin(selection_item->selected_facets) == std::end(selection_item->selected_facets))
{
angle_and_area_smoothing(pmesh, CGAL::parameters::do_project(projection)
.number_of_iterations(nb_iter)
.vertex_is_constrained_map(vcmap)
.edge_is_constrained_map(selection_item->constrained_edges_pmap())
.use_safety_constraints(use_safety_measures)
.use_angle_smoothing(use_angle_smoothing)
.use_area_smoothing(use_area_smoothing)
.use_Delaunay_flips(use_Delaunay_flips));
}
else // some faces exist in the selection
{
angle_and_area_smoothing(selection_item->selected_facets, pmesh, CGAL::parameters::do_project(projection)
.number_of_iterations(nb_iter)
.vertex_is_constrained_map(vcmap)
.edge_is_constrained_map(selection_item->constrained_edges_pmap())
.use_safety_constraints(use_safety_measures)
.use_angle_smoothing(use_angle_smoothing)
.use_area_smoothing(use_area_smoothing)
.use_Delaunay_flips(use_Delaunay_flips));
}
selection_item->poly_item_changed();
selection_item->changed_with_poly_item();
}
QApplication::restoreOverrideCursor();
}
void on_shape_smoothing_clicked()
{
const Scene_interface::Item_id index = scene->mainSelectionIndex();
Scene_face_graph_item* poly_item = qobject_cast<Scene_face_graph_item*>(scene->item(index));
Scene_polyhedron_selection_item* selection_item = qobject_cast<Scene_polyhedron_selection_item*>(scene->item(index));
if(!poly_item && !selection_item)
return;
Face_graph& pmesh = (poly_item != nullptr) ? * poly_item->polyhedron() : * selection_item->polyhedron();
const double time_step = ui_widget.time_step_spinBox->value();
const unsigned int nb_iter = ui_widget.smooth_iter_spinBox->value();
const bool constrain_border_vertices = ui_widget.border_button->isChecked() && !CGAL::is_closed(pmesh);
QApplication::setOverrideCursor(Qt::WaitCursor);
VCMap vcmap = get(Vertex_bool_property(), pmesh);
for(vertex_descriptor v : vertices(pmesh))
put(vcmap, v, false);
if(constrain_border_vertices)
mark_border_vertices(vcmap, pmesh);
if(poly_item)
{
smooth_shape(pmesh, time_step, CGAL::parameters::number_of_iterations(nb_iter)
.vertex_is_constrained_map(vcmap));
poly_item->invalidateOpenGLBuffers();
poly_item->itemChanged();
}
else if(selection_item)
{
mark_selected_vertices(vcmap, pmesh, selection_item);
if(std::begin(selection_item->selected_facets) == std::end(selection_item->selected_facets))
{
smooth_shape(pmesh, time_step, CGAL::parameters::number_of_iterations(nb_iter)
.vertex_is_constrained_map(vcmap));
}
else
{
smooth_shape(selection_item->selected_facets, pmesh, time_step,
CGAL::parameters::number_of_iterations(nb_iter)
.vertex_is_constrained_map(vcmap));
}
selection_item->poly_item_changed();
selection_item->changed_with_poly_item();
}
else
{
std::cerr << "Something's gone wrong.\n";
CGAL_assertion(false);
}
QApplication::restoreOverrideCursor();
}
private:
QAction* actionSmoothing_;
QAction* actionRelax_;
QDockWidget* dock_widget;
Ui::Smoothing ui_widget;
};
#include "Smoothing_plugin.moc"