ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvShiftAndScaleCloudDlg.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 // GUIs generated by Qt Designer
11 #include <ui_globalShiftAndScaleAboutDlg.h>
12 #include <ui_globalShiftAndScaleDlg.h>
13 
14 // Local
15 #include "ecvGlobalShiftManager.h"
16 
17 // Qt
18 #include <QDebug>
19 #include <QDir>
20 #include <QFile>
21 #include <QPushButton>
22 #include <QStringList>
23 #include <QTextStream>
24 
25 // Qt5/Qt6 Compatibility
26 #include <QtCompat.h>
27 
28 // CV_DB_LIB
29 #include <CVLog.h>
30 
31 // system
32 #include <assert.h>
33 #include <float.h>
34 
35 // default name for the Global Shift List file
36 static QString s_defaultGlobalShiftListFilename("global_shift_list.txt");
37 
39  double Dg /*=0*/,
40  QWidget* parent /*=0*/)
41  : QDialog(parent),
42  m_ui(0),
43  m_applyAll(false),
44  m_cancel(false),
45  m_activeInfoIndex(-1),
46  m_originalPoint(Pg),
47  m_originalDiagonal(Dg),
48  m_localPoint(0, 0, 0),
49  m_localDiagonal(-1.0),
50  m_reversedMode(false) {
51  init();
52 
53  showWarning(false);
57  showCancelButton(false);
58 }
59 
61  double Dl,
62  const CCVector3d& Pg,
63  double Dg,
64  QWidget* parent /*=0*/)
65  : QDialog(parent),
66  m_ui(0),
67  m_applyAll(false),
68  m_cancel(false),
69  m_activeInfoIndex(-1),
70  m_originalPoint(Pg),
71  m_originalDiagonal(Dg),
72  m_localPoint(Pl),
73  m_localDiagonal(Dl),
74  m_reversedMode(true) {
75  init();
76 
77  showWarning(false);
78  showTitle(false);
82  showCancelButton(true);
83 
84  // to update the GUI accordingly
85  onGlobalPosCheckBoxToggled(m_ui->keepGlobalPosCheckBox->isChecked());
86 }
87 
89  if (m_ui) {
90  delete m_ui;
91  m_ui = 0;
92  }
93 }
94 
96  m_ui->shiftX->setDecimals(precision);
97  m_ui->shiftY->setDecimals(precision);
98  m_ui->shiftZ->setDecimals(precision);
99 }
100 
102  // should be called once and only once!
103  if (m_ui) {
104  assert(false);
105  return;
106  }
107 
108  m_ui = new Ui_GlobalShiftAndScaleDlg;
109  m_ui->setupUi(this);
110 
111  // DGM: we sometimes need to input values > 1.0e9 (for georeferenced clouds
112  // expressed in mm!)
113  m_ui->shiftX->setRange(-1.0e12, 1.0e12);
114  m_ui->shiftY->setRange(-1.0e12, 1.0e12);
115  m_ui->shiftZ->setRange(-1.0e12, 1.0e12);
116 
118 
119  connect(m_ui->loadComboBox, SIGNAL(currentIndexChanged(int)), this,
120  SLOT(onLoadIndexChanged(int)));
121  connect(m_ui->moreInfoToolButton, SIGNAL(clicked()), this,
122  SLOT(displayMoreInfo()));
123  connect(m_ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), this,
124  SLOT(onClick(QAbstractButton*)));
125  connect(m_ui->shiftX, SIGNAL(valueChanged(double)), this,
127  connect(m_ui->shiftY, SIGNAL(valueChanged(double)), this,
129  connect(m_ui->shiftZ, SIGNAL(valueChanged(double)), this,
131  connect(m_ui->scaleSpinBox, SIGNAL(valueChanged(double)), this,
133  connect(m_ui->keepGlobalPosCheckBox, SIGNAL(toggled(bool)), this,
134  SLOT(onGlobalPosCheckBoxToggled(bool)));
135 }
136 
138  QDialog dlg(this);
139  Ui_GlobalShiftAndScaleAboutDlg uiDlg;
140  uiDlg.setupUi(&dlg);
141 
142  dlg.exec();
143 }
144 
146  // try to load the 'global_shift_list.txt" file
147  return loadInfoFromFile(QDir::currentPath() + QString("/") +
149 }
150 
152  QFile file(filename);
153  if (!file.open(QFile::Text | QFile::ReadOnly)) return false;
154 
155  size_t originalSize = m_defaultInfos.size();
156 
157  QTextStream stream(&file);
158  unsigned lineNumber = 0;
159 
160  while (true) {
161  // read next line
162  QString line = stream.readLine();
163  if (line.isEmpty()) break;
164  ++lineNumber;
165 
166  if (line.startsWith("//")) continue;
167 
168  // split line in 5 items
169  QStringList tokens = line.split(";", QtCompat::SkipEmptyParts);
170  if (tokens.size() != 5) {
171  // invalid file
173  QString("[ecvShiftAndScaleCloudDlg::loadInfoFromFile] File "
174  "'%1' is malformed (5 items expected per line)")
175  .arg(filename));
176  m_defaultInfos.resize(originalSize);
177  return false;
178  }
179 
180  // decode items
181  bool ok = true;
182  unsigned errors = 0;
184  info.name = tokens[0].trimmed();
185  info.shift.x = tokens[1].toDouble(&ok);
186  if (!ok) ++errors;
187  info.shift.y = tokens[2].toDouble(&ok);
188  if (!ok) ++errors;
189  info.shift.z = tokens[3].toDouble(&ok);
190  if (!ok) ++errors;
191  info.scale = tokens[4].toDouble(&ok);
192  if (!ok) ++errors;
193 
194  // process errors
195  if (errors) {
196  // invalid file
197  CVLog::Warning(QString("[ecvShiftAndScaleCloudDlg::"
198  "loadInfoFromFile] File '%1' is malformed "
199  "(wrong item type encountered on line %2)")
200  .arg(filename)
201  .arg(lineNumber));
202  m_defaultInfos.resize(originalSize);
203  return false;
204  }
205 
206  try {
207  m_defaultInfos.push_back(info);
208  } catch (const std::bad_alloc&) {
209  // not enough memory
211  QString("[ecvShiftAndScaleCloudDlg::loadInfoFromFile] Not "
212  "enough memory to read file '%1'")
213  .arg(filename));
214  m_defaultInfos.resize(originalSize);
215  return false;
216  }
217  }
218 
219  // now add the new entries in the combo-box
220  for (size_t i = originalSize; i < m_defaultInfos.size(); ++i) {
221  m_ui->loadComboBox->addItem(m_defaultInfos[i].name);
222  }
223  m_ui->loadComboBox->setEnabled(m_defaultInfos.size() >= 2);
224 
225  return true;
226 }
227 
231 }
232 
233 bool AlmostEq(double a, double b) {
234  qint64 ai = static_cast<qint64>(a * 100.0);
235  qint64 bi = static_cast<qint64>(b * 100.0);
236 
237  return ai == bi;
238 }
239 
242  double diag = m_originalDiagonal;
243  if (m_reversedMode && !keepGlobalPos()) {
244  P = (m_localPoint - getShift()) / getScale();
245  diag = m_localDiagonal / getScale();
246  }
247 
248  m_ui->xOriginLabel->setText(QString("x = %1").arg(P.x, 0, 'f'));
249  m_ui->xOriginLabel->setStyleSheet(AlmostEq(P.x, m_originalPoint.x)
250  ? QString()
251  : QString("color: purple;"));
252  m_ui->yOriginLabel->setText(QString("y = %1").arg(P.y, 0, 'f'));
253  m_ui->yOriginLabel->setStyleSheet(AlmostEq(P.y, m_originalPoint.y)
254  ? QString()
255  : QString("color: purple;"));
256  m_ui->zOriginLabel->setText(QString("z = %1").arg(P.z, 0, 'f'));
257  m_ui->zOriginLabel->setStyleSheet(AlmostEq(P.z, m_originalPoint.z)
258  ? QString()
259  : QString("color: purple;"));
260 
261  m_ui->diagOriginLabel->setText(QString("diagonal = %1").arg(diag, 0, 'f'));
262  m_ui->diagOriginLabel->setStyleSheet(AlmostEq(diag, m_originalDiagonal)
263  ? QString()
264  : QString("color: purple;"));
265 }
266 
268  CCVector3d localPoint = m_localPoint;
269  double localDiagonal = m_localDiagonal;
270  if (!m_reversedMode || keepGlobalPos()) {
271  localPoint = (m_originalPoint + getShift()) * getScale();
272  localDiagonal = m_originalDiagonal * getScale();
273  }
274 
275  // adaptive precision
276  double maxCoord = std::max(fabs(localPoint.x), fabs(localPoint.y));
277  maxCoord = std::max(fabs(localPoint.z), maxCoord);
278  int digitsBeforeDec = static_cast<int>(floor(log10(maxCoord))) + 1;
279  int prec = std::max(0, 8 - digitsBeforeDec);
280 
281  m_ui->xDestLabel->setText(
282  QString("x = %1").arg(localPoint.x, 0, 'f', prec));
283  m_ui->xDestLabel->setStyleSheet(
285  ? QString("color: red;")
286  : QString());
287  m_ui->yDestLabel->setText(
288  QString("y = %1").arg(localPoint.y, 0, 'f', prec));
289  m_ui->yDestLabel->setStyleSheet(
291  ? QString("color: red;")
292  : QString());
293  m_ui->zDestLabel->setText(
294  QString("z = %1").arg(localPoint.z, 0, 'f', prec));
295  m_ui->zDestLabel->setStyleSheet(
297  ? QString("color: red;")
298  : QString());
299 
300  m_ui->diagDestLabel->setText(
301  QString("diagonal = %1").arg(localDiagonal, 0, 'f', prec));
302  m_ui->diagDestLabel->setStyleSheet(
304  ? QString("color: red;")
305  : QString());
306 }
307 
309  m_ui->shiftX->setValue(shift.x);
310  m_ui->shiftY->setValue(shift.y);
311  m_ui->shiftZ->setValue(shift.z);
312 }
313 
315  return CCVector3d(m_ui->shiftX->value(), m_ui->shiftY->value(),
316  m_ui->shiftZ->value());
317 }
318 
320  m_ui->scaleSpinBox->setValue(scale);
321 }
322 
324  return m_ui->scaleSpinBox->value();
325 }
326 
328  m_ui->diagOriginLabel->setVisible(state);
329  m_ui->diagDestLabel->setVisible(state);
330  // m_ui->scaleFrame->setVisible(state);
331 }
332 
334  m_ui->buttonBox->button(QDialogButtonBox::YesToAll)->setVisible(state);
335 }
336 
338  m_ui->buttonBox->button(QDialogButtonBox::Yes)->setVisible(state);
339 }
340 
342  m_ui->buttonBox->button(QDialogButtonBox::No)->setVisible(state);
343 }
344 
346  m_ui->buttonBox->button(QDialogButtonBox::Cancel)->setVisible(state);
347 }
348 
350  m_ui->warningLabel->setVisible(state);
351 }
352 
354  m_ui->titleFrame->setVisible(state);
355 }
356 
358  m_ui->keepGlobalPosCheckBox->setVisible(state);
359 }
360 
362  m_ui->preserveShiftOnSaveCheckBox->setVisible(state);
363 }
364 
366  return m_ui->preserveShiftOnSaveCheckBox->isChecked();
367 }
368 
370  m_ui->preserveShiftOnSaveCheckBox->setChecked(state);
371 }
372 
374  return m_ui->keepGlobalPosCheckBox->isChecked();
375 }
376 
378  m_ui->keepGlobalPosCheckBox->setChecked(state);
379 }
380 
382  // set the thickest border to the point that will be modified
383  m_ui->smallCubeFrame->setLineWidth(state ? 2 : 1);
384  m_ui->bigCubeFrame->setLineWidth(state ? 1 : 2);
385 
388 }
389 
390 void ecvShiftAndScaleCloudDlg::onClick(QAbstractButton* button) {
391  m_applyAll =
392  (button == m_ui->buttonBox->button(QDialogButtonBox::YesToAll));
393  m_cancel = (button == m_ui->buttonBox->button(QDialogButtonBox::Cancel));
394 }
395 
397  if (index < 0 || index >= static_cast<int>(m_defaultInfos.size())) return;
398 
399  setShift(m_defaultInfos[index].shift);
400  if (m_ui->scaleSpinBox->isVisible()) setScale(m_defaultInfos[index].scale);
401 }
402 
404  size_t index, ecvGlobalShiftManager::ShiftInfo& info) const {
405  if (index >= m_defaultInfos.size()) return false;
406 
407  info = m_defaultInfos[index];
408 
409  return true;
410 }
411 
413  if (index >= 0 && index < static_cast<int>(m_defaultInfos.size())) {
414  m_ui->loadComboBox->setCurrentIndex(index);
415  }
416 }
417 
419  const ecvGlobalShiftManager::ShiftInfo& info) {
420  try {
421  m_defaultInfos.push_back(info);
422  } catch (const std::bad_alloc&) {
423  // not enough memory
424  return -1;
425  }
426 
427  m_ui->loadComboBox->addItem(m_defaultInfos.back().name);
428  m_ui->loadComboBox->setEnabled(m_defaultInfos.size() >= 2);
429 
430  return static_cast<int>(m_defaultInfos.size()) - 1;
431 }
432 
434  const std::vector<ecvGlobalShiftManager::ShiftInfo>& infos) {
435  for (const ecvGlobalShiftManager::ShiftInfo& info : infos) {
436  if (addShiftInfo(info) < 0) break;
437  }
438 
439  return static_cast<int>(m_defaultInfos.size()) - 1;
440 }
Vector3Tpl< double > CCVector3d
Double 3D Vector.
Definition: CVGeom.h:804
std::string filename
std::string name
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
static bool NeedShift(const CCVector3d &P)
Returns whether a particular point (coordinates) is too big or not.
static bool NeedRescale(double d)
Returns whether a particular dimension (e.g. diagonal) is too big or not.
bool preserveShiftOnSave() const
Returns whether the global shift should be preserved or not.
void showApplyButton(bool state)
Whether to show the 'Apply' button or not.
void init()
Initialization routine.
ecvShiftAndScaleCloudDlg(const CCVector3d &Pg, double Dg=0, QWidget *parent=0)
Default constructor.
void setPreserveShiftOnSave(bool state)
Sets whether the global shift should be preserved or not.
void showNoButton(bool state)
Whether to show the 'No' button or not.
void setScale(double scale)
Sets displayed scale.
bool loadInfoFromFile(QString filename)
Tries to load ShiftInfo data from a (text) file.
CCVector3d getShift() const
Returns shift.
void onGlobalPosCheckBoxToggled(bool)
Slot called when the 'Keep global position' checkbox is toggled.
void setShift(const CCVector3d &shift)
Sets displayed shift.
void setKeepGlobalPos(bool state)
Sets whether the global position should be preserved or not.
void setCurrentProfile(int index)
Sets the current combo-box entry (profile)
virtual ~ecvShiftAndScaleCloudDlg()
Destructor.
void showWarning(bool state)
Whether to show or not the warning about non pertinent shift information.
int addShiftInfo(const ecvGlobalShiftManager::ShiftInfo &info)
Adds shift info to the combox.
bool m_applyAll
Whether shift should be applied to all files.
CCVector3d m_localPoint
Local coordinate system point (reversed mode only)
void showApplyAllButton(bool state)
Whether to show the 'Apply all' button or not.
bool m_cancel
Whether the user has clicked on Cancel or not.
void showKeepGlobalPosCheckbox(bool state)
Whether to show or not the 'Keep global position' checkbox.
void showScaleItems(bool state)
Whether to show dialog items related to scale.
std::vector< ecvGlobalShiftManager::ShiftInfo > m_defaultInfos
Default infos (typically loaded from the global_shift_list.txt' file)
void onLoadIndexChanged(int)
Slot called when the 'loadComboBox' index changes.
void updateGlobalAndLocalSystems()
Updates info on the global and local coordinate systems.
double m_originalDiagonal
Original coordinate system diagonal.
void showCancelButton(bool state)
Whether to show the 'Cancel' button or not.
void showTitle(bool state)
Whether to show or not the title.
bool addFileInfo()
Adds information from default file (if any)
void displayMoreInfo()
Displays more info about global shift mechanism.
void setShiftFieldsPrecision(int precision)
Sets the Shift fields (X, Y and Z) precision (default should be 2)
bool keepGlobalPos() const
Returns whether the global position should be preserved or not.
double m_localDiagonal
Local coordinate system diagonal (reversed mode only)
void onClick(QAbstractButton *button)
Analyzes the clicked button.
bool m_reversedMode
Whether the reverse mode is active or not.
void showPreserveShiftOnSave(bool state)
Whether to show or not the 'Preserve shift on save' checkbox.
double getScale() const
Returns scale.
bool getInfo(size_t index, ecvGlobalShiftManager::ShiftInfo &info) const
Returns a given input info.
Ui_GlobalShiftAndScaleDlg * m_ui
Associated UI.
void updateLocalSystem()
Updates info on the local coordinate system.
CCVector3d m_originalPoint
Original coordinate system point.
void updateGlobalSystem()
Updates info on the global coordinate system.
static QString s_defaultGlobalShiftListFilename("global_shift_list.txt")
bool AlmostEq(double a, double b)
a[190]
constexpr Qt::SplitBehavior SkipEmptyParts
Definition: QtCompat.h:302
MiniVec< float, N > floor(const MiniVec< float, N > &a)
Definition: MiniVec.h:75