1 #include <QElapsedTimer>
2 #include <QApplication>
3 #include <QAction>
4 #include <QList>
5 #include <QMainWindow>
6 #include <QObject>
7
8 #include <fstream>
9
10 #include "Scene_polygon_soup_item.h"
11 #include "Scene_surface_mesh_item.h"
12 #include "Scene_points_with_normal_item.h"
13 #include "SMesh_type.h"
14 #include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
15 #include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
16
17 #include <CGAL/Real_timer.h>
18
19 #include "ui_Surface_reconstruction_plugin.h"
20 #include "CGAL/Kernel_traits.h"
21
22 typedef Kernel::Point_3 Point;
23 typedef Kernel::Vector_3 Vector;
24
25 SMesh* advancing_front (const Point_set& points,
26 double longest_edge,
27 double radius_ratio_bound,
28 double beta,
29 bool structuring,
30 double sampling);
31
32 SMesh* poisson_reconstruct (Point_set& points,
33 bool marching_tets,
34 Kernel::FT sm_angle, // Min triangle angle (degrees).
35 Kernel::FT sm_radius, // Max triangle size w.r.t. point set average spacing.
36 Kernel::FT sm_distance, // Approximation error w.r.t. point set average spacing.
37 bool conjugate_gradient,
38 bool use_two_passes,
39 bool do_not_fill_holes);
40
41 void scale_space (const Point_set& points,
42 std::vector<Scene_polygon_soup_item*>& items,
43 bool jet_smoother,
44 unsigned int iterations,
45 unsigned int neighbors, unsigned int fitting, unsigned int monge,
46 unsigned int neighborhood_size, unsigned int samples,
47 bool advancing_front_mesher,
48 bool generate_smooth,
49 double longest_edge, double radius_ratio_bound, double beta_angle,
50 bool separate_shells, bool force_manifold);
51
52 SMesh* polygonal_reconstruct (const Point_set& points,
53 double data_fitting,
54 double data_coverage,
55 double model_complexity,
56 const QString& solver_name);
57
58 class Polyhedron_demo_surface_reconstruction_plugin_dialog : public QDialog, private Ui::SurfaceReconstructionDialog
59 {
60 Q_OBJECT
61 public:
Polyhedron_demo_surface_reconstruction_plugin_dialog(QWidget * =nullptr)62 Polyhedron_demo_surface_reconstruction_plugin_dialog(QWidget* /*parent*/ = nullptr)
63 {
64 setupUi(this);
65 #if !defined(CGAL_USE_GLPK) && !defined(CGAL_USE_SCIP)
66 tabWidget->removeTab(3); // If no MIP solver is available, Polygonal method is disabled
67 #endif
68
69 #if defined(CGAL_USE_SCIP)
70 m_solver->addItem("SCIP");
71 #endif
72
73 #if defined(CGAL_USE_GLPK)
74 m_solver->addItem("GLPK");
75 #endif
76
77 }
78
method() const79 unsigned int method () const
80 {
81 return tabWidget->currentIndex();
82 }
83
disable_poisson()84 void disable_poisson()
85 {
86 tabWidget->setTabEnabled(1, false);
87 tabWidget->setTabToolTip(1, QString("Poisson requires oriented normals, please estimate normals first"));
88 }
89
disable_polygonal()90 void disable_polygonal()
91 {
92 tabWidget->setTabEnabled(3, false);
93 tabWidget->setTabToolTip(3, QString("Polygonal requires normals, please estimate normals first"));
94 }
95
96
disable_structuring()97 void disable_structuring()
98 {
99 m_use_structuring->setEnabled(false);
100 m_use_structuring->setToolTip(QString("Point Set Structuring requires detected planes, please detect shapes first"));
101 }
102
103 // Advancing front
longest_edge() const104 double longest_edge () const { return m_longestEdge->value (); }
radius_ratio_bound() const105 double radius_ratio_bound () const { return m_radiusRatioBound->value (); }
beta_angle() const106 double beta_angle () const { return m_betaAngle->value (); }
structuring() const107 bool structuring() const { return m_use_structuring->isChecked(); }
sampling() const108 double sampling () const { return m_sampling->value (); }
109
110 // Scale Space
scalespace_js() const111 bool scalespace_js() const { return m_scalespace_jet->isChecked(); }
iterations() const112 unsigned int iterations () const { return m_iterations->value (); }
neighbors() const113 unsigned int neighbors () const { return m_neighbors->value(); }
fitting() const114 unsigned int fitting () const { return m_fitting->value(); }
monge() const115 unsigned int monge () const { return m_monge->value(); }
neighborhood_size() const116 unsigned int neighborhood_size () const { return m_neighborhood_size->value (); }
samples() const117 unsigned int samples () const { return m_samples->value (); }
scalespace_af() const118 bool scalespace_af() const { return m_scalespace_af->isChecked(); }
generate_smoothed() const119 bool generate_smoothed () const { return m_genSmooth->isChecked (); }
longest_edge_2() const120 double longest_edge_2 () const { return m_longestEdge_2->value (); }
radius_ratio_bound_2() const121 double radius_ratio_bound_2 () const { return m_radiusRatioBound_2->value (); }
beta_angle_2() const122 double beta_angle_2 () const { return m_betaAngle_2->value (); }
separate_shells() const123 bool separate_shells () const { return m_genShells->isChecked (); }
force_manifold() const124 bool force_manifold () const { return m_forceManifold->isChecked (); }
125
126 // Poisson
marching_tets() const127 bool marching_tets() const { return m_marching_tets->isChecked(); }
angle() const128 double angle () const { return m_inputAngle->value (); }
radius() const129 double radius () const { return m_inputRadius->value (); }
distance() const130 double distance () const { return m_inputDistance->value (); }
conjugate_gradient() const131 bool conjugate_gradient() const { return m_conjugate_gradient->isChecked(); }
two_passes() const132 bool two_passes () const { return m_inputTwoPasses->isChecked (); }
do_not_fill_holes() const133 bool do_not_fill_holes () const { return m_doNotFillHoles->isChecked (); }
134
135 // Polygonal
data_fitting() const136 double data_fitting() const { return m_data_fitting->value(); }
data_coverage() const137 double data_coverage() const { return m_data_coverage->value(); }
model_complexity() const138 double model_complexity() const { return m_model_complexity->value(); }
solver_name() const139 QString solver_name() const { return m_solver->currentText(); }
140
141 };
142
143 class Polyhedron_demo_surface_reconstruction_plugin :
144 public QObject,
145 public CGAL::Three::Polyhedron_demo_plugin_helper
146 {
147 Q_OBJECT
148 Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
149
150 Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
151 QAction* actionSurfaceReconstruction;
152
153 public:
init(QMainWindow * mainWindow,CGAL::Three::Scene_interface * scene_interface,Messages_interface *)154 void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) {
155 scene = scene_interface;
156 mw = mainWindow;
157 actionSurfaceReconstruction = new QAction(tr("Surface Reconstruction"), mainWindow);
158 actionSurfaceReconstruction->setObjectName("actionSurfaceReconstruction");
159 autoConnectActions();
160
161 }
162
163 void advancing_front_reconstruction (const Polyhedron_demo_surface_reconstruction_plugin_dialog& dialog);
164 void scale_space_reconstruction (const Polyhedron_demo_surface_reconstruction_plugin_dialog& dialog);
165 void poisson_reconstruction (const Polyhedron_demo_surface_reconstruction_plugin_dialog& dialog);
166 void polygonal_reconstruction (const Polyhedron_demo_surface_reconstruction_plugin_dialog& dialog);
167
168 //! Applicate for Point_sets with normals.
applicable(QAction *) const169 bool applicable(QAction*) const {
170 return qobject_cast<Scene_points_with_normal_item*>(scene->item(scene->mainSelectionIndex()));
171 }
172
actions() const173 QList<QAction*> actions() const {
174 return QList<QAction*>() << actionSurfaceReconstruction;
175 }
176
177 private:
178
179 public Q_SLOTS:
180 void on_actionSurfaceReconstruction_triggered();
181 }; // end class Polyhedron_surface_reconstruction_plugin
182
183
on_actionSurfaceReconstruction_triggered()184 void Polyhedron_demo_surface_reconstruction_plugin::on_actionSurfaceReconstruction_triggered()
185 {
186 const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex();
187
188 Scene_points_with_normal_item* pts_item =
189 qobject_cast<Scene_points_with_normal_item*>(scene->item(index));
190
191 if(pts_item)
192 {
193 //generate the dialog box to set the options
194 Polyhedron_demo_surface_reconstruction_plugin_dialog dialog;
195 dialog.setWindowFlags(Qt::Dialog|Qt::CustomizeWindowHint|Qt::WindowCloseButtonHint);
196
197 if (!pts_item->point_set()->has_normal_map())
198 {
199 dialog.disable_poisson();
200 dialog.disable_polygonal();
201 }
202 if (!pts_item->point_set()->has_property_map<int> ("shape"))
203 {
204 dialog.disable_structuring();
205 dialog.disable_polygonal();
206 }
207
208 if(!dialog.exec())
209 return;
210
211 CGAL::Real_timer t;
212 t.start();
213 unsigned int method = dialog.method ();
214 switch (method)
215 {
216 case 0:
217 advancing_front_reconstruction (dialog);
218 break;
219 case 1:
220 poisson_reconstruction (dialog);
221 break;
222 case 2:
223 scale_space_reconstruction (dialog);
224 break;
225 case 3:
226 polygonal_reconstruction (dialog);
227 break;
228 default:
229 std::cerr << "Error: unkown method." << std::endl;
230 return;
231 }
232 std::cerr << "Reconstruction achieved in " << t.time() << "s" << std::endl;
233
234 }
235 }
236
advancing_front_reconstruction(const Polyhedron_demo_surface_reconstruction_plugin_dialog & dialog)237 void Polyhedron_demo_surface_reconstruction_plugin::advancing_front_reconstruction
238 (const Polyhedron_demo_surface_reconstruction_plugin_dialog& dialog)
239 {
240 const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex();
241
242 Scene_points_with_normal_item* pts_item =
243 qobject_cast<Scene_points_with_normal_item*>(scene->item(index));
244
245 if(pts_item)
246 {
247 // Gets point set
248 Point_set* points = pts_item->point_set();
249
250 // wait cursor
251 QApplication::setOverrideCursor(Qt::WaitCursor);
252
253 std::cerr << "Advancing front reconstruction... ";
254
255 // Reconstruct point set as a polyhedron
256 SMesh* mesh = advancing_front (*points,
257 dialog.longest_edge(),
258 dialog.radius_ratio_bound(),
259 CGAL_PI * dialog.beta_angle() / 180.,
260 dialog.structuring(),
261 dialog.sampling());
262 if (mesh)
263 {
264 // Add polyhedron to scene
265 Scene_surface_mesh_item* new_item = new Scene_surface_mesh_item(mesh);
266 new_item->setName(tr("%1 (advancing front)").arg(pts_item->name()));
267 new_item->setColor(Qt::darkGray);
268 new_item->invalidateOpenGLBuffers();
269 scene->addItem(new_item);
270
271 // Hide point set
272 pts_item->setVisible(false);
273 scene->itemChanged(index);
274 }
275
276 QApplication::restoreOverrideCursor();
277 }
278 }
279
280
scale_space_reconstruction(const Polyhedron_demo_surface_reconstruction_plugin_dialog & dialog)281 void Polyhedron_demo_surface_reconstruction_plugin::scale_space_reconstruction
282 (const Polyhedron_demo_surface_reconstruction_plugin_dialog& dialog)
283 {
284 const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex();
285
286 Scene_points_with_normal_item* pts_item =
287 qobject_cast<Scene_points_with_normal_item*>(scene->item(index));
288
289 if(pts_item)
290 {
291 // Gets point set
292 Point_set* points = pts_item->point_set();
293
294 // wait cursor
295 QApplication::setOverrideCursor(Qt::WaitCursor);
296
297 std::cout << "Scale scape surface reconstruction...";
298
299 std::vector<Scene_polygon_soup_item*> reco_items;
300
301 scale_space (*points, reco_items,
302 dialog.scalespace_js(),
303 dialog.iterations(),
304 dialog.neighbors(), dialog.fitting(), dialog.monge(),
305 dialog.neighborhood_size (), dialog.samples(),
306 dialog.scalespace_af(),
307 dialog.generate_smoothed (),
308 dialog.longest_edge_2(), dialog.radius_ratio_bound_2(),
309 CGAL_PI * dialog.beta_angle_2 () / 180.,
310 dialog.separate_shells (), dialog.force_manifold ());
311
312 for (std::size_t i = 0; i < reco_items.size (); ++ i)
313 {
314 if (!(dialog.scalespace_af()))
315 {
316 if (dialog.force_manifold () && i > reco_items.size () - 3)
317 {
318 if (dialog.generate_smoothed () && i % 2)
319 reco_items[i]->setName(tr("%1 (scale space smooth garbage)").arg(scene->item(index)->name()));
320 else
321 reco_items[i]->setName(tr("%1 (scale space garbage)").arg(scene->item(index)->name()));
322 }
323 else
324 {
325 if (dialog.generate_smoothed ())
326 {
327 if (i % 2)
328 reco_items[i]->setName(tr("%1 (scale space smooth shell %2)").arg(scene->item(index)->name()).arg((i+1)/2));
329 else
330 reco_items[i]->setName(tr("%1 (scale space shell %2)").arg(scene->item(index)->name()).arg(((i+1)/2)+1));
331 }
332 else
333 reco_items[i]->setName(tr("%1 (scale space shell %2)").arg(scene->item(index)->name()).arg(i+1));
334 }
335 }
336 else
337 {
338 if (dialog.generate_smoothed ())
339 {
340 if (i % 2)
341 reco_items[i]->setName(tr("%1 (scale space smooth)").arg(scene->item(index)->name()));
342 else
343 reco_items[i]->setName(tr("%1 (scale space)").arg(scene->item(index)->name()));
344 }
345 else
346 reco_items[i]->setName(tr("%1 (scale space)").arg(scene->item(index)->name()));
347 }
348 scene->addItem (reco_items[i]);
349 }
350
351 QApplication::restoreOverrideCursor();
352 }
353 }
354
355
poisson_reconstruction(const Polyhedron_demo_surface_reconstruction_plugin_dialog & dialog)356 void Polyhedron_demo_surface_reconstruction_plugin::poisson_reconstruction
357 (const Polyhedron_demo_surface_reconstruction_plugin_dialog& dialog)
358 {
359 const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex();
360
361 Scene_points_with_normal_item* point_set_item =
362 qobject_cast<Scene_points_with_normal_item*>(scene->item(index));
363
364 if(point_set_item)
365 {
366 // Gets point set
367 Point_set* points = point_set_item->point_set();
368 if(!points) return;
369
370 bool marching_tets = dialog.marching_tets();
371 const double sm_angle = dialog.angle ();
372 const double sm_radius = dialog.radius ();
373 const double sm_distance = dialog.distance ();
374 bool conjugate_gradient = dialog.conjugate_gradient();
375 bool use_two_passes = dialog.two_passes();
376 bool do_not_fill_holes = dialog.do_not_fill_holes();
377
378 QApplication::setOverrideCursor(Qt::WaitCursor);
379
380 // Reconstruct point set as a polyhedron
381 SMesh* mesh = poisson_reconstruct (*points, marching_tets,
382 sm_angle, sm_radius, sm_distance,
383 conjugate_gradient, use_two_passes,
384 do_not_fill_holes);
385 if (mesh)
386 {
387 // Add polyhedron to scene
388 Scene_surface_mesh_item* new_item = new Scene_surface_mesh_item(mesh);
389 new_item->setName(tr("%1 (poisson)").arg(point_set_item->name()));
390 new_item->setColor(Qt::darkGray);
391 scene->addItem(new_item);
392
393 // Hide point set
394 point_set_item->setVisible(false);
395 scene->itemChanged(index);
396 }
397
398 QApplication::restoreOverrideCursor();
399 }
400 }
401
polygonal_reconstruction(const Polyhedron_demo_surface_reconstruction_plugin_dialog & dialog)402 void Polyhedron_demo_surface_reconstruction_plugin::polygonal_reconstruction
403 (const Polyhedron_demo_surface_reconstruction_plugin_dialog& dialog)
404 {
405 const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex();
406
407 Scene_points_with_normal_item* point_set_item =
408 qobject_cast<Scene_points_with_normal_item*>(scene->item(index));
409
410 if(point_set_item)
411 {
412 // Gets point set
413 Point_set* points = point_set_item->point_set();
414 if(!points) return;
415
416 double data_fitting = dialog.data_fitting();
417 double data_coverage = dialog.data_coverage();
418 double model_complexity = dialog.model_complexity();
419 QString solver_name = dialog.solver_name();
420
421 double sum = data_fitting + data_coverage + model_complexity;
422 data_fitting /= sum;
423 data_coverage /= sum;
424 model_complexity /= sum;
425
426 std::cerr << "Polygonal reconstruction using:" << std::endl
427 << " * data fitting term = " << data_fitting << std::endl
428 << " * data coverage term = " << data_coverage << std::endl
429 << " * model complexity term = " << model_complexity << std::endl
430 << " * solver = " << solver_name.toStdString() << std::endl;
431
432 QApplication::setOverrideCursor(Qt::WaitCursor);
433
434 // Reconstruct point set as a polyhedron
435 SMesh* mesh = polygonal_reconstruct (*points,
436 data_fitting,
437 data_coverage,
438 model_complexity,
439 solver_name);
440 if (mesh)
441 {
442 // Add polyhedron to scene
443 Scene_surface_mesh_item* new_item = new Scene_surface_mesh_item(mesh);
444 new_item->setName(tr("%1 (polygonal)").arg(point_set_item->name()));
445 new_item->setColor(Qt::darkGray);
446 scene->addItem(new_item);
447
448 // Hide point set
449 point_set_item->setVisible(false);
450 scene->itemChanged(index);
451 }
452
453 QApplication::restoreOverrideCursor();
454 }
455 }
456
457 #include "Surface_reconstruction_plugin.moc"
458