ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
LasOpenDialog.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 "LasOpenDialog.h"
9 
10 // Qt
11 #include <QFileDialog>
12 #include <QLocale>
13 
14 constexpr int TILLING_TAB_INDEX = 1;
15 
16 static QListWidgetItem* CreateItem(const char* name)
17 {
18  auto item = new QListWidgetItem(name);
19  item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
20  item->setCheckState(Qt::Checked);
21  return item;
22 }
23 
24 static bool IsCheckedIn(const QString& name, const QListWidget* list)
25 {
26  if (!list)
27  {
28  assert(false);
29  return false;
30  }
31 
32  for (int i = 0; i < list->count(); ++i)
33  {
34  if (list->item(i)->text() == name)
35  {
36  return list->item(i)->checkState() == Qt::Checked;
37  }
38  }
39  return false;
40 }
41 
42 // TODO use std::remove_if
43 template <typename T, typename Pred>
44 static void RemoveFalse(std::vector<T>& vec, Pred predicate)
45 {
46  auto firstFalse = std::partition(vec.begin(), vec.end(), predicate);
47 
48  if (firstFalse != vec.end())
49  {
50  vec.erase(firstFalse, vec.end());
51  }
52 }
53 
55  : QDialog(parent)
56 {
57  setupUi(this);
58 
59  connect(applyButton, &QPushButton::clicked, this, &QDialog::accept);
60  connect(applyAllButton, &QPushButton::clicked, this, &QDialog::accept);
61  connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject);
62  connect(automaticTimeShiftCheckBox, &QCheckBox::toggled, this, &LasOpenDialog::onAutomaticTimeShiftToggle);
63  connect(applyAllButton, &QPushButton::clicked, this, &LasOpenDialog::onApplyAll);
64  connect(selectAllToolButton, &QPushButton::clicked, [&]
65  { doSelectAll(true); });
66  connect(unselectAllToolButton, &QPushButton::clicked, this, [&]
67  { doSelectAll(false); });
68  connect(tilingBrowseToolButton, &QPushButton::clicked, this, &LasOpenDialog::onBrowseTilingOutputDir);
69  connect(actionTab, &QTabWidget::currentChanged, this, &LasOpenDialog::onCurrentTabChanged);
70  connect(selectAllESFToolButton, &QPushButton::clicked, [&]
71  { doSelectAllESF(true); });
72  connect(unselectAllESFToolButton, &QPushButton::clicked, this, [&]
73  { doSelectAllESF(false); });
74 }
75 
76 void LasOpenDialog::doSelectAll(bool doSelect)
77 {
78  if (!availableScalarFields)
79  {
80  assert(false);
81  return;
82  }
83 
84  for (int i = 0; i < availableScalarFields->count(); ++i)
85  {
86  availableScalarFields->item(i)->setCheckState(doSelect ? Qt::Checked : Qt::Unchecked);
87  }
88 }
89 
90 void LasOpenDialog::doSelectAllESF(bool doSelect)
91 {
92  if (!availableExtraScalarFields)
93  {
94  assert(false);
95  return;
96  }
97 
98  for (int i = 0; i < availableExtraScalarFields->count(); ++i)
99  {
100  availableExtraScalarFields->item(i)->setCheckState(doSelect ? Qt::Checked : Qt::Unchecked);
101  }
102 }
103 
104 void LasOpenDialog::setInfo(int versionMinor, int pointFormatId, qulonglong numPoints)
105 {
106  versionLabelValue->setText(QString("1.%1").arg(QString::number(versionMinor)));
107  pointFormatLabelValue->setText(QString::number(pointFormatId));
108  numPointsLabelValue->setText(QLocale(QLocale::English).toString(numPoints));
109 
110  force8bitColorsCheckBox->setEnabled(LasDetails::HasRGB(pointFormatId));
111  timeShiftLayout->setEnabled(LasDetails::HasGpsTime(pointFormatId));
112 }
113 
114 void LasOpenDialog::setAvailableScalarFields(const std::vector<LasScalarField>& scalarFields,
115  const std::vector<LasExtraScalarField>& extraScalarFields)
116 {
117  availableScalarFields->clear();
118  availableExtraScalarFields->clear();
119 
120  if (!scalarFields.empty())
121  {
122  scalarFieldFrame->show();
123  for (const LasScalarField& lasScalarField : scalarFields)
124  {
125  availableScalarFields->addItem(CreateItem(lasScalarField.name()));
126  }
127  }
128  else
129  {
130  scalarFieldFrame->hide();
131  }
132 
133  if (!extraScalarFields.empty())
134  {
135  extraScalarFieldsFrame->show();
136  for (const LasExtraScalarField& lasExtraScalarField : extraScalarFields)
137  {
138  availableExtraScalarFields->addItem(CreateItem(lasExtraScalarField.name));
139  }
140  int height = availableExtraScalarFields->frameWidth() + (availableExtraScalarFields->sizeHintForRow(0) + availableExtraScalarFields->frameWidth()) * availableExtraScalarFields->count();
141  availableExtraScalarFields->setMaximumHeight(height);
142  }
143  else
144  {
145  extraScalarFieldsFrame->hide();
146  }
147 }
148 
149 void LasOpenDialog::filterOutNotChecked(std::vector<LasScalarField>& scalarFields,
150  std::vector<LasExtraScalarField>& extraScalarFields)
151 {
152  const auto isFieldSelected = [this](const auto& field)
153  { return isChecked(field); };
154 
155  RemoveFalse(scalarFields, isFieldSelected);
156  RemoveFalse(extraScalarFields, isFieldSelected);
157 }
158 
160 {
161  return ignoreFieldsWithDefaultValuesCheckBox->isChecked();
162 }
163 
165 {
166  return force8bitColorsCheckBox->isChecked();
167 }
168 
170 {
171  if (automaticTimeShiftCheckBox->isChecked())
172  {
173  return std::numeric_limits<double>::quiet_NaN();
174  }
175 
176  return manualTimeShiftSpinBox->value();
177 }
178 
179 bool LasOpenDialog::isChecked(const LasExtraScalarField& lasExtraScalarField) const
180 {
181  return IsCheckedIn(lasExtraScalarField.name, availableExtraScalarFields);
182 }
183 
184 bool LasOpenDialog::isChecked(const LasScalarField& lasScalarField) const
185 {
186  return IsCheckedIn(lasScalarField.name(), availableScalarFields);
187 }
188 
189 void LasOpenDialog::onAutomaticTimeShiftToggle(bool checked)
190 {
191  manualTimeShiftSpinBox->setEnabled(!checked);
192 }
193 
195 {
196  return m_shouldSkipDialog;
197 }
198 
200 {
201  m_shouldSkipDialog = false;
202 }
203 
204 void LasOpenDialog::onApplyAll()
205 {
206  m_shouldSkipDialog = true;
207  accept();
208 }
209 
211 {
212  if (actionTab->currentIndex() == TILLING_TAB_INDEX)
213  {
214  return Action::Tile;
215  }
216  else
217  {
218  return Action::Load;
219  }
220 }
221 
223 {
224  int index = tilingDimensioncomboBox->currentIndex();
225  if (index > 2)
226  {
227  index = 0;
228  }
229 
230  const auto dimensions = static_cast<LasTilingDimensions>(index);
231 
232  // Do these maxs for safety, but the UI should not allow
233  // users to enter values below 1
234  int numTiles0 = std::max(tilingSpinBox0->value(), 1);
235  int numTiles1 = std::max(tilingSpinBox0->value(), 1);
236 
237  return LasTilingOptions{
238  tilingOutputPathLineEdit->text(),
239  dimensions,
240  static_cast<unsigned>(numTiles0),
241  static_cast<unsigned>(numTiles1),
242  };
243 }
244 
245 void LasOpenDialog::onBrowseTilingOutputDir()
246 {
247  const QString outputDir = QFileDialog::getExistingDirectory(this, "Select output directory for tiles");
248  tilingOutputPathLineEdit->setText(outputDir);
249 }
250 
251 void LasOpenDialog::onCurrentTabChanged(int index)
252 {
253  const static QString TILE_TEXT = QStringLiteral("Tile");
254  const static QString TILE_ALL_TEXT = QStringLiteral("Tile All");
255 
256  const static QString APPLY_TEXT = QStringLiteral("Apply");
257  const static QString APPLY_ALL_TEXT = QStringLiteral("Apply All");
258 
259  if (index == TILLING_TAB_INDEX)
260  {
261  applyButton->setText(TILE_TEXT);
262  applyAllButton->setText(TILE_ALL_TEXT);
263  }
264  else
265  {
266  applyButton->setText(APPLY_TEXT);
267  applyAllButton->setText(APPLY_ALL_TEXT);
268  }
269 }
std::string name
int height
static QListWidgetItem * CreateItem(const char *name)
static bool IsCheckedIn(const QString &name, const QListWidget *list)
constexpr int TILLING_TAB_INDEX
static void RemoveFalse(std::vector< T > &vec, Pred predicate)
LasTilingDimensions
Definition: LasTiler.h:32
This serves the same purpose as LasScalarField but for extra bytes.
char name[MAX_NAME_SIZE]
LasTilingOptions tilingOptions() const
bool shouldSkipDialog() const
void setAvailableScalarFields(const std::vector< LasScalarField > &scalarFields, const std::vector< LasExtraScalarField > &extraScalarFields)
double timeShiftValue() const
Action action() const
@ Tile
The user wants to tile the file into multiple smaller ones.
@ Load
The user wants to load the file in ACloudViewer.
bool shouldForce8bitColors() const
void setInfo(int versionMinor, int pointFormatId, qulonglong numPoints)
void filterOutNotChecked(std::vector< LasScalarField > &scalarFields, std::vector< LasExtraScalarField > &extraScalarFields)
bool shouldIgnoreFieldsWithDefaultValues() const
LasOpenDialog(QWidget *parent=nullptr)
Default constructor.
void resetShouldSkipDialog()
int max(int a, int b)
Definition: cutil_math.h:48
bool HasRGB(unsigned pointFormatId)
Returns whether the point format supports RGB.
Definition: LasDetails.h:132
bool HasGpsTime(unsigned pointFormatId)
Returns whether the point format supports Gps Time.
Definition: LasDetails.h:125
std::string toString(T x)
Definition: Common.h:80
const char * name() const