Fix many issues with the smoothing polyhedron plugin + remake the GUI

This commit is contained in:
Mael Rouxel-Labbé 2019-06-05 16:00:02 +02:00
parent aa6ef78eb3
commit 82722a4e7d
2 changed files with 246 additions and 232 deletions

View File

@ -27,11 +27,18 @@
#include <QtPlugin> #include <QtPlugin>
#include <QMessageBox> #include <QMessageBox>
using namespace CGAL::Polygon_mesh_processing;
using namespace CGAL::Three;
typedef Scene_surface_mesh_item Scene_face_graph_item; typedef Scene_surface_mesh_item Scene_face_graph_item;
typedef Scene_face_graph_item::Face_graph Face_graph; typedef Scene_face_graph_item::Face_graph Face_graph;
using namespace CGAL::Polygon_mesh_processing; typedef boost::graph_traits<Face_graph>::vertex_descriptor vertex_descriptor;
using namespace CGAL::Three; 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 class Polyhedron_demo_smothing_plugin
: public QObject, public Polyhedron_demo_plugin_helper : public QObject, public Polyhedron_demo_plugin_helper
@ -46,7 +53,7 @@ public:
scene = scene_interface; scene = scene_interface;
mw = mainWindow; mw = mainWindow;
actionSmoothing_ = new QAction(tr("Smoothing"), mw); actionSmoothing_ = new QAction(tr("Mesh and Shape Smoothing"), mw);
actionSmoothing_->setProperty("subMenuName", "Polygon Mesh Processing"); actionSmoothing_->setProperty("subMenuName", "Polygon Mesh Processing");
connect(actionSmoothing_, SIGNAL(triggered()), this, SLOT(smoothing_action())); connect(actionSmoothing_, SIGNAL(triggered()), this, SLOT(smoothing_action()));
@ -57,9 +64,8 @@ public:
ui_widget.setupUi(dock_widget); ui_widget.setupUi(dock_widget);
addDockWidget(dock_widget); addDockWidget(dock_widget);
connect(ui_widget.angle_button, SIGNAL(clicked()), this, SLOT(on_angle_smoothing_clicked())); connect(ui_widget.mesh_smoothing_button, SIGNAL(clicked()), this, SLOT(on_mesh_smoothing_clicked()));
connect(ui_widget.area_button, SIGNAL(clicked()), this, SLOT(on_area_smoothing_clicked())); connect(ui_widget.shape_smoothing_button, SIGNAL(clicked()), this, SLOT(on_shape_smoothing_clicked()));
connect(ui_widget.curvature_flow_button, SIGNAL(clicked()), this, SLOT(on_curvature_flow_clicked()));
} }
QList<QAction*> actions() const QList<QAction*> actions() const
@ -85,28 +91,46 @@ public:
void init_ui() void init_ui()
{ {
ui_widget.angles_iter_spinBox ->setValue(1);
ui_widget.angles_iter_spinBox->setSingleStep(1);
ui_widget.angles_iter_spinBox->setMinimum(1);
ui_widget.areas_iter_spinBox->setValue(1);
ui_widget.areas_iter_spinBox->setSingleStep(1);
ui_widget.areas_iter_spinBox->setMinimum(1);
ui_widget.time_step_spinBox->setValue(0.00001); ui_widget.time_step_spinBox->setValue(0.00001);
ui_widget.time_step_spinBox->setSingleStep(0.00001); ui_widget.time_step_spinBox->setSingleStep(0.00001);
ui_widget.time_step_spinBox->setMinimum(1e-6); ui_widget.time_step_spinBox->setMinimum(1e-6);
// todo: replace this spinbox with a sliding bar ui_widget.smooth_iter_spinBox->setValue(1);
ui_widget.precision_spinBox->setValue(0.00001);
ui_widget.precision_spinBox->setSingleStep(0.0000001);
ui_widget.precision_spinBox->setMinimum(1e-7);
ui_widget.projection_checkBox->setChecked(true); ui_widget.projection_checkBox->setChecked(true);
ui_widget.explicit_checkBox->setChecked(false); ui_widget.explicit_checkBox->setChecked(false);
}
ui_widget.curvature_iter_spinBox->setValue(1); void mark_border_vertices(const VCMap vcmap, const Face_graph& pmesh) const
{
for(vertex_descriptor v : vertices(pmesh))
put(vcmap, v, false);
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);
}
for(face_descriptor f : selection_item->selected_facets)
{
for(vertex_descriptor v : vertices_around_face(halfedge(f, pmesh), pmesh))
put(vcmap, v, true);
}
} }
public Q_SLOTS: public Q_SLOTS:
@ -127,31 +151,104 @@ public Q_SLOTS:
} }
} }
void on_angle_smoothing_clicked() void on_mesh_smoothing_clicked()
{ {
const Scene_interface::Item_id index = scene->mainSelectionIndex(); const Scene_interface::Item_id index = scene->mainSelectionIndex();
Scene_face_graph_item* poly_item = qobject_cast<Scene_face_graph_item*>(scene->item(index)); 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)); Scene_polyhedron_selection_item* selection_item = qobject_cast<Scene_polyhedron_selection_item*>(scene->item(index));
Face_graph& pmesh = (poly_item != nullptr) ? * poly_item->polyhedron() : * selection_item->polyhedron(); Face_graph& pmesh = (poly_item != nullptr) ? * poly_item->polyhedron() : * selection_item->polyhedron();
const unsigned int nb_iter = ui_widget.angles_iter_spinBox->value(); const unsigned int nb_iter = ui_widget.smooth_iter_spinBox->value();
bool projection = ui_widget.projection_checkBox->isChecked(); const bool projection = ui_widget.projection_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();
QApplication::setOverrideCursor(Qt::WaitCursor); 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) if(poly_item)
{ {
smooth_angles(pmesh, if(use_angle_smoothing)
parameters::number_of_iterations(nb_iter).do_project(projection)); {
if(use_area_smoothing)
{
smooth(pmesh, parameters::number_of_iterations(nb_iter)
.do_project(projection)
.vertex_is_constrained_map(vcmap));
}
else
{
smooth_angles(pmesh, parameters::number_of_iterations(nb_iter)
.do_project(projection)
.vertex_is_constrained_map(vcmap));
}
}
else
{
smooth_areas(pmesh, parameters::number_of_iterations(nb_iter)
.do_project(projection)
.vertex_is_constrained_map(vcmap));
}
poly_item->invalidateOpenGLBuffers(); poly_item->invalidateOpenGLBuffers();
poly_item->itemChanged(); poly_item->itemChanged();
} }
else if(selection_item) else if(selection_item)
{ {
smooth_angles(selection_item->selected_facets, pmesh, mark_selected_vertices(vcmap, pmesh, selection_item);
parameters::number_of_iterations(nb_iter)
.do_project(projection)); // No faces selected --> use all faces
if(std::begin(selection_item->selected_facets) == std::end(selection_item->selected_facets))
{
if(use_angle_smoothing)
{
if(use_area_smoothing)
smooth(pmesh, parameters::number_of_iterations(nb_iter)
.do_project(projection)
.vertex_is_constrained_map(vcmap));
else
smooth_angles(pmesh, parameters::number_of_iterations(nb_iter)
.do_project(projection)
.vertex_is_constrained_map(vcmap));
}
else
{
smooth_areas(pmesh, parameters::number_of_iterations(nb_iter)
.do_project(projection)
.vertex_is_constrained_map(vcmap));
}
}
else // some faces exist in the selection
{
if(use_angle_smoothing)
{
if(use_area_smoothing)
{
smooth(selection_item->selected_facets, pmesh, parameters::number_of_iterations(nb_iter)
.do_project(projection)
.vertex_is_constrained_map(vcmap));
}
else
{
smooth_angles(selection_item->selected_facets, pmesh, parameters::number_of_iterations(nb_iter)
.do_project(projection)
.vertex_is_constrained_map(vcmap));
}
}
else
{
smooth_areas(selection_item->selected_facets, pmesh, parameters::number_of_iterations(nb_iter)
.do_project(projection)
.vertex_is_constrained_map(vcmap));
}
}
selection_item->poly_item_changed(); selection_item->poly_item_changed();
selection_item->changed_with_poly_item(); selection_item->changed_with_poly_item();
@ -160,89 +257,55 @@ public Q_SLOTS:
QApplication::restoreOverrideCursor(); QApplication::restoreOverrideCursor();
} }
void on_area_smoothing_clicked() void on_shape_smoothing_clicked()
{ {
std::cout << "on_shape_smoothing_clicked" << std::endl;
const Scene_interface::Item_id index = scene->mainSelectionIndex(); const Scene_interface::Item_id index = scene->mainSelectionIndex();
Scene_face_graph_item* poly_item = qobject_cast<Scene_face_graph_item*>(scene->item(index)); 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)); Scene_polyhedron_selection_item* selection_item = qobject_cast<Scene_polyhedron_selection_item*>(scene->item(index));
Face_graph& pmesh = (poly_item != nullptr) ? * poly_item->polyhedron() : * selection_item->polyhedron(); Face_graph& pmesh = (poly_item != nullptr) ? * poly_item->polyhedron() : * selection_item->polyhedron();
unsigned int nb_iter = ui_widget.areas_iter_spinBox->value();
bool projection = ui_widget.projection_checkBox->isChecked();
QApplication::setOverrideCursor(Qt::WaitCursor);
if(poly_item)
{
smooth_areas(pmesh, parameters::number_of_iterations(nb_iter).do_project(projection));
poly_item->invalidateOpenGLBuffers();
poly_item->itemChanged();
}
else if(selection_item)
{
smooth_areas(selection_item->selected_facets, pmesh, parameters::number_of_iterations(nb_iter)
.do_project(projection));
selection_item->poly_item_changed();
selection_item->changed_with_poly_item();
}
else
{
std::cerr << "Something's gone wrong.\n";
CGAL_assertion(false);
}
QApplication::restoreOverrideCursor();
}
void on_curvature_flow_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));
Face_graph& pmesh = (poly_item != nullptr) ? * poly_item->polyhedron() : * selection_item->polyhedron();
int index_id = scene->item_id(poly_item);
const double time_step = ui_widget.time_step_spinBox->value(); const double time_step = ui_widget.time_step_spinBox->value();
const unsigned int nb_iter = ui_widget.curvature_iter_spinBox->value(); const unsigned int nb_iter = ui_widget.smooth_iter_spinBox->value();
const bool use_constrained_vertex_map = ui_widget.border_button->isChecked() && !CGAL::is_closed(pmesh); const bool constrain_border_vertices = ui_widget.border_button->isChecked() && !CGAL::is_closed(pmesh);
const bool use_explicit = ui_widget.explicit_checkBox->isChecked(); const bool use_explicit = ui_widget.explicit_checkBox->isChecked();
QApplication::setOverrideCursor(Qt::WaitCursor); 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) if(poly_item)
{ {
if(use_constrained_vertex_map) smooth_along_curvature_flow(pmesh, time_step, parameters::use_explicit_scheme(use_explicit)
{ .number_of_iterations(nb_iter)
smooth_along_curvature_flow(pmesh, time_step, parameters::use_explicit_scheme(use_explicit) .vertex_is_constrained_map(vcmap));
.number_of_iterations(nb_iter)
.vertex_is_constrained_map(get_border_constrained_map(pmesh)));
}
else
{
smooth_along_curvature_flow(pmesh, time_step, parameters::use_explicit_scheme(use_explicit)
.number_of_iterations(nb_iter));
}
poly_item->invalidateOpenGLBuffers(); poly_item->invalidateOpenGLBuffers();
poly_item->itemChanged(); poly_item->itemChanged();
} }
else if(selection_item) else if(selection_item)
{ {
if(use_constrained_vertex_map) mark_selected_vertices(vcmap, pmesh, selection_item);
if(std::begin(selection_item->selected_facets) == std::end(selection_item->selected_facets))
{ {
smooth_along_curvature_flow(selection_item->selected_facets, smooth_along_curvature_flow(pmesh, time_step, parameters::use_explicit_scheme(use_explicit)
pmesh, time_step, parameters::use_explicit_scheme(use_explicit)
.number_of_iterations(nb_iter) .number_of_iterations(nb_iter)
.vertex_is_constrained_map(get_border_constrained_map(pmesh))); .vertex_is_constrained_map(vcmap));
} }
else else
{ {
smooth_along_curvature_flow(selection_item->selected_facets, smooth_along_curvature_flow(selection_item->selected_facets, pmesh, time_step,
pmesh, time_step, parameters::use_explicit_scheme(use_explicit) parameters::use_explicit_scheme(use_explicit)
.number_of_iterations(nb_iter)); .number_of_iterations(nb_iter)
.vertex_is_constrained_map(vcmap));
} }
selection_item->poly_item_changed(); selection_item->poly_item_changed();
@ -260,31 +323,6 @@ public Q_SLOTS:
QApplication::restoreOverrideCursor(); QApplication::restoreOverrideCursor();
} }
private:
typedef boost::graph_traits<Face_graph>::vertex_descriptor vertex_descriptor;
template<class TriangleMesh>
typename boost::property_map<TriangleMesh, CGAL::dynamic_vertex_property_t<bool> >::type
get_border_constrained_map(TriangleMesh& tm)
{
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
typedef CGAL::dynamic_vertex_property_t<bool> Vertex_bool_property;
typename boost::property_map<TriangleMesh, Vertex_bool_property>::type vcm = get(Vertex_bool_property(), tm);
for(vertex_descriptor v : vertices(tm))
put(vcm, v, false);
for(halfedge_descriptor h : halfedges(tm))
{
if(CGAL::is_border(h, tm))
put(vcm, target(h, tm), true);
}
return vcm;
}
private: private:
QAction* actionSmoothing_; QAction* actionSmoothing_;
QDockWidget* dock_widget; QDockWidget* dock_widget;

View File

@ -6,154 +6,74 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>467</width> <width>518</width>
<height>315</height> <height>478</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Smoothing</string> <string>Smoothing</string>
</property> </property>
<widget class="QWidget" name="dockWidgetContents"> <widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QGridLayout" name="gridLayout_3">
<item> <item row="0" column="1">
<widget class="QGroupBox" name="Mesh_groupBox"> <widget class="QSpinBox" name="smooth_iter_spinBox">
<property name="title"> <property name="maximum">
<string>Mesh</string> <number>1000</number>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QPushButton" name="angle_button">
<property name="text">
<string>Angle Smoothing</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>#Iterations: </string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="angles_iter_spinBox"/>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="area_button">
<property name="text">
<string>Area Smoothing</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>#Iterations: </string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="areas_iter_spinBox"/>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="projection_checkBox">
<property name="text">
<string> Re-project Vertices</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Precision:</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="precision_spinBox">
<property name="decimals">
<number>7</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item row="9" column="0" colspan="2">
<widget class="QGroupBox" name="Shape_groupBox"> <widget class="QGroupBox" name="Shape_groupBox">
<property name="title"> <property name="title">
<string>Shape</string> <string>Shape Smoothing</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="1" column="2">
<widget class="QPushButton" name="curvature_flow_button"> <widget class="QDoubleSpinBox" name="time_step_spinBox">
<property name="text"> <property name="decimals">
<string>Smooth Along Curvature Flow</string> <number>6</number>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="2"> <item row="5" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>#Iterations: </string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="curvature_iter_spinBox"/>
</item>
</layout>
</item>
<item row="0" column="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="time_step_label">
<property name="text">
<string>Time Step:</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="time_step_spinBox">
<property name="decimals">
<number>6</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="explicit_checkBox"> <widget class="QCheckBox" name="explicit_checkBox">
<property name="text"> <property name="text">
<string>Use Normalized Scheme</string> <string>Use Explicit Scheme</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="6" column="2">
<widget class="QCheckBox" name="border_button"> <widget class="QPushButton" name="shape_smoothing_button">
<property name="text"> <property name="text">
<string>Constrain Border Vertices</string> <string>Smooth Shape</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="time_step_label">
<property name="text">
<string>Time Step:</string>
</property> </property>
</widget> </widget>
</item> </item>
</layout> </layout>
</widget> </widget>
</item> </item>
<item> <item row="2" column="0">
<widget class="QCheckBox" name="border_button">
<property name="text">
<string>Constrain Border Vertices</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="projection_checkBox">
<property name="text">
<string> Re-project Vertices</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
@ -166,6 +86,62 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Number of iterations</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QGroupBox" name="Mesh_groupBox">
<property name="title">
<string>Mesh Smoothing</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="3" column="1">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="area_smoothing_checkBox">
<property name="text">
<string>Use Area Smoothing</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="mesh_smoothing_button">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Smooth Mesh</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="angle_smoothing_checkBox">
<property name="text">
<string>Use Angle Smoothing</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</widget> </widget>