1 #include "config.h"
2 #include "Scene_points_with_normal_item.h"
3 #include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
4 #include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
5 
6 #include <CGAL/grid_simplify_point_set.h>
7 #include <CGAL/random_simplify_point_set.h>
8 #include <CGAL/hierarchy_simplify_point_set.h>
9 #include <CGAL/compute_average_spacing.h>
10 #include <CGAL/Timer.h>
11 #include <CGAL/Memory_sizer.h>
12 
13 #include <QObject>
14 #include <QAction>
15 #include <QMainWindow>
16 #include <QApplication>
17 #include <QtPlugin>
18 #include <QMessageBox>
19 
20 #include "run_with_qprogressdialog.h"
21 
22 #include "ui_Point_set_simplification_plugin.h"
23 
24 // Concurrency
25 typedef CGAL::Parallel_if_available_tag Concurrency_tag;
26 
27 struct Compute_average_spacing_functor
28   : public Functor_with_signal_callback
29 {
30   Point_set* points;
31   const int nb_neighbors;
32   boost::shared_ptr<double> result;
33 
Compute_average_spacing_functorCompute_average_spacing_functor34   Compute_average_spacing_functor (Point_set* points, const int nb_neighbors)
35     : points (points), nb_neighbors (nb_neighbors), result (new double(0)) { }
36 
operator ()Compute_average_spacing_functor37   void operator()()
38   {
39     *result = CGAL::compute_average_spacing<Concurrency_tag>(
40       points->all_or_selection_if_not_empty(),
41       nb_neighbors,
42       points->parameters().
43       callback (*(this->callback())));
44   }
45 };
46 
47 struct Grid_simplify_functor
48   : public Functor_with_signal_callback
49 {
50   Point_set* points;
51   double grid_size;
52   boost::shared_ptr<Point_set::iterator> result;
53 
Grid_simplify_functorGrid_simplify_functor54   Grid_simplify_functor (Point_set* points, double grid_size)
55     : points (points), grid_size (grid_size), result (new Point_set::iterator) { }
56 
operator ()Grid_simplify_functor57   void operator()()
58   {
59     *result = CGAL::grid_simplify_point_set(*points,
60                                             grid_size,
61                                             points->parameters().
62                                             callback (*(this->callback())));
63   }
64 };
65 
66 struct Hierarchy_simplify_functor
67   : public Functor_with_signal_callback
68 {
69   Point_set* points;
70   unsigned int max_cluster_size;
71   double max_surface_variation;
72   boost::shared_ptr<Point_set::iterator> result;
73 
Hierarchy_simplify_functorHierarchy_simplify_functor74   Hierarchy_simplify_functor (Point_set* points,
75                               double max_cluster_size,
76                               double max_surface_variation)
77     : points (points), max_cluster_size (max_cluster_size)
78     , max_surface_variation (max_surface_variation), result (new Point_set::iterator) { }
79 
operator ()Hierarchy_simplify_functor80   void operator()()
81   {
82     *result = CGAL::hierarchy_simplify_point_set(*points,
83                                                  points->parameters().
84                                                  size(max_cluster_size).
85                                                  maximum_variation(max_surface_variation).
86                                                  callback (*(this->callback())));
87   }
88 };
89 
90 using namespace CGAL::Three;
91 class Polyhedron_demo_point_set_simplification_plugin :
92   public QObject,
93   public Polyhedron_demo_plugin_helper
94 {
95   Q_OBJECT
96   Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
97   Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
98 
99   QAction* actionSimplify;
100 
101 public:
init(QMainWindow * mainWindow,CGAL::Three::Scene_interface * scene_interface,Messages_interface *)102   void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface,Messages_interface*) {
103     scene = scene_interface;
104     mw = mainWindow;
105     actionSimplify = new QAction(tr("Simplification Selection"), mainWindow);
106     actionSimplify->setProperty("subMenuName","Point Set Processing");
107 
108     actionSimplify->setObjectName("actionSimplify");
109     autoConnectActions();
110   }
111 
applicable(QAction *) const112   bool applicable(QAction*) const {
113     return qobject_cast<Scene_points_with_normal_item*>(scene->item(scene->mainSelectionIndex()));
114   }
115 
actions() const116   QList<QAction*> actions() const {
117     return QList<QAction*>() << actionSimplify;
118   }
119 
120 public Q_SLOTS:
121   void on_actionSimplify_triggered();
122 
123 
124 }; // end Polyhedron_demo_point_set_simplification_plugin
125 
126 class Point_set_demo_point_set_simplification_dialog : public QDialog, private Ui::PointSetSimplificationDialog
127 {
128   Q_OBJECT
129   public:
Point_set_demo_point_set_simplification_dialog(QWidget * =nullptr)130     Point_set_demo_point_set_simplification_dialog(QWidget * /*parent*/ = nullptr)
131     {
132       setupUi(this);
133       m_maximumSurfaceVariation->setRange(0.000010, 0.33330);
134     }
135 
simplificationMethod() const136   unsigned int simplificationMethod() const
137   {
138     if (Random->isChecked())
139       return 0;
140     else if (Grid->isChecked())
141       return 1;
142     else
143       return 2;
144   }
randomSimplificationPercentage() const145   double randomSimplificationPercentage() const { return m_randomSimplificationPercentage->value(); }
gridCellSize() const146   double gridCellSize() const { return m_gridCellSize->value(); }
maximumClusterSize() const147   unsigned int maximumClusterSize() const { return m_maximumClusterSize->value(); }
maximumSurfaceVariation() const148   double maximumSurfaceVariation() const { return m_maximumSurfaceVariation->value(); }
149 
150 public Q_SLOTS:
151 
on_Random_toggled(bool toggled)152   void on_Random_toggled (bool toggled)
153   {
154     m_randomSimplificationPercentage->setEnabled (toggled);
155     m_gridCellSize->setEnabled (!toggled);
156     m_maximumClusterSize->setEnabled (!toggled);
157     m_maximumSurfaceVariation->setEnabled (!toggled);
158   }
on_Grid_toggled(bool toggled)159   void on_Grid_toggled (bool toggled)
160   {
161     m_randomSimplificationPercentage->setEnabled (!toggled);
162     m_gridCellSize->setEnabled (toggled);
163     m_maximumClusterSize->setEnabled (!toggled);
164     m_maximumSurfaceVariation->setEnabled (!toggled);
165   }
on_Hierarchy_toggled(bool toggled)166   void on_Hierarchy_toggled (bool toggled)
167   {
168     m_randomSimplificationPercentage->setEnabled (!toggled);
169     m_gridCellSize->setEnabled (!toggled);
170     m_maximumClusterSize->setEnabled (toggled);
171     m_maximumSurfaceVariation->setEnabled (toggled);
172   }
173 
174 };
175 
on_actionSimplify_triggered()176 void Polyhedron_demo_point_set_simplification_plugin::on_actionSimplify_triggered()
177 {
178   const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex();
179 
180   Scene_points_with_normal_item* item =
181     qobject_cast<Scene_points_with_normal_item*>(scene->item(index));
182 
183   if(item)
184   {
185     // Gets point set
186     Point_set* points = item->point_set();
187     if(points == nullptr)
188         return;
189 
190     // Gets options
191     Point_set_demo_point_set_simplification_dialog dialog;
192     if(!dialog.exec())
193       return;
194 
195     QApplication::setOverrideCursor(Qt::BusyCursor);
196 
197     CGAL::Timer task_timer; task_timer.start();
198 
199     // First point to delete
200     Point_set::iterator first_point_to_remove = points->end();
201 
202     unsigned int method = dialog.simplificationMethod ();
203     if (method == 0)
204     {
205       std::cerr << "Point set random simplification (" << dialog.randomSimplificationPercentage() <<"%)...\n";
206 
207       // Computes points to remove by random simplification
208       first_point_to_remove =
209         CGAL::random_simplify_point_set(*points,
210                                         dialog.randomSimplificationPercentage());
211     }
212     else if (method == 1)
213     {
214       std::cerr << "Point set grid simplification (cell size = " << dialog.gridCellSize() <<" * average spacing)...\n";
215 
216       // Computes average spacing
217       Compute_average_spacing_functor functor_as (points, 6);
218       run_with_qprogressdialog (functor_as, "Simplification: computing average spacing...", mw);
219 
220       double average_spacing = *functor_as.result;
221 
222       Grid_simplify_functor functor (points, dialog.gridCellSize() * average_spacing);
223       run_with_qprogressdialog<CGAL::Sequential_tag> (functor, "Grid simplyfing...", mw);
224 
225       // Computes points to remove by Grid Clustering
226       first_point_to_remove = *functor.result;
227 
228     }
229     else
230     {
231       std::cerr << "Point set hierarchy simplification (cluster size = " << dialog.maximumClusterSize()
232                 << ", maximum variation = " << dialog.maximumSurfaceVariation() << ")...\n";
233 
234       // Computes points to remove by Hierarchy
235       Hierarchy_simplify_functor functor (points, dialog.maximumClusterSize(),
236                                           dialog.maximumSurfaceVariation());
237       run_with_qprogressdialog<CGAL::Sequential_tag> (functor, "Hierarchy simplyfing...", mw);
238 
239       first_point_to_remove = *functor.result;
240 
241     }
242 
243     std::size_t nb_points_to_remove = std::distance(first_point_to_remove, points->end());
244     std::size_t memory = CGAL::Memory_sizer().virtual_size();
245     std::cerr << "Simplification: " << nb_points_to_remove << " point(s) are selected for removal ("
246                                     << task_timer.time() << " seconds, "
247                                     << (memory>>20) << " Mb allocated)"
248                                     << std::endl;
249 
250     // Selects points to delete
251     points->set_first_selected(first_point_to_remove);
252 
253     // Updates scene
254     item->invalidateOpenGLBuffers();
255     scene->itemChanged(index);
256 
257     QApplication::restoreOverrideCursor();
258 
259     // Warns user
260     if (nb_points_to_remove > 0)
261     {
262       QMessageBox::information(nullptr,
263                                tr("Points selected for removal"),
264                                tr("%1 point(s) are selected for removal.\nYou may delete or reset the selection using the item context menu.")
265                                .arg(nb_points_to_remove));
266     }
267   }
268 }
269 
270 #include "Point_set_simplification_plugin.moc"
271