ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
BasePclModule.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "BasePclModule.h"
9 
10 // CV_CORE_LIB
11 #include <CVPlatform.h>
12 
13 // CV_DB_LIB
14 #include <ecvDisplayTools.h>
15 #include <ecvHObjectCaster.h>
16 #include <ecvPointCloud.h>
17 
18 // app
19 #include <ecvMainAppInterface.h>
20 
21 // Qt
22 #include <qtconcurrentrun.h>
23 
24 #include <QAction>
25 #include <QApplication>
26 #include <QFuture>
27 #include <QProgressDialog>
28 
29 // system
30 #if defined(CV_WINDOWS)
31 #include "windows.h"
32 #else
33 #include <time.h>
34 #include <unistd.h>
35 #endif
36 
38  ccPluginInterface* parent_plugin)
39  : m_action(nullptr), m_desc(desc), m_show_progress(true) {
40  initAction();
41  m_parent_plugin = parent_plugin;
42 }
43 
45  if (m_action) return;
46 
47  m_action = new QAction(getIcon(), getEntryName(), this);
48  m_action->setStatusTip(getStatusTip());
49  // connect this action
50  connect(m_action, &QAction::triggered, this, &BasePclModule::performAction);
51 }
52 
53 void BasePclModule::throwError(int errCode) {
54  QString errMsg = getErrorMessage(errCode);
55 
56  // DGM: libraries shouldn't issue message themselves! The information should
57  // be sent to the plugin!
58  emit newErrorMessage(errMsg);
59 }
60 
62  const ccHObject::Container& selectedEntities) {
63  m_selected = selectedEntities;
64 
65  if (m_action) m_action->setEnabled(checkSelected() == 1);
66 }
67 
69  // check if selected entities are good
70  int check_result = checkSelected();
71  if (check_result != 1) {
72  throwError(check_result);
73  return check_result;
74  }
75 
76  // if dialog is needed open the dialog
77  int dialog_result = openInputDialog();
78  if (dialog_result < 1) {
79  if (dialog_result < 0)
80  throwError(dialog_result);
81  else
82  dialog_result = 1; // the operation is canceled by the user, no
83  // need to throw an error!
84  return dialog_result;
85  }
86 
87  // get the parameters from the dialog
89 
90  // are the given parameters ok?
91  int par_status = checkParameters();
92  if (par_status != 1) {
93  throwError(par_status);
94  return par_status;
95  }
96 
97  // if so go ahead with start()
98  int start_status = start();
99  if (start_status != 1) {
100  throwError(start_status);
101  return start_status;
102  }
103 
104  // if we have an output dialog is time to show it
105  int out_dialog_result = openOutputDialog();
106  if (out_dialog_result < 1) {
107  if (out_dialog_result < 0)
108  throwError(out_dialog_result);
109  else
110  out_dialog_result = 1; // the operation is canceled by the user, no
111  // need to throw an error!
112  return out_dialog_result; // maybe some module could ask the user if he
113  // wants to ac
114  }
115 
117  for (ccHObject* entity : m_selected) {
118  // clouds only
119  if (entity->isA(CV_TYPES::POINT_CLOUD) && entity->isGLTransEnabled()) {
121  if (cloud) {
122  // we temporarily detach entity, as it may undergo
123  //"severe" modifications (octree deletion, etc.) --> see
124  // ccHObject::applyRigidTransformation
128  m_app->putObjectBackIntoDBTree(cloud, objContext);
129  cloud->setRedrawFlagRecursive(true);
131  }
132  }
133  }
134  ecvDisplayTools::RedrawDisplay(false, true);
135 
136  return 1;
137 }
138 
140  // In most of the cases we just need 1 CC_POINT_CLOUD
141  if (m_selected.empty()) return -11;
142 
143  if (m_selected.size() != 1) return -12;
144 
145  if (!m_selected[0]->isA(CV_TYPES::POINT_CLOUD)) return -13;
146 
147  return 1;
148 }
149 
151 static int s_computeStatus = 0;
152 static bool s_computing = false;
153 static void doCompute() {
154  if (!s_module) {
155  s_computeStatus = -1;
156  return;
157  }
158 
160 }
161 
163  if (s_computing) {
164  throwError(-32);
165  return -1;
166  }
167 
168  QProgressDialog progressCb(tr("Operation in progress"), QString(), 0, 0);
169 
170  if (m_show_progress) {
171  progressCb.setWindowTitle(getModuleName());
172  progressCb.show();
173  QApplication::processEvents();
174  }
175 
176  s_computeStatus = -1;
177  s_module = this;
178  s_computing = true;
179  int progress = 0;
180 
181  QFuture<void> future = QtConcurrent::run(doCompute);
182  while (!future.isFinished()) {
183 #if defined(CV_WINDOWS)
184  ::Sleep(500);
185 #else
186  usleep(500 * 1000);
187 #endif
188  if (m_show_progress) progressCb.setValue(++progress);
189  }
190 
191  int is_ok = s_computeStatus;
192  s_module = 0;
193  s_computing = false;
194 
195  if (m_show_progress) {
196  progressCb.close();
197  QApplication::processEvents();
198  }
199 
200  if (is_ok < 0) {
201  throwError(is_ok);
202  // return -1;
203  }
204 
205  return 1;
206 }
207 
209 
211 
213 
214 QIcon BasePclModule::getIcon() const { return m_desc.m_icon; }
215 
216 QAction* BasePclModule::getAction() { return m_action; }
217 
218 QString BasePclModule::getErrorMessage(int errorCode) {
219  QString errorMsg;
220  switch (errorCode) {
221  // ERRORS RELATED TO SELECTION
222  case -11:
223  errorMsg = QString(tr("No entity selected in tree."));
224  break;
225 
226  case -12:
227  errorMsg = QString(tr("Too many entities selected."));
228  break;
229 
230  case -13:
231  errorMsg = QString(tr("Wrong type of entity selected"));
232  break;
233 
234  // ERRORS RELATED TO DIALOG
235  case -21:
236  errorMsg = QString(tr("Dialog was not correctly filled in"));
237  break;
238 
239  // ERRORS RELATED TO COMPUTATION
240  case -31:
241  errorMsg = QString(tr("Errors while computing"));
242  break;
243  case -32:
244  errorMsg = QString(tr("Thread already in use!"));
245  break;
246 
247  // DEFAULT
248  default:
249  errorMsg = tr("Undefined error in %1 module").arg(getModuleName());
250  break;
251  }
252 
253  return errorMsg;
254 }
255 
257  // does we have any selected entity?
258  if (m_selected.size() == 0) return nullptr;
259 
260  ccHObject* entity = m_selected.at(0);
261  if (!entity->isA(CV_TYPES::POINT_CLOUD)) return nullptr;
262 
263  return ccHObjectCaster::ToPointCloud(entity);
264 }
265 
267  // does we have any selected entity?
268  if (m_selected.size() == 0) return nullptr;
269 
270  return m_selected.at(0);
271 }
272 
274  const QString key) const {
275  ccHObject::Container new_sel;
276 
277  for (size_t i = 0; i < m_selected.size(); ++i) {
278  ccHObject* obj = m_selected.at(i);
279  if (obj->hasMetaData(key)) new_sel.push_back(obj);
280  }
281 
282  return new_sel;
283 }
284 
286  ccHObject::Container& entities) {
287  if (!m_app || !m_app->dbRootObject()) return;
288 
289  m_app->dbRootObject()->filterChildren(entities, true, type);
290 }
291 
293  QString key, ccHObject::Container& entities) {
294  entities.clear(); // better be sure
295  ccHObject::Container tempContainer;
297 
298  for (ccHObject::Container::const_iterator it = tempContainer.begin();
299  it != tempContainer.end(); ++it) {
300  if ((*it)->hasMetaData(key)) entities.push_back(*it);
301  }
302 }
303 
305  ccHObject::Container& entities) {
306  ccHObject::Container selected = m_selected;
307  for (size_t i = 0; i < selected.size(); ++i) {
308  ccHObject* this_obj = selected[i];
309  if (this_obj->isA(CV_TYPES::POINT_CLOUD)) {
310  entities.push_back(this_obj);
311  }
312  }
313 }
314 
316  ccHObject::Container& entities) {
317  ccHObject::Container selected = m_selected;
318  for (size_t i = 0; i < selected.size(); ++i) {
319  ccHObject* this_obj = selected[i];
320  if (this_obj->isA(kind)) {
321  entities.push_back(this_obj);
322  }
323  }
324 }
325 
326 int BasePclModule::hasSelectedScalarField(std::string field_name) {
328  if (!cloud) return -1;
329 
330  int result = cloud->getScalarFieldIndexByName(field_name.c_str());
331 
332  return (result >= 0 ? 1 : 0);
333 }
334 
336  if (isFirstSelectedCcPointCloud() != 1) return -1;
337 
339  if (!cloud) return -1;
340 
341  return (cloud->hasScalarFields() ? 1 : 0);
342 }
343 
345  std::vector<std::string> field_names;
346 
348  if (!cloud) return field_names;
349 
350  unsigned n_fields = cloud->getNumberOfScalarFields();
351  field_names.reserve(n_fields);
352  for (unsigned i = 0; i < n_fields; i++)
353  field_names.push_back(cloud->getScalarFieldName(i));
354 
355  return field_names;
356 }
357 
359  if (!m_selected.empty() && m_selected.at(0)->isA(CV_TYPES::POINT_CLOUD))
360  return 1;
361 
362  return -1;
363 }
364 
366  if (isFirstSelectedCcPointCloud() != 1) return -1;
367  // get the cloud
368 
369  ccPointCloud* cloud;
371 
372  return cloud->hasColors();
373 }
static bool s_computing
static int s_computeStatus
static void doCompute()
static BasePclModule * s_module
int64_t CV_CLASS_ENUM
Type of object type flags (64 bits)
Definition: CVTypes.h:97
char type
core::Tensor result
Definition: VtkUtils.cpp:76
Base abstract class for each implemented PCL filter.
Definition: BasePclModule.h:53
virtual void initAction()
Initializes the corresponding action.
std::vector< std::string > getSelectedAvailableScalarFields()
ccPluginInterface * m_parent_plugin
associated parent plugin of the filter
int hasSelectedRGB()
Returns 1 if the first selected entity has RGB info.
QAction * getAction()
Get the action associated with the button used in menu and toolbar creation.
QString getStatusTip() const
Returns the status tip.
void throwError(int errCode)
int isFirstSelectedCcPointCloud()
Returns 1 if the first selected object is a ccPointCloud.
virtual void updateSelectedEntities(const ccHObject::Container &selectedEntities)
Updates the internal copy of selected entities.
PclModuleDescription m_desc
Associated dialog.
QString getEntryName() const
Returns the entry name.
QString getModuleName() const
Returns the name of the filter.
virtual int checkParameters()
void getAllEntitiesThatHaveMetaData(QString key, ccHObject::Container &entities)
ccHObject::Container getSelectedThatHaveMetaData(const QString key) const
Get selected object that also have the provided metadata key.
virtual int openOutputDialog()
void getSelectedEntitiesThatAre(CV_CLASS_ENUM kind, ccHObject::Container &entities)
ecvMainAppInterface * m_app
Associated application interface.
virtual QString getErrorMessage(int errorCode)
Returns the error message corresponding to a given error code.
QAction * m_action
Forces the Ui to be updated.
virtual int compute()=0
Performs the actual filter job.
void getAllEntitiesOfType(CV_CLASS_ENUM type, ccHObject::Container &entities)
Returns all the objects in db tree of type "type".
int performAction()
Returns is called when the dialog window is accepted.
BasePclModule(PclModuleDescription desc=PclModuleDescription(), ccPluginInterface *parent_plugin=0)
Default constructor.
int hasSelectedScalarField()
Returns 1 if the first selected entity has at least one scalar field.
void newErrorMessage(QString)
Signal emitted when a new error message is produced.
virtual int start()
Starts computation.
void getSelectedEntitiesThatAreCCPointCloud(ccHObject::Container &entities)
get all entities that are selected and that also are cc_point_cloud
bool m_show_progress
Do we want to show a progress bar when the filter works?
ccPointCloud * getSelectedEntityAsCCPointCloud() const
Returns the first selected entity as a ccPointCloud.
QIcon getIcon() const
Returns the icon associated with the button.
ccHObject::Container m_selected
Pointer to the main window.
virtual int openInputDialog()
ccHObject * getSelectedEntityAsCCHObject() const
Returns the first selected entity as a ccHObject.
virtual void getParametersFromDialog()
Collects parameters from the filter dialog (if openDialog is successful)
virtual int checkSelected()
Checks if current selection is compliant with the filter.
static ccPointCloud * ToPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccPointCloud.
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
QString getViewId() const
Definition: ecvHObject.h:225
void applyGLTransformation_recursive(const ccGLMatrix *trans=nullptr)
Applies the active OpenGL transformation to the entity (recursive)
void setRedrawFlagRecursive(bool redraw=false)
unsigned filterChildren(Container &filteredChildren, bool recursive=false, CV_CLASS_ENUM filter=CV_TYPES::OBJECT, bool strict=false) const
Collects the children corresponding to a certain pattern.
std::vector< ccHObject * > Container
Standard instances container (for children, etc.)
Definition: ecvHObject.h:337
bool isA(CV_CLASS_ENUM type) const
Definition: ecvObject.h:131
bool hasMetaData(const QString &key) const
Returns whether a meta-data element with the given key exists or not.
Standard ECV plugin interface.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
bool hasColors() const override
Returns whether colors are enabled or not.
bool hasScalarFields() const override
Returns whether one or more scalar fields are instantiated.
int getScalarFieldIndexByName(const char *name) const
Returns the index of a scalar field represented by its name.
unsigned getNumberOfScalarFields() const
Returns the number of associated (and active) scalar fields.
const char * getScalarFieldName(int index) const
Returns the name of a specific scalar field.
static void SetRedrawRecursive(bool redraw=false)
static void RemoveBB(CC_DRAW_CONTEXT context)
static void RedrawDisplay(bool only2D=false, bool forceRedraw=true)
virtual ccHObject * dbRootObject()=0
Returns DB root (as a ccHObject)
virtual void putObjectBackIntoDBTree(ccHObject *obj, const ccHObjectContext &context)=0
Adds back object to DB tree.
virtual ccHObjectContext removeObjectTemporarilyFromDBTree(ccHObject *obj)=0
Removes object temporarily from DB tree.
@ HIERARCHY_OBJECT
Definition: CVTypes.h:103
@ POINT_CLOUD
Definition: CVTypes.h:104
void Sleep(int milliseconds)
Definition: Helper.cpp:278
PCL filter description.
Definition: BasePclModule.h:26
Backup "context" for an object.