ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
TemplateAlignmentDialog.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 
9 
10 // CV_DB_LIB
11 #include <ecvMainAppInterface.h>
12 #include <ecvPointCloud.h>
13 
14 // Qt
15 #include <QApplication>
16 #include <QComboBox>
17 #include <QMainWindow>
18 #include <QPushButton>
19 #include <QSettings>
20 #include <QThread>
21 
22 // Qt5/Qt6 Compatibility
23 #include <QtCompat.h>
24 
25 // system
26 #include <limits>
27 
29  : QDialog(app ? app->getActiveWindow() : 0),
31  m_app(app) {
32  setupUi(this);
33 
34  int maxThreadCount = QThread::idealThreadCount();
35  maxThreadCountSpinBox->setRange(1, maxThreadCount);
36  maxThreadCountSpinBox->setSuffix(QString("/%1").arg(maxThreadCount));
37  maxThreadCountSpinBox->setValue(maxThreadCount);
38 
40 
41  connect(template1CloudComboBox, SIGNAL(currentIndexChanged(int)), this,
42  SLOT(onCloudChanged(int)));
43  connect(template2CloudComboBox, SIGNAL(currentIndexChanged(int)), this,
44  SLOT(onCloudChanged(int)));
45 
46  onCloudChanged(0);
47 }
48 
50  if (m_app) {
51  // add list of clouds to the combo-boxes
52  ccHObject::Container clouds;
53  if (m_app->dbRootObject())
54  m_app->dbRootObject()->filterChildren(clouds, true,
56 
57  unsigned cloudCount = 0;
58  template1CloudComboBox->clear();
59  template2CloudComboBox->clear();
60  evaluationCloudComboBox->clear();
61  for (size_t i = 0; i < clouds.size(); ++i) {
62  if (clouds[i]->isA(CV_TYPES::POINT_CLOUD)) // as filterChildren
63  // only test 'isKindOf'
64  {
65  QString name = getEntityName(clouds[i]);
66  QVariant uniqueID(clouds[i]->getUniqueID());
67  template1CloudComboBox->addItem(name, uniqueID);
68  template2CloudComboBox->addItem(name, uniqueID);
69  evaluationCloudComboBox->addItem(name, uniqueID);
70  ++cloudCount;
71  }
72  }
73 
74  // if 3 clouds are loaded, then there's chances that the first one is
75  // the global cloud!
76  template1CloudComboBox->setCurrentIndex(
77  cloudCount > 0 ? (cloudCount > 2 ? 1 : 0) : -1);
78  template2CloudComboBox->setCurrentIndex(
79  cloudCount > 1 ? (cloudCount > 2 ? 2 : 1) : -1);
80 
81  if (cloudCount < 1 && m_app)
82  m_app->dispToConsole(tr("You need at least 1 loaded clouds to "
83  "perform alignment"),
85  }
86 }
87 
89  int c1 = template1CloudComboBox->currentIndex();
90  if (template1checkBox->isChecked()) {
91  if (c1 < 0) {
92  return false;
93  }
94  }
95  int c2 = template2CloudComboBox->currentIndex();
96  if (template2checkBox->isChecked()) {
97  if (c2 < 0) {
98  return false;
99  }
100  }
101 
102  if (template1checkBox->isChecked() && template2checkBox->isChecked()) {
103  if (c1 == c2) return false;
104  }
105 
106  return true;
107 }
108 
110  return maxThreadCountSpinBox->value();
111 }
112 
114  return static_cast<float>(normalRadiusSpinBox->value());
115 }
116 
118  return static_cast<float>(featureRadiusSpinBox->value());
119 }
120 
122  return static_cast<float>(minSampleDistanceSpinBox->value());
123 }
124 
126  return static_cast<float>(maxCorrespondenceDistanceSpinBox->value() *
127  maxCorrespondenceDistanceSpinBox->value());
128 }
129 
131  return maxIterationsSpinBox->value();
132 }
133 
135  if (useVoxelGridCheckBox->isChecked()) {
136  return static_cast<float>(leafSizeSpinBox->value());
137  } else {
138  return -1.0f;
139  }
140 }
141 
142 bool TemplateAlignmentDialog::getScales(std::vector<float>& scales) const {
143  scales.clear();
144 
145  try {
146  if (scalesRampRadioButton->isChecked()) {
147  double maxScale = maxScaleDoubleSpinBox->value();
148  double step = stepScaleDoubleSpinBox->value();
149  double minScale = minScaleDoubleSpinBox->value();
150  if (maxScale < minScale || maxScale < 0 || step < 1.0e-6)
151  return false;
152  unsigned stepCount =
153  static_cast<unsigned>(
154  floor((maxScale - minScale) / step + 1.0e-6)) +
155  1;
156  scales.resize(stepCount);
157  for (unsigned i = 0; i < stepCount; ++i)
158  scales[i] = static_cast<float>(maxScale - i * step);
159  } else if (scalesListRadioButton->isChecked()) {
160  QStringList scaleList = scalesListLineEdit->text().split(
162 
163  int listSize = scaleList.size();
164  scales.resize(listSize);
165  for (int i = 0; i < listSize; ++i) {
166  bool ok = false;
167  float f;
168  f = scaleList[i].toFloat(&ok);
169  if (!ok) return false;
170  scales[i] = f;
171  }
172  } else {
173  return false;
174  }
175  } catch (const std::bad_alloc&) {
176  return false;
177  }
178 
179  return true;
180 }
181 
183  buttonBox->button(QDialogButtonBox::Ok)->setEnabled(validParameters());
184 }
185 
187  // return the cloud currently selected in the combox box
188  if (template1checkBox->isChecked()) {
189  return getCloudFromCombo(template1CloudComboBox, m_app->dbRootObject());
190  } else {
191  return nullptr;
192  }
193 }
194 
196  // return the cloud currently selected in the combox box
197  if (template2checkBox->isChecked()) {
198  return getCloudFromCombo(template2CloudComboBox, m_app->dbRootObject());
199  } else {
200  return nullptr;
201  }
202 }
203 
205  // return the cloud currently selected in the combox box
206  return getCloudFromCombo(evaluationCloudComboBox, m_app->dbRootObject());
207 }
208 
210  QSettings settings("templateAlignment");
211  settings.beginGroup("Align");
212 
213  // read out parameters
214  // double minScale =
215  // settings.value("MinScale",minScaleDoubleSpinBox->value()).toDouble();
216  // double step =
217  // settings.value("Step",stepScaleDoubleSpinBox->value()).toDouble(); double
218  // maxScale =
219  // settings.value("MaxScale",maxScaleDoubleSpinBox->value()).toDouble();
220  // QString scalesList =
221  // settings.value("ScalesList",scalesListLineEdit->text()).toString(); bool
222  // scalesRampEnabled =
223  // settings.value("ScalesRampEnabled",scalesRampRadioButton->isChecked()).toBool();
224 
225  // unsigned maxPoints =
226  // settings.value("MaxPoints",maxPointsSpinBox->value()).toUInt(); int
227  // classifParam =
228  // settings.value("ClassifParam",paramComboBox->currentIndex()).toInt(); int
229  // maxThreadCount = settings.value("MaxThreadCount",
230  // maxThreadCountSpinBox->maximum()).toInt();
231 
233 
234  // minScaleDoubleSpinBox->setValue(minScale);
235  // stepScaleDoubleSpinBox->setValue(step);
236  // maxScaleDoubleSpinBox->setValue(maxScale);
237  // scalesListLineEdit->setText(scalesList);
238  // if (scalesRampEnabled)
239  // scalesRampRadioButton->setChecked(true);
240  // else
241  // scalesListRadioButton->setChecked(true);
242 
243  // maxPointsSpinBox->setValue(maxPoints);
244  // paramComboBox->setCurrentIndex(classifParam);
245  // maxThreadCountSpinBox->setValue(maxThreadCount);
246 }
247 
249  QSettings settings("templateAlignment");
250  settings.beginGroup("Align");
251 
252  // save parameters
253  // settings.setValue("MinScale", minScaleDoubleSpinBox->value());
254  // settings.setValue("Step", stepScaleDoubleSpinBox->value());
255  // settings.setValue("MaxScale", maxScaleDoubleSpinBox->value());
256  // settings.setValue("ScalesList", scalesListLineEdit->text());
257  // settings.setValue("ScalesRampEnabled",
258  // scalesRampRadioButton->isChecked());
259 
260  // settings.setValue("MaxPoints", maxPointsSpinBox->value());
261  // settings.setValue("ClassifParam", paramComboBox->currentIndex());
262  // settings.setValue("MaxThreadCount", maxThreadCountSpinBox->value());
263 }
264 
266  if (!obj) {
267  assert(false);
268  return QString();
269  }
270 
271  QString name = obj->getName();
272  if (name.isEmpty()) name = tr("unnamed");
273  name += QString(" [ID %1]").arg(obj->getUniqueID());
274 
275  return name;
276 }
277 
279  ccHObject* dbRoot) {
280  assert(comboBox && dbRoot);
281  if (!comboBox || !dbRoot) {
282  assert(false);
283  return nullptr;
284  }
285 
286  // return the cloud currently selected in the combox box
287  int index = comboBox->currentIndex();
288  if (index < 0) {
289  assert(false);
290  return nullptr;
291  }
292  unsigned uniqueID = comboBox->itemData(index).toUInt();
293  ccHObject* item = dbRoot->find(uniqueID);
294  if (!item || !item->isA(CV_TYPES::POINT_CLOUD)) {
295  assert(false);
296  return nullptr;
297  }
298  return static_cast<ccPointCloud*>(item);
299 }
std::string name
CANUPO plugin's training dialog.
float getMaxCorrespondenceDistance() const
Returns the Maximum Correspondence Distance.
TemplateAlignmentDialog(ecvMainAppInterface *app)
Default constructor.
float getFeatureRadius() const
Returns the Feature Radius.
float getMinSampleDistance() const
Returns the Minimum Sample Distance.
ecvMainAppInterface * m_app
Gives access to the application (data-base, UI, etc.)
void loadParamsFromPersistentSettings()
Loads parameters from persistent settings.
bool getScales(std::vector< float > &scales) const
Returns input scales.
int getMaxIterations() const
Returns the Maximum Iterations.
int getMaxThreadCount() const
Returns the max number of threads to use.
void saveParamsToPersistentSettings()
Saves parameters to persistent settings.
ccPointCloud * getTemplate1Cloud()
Get template #1 point cloud.
float getNormalRadius() const
Returns the Normal Radius.
ccPointCloud * getCloudFromCombo(QComboBox *comboBox, ccHObject *dbRoot)
ccPointCloud * getTemplate2Cloud()
Get template #2 point cloud.
ccPointCloud * getEvaluationCloud()
Get evaluation point cloud.
QString getEntityName(ccHObject *obj)
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.)
Main application interface (for plugins)
virtual ccHObject * dbRootObject()=0
Returns DB root (as a ccHObject)
virtual void dispToConsole(QString message, ConsoleMessageLevel level=STD_CONSOLE_MESSAGE)=0
@ POINT_CLOUD
Definition: CVTypes.h:104
constexpr Qt::SplitBehavior SkipEmptyParts
Definition: QtCompat.h:302
MiniVec< float, N > floor(const MiniVec< float, N > &a)
Definition: MiniVec.h:75