ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvGenericPointCloud.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 #ifdef USE_TBB
9 #include <tbb/parallel_for.h>
10 #endif
11 
12 #include "ecvGenericPointCloud.h"
13 
14 // cloudViewer
17 #include <Neighbourhood.h>
18 #include <ReferenceCloud.h>
19 
20 // Local
21 #include "ecvDisplayTools.h"
22 #include "ecvOctreeProxy.h"
23 #include "ecvPointCloud.h"
24 #include "ecvProgressDialog.h"
25 #include "ecvScalarField.h"
26 #include "ecvSensor.h"
27 
29  : ccShiftedObject(name), m_pointSize(0) {
30  setVisible(true);
31  lockVisibility(false);
32 }
33 
35  : ccShiftedObject(cloud),
36  m_pointsVisibility(cloud.m_pointsVisibility),
37  m_pointSize(cloud.m_pointSize) {}
38 
40 
43  deleteOctree();
44  enableTempColor(false);
45 }
46 
48  try {
49  m_pointsVisibility.resize(size());
50  } catch (const std::bad_alloc&) {
52  return false;
53  }
54 
55  std::fill(m_pointsVisibility.begin(), m_pointsVisibility.end(),
56  POINT_VISIBLE); // by default, all points are visible
57 
58  return true;
59 }
60 
62  if (m_pointsVisibility.empty()) {
63  assert(false);
64  return;
65  }
66 
67  for (unsigned char& vis : m_pointsVisibility) {
68  vis = (vis == POINT_HIDDEN ? POINT_VISIBLE : POINT_HIDDEN);
69  }
70 }
71 
73  m_pointsVisibility.resize(0);
74 }
75 
77  return !m_pointsVisibility.empty();
78 }
79 
82  if (oct != nullptr) {
83  removeChild(oct);
84  }
85 }
86 
88  for (auto child : m_children) {
89  if (child->isA(CV_TYPES::POINT_OCTREE)) {
90  return static_cast<ccOctreeProxy*>(child);
91  }
92  }
93 
94  return nullptr;
95 }
96 
98  ccOctreeProxy* proxy = getOctreeProxy();
99  if (proxy != nullptr) {
100  return proxy->getOctree();
101  } else {
102  return ccOctree::Shared(nullptr);
103  }
104 }
105 
107  bool autoAddChild /*=true*/) {
108  if (!octree || octree->getNumberOfProjectedPoints() == 0) {
109  assert(false);
110  return;
111  }
112 
113  deleteOctree();
114 
115  ccOctreeProxy* proxy = new ccOctreeProxy(octree);
116  // proxy->setDisplay(getDisplay());
117  proxy->setVisible(true);
118  proxy->setEnabled(false);
119  if (autoAddChild) {
120  addChild(proxy);
121  }
122 }
123 
126  bool autoAddChild /*=true*/) {
127  deleteOctree();
128 
130  if (octree->build(progressCb) > 0) {
131  setOctree(octree, autoAddChild);
132  } else {
133  octree.clear();
134  }
135 
136  return octree;
137 }
138 
139 ccBBox ccGenericPointCloud::getOwnBB(bool withGLFeatures /*=false*/) {
140  ccBBox box;
141 
142  if (size()) {
143  getBoundingBox(box.minCorner(), box.maxCorner());
144  box.setValidity(true);
145  }
146 
147  return box;
148 }
149 
150 bool ccGenericPointCloud::toFile_MeOnly(QFile& out, short dataVersion) const {
151  assert(out.isOpen() && (out.openMode() & QIODevice::WriteOnly));
152  if (dataVersion < 33) {
153  assert(false);
154  return false;
155  }
156 
157  if (!ccHObject::toFile_MeOnly(out, dataVersion)) return false;
158 
159  //'global shift & scale' (dataVersion>=39)
160  saveShiftInfoToFile(out);
161 
162  //'visibility' array (dataVersion>=20)
163  bool hasVisibilityArray = isVisibilityTableInstantiated();
164  if (out.write((const char*)&hasVisibilityArray, sizeof(bool)) < 0)
165  return WriteError();
166  if (hasVisibilityArray) {
167  if (!ccSerializationHelper::GenericArrayToFile<unsigned char, 1,
168  unsigned char>(
169  m_pointsVisibility, out))
170  return false;
171  }
172 
173  //'point size' (dataVersion>=24)
174  if (out.write((const char*)&m_pointSize, 1) < 0) return WriteError();
175 
176  return true;
177 }
178 
180  return std::max(static_cast<short>(33),
182 }
183 
185  short dataVersion,
186  int flags,
187  LoadedIDMap& oldToNewIDMap) {
188  if (!ccHObject::fromFile_MeOnly(in, dataVersion, flags, oldToNewIDMap))
189  return false;
190 
191  if (dataVersion < 20) return CorruptError();
192 
193  if (dataVersion < 33) {
194  //'coordinates shift' (dataVersion>=20)
195  if (in.read((char*)m_globalShift.u, sizeof(double) * 3) < 0)
196  return ReadError();
197 
198  m_globalScale = 1.0;
199  } else {
200  //'global shift & scale' (dataVersion>=33)
201  if (!loadShiftInfoFromFile(in)) return ReadError();
202  }
203 
204  //'visibility' array (dataVersion>=20)
205  bool hasVisibilityArray = false;
206  if (in.read((char*)&hasVisibilityArray, sizeof(bool)) < 0)
207  return ReadError();
208  if (hasVisibilityArray) {
209  if (!ccSerializationHelper::GenericArrayFromFile<unsigned char, 1,
210  unsigned char>(
211  m_pointsVisibility, in, dataVersion, "visibility array")) {
213  return false;
214  }
215  }
216 
217  //'point size' (dataVersion>=24)
218  m_pointSize = 0;
219  if (dataVersion >= 24) {
220  if (in.read((char*)&m_pointSize, 1) < 0) {
221  return ReadError();
222  }
223  }
224 
225  return true;
226 }
227 
229  const ccGenericPointCloud* cloud) {
230  if (!cloud) {
231  assert(false);
232  return;
233  }
234 
235  // original center
236  setGlobalShift(cloud->getGlobalShift());
237  setGlobalScale(cloud->getGlobalScale());
238  // keep the transformation history!
240  // custom point size
241  setPointSize(cloud->getPointSize());
242  // meta-data
243  setMetaData(cloud->metaData());
244 }
245 
246 #ifdef QT_DEBUG
247 // for tests
248 #include <ScalarField.h>
249 
250 #include "ecvPointCloud.h"
251 #endif
252 
254  const ccGLCameraParameters& camera,
255  int& nearestPointIndex,
256  double& nearestSquareDist,
257  double pickWidth /*=2.0*/,
258  double pickHeight /*=2.0*/,
259  bool autoComputeOctree /*=false*/) {
260  // can we use the octree to accelerate the point picking process?
261  if (pickWidth == pickHeight) {
263  if (!octree && autoComputeOctree) {
264  ecvProgressDialog pDlg(false,
267  : nullptr);
268  octree = computeOctree(&pDlg);
269  }
270 
271  if (octree) {
272  // we can now use the octree to do faster point picking
273 #ifdef QT_DEBUG
274  cloudViewer::ScalarField* sf = nullptr;
276  ccPointCloud* pc = static_cast<ccPointCloud*>(this);
277  int sfIdx = pc->getScalarFieldIndexByName("octree_picking");
278  if (sfIdx < 0) {
279  sfIdx = pc->addScalarField("octree_picking");
280  }
281  if (sfIdx >= 0) {
282  pc->setCurrentScalarField(sfIdx);
284  pc->showSF(true);
285  sf = pc->getScalarField(sfIdx);
286  }
287  }
288 #endif
290  if (octree->pointPicking(clickPos, camera, point, pickWidth)) {
291 #ifdef QT_DEBUG
292  if (sf) {
293  sf->computeMinAndMax();
294  // if (ecvDisplayTools::GetCurrentScreen())
295  // ecvDisplayTools::RedrawDisplay();
296  }
297 #endif
298  if (point.point) {
299  nearestPointIndex = point.pointIndex;
300  nearestSquareDist = point.squareDistd;
301  return true;
302  } else {
303  // nothing found
304  return false;
305  }
306  } else {
308  "[Point picking] Failed to use the octree. We'll fall "
309  "back to the slow process...");
310  }
311  }
312  }
313 
314  // otherwise we go 'brute force' (works quite well in fact?!)
315  nearestPointIndex = -1;
316  nearestSquareDist = -1.0;
317  {
318  // back project the clicked point in 3D
319  CCVector3d clickPosd(clickPos.x, clickPos.y, 0);
320  CCVector3d X(0, 0, 0);
321  if (!camera.unproject(clickPosd, X)) {
322  return false;
323  }
324 
325  // warning: we have to handle the relative GL transformation!
326  ccGLMatrix trans;
327  bool noGLTrans = !getAbsoluteGLTransformation(trans);
328 
329  // visibility table (if any)
332  : nullptr;
333 
334  // scalar field with hidden values (if any)
335  ccScalarField* activeSF = nullptr;
336  if (sfShown() && isA(CV_TYPES::POINT_CLOUD) &&
337  !visTable // if the visibility table is instantiated, we always
338  // display ALL points
339  ) {
340  ccPointCloud* pc = static_cast<ccPointCloud*>(this);
342  if (sf && sf->mayHaveHiddenValues() && sf->getColorScale()) {
343  // we must take this SF display parameters into account as some
344  // points may be hidden!
345  activeSF = sf;
346  }
347  }
348 
349 #ifdef USE_TBB
350  tbb::parallel_for(
351  0, static_cast<int>(size()),
352  [&](int i)
353 #else
354 #if defined(_OPENMP)
355 #pragma omp parallel for
356 #endif
357  for (int i = 0; i < static_cast<int>(size()); ++i)
358 #endif
359  {
360  // we shouldn't test points that are actually hidden!
361  if ((!visTable || visTable->at(i) == POINT_VISIBLE) &&
362  (!activeSF ||
363  activeSF->getColor(activeSF->getValue(i)))) {
364  const CCVector3* P = getPoint(i);
365 
366  CCVector3d Q2D;
367  if (noGLTrans) {
368  camera.project(*P, Q2D);
369  } else {
370  CCVector3 P3D = *P;
371  trans.apply(P3D);
372  camera.project(P3D, Q2D);
373  }
374 
375  if (fabs(Q2D.x - clickPos.x) <= pickWidth &&
376  fabs(Q2D.y - clickPos.y) <= pickHeight) {
377  const double squareDist =
378  CCVector3d(X.x - P->x, X.y - P->y,
379  X.z - P->z)
380  .norm2d();
381  if (nearestPointIndex < 0 ||
382  squareDist < nearestSquareDist) {
383  nearestSquareDist = squareDist;
384  nearestPointIndex = i;
385  }
386  }
387  }
388  }
389 #ifdef USE_TBB
390  );
391 #endif
392  }
393 
394  return (nearestPointIndex >= 0);
395 }
396 
397 std::tuple<Eigen::Vector3d, Eigen::Matrix3d>
399  CCVector3 gc =
401  cloudViewer::SquareMatrixd covaMatrix =
403  this, gc.u);
404  Eigen::Matrix3d cov;
405  covaMatrix.toArray(cov.data());
406  return std::make_tuple(CCVector3d::fromArray(gc), cov);
407 }
408 
410  CCVector3 gc =
413  gc.u);
414 }
415 
417  const VisibilityTableType* visTable /*=nullptr*/,
418  bool silent /*=false*/,
419  cloudViewer::ReferenceCloud* selection /*=nullptr*/) const {
420  if (!visTable) {
421  visTable = &m_pointsVisibility;
422  }
423 
424  unsigned count = size();
425  if (!visTable || visTable->size() != count) {
426  assert(false);
428  "[ccGenericPointCloud::getTheVisiblePoints] Invalid visibility "
429  "table!");
430  return nullptr;
431  }
432 
433  // count the number of points to copy
434  unsigned pointCount = 0;
435  {
436  for (unsigned i = 0; i < count; ++i) {
437  if (visTable->at(i) == POINT_VISIBLE) {
438  ++pointCount;
439  }
440  }
441  }
442 
443  // we create an entity with the 'visible' vertices only
444  cloudViewer::ReferenceCloud* rc = nullptr;
445  if (selection) {
446  assert(selection->getAssociatedCloud() == this &&
447  selection->size() == 0);
448  rc = selection;
449  rc->clear();
450  } else {
452  const_cast<ccGenericPointCloud*>(this));
453  }
454 
455  if (pointCount) {
456  if (rc->reserve(pointCount)) {
457  for (unsigned i = 0; i < count; ++i) {
458  if (visTable->at(i) == POINT_VISIBLE) {
459  rc->addPointIndex(i); // can't fail (see above)
460  }
461  }
462  } else {
464  "[ccGenericPointCloud::getTheVisiblePoints] Not enough "
465  "memory!");
466  delete rc;
467  rc = nullptr;
468  }
469  } else if (!silent) {
471  "[ccGenericPointCloud::getTheVisiblePoints] No point in "
472  "selection");
473  }
474 
475  return rc;
476 }
constexpr unsigned char POINT_VISIBLE
Definition: CVConst.h:92
constexpr unsigned char POINT_HIDDEN
Definition: CVConst.h:94
Vector3Tpl< double > CCVector3d
Double 3D Vector.
Definition: CVGeom.h:804
std::string name
int count
void * X
Definition: SmallVector.cpp:45
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
Type y
Definition: CVGeom.h:137
Type u[3]
Definition: CVGeom.h:139
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:36
Type y
Definition: CVGeom.h:36
double norm2d() const
Returns vector square norm (forces double precision output)
Definition: CVGeom.h:419
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
Definition: CVGeom.h:268
Bounding box structure.
Definition: ecvBBox.h:25
virtual void lockVisibility(bool state)
Locks/unlocks visibility.
virtual void setVisible(bool state)
Sets entity visibility.
virtual bool sfShown() const
Returns whether active scalar field is visible.
virtual void enableTempColor(bool state)
Set temporary color activation state.
virtual void showSF(bool state)
Sets active scalarfield visibility.
void apply(float vec[3]) const
Applies transformation to a 3D vector (in place) - float version.
Float version of ccGLMatrixTpl.
Definition: ecvGLMatrix.h:19
A 3D cloud interface with associated features (color, normals, octree, etc.)
virtual void invertVisibilityArray()
Inverts the visibility array.
ccGenericPointCloud(QString name=QString())
Default constructor.
virtual void deleteOctree()
Erases the octree.
bool fromFile_MeOnly(QFile &in, short dataVersion, int flags, LoadedIDMap &oldToNewIDMap) override
Loads own object data.
VisibilityTableType m_pointsVisibility
Per-point visibility table.
unsigned char getPointSize() const
Returns current point size.
virtual ccOctree::Shared computeOctree(cloudViewer::GenericProgressCallback *progressCb=nullptr, bool autoAddChild=true)
Computes the cloud octree.
virtual cloudViewer::ReferenceCloud * getTheVisiblePoints(const VisibilityTableType *visTable=nullptr, bool silent=false, cloudViewer::ReferenceCloud *selection=nullptr) const
Returns a ReferenceCloud equivalent to the visibility array.
unsigned char m_pointSize
Point size (won't be applied if 0)
virtual ccOctreeProxy * getOctreeProxy() const
Returns the associated octree proxy (if any)
virtual bool isVisibilityTableInstantiated() const
Returns whether the visibility array is allocated or not.
short minimumFileVersion_MeOnly() const override
void setPointSize(unsigned size=0)
Sets point size.
virtual void clear()
Clears the entity from all its points and features.
bool toFile_MeOnly(QFile &out, short dataVersion) const override
Save own object data.
~ccGenericPointCloud() override
Default destructor.
virtual void setOctree(ccOctree::Shared octree, bool autoAddChild=true)
Sets the associated octree.
virtual ccOctree::Shared getOctree() const
Returns the associated octree (if any)
virtual VisibilityTableType & getTheVisibilityArray()
Returns associated visibility array.
bool pointPicking(const CCVector2d &clickPos, const ccGLCameraParameters &camera, int &nearestPointIndex, double &nearestSquareDist, double pickWidth=2.0, double pickHeight=2.0, bool autoComputeOctree=false)
Point picking (brute force or octree-driven)
ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
virtual bool resetVisibilityArray()
Resets the associated visibility array.
std::tuple< Eigen::Vector3d, Eigen::Matrix3d > computeMeanAndCovariance() const
std::vector< unsigned char > VisibilityTableType
Array of "visibility" information for each point.
void importParametersFrom(const ccGenericPointCloud *cloud)
Imports the parameters from another cloud.
cloudViewer::SquareMatrixd computeCovariance() const
virtual void unallocateVisibilityArray()
Erases the points visibility information.
virtual const ccGLMatrix & getGLTransformationHistory() const
Returns the transformation 'history' matrix.
Definition: ecvHObject.h:631
bool getAbsoluteGLTransformation(ccGLMatrix &trans) const
Definition: ecvHObject.cpp:740
virtual short minimumFileVersion_MeOnly() const
virtual bool fromFile_MeOnly(QFile &in, short dataVersion, int flags, LoadedIDMap &oldToNewIDMap)
Loads own object data.
virtual bool toFile_MeOnly(QFile &out, short dataVersion) const
Save own object data.
virtual void setGLTransformationHistory(const ccGLMatrix &mat)
Sets the transformation 'history' matrix (handle with care!)
Definition: ecvHObject.h:635
void removeChild(ccHObject *child)
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
Definition: ecvHObject.cpp:534
Container m_children
Children.
Definition: ecvHObject.h:712
CV_CLASS_ENUM getClassID() const override
Returns class ID.
Definition: ecvHObject.h:232
const QVariantMap & metaData() const
Returns meta-data map (const only)
Definition: ecvObject.h:184
void setMetaData(const QString &key, const QVariant &data)
Sets a meta-data element.
Definition: ecvObject.cpp:216
bool isA(CV_CLASS_ENUM type) const
Definition: ecvObject.h:131
virtual void setEnabled(bool state)
Sets the "enabled" property.
Definition: ecvObject.h:102
Octree structure proxy.
ccOctree::Shared getOctree() const
Returns the associated octree.
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.
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.
A scalar field associated to display-related parameters.
const ccColorScale::Shared & getColorScale() const
Returns associated color scale.
const ecvColor::Rgb * getColor(ScalarType value) const
bool mayHaveHiddenValues() const
static bool CorruptError()
Sends a custom error message (corrupted file) and returns 'false'.
QMultiMap< unsigned, unsigned > LoadedIDMap
Map of loaded unique IDs (old ID --> new ID)
static bool ReadError()
Sends a custom error message (read error) and returns 'false'.
static bool WriteError()
Sends a custom error message (write error) and returns 'false'.
static bool GenericArrayFromFile(std::vector< Type > &data, QFile &in, short dataVersion, const QString &verboseDescription)
Helper: loads a vector structure from file.
static bool GenericArrayToFile(const std::vector< Type > &data, QFile &out)
Helper: saves a vector to file.
Shifted entity interface.
double m_globalScale
Global scale (typically applied at loading time)
CCVector3d m_globalShift
Global shift (typically applied at loading time)
bool loadShiftInfoFromFile(QFile &in)
Serialization helper (input)
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 void setGlobalScale(double scale)
virtual double getGlobalScale() const
Returns the scale applied to original coordinates.
bool saveShiftInfoToFile(QFile &out) const
Serialization helper (output)
const Vector3Tpl< T > & maxCorner() const
Returns max corner (const)
Definition: BoundingBox.h:156
void setValidity(bool state)
Sets bonding box validity.
Definition: BoundingBox.h:200
const Vector3Tpl< T > & minCorner() const
Returns min corner (const)
Definition: BoundingBox.h:154
virtual void clear()
Clears the octree.
Definition: DgmOctree.cpp:183
unsigned getNumberOfProjectedPoints() const
Returns the number of points projected into the octree.
Definition: DgmOctree.h:446
int build(GenericProgressCallback *progressCb=nullptr)
Builds the structure.
Definition: DgmOctree.cpp:196
virtual void getBoundingBox(CCVector3 &bbMin, CCVector3 &bbMax)=0
Returns the cloud bounding box.
virtual unsigned size() const =0
Returns the number of points.
virtual const CCVector3 * getPoint(unsigned index) const =0
Returns the ith point.
static cloudViewer::SquareMatrixd ComputeCovarianceMatrix(const GenericCloud *theCloud, const PointCoordinateType *_gravityCenter=nullptr)
Computes the covariance matrix of a clouds.
static CCVector3 ComputeGravityCenter(const GenericCloud *theCloud)
Computes the gravity center of a point cloud.
int getScalarFieldIndexByName(const char *name) const
Returns the index of a scalar field represented by its name.
ScalarField * getScalarField(int index) const
Returns a pointer to a specific scalar field.
void setCurrentScalarField(int index)
Sets both the INPUT & OUTPUT scalar field.
A very simple point cloud (no point duplication)
virtual bool addPointIndex(unsigned globalIndex)
Point global index insertion mechanism.
virtual GenericIndexedCloudPersist * getAssociatedCloud()
Returns the associated (source) cloud.
unsigned size() const override
Returns the number of points.
virtual void clear(bool releaseMemory=false)
Clears the cloud.
virtual bool reserve(unsigned n)
Reserves some memory for hosting the point references.
A simple scalar field (to be associated to a point cloud)
Definition: ScalarField.h:25
virtual void computeMinAndMax()
Determines the min and max values.
Definition: ScalarField.h:123
ScalarType & getValue(std::size_t index)
Definition: ScalarField.h:92
void toArray(Scalar data[])
Definition: SquareMatrix.h:123
static QMainWindow * GetMainWindow()
Graphical progress indicator (thread-safe)
@ POINT_CLOUD
Definition: CVTypes.h:104
@ POINT_OCTREE
Definition: CVTypes.h:110
cloudViewer::DgmOctree * octree
OpenGL camera parameters.
bool unproject(const CCVector3d &input2D, CCVector3d &output3D) const
Unprojects a 2D point (+ normalized 'z' coordinate) in 3D.
bool project(const CCVector3d &input3D, CCVector3d &output2D, bool *inFrustum=nullptr) const
Projects a 3D point in 2D (+ normalized 'z' coordinate)
Structure used during nearest neighbour search.
Definition: DgmOctree.h:101
const CCVector3 * point
Point.
Definition: DgmOctree.h:103
double squareDistd
Point associated distance value.
Definition: DgmOctree.h:107