ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvKdTree.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 #include "ecvKdTree.h"
9 
10 // Local
11 #include "ecvBBox.h"
12 #include "ecvDisplayTools.h"
13 #include "ecvGenericPointCloud.h"
14 #include "ecvPointCloud.h"
15 #include "ecvScalarField.h"
16 
18  : cloudViewer::TrueKdTree(aCloud),
19  ccHObject("Kd-tree"),
20  m_associatedGenericCloud(aCloud) {
21  setVisible(false);
22  lockVisibility(false);
23 }
24 
25 ccBBox ccKdTree::getOwnBB(bool withGLFeatures /*=false*/) {
27  ? m_associatedGenericCloud->getOwnBB(withGLFeatures)
28  : ccBBox());
29 }
30 
33 public:
35  : m_multFactor(multFactor) {}
36 
37  void visit(ccKdTree::BaseNode* node) {
38  if (node && node->isNode()) {
39  ccKdTree::Node* trueNode = static_cast<ccKdTree::Node*>(node);
40  trueNode->splitValue *= m_multFactor;
41  visit(trueNode->leftChild);
42  visit(trueNode->rightChild);
43  }
44  }
45 
46 protected:
48 };
49 
52 }
53 
56 public:
58 
59  void visit(ccKdTree::BaseNode* node) {
60  if (node && node->isNode()) {
61  ccKdTree::Node* trueNode = static_cast<ccKdTree::Node*>(node);
62  trueNode->splitValue += m_translation.u[trueNode->splitDim];
63  visit(trueNode->leftChild);
64  visit(trueNode->rightChild);
65  }
66  }
67 
68 protected:
70 };
71 
74 }
75 
78 public:
79  DrawMeOnlyVisitor(const ccBBox& box) : m_drawCellBBox(box), m_count(0) {}
80 
82  if (!node) return;
83 
84  if (node->isNode()) {
85  ccKdTree::Node* trueNode = static_cast<ccKdTree::Node*>(node);
86  // visit left child
87  PointCoordinateType oldBBPos =
88  m_drawCellBBox.maxCorner().u[trueNode->splitDim];
89  m_drawCellBBox.maxCorner().u[trueNode->splitDim] =
90  trueNode->splitValue;
91  visit(context, trueNode->leftChild);
92  m_drawCellBBox.maxCorner().u[trueNode->splitDim] =
93  oldBBPos; // restore old limit
94 
95  // then visit right child
96  oldBBPos = m_drawCellBBox.minCorner().u[trueNode->splitDim];
97  m_drawCellBBox.minCorner().u[trueNode->splitDim] =
98  trueNode->splitValue;
99  visit(context, trueNode->rightChild);
100  m_drawCellBBox.minCorner().u[trueNode->splitDim] =
101  oldBBPos; // restore old limit
102  } else // if (node->isLeaf())
103  {
104  m_count++;
105  CC_DRAW_CONTEXT CONTEXT = context;
106  CONTEXT.viewID = QString("Octree-") + context.viewID + "-" +
107  QString::number(m_count);
108  if (CONTEXT.visible) {
109  CONTEXT.bbDefaultCol = ecvColor::green;
110  CONTEXT.meshRenderingMode =
113  // m_drawCellBBox.draw(CONTEXT, ecvColor::green);
114  } else {
116  CONTEXT.removeViewID = CONTEXT.viewID;
118  }
119  }
120  }
121 
122 protected:
124  unsigned int m_count;
125 };
126 
128  if (!m_associatedGenericCloud || !m_root) return;
129 
130  if (!MACRO_Draw3D(context)) return;
131 
132  if (ecvDisplayTools::GetCurrentScreen() == nullptr) return;
133 
134  bool entityPickingMode = MACRO_EntityPicking(context);
135 
136  if (entityPickingMode) {
137  // not fast at all!
138  if (MACRO_FastEntityPicking(context)) return;
139  }
140 
141  context.visible = isEnabled();
142 
144  .visit(context, m_root);
145 }
146 
150  return false;
151 
152  // get leaves
153  std::vector<Leaf*> leaves;
154  if (!getLeaves(leaves) || leaves.empty()) return false;
155 
157 
158  const char c_defaultSFName[] = "Kd-tree indexes";
159  int sfIdx = pc->getScalarFieldIndexByName(c_defaultSFName);
160  if (sfIdx < 0) sfIdx = pc->addScalarField(c_defaultSFName);
161  if (sfIdx < 0) {
162  CVLog::Error("Not enough memory!");
163  return false;
164  }
165  pc->setCurrentScalarField(sfIdx);
166 
167  // for each cell
168  for (size_t i = 0; i < leaves.size(); ++i) {
169  cloudViewer::ReferenceCloud* subset = leaves[i]->points;
170  if (subset) {
171  for (unsigned j = 0; j < subset->size(); ++j)
172  subset->setPointScalarValue(j, (ScalarType)i);
173  }
174  }
175 
176  pc->getScalarField(sfIdx)->computeMinAndMax();
178  pc->showSF(true);
179 
180  return true;
181 }
182 
186  return false;
187 
188  // get leaves
189  std::vector<Leaf*> leaves;
190  if (!getLeaves(leaves) || leaves.empty()) return false;
191 
193  if (!pc->resizeTheRGBTable()) return false;
194 
195  // for each cell
196  for (size_t i = 0; i < leaves.size(); ++i) {
198  cloudViewer::ReferenceCloud* subset = leaves[i]->points;
199  if (subset) {
200  for (unsigned j = 0; j < subset->size(); ++j)
201  pc->setPointColor(subset->getPointGlobalIndex(j), col);
202  }
203  }
204 
205  pc->showColors(true);
206 
207  return true;
208 }
209 
212 public:
214 
216  // invalidate the initial bounding box
219  }
220 
221  void visit(ccKdTree::BaseNode* node) {
222  assert(node);
223  if (node && node->parent) {
224  assert(node->parent->isNode()); // a leaf can't have children!
225  ccKdTree::Node* parent = static_cast<ccKdTree::Node*>(node->parent);
226 
227  // we choose the right 'side' of the box that corresponds to the
228  // parent's split plane
229  CCVector3& boxCorner =
230  (parent->leftChild == node ? m_UpdatedBox.maxCorner()
231  : m_UpdatedBox.minCorner());
232 
233  // if this side has not been setup yet...
234  if (boxCorner.u[parent->splitDim] !=
235  boxCorner.u[parent->splitDim]) // NaN
236  boxCorner.u[parent->splitDim] = parent->splitValue;
237 
238  visit(node->parent);
239  }
240  }
241 };
242 
244  if (!node || !m_associatedCloud) return ccBBox();
245 
246  GetCellBBoxVisitor helper;
247  helper.visit(node);
248 
249  // finish the job
250  ccBBox& box = helper.m_UpdatedBox;
251  {
252  CCVector3 bbMin, bbMax;
253  m_associatedCloud->getBoundingBox(bbMin, bbMax);
254  for (int i = 0; i < 3; ++i) {
255  if (box.minCorner().u[i] !=
256  box.minCorner().u[i]) // still NaN value?
257  box.minCorner().u[i] = bbMin.u[i]; // we use the main bb limit
258  if (box.maxCorner().u[i] !=
259  box.maxCorner().u[i]) // still NaN value?
260  box.maxCorner().u[i] = bbMax.u[i]; // we use the main bb limit
261  }
262  box.setValidity(true);
263  }
264 
265  return box;
266 }
267 
270 public:
272  ccKdTree::LeafSet& neighbors,
273  const ccBBox& cellBox,
274  const ccBBox& treeBox)
275  : m_targetCell(cell),
276  m_targetCellBox(cellBox),
277  m_currentCellBox(treeBox),
278  m_neighbors(&neighbors),
281 
282  void setUserDataFilter(int value) {
284  m_userDataFilterValue = value;
285  }
286 
287  void visit(ccKdTree::BaseNode* node) {
288  assert(node);
289  if (!node || node == m_targetCell) return;
290 
291  if (node->isNode()) {
292  // test bounding box
294  ccKdTree::Node* trueNode = static_cast<ccKdTree::Node*>(node);
295  // visit left child
296  PointCoordinateType oldBBPos =
297  m_currentCellBox.maxCorner().u[trueNode->splitDim];
298  m_currentCellBox.maxCorner().u[trueNode->splitDim] =
299  trueNode->splitValue;
300  visit(trueNode->leftChild);
301  m_currentCellBox.maxCorner().u[trueNode->splitDim] =
302  oldBBPos; // restore old limit
303 
304  // then visit right child
305  oldBBPos = m_currentCellBox.minCorner().u[trueNode->splitDim];
306  m_currentCellBox.minCorner().u[trueNode->splitDim] =
307  trueNode->splitValue;
308  visit(trueNode->rightChild);
309  m_currentCellBox.minCorner().u[trueNode->splitDim] =
310  oldBBPos; // restore old limit
311  }
312  } else // if (node->isLeaf())
313  {
314  ccKdTree::Leaf* leaf = static_cast<ccKdTree::Leaf*>(node);
316  // the caller can set a filter on the user data value!
318  m_userDataFilterValue == leaf->userData) {
319  assert(m_neighbors);
320  m_neighbors->insert(leaf);
321  }
322  }
323  }
324  }
325 
326 protected:
333 };
334 
336  ccKdTree::LeafSet& neighbors,
337  const int* userDataFilter /*=0*/) {
338  if (!m_root) return false;
339 
340  // determine the cell bounding box
341  ccBBox cellBox = getCellBBox(cell);
342  if (!cellBox.isValid()) return false;
343 
344  try {
345  GetNeighborLeavesVisitor visitor(cell, neighbors, cellBox,
346  getOwnBB(false));
347  if (userDataFilter) visitor.setUserDataFilter(*userDataFilter);
348  visitor.visit(m_root);
349  } catch (const std::bad_alloc&) {
350  return false;
351  }
352 
353  return true;
354 }
constexpr PointCoordinateType PC_NAN
'NaN' as a PointCoordinateType value
Definition: CVConst.h:71
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
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Definition: CVLog.cpp:143
Recursive visitor for ccKdTree::drawMeOnly.
Definition: ecvKdTree.cpp:77
DrawMeOnlyVisitor(const ccBBox &box)
Definition: ecvKdTree.cpp:79
void visit(CC_DRAW_CONTEXT &context, ccKdTree::BaseNode *node)
Definition: ecvKdTree.cpp:81
unsigned int m_count
Definition: ecvKdTree.cpp:124
Recursive visitor for ccKdTree::getCellBBox.
Definition: ecvKdTree.cpp:211
void visit(ccKdTree::BaseNode *node)
Definition: ecvKdTree.cpp:221
Recursive visitor for ccKdTree::getNeighborLeaves.
Definition: ecvKdTree.cpp:269
ccKdTree::LeafSet * m_neighbors
Definition: ecvKdTree.cpp:330
void visit(ccKdTree::BaseNode *node)
Definition: ecvKdTree.cpp:287
void setUserDataFilter(int value)
Definition: ecvKdTree.cpp:282
GetNeighborLeavesVisitor(ccKdTree::BaseNode *cell, ccKdTree::LeafSet &neighbors, const ccBBox &cellBox, const ccBBox &treeBox)
Definition: ecvKdTree.cpp:271
ccKdTree::BaseNode * m_targetCell
Definition: ecvKdTree.cpp:327
Recursive visitor for ccKdTree::multiplyBoundingBox.
Definition: ecvKdTree.cpp:32
PointCoordinateType m_multFactor
Definition: ecvKdTree.cpp:47
void visit(ccKdTree::BaseNode *node)
Definition: ecvKdTree.cpp:37
MultiplyBoundingBoxVisitor(PointCoordinateType multFactor)
Definition: ecvKdTree.cpp:34
Recursive visitor for ccKdTree::translateBoundingBox.
Definition: ecvKdTree.cpp:55
TranslateBoundingBoxVisitor(const CCVector3 &T)
Definition: ecvKdTree.cpp:57
void visit(ccKdTree::BaseNode *node)
Definition: ecvKdTree.cpp:59
Type u[3]
Definition: CVGeom.h:139
Bounding box structure.
Definition: ecvBBox.h:25
virtual void lockVisibility(bool state)
Locks/unlocks visibility.
virtual void setVisible(bool state)
Sets entity visibility.
virtual void showColors(bool state)
Sets colors visibility.
virtual void showSF(bool state)
Sets active scalarfield visibility.
A 3D cloud interface with associated features (color, normals, octree, etc.)
ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
bool getNeighborLeaves(BaseNode *cell, ccKdTree::LeafSet &neighbors, const int *userDataFilter=0)
Returns the neighbor leaves around a given cell.
Definition: ecvKdTree.cpp:335
void translateBoundingBox(const CCVector3 &T)
Translates the bounding-box of the tree.
Definition: ecvKdTree.cpp:72
std::unordered_set< Leaf * > LeafSet
A set of leaves.
Definition: ecvKdTree.h:64
virtual void drawMeOnly(CC_DRAW_CONTEXT &context) override
Draws the entity only (not its children)
Definition: ecvKdTree.cpp:127
ccKdTree(ccGenericPointCloud *aCloud)
Default constructor.
Definition: ecvKdTree.cpp:17
ccGenericPointCloud * m_associatedGenericCloud
Associated cloud.
Definition: ecvKdTree.h:81
bool convertCellIndexToRandomColor()
Flag points with a random color per leaf.
Definition: ecvKdTree.cpp:183
ccBBox getCellBBox(BaseNode *node) const
Returns the bounding-box of a given cell.
Definition: ecvKdTree.cpp:243
virtual ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
Definition: ecvKdTree.cpp:25
void multiplyBoundingBox(const PointCoordinateType multFactor)
Multiplies the bounding-box of the tree.
Definition: ecvKdTree.cpp:50
bool convertCellIndexToSF()
Flag points with cell index (as a scalar field)
Definition: ecvKdTree.cpp:147
bool isA(CV_CLASS_ENUM type) const
Definition: ecvObject.h:131
virtual bool isEnabled() const
Returns whether the object is enabled or not.
Definition: ecvObject.h:97
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void setCurrentDisplayedScalarField(int index)
Sets the currently displayed scalar field.
int addScalarField(const char *uniqueName) override
Creates a new scalar field and registers it.
bool resizeTheRGBTable(bool fillWithWhite=false)
Resizes the RGB colors array.
void setPointColor(size_t pointIndex, const ecvColor::Rgb &col)
Sets a particular point color.
T minDistTo(const BoundingBoxTpl< T > &bbox) const
Definition: BoundingBox.h:209
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
bool isValid() const
Returns whether bounding box is valid or not.
Definition: BoundingBox.h:203
virtual void getBoundingBox(CCVector3 &bbMin, CCVector3 &bbMax)=0
Returns the cloud bounding box.
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)
void setPointScalarValue(unsigned pointIndex, ScalarType value) override
Sets the ith point associated scalar value.
unsigned size() const override
Returns the number of points.
virtual unsigned getPointGlobalIndex(unsigned localIndex) const
virtual void computeMinAndMax()
Determines the min and max values.
Definition: ScalarField.h:123
PointCoordinateType splitValue
Definition: TrueKdTree.h:57
BaseNode * m_root
Root node.
Definition: TrueKdTree.h:153
bool getLeaves(LeafVector &leaves) const
Returns all leaf nodes.
Definition: TrueKdTree.cpp:321
GenericIndexedCloudPersist * m_associatedCloud
Associated cloud.
Definition: TrueKdTree.h:156
static Rgb Random(bool lightOnly=true)
Generates a random color.
RGB color structure.
Definition: ecvColorTypes.h:49
static void RemoveEntities(const ccHObject *obj)
static void DrawBBox(const CC_DRAW_CONTEXT &context, const ccBBox *bbox)
static QWidget * GetCurrentScreen()
#define MACRO_Draw3D(context)
@ ECV_WIREFRAME_MODE
#define MACRO_FastEntityPicking(context)
#define MACRO_EntityPicking(context)
@ ECV_SHAPE
ImGuiContext * context
Definition: Window.cpp:76
@ POINT_CLOUD
Definition: CVTypes.h:104
Generic file read and write utility for python interface.
constexpr Rgb green(0, MAX, 0)
Display context.
ecvColor::Rgbub bbDefaultCol
Default bounding-box color.
ENTITY_TYPE removeEntityType
MESH_RENDERING_MODE meshRenderingMode