ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvCommandLineParser.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 "ecvCommandLineParser.h"
9 
10 // LOCAL
11 #include <ui_commandLineDlg.h>
12 
13 #include "ecvCommandCrossSection.h"
14 #include "ecvCommandLineCommands.h"
15 #include "ecvCommandRaster.h"
16 #include "ecvConsole.h"
17 #include "ecvPluginInterface.h"
18 
19 // CV_DB_LIB
20 #include <ecvGenericMesh.h>
21 #include <ecvHObjectCaster.h>
22 #include <ecvProgressDialog.h>
23 
24 // CV_IO_LIB
25 #include <AsciiFilter.h>
26 #include <BinFilter.h>
27 
28 // Qt
29 #include <QDateTime>
30 #include <QElapsedTimer>
31 #include <QMessageBox>
32 
33 // system
34 #include <unordered_set>
35 
36 // commands
37 constexpr char COMMAND_HELP[] = "HELP";
38 constexpr char COMMAND_SILENT_MODE[] = "SILENT";
39 
40 /*****************************************************/
41 /*************** ccCommandLineParser *****************/
42 /*****************************************************/
43 
44 void ccCommandLineParser::print(const QString& message) const {
45  ecvConsole::Print(message);
46 }
47 
48 void ccCommandLineParser::warning(const QString& message) const {
49  ecvConsole::Warning(message);
50 }
51 
52 bool ccCommandLineParser::error(const QString& message) const {
53  ecvConsole::Error(message);
54 
55  return false;
56 }
57 
59  char** args,
60  ccPluginInterfaceList& plugins) {
61  if (!args || nargs < 2) {
62  assert(false);
63  return EXIT_SUCCESS;
64  }
65 
66  // load arguments
67  QScopedPointer<ccCommandLineParser> parser(new ccCommandLineParser);
68 
69  parser->registerBuiltInCommands();
70 
71  for (int i = 1; i < nargs;
72  ++i) //'i=1' because first argument is always program executable file!
73  {
74  parser->arguments().push_back(QString(args[i]));
75  }
76 
77  assert(!parser->arguments().empty());
78 
79  // specific command: silent mode (will prevent the console dialog from
80  // appearing!
81  if (ccCommandLineInterface::IsCommand(parser->arguments().front(),
83  parser->arguments().pop_front();
84  parser->toggleSilentMode(true);
85  }
86 
87  QScopedPointer<QDialog> consoleDlg(nullptr);
88  if (!parser->silentMode()) {
89  // show console
90  consoleDlg.reset(new QDialog);
91  Ui_commandLineDlg commandLineDlg;
92  commandLineDlg.setupUi(consoleDlg.data());
93  consoleDlg->show();
94  ecvConsole::Init(commandLineDlg.consoleWidget, consoleDlg.data());
95  parser->fileLoadingParams().parentWidget = consoleDlg.data();
96  QApplication::processEvents(); // Get rid of the spinner
97  } else {
98  // allows CVLog ecvConsole or ccCommandLineParser (print,warning,error)
99  // to output to the console
100  ecvConsole::Init(nullptr, nullptr, nullptr, true);
101  }
102 
103  // load the plugins commands
104  for (ccPluginInterface* plugin : plugins) {
105  if (!plugin) {
106  assert(false);
107  continue;
108  }
109 
110  plugin->registerCommands(parser.data());
111  }
112 
113  // parse input
114  int result = parser->start(consoleDlg.data());
115 
116  if (!parser->silentMode()) {
117  if (result == EXIT_SUCCESS)
118  QMessageBox::information(consoleDlg.data(), "Processed finished",
119  "Job done");
120  else
121  QMessageBox::warning(consoleDlg.data(), "Processed finished",
122  "An error occurred! Check console");
123  }
124 
125  // release the parser before the console (as its dialogs may be chidren of
126  // the console)
127  parser->cleanup();
128  parser.reset();
129 
131 
132  return result;
133 }
134 
137  m_cloudExportFormat(BinFilter::GetFileFilter()),
138  m_cloudExportExt(BinFilter::GetDefaultExtension()),
139  m_meshExportFormat(BinFilter::GetFileFilter()),
140  m_meshExportExt(BinFilter::GetDefaultExtension()),
141  m_hierarchyExportFormat(BinFilter::GetFileFilter()),
142  m_hierarchyExportExt(BinFilter::GetDefaultExtension()),
143  m_orphans("orphans"),
144  m_progressDialog(nullptr),
145  m_parentWidget(nullptr) {}
146 
148  if (m_progressDialog) {
149  m_progressDialog->close();
150  m_progressDialog->deleteLater();
151  }
152 }
153 
154 bool ccCommandLineParser::registerCommand(Command::Shared command) {
155  if (!command) {
156  assert(false);
157  return false;
158  }
159 
160  if (m_commands.contains(command->m_keyword)) {
161  assert(false);
162  warning(QString("Internal error: keyword '%1' already registered (by "
163  "command '%2')")
164  .arg(command->m_keyword,
165  m_commands[command->m_keyword]->m_name));
166  return false;
167  }
168 
169  m_commands.insert(command->m_keyword, command);
170 
171  return true;
172 }
173 
175  const CLEntityDesc& entityDesc,
176  QString extension /*=QString()*/,
177  QString suffix /*=QString()*/,
178  QString* baseOutputFilename /*=0*/,
179  bool forceNoTimestamp /*=false*/) const {
180  // fetch the real entity
181  const ccHObject* entity = entityDesc.getEntity();
182  if (!entity) {
183  assert(false);
184  warning("[ExportEntity] Internal error: invalid input entity!");
185  return QString();
186  }
187 
188  // sub-item?
189  if (entityDesc.indexInFile >= 0) {
190  if (suffix.isEmpty())
191  suffix = QString("%1").arg(entityDesc.indexInFile);
192  else
193  suffix.prepend(QString("%1_").arg(entityDesc.indexInFile));
194  }
195 
196  QString baseName = entityDesc.basename;
197  if (!suffix.isEmpty()) {
198  baseName += QString("_") + suffix;
199  }
200 
201  QString outputFilename = baseName;
202  if (m_addTimestamp && !forceNoTimestamp) {
203  outputFilename +=
204  QString("_%1").arg(QDateTime::currentDateTime().toString(
205  "yyyy-MM-dd_hh'h'mm_ss_zzz"));
206  }
207 
208  if (!extension.isEmpty()) {
209  outputFilename += QString(".%1").arg(extension);
210  }
211 
212  if (baseOutputFilename) {
213  *baseOutputFilename = outputFilename;
214  }
215 
216  if (!entityDesc.path.isEmpty()) {
217  outputFilename.prepend(QString("%1/").arg(entityDesc.path));
218  }
219 
220  return outputFilename;
221 }
222 
224  CLEntityDesc& entityDesc,
225  const QString& suffix /*=QString()*/,
226  QString* baseOutputFilename /*=nullptr*/,
227  ccCommandLineInterface::ExportOptions
228  options /*ExportOptiopn::NoOption*/) {
229  print("[SAVING]");
230 
231  // fetch the real entity
232  ccHObject* entity = entityDesc.getEntity();
233  if (!entity) {
234  assert(false);
235  return "[ExportEntity] Internal error: invalid input entity!";
236  }
237 
238  bool anyForced = options.testFlag(ExportOption::ForceCloud) |
239  options.testFlag(ExportOption::ForceHierarchy) |
240  options.testFlag(ExportOption::ForceMesh);
241  // specific case: clouds
242  bool isCloud = entity->isA(CV_TYPES::POINT_CLOUD) ||
243  entityDesc.getCLEntityType() == CL_ENTITY_TYPE::CLOUD;
244 
245  // specific case: mesh
246  bool isMesh = entity->isKindOf(CV_TYPES::MESH) ||
247  entityDesc.getCLEntityType() == CL_ENTITY_TYPE::MESH;
248 
249  QString extension = isCloud ? m_cloudExportExt
250  : isMesh ? m_meshExportExt
251  : m_hierarchyExportExt;
252  QString format = isCloud ? m_cloudExportFormat
253  : isMesh ? m_meshExportFormat
254  : m_hierarchyExportFormat;
255  if (anyForced) {
256  if (options.testFlag(ExportOption::ForceCloud)) {
257  extension = m_cloudExportExt;
258  format = m_cloudExportFormat;
259  }
260  if (options.testFlag(ExportOption::ForceMesh)) {
261  extension = m_meshExportExt;
262  format = m_meshExportFormat;
263  }
264  if (options.testFlag(ExportOption::ForceHierarchy)) {
265  extension = m_hierarchyExportExt;
266  format = m_hierarchyExportFormat;
267  }
268  }
269  QString outputFilename =
270  getExportFilename(entityDesc, extension, suffix, baseOutputFilename,
271  options.testFlag(ExportOption::ForceNoTimestamp));
272  if (outputFilename.isEmpty()) {
273  return QString();
274  }
275 
276  // update the entity name as well
277  {
278  QString entName = entity->getName();
279  if (entName.isEmpty()) {
280  entName = entityDesc.basename;
281  }
282 
283  if (!suffix.isEmpty()) {
284  entName += QString("_") + suffix;
285  }
286 
287  entity->setName(entName);
288  }
289 
290  bool tempDependencyCreated = false;
291  ccGenericMesh* mesh = nullptr;
292  if (entity->isKindOf(CV_TYPES::MESH) &&
293  m_meshExportFormat == BinFilter::GetFileFilter()) {
294  // in a BIN file we must save the vertices cloud as well if it's not a
295  // child of the mesh!
296  mesh = static_cast<ccGenericMesh*>(entity);
297  ccGenericPointCloud* vertices = mesh->getAssociatedCloud();
298  if (vertices && !mesh->isAncestorOf(vertices)) {
299  // we save the cloud first!
300  vertices->addChild(
301  mesh,
302  ccHObject::DP_NONE); // we simply add a fake dependency
303  entity = vertices;
304  tempDependencyCreated = true;
305  }
306  }
307 
308  // save file
309  FileIOFilter::SaveParameters parameters;
310  {
311  // no dialog by default for command line mode!
312  parameters.alwaysDisplaySaveDialog = false;
313  if (!silentMode() && ecvConsole::TheInstance()) {
314  parameters.parentWidget = ecvConsole::TheInstance()->parentWidget();
315  }
316  }
317 
318 #ifdef _DEBUG
319  print("Output filename: " + outputFilename);
320 #endif
321  CC_FILE_ERROR result = FileIOFilter::SaveToFile(entity, outputFilename,
322  parameters, format);
323 
324  // restore input state!
325  if (tempDependencyCreated) {
326  if (mesh && entity) {
327  entity->detachChild(mesh);
328  } else {
329  assert(false);
330  }
331  }
332 
333  return (result != CC_FERR_NO_ERROR
334  ? QString("Failed to save result in file '%1'")
335  .arg(outputFilename)
336  : QString());
337 }
338 
339 void ccCommandLineParser::removeClouds(bool onlyLast /*=false*/) {
340  while (!m_clouds.empty()) {
341  delete m_clouds.back().pc;
342  m_clouds.pop_back();
343  if (onlyLast) break;
344  }
345 }
346 
347 void ccCommandLineParser::removeMeshes(bool onlyLast /*=false*/) {
348  while (!m_meshes.empty()) {
349  CLMeshDesc& desc = m_meshes.back();
350  delete desc.mesh;
351  m_meshes.pop_back();
352  if (onlyLast) break;
353  }
354 }
355 
357  QString filename,
358  const GlobalShiftOptions& globalShiftOptions,
359  FileIOFilter::Shared filter) {
360  print(QString("Opening file: '%1'").arg(filename));
361 
362  // whether Global (coordinate) shift has already been defined
363  static bool s_firstCoordinatesShiftEnabled = false;
364  // global shift (if defined)
365  static CCVector3d s_firstGlobalShift;
366 
367  // default Global Shift handling parameters
371 
372  switch (globalShiftOptions.mode) {
374  // let CC handle the global shift automatically
377  break;
378 
380  // use the first encountered global shift value (if any)
384  s_firstCoordinatesShiftEnabled;
385  m_loadingParameters.m_coordinatesShift = s_firstGlobalShift;
386  break;
387 
389  // set the user defined shift vector as default shift information
392  globalShiftOptions.customGlobalShift;
393  break;
394 
395  default:
396  // nothing to do
397  break;
398  }
399 
401  ccHObject* db = nullptr;
402  if (filter) {
404  result);
405  } else {
407  QString());
408  }
409 
410  if (!db) {
411  return false /*cmd.error(QString("Failed to open file
412  '%1'").arg(filename))*/
413  ; // Error message already issued
414  }
415 
416  if (globalShiftOptions.mode != GlobalShiftOptions::NO_GLOBAL_SHIFT) {
417  static bool s_firstTime = true;
418  if (s_firstTime) {
419  // remember the first Global Shift parameters used
420  s_firstCoordinatesShiftEnabled =
422  s_firstGlobalShift = m_loadingParameters.m_coordinatesShift;
423  s_firstTime = false;
424  }
425  }
426 
427  std::unordered_set<unsigned> verticesIDs;
428  // first look for meshes inside loaded DB (so that we don't consider mesh
429  // vertices as clouds!)
430  {
432  size_t count = 0;
433  // first look for all REAL meshes (so as to no consider sub-meshes)
434  if (db->filterChildren(meshes, true, CV_TYPES::MESH, true) != 0) {
435  count += meshes.size();
436  for (size_t i = 0; i < meshes.size(); ++i) {
438  if (mesh->getParent()) {
439  mesh->getParent()->detachChild(mesh);
440  }
441 
442  ccGenericPointCloud* vertices = mesh->getAssociatedCloud();
443  if (vertices) {
444  verticesIDs.insert(vertices->getUniqueID());
445  print(QString("Found one mesh with %1 faces and %2 "
446  "vertices: '%3'")
447  .arg(mesh->size())
448  .arg(mesh->getAssociatedCloud()->size())
449  .arg(mesh->getName()));
450  m_meshes.emplace_back(
451  mesh, filename,
452  count == 1 ? -1 : static_cast<int>(i));
453  } else {
454  delete mesh;
455  mesh = nullptr;
456  assert(false);
457  }
458  }
459  }
460 
461  // then look for the other meshes
462  meshes.clear();
463  if (db->filterChildren(meshes, true, CV_TYPES::MESH, false) != 0) {
464  size_t countBefore = count;
465  count += meshes.size();
466  for (size_t i = 0; i < meshes.size(); ++i) {
468  if (mesh->getParent()) mesh->getParent()->detachChild(mesh);
469 
470  ccGenericPointCloud* vertices = mesh->getAssociatedCloud();
471  if (vertices) {
472  verticesIDs.insert(vertices->getUniqueID());
473  print(QString("Found one kind of mesh with %1 faces and %2 "
474  "vertices: '%3'")
475  .arg(mesh->size())
476  .arg(mesh->getAssociatedCloud()->size())
477  .arg(mesh->getName()));
478  m_meshes.emplace_back(
479  mesh, filename,
480  count == 1 ? -1
481  : static_cast<int>(countBefore + i));
482  } else {
483  delete mesh;
484  mesh = nullptr;
485  assert(false);
486  }
487  }
488  }
489  }
490 
491  // now look for the remaining clouds inside loaded DB
492  {
495  size_t count = clouds.size();
496  for (size_t i = 0; i < count; ++i) {
497  ccPointCloud* pc = static_cast<ccPointCloud*>(clouds[i]);
498  if (pc->getParent()) {
499  pc->getParent()->detachChild(pc);
500  }
501 
502  // if the cloud is a set of vertices, we ignore it!
503  if (verticesIDs.find(pc->getUniqueID()) != verticesIDs.end()) {
504  m_orphans.addChild(pc);
505  continue;
506  }
507  print(QString("Found one cloud with %1 points").arg(pc->size()));
508  m_clouds.emplace_back(pc, filename,
509  count == 1 ? -1 : static_cast<int>(i));
510  }
511  }
512 
513  delete db;
514  db = nullptr;
515 
516  return true;
517 }
518 
519 bool ccCommandLineParser::saveClouds(QString suffix /*=QString()*/,
520  bool allAtOnce /*=false*/,
521  const QString* allAtOnceFileName /*=0*/) {
522  // all-at-once: all clouds in a single file
523  if (allAtOnce) {
524  FileIOFilter::Shared filter =
525  FileIOFilter::GetFilter(m_cloudExportFormat, false);
526  bool multiple = false;
527  if (filter) {
528  bool exclusive = true;
529  filter->canSave(CV_TYPES::POINT_CLOUD, multiple, exclusive);
530  }
531 
532  if (multiple) {
533  ccHObject tempContainer("Clouds");
534  {
535  for (CLCloudDesc& desc : m_clouds) {
536  tempContainer.addChild(desc.getEntity(),
538  }
539  }
540 
541  // save output
542  CLGroupDesc desc(&tempContainer, "AllClouds",
543  m_clouds.front().path);
544  if (allAtOnceFileName) {
545  CommandSave::SetFileDesc(desc, *allAtOnceFileName);
546  }
547 
548  QString errorStr = exportEntity(desc, suffix, nullptr,
550  if (!errorStr.isEmpty())
551  return error(errorStr);
552  else
553  return true;
554  } else {
555  error(QString("The currently selected ouput format for clouds (%1) "
556  "doesn't handle multiple entities at once!")
557  .arg(m_cloudExportFormat));
558  // will proceed with the standard way
559  }
560  }
561 
562  // standard way: one file per cloud
563  {
564  for (CLCloudDesc& desc : m_clouds) {
565  // save output
566  QString errorStr = exportEntity(desc, suffix);
567  if (!errorStr.isEmpty()) return error(errorStr);
568  }
569  }
570 
571  return true;
572 }
573 
574 bool ccCommandLineParser::saveMeshes(QString suffix /*=QString()*/,
575  bool allAtOnce /*=false*/,
576  const QString* allAtOnceFileName /*=0*/) {
577  // all-at-once: all meshes in a single file
578  if (allAtOnce) {
579  FileIOFilter::Shared filter =
580  FileIOFilter::GetFilter(m_meshExportFormat, false);
581  bool multiple = false;
582  if (filter) {
583  bool exclusive = true;
584  filter->canSave(CV_TYPES::MESH, multiple, exclusive);
585  }
586 
587  if (multiple) {
588  ccHObject tempContainer("Meshes");
589  {
590  for (auto& mesh : m_meshes) {
591  tempContainer.addChild(mesh.getEntity(),
593  }
594  }
595 
596  // save output
597  CLGroupDesc desc(&tempContainer, "AllMeshes",
598  m_meshes.front().path);
599  if (allAtOnceFileName) {
600  CommandSave::SetFileDesc(desc, *allAtOnceFileName);
601  }
602 
603  QString errorStr = exportEntity(desc, suffix, nullptr,
605  if (!errorStr.isEmpty())
606  return error(errorStr);
607  else
608  return true;
609  } else {
610  error(QString("The currently selected ouput format for meshes (%1) "
611  "doesn't handle multiple entities at once!")
612  .arg(m_meshExportFormat));
613  // will proceed with the standard way
614  }
615  }
616 
617  // standard way: one file per mesh
618  for (auto& mesh : m_meshes) {
619  // save output
620  QString errorStr = exportEntity(mesh, suffix);
621  if (!errorStr.isEmpty()) return error(errorStr);
622  }
623 
624  return true;
625 }
626 
694 }
695 
697  removeClouds();
698  removeMeshes();
699 }
700 
701 int ccCommandLineParser::start(QDialog* parent /*=0*/) {
702  if (m_arguments.empty()) {
703  assert(false);
704  return EXIT_FAILURE;
705  }
706 
707  m_parentWidget = parent;
708  // if (!m_silentMode)
709  //{
710  // m_progressDialog = new ecvProgressDialog(false, parent);
711  // //m_progressDialog->setAttribute(Qt::WA_DeleteOnClose);
712  // m_progressDialog->setAutoClose(false);
713  // m_progressDialog->hide();
714  // }
715 
716  QElapsedTimer eTimer;
717  eTimer.start();
718 
719  bool success = true;
720  while (success && !m_arguments.empty()) {
721  QApplication::processEvents(); // Without this the console is just a
722  // spinner until the end of all
723  // processing
724  QString argument = m_arguments.takeFirst();
725 
726  if (!argument.startsWith("-")) {
727  error(QString("Command expected (commands start with '-'). Found "
728  "'%1'")
729  .arg(argument));
730  success = false;
731  break;
732  }
733  QString keyword = argument.mid(1).toUpper();
734 
735  if (m_commands.contains(keyword)) {
736  assert(m_commands[keyword]);
737  success = m_commands[keyword]->process(*this);
738  }
739  // silent mode (i.e. no console)
740  else if (keyword == COMMAND_SILENT_MODE) {
741  warning(QString("Misplaced command: '%1' (must be first)")
742  .arg(COMMAND_SILENT_MODE));
743  } else if (keyword == COMMAND_HELP) {
744  print("Available commands:");
745  for (auto it = m_commands.constBegin(); it != m_commands.constEnd();
746  ++it) {
747  print(QString("-%1: %2").arg(it.key().toUpper(),
748  it.value()->m_name));
749  }
750  } else {
751  error(QString("Unknown or misplaced command: '%1'").arg(argument));
752  success = false;
753  break;
754  }
755  }
756 
757  print(QString("Processed finished in %1 s.")
758  .arg(eTimer.elapsed() / 1.0e3, 0, 'f', 2));
759 
760  return success ? EXIT_SUCCESS : EXIT_FAILURE;
761 }
Vector3Tpl< double > CCVector3d
Double 3D Vector.
Definition: CVGeom.h:804
std::string filename
filament::Texture::InternalFormat format
int count
CC_FILE_ERROR
Typical I/O filter errors.
Definition: FileIOFilter.h:20
@ CC_FERR_NO_ERROR
Definition: FileIOFilter.h:21
core::Tensor result
Definition: VtkUtils.cpp:76
CLOUDVIEWER dedicated binary point cloud I/O filter.
Definition: BinFilter.h:15
static QString GetFileFilter()
Definition: BinFilter.h:20
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
static bool Print(const char *format,...)
Prints out a formatted message in console.
Definition: CVLog.cpp:113
static CVLog * TheInstance()
Returns the static and unique instance.
Definition: CVLog.cpp:53
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Definition: CVLog.cpp:143
static CC_FILE_ERROR SaveToFile(ccHObject *entities, const QString &filename, const SaveParameters &parameters, Shared filter)
static Shared GetFilter(const QString &fileFilter, bool onImport)
Returns the filter corresponding to the given 'file filter'.
QSharedPointer< FileIOFilter > Shared
Shared type.
Definition: FileIOFilter.h:97
static ccHObject * LoadFromFile(const QString &filename, LoadParameters &parameters, Shared filter, CC_FILE_ERROR &result)
Loads one or more entities from a file with a known filter.
Command line interface.
std::vector< CLMeshDesc > m_meshes
Currently opened meshes and their filename.
bool m_addTimestamp
Whether a timestamp should be automatically added to output files or not.
std::vector< CLCloudDesc > m_clouds
Currently opened point clouds and their filename.
static bool IsCommand(const QString &token, const char *command)
Test whether a command line token is a valid command keyword or not.
CLLoadParameters m_loadingParameters
File loading parameters.
bool silentMode() const
Returns the silent mode.
virtual std::vector< CLMeshDesc > & meshes()
Currently opened meshes and their filename.
virtual std::vector< CLCloudDesc > & clouds()
Currently opened point clouds and their filename.
Command line parser.
int start(QDialog *parent=0)
Parses the command line.
bool error(const QString &message) const override
void print(const QString &message) const override
bool saveClouds(QString suffix=QString(), bool allAtOnce=false, const QString *allAtOnceFileName=nullptr) override
Saves all clouds.
bool saveMeshes(QString suffix=QString(), bool allAtOnce=false, const QString *allAtOnceFileName=nullptr) override
Saves all meshes.
bool importFile(QString filename, const GlobalShiftOptions &globalShiftOptions, FileIOFilter::Shared filter=FileIOFilter::Shared(nullptr)) override
Loads a file with a specific filter.
bool registerCommand(Command::Shared command) override
QString getExportFilename(const CLEntityDesc &entityDesc, QString extension=QString(), QString suffix=QString(), QString *baseOutputFilename=nullptr, bool forceNoTimestamp=false) const override
Returns the name of a to-be-exported entity.
~ccCommandLineParser() override
Destructor.
ccCommandLineParser()
Default constructor.
void removeClouds(bool onlyLast=false) override
Removes all clouds (or only the last one ;)
QString exportEntity(CLEntityDesc &entityDesc, const QString &suffix=QString(), QString *baseOutputFilename=nullptr, ccCommandLineInterface::ExportOptions options=ExportOption::NoOptions) override
Exports a cloud or a mesh.
void removeMeshes(bool onlyLast=false) override
Removes all meshes (or only the last one ;)
static int Parse(int nargs, char **args, ccPluginInterfaceList &plugins)
Parses the input command.
void warning(const QString &message) const override
Generic mesh interface.
virtual ccGenericPointCloud * getAssociatedCloud() const =0
Returns the vertices cloud.
A 3D cloud interface with associated features (color, normals, octree, etc.)
static ccGenericMesh * ToGenericMesh(ccHObject *obj)
Converts current object to ccGenericMesh (if possible)
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
void detachChild(ccHObject *child)
Detaches a specific child.
bool isAncestorOf(const ccHObject *anObject) const
Returns true if the current object is an ancestor of the specified one.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
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
virtual unsigned getUniqueID() const
Returns object unique ID.
Definition: ecvObject.h:86
bool isA(CV_CLASS_ENUM type) const
Definition: ecvObject.h:131
virtual void setName(const QString &name)
Sets object name.
Definition: ecvObject.h:75
bool isKindOf(CV_CLASS_ENUM type) const
Definition: ecvObject.h:128
Standard ECV plugin interface.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
virtual unsigned size() const =0
Returns the number of points.
virtual unsigned size() const =0
Returns the number of triangles.
unsigned size() const override
Definition: PointCloudTpl.h:38
static void ReleaseInstance(bool flush=true)
Releases unique instance.
Definition: ecvConsole.cpp:90
static void Init(QListWidget *textDisplay=nullptr, QWidget *parentWidget=nullptr, MainWindow *parentWindow=nullptr, bool redirectToStdOut=false)
Inits console (and optionaly associates it with a text output widget)
Definition: ecvConsole.cpp:178
constexpr char COMMAND_SILENT_MODE[]
constexpr char COMMAND_HELP[]
QVector< ccPluginInterface * > ccPluginInterfaceList
Simply a list of.
@ MESH
Definition: CVTypes.h:105
@ POINT_CLOUD
Definition: CVTypes.h:104
std::string toString(T x)
Definition: Common.h:80
Loaded cloud description.
Loaded entity description.
virtual CL_ENTITY_TYPE getCLEntityType() const =0
virtual ccHObject * getEntity()=0
Loaded group description.
Loaded mesh description.
ccGenericMesh * mesh
static void SetFileDesc(CLEntityDesc &desc, const QString &fileName)
ecvGlobalShiftManager::Mode shiftHandlingMode
How to handle big coordinates.
Definition: FileIOFilter.h:64
Generic saving parameters.
Definition: FileIOFilter.h:84
QWidget * parentWidget
Parent widget (if any)
Definition: FileIOFilter.h:93
QSharedPointer< Command > Shared
Shared type.