Ocean
Loading...
Searching...
No Matches
Octree.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef META_OCEAN_GEOMETRY_OCTREE_H
9#define META_OCEAN_GEOMETRY_OCTREE_H
10
12
14#include "ocean/math/Line3.h"
15#include "ocean/math/Vector3.h"
16
17namespace Ocean
18{
19
20namespace Geometry
21{
22
23/// Forward declaration.
24template <typename T>
25class OctreeT;
26
27/**
28 * Definition of an Octree using Scalar as data type.
29 * @see OctreeT
30 * @ingroup geometry
31 */
33
34/**
35 * Definition of an Octree using double as data type.
36 * @see OctreeT
37 * @ingroup geometry
38 */
40
41/**
42 * Definition of an Octree using float as data type.
43 * @see OctreeT
44 * @ingroup geometry
45 */
47
48/**
49 * This class implements an Octree allowing to manage 3D points.
50 * Each node in the Octree has exactly eight child nodes (unless it is a leaf node).
51 * @ingroup geometry
52 */
53template <typename T>
55{
56 public:
57
58 /// The data type of this octree.
59 typedef T Type;
60
61 /**
62 * This class stores construction parameters for an octree.
63 */
65 {
66 public:
67
68 /**
69 * Default constructor.
70 */
71 Parameters() = default;
72
73 /**
74 * Creates a new parameter object.
75 * @param maximalPointsPerLeaf The maximal number of points each leaf node can have, with range [1, infinity)
76 * @param useTightBoundingBoxes True, to use tight bounding boxes for each individual node (only covering the actual points); False, to use bisected bounding boxes of the bounding box of the previous node
77 */
78 inline Parameters(const unsigned int maximalPointsPerLeaf, const bool useTightBoundingBoxes);
79
80 /**
81 * Returns whether this object holds valid parameters.
82 * @return True, if so
83 */
84 inline bool isValid() const;
85
86 public:
87
88 /// The maximal number of points each leaf node can have.
89 unsigned int maximalPointsPerLeaf_ = 40u;
90
91 /// True, to use tight bounding boxes for each individual node (only covering the actual points); False, to use bisected bounding boxes of the bounding box of the previous node
93 };
94
95 /**
96 * Definition of a class which holds reusable data for internal use.
97 * This object can avoid reallocating memory when calling a matching function several times in a row.<br>
98 * Simply define this object outside of the loop and provide the object as parameter, e.g.,
99 * @code
100 * std::vector<const Indices32*> leafs;
101 * ReusableData reusableData;
102 * for (const Vector3& point : points)
103 * {
104 * leafs.clear();
105 * octree.closestLeafs(point, maximalDistance, leafs, reusableData);
106 * ...
107 * }
108 * @endcode
109 */
111 {
112 friend class OctreeT<T>;
113
114 public:
115
116 /**
117 * Creates a new object.
118 */
119 ReusableData() = default;
120
121 protected:
122
123 /// The internal reusable data.
124 mutable std::vector<const OctreeT<T>*> internalData_;
125 };
126
127 public:
128
129 /**
130 * Default constructor creating an empty tree.
131 */
132 OctreeT() = default;
133
134 /**
135 * Disabled copy constructor.
136 * @param octree The octree which would be copied
137 */
138 OctreeT(const OctreeT& octree) = delete;
139
140 /**
141 * Move constructor.
142 * @param octree The octree to be moved
143 */
144 OctreeT(OctreeT&& octree);
145
146 /**
147 * Creates a new Octree for a given set of 3D points.
148 * The given points must not change afterwards, the points must exist as long as the tree exists.
149 * @param treePoints The points for which the tree will be created, can be 'nullptr' if 'numberTreePoints == 0'
150 * @param numberTreePoints The number given tree points, with range [0, infinity)
151 * @param parameters The parameters to used to construct the tree, must be valid
152 */
153 OctreeT(const VectorT3<T>* treePoints, const size_t numberTreePoints, const Parameters& parameters = Parameters());
154
155 /**
156 * Destructs this tree node.
157 */
158 ~OctreeT();
159
160 /**
161 * Returns the bounding box containing all points of this node (of all points in all child leaf nodes)
162 * @return The tree node's bounding box
163 */
164 inline const BoundingBox& boundingBox() const;
165
166 /**
167 * Returns the indices of the tree points which belong to this leaf node.
168 * @return The leaf node's point indices, empty if this node is not a leaf node
169 */
170 inline const Indices32& pointIndices() const;
171
172 /**
173 * Returns the eight child nodes of this tree node
174 * @return The node's eight child node, nullptr if this node is a leaf node
175 */
176 inline const OctreeT<T>* const * childNodes() const;
177
178 /**
179 * Returns the closest leaf nodes for a given query point.
180 * @param queryPoint The query point for which the closest leaf nodes will be returned
181 * @param maximalDistance The maximal distance between the query point and any potential point in a leaf node, with range [0, infinity)
182 * @param leafs The resulting leaf nodes, mainly the point indices of the tree points which stored in the closest leaf nodes
183 * @param reusableData An reusable object to speedup the search, should be located outside of the function call if several function calls are done after each other
184 */
185 void closestLeafs(const VectorT3<T>& queryPoint, const T maximalDistance, std::vector<const Indices32*>& leafs, const ReusableData& reusableData = ReusableData()) const;
186
187 /**
188 * Returns the intersecting leaf nodes for a given query ray.
189 * @param queryRay The query ray for which the intersecting leaf nodes will be returned, the search treats the ray as an infinite ray in space, must be valid
190 * @param leafs The resulting leaf nodes, mainly the point indices of the tree points which stored in the intersecting leaf nodes
191 * @param reusableData An reusable object to speedup the search, should be located outside of the function call if several function calls are done after each other
192 */
193 void intersectingLeafs(const LineT3<T>& queryRay, std::vector<const Indices32*>& leafs, const ReusableData& reusableData = ReusableData()) const;
194
195 /**
196 * Returns the intersecting leaf nodes for a given approximated query cone expressed as a ray with a cone apex angle.
197 * This function applies an approximation to determine the distance between the cone's apex and leaf nodes.
198 * @param queryRay The query ray defining the apex and axis of the cone for which the intersecting leaf nodes will be returned, the search treats the ray as an infinite ray in space, must be valid
199 * @param tanHalfAngle The tangent of the cone's half apex angle, e.g., Numeric::tan(Numeric::deg2rad(1)), with range [0, 1)
200 * @param leafs The resulting leaf nodes, mainly the point indices of the tree points which stored in the intersecting leaf nodes
201 * @param reusableData An reusable object to speedup the search, should be located outside of the function call if several function calls are done after each other
202 */
203 void intersectingLeafs(const LineT3<T>& queryRay, const Scalar tanHalfAngle, std::vector<const Indices32*>& leafs, const ReusableData& reusableData = ReusableData()) const;
204
205 /**
206 * Returns the closest tree points for a given query point.
207 * @param treePoints The tree points from which the closest points will be determined (must be the same points for which the tree has been created), must be valid
208 * @param queryPoint The query point for which the closest points will be returned
209 * @param maximalDistance The maximal distance between the query point and any potential tree point in a leaf node, with range [0, infinity)
210 * @param pointIndices The resulting indices of the tree points which have a maximal distance of 'maximalDistance' to the query point
211 * @param points Optional resulting tree points, one for each resulting index, will be {treePoints[pointIndices[0]], treePoints[pointIndices[1]], ..., treePoints[pointIndices[pointIndices.size() - 1]]}; nullptr if not of interest
212 * @param reusableData An reusable object to speedup the search, should be located outside of the function call if several function calls are done after each other
213 */
214 void closestPoints(const VectorT3<T>* treePoints, const VectorT3<T>& queryPoint, const T maximalDistance, Indices32& pointIndices, VectorsT3<T>* points = nullptr, const ReusableData& reusableData = ReusableData()) const;
215
216 /**
217 * Returns whether this node is valid (if this node has a valid bounding box)
218 * @return True, if so
219 */
220 inline bool isValid() const;
221
222 /**
223 * Move operator.
224 * @param octree The octree to be moved
225 * @return Reference to this octree
226 */
227 OctreeT& operator=(OctreeT&& octree);
228
229 /**
230 * Disabled copy constructor.
231 * @param octree The octree which would be copied
232 * @return Reference to this octree
233 */
234 OctreeT& operator=(const OctreeT& octree) = delete;
235
236 protected:
237
238 /**
239 * Creates a new octree node.
240 * @param parameters The parameters to be used, must be valid
241 * @param treePoints The points for which the tree will be created, must be valid
242 * @param reusablePointIndicesInput The indices of the points for which the new node will be created, must be valid
243 * @param reusablePointIndicesOutput Memory block of indices with same size as 'reusableIndicesInput' which can be re-used internally, must be valid
244 * @param numberPointIndices The number of given indices in 'reusablePointIndicesInput', with range [0, infinity)
245 * @param boundingBox The bounding box of the new child node; will be ignored if `parameters.useTightBoundingBoxes_ == true`
246 */
247 OctreeT(const Parameters& parameters, const VectorT3<T>* treePoints, Index32* reusablePointIndicesInput, Index32* reusablePointIndicesOutput, const size_t numberPointIndices, const BoundingBox& boundingBox);
248
249 protected:
250
251 /// The bounding box of this tree node.
253
254 /// The indicies of the tree points which belong to this leaf node, empty if this node is not a leaf node.
256
257 /// The eight child nodes.
258 OctreeT<T>* childNodes_[8] = {nullptr};
259};
260
261template <typename T>
262inline OctreeT<T>::Parameters::Parameters(const unsigned int maximalPointsPerLeaf, const bool useTightBoundingBoxes) :
263 maximalPointsPerLeaf_(maximalPointsPerLeaf),
264 useTightBoundingBoxes_(useTightBoundingBoxes)
265{
266 ocean_assert(maximalPointsPerLeaf_ >= 1u);
267}
268
269template <typename T>
271{
272 return maximalPointsPerLeaf_ >= 1u;
273}
274
275template <typename T>
277{
278 *this = std::move(octree);
279}
280
281template <typename T>
282OctreeT<T>::OctreeT(const VectorT3<T>* treePoints, const size_t numberTreePoints, const Parameters& parameters)
283{
284 ocean_assert(parameters.isValid());
285
286 if (numberTreePoints == 0)
287 {
288 return;
289 }
290
291 ocean_assert(treePoints != nullptr);
292
293 Indices32 reusablePointIndicesInput(createIndices<Index32>(numberTreePoints, 0u));
294 Indices32 reusablePointIndicesOutput(reusablePointIndicesInput.size());
295
297
298 if (parameters.useTightBoundingBoxes_ == false)
299 {
300 for (size_t n = 0; n < numberTreePoints; ++n)
301 {
302 boundingBox += Vector3(treePoints[n]);
303 }
304 }
305
306 *this = Octree(parameters, treePoints, reusablePointIndicesInput.data(), reusablePointIndicesOutput.data(), numberTreePoints, boundingBox);
307}
308
309template <typename T>
310OctreeT<T>::OctreeT(const Parameters& parameters, const VectorT3<T>* treePoints, Index32* reusablePointIndicesInput, Index32* reusablePointIndicesOutput, const size_t numberPointIndices, const BoundingBox& boundingBox)
311{
312 ocean_assert(parameters.isValid());
313 ocean_assert(treePoints != nullptr);
314
315 if (numberPointIndices == 0)
316 {
317 return;
318 }
319
320 ocean_assert(reusablePointIndicesInput != nullptr && reusablePointIndicesOutput != nullptr);
321
322 bool isLeafNode = numberPointIndices <= parameters.maximalPointsPerLeaf_;
323
324 if (!isLeafNode)
325 {
326 // let's ensure that not all points are identical, in this case we have a leaf node as well
327
328 const Vector3& firstPoint = treePoints[reusablePointIndicesInput[0]];
329
330 bool allPointsIdentical = true;
331
332 for (size_t n = 1; n < numberPointIndices; ++n)
333 {
334 const Index32& index = reusablePointIndicesInput[n];
335 const VectorT3<T>& point = treePoints[index];
336
337 if (firstPoint != point)
338 {
339 allPointsIdentical = false;
340 break;
341 }
342 }
343
344 isLeafNode = allPointsIdentical;
345 }
346
347 if (parameters.useTightBoundingBoxes_ == false)
348 {
349 ocean_assert(boundingBox.isValid());
351
352#ifdef OCEAN_DEBUG
353 for (size_t n = 0; n < numberPointIndices; ++n)
354 {
355 const Index32& index = reusablePointIndicesInput[n];
356 ocean_assert(boundingBox_.isInside(Vector3(treePoints[index])));
357 }
358#endif
359
360 if (isLeafNode)
361 {
362 // we have a leaf node
363
364 pointIndices_.reserve(numberPointIndices);
365
366 for (size_t n = 0; n < numberPointIndices; ++n)
367 {
368 const Index32& index = reusablePointIndicesInput[n];
369 pointIndices_.emplace_back(index);
370 }
371
372 return;
373 }
374 }
375 else
376 {
377 if (isLeafNode)
378 {
379 // we have a leaf node
380
381 pointIndices_.reserve(numberPointIndices);
382
383 for (size_t n = 0; n < numberPointIndices; ++n)
384 {
385 const Index32& index = reusablePointIndicesInput[n];
386
387 boundingBox_ += Vector3(treePoints[index]);
388 pointIndices_.emplace_back(index);
389 }
390
391 ocean_assert(boundingBox_.isValid());
392
393 return;
394 }
395
396 // we need to separate the points
397
398 for (size_t n = 0; n < numberPointIndices; ++n)
399 {
400 const Index32& index = reusablePointIndicesInput[n];
401 boundingBox_ += Vector3(treePoints[index]);
402 }
403 }
404
405 ocean_assert(boundingBox_.isValid());
406
407 const VectorT3<T> center(boundingBox_.center());
408
409 // first, we count how may points fall in which node
410
411 size_t lowLowLow = 0;
412 size_t lowLowHigh = 0;
413 size_t lowHighLow = 0;
414 size_t lowHighHigh = 0;
415
416 size_t highLowLow = 0;
417 size_t highLowHigh = 0;
418 size_t highHighLow = 0;
419 size_t highHighHigh = 0;
420
421 for (size_t n = 0; n < numberPointIndices; ++n)
422 {
423 const Index32& index = reusablePointIndicesInput[n];
424 const VectorT3<T>& point = treePoints[index];
425
426 if (point.x() < center.x())
427 {
428 if (point.y() < center.y())
429 {
430 if (point.z() < center.z())
431 {
432 ++lowLowLow;
433 }
434 else
435 {
436 ++lowLowHigh;
437 }
438 }
439 else
440 {
441 if (point.z() < center.z())
442 {
443 ++lowHighLow;
444 }
445 else
446 {
447 ++lowHighHigh;
448 }
449 }
450 }
451 else
452 {
453 if (point.y() < center.y())
454 {
455 if (point.z() < center.z())
456 {
457 ++highLowLow;
458 }
459 else
460 {
461 ++highLowHigh;
462 }
463 }
464 else
465 {
466 if (point.z() < center.z())
467 {
468 ++highHighLow;
469 }
470 else
471 {
472 ++highHighHigh;
473 }
474 }
475 }
476 }
477
478 // now, we shuffle the indices of the individual points
479
480 Index32* lowLowLowPointer = reusablePointIndicesOutput;
481 Index32* lowLowHighPointer = lowLowLowPointer + lowLowLow;
482 Index32* lowHighLowPointer = lowLowHighPointer + lowLowHigh;
483 Index32* lowHighHighPointer = lowHighLowPointer + lowHighLow;
484
485 Index32* highLowLowPointer = lowHighHighPointer + lowHighHigh;
486 Index32* highLowHighPointer = highLowLowPointer + highLowLow;
487 Index32* highHighLowPointer = highLowHighPointer + highLowHigh;
488 Index32* highHighHighPointer = highHighLowPointer + highHighLow;
489
490 ocean_assert(highHighHighPointer + highHighHigh == reusablePointIndicesOutput + numberPointIndices);
491
492 for (size_t n = 0; n < numberPointIndices; ++n)
493 {
494 const Index32& index = reusablePointIndicesInput[n];
495 const VectorT3<T>& point = treePoints[index];
496
497 if (point.x() < center.x())
498 {
499 if (point.y() < center.y())
500 {
501 if (point.z() < center.z())
502 {
503 *lowLowLowPointer++ = index;
504 }
505 else
506 {
507 *lowLowHighPointer++ = index;
508 }
509 }
510 else
511 {
512 if (point.z() < center.z())
513 {
514 *lowHighLowPointer++ = index;
515 }
516 else
517 {
518 *lowHighHighPointer++ = index;
519 }
520 }
521 }
522 else
523 {
524 if (point.y() < center.y())
525 {
526 if (point.z() < center.z())
527 {
528 *highLowLowPointer++ = index;
529 }
530 else
531 {
532 *highLowHighPointer++ = index;
533 }
534 }
535 else
536 {
537 if (point.z() < center.z())
538 {
539 *highHighLowPointer++ = index;
540 }
541 else
542 {
543 *highHighHighPointer++ = index;
544 }
545 }
546 }
547 }
548
549 ocean_assert(lowLowLowPointer == reusablePointIndicesOutput + lowLowLow);
550 ocean_assert(lowLowHighPointer == lowLowLowPointer + lowLowHigh);
551 ocean_assert(lowHighLowPointer == lowLowHighPointer + lowHighLow);
552 ocean_assert(lowHighHighPointer == lowHighLowPointer + lowHighHigh);
553
554 ocean_assert(highLowLowPointer == lowHighHighPointer + highLowLow);
555 ocean_assert(highLowHighPointer == highLowLowPointer + highLowHigh);
556 ocean_assert(highHighLowPointer == highLowHighPointer + highHighLow);
557 ocean_assert(highHighHighPointer == highHighLowPointer + highHighHigh);
558
559 if (parameters.useTightBoundingBoxes_)
560 {
561 childNodes_[0] = new OctreeT<T>(parameters, treePoints, reusablePointIndicesOutput, reusablePointIndicesInput, lowLowLow, BoundingBox()); // with swapped reusableIndicesOutput and reusableIndicesInput
562 childNodes_[1] = new OctreeT<T>(parameters, treePoints, reusablePointIndicesOutput += lowLowLow, reusablePointIndicesInput += lowLowLow, lowLowHigh, BoundingBox());
563 childNodes_[2] = new OctreeT<T>(parameters, treePoints, reusablePointIndicesOutput += lowLowHigh, reusablePointIndicesInput += lowLowHigh, lowHighLow, BoundingBox());
564 childNodes_[3] = new OctreeT<T>(parameters, treePoints, reusablePointIndicesOutput += lowHighLow, reusablePointIndicesInput += lowHighLow, lowHighHigh, BoundingBox());
565
566 childNodes_[4] = new OctreeT<T>(parameters, treePoints, reusablePointIndicesOutput += lowHighHigh, reusablePointIndicesInput += lowHighHigh, highLowLow, BoundingBox());
567 childNodes_[5] = new OctreeT<T>(parameters, treePoints, reusablePointIndicesOutput += highLowLow, reusablePointIndicesInput += highLowLow, highLowHigh, BoundingBox());
568 childNodes_[6] = new OctreeT<T>(parameters, treePoints, reusablePointIndicesOutput += highLowHigh, reusablePointIndicesInput += highLowHigh, highHighLow, BoundingBox());
569 childNodes_[7] = new OctreeT<T>(parameters, treePoints, reusablePointIndicesOutput += highHighLow, reusablePointIndicesInput += highHighLow, highHighHigh, BoundingBox());
570 }
571 else
572 {
573 const BoundingBox boxLowLowLow(Vector3(boundingBox_.lower().x(), boundingBox_.lower().y(), boundingBox_.lower().z()), Vector3(center.x(), center.y(), center.z()));
574 const BoundingBox boxLowLowHigh(Vector3(boundingBox_.lower().x(), boundingBox_.lower().y(), center.z()), Vector3(center.x(), center.y(), boundingBox_.higher().z()));
575 const BoundingBox boxLowHighLow(Vector3(boundingBox_.lower().x(), center.y(), boundingBox_.lower().z()), Vector3(center.x(), boundingBox_.higher().y(), center.z()));
576 const BoundingBox boxLowHighHigh(Vector3(boundingBox_.lower().x(), center.y(), center.z()), Vector3(center.x(), boundingBox_.higher().y(), boundingBox_.higher().z()));
577
578 const BoundingBox boxHighLowLow(Vector3(center.x(), boundingBox_.lower().y(), boundingBox_.lower().z()), Vector3(boundingBox_.higher().x(), center.y(), center.z()));
579 const BoundingBox boxHighLowHigh(Vector3(center.x(), boundingBox_.lower().y(), center.z()), Vector3(boundingBox_.higher().x(), center.y(), boundingBox_.higher().z()));
580 const BoundingBox boxHighHighLow(Vector3(center.x(), center.y(), boundingBox_.lower().z()), Vector3(boundingBox_.higher().x(), boundingBox_.higher().y(), center.z()));
581 const BoundingBox boxHighHighHigh(Vector3(center.x(), center.y(), center.z()), Vector3(boundingBox_.higher().x(), boundingBox_.higher().y(), boundingBox_.higher().z()));
582
583 childNodes_[0] = new OctreeT<T>(parameters, treePoints, reusablePointIndicesOutput, reusablePointIndicesInput, lowLowLow, boxLowLowLow); // with swapped reusableIndicesOutput and reusableIndicesInput
584 childNodes_[1] = new OctreeT<T>(parameters, treePoints, reusablePointIndicesOutput += lowLowLow, reusablePointIndicesInput += lowLowLow, lowLowHigh, boxLowLowHigh);
585 childNodes_[2] = new OctreeT<T>(parameters, treePoints, reusablePointIndicesOutput += lowLowHigh, reusablePointIndicesInput += lowLowHigh, lowHighLow, boxLowHighLow);
586 childNodes_[3] = new OctreeT<T>(parameters, treePoints, reusablePointIndicesOutput += lowHighLow, reusablePointIndicesInput += lowHighLow, lowHighHigh, boxLowHighHigh);
587
588 childNodes_[4] = new OctreeT<T>(parameters, treePoints, reusablePointIndicesOutput += lowHighHigh, reusablePointIndicesInput += lowHighHigh, highLowLow, boxHighLowLow);
589 childNodes_[5] = new OctreeT<T>(parameters, treePoints, reusablePointIndicesOutput += highLowLow, reusablePointIndicesInput += highLowLow, highLowHigh, boxHighLowHigh);
590 childNodes_[6] = new OctreeT<T>(parameters, treePoints, reusablePointIndicesOutput += highLowHigh, reusablePointIndicesInput += highLowHigh, highHighLow, boxHighHighLow);
591 childNodes_[7] = new OctreeT<T>(parameters, treePoints, reusablePointIndicesOutput += highHighLow, reusablePointIndicesInput += highHighLow, highHighHigh, boxHighHighHigh);
592 }
593}
594
595template <typename T>
597{
598 for (unsigned int n = 0u; n < 8u; ++n)
599 {
600 delete childNodes_[n];
601 }
602}
603
604template <typename T>
606{
607 return boundingBox_;
608}
609
610template <typename T>
612{
613 return pointIndices_;
614}
615
616template <typename T>
617inline const OctreeT<T>* const * OctreeT<T>::childNodes() const
618{
619 if (childNodes_[0] == nullptr)
620 {
621 return nullptr;
622 }
623
624 return childNodes_;
625}
626
627template <typename T>
628void OctreeT<T>::closestLeafs(const VectorT3<T>& queryPoint, const T maximalDistance, std::vector<const Indices32*>& leafs, const ReusableData& reusableData) const
629{
630 if (!isValid())
631 {
632 return;
633 }
634
635 const Vector3 scalarPoint(queryPoint);
636
637 const T maximalSqrDistance = Scalar(maximalDistance * maximalDistance);
638
639 if (!boundingBox_.isInside(scalarPoint, Scalar(maximalDistance)))
640 {
641 return;
642 }
643
644 std::vector<const OctreeT<T>*>& nodes = reusableData.internalData_;
645 nodes.emplace_back(this);
646
647 while (!nodes.empty())
648 {
649 const OctreeT<T>* node = nodes.back();
650 nodes.pop_back();
651
652 ocean_assert(node != nullptr);
653 ocean_assert(node->boundingBox_.isInside(scalarPoint, Scalar(maximalDistance)));
654
655 if (node->childNodes_[0] != nullptr)
656 {
657 for (unsigned int n = 0u; n < 8u; ++n)
658 {
659 ocean_assert(node->childNodes_[n] != nullptr);
660 const OctreeT<T>& childNode = *node->childNodes_[n];
661
662 if (childNode.isValid() && childNode.boundingBox_.isInside(scalarPoint, Scalar(maximalDistance)))
663 {
664 nodes.emplace_back(&childNode);
665 }
666 }
667 }
668 else if (!node->pointIndices_.empty())
669 {
670 leafs.emplace_back(&node->pointIndices_);
671 }
672 }
673}
674
675template <typename T>
676void OctreeT<T>::intersectingLeafs(const LineT3<T>& queryRay, std::vector<const Indices32*>& leafs, const ReusableData& reusableData) const
677{
678 ocean_assert(queryRay.isValid());
679 ocean_assert(leafs.empty());
680
681 if (!isValid())
682 {
683 return;
684 }
685
686 const Line3 scalarRay(queryRay);
687
688 if (!boundingBox_.hasIntersection(scalarRay))
689 {
690 return;
691 }
692
693 std::vector<const OctreeT<T>*>& nodes = reusableData.internalData_;
694 nodes.emplace_back(this);
695
696 while (!nodes.empty())
697 {
698 const OctreeT<T>* node = nodes.back();
699 nodes.pop_back();
700
701 ocean_assert(node != nullptr);
702 ocean_assert(node->boundingBox_.hasIntersection(scalarRay));
703
704 if (node->childNodes_[0] != nullptr)
705 {
706 for (unsigned int n = 0u; n < 8u; ++n)
707 {
708 ocean_assert(node->childNodes_[n] != nullptr);
709 const OctreeT<T>& childNode = *node->childNodes_[n];
710
711 if (childNode.isValid() && childNode.boundingBox_.hasIntersection(scalarRay))
712 {
713 nodes.emplace_back(&childNode);
714 }
715 }
716 }
717 else if (!node->pointIndices_.empty())
718 {
719 leafs.emplace_back(&node->pointIndices_);
720 }
721 }
722}
723
724template <typename T>
725void OctreeT<T>::intersectingLeafs(const LineT3<T>& queryRay, const Scalar tanHalfAngle, std::vector<const Indices32*>& leafs, const ReusableData& reusableData) const
726{
727 ocean_assert(queryRay.isValid());
728 ocean_assert(tanHalfAngle >= 0 && tanHalfAngle < 1);
729 ocean_assert(leafs.empty());
730
731 if (!isValid())
732 {
733 return;
734 }
735
736 const Line3 scalarRay(queryRay);
737
738 const Scalar& epsPerDistance = tanHalfAngle;
739
740 if (!boundingBox_.hasIntersection(scalarRay, epsPerDistance))
741 {
742 return;
743 }
744
745 std::vector<const OctreeT<T>*>& nodes = reusableData.internalData_;
746 nodes.emplace_back(this);
747
748 while (!nodes.empty())
749 {
750 const OctreeT<T>* node = nodes.back();
751 nodes.pop_back();
752
753 ocean_assert(node != nullptr);
754 ocean_assert(node->boundingBox_.hasIntersection(scalarRay, epsPerDistance));
755
756 if (node->childNodes_[0] != nullptr)
757 {
758 for (unsigned int n = 0u; n < 8u; ++n)
759 {
760 ocean_assert(node->childNodes_[n] != nullptr);
761 const OctreeT<T>& childNode = *node->childNodes_[n];
762
763 if (childNode.isValid() && childNode.boundingBox_.hasIntersection(scalarRay, epsPerDistance))
764 {
765 nodes.emplace_back(&childNode);
766 }
767 }
768 }
769 else if (!node->pointIndices_.empty())
770 {
771 leafs.emplace_back(&node->pointIndices_);
772 }
773 }
774}
775
776template <typename T>
777void OctreeT<T>::closestPoints(const VectorT3<T>* treePoints, const VectorT3<T>& queryPoint, const T maximalDistance, Indices32& pointIndices, VectorsT3<T>* points, const ReusableData& reusableData) const
778{
779 ocean_assert(treePoints != nullptr);
780
781 ocean_assert(pointIndices.empty());
782 ocean_assert(points == nullptr || points->empty());
783
784 if (!isValid())
785 {
786 return;
787 }
788
789 const Vector3 scalarPoint(queryPoint);
790
791 const T maximalSqrDistance = Scalar(maximalDistance * maximalDistance);
792
793 if (!boundingBox_.isInside(scalarPoint, Scalar(maximalDistance)))
794 {
795 return;
796 }
797
798 std::vector<const OctreeT<T>*>& nodes = reusableData.internalData_;
799 nodes.emplace_back(this);
800
801 while (!nodes.empty())
802 {
803 const OctreeT<T>* node = nodes.back();
804 nodes.pop_back();
805
806 ocean_assert(node != nullptr);
807 ocean_assert(node->boundingBox_.isInside(scalarPoint, Scalar(maximalDistance)));
808
809 if (node->childNodes_[0] != nullptr)
810 {
811 for (unsigned int n = 0u; n < 8u; ++n)
812 {
813 const OctreeT<T>& childNode = *node->childNodes_[n];
814
815 if (childNode.isValid() && childNode.boundingBox_.isInside(scalarPoint, Scalar(maximalDistance)))
816 {
817 nodes.emplace_back(&childNode);
818 }
819 }
820 }
821 else
822 {
823 for (const Index32& pointIndex : node->pointIndices_)
824 {
825 const VectorT3<T>& treePoint = treePoints[pointIndex];
826
827 if (points != nullptr)
828 {
829 if (treePoint.sqrDistance(queryPoint) <= maximalSqrDistance)
830 {
831 pointIndices.emplace_back(pointIndex);
832 points->emplace_back(treePoints[pointIndex]);
833 }
834 }
835 else
836 {
837 if (treePoint.sqrDistance(queryPoint) <= maximalSqrDistance)
838 {
839 pointIndices.emplace_back(pointIndex);
840 }
841 }
842 }
843 }
844 }
845}
846
847template <typename T>
848inline bool OctreeT<T>::isValid() const
849{
850 return boundingBox_.isValid();
851}
852
853template <typename T>
855{
856 if (this != &octree)
857 {
858 boundingBox_ = octree.boundingBox_;
859 octree.boundingBox_ = BoundingBox();
860
861 pointIndices_ = std::move(octree.pointIndices_);
862
863 for (unsigned int n = 0u; n < 8u; ++n)
864 {
865 childNodes_[n] = octree.childNodes_[n];
866 octree.childNodes_[n] = nullptr;
867 }
868 }
869
870 return *this;
871}
872
873}
874
875}
876
877#endif // META_OCEAN_GEOMETRY_GRID_H
This class implements a 3D bounding box.
Definition BoundingBox.h:23
bool isInside(const VectorT3< T > &point, const T eps=T(0)) const
Returns whether a given point is inside this bounding box.
bool isValid() const
Returns whether the bounding box is valid.
VectorT3< T > center() const
Returns the center of the box.
const VectorT3< T > & higher() const
Returns the higher corner of the box.
bool hasIntersection(const LineT3< T > &ray) const
Returns whether a given ray has an intersection with this box.
const VectorT3< T > & lower() const
Returns the lower corner of the box.
This class stores construction parameters for an octree.
Definition Octree.h:65
bool useTightBoundingBoxes_
True, to use tight bounding boxes for each individual node (only covering the actual points); False,...
Definition Octree.h:92
bool isValid() const
Returns whether this object holds valid parameters.
Definition Octree.h:270
Parameters()=default
Default constructor.
unsigned int maximalPointsPerLeaf_
The maximal number of points each leaf node can have.
Definition Octree.h:89
Definition of a class which holds reusable data for internal use.
Definition Octree.h:111
std::vector< const OctreeT< T > * > internalData_
The internal reusable data.
Definition Octree.h:124
ReusableData()=default
Creates a new object.
Forward declaration.
Definition Octree.h:55
void closestLeafs(const VectorT3< T > &queryPoint, const T maximalDistance, std::vector< const Indices32 * > &leafs, const ReusableData &reusableData=ReusableData()) const
Returns the closest leaf nodes for a given query point.
Definition Octree.h:628
Indices32 pointIndices_
The indicies of the tree points which belong to this leaf node, empty if this node is not a leaf node...
Definition Octree.h:255
void intersectingLeafs(const LineT3< T > &queryRay, std::vector< const Indices32 * > &leafs, const ReusableData &reusableData=ReusableData()) const
Returns the intersecting leaf nodes for a given query ray.
Definition Octree.h:676
OctreeT< T > * childNodes_[8]
The eight child nodes.
Definition Octree.h:258
OctreeT(const OctreeT &octree)=delete
Disabled copy constructor.
OctreeT()=default
Default constructor creating an empty tree.
T Type
The data type of this octree.
Definition Octree.h:59
OctreeT & operator=(OctreeT &&octree)
Move operator.
Definition Octree.h:854
OctreeT & operator=(const OctreeT &octree)=delete
Disabled copy constructor.
const BoundingBox & boundingBox() const
Returns the bounding box containing all points of this node (of all points in all child leaf nodes)
Definition Octree.h:605
~OctreeT()
Destructs this tree node.
Definition Octree.h:596
void closestPoints(const VectorT3< T > *treePoints, const VectorT3< T > &queryPoint, const T maximalDistance, Indices32 &pointIndices, VectorsT3< T > *points=nullptr, const ReusableData &reusableData=ReusableData()) const
Returns the closest tree points for a given query point.
Definition Octree.h:777
BoundingBox boundingBox_
The bounding box of this tree node.
Definition Octree.h:252
const Indices32 & pointIndices() const
Returns the indices of the tree points which belong to this leaf node.
Definition Octree.h:611
const OctreeT< T > *const * childNodes() const
Returns the eight child nodes of this tree node.
Definition Octree.h:617
bool isValid() const
Returns whether this node is valid (if this node has a valid bounding box)
Definition Octree.h:848
This class implements an infinite line in 3D space.
Definition Line3.h:68
bool isValid() const
Returns whether this line has valid parameters.
Definition Line3.h:301
This class implements a vector with three elements.
Definition Vector3.h:97
const T & y() const noexcept
Returns the y value.
Definition Vector3.h:824
const T & x() const noexcept
Returns the x value.
Definition Vector3.h:812
const T & z() const noexcept
Returns the z value.
Definition Vector3.h:836
const T * data() const noexcept
Returns an pointer to the vector elements.
Definition Vector3.h:854
T sqrDistance(const VectorT3< T > &right) const
Returns the square distance between this 3D position and a second 3D position.
Definition Vector3.h:694
std::vector< Index32 > Indices32
Definition of a vector holding 32 bit index values.
Definition Base.h:96
uint32_t Index32
Definition of a 32 bit index value.
Definition Base.h:84
OctreeT< double > OctreeD
Definition of an Octree using double as data type.
Definition Octree.h:39
OctreeT< float > OctreeF
Definition of an Octree using float as data type.
Definition Octree.h:46
OctreeT< Scalar > Octree
Definition of an Octree using Scalar as data type.
Definition Octree.h:32
float Scalar
Definition of a scalar type.
Definition Math.h:129
VectorT3< Scalar > Vector3
Definition of a 3D vector.
Definition Vector3.h:29
std::vector< VectorT3< T > > VectorsT3
Definition of a typename alias for vectors with VectorT3 objects.
Definition Vector3.h:58
The namespace covering the entire Ocean framework.
Definition Accessor.h:15