ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ccMPlaneDlg.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 "ccMPlaneDlg.h"
9 
10 // Qt
11 #include <qheaderview.h>
12 #include <qpushbutton.h>
13 #include <qscrollbar.h>
14 #include <qsizepolicy.h>
15 
16 // Sizing of Qt tables inspired by:
17 // https://stackoverflow.com/questions/8766633/how-to-determine-the-correct-size-of-a-qtablewidget
18 
19 ccMPlaneDlg::ccMPlaneDlg(QWidget *parent /*=0*/)
20  : ccOverlayDialog(parent), Ui::MPlaneDialog() {
21  setupUi(this);
22 
23  QPalette p;
24  p.setColor(backgroundRole(), QColor(240, 240, 240, 200));
25  setPalette(p);
26  setAutoFillBackground(true);
27 
28  // Create the TabWidget + Tabs
29  m_tabWidget = new QTabWidget();
30  layout()->addWidget(m_tabWidget);
31 
32  createPlaneFittingTab();
33  createMeasurementTab();
34 
35  m_tabWidget->addTab(m_tabPlaneFitting, "Point selection");
36  m_tabWidget->addTab(m_tabMeasurement, "Measurement");
37 
38  // Create the close button
39  QPushButton *buttonClose = new QPushButton("Close");
40  layout()->addWidget(buttonClose);
41 
42  // Qt Signal <-> Slot connections
43  connect(buttonClose, &QPushButton::clicked, this,
45  connect(m_tabWidget, &QTabWidget::currentChanged, this,
47 
48  m_tabWidget->setTabEnabled(1, false);
49  adjustSize();
50 }
51 
52 void ccMPlaneDlg::createPlaneFittingTab() {
53  // Create the tab
54  m_tabPlaneFitting = new QWidget();
55  m_tabPlaneFitting->setLayout(new QVBoxLayout());
56 
57  // Create the table
58  m_pointTableWidget = new QTableWidget();
59  m_tabPlaneFitting->layout()->addWidget(m_pointTableWidget);
61 
62  m_pointTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
63  m_pointTableWidget->setFocusPolicy(Qt::NoFocus);
64  m_pointTableWidget->setSelectionMode(QAbstractItemView::NoSelection);
65  m_pointTableWidget->setSizePolicy(QSizePolicy::Minimum,
67  m_pointTableWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
68  m_pointTableWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
69  m_pointTableWidget->horizontalHeader()->setStyleSheet(
70  "QHeaderView::section { background-color: #EDEDED; }");
71  m_pointTableWidget->verticalHeader()->setStyleSheet(
72  "QHeaderView::section { background-color: #EDEDED; }");
73 
74  m_pointTableWidget->resizeColumnsToContents();
75  m_pointTableMinWidth = static_cast<unsigned int>(
76  (m_pointTableWidget->horizontalHeader()->length() +
77  m_pointTableWidget->verticalHeader()->width() +
78  m_pointTableWidget->verticalScrollBar()->width()) *
79  1.5);
80  m_pointTableMinHeight = static_cast<unsigned int>(
81  m_pointTableWidget->verticalHeader()->length() +
82  m_pointTableWidget->horizontalHeader()->height() +
83  m_pointTableWidget->horizontalScrollBar()->height());
84  m_pointTableWidget->setFixedSize(m_pointTableMinWidth,
85  m_pointTableMinHeight);
86 
87  // Stretch the dialog by default
88  m_pointTableWidget->horizontalHeader()->setSectionResizeMode(
89  QHeaderView::Stretch);
90  m_pointTableWidget->verticalHeader()->setSectionResizeMode(
91  QHeaderView::Stretch);
92 }
93 
94 void ccMPlaneDlg::createMeasurementTab() {
95  // Create the tab
96  m_tabMeasurement = new QWidget();
97  m_tabMeasurement->setLayout(new QVBoxLayout());
98 
99  // Create the table
100  m_measurementTableWidget = new QTableWidget();
101  m_radioButtonSignedMeasurement = new QRadioButton("Signed measurement");
102  m_radioButtonUnsignedMeasurement = new QRadioButton("Unsigned measurement");
103  m_checkBoxShowNormal = new QCheckBox("Show normal vector");
104 
105  QWidget *savingWidget = new QWidget();
106  QHBoxLayout *hLayout = new QHBoxLayout();
107  hLayout->setSpacing(0);
108 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
109  hLayout->setMargin(0);
110 #endif
111  hLayout->setContentsMargins(0, 0, 0, 0);
112 
113  QPushButton *buttonSaving = new QPushButton("Save");
114  buttonSaving->setIcon(QIcon(":/CC/plugin/qMPlane/images/ccSave.png"));
115  buttonSaving->setContentsMargins(0, 0, 0, 0);
116 
117  savingWidget->setLayout(hLayout);
118  savingWidget->layout()->addWidget(buttonSaving);
119  hLayout->addStretch();
120 
121  m_tabMeasurement->layout()->addWidget(m_radioButtonSignedMeasurement);
122  m_tabMeasurement->layout()->addWidget(m_radioButtonUnsignedMeasurement);
123  m_tabMeasurement->layout()->addWidget(m_checkBoxShowNormal);
124  m_tabMeasurement->layout()->addWidget(m_measurementTableWidget);
125  m_tabMeasurement->layout()->addWidget(savingWidget);
126 
127  m_measurementTableWidget->setRowCount(3);
128  m_measurementTableWidget->setColumnCount(2);
129  QStringList header1;
130  header1 << "Measurement"
131  << "Distance";
132  m_measurementTableWidget->setHorizontalHeaderLabels(header1);
133  m_radioButtonUnsignedMeasurement->setChecked(true);
134 
135  m_measurementTableWidget->setSizePolicy(QSizePolicy::Minimum,
137  m_measurementTableWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
138  m_measurementTableWidget->setHorizontalScrollBarPolicy(
139  Qt::ScrollBarAlwaysOn);
140  m_measurementTableWidget->horizontalHeader()->setStyleSheet(
141  "QHeaderView::section { background-color: #EDEDED; }");
142 
143  m_measurementTableWidget->resizeColumnsToContents();
144  m_measurementTableWidget->setFixedSize(
145  m_pointTableMinWidth,
146  m_measurementTableWidget->verticalHeader()->length() +
147  m_measurementTableWidget->horizontalHeader()->height() +
148  m_measurementTableWidget->horizontalScrollBar()->height() *
149  1.5);
150 
151  // Stretch the dialog by default
152  m_measurementTableWidget->horizontalHeader()->setSectionResizeMode(
153  QHeaderView::Stretch);
154  m_measurementTableWidget->verticalHeader()->setSectionResizeMode(
155  QHeaderView::Stretch);
156  m_measurementTableWidget->verticalHeader()->hide();
157 
158  connect(m_measurementTableWidget, &QTableWidget::itemChanged, this,
160  connect(m_radioButtonSignedMeasurement, &QRadioButton::clicked, this,
162  connect(m_radioButtonUnsignedMeasurement, &QRadioButton::clicked, this,
164  connect(m_checkBoxShowNormal, &QCheckBox::clicked, this,
166  connect(buttonSaving, &QCheckBox::clicked, this,
168 }
169 
170 int ccMPlaneDlg::getFittingPointContentWidth() const {
171  m_pointTableWidget->sizeHint();
172  return m_pointTableWidget->columnWidth(0) +
173  m_pointTableWidget->columnWidth(1) +
174  m_pointTableWidget->columnWidth(2) +
175  m_pointTableWidget->columnWidth(3);
176 }
177 
178 int ccMPlaneDlg::getFittingPointTableWidth() const {
179  return m_pointTableWidget->width() -
180  m_pointTableWidget->verticalHeader()->width() -
181  m_pointTableWidget->verticalScrollBar()->width();
182 }
183 
184 QPushButton *ccMPlaneDlg::createDeleteButton() {
185  QPushButton *deleteButton = new QPushButton();
186  deleteButton->setIcon(QIcon(":/CC/plugin/qMPlane/images/icon_delete.png"));
187  deleteButton->setStyleSheet(
188  "QPushButton {border-style: outset; border-width: 0px;}");
189  connect(deleteButton, SIGNAL(clicked()), this,
190  SLOT(onDeleteButtonClicked()));
191  return deleteButton;
192 }
193 
194 void ccMPlaneDlg::addFittingPoint(int rowIndex, const CCVector3 &point) {
195  m_pointTableWidget->horizontalHeader()->setSectionResizeMode(
196  QHeaderView::ResizeToContents);
197 
198  if ((rowIndex + 1) > m_pointTableWidget->rowCount()) {
199  m_pointTableWidget->insertRow(m_pointTableWidget->rowCount());
200  }
201 
202  QTableWidgetItem itemPrefab;
203  itemPrefab.setTextAlignment(Qt::AlignCenter);
204 
205  m_pointTableWidget->setVerticalHeaderItem(
206  rowIndex, new QTableWidgetItem(QString("Point %1").arg(rowIndex)));
207 
208  QTableWidgetItem *xItem = itemPrefab.clone();
209  xItem->setText(QString::number(point.x, 'f', 3));
210  m_pointTableWidget->setItem(rowIndex, 0, xItem);
211 
212  QTableWidgetItem *yItem = itemPrefab.clone();
213  yItem->setText(QString::number(point.y, 'f', 3));
214  m_pointTableWidget->setItem(rowIndex, 1, yItem);
215 
216  QTableWidgetItem *zItem = itemPrefab.clone();
217  zItem->setText(QString::number(point.z, 'f', 3));
218  m_pointTableWidget->setItem(rowIndex, 2, zItem);
219 
220  m_pointTableWidget->setCellWidget(rowIndex, 3, createDeleteButton());
221 
222  m_pointTableWidget->resizeColumnToContents(0);
223  m_pointTableWidget->resizeColumnToContents(1);
224  m_pointTableWidget->resizeColumnToContents(2);
225 
226  // Finally check if actual content is smaller than the table
227  // If so -> apply stretch to fill the available area
228  if (getFittingPointContentWidth() <= getFittingPointTableWidth()) {
229  m_pointTableWidget->horizontalHeader()->setSectionResizeMode(
230  QHeaderView::Stretch);
231  }
232 }
233 
234 void ccMPlaneDlg::selectFittingPoint(unsigned int rowIndex) {
235  m_pointTableWidget->selectRow(rowIndex);
236 }
237 
239  m_pointTableWidget->setRowCount(0);
241 }
242 
243 void ccMPlaneDlg::addMeasurementPoint(const QString &name, float distance) {
244  QTableWidgetItem itemPrefab;
245  itemPrefab.setTextAlignment(Qt::AlignCenter);
246 
247  m_measurementTableWidget->blockSignals(true);
248 
249  unsigned int rowCount = m_measurementTableWidget->rowCount();
250  m_measurementTableWidget->insertRow(rowCount);
251 
252  QTableWidgetItem *idItem = itemPrefab.clone();
253  idItem->setText(name);
254  m_measurementTableWidget->setItem(rowCount, 0, idItem);
255 
256  QTableWidgetItem *distanceItem = itemPrefab.clone();
257  distanceItem->setText(QString::number(distance, 'f', 3));
258  distanceItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
259  m_measurementTableWidget->setItem(rowCount, 1, distanceItem);
260  m_measurementTableWidget->selectRow(rowCount);
261 
262  m_measurementTableWidget->blockSignals(false);
263 }
264 
266  unsigned int rowIndex) {
267  m_measurementTableWidget->blockSignals(true);
268  m_measurementTableWidget->item(rowIndex, 0)->setText(name);
269  m_measurementTableWidget->blockSignals(false);
270 }
271 
273  m_tabWidget->setTabEnabled(1, enable);
274 }
275 
277  m_measurementTableWidget->setRowCount(0);
278 }
279 
281  return m_radioButtonSignedMeasurement->isChecked();
282 }
283 
285  return m_checkBoxShowNormal->isChecked();
286 }
287 
289  m_pointTableWidget->setRowCount(6);
290  m_pointTableWidget->setColumnCount(4);
291  QStringList header;
292  header << "x"
293  << "y"
294  << "z"
295  << "";
296  m_pointTableWidget->setHorizontalHeaderLabels(header);
297  for (unsigned int i = 0; i < 6; ++i) {
298  m_pointTableWidget->setVerticalHeaderItem(
299  i, new QTableWidgetItem(QString("Point %1").arg(i)));
300  }
301 }
302 
304 
305 void ccMPlaneDlg::onTabChanged(int tab) { emit signalTabChanged(tab); }
306 
309 }
310 
312  QWidget *w = qobject_cast<QWidget *>(sender());
313  if (w) {
314  int index = m_pointTableWidget->indexAt(w->pos()).row();
315  m_pointTableWidget->removeRow(index);
316  emit signalFittingPointDelete(index);
317  }
318 }
319 
321  emit signalShowNormalCheckBoxClicked(m_checkBoxShowNormal->isChecked());
322 }
323 
325 
326 void ccMPlaneDlg::onMeasurementPointNameChanged(QTableWidgetItem *item) {
327  emit signalMeasureNameChanged(item);
328 }
std::string name
void onMeasurementPointNameChanged(QTableWidgetItem *item)
void onTabChanged(int tab)
void signalShowNormalCheckBoxClicked(bool checked)
void onRadioButtonClicked()
void onDeleteButtonClicked()
void enableMeasurementTab(bool enable)
void onSaveButtonClicked()
void signalMeasureNameChanged(QTableWidgetItem *item)
ccMPlaneDlg(QWidget *parent=0)
Default constructor.
Definition: ccMPlaneDlg.cpp:19
void selectFittingPoint(unsigned int rowIndex)
void addFittingPoint(int rowIndex, const CCVector3 &point)
void initializeFittingPointTable()
void renameMeasurement(const QString &name, unsigned int rowIndex)
void onCloseButtonPressed()
void onShowNormalCheckBox(bool checked)
void signalFittingPointDelete(int index)
void clearFittingPoints()
bool isSignedMeasurement() const
void signalTabChanged(int tab)
void addMeasurementPoint(const QString &name, float distance)
bool isNormalVectorChecked() const
void signalSaveButtonClicked()
void clearMeasurementPoints()
void signalCloseButtonPressed()
void signalMeasurementModeChanged()
Generic overlay dialog interface.
Tensor Minimum(const Tensor &input, const Tensor &other)
Computes the element-wise minimum of input and other. The tensors must have same data type and device...
Definition: lsd.c:149
int y
Definition: lsd.c:149
int x
Definition: lsd.c:149