ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvCommandRaster.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 // local
9 #include "ecvRasterizeTool.h"
10 
11 // Qt
12 #include <QMessageBox>
13 #include <QString>
14 
15 // qCC_db
16 #include <ecvMesh.h>
17 #include <ecvProgressDialog.h>
18 #include <ecvVolumeCalcTool.h>
19 
20 #include <QDateTime>
21 
22 #include "ecvCommandRaster.h"
23 
24 // shared commands
25 constexpr char COMMAND_GRID_VERT_DIR[] = "VERT_DIR";
26 constexpr char COMMAND_GRID_STEP[] = "GRID_STEP";
27 constexpr char COMMAND_GRID_OUTPUT_CLOUD[] = "OUTPUT_CLOUD";
28 constexpr char COMMAND_GRID_OUTPUT_MESH[] = "OUTPUT_MESH";
29 constexpr char COMMAND_GRID_OUTPUT_RASTER_Z[] = "OUTPUT_RASTER_Z";
30 constexpr char COMMAND_GRID_OUTPUT_RASTER_RGB[] = "OUTPUT_RASTER_RGB";
31 
32 // Rasterize specific commands
33 constexpr char COMMAND_RASTERIZE[] = "RASTERIZE";
34 constexpr char COMMAND_RASTER_CUSTOM_HEIGHT[] = "CUSTOM_HEIGHT";
35 constexpr char COMMAND_RASTER_FILL_EMPTY_CELLS[] = "EMPTY_FILL";
36 constexpr char COMMAND_RASTER_FILL_MIN_HEIGHT[] = "MIN_H";
37 constexpr char COMMAND_RASTER_FILL_MAX_HEIGHT[] = "MAX_H";
38 constexpr char COMMAND_RASTER_FILL_CUSTOM_HEIGHT[] = "CUSTOM_H";
39 constexpr char COMMAND_RASTER_FILL_INTERPOLATE[] = "INTERP";
40 constexpr char COMMAND_RASTER_PROJ_TYPE[] = "PROJ";
41 constexpr char COMMAND_RASTER_SF_PROJ_TYPE[] = "SF_PROJ";
42 constexpr char COMMAND_RASTER_PROJ_MIN[] = "MIN";
43 constexpr char COMMAND_RASTER_PROJ_MAX[] = "MAX";
44 constexpr char COMMAND_RASTER_PROJ_AVG[] = "AVG";
45 constexpr char COMMAND_RASTER_RESAMPLE[] = "RESAMPLE";
46 
47 // 2.5D Volume calculation specific commands
48 constexpr char COMMAND_VOLUME[] = "VOLUME";
49 constexpr char COMMAND_VOLUME_GROUND_IS_FIRST[] = "GROUND_IS_FIRST";
50 constexpr char COMMAND_VOLUME_CONST_HEIGHT[] = "CONST_HEIGHT";
51 
53  QString option, ccCommandLineInterface& cmd) {
54  if (option == COMMAND_RASTER_PROJ_MIN) {
56  } else if (option == COMMAND_RASTER_PROJ_MAX) {
58  } else if (option == COMMAND_RASTER_PROJ_AVG) {
60  } else {
61  assert(false);
62  cmd.warning(
63  QString("Unknwon projection type: %1 (defaulting to 'average')")
64  .arg(option));
66  }
67 }
68 
70  QString option, ccCommandLineInterface& cmd) {
71  if (option == COMMAND_RASTER_FILL_MIN_HEIGHT) {
73  } else if (option == COMMAND_RASTER_FILL_MAX_HEIGHT) {
75  } else if (option == COMMAND_RASTER_FILL_CUSTOM_HEIGHT) {
77  } else if (option == COMMAND_RASTER_FILL_INTERPOLATE) {
79  } else {
80  assert(false);
81  cmd.warning(QString("Unknwon empty cell filling strategy: %1 "
82  "(defaulting to 'leave empty')")
83  .arg(option));
85  }
86 }
87 
89  : ccCommandLineInterface::Command("Rasterize", COMMAND_RASTERIZE) {}
90 
92  cmd.print("[RASTERIZE]");
93 
94  // look for local options
95  double gridStep = 0;
96  bool outputCloud = false;
97  bool outputRasterZ = false;
98  bool outputRasterRGB = false;
99  bool outputMesh = false;
100  bool resample = false;
101  double customHeight = std::numeric_limits<double>::quiet_NaN();
102  int vertDir = 2;
103  ccRasterGrid::ProjectionType projectionType =
105  ccRasterGrid::ProjectionType sfProjectionType =
107  ccRasterGrid::EmptyCellFillOption emptyCellFillStrategy =
109 
110  while (!cmd.arguments().empty()) {
111  QString argument = cmd.arguments().front();
114  // local option confirmed, we can move on
115  cmd.arguments().pop_front();
116 
117  if (outputMesh) {
118  cmd.warning(
119  "Can't output the grid as a mesh AND a cloud at the "
120  "same time");
121  } else {
122  outputCloud = true;
123  }
125  argument, COMMAND_GRID_OUTPUT_MESH)) {
126  // local option confirmed, we can move on
127  cmd.arguments().pop_front();
128 
129  if (outputCloud) {
130  cmd.warning(
131  "Can't output the grid as a mesh AND a cloud at the "
132  "same time");
133  } else {
134  outputMesh = true;
135  }
137  argument, COMMAND_GRID_OUTPUT_RASTER_Z)) {
138  // local option confirmed, we can move on
139  cmd.arguments().pop_front();
140 
141  outputRasterZ = true;
143  argument, COMMAND_GRID_OUTPUT_RASTER_RGB)) {
144  // local option confirmed, we can move on
145  cmd.arguments().pop_front();
146 
147  outputRasterRGB = true;
148  } else if (ccCommandLineInterface::IsCommand(argument,
150  // local option confirmed, we can move on
151  cmd.arguments().pop_front();
152 
153  bool ok;
154  gridStep = cmd.arguments().takeFirst().toDouble(&ok);
155  if (!ok || gridStep <= 0) {
156  return cmd.error(QString("Invalid grid step value! (after %1)")
157  .arg(COMMAND_GRID_STEP));
158  }
160  argument, COMMAND_RASTER_CUSTOM_HEIGHT)) {
161  // local option confirmed, we can move on
162  cmd.arguments().pop_front();
163 
164  bool ok;
165  customHeight = cmd.arguments().takeFirst().toDouble(&ok);
166  if (!ok) {
167  return cmd.error(
168  QString("Invalid custom height value! (after %1)")
170  }
171  } else if (ccCommandLineInterface::IsCommand(argument,
173  // local option confirmed, we can move on
174  cmd.arguments().pop_front();
175 
176  bool ok;
177  vertDir = cmd.arguments().takeFirst().toInt(&ok);
178  if (!ok || vertDir < 0 || vertDir > 2) {
179  return cmd.error(QString("Invalid vert. direction! (after %1)")
180  .arg(COMMAND_GRID_VERT_DIR));
181  }
183  argument, COMMAND_RASTER_FILL_EMPTY_CELLS)) {
184  // local option confirmed, we can move on
185  cmd.arguments().pop_front();
186 
187  emptyCellFillStrategy = GetEmptyCellFillingStrategy(
188  cmd.arguments().takeFirst().toUpper(), cmd);
190  argument, COMMAND_RASTER_PROJ_TYPE)) {
191  // local option confirmed, we can move on
192  cmd.arguments().pop_front();
193 
194  projectionType = GetProjectionType(
195  cmd.arguments().takeFirst().toUpper(), cmd);
197  argument, COMMAND_RASTER_SF_PROJ_TYPE)) {
198  // local option confirmed, we can move on
199  cmd.arguments().pop_front();
200 
201  sfProjectionType = GetProjectionType(
202  cmd.arguments().takeFirst().toUpper(), cmd);
203  } else if (ccCommandLineInterface::IsCommand(argument,
205  // local option confirmed, we can move on
206  cmd.arguments().pop_front();
207 
208  resample = true;
209  } else {
210  break;
211  }
212  }
213 
214  if (gridStep == 0) {
215  return cmd.error(QString("Grid step value not defined (use %1)")
216  .arg(COMMAND_GRID_STEP));
217  }
218 
219  if (emptyCellFillStrategy == ccRasterGrid::FILL_CUSTOM_HEIGHT &&
220  std::isnan(customHeight)) {
221  cmd.warning(
222  "[Rasterize] The filling stragety is set to 'fill with custom "
223  "height' but no custom height was defined...");
224  emptyCellFillStrategy = ccRasterGrid::LEAVE_EMPTY;
225  }
226 
227  if (!outputCloud && !outputMesh && !outputRasterZ && !outputRasterRGB) {
228  // if no export target is specified, we chose the cloud by default
229  outputCloud = true;
230  }
231  assert(outputCloud || outputMesh);
232 
233  if (resample && !outputCloud && !outputMesh) {
234  cmd.warning(
235  "[Rasterize] The 'resample' option is set while the raster "
236  "won't be exported as a cloud nor as a mesh");
237  }
238 
239  // we'll get the first two clouds
240  for (CLCloudDesc& cloudDesc : cmd.clouds()) {
241  if (!cloudDesc.pc) {
242  assert(false);
243  continue;
244  }
245  ccBBox gridBBox = cloudDesc.pc->getOwnBB();
246 
247  // compute the grid size
248  unsigned gridWidth = 0;
249  unsigned gridHeight = 0;
250  if (!ccRasterGrid::ComputeGridSize(vertDir, gridBBox, gridStep,
251  gridWidth, gridHeight)) {
252  return cmd.error(
253  "Failed to compute the grid dimensions (check input "
254  "cloud(s) bounding-box)");
255  }
256 
257  cmd.print(QString("Grid size: %1 x %2").arg(gridWidth).arg(gridHeight));
258 
259  if (gridWidth * gridHeight > (1 << 26)) // 64 million of cells
260  {
261  if (cmd.silentMode()) {
262  CVLog::Warning("Huge grid detected!");
263  } else {
264  static bool s_firstTime = true;
265  if (s_firstTime &&
266  QMessageBox::warning(
267  cmd.widgetParent(), "Raster grid",
268  "Grid size is huge. Are you sure you want to "
269  "proceed?\n(you can avoid this message by running "
270  "in SILENT mode)",
271  QMessageBox::Yes,
272  QMessageBox::No) == QMessageBox::No) {
273  return CVLog::Warning("Process cancelled");
274  }
275  s_firstTime = false;
276  }
277  }
278 
279  ccRasterGrid grid;
280  {
281  // memory allocation
282  CCVector3d minCorner =
283  CCVector3d::fromArray(gridBBox.minCorner().u);
284  if (!grid.init(gridWidth, gridHeight, gridStep, minCorner)) {
285  // not enough memory
286  return cmd.error("Not enough memory");
287  }
288 
289  // progress dialog
290  QScopedPointer<ecvProgressDialog> pDlg(nullptr);
291  if (!cmd.silentMode()) {
292  pDlg.reset(new ecvProgressDialog(true, cmd.widgetParent()));
293  }
294 
295  if (grid.fillWith(cloudDesc.pc, vertDir, projectionType,
296  emptyCellFillStrategy ==
298  sfProjectionType, pDlg.data())) {
299  grid.fillEmptyCells(emptyCellFillStrategy, customHeight);
300  cmd.print(QString("[Rasterize] Raster grid: size: %1 x %2 / "
301  "heights: [%3 ; %4]")
302  .arg(grid.width)
303  .arg(grid.height)
304  .arg(grid.minHeight)
305  .arg(grid.maxHeight));
306  } else {
307  return cmd.error("Rasterize process failed");
308  }
309  }
310 
311  // generate the result entity (cloud by default)
312  if (outputCloud || outputMesh) {
313  std::vector<ccRasterGrid::ExportableFields> exportedFields;
314  try {
315  // we always compute the default 'height' layer
316  exportedFields.push_back(ccRasterGrid::PER_CELL_VALUE);
317  } catch (const std::bad_alloc&) {
318  return cmd.error("Not enough memory");
319  }
320 
321  ccPointCloud* rasterCloud = grid.convertToCloud(
322  exportedFields, true, true, resample, resample,
323  cloudDesc.pc, vertDir, gridBBox,
324  emptyCellFillStrategy == ccRasterGrid::FILL_CUSTOM_HEIGHT,
325  customHeight, true);
326 
327  if (!rasterCloud) {
328  return cmd.error("Failed to output the raster grid as a cloud");
329  }
330 
331  rasterCloud->showColors(cloudDesc.pc->hasColors());
332  if (rasterCloud->hasScalarFields()) {
333  rasterCloud->showSF(!cloudDesc.pc->hasColors());
334  rasterCloud->setCurrentDisplayedScalarField(0);
335  }
336  // don't forget the original shift
337  rasterCloud->setGlobalShift(cloudDesc.pc->getGlobalShift());
338  rasterCloud->setGlobalScale(cloudDesc.pc->getGlobalScale());
339 
340  if (outputCloud) {
341  assert(!outputMesh);
342  // replace current cloud by the restarized version
343  delete cloudDesc.pc;
344  cloudDesc.pc = rasterCloud;
345  cloudDesc.basename += QString("_RASTER");
346 
347  rasterCloud = nullptr;
348 
349  if (cmd.autoSaveMode()) {
350  QString errorStr = cmd.exportEntity(cloudDesc);
351  if (!errorStr.isEmpty()) {
352  return cmd.error(errorStr);
353  }
354  }
355  } else if (outputMesh) {
356  std::string errorStr;
359  rasterCloud,
362  IGNORE_MAX_EDGE_LENGTH,
363  vertDir, errorStr);
364 
365  if (baseMesh) {
366  ccMesh* rasterMesh = new ccMesh(baseMesh, rasterCloud);
367  delete baseMesh;
368  baseMesh = nullptr;
369 
370  rasterCloud->setEnabled(false);
371  rasterCloud->setVisible(true);
372  rasterMesh->addChild(rasterCloud);
373  rasterMesh->setName(rasterCloud->getName());
374  // rasterCloud->setName("vertices");
375  rasterMesh->showSF(rasterCloud->sfShown());
376  rasterMesh->showColors(rasterCloud->colorsShown());
377  rasterCloud = nullptr; // to avoid deleting it later
378 
379  cmd.print(QString("[Rasterize] Mesh '%1' successfully "
380  "generated")
381  .arg(rasterMesh->getName()));
382 
383  CLMeshDesc meshDesc;
384  meshDesc.mesh = rasterMesh;
385  meshDesc.basename =
386  cloudDesc.basename + QString("_RASTER_MESH");
387  meshDesc.path = cloudDesc.path;
388 
389  QString errorStr = cmd.exportEntity(meshDesc);
390  if (!errorStr.isEmpty()) {
391  delete rasterMesh;
392  return cmd.error(errorStr);
393  }
394 
395  // we keep the mesh loaded
396  cmd.meshes().push_back(meshDesc);
397  // delete rasterMesh;
398  // rasterMesh = 0;
399  } else {
400  cmd.warning(QString("[Rasterize] Failed to create output "
401  "mesh ('%1')")
402  .arg(QString::fromStdString(errorStr)));
403  }
404  }
405 
406  if (rasterCloud) {
407  delete rasterCloud;
408  rasterCloud = nullptr;
409  }
410  }
411 
412  if (outputRasterZ) {
414  {
415  bands.height = true;
416  bands.rgb =
417  false; // not a good idea to mix RGB and height values!
418  bands.allSFs = true;
419  }
420  QString exportFilename = cmd.getExportFilename(
421  cloudDesc, "tif", "RASTER_Z", nullptr, !cmd.addTimestamp());
422  if (exportFilename.isEmpty()) {
423  exportFilename = "rasterZ.tif";
424  }
425 
427  exportFilename, bands, emptyCellFillStrategy, grid,
428  gridBBox, vertDir, customHeight, cloudDesc.pc);
429  }
430 
431  if (outputRasterRGB) {
433  {
434  bands.rgb = true;
435  bands.height =
436  false; // not a good idea to mix RGB and height values!
437  bands.allSFs = false;
438  }
439  QString exportFilename =
440  cmd.getExportFilename(cloudDesc, "tif", "RASTER_RGB",
441  nullptr, !cmd.addTimestamp());
442  if (exportFilename.isEmpty()) {
443  exportFilename = "rasterRGB.tif";
444  }
445 
447  exportFilename, bands, emptyCellFillStrategy, grid,
448  gridBBox, vertDir, customHeight, cloudDesc.pc);
449  }
450  }
451 
452  return true;
453 }
454 
456  : ccCommandLineInterface::Command("2.5D Volume Calculation",
457  COMMAND_VOLUME) {}
458 
460  cmd.print("[2.5D VOLUME]");
461 
462  // look for local options
463  bool groundIsFirst = false;
464  double gridStep = 0;
465  double constHeight = std::numeric_limits<double>::quiet_NaN();
466  bool outputMesh = false;
467  int vertDir = 2;
468 
469  while (!cmd.arguments().empty()) {
470  QString argument = cmd.arguments().front();
473  // local option confirmed, we can move on
474  cmd.arguments().pop_front();
475 
476  groundIsFirst = true;
478  argument, COMMAND_GRID_OUTPUT_MESH)) {
479  // local option confirmed, we can move on
480  cmd.arguments().pop_front();
481 
482  outputMesh = true;
483  } else if (ccCommandLineInterface::IsCommand(argument,
485  // local option confirmed, we can move on
486  cmd.arguments().pop_front();
487 
488  bool ok;
489  gridStep = cmd.arguments().takeFirst().toDouble(&ok);
490  if (!ok || gridStep <= 0) {
491  return cmd.error(QString("Invalid grid step value! (after %1)")
492  .arg(COMMAND_GRID_STEP));
493  }
495  argument, COMMAND_VOLUME_CONST_HEIGHT)) {
496  // local option confirmed, we can move on
497  cmd.arguments().pop_front();
498 
499  bool ok;
500  constHeight = cmd.arguments().takeFirst().toDouble(&ok);
501  if (!ok) {
502  return cmd.error(
503  QString("Invalid const. height value! (after %1)")
505  }
506  } else if (ccCommandLineInterface::IsCommand(argument,
508  // local option confirmed, we can move on
509  cmd.arguments().pop_front();
510 
511  bool ok;
512  vertDir = cmd.arguments().takeFirst().toInt(&ok);
513  if (!ok || vertDir < 0 || vertDir > 2) {
514  return cmd.error(QString("Invalid vert. direction! (after %1)")
515  .arg(COMMAND_GRID_VERT_DIR));
516  }
517  } else {
518  // unrecognized argument (probably another command?)
519  break;
520  }
521  }
522 
523  if (gridStep == 0) {
524  return cmd.error(QString("Grid step value not defined (use %1)")
525  .arg(COMMAND_GRID_STEP));
526  }
527 
528  // we'll get the first two clouds
529  CLCloudDesc* ground = nullptr;
530  CLCloudDesc* ceil = nullptr;
531  {
532  CLCloudDesc* clouds[2] = {nullptr, nullptr};
533  int index = 0;
534  if (!cmd.clouds().empty()) {
535  clouds[index++] = &cmd.clouds()[0];
536  if (std::isnan(constHeight) && cmd.clouds().size() > 1) {
537  clouds[index++] = &cmd.clouds()[1];
538  }
539  }
540 
541  int expectedCount = std::isnan(constHeight) ? 2 : 1;
542  if (index != expectedCount) {
543  return cmd.error(QString("Not enough loaded entities (%1 found, %2 "
544  "expected)")
545  .arg(index)
546  .arg(expectedCount));
547  }
548 
549  if (index == 2 && groundIsFirst) {
550  // put them in the right order (ground then ceil)
551  std::swap(clouds[0], clouds[1]);
552  }
553 
554  ceil = clouds[0];
555  ground = clouds[1];
556  }
557 
558  ccBBox gridBBox = ceil ? ceil->pc->getOwnBB() : ccBBox();
559  if (ground) {
560  gridBBox += ground->pc->getOwnBB();
561  }
562 
563  // compute the grid size
564  unsigned gridWidth = 0;
565  unsigned gridHeight = 0;
566  if (!ccRasterGrid::ComputeGridSize(vertDir, gridBBox, gridStep, gridWidth,
567  gridHeight)) {
568  return cmd.error(
569  "Failed to compute the grid dimensions (check input cloud(s) "
570  "bounding-box)");
571  }
572 
573  cmd.print(QString("Grid size: %1 x %2").arg(gridWidth).arg(gridHeight));
574 
575  if (gridWidth * gridHeight > (1 << 26)) // 64 million of cells
576  {
577  if (cmd.silentMode()) {
578  CVLog::Warning("Huge grid detected!");
579  } else {
580  static bool s_firstTime = true;
581  if (s_firstTime &&
582  QMessageBox::warning(cmd.widgetParent(), "Volume grid",
583  "Grid size is huge. Are you sure you want "
584  "to proceed?\n(you can avoid this message "
585  "by running in SILENT mode)",
586  QMessageBox::Yes,
587  QMessageBox::No) == QMessageBox::No) {
588  return CVLog::Warning("Process cancelled");
589  }
590  s_firstTime = false;
591  }
592  }
593 
594  ccRasterGrid grid;
595  ccVolumeCalcTool::ReportInfo reportInfo;
597  grid, ground ? ground->pc : nullptr, ceil ? ceil->pc : nullptr,
598  gridBBox, vertDir, gridStep, gridWidth, gridHeight,
600  ccRasterGrid::LEAVE_EMPTY, reportInfo, constHeight, constHeight,
601  cmd.silentMode() ? nullptr : cmd.widgetParent())) {
602  CLCloudDesc* desc = ceil ? ceil : ground;
603  assert(desc);
604 
605  // save repot in a separate text file
606  {
607  QString txtFilename =
608  QString("%1/VolumeCalculationReport").arg(desc->path);
609  if (cmd.addTimestamp())
610  txtFilename += QString("_%1").arg(
611  QDateTime::currentDateTime().toString(
612  "yyyy-MM-dd_hh'h'mm"));
613  txtFilename += QString(".txt");
614 
615  QFile txtFile(txtFilename);
616  txtFile.open(QIODevice::WriteOnly | QIODevice::Text);
617  QTextStream txtStream(&txtFile);
618  txtStream << reportInfo.toText() << QtCompat::endl;
619  txtFile.close();
620  }
621 
622  // generate the result entity (cloud by default)
623  {
625  grid, gridBBox, vertDir, true);
626  if (!rasterCloud) {
627  return cmd.error("Failed to output the volume grid");
628  }
629  if (rasterCloud->hasScalarFields()) {
630  // convert SF to RGB
631  // rasterCloud->setCurrentDisplayedScalarField(0);
632  rasterCloud->convertCurrentScalarFieldToColors(false);
633  rasterCloud->showColors(true);
634  }
635 
636  ccMesh* rasterMesh = nullptr;
637  if (outputMesh) {
638  std::string errorStr;
641  rasterCloud,
644  IGNORE_MAX_EDGE_LENGTH,
645  vertDir, errorStr);
646 
647  if (baseMesh) {
648  rasterMesh = new ccMesh(baseMesh, rasterCloud);
649  delete baseMesh;
650  baseMesh = nullptr;
651  }
652 
653  if (rasterMesh) {
654  rasterCloud->setEnabled(false);
655  rasterCloud->setVisible(true);
656  rasterMesh->addChild(rasterCloud);
657  rasterMesh->setName(rasterCloud->getName());
658  rasterCloud->setName("vertices");
659  rasterMesh->showSF(rasterCloud->sfShown());
660  rasterMesh->showColors(rasterCloud->colorsShown());
661 
662  cmd.print(
663  QString("[Volume] Mesh '%1' successfully generated")
664  .arg(rasterMesh->getName()));
665  } else {
666  delete rasterCloud;
667  return cmd.error(
668  QString("[Voume] Failed to create output "
669  "mesh ('%1')")
670  .arg(QString::fromStdString(errorStr)));
671  }
672  }
673 
674  CLEntityDesc* outputDesc = nullptr;
675  if (rasterMesh) {
676  CLMeshDesc meshDesc;
677  meshDesc.mesh = rasterMesh;
678  meshDesc.basename = desc->basename;
679  meshDesc.path = desc->path;
680  cmd.meshes().push_back(meshDesc);
681  outputDesc = &cmd.meshes().back();
682  } else {
683  CLCloudDesc cloudDesc;
684  cloudDesc.pc = rasterCloud;
685  cloudDesc.basename = desc->basename;
686  cloudDesc.path = desc->path;
687  cmd.clouds().push_back(cloudDesc);
688  outputDesc = &cmd.clouds().back();
689  }
690 
691  // save result
692  if (outputDesc && cmd.autoSaveMode()) {
693  QString outputFilename;
694  QString errorStr = cmd.exportEntity(
695  *outputDesc, "HEIGHT_DIFFERENCE", &outputFilename);
696  if (!errorStr.isEmpty()) cmd.warning(errorStr);
697  }
698  }
699  } else {
700  return cmd.error("Failed to compte the volume");
701  }
702 
703  return true;
704 }
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
Type u[3]
Definition: CVGeom.h:139
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
Definition: CVGeom.h:268
Bounding box structure.
Definition: ecvBBox.h:25
virtual ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
Definition: ecvBBox.h:64
Command line interface.
virtual QStringList & arguments()=0
Returns the list of arguments.
virtual void warning(const QString &message) const =0
virtual void print(const QString &message) const =0
virtual QString getExportFilename(const CLEntityDesc &entityDesc, QString extension=QString(), QString suffix=QString(), QString *baseOutputFilename=nullptr, bool forceNoTimestamp=false) const =0
Returns the name of a to-be-exported entity.
virtual bool error(const QString &message) const =0
static bool IsCommand(const QString &token, const char *command)
Test whether a command line token is a valid command keyword or not.
bool silentMode() const
Returns the silent mode.
virtual QString exportEntity(CLEntityDesc &entityDesc, const QString &suffix=QString(), QString *outputFilename=nullptr, ccCommandLineInterface::ExportOptions options=ExportOption::NoOptions)=0
Exports a cloud or a mesh.
virtual std::vector< CLMeshDesc > & meshes()
Currently opened meshes and their filename.
virtual QDialog * widgetParent()
Returns a (widget) parent (if any is available)
virtual std::vector< CLCloudDesc > & clouds()
Currently opened point clouds and their filename.
virtual bool colorsShown() const
Returns whether colors are shown or not.
virtual void setVisible(bool state)
Sets entity visibility.
virtual bool sfShown() const
Returns whether active scalar field is visible.
virtual void showColors(bool state)
Sets colors visibility.
virtual void showSF(bool state)
Sets active scalarfield visibility.
ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
Triangular mesh.
Definition: ecvMesh.h:35
virtual QString getName() const
Returns object name.
Definition: ecvObject.h:72
virtual void setName(const QString &name)
Sets object name.
Definition: ecvObject.h:75
virtual void setEnabled(bool state)
Sets the "enabled" property.
Definition: ecvObject.h:102
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void setCurrentDisplayedScalarField(int index)
Sets the currently displayed scalar field.
bool convertCurrentScalarFieldToColors(bool mixWithExistingColor=false)
bool hasScalarFields() const override
Returns whether one or more scalar fields are instantiated.
static bool ExportGeoTiff(QString outputFilename, const ExportBands &exportBands, ccRasterGrid::EmptyCellFillOption fillEmptyCellsStrategy, const ccRasterGrid &grid, const ccBBox &gridBBox, unsigned char Z, double customHeightForEmptyCells=std::numeric_limits< double >::quiet_NaN(), ccGenericPointCloud *originCloud=0, int visibleSfIndex=-1)
Exports a raster grid as a geotiff file.
virtual void setGlobalScale(double scale)
virtual void setGlobalShift(double x, double y, double z)
Sets shift applied to original coordinates (information storage only)
static ccPointCloud * ConvertGridToCloud(ccRasterGrid &grid, const ccBBox &gridBox, unsigned char vertDim, bool exportToOriginalCS)
Converts a (volume) grid to a point cloud.
static bool ComputeVolume(ccRasterGrid &grid, ccGenericPointCloud *ground, ccGenericPointCloud *ceil, const ccBBox &gridBox, unsigned char vertDim, double gridStep, unsigned gridWidth, unsigned gridHeight, ccRasterGrid::ProjectionType projectionType, ccRasterGrid::EmptyCellFillOption groundEmptyCellFillStrategy, ccRasterGrid::EmptyCellFillOption ceilEmptyCellFillStrategy, ccVolumeCalcTool::ReportInfo &reportInfo, double groundHeight, double ceilHeight, QWidget *parentWidget=0)
Static accessor.
const Vector3Tpl< T > & minCorner() const
Returns min corner (const)
Definition: BoundingBox.h:154
A generic mesh with index-based vertex access.
static GenericIndexedMesh * computeTriangulation(GenericIndexedCloudPersist *cloud, TRIANGULATION_TYPES type, PointCoordinateType maxEdgeLength, unsigned char dim, std::string &outputErrorStr)
Applys a geometrical transformation to a single point.
Graphical progress indicator (thread-safe)
constexpr char COMMAND_RASTERIZE[]
constexpr char COMMAND_RASTER_PROJ_MIN[]
static ccRasterGrid::EmptyCellFillOption GetEmptyCellFillingStrategy(QString option, ccCommandLineInterface &cmd)
constexpr char COMMAND_GRID_VERT_DIR[]
constexpr char COMMAND_RASTER_FILL_MAX_HEIGHT[]
constexpr char COMMAND_RASTER_FILL_INTERPOLATE[]
constexpr char COMMAND_RASTER_CUSTOM_HEIGHT[]
constexpr char COMMAND_RASTER_FILL_MIN_HEIGHT[]
constexpr char COMMAND_VOLUME[]
constexpr char COMMAND_RASTER_PROJ_MAX[]
constexpr char COMMAND_GRID_OUTPUT_RASTER_Z[]
constexpr char COMMAND_RASTER_PROJ_TYPE[]
constexpr char COMMAND_RASTER_RESAMPLE[]
constexpr char COMMAND_GRID_OUTPUT_RASTER_RGB[]
constexpr char COMMAND_VOLUME_GROUND_IS_FIRST[]
constexpr char COMMAND_RASTER_FILL_EMPTY_CELLS[]
static ccRasterGrid::ProjectionType GetProjectionType(QString option, ccCommandLineInterface &cmd)
constexpr char COMMAND_GRID_STEP[]
constexpr char COMMAND_RASTER_PROJ_AVG[]
constexpr char COMMAND_RASTER_FILL_CUSTOM_HEIGHT[]
constexpr char COMMAND_GRID_OUTPUT_CLOUD[]
constexpr char COMMAND_VOLUME_CONST_HEIGHT[]
constexpr char COMMAND_GRID_OUTPUT_MESH[]
constexpr char COMMAND_RASTER_SF_PROJ_TYPE[]
QTextStream & endl(QTextStream &stream)
Definition: QtCompat.h:718
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
Definition: MiniVec.h:89
std::string toString(T x)
Definition: Common.h:80
void swap(cloudViewer::core::SmallVectorImpl< T > &LHS, cloudViewer::core::SmallVectorImpl< T > &RHS)
Implement std::swap in terms of SmallVector swap.
Definition: SmallVector.h:1370
Loaded cloud description.
ccPointCloud * pc
Loaded entity description.
Loaded mesh description.
ccGenericMesh * mesh
bool process(ccCommandLineInterface &cmd) override
Main process.
bool process(ccCommandLineInterface &cmd) override
Main process.
Raster grid type.
Definition: ecvRasterGrid.h:53
ProjectionType
Types of projection.
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.
static bool ComputeGridSize(unsigned char Z, const ccBBox &box, double gridStep, unsigned &width, unsigned &height)
Computes the raster size for a given bounding-box.
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)
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')
Bands to be exported.
QString toText(int precision=6) const