ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
PCVCommand.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 "PCVCommand.h"
9 
10 #include "PCV.h"
11 #include "qPCV.h"
12 
13 // qCC_db
14 #include <ecvColorScalesManager.h>
15 #include <ecvGenericMesh.h>
16 #include <ecvHObjectCaster.h>
17 #include <ecvPointCloud.h>
18 #include <ecvProgressDialog.h>
19 #include <ecvScalarField.h>
20 
21 constexpr char CC_PCV_FIELD_LABEL_NAME[] = "Illuminance (PCV)";
22 
23 constexpr char COMMAND_PCV[] = "PCV";
24 constexpr char COMMAND_PCV_N_RAYS[] = "N_RAYS";
25 constexpr char COMMAND_PCV_IS_CLOSED[] = "IS_CLOSED";
26 constexpr char COMMAND_PCV_180[] = "180";
27 constexpr char COMMAND_PCV_RESOLUTION[] = "RESOLUTION";
28 
29 PCVCommand::PCVCommand() : Command("PCV", COMMAND_PCV) {}
30 
32  const std::vector<CCVector3>& rays,
33  bool meshIsClosed,
34  unsigned resolution,
35  ecvProgressDialog* progressDlg /*=nullptr*/,
36  ecvMainAppInterface* app /*=nullptr*/) {
37  size_t count = 0;
38  size_t errorCount = 0;
39 
40  for (ccHObject* obj : candidates) {
41  ccPointCloud* cloud = nullptr;
42  ccGenericMesh* mesh = nullptr;
43  QString objName("unknown");
44 
45  assert(obj);
46  if (obj->isA(CV_TYPES::POINT_CLOUD)) {
47  // we need a real point cloud
48  cloud = ccHObjectCaster::ToPointCloud(obj);
49  objName = cloud->getName();
50  } else if (obj->isKindOf(CV_TYPES::MESH)) {
53  objName = mesh->getName();
54  }
55 
56  if (cloud == nullptr) {
57  assert(false);
58  if (app)
59  app->dispToConsole(QObject::tr("Invalid object type"),
61  ++errorCount;
62  continue;
63  }
64 
65  // we get the PCV field if it already exists
67 
68  // otherwise we create it
69  if (sfIdx < 0) {
71  }
72 
73  if (sfIdx < 0) {
74  if (app)
75  app->dispToConsole(
76  "Couldn't allocate a new scalar field for computing "
77  "PCV field! Try to free some memory...",
79  return false;
80  }
81  cloud->setCurrentScalarField(sfIdx);
82 
83  QString objNameForPorgressDialog = objName;
84  if (candidates.size() > 1) {
85  objNameForPorgressDialog +=
86  QStringLiteral("(%1/%2)").arg(++count).arg(
87  candidates.size());
88  }
89 
90  bool wasEnabled = obj->isEnabled();
91  bool wasVisible = obj->isVisible();
92  obj->setEnabled(true);
93  obj->setVisible(true);
94  bool success =
95  PCV::Launch(rays, cloud, mesh, meshIsClosed, resolution,
96  resolution, progressDlg, objNameForPorgressDialog);
97  obj->setEnabled(wasEnabled);
98  obj->setVisible(wasVisible);
99 
100  if (!success) {
101  cloud->deleteScalarField(sfIdx);
102  if (app)
103  app->dispToConsole(QObject::tr("An error occurred during "
104  "entity '%1' illumination!")
105  .arg(objName),
107  ++errorCount;
108  } else {
109  ccScalarField* sf =
110  static_cast<ccScalarField*>(cloud->getScalarField(sfIdx));
111  if (sf) {
112  sf->computeMinAndMax();
113  cloud->setCurrentDisplayedScalarField(sfIdx);
116  if (obj->hasNormals() && obj->normalsShown()) {
117  if (app)
118  app->dispToConsole(
119  QObject::tr("Entity '%1' normals have been "
120  "automatically disabled")
121  .arg(objName),
123  }
124  obj->showNormals(false);
125  obj->showSF(true);
126  if (obj != cloud) {
127  cloud->showSF(true);
128  }
129  obj->prepareDisplayForRefresh_recursive();
130  } else {
131  assert(false);
132  }
133  }
134 
135  if (progressDlg && progressDlg->wasCanceled()) {
136  if (app)
137  app->dispToConsole(
138  QObject::tr("Process has been cancelled by the user"),
140  ++errorCount;
141  break;
142  }
143  }
144 
145  return (errorCount == 0);
146 }
147 
149  cmd.print("[PCV]");
150 
151  if (cmd.meshes().empty() && cmd.clouds().empty()) {
152  return cmd.error(qPCV::tr("No entity is loaded."));
153  }
154 
155  // Initialize to match PCV::Launch defaults
156  unsigned rayCount = 256;
157  bool meshIsClosed = false;
158  bool mode360 = true;
159  unsigned resolution = 1024;
160 
161  while (!cmd.arguments().empty()) {
162  const QString& arg = cmd.arguments().front();
164  cmd.arguments().pop_front();
165  meshIsClosed = true;
166  }
167 
168  // PCV::Launch mode360 defaults to true. To make absence / presence of
169  // command map to false / true, the command is named "180," and is the
170  // inverse of mode360.
172  cmd.arguments().pop_front();
173  mode360 = false;
175  cmd.arguments().pop_front();
176  bool conversionOk = false;
177  rayCount = cmd.arguments().takeFirst().toUInt(&conversionOk);
178  if (!conversionOk) {
179  return cmd.error(
180  QObject::tr("Invalid parameter: value after \"-%1\"")
181  .arg(COMMAND_PCV_N_RAYS));
182  }
183  } else if (ccCommandLineInterface::IsCommand(arg,
185  cmd.arguments().pop_front();
186  bool conversionOk = false;
187  resolution = cmd.arguments().takeFirst().toUInt(&conversionOk);
188  if (!conversionOk) {
189  return cmd.error(
190  QObject::tr("Invalid parameter: value after \"-%1\"")
191  .arg(COMMAND_PCV_RESOLUTION));
192  }
193  } else {
194  break;
195  }
196  }
197 
198  // generates light directions
199  std::vector<CCVector3> rays;
200  if (!PCV::GenerateRays(rayCount, rays, mode360)) {
201  return cmd.error(QObject::tr("Failed to generate the set of rays"));
202  }
203 
204  ecvProgressDialog pcvProgressCb(true);
205  pcvProgressCb.setAutoClose(false);
206 
207  ccHObject::Container candidates;
208  try {
209  candidates.reserve(cmd.clouds().size() + cmd.meshes().size());
210  } catch (const std::bad_alloc) {
211  return cmd.error(QObject::tr("Not enough memory"));
212  }
213 
214  for (CLCloudDesc& desc : cmd.clouds()) candidates.push_back(desc.pc);
215  for (CLMeshDesc& desc : cmd.meshes()) candidates.push_back(desc.mesh);
216 
217  if (!Process(candidates, rays, meshIsClosed, resolution, &pcvProgressCb,
218  nullptr)) {
219  return cmd.error(QObject::tr("Process failed"));
220  }
221 
222  for (CLCloudDesc& desc : cmd.clouds()) {
223  desc.basename += QString("_PCV");
224 
225  // save output
226  if (cmd.autoSaveMode()) {
227  QString errorStr = cmd.exportEntity(desc);
228  if (!errorStr.isEmpty()) {
229  return cmd.error(errorStr);
230  }
231  }
232  }
233 
234  for (CLMeshDesc& desc : cmd.meshes()) {
235  desc.basename += QString("_PCV");
236 
237  // save output
238  if (cmd.autoSaveMode()) {
239  QString errorStr = cmd.exportEntity(desc);
240  if (!errorStr.isEmpty()) {
241  return cmd.error(errorStr);
242  }
243  }
244  }
245 
246  return true;
247 }
int count
constexpr char COMMAND_PCV_180[]
Definition: PCVCommand.cpp:26
constexpr char COMMAND_PCV_IS_CLOSED[]
Definition: PCVCommand.cpp:25
constexpr char COMMAND_PCV_N_RAYS[]
Definition: PCVCommand.cpp:24
constexpr char COMMAND_PCV[]
Definition: PCVCommand.cpp:23
constexpr char CC_PCV_FIELD_LABEL_NAME[]
Definition: PCVCommand.cpp:21
constexpr char COMMAND_PCV_RESOLUTION[]
Definition: PCVCommand.cpp:27
bool process(ccCommandLineInterface &cmd) override
Main process.
Definition: PCVCommand.cpp:148
static bool Process(const ccHObject::Container &candidates, const std::vector< CCVector3 > &rays, bool meshIsClosed, unsigned resolution, ecvProgressDialog *progressDlg=nullptr, ecvMainAppInterface *app=nullptr)
Definition: PCVCommand.cpp:31
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 QStringList & arguments()=0
Returns the list of arguments.
virtual void print(const QString &message) const =0
virtual bool error(const QString &message) const =0
static bool IsCommand(const QString &token, const char *command)
Test whether a command line token is a valid command keyword or not.
virtual QString exportEntity(CLEntityDesc &entityDesc, const QString &suffix=QString(), QString *outputFilename=nullptr, ccCommandLineInterface::ExportOptions options=ExportOption::NoOptions)=0
Exports a cloud or a mesh.
virtual std::vector< CLMeshDesc > & meshes()
Currently opened meshes and their filename.
virtual std::vector< CLCloudDesc > & clouds()
Currently opened point clouds and their filename.
virtual void showSF(bool state)
Sets active scalarfield visibility.
Generic mesh interface.
virtual ccGenericPointCloud * getAssociatedCloud() const =0
Returns the vertices cloud.
static ccPointCloud * ToPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccPointCloud.
static ccGenericMesh * ToGenericMesh(ccHObject *obj)
Converts current object to ccGenericMesh (if possible)
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
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
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.
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.
Main application interface (for plugins)
virtual void dispToConsole(QString message, ConsoleMessageLevel level=STD_CONSOLE_MESSAGE)=0
Graphical progress indicator (thread-safe)
@ MESH
Definition: CVTypes.h:105
@ POINT_CLOUD
Definition: CVTypes.h:104
Loaded cloud description.
Loaded mesh description.