ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
PointCloudTpl.h
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 #pragma once
9 
10 // Local
11 #include "BoundingBox.h"
13 #include "ScalarField.h"
14 
15 // STL
16 #include <vector>
17 
18 namespace cloudViewer {
19 
22 template <class T>
23 class PointCloudTpl : public T {
24  static_assert(std::is_base_of<GenericIndexedCloudPersist, T>::value,
25  "T must be a descendant of GenericIndexedCloudPersist");
26 
27 public:
30  : T(),
34 
37 
38  inline unsigned size() const override {
39  return static_cast<unsigned>(m_points.size());
40  }
41 
42  void forEach(GenericCloud::genericPointAction action) override {
43  // there's no point of calling forEach if there's no activated scalar
44  // field!
45  ScalarField* currentOutScalarFieldArray = getCurrentOutScalarField();
46  if (!currentOutScalarFieldArray) {
47  assert(false);
48  return;
49  }
50 
51  unsigned n = size();
52  for (unsigned i = 0; i < n; ++i) {
53  action(m_points[i], (*currentOutScalarFieldArray)[i]);
54  }
55  }
56 
57  void getBoundingBox(CCVector3& bbMin, CCVector3& bbMax) override {
58  if (!m_bbox.isValid()) {
59  m_bbox.clear();
60  for (const CCVector3& P : m_points) {
61  m_bbox.add(P);
62  }
63  }
64 
65  bbMin = m_bbox.minCorner();
66  bbMax = m_bbox.maxCorner();
67  }
68 
70 
71  const CCVector3* getNextPoint() override {
72  return (m_currentPointIndex < m_points.size()
74  : 0);
75  }
76 
77  bool enableScalarField() override {
78  ScalarField* currentInScalarField = getCurrentInScalarField();
79 
80  if (!currentInScalarField) {
81  // if we get there, it means that either the caller has forgot to
82  // create (and assign) a scalar field to the cloud, or that we are
83  // in a compatibility mode with old/basic behaviour: a unique SF for
84  // everything (input/output)
85 
86  // we look for any already existing "default" scalar field
89  // if not, we create it
91  if (m_currentInScalarFieldIndex < 0) // Something went wrong
92  {
93  return false;
94  }
95  }
96 
97  currentInScalarField = getCurrentInScalarField();
98  assert(currentInScalarField);
99  }
100 
101  // if there's no output scalar field either, we set this new scalar
102  // field as output also
103  if (!getCurrentOutScalarField()) {
105  }
106 
107  return currentInScalarField->resizeSafe(m_points.capacity());
108  }
109 
110  bool isScalarFieldEnabled() const override {
111  ScalarField* currentInScalarFieldArray = getCurrentInScalarField();
112  if (!currentInScalarFieldArray) {
113  return false;
114  }
115 
116  std::size_t sfValuesCount = currentInScalarFieldArray->size();
117  return (sfValuesCount != 0 && sfValuesCount >= m_points.size());
118  }
119 
120  void setPointScalarValue(unsigned pointIndex, ScalarType value) override {
121  assert(m_currentInScalarFieldIndex >= 0 &&
123  static_cast<int>(m_scalarFields.size()));
124  // slow version
125  // ScalarField* currentInScalarFieldArray = getCurrentInScalarField();
126  // if (currentInScalarFieldArray)
127  // currentInScalarFieldArray->setValue(pointIndex,value);
128 
129  // fast version
130  m_scalarFields[m_currentInScalarFieldIndex]->setValue(pointIndex,
131  value);
132  }
133 
134  ScalarType getPointScalarValue(unsigned pointIndex) const override {
135  assert(m_currentOutScalarFieldIndex >= 0 &&
137  static_cast<int>(m_scalarFields.size()));
138 
140  pointIndex);
141  }
142 
143  inline const CCVector3* getPoint(unsigned index) const override {
144  return point(index);
145  }
146  inline CCVector3* getPointPtr(size_t index) {
147  return point(static_cast<unsigned>(index));
148  }
149  inline std::vector<CCVector3>& getPoints() { return m_points; }
150  inline const std::vector<CCVector3>& getPoints() const { return m_points; }
151  inline void getPoint(unsigned index, CCVector3& P) const override {
152  P = *point(index);
153  }
154  inline void getPoint(unsigned index, double P[3]) const override {
155  P[0] = static_cast<double>(point(index)->x);
156  P[1] = static_cast<double>(point(index)->y);
157  P[2] = static_cast<double>(point(index)->z);
158  }
159 
160  inline const CCVector3* getPointPersistentPtr(unsigned index) override {
161  return point(index);
162  }
163  inline const CCVector3* getPointPersistentPtr(unsigned index) const {
164  return point(index);
165  }
166 
168 
175  virtual bool resize(unsigned newCount) {
176  std::size_t oldCount = m_points.size();
177 
178  // we try to enlarge the 3D points array
179  try {
180  m_points.resize(newCount);
181  } catch (const std::bad_alloc&) {
182  return false;
183  }
184 
185  // then the scalar fields
186  for (std::size_t i = 0; i < m_scalarFields.size(); ++i) {
187  if (!m_scalarFields[i]->resizeSafe(newCount)) {
188  // if something fails, we restore the previous size for already
189  // processed SFs!
190  for (std::size_t j = 0; j < i; ++j) {
191  m_scalarFields[j]->resize(oldCount);
192  m_scalarFields[j]->computeMinAndMax();
193  }
194  // we can assume that newCount > oldNumberOfPoints, so it should
195  // always be ok
196  m_points.resize(oldCount);
197  return false;
198  }
199  m_scalarFields[i]->computeMinAndMax();
200  }
201 
202  return true;
203  }
204 
206 
213  virtual bool reserve(unsigned newCapacity) {
214  // we try to enlarge the 3D points array
215  try {
216  m_points.reserve(newCapacity);
217  } catch (const std::bad_alloc&) {
218  return false;
219  }
220 
221  // then the scalar fields
222  for (std::size_t i = 0; i < m_scalarFields.size(); ++i) {
223  if (!m_scalarFields[i]->reserveSafe(newCapacity)) return false;
224  }
225 
226  // double check
227  return (m_points.capacity() >= newCapacity);
228  }
229 
231 
233  void reset() {
234  m_points.resize(0);
238  }
239 
241 
246  void addPoint(const CCVector3& P) {
247  // NaN coordinates check
248  if (P.x != P.x || P.y != P.y || P.z != P.z) {
249  // replace NaN point by (0, 0, 0)
250  CCVector3 fakeP(0, 0, 0);
251  m_points.push_back(fakeP);
252  } else {
253  m_points.push_back(P);
254  }
255 
256  m_bbox.setValidity(false);
257  }
258 
259  void setPoint(size_t index, const CCVector3& P) {
260  if (index < size()) {
261  // NaN coordinates check
262  if (P.x != P.x || P.y != P.y || P.z != P.z) {
263  // replace NaN point by (0, 0, 0)
264  CCVector3 fakeP(0, 0, 0);
265  m_points[index] = fakeP;
266  } else {
267  m_points[index] = P;
268  }
269  }
270  }
271 
272  void setEigenPoint(size_t index, const Eigen::Vector3d& point) {
273  if (index < size()) {
274  bool is_nan = (std::isnan(point(0)) || std::isnan(point(1)) ||
275  std::isnan(point(2)));
276  bool is_infinite = (std::isinf(point(0)) || std::isinf(point(1)) ||
277  std::isinf(point(2)));
278 
279  // NaN coordinates check
280  if (!is_nan && !is_infinite) {
281  m_points[index] = point;
282  } else {
283  // replace NaN or infinite point by (0, 0, 0)
284  CCVector3 fakeP(0, 0, 0);
285  m_points[index] = fakeP;
286  }
287  }
288  }
289 
290  void addEigenPoint(const Eigen::Vector3d& point) { addPoint(point); }
291 
292  void addPoint(double x, double y, double z) {
293  addPoint(CCVector3(static_cast<PointCoordinateType>(x),
294  static_cast<PointCoordinateType>(y),
295  static_cast<PointCoordinateType>(z)));
296  }
297 
298  void addPoint(double xyz[3]) { addPoint(xyz[0], xyz[1], xyz[2]); }
299 
300  void addPoints(const std::vector<CCVector3>& points) {
301  for (auto& P : points) {
302  addPoint(P);
303  }
304  }
305 
306  void addPoints(const std::vector<Eigen::Vector3d>& points) {
307  if (m_points.size() == 0) {
308  m_points.reserve(points.size());
309  }
310 
311  if (points.size() == m_points.size()) {
313  } else {
314  m_points.clear();
315  m_points.reserve(points.size());
317  }
318  }
319 
320  inline Eigen::Vector3d getEigenPoint(size_t index) const {
321  return CCVector3d::fromArray(*point(static_cast<unsigned int>(index)));
322  }
323 
324  inline std::vector<Eigen::Vector3d> getEigenPoints() const {
326  }
327  inline void setEigenPoints(const std::vector<Eigen::Vector3d>& points) {
328  assert(points.size() == m_points.size());
329  for (size_t i = 0; i < points.size(); ++i) {
330  setEigenPoint(i, points[i]);
331  }
332  }
333 
335 
338  virtual void invalidateBoundingBox() { m_bbox.setValidity(false); }
339 
340  /*** scalar fields management ***/
341 
343 
345  inline unsigned getNumberOfScalarFields() const {
346  return static_cast<unsigned>(m_scalarFields.size());
347  }
348 
350 
354  ScalarField* getScalarField(int index) const {
355  return (index >= 0 && index < static_cast<int>(m_scalarFields.size())
356  ? m_scalarFields[index]
357  : 0);
358  }
359 
361 
365  const char* getScalarFieldName(int index) const {
366  return (index >= 0 && index < static_cast<int>(m_scalarFields.size())
367  ? m_scalarFields[index]->getName()
368  : 0);
369  }
370 
372 
375  int getScalarFieldIndexByName(const char* name) const {
376  std::size_t sfCount = m_scalarFields.size();
377  for (std::size_t i = 0; i < sfCount; ++i) {
378  // we don't accept two SF with the same name!
379  if (strcmp(m_scalarFields[i]->getName(), name) == 0)
380  return static_cast<int>(i);
381  }
382 
383  return -1;
384  }
385 
387 
393  }
394 
396 
402  }
403 
405 
408  inline void setCurrentInScalarField(int index) {
410  }
411 
415  }
416 
418 
421  inline void setCurrentOutScalarField(int index) {
423  }
424 
428  }
429 
431 
435  inline void setCurrentScalarField(int index) {
438  }
439 
441 
448  virtual int addScalarField(const char* uniqueName) {
449  // we don't accept two SF with the same name!
450  if (getScalarFieldIndexByName(uniqueName) >= 0) {
451  return -1;
452  }
453 
454  // create requested scalar field
455  ScalarField* sf = new ScalarField(uniqueName);
456  if (!sf || (size() && !sf->resizeSafe(size()))) {
457  // Not enough memory!
458  if (sf) sf->release();
459  return -1;
460  }
461 
462  try {
463  // we don't want 'm_scalarFields' to grow by 50% each time! (default
464  // behavior of std::vector::push_back)
465  m_scalarFields.resize(m_scalarFields.size() + 1, sf);
466  } catch (const std::bad_alloc&) // out of memory
467  {
468  sf->release();
469  return -1;
470  }
471 
472  return static_cast<int>(m_scalarFields.size()) - 1;
473  }
474 
476 
481  bool renameScalarField(int index, const char* newName) {
482  if (getScalarFieldIndexByName(newName) < 0) {
483  ScalarField* sf = getScalarField(index);
484  if (sf) {
485  sf->setName(newName);
486  return true;
487  }
488  }
489  return false;
490  }
491 
493 
499  virtual void deleteScalarField(int index) {
500  int sfCount = static_cast<int>(m_scalarFields.size());
501  if (index < 0 || index >= sfCount) return;
502 
503  // we update SF roles if they point to the deleted scalar field
504  if (index == m_currentInScalarFieldIndex)
506  if (index == m_currentOutScalarFieldIndex)
508 
509  // if the deleted SF is not the last one, we swap it with the last
510  // element
511  int lastIndex = sfCount - 1; // lastIndex>=0
512  if (index < lastIndex) // i.e.lastIndex>0
513  {
514  std::swap(m_scalarFields[index], m_scalarFields[lastIndex]);
515  // don't forget to update SF roles also if they point to the last
516  // element
517  if (lastIndex == m_currentInScalarFieldIndex)
519  if (lastIndex == m_currentOutScalarFieldIndex)
521  }
522 
523  // we can always delete the last element (and the vector stays
524  // consistent)
525  m_scalarFields.back()->release();
526  m_scalarFields.pop_back();
527  }
528 
530  virtual void deleteAllScalarFields() {
532 
533  while (!m_scalarFields.empty()) {
534  m_scalarFields.back()->release();
535  m_scalarFields.pop_back();
536  }
537  }
538 
540  inline unsigned capacity() const {
541  return static_cast<unsigned>(m_points.capacity());
542  }
543 
544 protected:
546  virtual void swapPoints(unsigned firstIndex, unsigned secondIndex) {
547  if (firstIndex == secondIndex || firstIndex >= m_points.size() ||
548  secondIndex >= m_points.size()) {
549  return;
550  }
551 
552  std::swap(m_points[firstIndex], m_points[secondIndex]);
553 
554  for (std::size_t i = 0; i < m_scalarFields.size(); ++i) {
555  m_scalarFields[i]->swap(firstIndex, secondIndex);
556  }
557  }
558 
560 
564  inline CCVector3* point(unsigned index) {
565  assert(index < size());
566  return &(m_points[index]);
567  }
568 
570 
574  inline const CCVector3* point(unsigned index) const {
575  assert(index < size());
576  return &(m_points[index]);
577  }
578 
580  std::vector<CCVector3> m_points;
581 
584 
587 
589  std::vector<ScalarField*> m_scalarFields;
590 
593 
596 };
597 
598 } // namespace cloudViewer
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 points
virtual void release()
Decrease counter and deletes object when 0.
Definition: CVShareable.cpp:35
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
Definition: CVGeom.h:268
static std::vector< Eigen::Matrix< double, 3, 1 > > fromArrayContainer(const std::vector< Vector3Tpl< PointCoordinateType >> &container)
Definition: CVGeom.h:301
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
void clear()
Resets the bounding box.
Definition: BoundingBox.h:125
const Vector3Tpl< T > & minCorner() const
Returns min corner (const)
Definition: BoundingBox.h:154
bool isValid() const
Returns whether bounding box is valid or not.
Definition: BoundingBox.h:203
void add(const Vector3Tpl< T > &P)
'Enlarges' the bounding box with a point
Definition: BoundingBox.h:131
std::function< void(const CCVector3 &, ScalarType &)> genericPointAction
Generic function applied to a point (used by foreach)
Definition: GenericCloud.h:30
void setEigenPoints(const std::vector< Eigen::Vector3d > &points)
void addPoint(double x, double y, double z)
std::vector< ScalarField * > m_scalarFields
Associated scalar fields.
std::vector< CCVector3 > m_points
3D Points database
void addEigenPoint(const Eigen::Vector3d &point)
ScalarField * getCurrentOutScalarField() const
Returns the scalar field currently associated to the cloud output.
int getScalarFieldIndexByName(const char *name) const
Returns the index of a scalar field represented by its name.
const CCVector3 * getNextPoint() override
Definition: PointCloudTpl.h:71
void reset()
Clears the cloud database.
virtual void swapPoints(unsigned firstIndex, unsigned secondIndex)
Swaps two points (and their associated scalar values!)
void forEach(GenericCloud::genericPointAction action) override
Definition: PointCloudTpl.h:42
virtual void deleteScalarField(int index)
Deletes a specific scalar field.
virtual void invalidateBoundingBox()
Invalidates bounding box.
int getCurrentInScalarFieldIndex()
Returns current INPUT scalar field index (or -1 if none)
void setCurrentOutScalarField(int index)
Sets the OUTPUT scalar field.
ScalarField * getScalarField(int index) const
Returns a pointer to a specific scalar field.
unsigned getNumberOfScalarFields() const
Returns the number of associated (and active) scalar fields.
std::vector< CCVector3 > & getPoints()
CCVector3 * getPointPtr(size_t index)
void setPointScalarValue(unsigned pointIndex, ScalarType value) override
CCVector3 * point(unsigned index)
Returns non const access to a given point.
void addPoint(double xyz[3])
virtual bool reserve(unsigned newCapacity)
Reserves memory for the point database.
void addPoints(const std::vector< Eigen::Vector3d > &points)
virtual int addScalarField(const char *uniqueName)
Creates a new scalar field and registers it.
BoundingBox m_bbox
Bounding-box.
bool isScalarFieldEnabled() const override
void setCurrentScalarField(int index)
Sets both the INPUT & OUTPUT scalar field.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
const CCVector3 * getPointPersistentPtr(unsigned index) override
int getCurrentOutScalarFieldIndex()
Returns current OUTPUT scalar field index (or -1 if none)
void getBoundingBox(CCVector3 &bbMin, CCVector3 &bbMax) override
Definition: PointCloudTpl.h:57
unsigned size() const override
Definition: PointCloudTpl.h:38
bool renameScalarField(int index, const char *newName)
Renames a specific scalar field.
virtual void deleteAllScalarFields()
Deletes all scalar fields associated to this cloud.
const char * getScalarFieldName(int index) const
Returns the name of a specific scalar field.
const std::vector< CCVector3 > & getPoints() const
ScalarType getPointScalarValue(unsigned pointIndex) const override
void setEigenPoint(size_t index, const Eigen::Vector3d &point)
void getPoint(unsigned index, CCVector3 &P) const override
void getPoint(unsigned index, double P[3]) const override
int m_currentInScalarFieldIndex
Index of current scalar field used for input.
std::vector< Eigen::Vector3d > getEigenPoints() const
virtual bool resize(unsigned newCount)
Resizes the point database.
void setCurrentInScalarField(int index)
Sets the INPUT scalar field.
const CCVector3 * point(unsigned index) const
Returns const access to a given point.
PointCloudTpl()
Default constructor.
Definition: PointCloudTpl.h:29
unsigned capacity() const
Returns cloud capacity (i.e. reserved size)
Eigen::Vector3d getEigenPoint(size_t index) const
void setPoint(size_t index, const CCVector3 &P)
int m_currentOutScalarFieldIndex
Index of current scalar field used for output.
void placeIteratorAtBeginning() override
Definition: PointCloudTpl.h:69
unsigned m_currentPointIndex
'Iterator' on the points db
const CCVector3 * getPoint(unsigned index) const override
const CCVector3 * getPointPersistentPtr(unsigned index) const
void addPoints(const std::vector< CCVector3 > &points)
bool enableScalarField() override
Definition: PointCloudTpl.h:77
ScalarField * getCurrentInScalarField() const
Returns the scalar field currently associated to the cloud input.
virtual ~PointCloudTpl()
Default destructor.
Definition: PointCloudTpl.h:36
A simple scalar field (to be associated to a point cloud)
Definition: ScalarField.h:25
void setName(const char *name)
Sets scalar field name.
Definition: ScalarField.cpp:22
bool resizeSafe(std::size_t count, bool initNewElements=false, ScalarType valueForNewElements=0)
Resizes memory (no exception thrown)
Definition: ScalarField.cpp:81
Generic file read and write utility for python interface.
void swap(cloudViewer::core::SmallVectorImpl< T > &LHS, cloudViewer::core::SmallVectorImpl< T > &RHS)
Implement std::swap in terms of SmallVector swap.
Definition: SmallVector.h:1370
Definition: lsd.c:149