ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
qPCV.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 "qPCV.h"
9 
10 #include "PCVCommand.h"
11 #include "ccPcvDlg.h"
12 
13 // CV_CORE_LIB
14 #include <PCV.h>
15 #include <ScalarField.h>
16 
17 // CV_DB_LIB
18 #include <ecvColorScalesManager.h>
19 #include <ecvGenericMesh.h>
20 #include <ecvGenericPointCloud.h>
21 #include <ecvHObjectCaster.h>
22 #include <ecvPointCloud.h>
23 #include <ecvProgressDialog.h>
24 #include <ecvScalarField.h>
25 
26 // Qt
27 #include <QMainWindow>
28 #include <QProgressBar>
29 
30 // persistent settings during a single session
31 static bool s_firstLaunch = true;
32 static int s_raysSpinBoxValue = 256;
33 static int s_resSpinBoxValue = 1024;
34 static bool s_mode180CheckBoxState = true;
35 static bool s_closedMeshCheckBoxState = false;
36 
37 qPCV::qPCV(QObject* parent /*=0*/)
38  : QObject(parent),
39  ccStdPluginInterface(":/CC/plugin/qPCV/info.json"),
40  m_action(nullptr) {}
41 
42 void qPCV::onNewSelection(const ccHObject::Container& selectedEntities) {
43  if (m_action) {
44  bool elligibleEntitiies = false;
45  for (ccHObject* obj : selectedEntities) {
46  if (obj && (obj->isKindOf(CV_TYPES::POINT_CLOUD) ||
47  obj->isKindOf(CV_TYPES::MESH))) {
48  elligibleEntitiies = true;
49  break;
50  }
51  }
52  m_action->setEnabled(elligibleEntitiies);
53  }
54 }
55 
56 QList<QAction*> qPCV::getActions() {
57  // default action
58  if (!m_action) {
59  m_action = new QAction(getName(), this);
60  m_action->setToolTip(getDescription());
61  m_action->setIcon(getIcon());
62  // connect signal
63  connect(m_action, &QAction::triggered, this, &qPCV::doAction);
64  }
65 
66  return QList<QAction*>{m_action};
67 }
68 
70  assert(m_app);
71  if (!m_app) return;
72 
73  const ccHObject::Container& selectedEntities = m_app->getSelectedEntities();
74 
75  ccHObject::Container candidates;
76  bool hasMeshes = false;
77  for (ccHObject* obj : selectedEntities) {
78  if (!obj) {
79  assert(false);
80  continue;
81  }
82 
83  if (obj->isA(CV_TYPES::POINT_CLOUD)) {
84  // we need a real point cloud
85  candidates.push_back(obj);
86  } else if (obj->isKindOf(CV_TYPES::MESH)) {
88  if (mesh->getAssociatedCloud() &&
90  // we need a mesh with a real point cloud
91  candidates.push_back(obj);
92  hasMeshes = true;
93  }
94  }
95  }
96 
98 
99  // restore previous dialog state
100  if (!s_firstLaunch) {
101  dlg.raysSpinBox->setValue(s_raysSpinBoxValue);
102  dlg.mode180CheckBox->setChecked(s_mode180CheckBoxState);
103  dlg.resSpinBox->setValue(s_resSpinBoxValue);
104  dlg.closedMeshCheckBox->setChecked(s_closedMeshCheckBoxState);
105  }
106 
107  dlg.closedMeshCheckBox->setEnabled(hasMeshes); // for meshes only
108 
109  // for using clouds normals as rays
110  std::vector<ccGenericPointCloud*> cloudsWithNormals;
111  ccHObject* root = m_app->dbRootObject();
112  if (root) {
113  ccHObject::Container clouds;
114  root->filterChildren(clouds, true, CV_TYPES::POINT_CLOUD);
115  for (size_t i = 0; i < clouds.size(); ++i) {
116  // we keep only clouds with normals
117  ccGenericPointCloud* cloud =
119  if (cloud && cloud->hasNormals()) {
120  cloudsWithNormals.push_back(cloud);
121  QString cloudTitle = QString("%1 - %2 points")
122  .arg(cloud->getName())
123  .arg(cloud->size());
124  if (cloud->getParent() &&
125  cloud->getParent()->isKindOf(CV_TYPES::MESH)) {
126  cloudTitle.append(QString(" (%1)").arg(
127  cloud->getParent()->getName()));
128  }
129 
130  dlg.cloudsComboBox->addItem(cloudTitle);
131  }
132  }
133  }
134  if (cloudsWithNormals.empty()) {
135  dlg.useCloudRadioButton->setEnabled(false);
136  }
137 
138  if (!dlg.exec()) {
139  return;
140  }
141 
142  // save dialog state
143  {
144  s_firstLaunch = false;
145  s_raysSpinBoxValue = dlg.raysSpinBox->value();
146  s_mode180CheckBoxState = dlg.mode180CheckBox->isChecked();
147  s_resSpinBoxValue = dlg.resSpinBox->value();
148  s_closedMeshCheckBoxState = dlg.closedMeshCheckBox->isChecked();
149  }
150 
151  unsigned raysNumber = dlg.raysSpinBox->value();
152  unsigned resolution = dlg.resSpinBox->value();
153  bool meshIsClosed =
154  (hasMeshes ? dlg.closedMeshCheckBox->isChecked() : false);
155  bool mode360 = !dlg.mode180CheckBox->isChecked();
156 
157  // PCV type ShadeVis
158  std::vector<CCVector3> rays;
159  if (!cloudsWithNormals.empty() && dlg.useCloudRadioButton->isChecked()) {
160  // Version with cloud normals as light rays
161  assert(dlg.cloudsComboBox->currentIndex() <
162  static_cast<int>(cloudsWithNormals.size()));
163  ccGenericPointCloud* pc =
164  cloudsWithNormals[dlg.cloudsComboBox->currentIndex()];
165  unsigned count = pc->size();
166  try {
167  rays.resize(count);
168  } catch (std::bad_alloc) {
170  "Not enough memory to generate the set of rays",
172  return;
173  }
174  for (unsigned i = 0; i < count; ++i) {
175  rays[i] = CCVector3(pc->getPointNormal(i));
176  }
177  } else {
178  // generates light directions
179  if (!PCV::GenerateRays(raysNumber, rays, mode360)) {
180  m_app->dispToConsole("Failed to generate the set of rays",
182  return;
183  }
184  }
185 
186  if (rays.empty()) {
187  assert(false);
188  m_app->dispToConsole("No ray was generated?!",
190  return;
191  }
192 
193  ecvProgressDialog pcvProgressCb(true, m_app->getMainWindow());
194  pcvProgressCb.setAutoClose(false);
195 
196  size_t count = 0;
197  for (ccHObject* obj : candidates) {
198  ccPointCloud* cloud = nullptr;
199  ccGenericMesh* mesh = nullptr;
200  QString objName = "unknown";
201 
202  assert(obj);
203  if (obj->isA(CV_TYPES::POINT_CLOUD)) {
204  // we need a real point cloud
205  cloud = ccHObjectCaster::ToPointCloud(obj);
206  objName = cloud->getName();
207  } else if (obj->isKindOf(CV_TYPES::MESH)) {
208  mesh = ccHObjectCaster::ToGenericMesh(obj);
210  objName = mesh->getName();
211  }
212  assert(cloud);
213 
214  // we get the PCV field if it already exists
216  // otherwise we create it
217  if (sfIdx < 0) {
218  sfIdx = cloud->addScalarField(CC_PCV_FIELD_LABEL_NAME);
219  }
220  if (sfIdx < 0) {
222  "Couldn't allocate a new scalar field for computing PCV "
223  "field ! Try to free some memory ...",
225  return;
226  }
227  cloud->setCurrentScalarField(sfIdx);
228 
229  QString objNameForPorgressDialog = objName;
230  if (candidates.size() > 1) {
231  objNameForPorgressDialog +=
232  QString("(%1/%2)").arg(++count).arg(candidates.size());
233  }
234 
235  bool wasEnabled = obj->isEnabled();
236  bool wasVisible = obj->isVisible();
237  obj->setEnabled(true);
238  obj->setVisible(true);
239  bool success = PCV::Launch(rays, cloud, mesh, meshIsClosed, resolution,
240  resolution, &pcvProgressCb,
241  objNameForPorgressDialog);
242  obj->setEnabled(wasEnabled);
243  obj->setVisible(wasVisible);
244 
245  if (!success) {
246  cloud->deleteScalarField(sfIdx);
248  tr("An error occurred during entity '%1' illumination!")
249  .arg(objName),
251  } else {
252  ccScalarField* sf =
253  static_cast<ccScalarField*>(cloud->getScalarField(sfIdx));
254  if (sf) {
255  sf->computeMinAndMax();
256  cloud->setCurrentDisplayedScalarField(sfIdx);
259  if (obj->hasNormals() && obj->normalsShown()) {
261  tr("Entity '%1' normals have been automatically "
262  "disabled")
263  .arg(objName),
265  }
266  obj->showNormals(false);
267  obj->showSF(true);
268  if (obj != cloud) {
269  cloud->showSF(true);
270  }
271  } else {
272  assert(false);
273  }
274  }
275 
276  if (pcvProgressCb.wasCanceled()) {
277  m_app->dispToConsole(tr("Process has been cancelled by the user"),
279  break;
280  }
281  }
282 
283  pcvProgressCb.close();
284 
285  // currently selected entities parameters may have changed!
286  m_app->updateUI();
287  // currently selected entities appearance may have changed!
289 }
290 
292  cmd->registerCommand(
294 }
Vector3Tpl< PointCoordinateType > CCVector3
Default 3D Vector.
Definition: CVGeom.h:798
int count
constexpr char CC_PCV_FIELD_LABEL_NAME[]
Definition: PCVCommand.cpp:21
static bool GenerateRays(unsigned numberOfRays, std::vector< CCVector3 > &rays, bool mode360=true)
Generates a given number of rays.
Definition: PCV.cpp:159
static int Launch(unsigned numberOfRays, cloudViewer::GenericCloud *vertices, cloudViewer::GenericMesh *mesh=nullptr, bool meshIsClosed=false, bool mode360=true, unsigned width=1024, unsigned height=1024, cloudViewer::GenericProgressCallback *progressCb=nullptr, QString entityName=QString())
static ccColorScale::Shared GetDefaultScale(DEFAULT_SCALES scale=BGYR)
Returns a pre-defined color scale (static shortcut)
Command line interface.
virtual bool registerCommand(Command::Shared command)=0
Registers a new command.
virtual QString getName() const override
Returns (short) name (for menu entry, etc.)
virtual QString getDescription() const override
Returns long name/description (for tooltip, etc.)
virtual QIcon getIcon() const override
Returns icon.
virtual bool hasNormals() const
Returns whether normals are enabled or not.
virtual void showSF(bool state)
Sets active scalarfield visibility.
Generic mesh interface.
virtual ccGenericPointCloud * getAssociatedCloud() const =0
Returns the vertices cloud.
A 3D cloud interface with associated features (color, normals, octree, etc.)
virtual const CCVector3 & getPointNormal(unsigned pointIndex) const =0
Returns normal corresponding to a given point.
static ccPointCloud * ToPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccPointCloud.
static ccGenericPointCloud * ToGenericPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccGenericPointCloud.
static ccGenericMesh * ToGenericMesh(ccHObject *obj)
Converts current object to ccGenericMesh (if possible)
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
ccHObject * getParent() const
Returns parent object.
Definition: ecvHObject.h:245
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
virtual QString getName() const
Returns object name.
Definition: ecvObject.h:72
bool isA(CV_CLASS_ENUM type) const
Definition: ecvObject.h:131
bool isKindOf(CV_CLASS_ENUM type) const
Definition: ecvObject.h:128
Dialog for the PCV plugin.
Definition: ccPcvDlg.h:13
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void setCurrentDisplayedScalarField(int index)
Sets the currently displayed scalar field.
int addScalarField(const char *uniqueName) override
Creates a new scalar field and registers it.
void deleteScalarField(int index) override
Deletes a specific scalar field.
A scalar field associated to display-related parameters.
void setColorScale(ccColorScale::Shared scale)
Sets associated color scale.
void computeMinAndMax() override
Determines the min and max values.
Standard ECV plugin interface.
ecvMainAppInterface * m_app
Main application interface.
virtual unsigned size() const =0
Returns the number of points.
int getScalarFieldIndexByName(const char *name) const
Returns the index of a scalar field represented by its name.
ScalarField * getScalarField(int index) const
Returns a pointer to a specific scalar field.
void setCurrentScalarField(int index)
Sets both the INPUT & OUTPUT scalar field.
virtual void updateUI()=0
virtual ccHObject * dbRootObject()=0
Returns DB root (as a ccHObject)
virtual QMainWindow * getMainWindow()=0
Returns main window.
virtual void refreshSelected(bool only2D=false, bool forceRedraw=true)=0
virtual const ccHObject::Container & getSelectedEntities() const =0
Returns currently selected entities ("read only")
virtual void dispToConsole(QString message, ConsoleMessageLevel level=STD_CONSOLE_MESSAGE)=0
Graphical progress indicator (thread-safe)
virtual QList< QAction * > getActions() override
Get a list of actions for this plugin.
Definition: qPCV.cpp:56
void doAction()
Slot called when associated ation is triggered.
Definition: qPCV.cpp:69
QAction * m_action
Associated action.
Definition: qPCV.h:44
qPCV(QObject *parent=nullptr)
Default constructor.
Definition: qPCV.cpp:37
virtual void onNewSelection(const ccHObject::Container &selectedEntities) override
Definition: qPCV.cpp:42
virtual void registerCommands(ccCommandLineInterface *cmd) override
Optional: registers commands (for the command line mode)
Definition: qPCV.cpp:291
@ MESH
Definition: CVTypes.h:105
@ POINT_CLOUD
Definition: CVTypes.h:104
static bool s_closedMeshCheckBoxState
Definition: qPCV.cpp:35
static bool s_firstLaunch
Definition: qPCV.cpp:31
static bool s_mode180CheckBoxState
Definition: qPCV.cpp:34
static int s_resSpinBoxValue
Definition: qPCV.cpp:33
static int s_raysSpinBoxValue
Definition: qPCV.cpp:32
QSharedPointer< Command > Shared
Shared type.