31 #include <QApplication>
35 #include <QMessageBox>
36 #include <QPushButton>
45 : QDialog(parent, Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint),
47 Ui::VolumeCalcDialog(),
52 connect(buttonBox, &QDialogButtonBox::accepted,
this,
54 connect(buttonBox, &QDialogButtonBox::rejected,
this,
55 &ccVolumeCalcTool::reject);
56 connect(gridStepDoubleSpinBox,
57 static_cast<void (QDoubleSpinBox::*)(
double)
>(
58 &QDoubleSpinBox::valueChanged),
60 connect(gridStepDoubleSpinBox,
61 static_cast<void (QDoubleSpinBox::*)(
double)
>(
62 &QDoubleSpinBox::valueChanged),
64 connect(groundEmptyValueDoubleSpinBox,
65 static_cast<void (QDoubleSpinBox::*)(
double)
>(
66 &QDoubleSpinBox::valueChanged),
68 connect(ceilEmptyValueDoubleSpinBox,
69 static_cast<void (QDoubleSpinBox::*)(
double)
>(
70 &QDoubleSpinBox::valueChanged),
72 connect(projDimComboBox,
73 static_cast<void (QComboBox::*)(
int)
>(
74 &QComboBox::currentIndexChanged),
76 connect(updatePushButton, &QPushButton::clicked,
this,
78 connect(heightProjectionComboBox,
79 static_cast<void (QComboBox::*)(
int)
>(
80 &QComboBox::currentIndexChanged),
82 connect(fillGroundEmptyCellsComboBox,
83 static_cast<void (QComboBox::*)(
int)
>(
84 &QComboBox::currentIndexChanged),
86 connect(fillCeilEmptyCellsComboBox,
87 static_cast<void (QComboBox::*)(
int)
>(
88 &QComboBox::currentIndexChanged),
90 connect(swapToolButton, &QToolButton::clicked,
this,
92 connect(groundComboBox,
93 static_cast<void (QComboBox::*)(
int)
>(
94 &QComboBox::currentIndexChanged),
97 static_cast<void (QComboBox::*)(
int)
>(
98 &QComboBox::currentIndexChanged),
100 connect(clipboardPushButton, &QPushButton::clicked,
this,
102 connect(exportGridPushButton, &QPushButton::clicked,
this,
104 connect(precisionSpinBox,
105 static_cast<void (QSpinBox::*)(
int)
>(&QSpinBox::valueChanged),
this,
121 connect(editGridToolButton, &QToolButton::clicked,
this,
124 editGridToolButton->setEnabled(
false);
127 groundComboBox->addItem(
"Constant");
128 ceilComboBox->addItem(
"Constant");
137 assert(groundComboBox->count() >= 2);
138 groundComboBox->setCurrentIndex(groundComboBox->count() - 2);
139 ceilComboBox->setCurrentIndex(ceilComboBox->count() - 1);
145 params.colorScaleShowHistogram =
false;
146 params.displayedNumPrecision = precisionSpinBox->value();
163 params.displayedNumPrecision = precision;
169 if (clipboardPushButton->isEnabled()) {
175 fillGroundEmptyCellsComboBox->setEnabled(groundComboBox->currentIndex() >
181 fillCeilEmptyCellsComboBox->setEnabled(ceilComboBox->currentIndex() > 0);
186 int sourceIndex = ceilComboBox->currentIndex();
187 int emptyCellStrat = fillCeilEmptyCellsComboBox->currentIndex();
188 double emptyCellValue = ceilEmptyValueDoubleSpinBox->value();
190 ceilComboBox->setCurrentIndex(groundComboBox->currentIndex());
191 fillCeilEmptyCellsComboBox->setCurrentIndex(
192 fillGroundEmptyCellsComboBox->currentIndex());
193 ceilEmptyValueDoubleSpinBox->setValue(
194 groundEmptyValueDoubleSpinBox->value());
196 groundComboBox->setCurrentIndex(sourceIndex);
197 fillGroundEmptyCellsComboBox->setCurrentIndex(emptyCellStrat);
198 groundEmptyValueDoubleSpinBox->setValue(emptyCellValue);
217 return gridStepDoubleSpinBox->value();
221 int dim = projDimComboBox->currentIndex();
222 assert(dim >= 0 && dim < 3);
224 return static_cast<unsigned char>(dim);
240 groundEmptyValueDoubleSpinBox->setEnabled(
241 groundComboBox->currentIndex() == 0 ||
250 ceilEmptyValueDoubleSpinBox->setEnabled(
251 ceilComboBox->currentIndex() == 0 ||
259 switch (heightProjectionComboBox->currentIndex()) {
277 int projType = settings.value(
"ProjectionType",
278 heightProjectionComboBox->currentIndex())
281 settings.value(
"ProjectionDim", projDimComboBox->currentIndex())
283 int groundFillStrategy =
284 settings.value(
"gFillStrategy",
285 fillGroundEmptyCellsComboBox->currentIndex())
287 int ceilFillStrategy =
288 settings.value(
"cFillStrategy",
289 fillCeilEmptyCellsComboBox->currentIndex())
291 double step = settings.value(
"GridStep", gridStepDoubleSpinBox->value())
293 double groundEmptyHeight =
294 settings.value(
"gEmptyCellsHeight",
295 groundEmptyValueDoubleSpinBox->value())
297 double ceilEmptyHeight =
298 settings.value(
"cEmptyCellsHeight",
299 ceilEmptyValueDoubleSpinBox->value())
302 settings.value(
"NumPrecision", precisionSpinBox->value()).toInt();
305 gridStepDoubleSpinBox->setValue(step);
306 heightProjectionComboBox->setCurrentIndex(projType);
307 fillGroundEmptyCellsComboBox->setCurrentIndex(groundFillStrategy);
308 fillCeilEmptyCellsComboBox->setCurrentIndex(ceilFillStrategy);
309 groundEmptyValueDoubleSpinBox->setValue(groundEmptyHeight);
310 ceilEmptyValueDoubleSpinBox->setValue(ceilEmptyHeight);
311 projDimComboBox->setCurrentIndex(projDim);
312 precisionSpinBox->setValue(precision);
323 settings.setValue(
"ProjectionType",
324 heightProjectionComboBox->currentIndex());
325 settings.setValue(
"ProjectionDim", projDimComboBox->currentIndex());
326 settings.setValue(
"gFillStrategy",
327 fillGroundEmptyCellsComboBox->currentIndex());
328 settings.setValue(
"cFillStrategy",
329 fillCeilEmptyCellsComboBox->currentIndex());
330 settings.setValue(
"GridStep", gridStepDoubleSpinBox->value());
331 settings.setValue(
"gEmptyCellsHeight",
332 groundEmptyValueDoubleSpinBox->value());
333 settings.setValue(
"cEmptyCellsHeight",
334 ceilEmptyValueDoubleSpinBox->value());
335 settings.setValue(
"NumPrecision", precisionSpinBox->value());
342 updatePushButton->setStyleSheet(QString());
345 updatePushButton->setStyleSheet(
"color: white; background-color:red;");
347 updatePushButton->setDisabled(state);
348 clipboardPushButton->setEnabled(state);
349 exportGridPushButton->setEnabled(state);
351 spareseWarningLabel->hide();
352 reportPlainTextEdit->setPlainText(
"Update the grid first");
358 unsigned char vertDim,
359 bool exportToOriginalCS) {
366 std::vector<ccRasterGrid::ExportableFields> exportedFields;
370 exportedFields,
false,
false,
false,
false, 0, vertDim, gridBox,
371 false, std::numeric_limits<double>::quiet_NaN(),
375 rasterCloud->
showSF(
true);
380 sf->
setName(
"Relative height");
384 }
catch (
const std::bad_alloc&) {
396 bool exportToOriginalCS)
const {
400 std::vector<ccRasterGrid::ExportableFields> exportedFields;
403 exportedFields,
false,
false,
false,
false, 0,
false,
404 std::numeric_limits<double>::quiet_NaN(), exportToOriginalCS);
407 rasterCloud->
showSF(
true);
412 sf->
setName(
"Relative height");
416 }
catch (
const std::bad_alloc&) {
452 QLocale locale(QLocale::English);
454 QStringList reportText;
455 reportText << QString(
"Volume: %1")
456 .arg(locale.toString(
volume,
'f', precision));
457 reportText << QString(
"Surface: %1")
458 .arg(locale.toString(
surface,
'f', precision));
459 reportText << QString(
"----------------------");
460 reportText << QString(
"Added volume: (+)%1")
461 .arg(locale.toString(
addedVolume,
'f', precision));
462 reportText << QString(
"Removed volume: (-)%1")
464 reportText << QString(
"----------------------");
467 reportText << QString(
"Non-matching cells:");
468 reportText << QString(
" ground = %1%")
472 reportText << QString(
"Average neighbors per cell: %1 / 8.0")
475 return reportText.join(
"\n");
479 int precision = precisionSpinBox->value();
481 reportPlainTextEdit->setPlainText(info.
toText(precision));
487 clipboardPushButton->setEnabled(
true);
490 bool SendError(
const QString& message, QWidget* parentWidget) {
504 unsigned char vertDim,
512 double groundHeight = std::numeric_limits<double>::quiet_NaN(),
513 double ceilHeight = std::numeric_limits<double>::quiet_NaN(),
514 QWidget* parentWidget ) {
515 if (gridStep <= 1.0e-8 || gridWidth == 0 || gridHeight == 0 ||
522 if (!ground && !
ceil) {
534 unsigned gridTotalSize = gridWidth * gridHeight;
535 if (gridTotalSize == 1) {
537 QMessageBox::question(parentWidget,
"Unexpected grid size",
538 "The generated grid will only have 1 cell! "
539 "Do you want to proceed anyway?",
541 QMessageBox::No) == QMessageBox::No)
543 }
else if (gridTotalSize > 10000000) {
545 QMessageBox::question(
546 parentWidget,
"Big grid size",
547 "The generated grid will have more than 10.000.000 cells! "
548 "Do you want to proceed anyway?",
549 QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
555 if (!grid.
init(gridWidth, gridHeight, gridStep, minCorner)) {
557 return SendError(
"Not enough memory", parentWidget);
561 QScopedPointer<ecvProgressDialog> pDlg(0);
568 if (!groundRaster.
init(gridWidth, gridHeight, gridStep, minCorner)) {
570 return SendError(
"Not enough memory", parentWidget);
573 if (groundRaster.
fillWith(ground, vertDim, projectionType,
574 groundEmptyCellFillStrategy ==
580 CVLog::Print(QString(
"[Volume] Ground raster grid: size: %1 x %2 / "
581 "heights: [%3 ; %4]")
582 .arg(groundRaster.
width)
594 if (!ceilRaster.
init(gridWidth, gridHeight, gridStep, minCorner)) {
596 return SendError(
"Not enough memory", parentWidget);
600 ceilEmptyCellFillStrategy ==
605 CVLog::Print(QString(
"[Volume] Ceil raster grid: size: %1 x %2 / "
606 "heights: [%3 ; %4]")
607 .arg(ceilRaster.
width)
619 pDlg->setMethodTitle(QObject::tr(
"Volume computation"));
620 pDlg->setInfo(QObject::tr(
"Cells: %1 x %2")
625 QCoreApplication::processEvents();
630 size_t ceilNonMatchingCount = 0;
631 size_t groundNonMatchingCount = 0;
632 size_t cellCount = 0;
636 for (
unsigned i = 0; i < grid.
height; ++i) {
637 for (
unsigned j = 0; j < grid.
width; ++j) {
640 bool validGround =
true;
644 validGround = std::isfinite(cell.
minHeight);
647 bool validCeil =
true;
651 validCeil = std::isfinite(cell.
maxHeight);
654 if (validGround && validCeil) {
661 }
else if (cell.
h > 0) {
670 ++groundNonMatchingCount;
671 }
else if (validCeil) {
673 ++ceilNonMatchingCount;
675 cell.
h = std::numeric_limits<double>::quiet_NaN();
679 cell.
avgHeight = (groundHeight + ceilHeight) / 2;
692 size_t validNeighborsCount = 0;
694 for (
unsigned i = 1; i < grid.
height - 1; ++i) {
695 for (
unsigned j = 1; j < grid.
width - 1; ++j) {
697 if (cell.
h == cell.
h) {
698 for (
unsigned k = i - 1; k <= i + 1; ++k) {
699 for (
unsigned l = j - 1; l <= j + 1; ++l) {
700 if (k != i || l != j) {
702 if (std::isfinite(otherCell.
h)) {
703 ++validNeighborsCount;
716 static_cast<double>(validNeighborsCount) /
count;
723 static_cast<float>(groundNonMatchingCount * 100) / cellCount;
725 static_cast<float>(ceilNonMatchingCount * 100) / cellCount;
727 reportInfo.
volume *= cellArea;
730 reportInfo.
surface *= cellArea;
750 unsigned gridWidth = 0, gridHeight = 0;
757 assert(gridStep != 0);
761 double groundHeight = 0;
762 switch (groundComboBox->currentIndex()) {
764 groundHeight = groundEmptyValueDoubleSpinBox->value();
779 double ceilHeight = 0;
780 switch (ceilComboBox->currentIndex()) {
782 ceilHeight = ceilEmptyValueDoubleSpinBox->value();
802 reportInfo, groundHeight, ceilHeight,
this)) {
811 QClipboard* clipboard = QApplication::clipboard();
813 clipboard->setText(reportPlainTextEdit->toPlainText());
828 rasterCloud->
setName(
"Height difference " + rasterCloud->
getName());
840 mainWindow->
addToDB(rasterCloud);
841 CVLog::Print(QString(
"[Volume] Cloud '%1' successfully exported")
cmdLineReadable * params[]
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
static bool Print(const char *format,...)
Prints out a formatted message in console.
static bool Error(const char *format,...)
Display an error dialog with formatted message.
static MainWindow * TheInstance()
Returns the unique instance of this object.
void addToDB(const QStringList &filenames, QString fileFilter=QString(), bool displayDialog=true)
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
2.5D data editor (generic interface)
virtual ccBBox getCustomBBox() const
Returns custom bbox.
ccRasterGrid::EmptyCellFillOption getFillEmptyCellsStrategy(QComboBox *comboBox) const
Returns the empty cell strategy (for a given combo-box)
void createBoundingBoxEditor(const ccBBox &gridBBox, QWidget *parent)
Creates the bounding-box editor.
ccPointCloud * convertGridToCloud(const std::vector< ccRasterGrid::ExportableFields > &exportedFields, bool interpolateSF, bool interpolateColors, bool resampleInputCloudXY, bool resampleInputCloudZ, ccGenericPointCloud *inputCloud, bool fillEmptyCells, double emptyCellsHeight, bool exportToOriginalCS) const
Shortcut to ccRasterGrid::convertToCloud.
ccRasterGrid m_grid
Raster grid.
virtual void update2DDisplayZoom(ccBBox &box)
Updates the 2D display zoom.
ccPointCloud * m_rasterCloud
'Raster' cloud
virtual bool showGridBoxEditor()
Show grid box editor and update.
virtual QString getGridSizeAsString() const
Returns the grid size as a string.
void create2DView(QFrame *parentFrame)
Creates the 2D view.
virtual bool getGridSize(unsigned &width, unsigned &height) const
Returns the grid size.
virtual void showSF(bool state)
Sets active scalarfield visibility.
A 3D cloud interface with associated features (color, normals, octree, etc.)
ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
virtual ccBBox getDisplayBB_recursive(bool relative)
Returns the bounding-box of this entity and it's children WHEN DISPLAYED.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
ccHObject * getParent() const
Returns parent object.
virtual QString getName() const
Returns object name.
virtual void setName(const QString &name)
Sets object name.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void setCurrentDisplayedScalarField(int index)
Sets the currently displayed scalar field.
void showSFColorsScale(bool state)
Sets whether color scale should be displayed or not.
bool hasScalarFields() const override
Returns whether one or more scalar fields are instantiated.
A scalar field associated to display-related parameters.
void setSymmetricalScale(bool state)
Sets whether the color scale should be symmetrical or not.
const Vector3Tpl< T > & minCorner() const
Returns min corner (const)
bool isValid() const
Returns whether bounding box is valid or not.
bool oneStep()
Increments total progress value of a single unit.
ScalarField * getScalarField(int index) const
Returns a pointer to a specific scalar field.
ScalarType getMin() const
Returns the minimum value.
void setName(const char *name)
Sets scalar field name.
ScalarType getMax() const
Returns the maximum value.
static const QString VolumeCalculation()
Graphical progress indicator (thread-safe)
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
void swap(cloudViewer::core::SmallVectorImpl< T > &LHS, cloudViewer::core::SmallVectorImpl< T > &RHS)
Implement std::swap in terms of SmallVector swap.
double avgHeight
Average height value.
unsigned nbPoints
Number of points projected in this cell.
PointCoordinateType maxHeight
Max height value.
PointCoordinateType minHeight
Min height value.
double stdDevHeight
Height std.dev.
unsigned validCellCount
Number of VALID cells.
unsigned nonEmptyCellCount
Number of NON-EMPTY cells.
void setValid(bool state)
Sets valid.
ProjectionType
Types of projection.
@ INVALID_PROJECTION_TYPE
double gridStep
Grid step ('pixel' size)
unsigned height
Number of rows.
bool init(unsigned w, unsigned h, double gridStep, const CCVector3d &minCorner)
Initializes / resets the grid.
bool fillWith(ccGenericPointCloud *cloud, unsigned char projectionDimension, ProjectionType projectionType, bool interpolateEmptyCells, ProjectionType sfInterpolation=INVALID_PROJECTION_TYPE, ecvProgressDialog *progressDialog=nullptr)
Fills the grid with a point cloud.
std::vector< Row > rows
All cells.
double maxHeight
Max height (computed on the NON-EMPTY or INTERPOLATED cells)
ccPointCloud * convertToCloud(const std::vector< ExportableFields > &exportedFields, bool interpolateSF, bool interpolateColors, bool resampleInputCloudXY, bool resampleInputCloudZ, ccGenericPointCloud *inputCloud, unsigned char Z, const ccBBox &box, bool fillEmptyCells, double emptyCellsHeight, bool exportToOriginalCS) const
Converts the grid to a cloud with scalar field(s)
bool isValid() const
Returns whether the grid is 'valid' or not.
unsigned width
Number of columns.
EmptyCellFillOption
Option for handling empty cells.
double minHeight
Min height (computed on the NON-EMPTY or INTERPOLATED cells)
void fillEmptyCells(EmptyCellFillOption fillEmptyCellsStrategy, double customCellHeight=0)
Fills the empty cell (for all strategies but 'INTERPOLATE_DELAUNAY')