ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
PlyOpenDlg.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 "PlyOpenDlg.h"
9 
10 // Qt
11 #include <QListWidgetItem>
12 #include <QMessageBox>
13 #include <QStringList>
14 
15 // CV_DB_LIB
16 #include <CVLog.h>
17 
18 // System
19 #include <assert.h>
20 #include <string.h>
21 
24  PlyLoadingContext() : ignoredProps(0), valid(false), applyAll(false) {}
25 
26  QStringList allProperties;
27  std::vector<QString> standardCombosProperties;
28  std::vector<QString> sfCombosProperties;
29  std::vector<QString> listCombosProperties;
30  std::vector<QString> singleCombosProperties;
32  bool valid;
33  bool applyAll;
34 };
37 
38 PlyOpenDlg::PlyOpenDlg(QWidget* parent) : QDialog(parent), Ui::PlyOpenDlg() {
39  setupUi(this);
40 
41  try {
42  m_standardCombos.push_back(xComboBox);
43  m_standardCombos.push_back(yComboBox);
44  m_standardCombos.push_back(zComboBox);
45  m_standardCombos.push_back(rComboBox);
46  m_standardCombos.push_back(gComboBox);
47  m_standardCombos.push_back(bComboBox);
48  m_standardCombos.push_back(iComboBox);
49  m_standardCombos.push_back(nxComboBox);
50  m_standardCombos.push_back(nyComboBox);
51  m_standardCombos.push_back(nzComboBox);
52 
53  m_listCombos.push_back(facesComboBox);
54  m_listCombos.push_back(textCoordsComboBox);
55 
56  m_singleCombos.push_back(texIndexComboBox);
57  } catch (const std::bad_alloc&) {
58  // not enough memory?! What can we do...
59  }
60 
61  connect(addSFToolButton, &QAbstractButton::clicked, this,
63  connect(addAllSFToolButton, &QAbstractButton::clicked, this,
65  connect(applyButton, &QAbstractButton::clicked, this, &PlyOpenDlg::apply);
66  connect(applyAllButton, &QAbstractButton::clicked, this,
68  connect(cancelButton, &QAbstractButton::clicked, this, &QDialog::reject);
69  connect(this, &PlyOpenDlg::fullyAccepted, this, &QDialog::accept);
70 }
71 
72 void PlyOpenDlg::setDefaultComboItems(const QStringList& stdPropsText) {
73  m_stdPropsText = stdPropsText;
74  int stdPropsCount = stdPropsText.count();
75 
76  for (QComboBox* combo : m_standardCombos) {
77  assert(combo);
78  combo->addItems(m_stdPropsText);
79  combo->setMaxVisibleItems(stdPropsCount);
80  }
81 
82  for (QComboBox* combo : m_sfCombos) {
83  assert(combo);
84  combo->addItems(m_stdPropsText);
85  combo->setMaxVisibleItems(stdPropsCount);
86  }
87 }
88 
89 void PlyOpenDlg::setListComboItems(const QStringList& listPropsText) {
90  m_listPropsText = listPropsText;
91  int listPropsCount = listPropsText.count();
92 
93  for (QComboBox* combo : m_listCombos) {
94  assert(combo);
95  combo->addItems(m_listPropsText);
96  combo->setMaxVisibleItems(listPropsCount);
97  }
98 }
99 
100 void PlyOpenDlg::setSingleComboItems(const QStringList& singlePropsText) {
101  m_singlePropsText = singlePropsText;
102  int singlePropsCount = singlePropsText.count();
103 
104  for (QComboBox* combo : m_singleCombos) {
105  assert(combo);
106  combo->addItems(m_singlePropsText);
107  combo->setMaxVisibleItems(singlePropsCount);
108  }
109 }
110 
112 
113 bool PlyOpenDlg::restorePreviousContext(bool& hasAPreviousContext) {
114  hasAPreviousContext = s_lastContext.valid;
115  if (!hasAPreviousContext) return false;
116 
117  int unassignedProps = 0;
118  int mismatchProps = 0;
119  bool restored =
120  restoreContext(&s_lastContext, unassignedProps, mismatchProps);
121 
122  // auto-stop: we can't keep 'apply all' if something has changed
123  if (!restored || mismatchProps != 0 /* || unassignedProps > 0*/) {
124  s_lastContext.applyAll = false;
125  return false;
126  }
127 
128  return true;
129 }
130 
132  if (!context) {
133  assert(false);
134  return;
135  }
136  context->valid = false;
137 
138  // create the list of all properties
139  context->allProperties.clear();
140  assert(m_standardCombos.front());
141  if (m_standardCombos.front())
142  for (int i = 1; i < m_standardCombos.front()->count();
143  ++i) // the first item is always 'NONE'
144  context->allProperties.append(
145  m_standardCombos.front()->itemText(i));
146  assert(m_listCombos.front());
147  if (m_listCombos.front())
148  for (int i = 1; i < m_listCombos.front()->count();
149  ++i) // the first item is always 'NONE'
150  context->allProperties.append(m_listCombos.front()->itemText(i));
151  assert(m_singleCombos.front());
152  if (m_singleCombos.front())
153  for (int i = 1; i < m_singleCombos.front()->count();
154  ++i) // the first item is always 'NONE'
155  context->allProperties.append(m_singleCombos.front()->itemText(i));
156 
157  // now remember how each combo-box is mapped
158  int assignedProps = 0;
159  try {
160  // standard combos
161  {
162  context->standardCombosProperties.resize(m_standardCombos.size());
163  std::fill(context->standardCombosProperties.begin(),
164  context->standardCombosProperties.end(), QString());
165  for (size_t i = 0; i < m_standardCombos.size(); ++i) {
166  if (m_standardCombos[i] &&
167  m_standardCombos[i]->currentIndex() >
168  0) // currentIndex == 0 means 'NONE'!!!
169  {
170  context->standardCombosProperties[i] =
171  m_standardCombos[i]->currentText();
172  ++assignedProps;
173  }
174  }
175  }
176  // list combos
177  {
178  context->listCombosProperties.resize(m_listCombos.size());
179  std::fill(context->listCombosProperties.begin(),
180  context->listCombosProperties.end(), QString());
181  for (size_t i = 0; i < m_listCombos.size(); ++i) {
182  if (m_listCombos[i] && m_listCombos[i]->currentIndex() > 0) {
183  context->listCombosProperties[i] =
184  m_listCombos[i]->currentText();
185  ++assignedProps;
186  }
187  }
188  }
189  // single combos
190  {
191  context->singleCombosProperties.resize(m_singleCombos.size());
192  std::fill(context->singleCombosProperties.begin(),
193  context->singleCombosProperties.end(), QString());
194  for (size_t i = 0; i < m_singleCombos.size(); ++i) {
195  if (m_singleCombos[i] &&
196  m_singleCombos[i]->currentIndex() > 0) {
197  context->singleCombosProperties[i] =
198  m_singleCombos[i]->currentText();
199  ++assignedProps;
200  }
201  }
202  }
203  // additional SF combos
204  {
205  context->sfCombosProperties.clear();
206  for (size_t i = 0; i < m_sfCombos.size(); ++i) {
207  // we only copy the valid ones!
208  if (m_sfCombos[i] && m_sfCombos[i]->currentIndex() > 0) {
209  context->sfCombosProperties.push_back(
210  m_sfCombos[i]->currentText());
211  ++assignedProps;
212  }
213  }
214  }
215  } catch (const std::bad_alloc&) {
216  // not enough memory
217  return;
218  }
219 
220  context->ignoredProps = context->allProperties.size() - assignedProps;
221  context->valid = true;
222 }
223 
225  int& unassignedProps,
226  int& mismatchProps) {
227  if (!context || !context->valid) {
228  assert(false);
229  return false;
230  }
231 
232  // first check if all new properties are in the old properties set
233  mismatchProps = 0;
234  int totalProps = 0;
235  {
236  assert(m_standardCombos.front());
237  if (m_standardCombos.front())
238  for (int i = 1; i < m_standardCombos.front()->count();
239  ++i) // the first item is always 'NONE'
240  {
241  ++totalProps;
242  if (!context->allProperties.contains(
243  m_standardCombos.front()->itemText(i)))
244  ++mismatchProps;
245  }
246  assert(m_listCombos.front());
247  if (m_listCombos.front())
248  for (int i = 1; i < m_listCombos.front()->count();
249  ++i) // the first item is always 'NONE'
250  {
251  ++totalProps;
252  if (!context->allProperties.contains(
253  m_listCombos.front()->itemText(i)))
254  ++mismatchProps;
255  }
256  assert(m_singleCombos.front());
257  if (m_singleCombos.front())
258  for (int i = 1; i < m_singleCombos.front()->count();
259  ++i) // the first item is always 'NONE'
260  {
261  ++totalProps;
262  if (!context->allProperties.contains(
263  m_singleCombos.front()->itemText(i)))
264  ++mismatchProps;
265  }
266  }
267 
268  int assignedEntries = 0;
269 
270  // standard combos
271  assert(m_standardCombos.size() == context->standardCombosProperties.size());
272  {
273  for (size_t i = 0; i < m_standardCombos.size(); ++i) {
274  if (m_standardCombos[i]) {
275  m_standardCombos[i]->setCurrentIndex(0);
276  // if a specific property was defined for this field
277  if (!context->standardCombosProperties[i].isNull()) {
278  // try to find it in the new property list!
279  int idx = m_standardCombos[i]->findText(
280  context->standardCombosProperties[i]);
281  if (idx >= 0) {
282  ++assignedEntries;
283  m_standardCombos[i]->setCurrentIndex(idx);
284  }
285  }
286  }
287  }
288  }
289 
290  // list combos
291  assert(m_listCombos.size() == context->listCombosProperties.size());
292  {
293  for (size_t i = 0; i < m_listCombos.size(); ++i) {
294  if (m_listCombos[i]) {
295  m_listCombos[i]->setCurrentIndex(0);
296  // if a specific property was defined for this field
297  if (!context->listCombosProperties[i].isNull()) {
298  // try to find it in the new property list!
299  int idx = m_listCombos[i]->findText(
300  context->listCombosProperties[i]);
301  if (idx >= 0) {
302  ++assignedEntries;
303  m_listCombos[i]->setCurrentIndex(idx);
304  }
305  }
306  }
307  }
308  }
309 
310  // single combox
311  assert(m_singleCombos.size() == context->singleCombosProperties.size());
312  {
313  for (size_t i = 0; i < m_singleCombos.size(); ++i) {
314  if (m_singleCombos[i]) {
315  m_singleCombos[i]->setCurrentIndex(0);
316  // if a specific property was defined for this field
317  if (!context->singleCombosProperties[i].isNull()) {
318  // try to find it in the new property list!
319  int idx = m_singleCombos[i]->findText(
320  context->singleCombosProperties[i]);
321  if (idx >= 0) {
322  ++assignedEntries;
323  m_singleCombos[i]->setCurrentIndex(idx);
324  }
325  }
326  }
327  }
328  }
329 
330  // additional SF combos
331  {
332  for (size_t i = 0; i < context->sfCombosProperties.size(); ++i) {
333  // try to find it in the new property list!
334  int idx =
335  m_stdPropsText.lastIndexOf(context->sfCombosProperties[i]);
336  if (idx >= 0) {
337  ++assignedEntries;
338  addSFComboBox(idx);
339  }
340  }
341  }
342 
343  assert(assignedEntries <= totalProps);
344  unassignedProps = totalProps - assignedEntries;
345 
346  return true;
347 }
348 
350  if (isValid()) {
352  s_lastContext.applyAll = false;
353  Q_EMIT fullyAccepted();
354  }
355 }
356 
358  if (isValid()) {
360  s_lastContext.applyAll = true;
361  Q_EMIT fullyAccepted();
362  }
363 }
364 
365 bool PlyOpenDlg::isValid(bool displayErrors /*=true*/) const {
366  // we need at least two coordinates per point (i.e. 2D)
367  int zeroCoord = 0;
368  if (xComboBox->currentIndex() == 0) ++zeroCoord;
369  if (yComboBox->currentIndex() == 0) ++zeroCoord;
370  if (zComboBox->currentIndex() == 0) ++zeroCoord;
371 
372  if (zeroCoord > 1) {
373  if (displayErrors)
374  QMessageBox::warning(
375  nullptr, "Error",
376  "At least two vertex coordinates (X,Y,Z) must be defined!");
377  return false;
378  }
379 
380  // we must ensure that no property is assigned to more than one field
381  int n = m_stdPropsText.size();
382  int p = m_listPropsText.size();
383  int q = m_singlePropsText.size();
384 
385  assert(n + p + q >= 2);
386  std::vector<int> assignedIndexCount(n + p + q, 0);
387 
388  for (size_t i = 0; i < m_standardCombos.size(); ++i)
389  ++assignedIndexCount[m_standardCombos[i]->currentIndex()];
390  for (size_t j = 0; j < m_listCombos.size(); ++j)
391  ++assignedIndexCount[m_listCombos[j]->currentIndex() > 0
392  ? n + m_listCombos[j]->currentIndex()
393  : 0];
394  for (size_t k = 0; k < m_singleCombos.size(); ++k)
395  ++assignedIndexCount[m_singleCombos[k]->currentIndex() > 0
396  ? n + p + m_singleCombos[k]->currentIndex()
397  : 0];
398  for (size_t l = 0; l < m_sfCombos.size(); ++l)
399  ++assignedIndexCount[m_sfCombos[l]->currentIndex()];
400 
401  for (int i = 1; i < n + p + q; ++i) {
402  if (assignedIndexCount[i] > 1) {
403  if (displayErrors)
404  QMessageBox::warning(nullptr, "Error",
405  QString("Can't assign same property to "
406  "multiple fields! (%1)")
407  .arg(xComboBox->itemText(i)));
408  return false;
409  }
410  }
411 
412  return true;
413 }
414 
416  return s_lastContext.valid && s_lastContext.applyAll && isValid(false);
417 }
418 
419 void PlyOpenDlg::addSFComboBox(int selectedIndex /*=0*/) {
420  // create a new item in the SF list
421  QString itemTitle = QString("Scalar #%1").arg(m_sfCombos.size());
422  QListWidgetItem* sfItem = new QListWidgetItem(itemTitle);
423 
424  // create a new combo-box
425  QComboBox* sfCombo = new QComboBox;
426  // fill it with default items
427  sfCombo->addItems(m_stdPropsText);
428  sfCombo->setMaxVisibleItems(m_stdPropsText.size());
429  sfCombo->setCurrentIndex(selectedIndex);
430 
431  scalarFields->addItem(sfItem);
432  scalarFields->setItemWidget(sfItem, sfCombo);
433 
434  m_sfCombos.push_back(sfCombo);
435 }
436 
438  std::vector<bool> notUsed;
439  notUsed.resize(m_stdPropsText.size(), true);
440 
441  // check standard comboboxes
442  for (QComboBox* combo : m_standardCombos) {
443  assert(combo);
444  int index = combo->currentIndex();
445  if (index >= 0) {
446  if (static_cast<size_t>(index) < notUsed.size()) {
447  notUsed[index] = false;
448  }
449  } else {
450  assert(false);
451  CVLog::Warning("Invalid combobox index!");
452  }
453  }
454 
455  // check already existing SF combos
456  for (QComboBox* combo : m_sfCombos) {
457  assert(combo);
458  int index = combo->currentIndex();
459  if (index >= 0) {
460  if (static_cast<size_t>(index) < notUsed.size()) {
461  notUsed[index] = false;
462  }
463  } else {
464  assert(false);
465  CVLog::Warning("Invalid combobox index!");
466  }
467  }
468 
469  size_t createdSFCount = 0;
470  for (size_t i = 0; i < notUsed.size(); ++i) {
471  if (notUsed[i]) {
472  addSFComboBox(static_cast<int>(i));
473  ++createdSFCount;
474  }
475  }
476 
477  if (createdSFCount == 0) {
478  QMessageBox::warning(this, "Add all SFs", "No unused property");
479  }
480 }
int count
static PlyLoadingContext s_lastContext
Last loading context.
Definition: PlyOpenDlg.cpp:36
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
Dialog for configuration of PLY files opening sequence.
Definition: PlyOpenDlg.h:24
void addAllStdPropsAsSF()
Definition: PlyOpenDlg.cpp:437
bool isValid(bool displayErrors=true) const
Returns whether the current configuration is valid or not.
Definition: PlyOpenDlg.cpp:365
void addSFComboBox(int selectedIndex=0)
Definition: PlyOpenDlg.cpp:419
QStringList m_stdPropsText
Standard comboboxes elements.
Definition: PlyOpenDlg.h:81
std::vector< QComboBox * > m_listCombos
List-related comboboxes (faces, etc.)
Definition: PlyOpenDlg.h:37
void setListComboItems(const QStringList &listPropsText)
Definition: PlyOpenDlg.cpp:89
PlyOpenDlg(QWidget *parent=nullptr)
Definition: PlyOpenDlg.cpp:38
static void ResetApplyAll()
Resets the "apply all" flag (if set)
Definition: PlyOpenDlg.cpp:111
void saveContext(PlyLoadingContext *context)
Saves current configuration (for internal use)
Definition: PlyOpenDlg.cpp:131
void setSingleComboItems(const QStringList &singlePropsText)
Definition: PlyOpenDlg.cpp:100
bool canBeSkipped() const
Returns whether the dialog can be 'skipped'.
Definition: PlyOpenDlg.cpp:415
void apply()
Definition: PlyOpenDlg.cpp:349
bool restorePreviousContext(bool &hasAPreviousContext)
Restores the previously saved configuration (if any)
Definition: PlyOpenDlg.cpp:113
void setDefaultComboItems(const QStringList &stdPropsText)
Definition: PlyOpenDlg.cpp:72
bool restoreContext(PlyLoadingContext *context, int &unassignedProps, int &mismatchProps)
Restore a previously saved configuration (for internal use)
Definition: PlyOpenDlg.cpp:224
QStringList m_singlePropsText
Single-related comboboxes elements.
Definition: PlyOpenDlg.h:85
void fullyAccepted()
void applyAll()
Definition: PlyOpenDlg.cpp:357
std::vector< QComboBox * > m_standardCombos
Standard comboboxes.
Definition: PlyOpenDlg.h:35
std::vector< QComboBox * > m_singleCombos
Single-related comboboxes (texture index, etc.)
Definition: PlyOpenDlg.h:39
std::vector< QComboBox * > m_sfCombos
SF comboboxes.
Definition: PlyOpenDlg.h:41
QStringList m_listPropsText
List-related comboboxes elements.
Definition: PlyOpenDlg.h:83
ImGuiContext * context
Definition: Window.cpp:76
Definition: sfEditDlg.h:16
Ply dialog loading context.
Definition: PlyOpenDlg.cpp:23
std::vector< QString > standardCombosProperties
Definition: PlyOpenDlg.cpp:27
std::vector< QString > listCombosProperties
Definition: PlyOpenDlg.cpp:29
std::vector< QString > singleCombosProperties
Definition: PlyOpenDlg.cpp:30
QStringList allProperties
Definition: PlyOpenDlg.cpp:26
std::vector< QString > sfCombosProperties
Definition: PlyOpenDlg.cpp:28