ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
LasExtraScalarFieldCard.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 #include <ecvPointCloud.h>
11 #include <ecvScalarField.h>
12 
14  : QWidget(parent)
15 {
16  setupUi(this);
17 
18  nameEdit->setMaxLength(LasExtraScalarField::MAX_NAME_SIZE);
19  descriptionEdit->setMaxLength(LasExtraScalarField::MAX_DESCRIPTION_SIZE);
20 
21  m_scalarFieldsUserInputs[0] = {firstScalarFieldComboBox, firstScalarFieldScaleSpinBox, firstScalarFieldOffsetSpinBox};
22  m_scalarFieldsUserInputs[1] = {secondScalarFieldComboBox, secondScalarFieldScaleSpinBox, secondScalarFieldOffsetSpinBox};
23  m_scalarFieldsUserInputs[2] = {thirdScalarFieldComboBox, thirdScalarFieldScaleSpinBox, thirdScalarFieldOffsetSpinBox};
24 
25  connect(radioButton1,
26  &QRadioButton::clicked,
27  this,
28  &LasExtraScalarFieldCard::onRadioButton1Selected);
29 
30  connect(radioButton2,
31  &QRadioButton::clicked,
32  this,
33  &LasExtraScalarFieldCard::onRadioButton2Selected);
34 
35  connect(radioButton3,
36  &QRadioButton::clicked,
37  this,
38  &LasExtraScalarFieldCard::onRadioButton3Selected);
39 
40  connect(firstScalarFieldComboBox,
41  &QComboBox::currentTextChanged,
42  this,
43  [this](const QString& text)
44  {
45  if (radioButton1->isChecked())
46  {
47  nameEdit->setText(text);
48  }
49  });
50 
51  advancedOptionFrame->hide();
52  scaledCheckBox->setChecked(false);
53  scalingOptionGroup->setEnabled(false);
54 
55  connect(advancedOptionsButton, &QPushButton::clicked, this, &LasExtraScalarFieldCard::onToggleAdvancedOptionsClicked);
56  connect(scaledCheckBox, &QCheckBox::stateChanged, scalingOptionGroup, &QGroupBox::setEnabled);
57 
58  reset();
59 }
60 
62 {
63  radioButton1->setChecked(true);
64  emit radioButton1->clicked(true);
65 
66  nameEdit->clear();
67  if (advancedOptionsButton->isChecked())
68  {
69  advancedOptionsButton->setChecked(false);
70  emit advancedOptionsButton->clicked();
71  }
72 
73 #ifdef CC_CORE_LIB_USES_DOUBLE
74  const char* defaultType = "float64";
75 #else
76  const char* defaultType = "float32";
77 #endif
78  typeComboBox->setCurrentText(defaultType);
79 
80  firstScalarFieldComboBox->setCurrentIndex(0);
81  secondScalarFieldComboBox->setCurrentIndex(0);
82  thirdScalarFieldComboBox->setCurrentIndex(0);
83 }
84 
86 {
87  assert(field.ccName[0] == 0); // TODO
88 
89  nameEdit->setText(field.name);
90  switch (field.numElements())
91  {
92  case 1:
93  radioButton1->setChecked(true);
94  emit radioButton1->clicked(true);
95  assert(field.scalarFields[0] != nullptr);
96  firstScalarFieldComboBox->setCurrentText(field.scalarFields[0]->getName());
97  break;
98  case 2:
99  radioButton2->setChecked(true);
100  emit radioButton2->clicked(true);
101  assert(field.scalarFields[0] != nullptr);
102  firstScalarFieldComboBox->setCurrentText(field.scalarFields[0]->getName());
103  assert(field.scalarFields[1] != nullptr);
104  secondScalarFieldComboBox->setCurrentText(field.scalarFields[1]->getName());
105  break;
106  case 3:
107  radioButton3->setChecked(true);
108  emit radioButton3->clicked(true);
109  firstScalarFieldComboBox->setCurrentText(field.scalarFields[0]->getName());
110  assert(field.scalarFields[1] != nullptr);
111  secondScalarFieldComboBox->setCurrentText(field.scalarFields[1]->getName());
112  assert(field.scalarFields[1] != nullptr);
113  secondScalarFieldComboBox->setCurrentText(field.scalarFields[1]->getName());
114  assert(field.scalarFields[2] != nullptr);
115  thirdScalarFieldComboBox->setCurrentText(field.scalarFields[2]->getName());
116  break;
117  default:
118  assert(false);
119  return;
120  }
121 
122  descriptionEdit->setText(field.description);
123  scaledCheckBox->setChecked(false);
124  emit scaledCheckBox->stateChanged(false);
125 
126  if (field.scaleIsRelevant())
127  {
128  scaledCheckBox->setChecked(true);
129  emit scaledCheckBox->stateChanged(true);
130  assert(field.numElements() <= 3);
131  for (size_t i = 0; i < field.numElements(); ++i)
132  {
133  m_scalarFieldsUserInputs[i].scaleSpinBox->setValue(field.scales[i]);
134  }
135  }
136 
137  if (field.offsetIsRelevant())
138  {
139  emit scaledCheckBox->stateChanged(true);
140  assert(field.numElements() <= 3);
141  for (size_t i = 0; i < field.numElements(); ++i)
142  {
143  m_scalarFieldsUserInputs[i].offsetSpinBox->setValue(field.offsets[i]);
144  }
145  }
146 
147  switch (field.type)
148  {
150  typeComboBox->setCurrentText("uint8");
151  break;
153  typeComboBox->setCurrentText("uint16");
154  break;
156  typeComboBox->setCurrentText("uint32");
157  break;
159  typeComboBox->setCurrentText("uint64");
160  break;
162  typeComboBox->setCurrentText("int8");
163  break;
165  typeComboBox->setCurrentText("int16");
166  break;
167  case LasExtraScalarField::DataType::i32:
168  typeComboBox->setCurrentText("int32");
169  break;
171  typeComboBox->setCurrentText("int64");
172  break;
173  case LasExtraScalarField::DataType::f32:
174  typeComboBox->setCurrentText("float32");
175  break;
176  case LasExtraScalarField::DataType::f64:
177  typeComboBox->setCurrentText("float64");
178  break;
179  default:
180  typeComboBox->setCurrentText("float32");
181  break;
182  }
183 }
184 
186 {
187  if (nameEdit->text().isEmpty())
188  {
189  return false;
190  }
191 
192  const std::string stdName = nameEdit->text().toStdString();
193  strncpy(field.name, stdName.c_str(), LasExtraScalarField::MAX_NAME_SIZE);
194 
195  const std::string stdDescription = descriptionEdit->text().toStdString();
196  strncpy(field.description, stdDescription.c_str(), LasExtraScalarField::MAX_DESCRIPTION_SIZE);
197 
198  // since the corresponding line edits max length are properly set
199  // this should only happen in (rare) cases when converting from
200  // QString utf16 to bytes yields more bytes than chars if the users
201  // used too many non ascii symbols
202  if (stdName.size() > LasExtraScalarField::MAX_NAME_SIZE)
203  {
204  CVLog::Warning("[LAS] Extra Scalar field name '%s' is too long and will be truncated",
205  stdName.c_str());
206  }
207  if (stdDescription.size() > LasExtraScalarField::MAX_DESCRIPTION_SIZE)
208  {
209  CVLog::Warning("[LAS] Extra scalar field description '%s' is too long and will be truncated",
210  stdDescription.c_str());
211  }
212 
213  field.type = dataType();
214  if (radioButton1->isChecked())
215  {
217  }
218  else if (radioButton2->isChecked())
219  {
221  }
222  else if (radioButton3->isChecked())
223  {
225  }
226 
227  if (scaledCheckBox->isChecked())
228  {
229  field.setScaleIsRelevant(true);
230  field.setOffsetIsRelevant(true);
231 
232  for (size_t i = 0; i < field.numElements(); i++)
233  {
234  field.scales[i] = m_scalarFieldsUserInputs[i].scaleSpinBox->value();
235  field.offsets[i] = m_scalarFieldsUserInputs[i].offsetSpinBox->value();
236  }
237  }
238  else
239  {
240  field.setScaleIsRelevant(false);
241  field.setOffsetIsRelevant(false);
242  }
243 
244  for (size_t i = 0; i < field.numElements(); i++)
245  {
246  const std::string sfName =
247  m_scalarFieldsUserInputs[i].scalarFieldComboBox->currentText().toStdString();
248  int sfIndex = pointCloud.getScalarFieldIndexByName(sfName.c_str());
249 
250  if (sfIndex < 0)
251  {
252  CVLog::Warning("Failed to get scalar field named '%s'", sfName.c_str());
253  return false;
254  }
255  field.scalarFields[i] = static_cast<ccScalarField*>(pointCloud.getScalarField(sfIndex));
256  }
257 
258  return true;
259 }
260 
262 {
263  const QString selectedElementType = typeComboBox->currentText();
264 
265  if (selectedElementType == "uint8")
266  {
268  }
269 
270  if (selectedElementType == "uint16")
271  {
273  }
274 
275  if (selectedElementType == "uint32")
276  {
278  }
279 
280  if (selectedElementType == "uint64")
281  {
283  }
284 
285  if (selectedElementType == "int8")
286  {
288  }
289 
290  if (selectedElementType == "int16")
291  {
293  }
294 
295  if (selectedElementType == "int32")
296  {
297  return LasExtraScalarField::DataType::i32;
298  }
299 
300  if (selectedElementType == "int64")
301  {
303  }
304 
305  if (selectedElementType == "float32")
306  {
307  return LasExtraScalarField::DataType::f32;
308  }
309 
310  if (selectedElementType == "float64")
311  {
312  return LasExtraScalarField::DataType::f64;
313  }
314 
315  assert(false);
316  return LasExtraScalarField::DataType::Invalid;
317 }
318 
319 void LasExtraScalarFieldCard::onNumberOfElementsSelected(unsigned numberOfElements)
320 {
321  if (numberOfElements == 0 || numberOfElements > 3)
322  {
323  Q_ASSERT_X(false, "onNumberOfElementsSelected", "Invalid number of elements");
324  return;
325  }
326 
327  for (size_t i = 0; i < LasExtraScalarField::MAX_DIM_SIZE; i++)
328  {
329  ScalarFieldUserInputs& userInput = m_scalarFieldsUserInputs[i];
330 
331  const bool isPartOfSelected = i <= (numberOfElements - 1);
332 
333  userInput.scalarFieldComboBox->setVisible(isPartOfSelected);
334  userInput.scaleSpinBox->setEnabled(isPartOfSelected);
335  userInput.offsetSpinBox->setEnabled(isPartOfSelected);
336  }
337 }
338 
339 void LasExtraScalarFieldCard::onRadioButton1Selected(bool)
340 {
341  onNumberOfElementsSelected(1);
342 }
343 
344 void LasExtraScalarFieldCard::onRadioButton2Selected(bool)
345 {
346  onNumberOfElementsSelected(2);
347 }
348 
349 void LasExtraScalarFieldCard::onRadioButton3Selected(bool)
350 {
351  onNumberOfElementsSelected(3);
352 }
353 
354 void LasExtraScalarFieldCard::onToggleAdvancedOptionsClicked()
355 {
356  if (advancedOptionFrame->isHidden())
357  {
358  advancedOptionFrame->show();
359  }
360  else
361  {
362  advancedOptionFrame->hide();
363  }
364 }
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
void fillFrom(const LasExtraScalarField &field)
LasExtraScalarField::DataType dataType() const
bool fillField(LasExtraScalarField &field, const ccPointCloud &pointCloud) const
LasExtraScalarFieldCard(QWidget *parent=nullptr)
This serves the same purpose as LasScalarField but for extra bytes.
static constexpr unsigned MAX_NAME_SIZE
char name[MAX_NAME_SIZE]
char ccName[MAX_NAME_SIZE+8]
static constexpr unsigned MAX_DIM_SIZE
static constexpr unsigned MAX_DESCRIPTION_SIZE
char description[MAX_DESCRIPTION_SIZE]
double scales[MAX_DIM_SIZE]
DataType
Data types available LAS Extra Field.
unsigned numElements() const
void setScaleIsRelevant(bool isRelevant)
void setOffsetIsRelevant(bool isRelevant)
double offsets[MAX_DIM_SIZE]
ccScalarField * scalarFields[MAX_DIM_SIZE]
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
A scalar field associated to display-related parameters.
int getScalarFieldIndexByName(const char *name) const
Returns the index of a scalar field represented by its name.
ScalarField * getScalarField(int index) const
Returns a pointer to a specific scalar field.
const char * getName() const
Returns scalar field name.
Definition: ScalarField.h:43
sqlite3_uint64 u64
Definition: shell.c:91
sqlite3_int64 i64
Definition: shell.c:90
unsigned char u8
Definition: shell.c:92
unsigned int u32
Definition: sqlite3.c:14316
short int i16
Definition: sqlite3.c:14318
signed char i8
Definition: sqlite3.c:14320
unsigned short int u16
Definition: sqlite3.c:14317