ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvFastMarchingForNormsDirection.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 // Local
11 #include "CVLog.h"
12 #include "ecvGenericPointCloud.h"
13 #include "ecvNormalVectors.h"
14 #include "ecvOctree.h"
15 #include "ecvPointCloud.h"
16 #include "ecvProgressDialog.h"
17 #ifdef QT_DEBUG
18 #include "ecvScalarField.h"
19 #endif
20 
21 // system
22 #include <cassert>
23 
25  : cloudViewer::FastMarching() {}
26 
29  if (!subset || subset->size() == 0 || !sourceCloud)
30  return CCVector3(0, 0, 1);
31 
32  assert(sourceCloud->hasNormals());
33  assert(subset->getAssociatedCloud() ==
35 
36  // we simply take the first normal as reference (DGM: seems to work better
37  // than the LS plane!)
38  const CCVector3& N =
40 
41  // now we can compute the mean normal, using the first normal as reference
42  // for the sign
43  CCVector3 Nout(0, 0, 0);
44  unsigned n = subset->size();
45  for (unsigned i = 0; i < n; ++i) {
46  const CCVector3& Ni =
48  // compute the scalar product between the ith point normal and the
49  // robust one
50  PointCoordinateType ps = Ni.dot(N);
51  if (ps < 0)
52  Nout -= Ni;
53  else
54  Nout += Ni;
55  }
56 
57  Nout.normalize();
58 
59  return Nout;
60 }
61 
63  NormsIndexesTableType* theNorms,
64  ccOctree* theOctree,
65  unsigned char level) {
66  int result = initGridWithOctree(theOctree, level);
67  if (result < 0) return result;
68 
69  // fill the grid with the octree
71  theOctree->getCellCodes(level, cellCodes, true);
72 
74 
75  while (!cellCodes.empty()) {
76  if (!theOctree->getPointsInCell(cellCodes.back(), level, &Yk, true)) {
77  // not enough memory
78  return -1;
79  }
80 
81  // convert the octree cell code to grid position
82  Tuple3i cellPos;
83  theOctree->getCellPos(cellCodes.back(), level, cellPos, true);
84 
85  // convert it to FM cell pos index
86  unsigned gridPos = pos2index(cellPos);
87 
88  // create corresponding cell
89  DirectionCell* aCell = new DirectionCell;
90  {
91  // aCell->signConfidence = 1;
92  aCell->cellCode = cellCodes.back();
93  aCell->N = ComputeRobustAverageNorm(&Yk, cloud);
95  }
96 
97  m_theGrid[gridPos] = aCell;
98 
99  cellCodes.pop_back();
100  }
101 
102  m_initialized = true;
103 
104  return 0;
105 }
106 
108  DirectionCell* originCell, DirectionCell* destCell) const {
109  // 1) it depends on the angle between the current cell's orientation
110  // and its neighbor's orientation (symmetric)
111  // 2) it depends on whether the neighbor's relative position is
112  // compatible with the current cell orientation (symmetric)
113  CCVector3 AB = destCell->C - originCell->C;
114  AB.normalize();
115 
116  float psOri = fabs(
117  static_cast<float>(AB.dot(originCell->N))); // ideal: 90 degrees
118  float psDest =
119  fabs(static_cast<float>(AB.dot(destCell->N))); // ideal: 90 degrees
120  float oriConfidence = (psOri + psDest) / 2; // between 0 and 1 (ideal: 0)
121 
122  return 1.0f - oriConfidence;
123 }
124 
126  DirectionCell* theCell = static_cast<DirectionCell*>(m_theGrid[index]);
127  CCVector3& N = theCell->N;
128 
129  // we resolve the normal direction by looking at the (already processed)
130  // neighbors
131  bool inverseNormal = false;
132  float bestConf = 0;
133 // #define USE_BEST_NEIGHBOR_ONLY
134 #ifndef USE_BEST_NEIGHBOR_ONLY
135  unsigned nPos = 0;
136  float confPos = 0;
137  unsigned nNeg = 0;
138  float confNeg = 0;
139 #endif
140  for (unsigned i = 0; i < m_numberOfNeighbours; ++i) {
141  DirectionCell* nCell = static_cast<DirectionCell*>(
142  m_theGrid[static_cast<int>(index) + m_neighboursIndexShift[i]]);
143  if (nCell && nCell->state == DirectionCell::ACTIVE_CELL) {
144  // compute the confidence for each neighbor
145  float confidence = computePropagationConfidence(nCell, theCell);
146 #ifdef USE_BEST_NEIGHBOR_ONLY
147  if (confidence > bestConf) {
148  bestConf = confidence;
149  float ps = static_cast<float>(nCell->N.dot(N));
150  inverseNormal = (ps < 0);
151  }
152 #else
153  // voting
154  float ps = static_cast<float>(nCell->N.dot(N));
155  if (ps < 0) {
156  nNeg++;
157  confNeg += confidence;
158  } else {
159  nPos++;
160  confPos += confidence;
161  }
162 #endif
163  }
164  }
165 
166 #ifndef USE_BEST_NEIGHBOR_ONLY
167  inverseNormal = (nNeg == nPos ? confNeg > confPos : nNeg > nPos);
168  bestConf = inverseNormal ? confNeg : confPos; // DGM: absolute confidence
169  // seems to work better...
170  // bestConf = inverseNormal ? confNeg/static_cast<float>(nNeg) :
171  // confPos/static_cast<float>(nPos);
172 #endif
173  if (inverseNormal) {
174  N *= -1;
175  }
176  theCell->signConfidence = bestConf;
177  assert(theCell->signConfidence > 0);
178 }
179 
180 #ifdef QT_DEBUG
181 // for debug purposes only
182 static unsigned s_cellIndex = 0;
183 #endif
185  if (!m_initialized) return -1;
186 
187  // get 'earliest' cell
188  unsigned minTCellIndex = getNearestTrialCell();
189  if (minTCellIndex == 0) return 0;
190 
191  cloudViewer::FastMarching::Cell* minTCell = m_theGrid[minTCellIndex];
192  assert(minTCell && minTCell->state != DirectionCell::ACTIVE_CELL);
193 
194  if (minTCell->T < Cell::T_INF()) {
195 #ifdef QT_DEBUG
196  if (s_cellIndex == 0) {
197  // process seed cells first!
198  for (size_t i = 0; i < m_activeCells.size(); ++i)
199  static_cast<DirectionCell*>(m_theGrid[m_activeCells[i]])
200  ->scalar = static_cast<float>(0);
201  s_cellIndex++;
202  }
203  static_cast<DirectionCell*>(minTCell)->scalar =
204  static_cast<float>(s_cellIndex++);
205 #endif
206 
207  // resolve the cell orientation
208  resolveCellOrientation(minTCellIndex);
209  // we add this cell to the "ACTIVE" set
210  addActiveCell(minTCellIndex);
211 
212  // add its neighbors to the TRIAL set
213  for (unsigned i = 0; i < m_numberOfNeighbours; ++i) {
214  // get neighbor cell
215  unsigned nIndex = minTCellIndex + m_neighboursIndexShift[i];
217  if (nCell) {
218  // if it' not yet a TRIAL cell
219  if (nCell->state == DirectionCell::FAR_CELL) {
220  nCell->T = computeT(nIndex);
221  addTrialCell(nIndex);
222  }
223  // otherwise we must update it's arrival time
224  else if (nCell->state == DirectionCell::TRIAL_CELL) {
225  const float& t_old = nCell->T;
226  float t_new = computeT(nIndex);
227 
228  if (t_new < t_old) nCell->T = t_new;
229  }
230  }
231  }
232  } else {
233  addIgnoredCell(minTCellIndex);
234  }
235 
236  return 1;
237 }
238 
241  cloudViewer::FastMarching::Cell* destCell) const {
242  DirectionCell* oCell = static_cast<DirectionCell*>(originCell);
243  DirectionCell* dCell = static_cast<DirectionCell*>(destCell);
244  float orientationConfidence = computePropagationConfidence(
245  oCell, dCell); // between 0 and 1 (ideal: 1)
246 
247  return (1.0f - orientationConfidence) * oCell->signConfidence;
248 }
249 
251  // init "TRIAL" set with seed's neighbors
252  initTrialCells();
253 
254  int result = 1;
255  while (result > 0) {
256  result = step();
257  }
258 
259  return result;
260 }
261 
263  ccGenericPointCloud* cloud,
264  std::vector<unsigned char>& resolved,
265  NormsIndexesTableType* theNorms) {
266  if (!m_initialized || !m_octree ||
268  return 0;
269 
271 
272  unsigned count = 0;
273  for (unsigned int cell : m_activeCells) {
274  DirectionCell* aCell = static_cast<DirectionCell*>(m_theGrid[cell]);
275  if (!m_octree->getPointsInCell(aCell->cellCode, m_gridLevel, &Yk,
276  true)) {
277  // not enough memory
278  return 0;
279  }
280 
281  for (unsigned k = 0; k < Yk.size(); ++k) {
282  unsigned index = Yk.getPointGlobalIndex(k);
283  resolved[index] = 1;
284 
285  const CompressedNormType& norm = theNorms->getValue(index);
286  const CCVector3& N = ccNormalVectors::GetNormal(norm);
287 
288  // inverse point normal if necessary
289  if (N.dot(aCell->N) < 0) {
290  theNorms->setValue(index, ccNormalVectors::GetNormIndex(-N));
291  }
292 
293 #ifdef QT_DEBUG
294  cloud->setPointScalarValue(index, aCell->T);
295  // cloud->setPointScalarValue(index,aCell->signConfidence);
296  // cloud->setPointScalarValue(index,aCell->scalar);
297 #endif
298 
299  ++count;
300  }
301  }
302 
303  return count;
304 }
305 
307  // we expect at most one 'ACTIVE' cell (i.e. the current seed)
308  size_t seedCount = m_activeCells.size();
309  assert(seedCount <= 1);
310 
311  if (seedCount == 1) {
312  unsigned index = m_activeCells.front();
313  DirectionCell* seedCell = static_cast<DirectionCell*>(m_theGrid[index]);
314 
315  assert(seedCell != nullptr);
316  assert(seedCell->T == 0);
317  assert(seedCell->signConfidence == 1);
318 
319  // add all its neighbour cells to the TRIAL set
320  for (unsigned i = 0; i < m_numberOfNeighbours; ++i) {
321  unsigned nIndex = index + m_neighboursIndexShift[i];
322  DirectionCell* nCell =
323  static_cast<DirectionCell*>(m_theGrid[nIndex]);
324  // if the neighbor exists (it shouldn't be in the TRIAL or ACTIVE
325  // sets)
326  if (nCell /* && nCell->state == DirectionCell::FAR_CELL*/) {
327  assert(nCell->state == DirectionCell::FAR_CELL);
328  addTrialCell(nIndex);
329 
330  // compute its approximate arrival time
331  nCell->T = seedCell->T +
333  computeTCoefApprox(seedCell, nCell);
334  }
335  }
336  }
337 }
338 
340  ccPointCloud* cloud,
341  unsigned char octreeLevel,
342  ecvProgressDialog* progressCb) {
343  if (!cloud || !cloud->normals()) {
344  const QString name((cloud == nullptr) ? QStringLiteral("[unnamed]")
345  : cloud->getName());
346 
347  CVLog::Warning(QString("[orientNormalsWithFM] Cloud '%1' is invalid "
348  "(or cloud has no normals)")
349  .arg(name));
350  assert(false);
351  return 0;
352  }
353  NormsIndexesTableType* theNorms = cloud->normals();
354 
355  unsigned numberOfPoints = cloud->size();
356  if (numberOfPoints == 0) return -1;
357 
358  // we need the octree
359  if (!cloud->getOctree()) {
360  if (!cloud->computeOctree(progressCb)) {
361  CVLog::Warning(QString("[orientNormalsWithFM] Could not compute "
362  "octree on cloud '%1'")
363  .arg(cloud->getName()));
364  return 0;
365  }
366  }
367  ccOctree::Shared octree = cloud->getOctree();
368  assert(octree);
369 
370  // temporary SF
371 #ifndef QT_DEBUG
372  bool sfWasDisplayed = cloud->sfShown();
373 #endif
374  int oldSfIdx = cloud->getCurrentDisplayedScalarFieldIndex();
375  int sfIdx = cloud->getScalarFieldIndexByName("FM_Propagation");
376  if (sfIdx < 0) sfIdx = cloud->addScalarField("FM_Propagation");
377  if (sfIdx >= 0) {
378  cloud->setCurrentScalarField(sfIdx);
379  } else {
381  "[orientNormalsWithFM] Couldn't create temporary scalar field! "
382  "Not enough memory?");
383  return -3;
384  }
385 
386  if (!cloud->enableScalarField()) {
388  "[orientNormalsWithFM] Couldn't enable temporary scalar field! "
389  "Not enough memory?");
390  cloud->deleteScalarField(sfIdx);
391  cloud->setCurrentScalarField(oldSfIdx);
392  return -4;
393  }
394 
395  // flags indicating if each point has been processed or not
396  std::vector<unsigned char> resolved;
397  try {
398  resolved.resize(numberOfPoints, 0);
399  } catch (const std::bad_alloc&) {
400  CVLog::Warning("[orientNormalsWithFM] Not enough memory!");
401  cloud->deleteScalarField(sfIdx);
402  cloud->setCurrentScalarField(oldSfIdx);
403  return -5;
404  }
405 
406  // Fast Marching propagation
408 
409  int result = fm.init(cloud, theNorms, octree.data(), octreeLevel);
410  if (result < 0) {
411  CVLog::Error(
412  "[orientNormalsWithFM] Something went wrong during "
413  "initialization...");
414  cloud->deleteScalarField(sfIdx);
415  cloud->setCurrentScalarField(oldSfIdx);
416  return -6;
417  }
418 
419  // progress notification
420  if (progressCb) {
421  if (progressCb->textCanBeEdited()) {
422  progressCb->setMethodTitle("Norms direction");
423  progressCb->setInfo(
424  qPrintable(QString("Octree level: %1\nPoints: %2")
425  .arg(octreeLevel)
426  .arg(numberOfPoints)));
427  }
428  progressCb->update(0);
429  progressCb->start();
430  }
431 
432  const int octreeWidth = (1 << octreeLevel) - 1;
433 
434  // enable 26-connectivity
435  // fm.setExtendedConnectivity(true);
436 
437  // while non-processed points remain...
438  unsigned resolvedPoints = 0;
439  int lastProcessedPoint = -1;
440  bool success = true;
441  while (success) {
442  // find the next non-processed point
443  do {
444  ++lastProcessedPoint;
445  } while (lastProcessedPoint < static_cast<int>(numberOfPoints) &&
446  resolved[lastProcessedPoint] != 0);
447 
448  // all points have been processed? Then we can stop.
449  if (lastProcessedPoint == static_cast<int>(numberOfPoints)) break;
450 
451  // we start the propagation from this point
452  // its corresponding cell in fact ;)
453  const CCVector3* thePoint = cloud->getPoint(lastProcessedPoint);
454  Tuple3i cellPos;
455  octree->getTheCellPosWhichIncludesThePoint(thePoint, cellPos,
456  octreeLevel);
457 
458  // clipping (in case the octree is not 'complete')
459  cellPos.x = std::min(octreeWidth, cellPos.x);
460  cellPos.y = std::min(octreeWidth, cellPos.y);
461  cellPos.z = std::min(octreeWidth, cellPos.z);
462 
463  // set corresponding FM cell as 'seed'
464  fm.setSeedCell(cellPos);
465 
466  // launch propagation
467  int propagationResult = fm.propagate();
468 
469  // if it's a success
470  if (propagationResult >= 0) {
471  // compute the number of points processed during this pass
472  unsigned count = fm.updateResolvedTable(cloud, resolved, theNorms);
473 
474  if (count != 0) {
475  resolvedPoints += count;
476  if (progressCb)
477  progressCb->update(resolvedPoints /
478  (numberOfPoints * 100.0f));
479  }
480 
482  } else {
483  CVLog::Error(
484  "An error occurred during front propagation! Process "
485  "cancelled...");
486  success = false;
487  }
488  }
489 
490  if (progressCb) progressCb->stop();
491 
492  cloud->showNormals(true);
493 #ifdef QT_DEBUG
494  cloud->setCurrentDisplayedScalarField(sfIdx);
496  cloud->showSF(true);
497 #else
498  cloud->deleteScalarField(sfIdx);
499  cloud->setCurrentScalarField(oldSfIdx);
500  cloud->showSF(sfWasDisplayed);
501 #endif
502 
503  return (success ? 1 : 0);
504 }
Vector3Tpl< PointCoordinateType > CCVector3
Default 3D Vector.
Definition: CVGeom.h:798
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
std::string name
int count
core::Tensor result
Definition: VtkUtils.cpp:76
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Definition: CVLog.cpp:143
Array of compressed 3D normals (single index)
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
void normalize()
Sets vector norm to unity.
Definition: CVGeom.h:428
Type dot(const Vector3Tpl &v) const
Dot product.
Definition: CVGeom.h:408
Type & getValue(size_t index)
Definition: ecvArray.h:100
void setValue(size_t index, const Type &value)
Definition: ecvArray.h:102
virtual bool sfShown() const
Returns whether active scalar field is visible.
virtual bool hasNormals() const
Returns whether normals are enabled or not.
virtual void showNormals(bool state)
Sets normals visibility.
virtual void showSF(bool state)
Sets active scalarfield visibility.
A Fast Marching grid cell for normals direction resolution.
cloudViewer::DgmOctree::CellCode cellCode
the code of the equivalent cell in the octree
Fast Marching algorithm for normals direction resolution.
float computePropagationConfidence(DirectionCell *originCell, DirectionCell *destCell) const
Computes relative 'confidence' between two cells (orientations)
int step() override
Propagates the front (one step)
void resolveCellOrientation(unsigned index)
Resolves the direction of a given cell (once and for all)
float computeTCoefApprox(cloudViewer::FastMarching::Cell *currentCell, cloudViewer::FastMarching::Cell *neighbourCell) const override
Computes the front acceleration between two cells.
static int OrientNormals(ccPointCloud *theCloud, unsigned char octreeLevel, ecvProgressDialog *progressCb=nullptr)
Static entry point (helper)
int propagate() override
Propagates the front.
void initTrialCells() override
Initializes the TRIAL cells list.
unsigned updateResolvedTable(ccGenericPointCloud *theCloud, std::vector< unsigned char > &resolved, NormsIndexesTableType *theNorms)
Updates a list of point flags, indicating the points already processed.
int init(ccGenericPointCloud *cloud, NormsIndexesTableType *theNorms, ccOctree *theOctree, unsigned char gridLevel)
Initializes the grid with a point cloud (and ist corresponding octree)
A 3D cloud interface with associated features (color, normals, octree, etc.)
virtual const CCVector3 & getPointNormal(unsigned pointIndex) const =0
Returns normal corresponding to a given point.
virtual ccOctree::Shared computeOctree(cloudViewer::GenericProgressCallback *progressCb=nullptr, bool autoAddChild=true)
Computes the cloud octree.
virtual ccOctree::Shared getOctree() const
Returns the associated octree (if any)
static const CCVector3 & GetNormal(unsigned normIndex)
Static access to ccNormalVectors::getNormal.
static CompressedNormType GetNormIndex(const PointCoordinateType N[])
Returns the compressed index corresponding to a normal vector.
virtual QString getName() const
Returns object name.
Definition: ecvObject.h:72
Octree structure.
Definition: ecvOctree.h:27
QSharedPointer< ccOctree > Shared
Shared pointer.
Definition: ecvOctree.h:32
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void setCurrentDisplayedScalarField(int index)
Sets the currently displayed scalar field.
NormsIndexesTableType * normals() const
Returns pointer on compressed normals indexes table.
ccScalarField * getCurrentDisplayedScalarField() const
Returns the currently displayed scalar (or 0 if none)
int addScalarField(const char *uniqueName) override
Creates a new scalar field and registers it.
int getCurrentDisplayedScalarFieldIndex() const
Returns the currently displayed scalar field index (or -1 if none)
void deleteScalarField(int index) override
Deletes a specific scalar field.
void computeMinAndMax() override
Determines the min and max values.
GenericIndexedCloudPersist * associatedCloud() const
Returns the associated cloud.
Definition: DgmOctree.h:1191
void getCellPos(CellCode code, unsigned char level, Tuple3i &cellPos, bool isCodeTruncated) const
Definition: DgmOctree.cpp:498
static const int MAX_OCTREE_LEVEL
Max octree subdivision level.
Definition: DgmOctree.h:67
bool getPointsInCell(CellCode cellCode, unsigned char level, ReferenceCloud *subset, bool isCodeTruncated=false, bool clearOutputCloud=true) const
Returns the points lying in a specific cell.
Definition: DgmOctree.cpp:537
void getTheCellPosWhichIncludesThePoint(const CCVector3 *thePoint, Tuple3i &cellPos) const
Definition: DgmOctree.h:779
std::vector< CellCode > cellCodesContainer
Octree cell codes container.
Definition: DgmOctree.h:92
bool getCellCodes(unsigned char level, cellCodesContainer &vec, bool truncatedCodes=false) const
Definition: DgmOctree.cpp:2822
A generic Fast Marching grid cell.
Definition: FastMarching.h:95
static float T_INF()
Returns infinite time value.
Definition: FastMarching.h:98
float T
Front arrival time.
Definition: FastMarching.h:118
virtual void addActiveCell(unsigned index)
Add a cell to the ACTIVE cells list.
unsigned pos2index(const Tuple3i &pos) const
Definition: FastMarching.h:87
Cell ** m_theGrid
Grid used to process Fast Marching.
Definition: FastMarching.h:235
virtual float computeT(unsigned index)
Computes the front arrival time at a given cell.
DgmOctree * m_octree
Associated octree.
Definition: FastMarching.h:238
std::vector< unsigned > m_activeCells
ACTIVE cells list.
Definition: FastMarching.h:212
unsigned char m_gridLevel
Equivalent octree subdivision level.
Definition: FastMarching.h:240
bool m_initialized
Specifiies whether structure is initialized or not.
Definition: FastMarching.h:219
virtual void addTrialCell(unsigned index)
Add a cell to the TRIAL cells list.
float m_neighboursDistance[26]
Neighbours distance weight.
Definition: FastMarching.h:251
virtual int initGridWithOctree(DgmOctree *octree, unsigned char gridLevel)
virtual bool setSeedCell(const Tuple3i &pos)
Sets a given cell as "seed".
unsigned m_numberOfNeighbours
Current number of neighbours (6 or 26)
Definition: FastMarching.h:247
virtual void addIgnoredCell(unsigned index)
Add a cell to the IGNORED cells list.
virtual unsigned getNearestTrialCell()
Returns the TRIAL cell with the smallest front arrival time.
int m_neighboursIndexShift[26]
Neighbours coordinates shifts in grid.
Definition: FastMarching.h:249
virtual void cleanLastPropagation()
virtual void setPointScalarValue(unsigned pointIndex, ScalarType value)=0
Sets the ith point associated scalar value.
A generic 3D point cloud with index-based point access.
virtual bool textCanBeEdited() const
Returns whether the dialog title and info can be updated or not.
const CCVector3 * getGravityCenter()
Returns gravity center.
int getScalarFieldIndexByName(const char *name) const
Returns the index of a scalar field represented by its name.
void setCurrentScalarField(int index)
Sets both the INPUT & OUTPUT scalar field.
unsigned size() const override
Definition: PointCloudTpl.h:38
const CCVector3 * getPoint(unsigned index) const override
bool enableScalarField() override
Definition: PointCloudTpl.h:77
A very simple point cloud (no point duplication)
virtual GenericIndexedCloudPersist * getAssociatedCloud()
Returns the associated (source) cloud.
unsigned size() const override
Returns the number of points.
virtual unsigned getPointGlobalIndex(unsigned localIndex) const
Graphical progress indicator (thread-safe)
virtual void stop() override
Notifies the fact that the process has ended.
virtual void update(float percent) override
Notifies the algorithm progress.
virtual void setInfo(const char *infoStr) override
Notifies some information about the ongoing process.
virtual void start() override
virtual void setMethodTitle(const char *methodTitle) override
Notifies the algorithm title.
unsigned int CompressedNormType
Compressed normals type.
Definition: ecvBasicTypes.h:16
static CCVector3 ComputeRobustAverageNorm(cloudViewer::ReferenceCloud *subset, ccGenericPointCloud *sourceCloud)
normal_z scalar
Generic file read and write utility for python interface.
cloudViewer::DgmOctree * octree
unsigned char octreeLevel
ccGenericPointCloud * sourceCloud