1 #include <QtCore/qglobal.h>
2 
3 #include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
4 #include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
5 
6 #include <CGAL/iterator.h>
7 #include <CGAL/utility.h>
8 #include <CGAL/property_map.h>
9 #include <CGAL/Surface_mesh.h>
10 
11 #include <CGAL/Polygon_mesh_processing/smooth_mesh.h>
12 #include <CGAL/Polygon_mesh_processing/smooth_shape.h>
13 
14 #include "Scene.h"
15 #include "Scene_surface_mesh_item.h"
16 #include "Scene_polyhedron_selection_item.h"
17 
18 #include "ui_Smoothing_plugin.h"
19 
20 #include <QElapsedTimer>
21 #include <QAction>
22 #include <QMainWindow>
23 #include <QApplication>
24 #include <QDockWidget>
25 #include <QString>
26 #include <QInputDialog>
27 #include <QtPlugin>
28 #include <QMessageBox>
29 
30 using namespace CGAL::Polygon_mesh_processing;
31 using namespace CGAL::Three;
32 
33 typedef Scene_surface_mesh_item                                     Scene_face_graph_item;
34 typedef Scene_face_graph_item::Face_graph                           Face_graph;
35 
36 typedef boost::graph_traits<Face_graph>::vertex_descriptor          vertex_descriptor;
37 typedef boost::graph_traits<Face_graph>::edge_descriptor            edge_descriptor;
38 typedef boost::graph_traits<Face_graph>::face_descriptor            face_descriptor;
39 
40 typedef CGAL::dynamic_vertex_property_t<bool>                       Vertex_bool_property;
41 typedef typename boost::property_map<Face_graph, Vertex_bool_property>::type VCMap;
42 
43 class Polyhedron_demo_smothing_plugin
44   : public QObject, public Polyhedron_demo_plugin_helper
45 {
46   Q_OBJECT
47   Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
48   Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
49 
50 public:
init(QMainWindow * mainWindow,Scene_interface * scene_interface,Messages_interface *)51   void init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*)
52   {
53     scene = scene_interface;
54     mw = mainWindow;
55 
56     actionSmoothing_ = new QAction(tr("Mesh and Shape Smoothing"), mw);
57     actionSmoothing_->setProperty("subMenuName", "Polygon Mesh Processing");
58 
59     connect(actionSmoothing_, SIGNAL(triggered()), this, SLOT(smoothing_action()));
60 
61     dock_widget = new QDockWidget("Smoothing", mw);
62     dock_widget->setVisible(false);
63 
64     ui_widget.setupUi(dock_widget);
65     addDockWidget(dock_widget);
66 
67     connect(ui_widget.area_smoothing_checkBox, SIGNAL(toggled(bool)),
68             ui_widget.flip_checkBox, SLOT(setEnabled(bool)));
69 
70     connect(ui_widget.mesh_smoothing_button,  SIGNAL(clicked()), this, SLOT(on_mesh_smoothing_clicked()));
71     connect(ui_widget.shape_smoothing_button,  SIGNAL(clicked()), this, SLOT(on_shape_smoothing_clicked()));
72   }
73 
actions() const74   QList<QAction*> actions() const
75   {
76     return QList<QAction*>() << actionSmoothing_;
77   }
78 
applicable(QAction *) const79   bool applicable(QAction*) const
80   {
81     const Scene_interface::Item_id index = scene->mainSelectionIndex();
82     if(qobject_cast<Scene_face_graph_item*>(scene->item(index)))
83       return true;
84     else if(qobject_cast<Scene_polyhedron_selection_item*>(scene->item(index)))
85       return true;
86     else
87       return false;
88   }
89 
closure()90   virtual void closure()
91   {
92     dock_widget->hide();
93   }
94 
init_ui()95   void init_ui()
96   {
97     ui_widget.time_step_spinBox->setValue(0.00001);
98     ui_widget.time_step_spinBox->setMinimum(1e-6);
99 
100     ui_widget.smooth_iter_spinBox->setValue(1);
101     ui_widget.projection_checkBox->setChecked(true);
102 
103     ui_widget.area_smoothing_checkBox->setChecked(false);
104     ui_widget.flip_checkBox->setDisabled(true);
105   }
106 
mark_border_vertices(const VCMap vcmap,const Face_graph & pmesh) const107   void mark_border_vertices(const VCMap vcmap, const Face_graph& pmesh) const
108   {
109     for(halfedge_descriptor h : halfedges(pmesh))
110     {
111       if(CGAL::is_border(h, pmesh))
112         put(vcmap, target(h, pmesh), true);
113     }
114   }
115 
mark_selected_vertices(const VCMap vcmap,const Face_graph & pmesh,Scene_polyhedron_selection_item * selection_item) const116   void mark_selected_vertices(const VCMap vcmap,
117                               const Face_graph& pmesh,
118                               Scene_polyhedron_selection_item* selection_item) const
119   {
120     for(vertex_descriptor v : selection_item->selected_vertices)
121       put(vcmap, v, true);
122 
123     for(edge_descriptor e : selection_item->selected_edges)
124     {
125       put(vcmap, source(e, pmesh), true);
126       put(vcmap, target(e, pmesh), true);
127     }
128   }
129 
130 public Q_SLOTS:
smoothing_action()131   void smoothing_action()
132   {
133     dock_widget->show();
134     dock_widget->raise();
135 
136     const Scene_interface::Item_id index = scene->mainSelectionIndex();
137     Scene_face_graph_item* poly_item = qobject_cast<Scene_face_graph_item*>(scene->item(index));
138 
139     Scene_polyhedron_selection_item* selection_item =
140         qobject_cast<Scene_polyhedron_selection_item*>(scene->item(index));
141 
142     if(poly_item || selection_item)
143     {
144       init_ui();
145     }
146   }
147 
on_mesh_smoothing_clicked()148   void on_mesh_smoothing_clicked()
149   {
150     const Scene_interface::Item_id index = scene->mainSelectionIndex();
151     Scene_face_graph_item* poly_item = qobject_cast<Scene_face_graph_item*>(scene->item(index));
152     Scene_polyhedron_selection_item* selection_item = qobject_cast<Scene_polyhedron_selection_item*>(scene->item(index));
153 
154     if(!poly_item && !selection_item)
155       return;
156 
157     Face_graph& pmesh = (poly_item != nullptr) ? * poly_item->polyhedron() : * selection_item->polyhedron();
158 
159     const unsigned int nb_iter = ui_widget.smooth_iter_spinBox->value();
160     const bool projection = ui_widget.projection_checkBox->isChecked();
161     const bool use_safety_measures = ui_widget.sanity_checkBox->isChecked();
162     const bool constrain_border_vertices = ui_widget.border_button->isChecked() && !CGAL::is_closed(pmesh);
163     const bool use_angle_smoothing = ui_widget.angle_smoothing_checkBox->isChecked();
164     const bool use_area_smoothing = ui_widget.area_smoothing_checkBox->isChecked();
165     const bool use_Delaunay_flips = ui_widget.flip_checkBox->isChecked();
166 
167     QApplication::setOverrideCursor(Qt::WaitCursor);
168 
169     VCMap vcmap = get(Vertex_bool_property(), pmesh);
170     for(vertex_descriptor v : vertices(pmesh))
171       put(vcmap, v, false);
172 
173     if(constrain_border_vertices)
174       mark_border_vertices(vcmap, pmesh);
175 
176     if(poly_item)
177     {
178       smooth_mesh(pmesh, parameters::do_project(projection)
179                                     .number_of_iterations(nb_iter)
180                                     .vertex_is_constrained_map(vcmap)
181                                     .use_safety_constraints(use_safety_measures)
182                                     .use_angle_smoothing(use_angle_smoothing)
183                                     .use_area_smoothing(use_area_smoothing)
184                                     .use_Delaunay_flips(use_Delaunay_flips));
185 
186       poly_item->invalidateOpenGLBuffers();
187       poly_item->itemChanged();
188     }
189     else if(selection_item)
190     {
191       mark_selected_vertices(vcmap, pmesh, selection_item);
192 
193       // No faces selected --> use all faces
194       if(std::begin(selection_item->selected_facets) == std::end(selection_item->selected_facets))
195       {
196         smooth_mesh(pmesh, parameters::do_project(projection)
197                                       .number_of_iterations(nb_iter)
198                                       .vertex_is_constrained_map(vcmap)
199                                       .edge_is_constrained_map(selection_item->constrained_edges_pmap())
200                                       .use_safety_constraints(use_safety_measures)
201                                       .use_angle_smoothing(use_angle_smoothing)
202                                       .use_area_smoothing(use_area_smoothing)
203                                       .use_Delaunay_flips(use_Delaunay_flips));
204       }
205       else // some faces exist in the selection
206       {
207         smooth_mesh(selection_item->selected_facets, pmesh, parameters::do_project(projection)
208                                                                        .number_of_iterations(nb_iter)
209                                                                        .vertex_is_constrained_map(vcmap)
210                                                                        .edge_is_constrained_map(selection_item->constrained_edges_pmap())
211                                                                        .use_safety_constraints(use_safety_measures)
212                                                                        .use_angle_smoothing(use_angle_smoothing)
213                                                                        .use_area_smoothing(use_area_smoothing)
214                                                                        .use_Delaunay_flips(use_Delaunay_flips));
215       }
216 
217       selection_item->poly_item_changed();
218       selection_item->changed_with_poly_item();
219     }
220 
221     QApplication::restoreOverrideCursor();
222   }
223 
on_shape_smoothing_clicked()224   void on_shape_smoothing_clicked()
225   {
226     const Scene_interface::Item_id index = scene->mainSelectionIndex();
227     Scene_face_graph_item* poly_item = qobject_cast<Scene_face_graph_item*>(scene->item(index));
228     Scene_polyhedron_selection_item* selection_item = qobject_cast<Scene_polyhedron_selection_item*>(scene->item(index));
229 
230     if(!poly_item && !selection_item)
231       return;
232 
233     Face_graph& pmesh = (poly_item != nullptr) ? * poly_item->polyhedron() : * selection_item->polyhedron();
234 
235     const double time_step = ui_widget.time_step_spinBox->value();
236     const unsigned int nb_iter = ui_widget.smooth_iter_spinBox->value();
237 
238     const bool constrain_border_vertices = ui_widget.border_button->isChecked() && !CGAL::is_closed(pmesh);
239 
240     QApplication::setOverrideCursor(Qt::WaitCursor);
241 
242     VCMap vcmap = get(Vertex_bool_property(), pmesh);
243     for(vertex_descriptor v : vertices(pmesh))
244       put(vcmap, v, false);
245 
246     if(constrain_border_vertices)
247       mark_border_vertices(vcmap, pmesh);
248 
249     if(poly_item)
250     {
251       smooth_shape(pmesh, time_step, parameters::number_of_iterations(nb_iter)
252                                                 .vertex_is_constrained_map(vcmap));
253 
254       poly_item->invalidateOpenGLBuffers();
255       poly_item->itemChanged();
256     }
257     else if(selection_item)
258     {
259       mark_selected_vertices(vcmap, pmesh, selection_item);
260 
261       if(std::begin(selection_item->selected_facets) == std::end(selection_item->selected_facets))
262       {
263         smooth_shape(pmesh, time_step, parameters::number_of_iterations(nb_iter)
264                                                   .vertex_is_constrained_map(vcmap));
265       }
266       else
267       {
268         smooth_shape(selection_item->selected_facets, pmesh, time_step,
269                      parameters::number_of_iterations(nb_iter)
270                                 .vertex_is_constrained_map(vcmap));
271       }
272 
273       selection_item->poly_item_changed();
274       selection_item->changed_with_poly_item();
275     }
276     else
277     {
278       std::cerr << "Something's gone wrong.\n";
279       CGAL_assertion(false);
280     }
281 
282     QApplication::restoreOverrideCursor();
283   }
284 
285 private:
286   QAction* actionSmoothing_;
287   QDockWidget* dock_widget;
288   Ui::Smoothing ui_widget;
289 };
290 
291 #include "Smoothing_plugin.moc"
292