ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
NurbsSurfaceReconstruction.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"
14 #include "Tools/Common/ecvTools.h" // must below above three
16 
17 // CV_DB_LIB
18 #include <ecvMesh.h>
19 #include <ecvPointCloud.h>
20 #include <ecvPolyline.h>
21 
22 // ECV_PLUGINS
23 #include <ecvMainAppInterface.h>
24 
25 // QT
26 #include <QMainWindow>
27 
28 // SYSTEM
29 #include <iostream>
30 
33  tr("Nurbs Surface Triangulation"),
34  tr("Nurbs Surface Triangulation"),
35  tr("Nurbs Surface Triangulation from clouds"),
36  ":/toolbar/PclAlgorithms/icons/bspline_surface.png")),
37  m_dialog(nullptr),
38  m_order(3),
39  m_curveResolution(4),
40  m_meshResolution(128),
41  m_refinements(4),
42  m_iterations(10),
43  m_twoDim(true),
44  m_fitBSplineCurve(true),
45  m_useVoxelGrid(false),
46  m_interiorSmoothness(0.2f),
47  m_interiorWeight(1.0f),
48  m_boundarySmoothness(0.2f),
49  m_boundaryWeight(0.0f) {}
50 
52  // we must delete parent-less dialogs ourselves!
53  if (m_dialog && m_dialog->parent() == nullptr) delete m_dialog;
54 }
55 
57  // do we have a selected cloud?
58  int have_cloud = isFirstSelectedCcPointCloud();
59  if (have_cloud != 1) return -11;
60 
61  return 1;
62 }
63 
65  // initialize the dialog object
66  if (!m_dialog)
68 
69  if (!m_dialog->exec()) return 0;
70 
71  return 1;
72 }
73 
75  if (!m_dialog) return;
76 
77  // get the parameters from the dialog
78  m_order = m_dialog->orderSpinBox->value();
79  m_iterations = m_dialog->iterationsSpinBox->value();
80  m_refinements = m_dialog->refinementsSpinBox->value();
81  m_meshResolution = m_dialog->meshResolutionSpinBox->value();
82  m_curveResolution = m_dialog->curveResolutionSpinBox->value();
83  m_twoDim = m_dialog->twoDimCheckBox->isChecked();
84  m_fitBSplineCurve = m_dialog->fitBsplineCurveCheckBox->isChecked();
85  m_useVoxelGrid = m_dialog->useVoxelGridCheckBox->isChecked();
86 
87  m_interiorWeight = static_cast<float>(m_dialog->interiorWSpinBox->value());
89  static_cast<float>(m_dialog->interiorSSpinBox->value());
90  m_boundaryWeight = static_cast<float>(m_dialog->boundaryWSpinBox->value());
92  static_cast<float>(m_dialog->boundarySSpinBox->value());
93 }
94 
96 
99  if (!cloud) return -1;
100 
101  // get xyz as pcl point cloud
102  pcl::PointCloud<pcl::PointXYZ>::Ptr xyzCloud = cc2smReader(cloud).getXYZ2();
103  if (!xyzCloud) return -1;
104 
105  // 2. voxel grid filter
106  if (m_useVoxelGrid) {
107  double leafSize =
108  3 * PCLModules::ComputeCloudResolution<PointT>(xyzCloud);
109  if (leafSize > 0) {
110  PointCloudT::Ptr tempCloud(new PointCloudT);
111  if (!PCLModules::VoxelGridFilter<PointT>(
112  xyzCloud, tempCloud, leafSize, leafSize, leafSize)) {
113  return -1;
114  }
115  xyzCloud = tempCloud;
116  }
117  }
118 
119  // reconstruction
120  PCLMesh mesh;
121  PointCloudRGB::Ptr outCurve(new PointCloudRGB);
122 #if defined(WITH_PCL_NURBS)
123  // init parameters
124  PCLModules::NurbsParameters nurbsParams;
125  {
126  nurbsParams.fittingParams_.interior_smoothness = m_interiorSmoothness;
127  nurbsParams.fittingParams_.interior_weight = m_interiorWeight;
128  nurbsParams.fittingParams_.boundary_smoothness = m_boundarySmoothness;
129  nurbsParams.fittingParams_.boundary_weight = m_boundaryWeight;
130 
131  nurbsParams.order_ = m_order;
132  nurbsParams.meshResolution_ = m_meshResolution;
133  nurbsParams.curveResolution_ = m_curveResolution;
134  nurbsParams.refinements_ = m_refinements;
135  nurbsParams.iterations_ = m_iterations;
136  nurbsParams.twoDim_ = m_twoDim;
137  }
138 
139  if (m_fitBSplineCurve) {
140  if (!PCLModules::NurbsSurfaceFitting<PointT>(xyzCloud, nurbsParams,
141  mesh, outCurve)) {
142  return -1;
143  }
144  } else {
145  if (!PCLModules::NurbsSurfaceFitting<PointT>(xyzCloud, nurbsParams,
146  mesh, nullptr)) {
147  return -1;
148  }
149  }
150 #else
151  CVLog::Print(tr(
152  "[NurbsSurfaceReconstruction] PCL not supported with nurbs, please "
153  "rebuild pcl with -DBUILD_surface_on_nurbs=ON again"));
154  return -1;
155 #endif
156 
157  // convert output curve to polyline
158  ccPolyline* curvePoly = nullptr;
159  if (m_fitBSplineCurve && outCurve->points.size() > 1) {
160  PCLCloud::Ptr curve_sm(new PCLCloud);
161  TO_PCL_CLOUD(*outCurve, *curve_sm);
162  curvePoly = ecvTools::GetPolylines(curve_sm, "nurbs-curve", true);
163  }
164 
165  PCLCloud out_cloud_sm(mesh.cloud);
166  if (out_cloud_sm.height * out_cloud_sm.width == 0) {
167  // cloud is empty
168  return -53;
169  }
170 
171  ccMesh* out_mesh = pcl2cc::Convert(out_cloud_sm, mesh.polygons);
172  if (!out_mesh) {
173  // conversion failed (not enough memory?)
174  return -1;
175  }
176 
177  unsigned vertCount = out_mesh->getAssociatedCloud()->size();
178  unsigned faceCount = out_mesh->size();
179  CVLog::Print(tr("[NurbsSurfaceReconstruction] %1 points, %2 face(s)")
180  .arg(vertCount)
181  .arg(faceCount));
182 
183  out_mesh->setName(tr("nurbs-surface-%1").arg(m_order));
184  // copy global shift & scale
185  out_mesh->getAssociatedCloud()->setGlobalScale(cloud->getGlobalScale());
186  out_mesh->getAssociatedCloud()->setGlobalShift(cloud->getGlobalShift());
187 
188  if (cloud->getParent()) cloud->getParent()->addChild(out_mesh);
189 
190  if (curvePoly) {
191  if (cloud->getParent()) cloud->getParent()->addChild(curvePoly);
192  emit newEntity(curvePoly);
193  }
194 
195  emit newEntity(out_mesh);
196 
197  return 1;
198 }
199 
201  switch (errorCode) {
202  // THESE CASES CAN BE USED TO OVERRIDE OR ADD FILTER-SPECIFIC ERRORS
203  // CODES ALSO IN DERIVED CLASSES DEFULAT MUST BE ""
204 
205  case -51:
206  return tr(
207  "Selected entity does not have any suitable scalar field "
208  "or RGB.");
209  case -52:
210  return tr(
211  "Wrong Parameters. One or more parameters cannot be "
212  "accepted");
213  case -53:
214  return tr(
215  "Nurbs Surface Triangulation does not returned any point. "
216  "Try relaxing your parameters");
217  default:
218  break;
219  }
220 
221  return BasePclModule::getErrorMessage(errorCode);
222 }
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 void getParametersFromDialog()
Collects parameters from the filter dialog (if openDialog is successful)
virtual QString getErrorMessage(int errorCode)
Returns the error message corresponding to a given error code.
virtual int compute()
Performs the actual filter job.
virtual int checkSelected()
Checks if current selection is compliant with the filter.
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.)
Colored polyline.
Definition: ecvPolyline.h:24
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.
virtual unsigned size() const =0
Returns the number of points.
virtual QWidget * getActiveWindow()=0
PCL filter description.
Definition: BasePclModule.h:26