ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
MarchingCubeReconstruction.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 
9 
10 #include <Utils/cc2sm.h>
11 #include <Utils/sm2cc.h>
12 
13 #include "PclUtils/PCLModules.h"
15 
16 // CV_DB_LIB
17 #include <ecvMesh.h>
18 #include <ecvPointCloud.h>
19 
20 // ECV_PLUGINS
21 #include <ecvMainAppInterface.h>
22 
23 // QT
24 #include <QMainWindow>
25 
26 // SYSTEM
27 #include <iostream>
28 
31  tr("Marching Cube"),
32  tr("Marching Cube Reconstruction"),
33  tr("Marching Cube Reconstruction from clouds"),
34  ":/toolbar/PclAlgorithms/icons/MarchingCubeReconstruction.png")),
35  m_dialog(nullptr),
36  m_normalSearchRadius(0),
37  m_knn_radius(20),
38  m_useKnn(true),
39  m_marchingMethod(0),
40  m_epsilon(0.01f),
41  m_isoLevel(0.0f),
42  m_gridResolution(50),
43  m_percentageExtendGrid(0.0f) {}
44 
46  // we must delete parent-less dialogs ourselves!
47  if (m_dialog && m_dialog->parent() == nullptr) delete m_dialog;
48 }
49 
51  // do we have a selected cloud?
52  int have_cloud = isFirstSelectedCcPointCloud();
53  if (have_cloud != 1) return -11;
54 
55  return 1;
56 }
57 
59  // initialize the dialog object
60  if (!m_dialog)
62 
64  if (cloud) {
65  ccBBox bBox = cloud->getOwnBB();
66  if (bBox.isValid())
67  m_dialog->normalSearchRadius->setValue(bBox.getDiagNorm() * 0.005);
68  }
69 
70  if (!m_dialog->exec()) return 0;
71 
72  return 1;
73 }
74 
76  if (!m_dialog) return;
77 
78  // get the parameters from the dialog
79  m_useKnn = m_dialog->useKnnCheckBoxForTriangulation->isChecked();
80  m_knn_radius = m_dialog->knnSpinBoxForTriangulation->value();
82  static_cast<float>(m_dialog->normalSearchRadius->value());
83 
84  m_marchingMethod = m_dialog->MarchingMethodsCombo->currentIndex();
85  m_epsilon = static_cast<float>(m_dialog->epsilonSpinBox->value());
86  m_isoLevel = static_cast<float>(m_dialog->isoLevelSpinBox->value());
88  static_cast<float>(m_dialog->gridResolutionSpinBox->value());
90  static_cast<float>(m_dialog->percentageExtendedSpinBox->value());
91 }
92 
94 
97  if (!cloud) return -1;
98 
99  // create storage for normals
100  PointCloudNormal::Ptr cloudWithNormals(new PointCloudNormal);
101 
102  if (!cloud->hasNormals()) {
103  // get xyz as pcl point cloud
104  PointCloudT::Ptr xyzCloud = cc2smReader(cloud).getXYZ2();
105  if (!xyzCloud) return -1;
106 
107  // now compute
108  CloudNormal::Ptr normals(new CloudNormal);
109  int result = PCLModules::ComputeNormals<PointT, NormalT>(
110  xyzCloud, normals,
112  if (result < 0) return -1;
113 
114  // concat points and normals
115  pcl::concatenateFields(*xyzCloud, *normals, *cloudWithNormals);
116  CVLog::Print(tr(
117  "[MarchingCubeReconstruction::compute] generate new normals"));
118  } else {
119  PCLCloud::Ptr sm_cloud = cc2smReader(cloud).getAsSM();
120  FROM_PCL_CLOUD(*sm_cloud, *cloudWithNormals);
121  CVLog::Print(
122  tr("[MarchingCubeReconstruction::compute] find normals and use "
123  "the normals"));
124  }
125 
126  // Marching Cube
127  PCLMesh mesh;
128  PCLModules::MarchingMethod marchingMethod =
129  (PCLModules::MarchingMethod)m_marchingMethod;
130  if (!PCLModules::GetMarchingCubes<PointNT>(
131  cloudWithNormals, marchingMethod, mesh, m_epsilon, m_isoLevel,
133  return -1;
134  }
135 
136  PCLCloud out_cloud_sm(mesh.cloud);
137  if (out_cloud_sm.height * out_cloud_sm.width == 0) {
138  // cloud is empty
139  return -53;
140  }
141 
142  ccMesh* out_mesh = pcl2cc::Convert(out_cloud_sm, mesh.polygons);
143  if (!out_mesh) {
144  // conversion failed (not enough memory?)
145  return -1;
146  }
147 
148  unsigned vertCount = out_mesh->getAssociatedCloud()->size();
149  unsigned faceCount = out_mesh->size();
150  CVLog::Print(tr("[MarchingCube-Reconstruction] %1 points, %2 face(s)")
151  .arg(vertCount)
152  .arg(faceCount));
153 
154  out_mesh->setName(tr("Marching Cube"));
155  // copy global shift & scale
156  out_mesh->getAssociatedCloud()->setGlobalScale(cloud->getGlobalScale());
157  out_mesh->getAssociatedCloud()->setGlobalShift(cloud->getGlobalShift());
158 
159  if (cloud->getParent()) cloud->getParent()->addChild(out_mesh);
160 
161  emit newEntity(out_mesh);
162 
163  return 1;
164 }
165 
167  switch (errorCode) {
168  // THESE CASES CAN BE USED TO OVERRIDE OR ADD FILTER-SPECIFIC ERRORS
169  // CODES ALSO IN DERIVED CLASSES DEFULAT MUST BE ""
170 
171  case -51:
172  return tr(
173  "Selected entity does not have any suitable scalar field "
174  "or RGB.");
175  case -52:
176  return tr(
177  "Wrong Parameters. One or more parameters cannot be "
178  "accepted");
179  case -53:
180  return tr(
181  "Marching Cube Reconstruction does not returned any point. "
182  "Try relaxing your parameters");
183  default:
184  break;
185  }
186 
187  return BasePclModule::getErrorMessage(errorCode);
188 }
core::Tensor result
Definition: VtkUtils.cpp:76
Base abstract class for each implemented PCL filter.
Definition: BasePclModule.h:53
int isFirstSelectedCcPointCloud()
Returns 1 if the first selected object is a ccPointCloud.
void newEntity(ccHObject *)
Signal emitted when a new entity is created by the filter.
ecvMainAppInterface * m_app
Associated application interface.
virtual QString getErrorMessage(int errorCode)
Returns the error message corresponding to a given error code.
ccPointCloud * getSelectedEntityAsCCPointCloud() const
Returns the first selected entity as a ccPointCloud.
static bool Print(const char *format,...)
Prints out a formatted message in console.
Definition: CVLog.cpp:113
virtual int compute()
Performs the actual filter job.
virtual int checkSelected()
Checks if current selection is compliant with the filter.
virtual QString getErrorMessage(int errorCode)
Returns the error message corresponding to a given error code.
virtual void getParametersFromDialog()
Collects parameters from the filter dialog (if openDialog is successful)
Bounding box structure.
Definition: ecvBBox.h:25
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.
ccHObject * getParent() const
Returns parent object.
Definition: ecvHObject.h:245
Triangular mesh.
Definition: ecvMesh.h:35
ccGenericPointCloud * getAssociatedCloud() const override
Returns the vertices cloud.
Definition: ecvMesh.h:143
virtual unsigned size() const override
Returns the number of triangles.
virtual void setName(const QString &name)
Sets object name.
Definition: ecvObject.h:75
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
bool hasNormals() const override
Returns whether normals are enabled or not.
virtual void setGlobalScale(double scale)
virtual void setGlobalShift(double x, double y, double z)
Sets shift applied to original coordinates (information storage only)
virtual const CCVector3d & getGlobalShift() const
Returns the shift applied to original coordinates.
virtual double getGlobalScale() const
Returns the scale applied to original coordinates.
T getDiagNorm() const
Returns diagonal length.
Definition: BoundingBox.h:172
bool isValid() const
Returns whether bounding box is valid or not.
Definition: BoundingBox.h:203
virtual unsigned size() const =0
Returns the number of points.
virtual QWidget * getActiveWindow()=0
double normals[3]
PCL filter description.
Definition: BasePclModule.h:26