ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
qM3C2Dialog.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 "qM3C2Dialog.h"
9 
10 // CV_DB_LIB
11 #include <ecvFileUtils.h>
12 #include <ecvPointCloud.h>
13 
14 #include "ecvMainAppInterface.h"
15 
16 // Qt
17 #include <QComboBox>
18 #include <QFileDialog>
19 #include <QFileInfo>
20 #include <QMainWindow>
21 #include <QMessageBox>
22 #include <QThread>
23 
24 static bool s_firstTimeInit = true;
25 
26 /*** HELPERS ***/
27 static QString GetEntityName(ccHObject* obj) {
28  if (!obj) {
29  assert(false);
30  return QString();
31  }
32 
33  QString name = obj->getName();
34  if (name.isEmpty()) name = "unnamed";
35  name += QString(" [ID %1]").arg(obj->getUniqueID());
36 
37  return name;
38 }
39 
40 static ccPointCloud* GetCloudFromCombo(QComboBox* comboBox, ccHObject* dbRoot) {
41  assert(comboBox && dbRoot);
42  if (!comboBox || !dbRoot) {
43  assert(false);
44  return 0;
45  }
46 
47  // return the cloud currently selected in the combox box
48  int index = comboBox->currentIndex();
49  if (index < 0) {
50  assert(false);
51  return 0;
52  }
53  assert(comboBox->itemData(index).isValid());
54  unsigned uniqueID = comboBox->itemData(index).toUInt();
55  ccHObject* item = dbRoot->find(uniqueID);
56  if (!item || !item->isA(CV_TYPES::POINT_CLOUD)) {
57  assert(false);
58  return 0;
59  }
60  return static_cast<ccPointCloud*>(item);
61 }
62 
63 /*** HELPERS (END) ***/
64 
66  ccPointCloud* cloud2,
68  : QDialog(app ? app->getMainWindow() : 0),
69  Ui::M3C2Dialog(),
70  m_app(app),
71  m_cloud1(nullptr),
72  m_cloud2(nullptr),
73  m_corePointsCloud(nullptr) {
74  setupUi(this);
75 
76  int maxThreadCount = QThread::idealThreadCount();
77  maxThreadCountSpinBox->setRange(1, maxThreadCount);
78  maxThreadCountSpinBox->setSuffix(QString(" / %1").arg(maxThreadCount));
79 
80  connect(showCloud1CheckBox, SIGNAL(toggled(bool)), this,
81  SLOT(setCloud1Visibility(bool)));
82  connect(showCloud2CheckBox, SIGNAL(toggled(bool)), this,
83  SLOT(setCloud2Visibility(bool)));
84 
85  connect(loadParamsToolButton, SIGNAL(clicked()), this,
86  SLOT(loadParamsFromFile()));
87  connect(saveParamsToolButton, SIGNAL(clicked()), this,
88  SLOT(saveParamsToFile()));
89  connect(swapCloudsToolButton, SIGNAL(clicked()), this, SLOT(swapClouds()));
90  connect(guessParamsPushButton, SIGNAL(clicked()), this,
91  SLOT(guessParamsSlow()));
92 
93  connect(projDestComboBox, SIGNAL(currentIndexChanged(int)), this,
94  SLOT(projDestIndexChanged(int)));
95 
96  connect(cpOtherCloudComboBox, SIGNAL(currentIndexChanged(int)), this,
97  SLOT(updateNormalComboBox()));
98  connect(normalSourceComboBox, SIGNAL(currentIndexChanged(int)), this,
100  connect(cpUseCloud1RadioButton, SIGNAL(toggled(bool)), this,
101  SLOT(updateNormalComboBox()));
102  connect(cpSubsampleRadioButton, SIGNAL(toggled(bool)), this,
103  SLOT(updateNormalComboBox()));
104  connect(cpUseOtherCloudRadioButton, SIGNAL(toggled(bool)), this,
105  SLOT(updateNormalComboBox()));
106 
108 
109  setClouds(cloud1, cloud2);
110 
111  if (m_app) {
112  // add list of clouds to the combo-boxes
113  ccHObject::Container clouds;
114  if (m_app->dbRootObject()) {
115  m_app->dbRootObject()->filterChildren(clouds, true,
117  }
118 
119  for (size_t i = 0; i < clouds.size(); ++i) {
120  if (clouds[i]->isA(CV_TYPES::POINT_CLOUD)) // as filterChildren
121  // only test 'isKindOf'
122  {
123  cpOtherCloudComboBox->addItem(
124  GetEntityName(clouds[i]),
125  QVariant(clouds[i]->getUniqueID()));
126  normOriCloudComboBox->addItem(
127  GetEntityName(clouds[i]),
128  QVariant(clouds[i]->getUniqueID()));
129  }
130  }
131  }
132 }
133 
134 bool PopulateSFCombo(QComboBox* combo,
135  const ccPointCloud& cloud,
136  int defaultFieldIndex = -1,
137  QString defaultField = QString()) {
138  unsigned sfCount = cloud.getNumberOfScalarFields();
139  if (!combo || sfCount == 0) {
140  assert(false);
141  return false;
142  }
143 
144  combo->clear();
145  int selectedFieldIndex = -1;
146  bool defaultFieldFound = false;
147  for (unsigned i = 0; i < sfCount; ++i) {
148  QString sfName = cloud.getScalarFieldName(i);
149  combo->addItem(sfName);
150  if (selectedFieldIndex < 0 && !defaultField.isEmpty()) {
151  if (sfName.contains(defaultField, Qt::CaseInsensitive)) {
152  selectedFieldIndex = static_cast<int>(i);
153  defaultFieldFound = true;
154  }
155  }
156  }
157 
158  if (selectedFieldIndex < 0) {
159  selectedFieldIndex = defaultFieldIndex;
160  }
161  combo->setCurrentIndex(selectedFieldIndex);
162 
163  return defaultFieldFound;
164 }
165 
166 bool PopulatePMFields(QComboBox* sx,
167  QComboBox* sy,
168  QComboBox* sz,
169  const ccPointCloud& cloud) {
170  assert(sx && sy && sz);
171  int sfCount = static_cast<int>(cloud.getNumberOfScalarFields());
172  if (sfCount == 0) {
173  assert(false);
174  return false;
175  }
176 
177  bool sxFound = PopulateSFCombo(sx, cloud, std::min<int>(sfCount, 0), "sx");
178  bool syFound = PopulateSFCombo(sy, cloud, std::min<int>(sfCount, 1), "sy");
179  bool szFound = PopulateSFCombo(sz, cloud, std::min<int>(sfCount, 2), "sz");
180 
181  return sxFound && syFound && szFound;
182 }
183 
185  precisionMapsGroupBox->setEnabled(false);
186 
187  if (!m_cloud1 || !m_cloud2) {
188  assert(false);
189  return;
190  }
191 
193  bool wasChecked = precisionMapsGroupBox->isChecked();
194  bool auto1 = PopulatePMFields(c1SxComboBox, c1SyComboBox, c1SzComboBox,
195  *m_cloud1);
196  bool auto2 = PopulatePMFields(c2SxComboBox, c2SyComboBox, c2SzComboBox,
197  *m_cloud2);
198  precisionMapsGroupBox->setChecked(wasChecked && (auto1 && auto2));
199  precisionMapsGroupBox->setEnabled(true);
200  }
201 }
202 
206 }
207 
209  if (!cloud1 || !cloud2) {
210  assert(false);
211  return;
212  }
213 
214  m_cloud1 = cloud1;
215  m_cloud2 = cloud2;
216 
217  // cloud #1
218  cloud1LineEdit->setText(GetEntityName(cloud1));
219  showCloud1CheckBox->blockSignals(true);
220  showCloud1CheckBox->setChecked(cloud1->isVisible());
221  showCloud1CheckBox->blockSignals(false);
222 
223  // cloud #2
224  cloud2LineEdit->setText(GetEntityName(cloud2));
225  showCloud2CheckBox->blockSignals(true);
226  showCloud2CheckBox->setChecked(cloud2->isVisible());
227  showCloud2CheckBox->blockSignals(false);
228 
229  if (s_firstTimeInit) {
230  // on initialization, try to guess some parameters from the input clouds
231  guessParams(true);
232  s_firstTimeInit = false;
233  }
234 
236 }
237 
239  int selectedItem = normalSourceComboBox->currentIndex() >= 0
240  ? normalSourceComboBox->currentData().toInt()
241  : -1;
242  switch (selectedItem) {
245  normParamsFrame->setEnabled(false);
246  normalScaleDoubleSpinBox->setEnabled(false);
247  break;
248  default:
249  normParamsFrame->setEnabled(true);
250  normalScaleDoubleSpinBox->setEnabled(true);
251  break;
252  }
253 }
254 
256  int previouslySelectedItem =
257  normalSourceComboBox->currentIndex() >= 0
258  ? normalSourceComboBox->currentData().toInt()
259  : -1;
260  int lastIndex = -1;
261  normalSourceComboBox->clear();
262  normalSourceComboBox->addItem("Compute normals (on core points)",
263  QVariant(qM3C2Normals::DEFAULT_MODE));
264  ++lastIndex;
265  // if (previouslySelectedItem == qM3C2Normals::DEFAULT_MODE)
266  {
267  normalSourceComboBox->setCurrentIndex(lastIndex); // default mode
268  }
269 
270  if (m_cloud1 && m_cloud1->hasNormals()) {
271  normalSourceComboBox->addItem(
272  "Use cloud #1 normals",
274  ++lastIndex;
275  if (previouslySelectedItem == qM3C2Normals::USE_CLOUD1_NORMALS ||
276  previouslySelectedItem < 0) {
277  normalSourceComboBox->setCurrentIndex(lastIndex);
278  previouslySelectedItem = qM3C2Normals::USE_CLOUD1_NORMALS;
279  }
280  }
281 
282  if (cpUseOtherCloudRadioButton->isChecked()) {
283  // return the cloud currently selected in the combox box
284  ccPointCloud* otherCloud =
285  GetCloudFromCombo(cpOtherCloudComboBox, m_app->dbRootObject());
286  if (otherCloud && otherCloud->hasNormals()) {
287  normalSourceComboBox->addItem(
288  "Use core points normals",
290  ++lastIndex;
291  if (previouslySelectedItem ==
293  previouslySelectedItem < 0) {
294  normalSourceComboBox->setCurrentIndex(lastIndex);
295  previouslySelectedItem = qM3C2Normals::USE_CORE_POINTS_NORMALS;
296  }
297  }
298  }
299 }
300 
302  if (m_corePointsCloud) {
303  return m_corePointsCloud;
304  } else if (cpUseCloud1RadioButton->isChecked()) {
305  return m_cloud1;
306  } else if (cpUseOtherCloudRadioButton->isChecked()) {
307  // return the cloud currently selected in the combox box
308  return GetCloudFromCombo(cpOtherCloudComboBox, m_app->dbRootObject());
309  } else {
310  return nullptr;
311  }
312 }
313 
315  if (normOriUseCloudRadioButton->isChecked()) {
316  // return the cloud currently selected in the combox box
317  return GetCloudFromCombo(normOriCloudComboBox, m_app->dbRootObject());
318  } else {
319  return nullptr;
320  }
321 }
322 
324  if (m_cloud1) {
325  m_cloud1->setVisible(state);
326  // m_cloud1->prepareDisplayForRefresh();
327  }
328  if (m_app) {
329  m_app->refreshAll();
330  m_app->updateUI();
331  }
332 }
333 
335  if (m_cloud2) {
336  m_cloud2->setVisible(state);
337  // m_cloud2->prepareDisplayForRefresh();
338  }
339  if (m_app) {
340  m_app->refreshAll();
341  m_app->updateUI();
342  }
343 }
344 
346  // special case
347  if (normalSourceComboBox->currentIndex() >= 0) {
348  int selectedItem = normalSourceComboBox->currentData().toInt();
349  if (selectedItem == qM3C2Normals::USE_CLOUD1_NORMALS) {
350  assert(m_cloud1 && m_cloud1->hasNormals());
352  } else if (selectedItem == qM3C2Normals::USE_CORE_POINTS_NORMALS) {
354  }
355  }
356 
357  // otherwise we are in the default mode
358  if (normMultiScaleRadioButton->isChecked()) {
360  } else if (normVertRadioButton->isChecked()) {
362  } else if (normHorizRadioButton->isChecked()) {
364  } else /*if (normDefaultRadioButton->isChecked())*/
365  {
367  }
368 }
369 
371  switch (projDestComboBox->currentIndex()) {
372  case 0:
373  return PROJECT_ON_CLOUD1;
374  case 1:
375  return PROJECT_ON_CLOUD2;
376  case 2:
377  return PROJECT_ON_CORE_POINTS;
378  default:
379  assert(false);
380  break;
381  }
382 
383  return PROJECT_ON_CORE_POINTS;
384 }
385 
387  useOriginalCloudCheckBox->setEnabled(getExportOption() ==
389 }
390 
392  return useOriginalCloudCheckBox->isEnabled() &&
393  useOriginalCloudCheckBox->isChecked();
394 }
395 
397  return maxThreadCountSpinBox->value();
398 }
399 
400 unsigned qM3C2Dialog::getMinPointsForStats(unsigned defaultValue /*=5*/) const {
401  return useMinPoints4StatCheckBox->isChecked()
402  ? static_cast<unsigned>(
403  std::max(0, minPoints4StatSpinBox->value()))
404  : defaultValue;
405 }
406 
408  QSettings settings("qM3C2");
409  loadParamsFrom(settings);
410 }
411 
412 void qM3C2Dialog::loadParamsFrom(const QSettings& settings) {
413  // read out parameters
414  double normalScale =
415  settings.value("NormalScale", normalScaleDoubleSpinBox->value())
416  .toDouble();
417  int normModeInt =
418  settings.value("NormalMode",
419  static_cast<int>(getNormalsComputationMode()))
420  .toInt();
421  double normMinScale =
422  settings.value("NormalMinScale", minScaleDoubleSpinBox->value())
423  .toDouble();
424  double normStep =
425  settings.value("NormalStep", stepScaleDoubleSpinBox->value())
426  .toDouble();
427  double normMaxScale =
428  settings.value("NormalMaxScale", maxScaleDoubleSpinBox->value())
429  .toDouble();
430  bool normUseCorePoints =
431  settings.value("NormalUseCorePoints",
432  normUseCorePointsCheckBox->isChecked())
433  .toBool();
434  int normPreferredOri =
435  settings.value("NormalPreferedOri",
436  normOriPreferredComboBox->currentIndex())
437  .toInt();
438 
439  double seachScale =
440  settings.value("SearchScale", cylDiameterDoubleSpinBox->value())
441  .toDouble();
442  double searchDepth =
443  settings.value("SearchDepth", cylHalfHeightDoubleSpinBox->value())
444  .toDouble();
445 
446  double subsampleRadius = settings.value("SubsampleRadius",
447  cpSubsamplingDoubleSpinBox->value())
448  .toDouble();
449  bool subsampleEnabled = settings.value("SubsampleEnabled",
450  cpSubsampleRadioButton->isChecked())
451  .toBool();
452 
453  double registrationError =
454  settings.value("RegistrationError", rmsDoubleSpinBox->value())
455  .toDouble();
456  bool registrationErrorEnabled =
457  settings.value("RegistrationErrorEnabled", rmsCheckBox->isChecked())
458  .toBool();
459 
460  bool useSinglePass4Depth =
461  settings.value("UseSinglePass4Depth",
462  useSinglePass4DepthCheckBox->isChecked())
463  .toBool();
464  bool positiveSearchOnly =
465  settings.value("PositiveSearchOnly",
466  positiveSearchOnlyCheckBox->isChecked())
467  .toBool();
468  bool useMedian = settings.value("UseMedian", useMedianCheckBox->isChecked())
469  .toBool();
470 
471  bool useMinPoints4Stat =
472  settings.value("UseMinPoints4Stat",
473  useMinPoints4StatCheckBox->isChecked())
474  .toBool();
475  int minPoints4Stat =
476  settings.value("MinPoints4Stat", minPoints4StatSpinBox->value())
477  .toInt();
478 
479  int projDestIndex =
480  settings.value("ProjDestIndex", projDestComboBox->currentIndex())
481  .toInt();
482  bool useOriginalCloud =
483  settings.value("UseOriginalCloud",
484  useOriginalCloudCheckBox->isChecked())
485  .toBool();
486 
487  bool exportStdDevInfo =
488  settings.value("ExportStdDevInfo",
489  exportStdDevInfoCheckBox->isChecked())
490  .toBool();
491  bool exportDensityAtProjScale =
492  settings.value("ExportDensityAtProjScale",
493  exportDensityAtProjScaleCheckBox->isChecked())
494  .toBool();
495 
496  int maxThreadCount =
497  settings.value("MaxThreadCount", maxThreadCountSpinBox->maximum())
498  .toInt();
499 
500  bool usePrecisionMaps = settings.value("UsePrecisionMaps",
501  precisionMapsGroupBox->isChecked())
502  .toBool();
503  double pm1Scale = settings.value("PM1Scale", pm1ScaleDoubleSpinBox->value())
504  .toDouble();
505  double pm2Scale = settings.value("PM2Scale", pm2ScaleDoubleSpinBox->value())
506  .toDouble();
507 
508  // apply parameters
509  normalScaleDoubleSpinBox->setValue(normalScale);
510  switch (normModeInt) {
513  bool found = false;
514  for (int i = 0; i < normalSourceComboBox->count(); ++i) {
515  if (normalSourceComboBox->itemData(i) == normModeInt) {
516  normalSourceComboBox->setCurrentIndex(i);
517  found = true;
518  break;
519  }
520  }
521  if (!found) {
523  "Can't restore the previous normal computation method "
524  "(cloud #1 or core points has no normals)");
525  }
526  } break;
527 
529  normDefaultRadioButton->setChecked(true);
530  break;
531 
533  normMultiScaleRadioButton->setChecked(true);
534  break;
535 
537  normVertRadioButton->setChecked(true);
538  break;
539 
541  normHorizRadioButton->setChecked(true);
542  break;
543 
544  default:
545  // nothing to do
546  break;
547  }
548 
549  minScaleDoubleSpinBox->setValue(normMinScale);
550  stepScaleDoubleSpinBox->setValue(normStep);
551  maxScaleDoubleSpinBox->setValue(normMaxScale);
552  normUseCorePointsCheckBox->setChecked(normUseCorePoints);
553  normOriPreferredComboBox->setCurrentIndex(normPreferredOri);
554 
555  cylDiameterDoubleSpinBox->setValue(seachScale);
556  cylHalfHeightDoubleSpinBox->setValue(searchDepth);
557 
558  cpSubsamplingDoubleSpinBox->setValue(subsampleRadius);
559  cpSubsampleRadioButton->setChecked(subsampleEnabled);
560 
561  rmsCheckBox->setChecked(registrationErrorEnabled);
562  rmsDoubleSpinBox->setValue(registrationError);
563 
564  useSinglePass4DepthCheckBox->setChecked(useSinglePass4Depth);
565  positiveSearchOnlyCheckBox->setChecked(positiveSearchOnly);
566  useMedianCheckBox->setChecked(useMedian);
567 
568  useMinPoints4StatCheckBox->setChecked(useMinPoints4Stat);
569  minPoints4StatSpinBox->setValue(minPoints4Stat);
570 
571  projDestComboBox->setCurrentIndex(projDestIndex);
572  useOriginalCloudCheckBox->setChecked(useOriginalCloud);
573 
574  exportStdDevInfoCheckBox->setChecked(exportStdDevInfo);
575  exportDensityAtProjScaleCheckBox->setChecked(exportDensityAtProjScale);
576 
577  maxThreadCountSpinBox->setValue(maxThreadCount);
578 
579  precisionMapsGroupBox->setChecked(usePrecisionMaps);
580  pm1ScaleDoubleSpinBox->setValue(pm1Scale);
581  pm2ScaleDoubleSpinBox->setValue(pm2Scale);
582 }
583 
585  QSettings settings("qM3C2");
586  saveParamsTo(settings);
587 }
588 
589 void qM3C2Dialog::saveParamsTo(QSettings& settings) {
590  // save parameters
591  settings.setValue("NormalScale", normalScaleDoubleSpinBox->value());
592  settings.setValue("NormalMode",
593  static_cast<int>(getNormalsComputationMode()));
594  settings.setValue("NormalMinScale", minScaleDoubleSpinBox->value());
595  settings.setValue("NormalStep", stepScaleDoubleSpinBox->value());
596  settings.setValue("NormalMaxScale", maxScaleDoubleSpinBox->value());
597  settings.setValue("NormalUseCorePoints",
598  normUseCorePointsCheckBox->isChecked());
599  settings.setValue("NormalPreferedOri",
600  normOriPreferredComboBox->currentIndex());
601 
602  settings.setValue("SearchScale", cylDiameterDoubleSpinBox->value());
603  settings.setValue("SearchDepth", cylHalfHeightDoubleSpinBox->value());
604 
605  settings.setValue("SubsampleRadius", cpSubsamplingDoubleSpinBox->value());
606  settings.setValue("SubsampleEnabled", cpSubsampleRadioButton->isChecked());
607 
608  settings.setValue("RegistrationError", rmsDoubleSpinBox->value());
609  settings.setValue("RegistrationErrorEnabled", rmsCheckBox->isChecked());
610 
611  settings.setValue("UseSinglePass4Depth",
612  useSinglePass4DepthCheckBox->isChecked());
613  settings.setValue("PositiveSearchOnly",
614  positiveSearchOnlyCheckBox->isChecked());
615  settings.setValue("UseMedian", useMedianCheckBox->isChecked());
616 
617  settings.setValue("UseMinPoints4Stat",
618  useMinPoints4StatCheckBox->isChecked());
619  settings.setValue("MinPoints4Stat", minPoints4StatSpinBox->value());
620 
621  settings.setValue("ProjDestIndex", projDestComboBox->currentIndex());
622  settings.setValue("UseOriginalCloud",
623  useOriginalCloudCheckBox->isChecked());
624 
625  settings.setValue("ExportStdDevInfo",
626  exportStdDevInfoCheckBox->isChecked());
627  settings.setValue("ExportDensityAtProjScale",
628  exportDensityAtProjScaleCheckBox->isChecked());
629 
630  settings.setValue("MaxThreadCount", maxThreadCountSpinBox->value());
631 
632  settings.setValue("UsePrecisionMaps", precisionMapsGroupBox->isChecked());
633  settings.setValue("PM1Scale", pm1ScaleDoubleSpinBox->value());
634  settings.setValue("PM2Scale", pm2ScaleDoubleSpinBox->value());
635 }
636 
638  // select file to open
639  QString filename;
640  {
641  QSettings settings("qM3C2");
642  QString currentPath =
643  settings.value("currentPath", ecvFileUtils::defaultDocPath())
644  .toString();
645 
646  filename = QFileDialog::getOpenFileName(this, "Load M3C2 parameters",
647  currentPath, "*.txt");
648  if (filename.isEmpty()) return;
649 
650  // we update current file path
651  currentPath = QFileInfo(filename).absolutePath();
652  settings.setValue("currentPath", currentPath);
653  }
654 
656 }
657 
659  QSettings fileSettings(filename, QSettings::IniFormat);
660  // check validity
661  if (!fileSettings.contains("M3C2VER")) {
662  QMessageBox::critical(this, "Invalid file",
663  "File doesn't seem to be a valid M3C2 parameters "
664  "file ('M3C2VER' not found)!");
665  return false;
666  }
667 
668  loadParamsFrom(fileSettings);
669 
670  return true;
671 }
672 
674  // select file to save
675  QString filename;
676  {
677  QSettings settings("qM3C2");
678  QString currentPath =
679  settings.value("currentPath", ecvFileUtils::defaultDocPath())
680  .toString();
681 
682  filename = QFileDialog::getSaveFileName(
683  this, "Save M3C2 parameters",
684  currentPath + QString("/m3c2_params.txt"), "*.txt");
685  if (filename.isEmpty()) return;
686 
687  // we update current file path
688  currentPath = QFileInfo(filename).absolutePath();
689  settings.setValue("currentPath", currentPath);
690  }
691 
692  // save file
693  {
694  QSettings fileSettings(filename, QSettings::IniFormat);
695  // set version tag (mandatory for a valid parameters file!)
696  fileSettings.setValue("M3C2VER", QVariant::fromValue<int>(1));
697  saveParamsTo(fileSettings);
698  }
699 }
700 
701 void qM3C2Dialog::guessParams(bool fastMode /*=false*/) {
702  if (!m_cloud1 || !m_cloud2) return;
703 
704  // see article: ideal = 30 while default = 5
705  unsigned minPoints4Stats = getMinPointsForStats() * 6;
706 
708  if (qM3C2Tools::GuessBestParams(m_cloud1, m_cloud2, minPoints4Stats, params,
709  fastMode, m_app)) {
710  normalScaleDoubleSpinBox->setValue(params.normScale);
711  cylDiameterDoubleSpinBox->setValue(params.projScale);
712  cylHalfHeightDoubleSpinBox->setValue(params.projDepth);
713  if (params.preferredDimension >= 0 && params.preferredDimension < 3) {
714  //*2 because for each dimension, the preferred
715  // orientation is either + or -
716  normOriPreferredComboBox->setCurrentIndex(
717  params.preferredDimension * 2);
718  }
719 
720  minScaleDoubleSpinBox->setValue(params.normScale / 2);
721  stepScaleDoubleSpinBox->setValue(params.normScale / 2);
722  maxScaleDoubleSpinBox->setValue(params.normScale * 2);
723 
724  cpSubsamplingDoubleSpinBox->setValue(params.projScale / 2);
725  }
726 }
std::string filename
std::string name
cmdLineReadable * params[]
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
virtual bool isVisible() const
Returns whether entity is visible or not.
virtual void setVisible(bool state)
Sets entity visibility.
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
ccHObject * find(unsigned uniqueID)
Finds an entity in this object hierarchy.
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
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
bool hasNormals() const override
Returns whether normals are enabled or not.
bool hasScalarFields() const override
Returns whether one or more scalar fields are instantiated.
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.
void setValue(std::size_t index, ScalarType value)
Definition: ScalarField.h:96
Main application interface (for plugins)
virtual void updateUI()=0
virtual ccHObject * dbRootObject()=0
Returns DB root (as a ccHObject)
virtual void refreshAll(bool only2D=false, bool forceRedraw=true)=0
Redraws all GL windows that have the 'refresh' flag on.
void guessParams(bool fastMode)
Guess parameters from the cloud #1.
qM3C2Normals::ComputationMode getNormalsComputationMode() const
Returns selected normals computation mode.
void onUpdateNormalComboBoxChanged(int)
ecvMainAppInterface * m_app
Definition: qM3C2Dialog.h:114
void saveParamsToFile()
void setCloud1Visibility(bool)
void loadParamsFromFile()
unsigned getMinPointsForStats(unsigned defaultValue=5) const
ccPointCloud * m_cloud2
Definition: qM3C2Dialog.h:117
ExportOptions
Exportation options.
Definition: qM3C2Dialog.h:57
@ PROJECT_ON_CLOUD1
Definition: qM3C2Dialog.h:58
@ PROJECT_ON_CORE_POINTS
Definition: qM3C2Dialog.h:60
@ PROJECT_ON_CLOUD2
Definition: qM3C2Dialog.h:59
void loadParamsFromPersistentSettings()
Loads parameters from persistent settings.
ccPointCloud * m_cloud1
Definition: qM3C2Dialog.h:116
void guessParamsSlow()
Definition: qM3C2Dialog.h:89
ccPointCloud * getNormalsOrientationCloud() const
Returns the cloud to be used for normals orientation (if any)
void updateNormalComboBox()
Updates the normalSourceComboBox.
ccPointCloud * m_corePointsCloud
Definition: qM3C2Dialog.h:118
qM3C2Dialog(ccPointCloud *cloud1, ccPointCloud *cloud2, ecvMainAppInterface *app)
Default constructor.
Definition: qM3C2Dialog.cpp:65
void loadParamsFrom(const QSettings &settings)
Load parameters from QSettings.
void swapClouds()
ExportOptions getExportOption() const
Returns selected export option.
void setupPrecisionMapsTab()
Setups the precision maps tab.
void projDestIndexChanged(int)
void setCloud2Visibility(bool)
ccPointCloud * getCorePointsCloud() const
Get core points cloud (if any)
int getMaxThreadCount() const
Returns the max number of threads to use.
void setClouds(ccPointCloud *cloud1, ccPointCloud *cloud2)
Sets clouds.
bool keepOriginalCloud() const
void saveParamsTo(QSettings &settings)
Saves parameters to QSettings.
void saveParamsToPersistentSettings()
Saves parameters to persistent settings.
ComputationMode
Normals computation mode.
Definition: qM3C2Tools.h:27
@ USE_CLOUD1_NORMALS
Definition: qM3C2Tools.h:29
@ USE_CORE_POINTS_NORMALS
Definition: qM3C2Tools.h:33
@ MULTI_SCALE_MODE
Definition: qM3C2Tools.h:30
static bool GuessBestParams(ccPointCloud *cloud1, ccPointCloud *cloud2, unsigned minPoints4Stats, GuessedParams &params, bool fastMode, ecvMainAppInterface *app=nullptr, unsigned probingCount=1000)
Tries to guess some M3C2 parameters by randomly 'probing' the cloud.
Definition: qM3C2Tools.cpp:529
int max(int a, int b)
Definition: cutil_math.h:48
@ POINT_CLOUD
Definition: CVTypes.h:104
constexpr QRegularExpression::PatternOption CaseInsensitive
Definition: QtCompat.h:174
QString defaultDocPath()
Shortcut for getting the documents location path.
Definition: ecvFileUtils.h:30
static bool s_firstTimeInit
Definition: qM3C2Dialog.cpp:24
bool PopulatePMFields(QComboBox *sx, QComboBox *sy, QComboBox *sz, const ccPointCloud &cloud)
static QString GetEntityName(ccHObject *obj)
Definition: qM3C2Dialog.cpp:27
static ccPointCloud * GetCloudFromCombo(QComboBox *comboBox, ccHObject *dbRoot)
Definition: qM3C2Dialog.cpp:40
bool PopulateSFCombo(QComboBox *combo, const ccPointCloud &cloud, int defaultFieldIndex=-1, QString defaultField=QString())
ccScalarField * normalScale
Definition: qM3C2Tools.cpp:44
M3C2 parameters that can be guessed automatically by 'probing'.
Definition: qM3C2Tools.h:78