ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvLibAlgorithms.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 "ecvLibAlgorithms.h"
9 
10 // cloudViewer
11 #include <ScalarFieldTools.h>
12 
13 // CV_DB_LIB
14 #include <ecvDisplayTools.h>
15 #include <ecvOctree.h>
16 #include <ecvPointCloud.h>
17 #include <ecvScalarField.h>
18 
19 // Local
20 #include "ecvCommon.h"
21 #include "ecvConsole.h"
22 #include "ecvProgressDialog.h"
23 #include "ecvRegistrationTools.h"
24 #include "ecvUtils.h"
25 
26 // Qt
27 #include <QApplication>
28 #include <QElapsedTimer>
29 #include <QInputDialog>
30 #include <QMessageBox>
31 
32 // This is included only for temporarily removing an object from the tree.
33 // TODO figure out a cleaner way to do this without having to include all
34 // of MainWindow.h
35 #include "MainWindow.h"
36 
37 namespace ccLibAlgorithms {
38 static QString GetDensitySFName(
40  bool approx,
41  double densityKernelSize = 0.0) {
42  QString sfName;
43 
44  // update the name with the density type
45  switch (densityType) {
48  break;
51  break;
54  break;
55  default:
56  assert(false);
57  break;
58  }
59 
60  sfName += QString(" (r=%2)").arg(densityKernelSize);
61 
62  if (approx) sfName += " [approx]";
63 
64  return sfName;
65 }
66 
68  unsigned knn /*=12*/) {
69  assert(cloud);
70  if (cloud && cloud->size() != 0) {
71  // we get 1% of the cloud bounding box
72  // and we divide by the number of points / 10e6 (so that the kernel for
73  // a 20 M. points cloud is half the one of a 10 M. cloud)
74  ccBBox box = cloud->getOwnBB();
75 
76  // old way
77  // PointCoordinateType radius = box.getDiagNorm() *
78  // static_cast<PointCoordinateType>(0.01/std::max(1.0,1.0e-7*static_cast<double>(cloud->size())));
79 
80  // new way
81  CCVector3 d = box.getDiagVec();
82  PointCoordinateType volume = d[0] * d[1] * d[2];
83  PointCoordinateType surface =
84  pow(volume, static_cast<PointCoordinateType>(2.0 / 3.0));
85  PointCoordinateType surfacePerPoint = surface / cloud->size();
86  return sqrt(surfacePerPoint * knn);
87  }
88 
89  return -PC_ONE;
90 }
91 
93  const ccHObject::Container& entities, unsigned knn /*=12*/) {
94  PointCoordinateType sigma = -PC_ONE;
95 
96  size_t selNum = entities.size();
97  // computation of a first sigma guess
98  for (size_t i = 0; i < selNum; ++i) {
101 
102  // we keep the smallest value
103  if (sigma < 0 || sigmaCloud < sigma) sigma = sigmaCloud;
104  }
105 
106  return sigma;
107 }
108 
110  PointCoordinateType radius,
111  ccHObject::Container& entities,
112  const CCVector3* roughnessUpDir /*=nullptr*/,
113  QWidget* parent /*=nullptr*/) {
114  // no feature case
115  if (characteristics.empty()) {
116  // nothing to do
117  assert(false);
118  return true;
119  }
120 
121  // single features case
122  if (characteristics.size() == 1) {
123  return ComputeGeomCharacteristic(characteristics.front().charac,
124  characteristics.front().subOption,
125  radius, entities, roughnessUpDir,
126  parent);
127  }
128 
129  // multiple features case
130  QScopedPointer<ecvProgressDialog> pDlg;
131  if (parent) {
132  pDlg.reset(new ecvProgressDialog(true, parent));
133  pDlg->setAutoClose(false);
134  }
135 
136  for (const GeomCharacteristic& g : characteristics) {
137  if (!ComputeGeomCharacteristic(g.charac, g.subOption, radius, entities,
138  roughnessUpDir, parent, pDlg.data())) {
139  return false;
140  }
141  }
142 
143  return true;
144 }
145 
148  int subOption,
149  PointCoordinateType radius,
150  ccHObject::Container& entities,
151  const CCVector3* roughnessUpDir /*=nullptr*/,
152  QWidget* parent /*= nullptr*/,
153  ecvProgressDialog* progressDialog /*=nullptr*/) {
154  size_t selNum = entities.size();
155  if (selNum < 1) return false;
156 
157  // generate the right SF name
158  QString sfName;
159 
160  switch (c) {
162  switch (subOption) {
164  sfName = "Eigenvalues sum";
165  break;
167  sfName = "Omnivariance";
168  break;
170  sfName = "Eigenentropy";
171  break;
173  sfName = "Anisotropy";
174  break;
176  sfName = "Planarity";
177  break;
179  sfName = "Linearity";
180  break;
182  sfName = "PCA1";
183  break;
185  sfName = "PCA2";
186  break;
188  sfName = "Surface variation";
189  break;
191  sfName = "Sphericity";
192  break;
194  sfName = "Verticality";
195  break;
197  sfName = "1st eigenvalue";
198  break;
200  sfName = "2nd eigenvalue";
201  break;
203  sfName = "3rd eigenvalue";
204  break;
205  default:
206  assert(false);
207  CVLog::Error(
208  "Internal error: invalid sub option for Feature "
209  "computation");
210  return false;
211  }
212 
213  sfName += QString(" (%1)").arg(radius);
214  } break;
215 
217  switch (subOption) {
220  break;
223  break;
226  break;
227  default:
228  assert(false);
229  CVLog::Error(
230  "Internal error: invalid sub option for Curvature "
231  "computation");
232  return false;
233  }
234  sfName += QString(" (%1)").arg(radius);
235  } break;
236 
238  sfName = GetDensitySFName(
240  subOption),
241  false, radius);
242  break;
243 
245  sfName = GetDensitySFName(
247  subOption),
248  true);
249  break;
250 
252  sfName = CC_ROUGHNESS_FIELD_NAME + QString(" (%1)").arg(radius);
253  break;
254 
256  sfName = CC_MOMENT_ORDER1_FIELD_NAME + QString(" (%1)").arg(radius);
257  break;
258 
259  default:
260  assert(false);
261  return false;
262  }
263 
264  ecvProgressDialog* pDlg = progressDialog;
265  if (!pDlg && parent) {
266  pDlg = new ecvProgressDialog(true, parent);
267  pDlg->setAutoClose(false);
268  }
269 
270  for (size_t i = 0; i < selNum; ++i) {
271  // is the ith selected data is eligible for processing?
272  if (entities[i]->isKindOf(CV_TYPES::POINT_CLOUD)) {
273  ccGenericPointCloud* cloud =
275 
276  ccPointCloud* pc = 0;
277  int sfIdx = -1;
278  if (cloud->isA(CV_TYPES::POINT_CLOUD)) {
279  pc = static_cast<ccPointCloud*>(cloud);
280 
281  sfIdx = pc->getScalarFieldIndexByName(qPrintable(sfName));
282  if (sfIdx < 0) sfIdx = pc->addScalarField(qPrintable(sfName));
283  if (sfIdx >= 0)
284  pc->setCurrentScalarField(sfIdx);
285  else {
287  QString("Failed to create scalar field on cloud "
288  "'%1' (not enough memory?)")
289  .arg(pc->getName()));
290  continue;
291  }
292  }
293 
294  ccOctree::Shared octree = cloud->getOctree();
295  if (!octree) {
296  if (pDlg) {
297  pDlg->show();
298  }
299  octree = cloud->computeOctree(pDlg);
300  if (!octree) {
302  QString("Couldn't compute octree for cloud '%1'!")
303  .arg(cloud->getName()));
304  break;
305  }
306  }
307 
310  ComputeCharactersitic(c, subOption, cloud, radius,
311  roughnessUpDir, pDlg,
312  octree.data());
313 
315  if (pc && sfIdx >= 0) {
317  pc->showSF(sfIdx >= 0);
320  roughnessUpDir != nullptr) {
321  // signed roughness should be displayed with a
322  // symmetrical color scale
323  ccScalarField* sf = dynamic_cast<ccScalarField*>(
325  if (sf) {
326  sf->setSymmetricalScale(true);
327  } else {
328  assert(false);
329  }
330  }
331  }
332  } else {
333  QString errorMessage;
334  switch (result) {
336  errorMessage = "Internal error (invalid input)";
337  break;
339  errorMessage = "Not enough points";
340  break;
343  errorMessage =
344  "Failed to compute octree (not enough memory?)";
345  break;
347  errorMessage = "Process failed";
348  break;
351  errorMessage =
352  "Internal error (unhandled characteristic)";
353  break;
355  errorMessage = "Not enough memory";
356  break;
359  errorMessage = "Process cancelled by user";
360  break;
361  default:
362  assert(false);
363  errorMessage = "Unknown error";
364  break;
365  }
366 
368  QString("Failed to apply processing to cloud '%1'")
369  .arg(cloud->getName()));
370  ecvConsole::Warning(errorMessage);
371 
372  if (pc && sfIdx >= 0) {
373  pc->deleteScalarField(sfIdx);
374  sfIdx = -1;
375  }
376 
377  if (pDlg != progressDialog) {
378  delete pDlg;
379  pDlg = nullptr;
380  }
381 
382  return false;
383  }
384  }
385  }
386 
387  if (pDlg != progressDialog) {
388  delete pDlg;
389  pDlg = nullptr;
390  }
391 
392  return true;
393 }
394 
396  ccHObject::Container& entities,
397  QWidget* parent /*=0*/,
398  void** additionalParameters /*=0*/) {
399  size_t selNum = entities.size();
400  if (selNum < 1) return false;
401 
402  // generic parameters
403  QString sfName;
404 
405  // computeScalarFieldGradient parameters
406  bool euclidean = false;
407 
408  switch (algo) {
409  case CCLIB_ALGO_SF_GRADIENT: {
411  // parameters already provided?
412  if (additionalParameters) {
413  euclidean = *static_cast<bool*>(additionalParameters[0]);
414  } else // ask the user!
415  {
416  euclidean = (QMessageBox::question(
417  parent, "Gradient",
418  "Is the scalar field composed of "
419  "(euclidean) distances?",
420  QMessageBox::Yes | QMessageBox::No,
421  QMessageBox::No) == QMessageBox::Yes);
422  }
423  } break;
424 
425  default:
426  assert(false);
427  return false;
428  }
429 
430  for (size_t i = 0; i < selNum; ++i) {
431  // is the ith selected data is eligible for processing?
432  ccGenericPointCloud* cloud = nullptr;
433  switch (algo) {
435  // for scalar field gradient, we can apply it directly on meshes
436  bool lockedVertices;
437  cloud = ccHObjectCaster::ToGenericPointCloud(entities[i],
438  &lockedVertices);
439  if (lockedVertices) {
441  entities[i]->getName(), selNum == 1);
442  cloud = nullptr;
443  }
444  if (cloud) {
445  // but we need an already displayed SF!
446  if (cloud->isA(CV_TYPES::POINT_CLOUD)) {
447  ccPointCloud* pc = static_cast<ccPointCloud*>(cloud);
448  int outSfIdx =
450  if (outSfIdx < 0) {
451  cloud = nullptr;
452  } else {
453  // we set as 'output' SF the currently displayed
454  // scalar field
455  pc->setCurrentOutScalarField(outSfIdx);
456  sfName = QString("%1(%2)").arg(
458  pc->getScalarFieldName(outSfIdx));
459  }
460  } else // if (!cloud->hasDisplayedScalarField()) //TODO:
461  // displayed but not necessarily set as OUTPUT!
462  {
463  cloud = nullptr;
464  }
465  }
466  break;
467 
468  // by default, we apply processings on clouds only
469  default:
470  if (entities[i]->isKindOf(CV_TYPES::POINT_CLOUD))
471  cloud = ccHObjectCaster::ToGenericPointCloud(entities[i]);
472  break;
473  }
474 
475  if (cloud) {
476  ccPointCloud* pc = nullptr;
477  int sfIdx = -1;
478  if (cloud->isA(CV_TYPES::POINT_CLOUD)) {
479  pc = static_cast<ccPointCloud*>(cloud);
480 
481  sfIdx = pc->getScalarFieldIndexByName(qPrintable(sfName));
482  if (sfIdx < 0) sfIdx = pc->addScalarField(qPrintable(sfName));
483  if (sfIdx >= 0)
484  pc->setCurrentInScalarField(sfIdx);
485  else {
487  QString("Failed to create scalar field on cloud "
488  "'%1' (not enough memory?)")
489  .arg(pc->getName()));
490  continue;
491  }
492  }
493 
494  QScopedPointer<ecvProgressDialog> pDlg;
495  if (parent) {
496  pDlg.reset(new ecvProgressDialog(true, parent));
497  }
498 
499  ccOctree::Shared octree = cloud->getOctree();
500  if (!octree) {
501  if (pDlg) {
502  pDlg->show();
503  }
504  octree = cloud->computeOctree(pDlg.data());
505  if (!octree) {
507  QString("Couldn't compute octree for cloud '%1'!")
508  .arg(cloud->getName()));
509  break;
510  }
511  }
512 
513  int result = 0;
514  QElapsedTimer eTimer;
515  eTimer.start();
516  switch (algo) {
520  cloud,
521  0, // auto --> FIXME: should be properly
522  // set by the user!
523  euclidean, false, pDlg.data(),
524  octree.data());
525  break;
526 
527  default:
528  // missed something?
529  assert(false);
530  }
531  qint64 elapsedTime_ms = eTimer.elapsed();
532 
533  if (result == 0) {
534  if (pc && sfIdx >= 0) {
536  pc->showSF(sfIdx >= 0);
538  }
539  // cloud->prepareDisplayForRefresh();
540  ecvConsole::Print("[Algortihm] Timing: %3.2f s.",
541  static_cast<double>(elapsedTime_ms) / 1000.0);
542  } else {
544  QString("Failed to apply processing to cloud '%1'")
545  .arg(cloud->getName()));
546  if (pc && sfIdx >= 0) {
547  pc->deleteScalarField(sfIdx);
548  sfIdx = -1;
549  }
550  }
551  }
552  }
553 
554  return true;
555 }
556 
558  ccHObject::Container& entities,
559  double icpRmsDiff,
560  int icpFinalOverlap,
561  unsigned refEntityIndex /*=0*/,
562  QWidget* parent /*=0*/) {
563  if (entities.size() < 2 || refEntityIndex >= entities.size()) {
564  CVLog::Error(
565  "[ApplyScaleMatchingAlgorithm] Invalid input parameter(s)");
566  return false;
567  }
568 
569  std::vector<double> scales;
570  try {
571  scales.resize(entities.size(), -1.0);
572  } catch (const std::bad_alloc&) {
573  CVLog::Error("Not enough memory!");
574  return false;
575  }
576 
577  // check the reference entity
578  ccHObject* refEntity = entities[refEntityIndex];
579  if (!refEntity->isKindOf(CV_TYPES::POINT_CLOUD) &&
580  !refEntity->isKindOf(CV_TYPES::MESH)) {
582  "[Scale Matching] The reference entity must be a cloud or a "
583  "mesh!");
584  return false;
585  }
586 
587  unsigned count = static_cast<unsigned>(entities.size());
588 
589  // now compute the scales
590  ecvProgressDialog pDlg(true, parent);
591  pDlg.setMethodTitle(QObject::tr("Computing entities scales"));
592  pDlg.setInfo(QObject::tr("Entities: %1").arg(count));
594  pDlg.start();
595  QApplication::processEvents();
596 
597  for (unsigned i = 0; i < count; ++i) {
598  ccHObject* ent = entities[i];
599  // try to get the underlying cloud (or the vertices set for a mesh)
600  bool lockedVertices;
601  ccGenericPointCloud* cloud =
602  ccHObjectCaster::ToGenericPointCloud(ent, &lockedVertices);
603  if (cloud && !lockedVertices) {
604  switch (algo) {
605  case BB_MAX_DIM:
606  case BB_VOLUME: {
607  ccBBox box = ent->getOwnBB();
608  if (box.isValid())
609  scales[i] = algo == BB_MAX_DIM ? box.getMaxBoxDim()
610  : box.computeVolume();
611  else
612  CVLog::Warning(QString("[Scale Matching] Entity '%1' "
613  "has an invalid bounding-box!")
614  .arg(ent->getName()));
615  } break;
616 
617  case PCA_MAX_DIM: {
618  cloudViewer::Neighbourhood Yk(cloud);
619  if (!Yk.getLSPlane()) {
620  CVLog::Warning(QString("[Scale Matching] Failed to "
621  "perform PCA on entity '%1'!")
622  .arg(ent->getName()));
623  break;
624  }
625  // deduce the scale
626  {
627  const CCVector3* X = Yk.getLSPlaneX();
628  const CCVector3* O = Yk.getGravityCenter();
629  double minX = 0;
630  double maxX = 0;
631  for (unsigned j = 0; j < cloud->size(); ++j) {
632  double x = (*cloud->getPoint(j) - *O).dot(*X);
633  if (j != 0) {
634  minX = std::min(x, minX);
635  maxX = std::max(x, maxX);
636  } else {
637  minX = maxX = x;
638  }
639  }
640  scales[i] = maxX - minX;
641  }
642  } break;
643 
644  case ICP_SCALE: {
645  ccGLMatrix transMat;
646  double finalError = 0.0;
647  double finalScale = 1.0;
648  unsigned finalPointCount = 0;
649 
651  {
652  parameters.convType = cloudViewer::
654  parameters.minRMSDecrease = icpRmsDiff;
655  parameters.nbMaxIterations = 0;
656  parameters.adjustScale = true;
657  parameters.filterOutFarthestPoints = false;
658  parameters.samplingLimit = 50000;
659  parameters.finalOverlapRatio = icpFinalOverlap / 100.0;
660  parameters.transformationFilters =
661  0; // cloudViewer::RegistrationTools::SKIP_ROTATION
662  parameters.maxThreadCount = 0;
663  parameters.useC2MSignedDistances = false;
664  parameters.normalsMatching =
666  }
667 
668  if (ccRegistrationTools::ICP(ent, refEntity, transMat,
669  finalScale, finalError,
670  finalPointCount, parameters,
671  false, false, parent)) {
672  scales[i] = finalScale;
673  } else {
674  CVLog::Warning(QString("[Scale Matching] Failed to "
675  "register entity '%1'!")
676  .arg(ent->getName()));
677  }
678 
679  } break;
680 
681  default:
682  assert(false);
683  break;
684  }
685  } else if (cloud && lockedVertices) {
686  // locked entities
688  } else {
689  // we need a cloud or a mesh
690  CVLog::Warning(QString("[Scale Matching] Entity '%1' can't be "
691  "rescaled this way!")
692  .arg(ent->getName()));
693  }
694 
695  // if the reference entity is invalid!
696  if (scales[i] <= 0 && i == refEntityIndex) {
697  CVLog::Error(
698  "Reference entity has an invalid scale! Can't proceed.");
699  return false;
700  }
701 
702  if (!nProgress.oneStep()) {
703  // process cancelled by user
704  return false;
705  }
706  }
707 
708  CVLog::Print(QString("[Scale Matching] Reference entity scale: %1")
709  .arg(scales[refEntityIndex]));
710 
711  // now we can rescale
712  pDlg.setMethodTitle(QObject::tr("Rescaling entities"));
713  {
714  ccHObject::Container toBeRescaleEntities;
715  for (unsigned i = 0; i < count; ++i) {
716  if (i == refEntityIndex) continue;
717  if (scales[i] < 0) continue;
718 
719  CVLog::Print(QString("[Scale Matching] Entity '%1' scale: %2")
720  .arg(entities[i]->getName())
721  .arg(scales[i]));
722  if (scales[i] <= ZERO_TOLERANCE_D) {
723  CVLog::Warning("[Scale Matching] Entity scale is too small!");
724  continue;
725  }
726 
727  ccHObject* ent = entities[i];
728 
729  bool lockedVertices;
730  ccGenericPointCloud* cloud =
731  ccHObjectCaster::ToGenericPointCloud(ent, &lockedVertices);
732  if (!cloud || lockedVertices) continue;
733 
734  double scaled = 1.0;
735  if (algo == ICP_SCALE)
736  scaled = scales[i];
737  else
738  scaled = scales[refEntityIndex] / scales[i];
739 
740  PointCoordinateType scale_pc =
741  static_cast<PointCoordinateType>(scaled);
742 
743  // we temporarily detach entity, as it may undergo
744  //"severe" modifications (octree deletion, etc.) --> see
745  // ccPointCloud::scale
746  MainWindow* instance = dynamic_cast<MainWindow*>(parent);
747  MainWindow::ccHObjectContext objContext;
748  if (instance) {
749  objContext = instance->removeObjectTemporarilyFromDBTree(cloud);
750  }
751 
752  CCVector3 C = cloud->getOwnBB().getCenter();
753 
754  cloud->scale(scale_pc, scale_pc, scale_pc, C);
755 
756  if (instance) instance->putObjectBackIntoDBTree(cloud, objContext);
757  // cloud->prepareDisplayForRefresh_recursive();
758 
759  // don't forget the 'global shift'!
760  const CCVector3d& shift = cloud->getGlobalShift();
761  cloud->setGlobalShift(shift * scaled);
762  toBeRescaleEntities.push_back(cloud);
763  // DGM: nope! Not the global scale!
764  }
765 
766  // only refresh rescaled
768  for (unsigned i = 0; i < toBeRescaleEntities.size(); ++i) {
769  ccHObject* obj = toBeRescaleEntities[i];
770  if (obj) {
772  obj->setRedraw(true);
773  }
774  }
776 
777  if (!nProgress.oneStep()) {
778  // process cancelled by user
779  return false;
780  }
781  }
782 
783  return true;
784 }
785 } // namespace ccLibAlgorithms
constexpr PointCoordinateType PC_ONE
'1' as a PointCoordinateType value
Definition: CVConst.h:67
constexpr double ZERO_TOLERANCE_D
Definition: CVConst.h:49
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
int count
void * X
Definition: SmallVector.cpp:45
core::Tensor result
Definition: VtkUtils.cpp:76
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 bool Error(const char *format,...)
Display an error dialog with formatted message.
Definition: CVLog.cpp:143
ccHObjectContext removeObjectTemporarilyFromDBTree(ccHObject *obj) override
Removes object temporarily from DB tree.
void putObjectBackIntoDBTree(ccHObject *obj, const ccHObjectContext &context) override
Adds back object to DB tree.
Type * data()
Definition: CVGeom.h:145
Bounding box structure.
Definition: ecvBBox.h:25
virtual void setRedraw(bool state)
Sets entity redraw mode.
virtual void showSF(bool state)
Sets active scalarfield visibility.
Float version of ccGLMatrixTpl.
Definition: ecvGLMatrix.h:19
A 3D cloud interface with associated features (color, normals, octree, etc.)
virtual void scale(PointCoordinateType fx, PointCoordinateType fy, PointCoordinateType fz, CCVector3 center=CCVector3(0, 0, 0))=0
Multiplies all coordinates by constant factors (one per dimension)
virtual ccOctree::Shared computeOctree(cloudViewer::GenericProgressCallback *progressCb=nullptr, bool autoAddChild=true)
Computes the cloud octree.
ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
virtual ccOctree::Shared getOctree() const
Returns the associated octree (if any)
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.
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
virtual ccBBox getOwnBB(bool withGLFeatures=false)
Returns the entity's own bounding-box.
QString getViewId() const
Definition: ecvHObject.h:225
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
QSharedPointer< ccOctree > Shared
Shared pointer.
Definition: ecvOctree.h:32
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.
int getCurrentDisplayedScalarFieldIndex() const
Returns the currently displayed scalar field index (or -1 if none)
void deleteScalarField(int index) override
Deletes a specific scalar field.
static bool ICP(ccHObject *data, ccHObject *model, ccGLMatrix &transMat, double &finalScale, double &finalRMS, unsigned &finalPointCount, const cloudViewer::ICPRegistrationTools::Parameters &inputParameters, bool useDataSFAsWeights=false, bool useModelSFAsWeights=false, QWidget *parent=nullptr)
Applies ICP registration on two entities.
A scalar field associated to display-related parameters.
void setSymmetricalScale(bool state)
Sets whether the color scale should be symmetrical or not.
virtual void setGlobalShift(double x, double y, double z)
Sets shift applied to original coordinates (information storage only)
virtual const CCVector3d & getGlobalShift() const
Returns the shift applied to original coordinates.
Vector3Tpl< T > getDiagVec() const
Returns diagonal vector.
Definition: BoundingBox.h:169
Vector3Tpl< T > getCenter() const
Returns center.
Definition: BoundingBox.h:164
double computeVolume() const
Returns the bounding-box volume.
Definition: BoundingBox.h:192
T getMaxBoxDim() const
Returns maximal box dimension.
Definition: BoundingBox.h:185
bool isValid() const
Returns whether bounding box is valid or not.
Definition: BoundingBox.h:203
virtual unsigned size() const =0
Returns the number of points.
virtual const CCVector3 * getPoint(unsigned index) const =0
Returns the ith point.
static ErrorCode ComputeCharactersitic(GeomCharacteristic c, int subOption, GenericIndexedCloudPersist *cloud, PointCoordinateType kernelRadius, const CCVector3 *roughnessUpDir=nullptr, GenericProgressCallback *progressCb=nullptr, DgmOctree *inputOctree=nullptr)
Unified way to compute a geometric characteristic.
const PointCoordinateType * getLSPlane()
Returns best interpolating plane equation (Least-square)
const CCVector3 * getGravityCenter()
Returns gravity center.
const CCVector3 * getLSPlaneX()
Returns best interpolating plane (Least-square) 'X' base vector.
bool oneStep()
Increments total progress value of a single unit.
int getScalarFieldIndexByName(const char *name) const
Returns the index of a scalar field represented by its name.
void setCurrentOutScalarField(int index)
Sets the OUTPUT scalar field.
void setCurrentScalarField(int index)
Sets both the INPUT & OUTPUT scalar field.
const char * getScalarFieldName(int index) const
Returns the name of a specific scalar field.
void setCurrentInScalarField(int index)
Sets the INPUT scalar field.
ScalarField * getCurrentInScalarField() const
Returns the scalar field currently associated to the cloud input.
static int computeScalarFieldGradient(GenericIndexedCloudPersist *theCloud, PointCoordinateType radius, bool euclideanDistances, bool sameInAndOutScalarField=false, GenericProgressCallback *progressCb=nullptr, DgmOctree *theOctree=nullptr)
virtual void computeMinAndMax()
Determines the min and max values.
Definition: ScalarField.h:123
static void SetRedrawRecursive(bool redraw=false)
static void RemoveBB(CC_DRAW_CONTEXT context)
static void RedrawDisplay(bool only2D=false, bool forceRedraw=true)
Graphical progress indicator (thread-safe)
virtual void start() override
virtual void setInfo(const char *infoStr) override
Notifies some information about the ongoing process.
virtual void setMethodTitle(const char *methodTitle) override
Notifies the algorithm title.
__host__ __device__ float dot(float2 a, float2 b)
Definition: cutil_math.h:1119
int min(int a, int b)
Definition: cutil_math.h:53
int max(int a, int b)
Definition: cutil_math.h:48
#define CC_LOCAL_VOL_DENSITY_FIELD_NAME
Definition: ecvCommon.h:26
#define CC_MOMENT_ORDER1_FIELD_NAME
Definition: ecvCommon.h:28
#define CC_CURVATURE_NORM_CHANGE_RATE_FIELD_NAME
Definition: ecvCommon.h:31
#define CC_GRADIENT_NORMS_FIELD_NAME
Definition: ecvCommon.h:32
#define CC_CURVATURE_GAUSSIAN_FIELD_NAME
Definition: ecvCommon.h:29
#define CC_CURVATURE_MEAN_FIELD_NAME
Definition: ecvCommon.h:30
#define CC_LOCAL_KNN_DENSITY_FIELD_NAME
Definition: ecvCommon.h:24
#define CC_LOCAL_SURF_DENSITY_FIELD_NAME
Definition: ecvCommon.h:25
#define CC_ROUGHNESS_FIELD_NAME
Definition: ecvCommon.h:27
@ MESH
Definition: CVTypes.h:105
@ POINT_CLOUD
Definition: CVTypes.h:104
static QString GetDensitySFName(cloudViewer::GeometricalAnalysisTools::Density densityType, bool approx, double densityKernelSize=0.0)
bool ApplyScaleMatchingAlgorithm(ScaleMatchingAlgorithm algo, ccHObject::Container &entities, double icpRmsDiff, int icpFinalOverlap, unsigned refEntityIndex, QWidget *parent)
bool ApplyCCLibAlgorithm(CC_LIB_ALGORITHM algo, ccHObject::Container &entities, QWidget *parent, void **additionalParameters)
bool ComputeGeomCharacteristics(const GeomCharacteristicSet &characteristics, PointCoordinateType radius, ccHObject::Container &entities, const CCVector3 *roughnessUpDir, QWidget *parent)
ScaleMatchingAlgorithm
Scale matching algorithms.
std::vector< GeomCharacteristic > GeomCharacteristicSet
Set of GeomCharacteristic instances.
bool ComputeGeomCharacteristic(cloudViewer::GeometricalAnalysisTools::GeomCharacteristic c, int subOption, PointCoordinateType radius, ccHObject::Container &entities, const CCVector3 *roughnessUpDir, QWidget *parent, ecvProgressDialog *progressDialog)
PointCoordinateType GetDefaultCloudKernelSize(ccGenericPointCloud *cloud, unsigned knn)
Returns a default first guess for algorithms kernel size (one cloud)
void DisplayLockedVerticesWarning(const QString &meshName, bool displayAsError)
Display a warning or error for locked verts.
Definition: ecvUtils.cpp:13
cloudViewer::NormalizedProgress * nProgress
cloudViewer::DgmOctree * octree
Geometric characteristic (with sub option)
CONVERGENCE_TYPE convType
Convergence type.
NORMALS_MATCHING normalsMatching
Normals matching method.
int maxThreadCount
Maximum number of threads to use (0 = max)
bool useC2MSignedDistances
Whether to compute signed C2M distances.
Backup "context" for an object.