OpenVDB 12.0.0
 
Loading...
Searching...
No Matches
PointIndexGrid.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3
4/// @file PointIndexGrid.h
5///
6/// @brief Space-partitioning acceleration structure for points. Partitions
7/// the points into voxels to accelerate range and nearest neighbor
8/// searches.
9///
10/// @note Leaf nodes store a single point-index array and the voxels are only
11/// integer offsets into that array. The actual points are never stored
12/// in the acceleration structure, only offsets into an external array.
13///
14/// @author Mihai Alden
15
16#ifndef OPENVDB_TOOLS_POINT_INDEX_GRID_HAS_BEEN_INCLUDED
17#define OPENVDB_TOOLS_POINT_INDEX_GRID_HAS_BEEN_INCLUDED
18
19#include "PointPartitioner.h"
20
21#include <openvdb/thread/Threading.h>
22#include <openvdb/version.h>
23#include <openvdb/Exceptions.h>
24#include <openvdb/Grid.h>
25#include <openvdb/Types.h>
29#include <openvdb/tree/Tree.h>
30#include <openvdb/util/Assert.h>
31
32#include <tbb/blocked_range.h>
33#include <tbb/parallel_for.h>
34#include <atomic>
35#include <algorithm> // for std::min(), std::max()
36#include <cmath> // for std::sqrt()
37#include <deque>
38#include <iostream>
39#include <type_traits> // for std::is_same
40#include <utility> // for std::pair
41#include <vector>
42
43
44namespace openvdb {
46namespace OPENVDB_VERSION_NAME {
47
48namespace tree {
49template<Index, typename> struct SameLeafConfig; // forward declaration
50}
51
52namespace tools {
53
54template<typename T, Index Log2Dim> struct PointIndexLeafNode; // forward declaration
55
56/// Point index tree configured to match the default OpenVDB tree configuration
59
60/// Point index grid
62
63
64////////////////////////////////////////
65
66
67/// @interface PointArray
68/// Expected interface for the PointArray container:
69/// @code
70/// template<typename VectorType>
71/// struct PointArray
72/// {
73/// // The type used to represent world-space point positions
74/// using PosType = VectorType;
75///
76/// // Return the number of points in the array
77/// size_t size() const;
78///
79/// // Return the world-space position of the nth point in the array.
80/// void getPos(size_t n, PosType& xyz) const;
81/// };
82/// @endcode
83
84
85////////////////////////////////////////
86
87
88/// @brief Partition points into a point index grid to accelerate range and
89/// nearest-neighbor searches.
90///
91/// @param points world-space point array conforming to the PointArray interface
92/// @param voxelSize voxel size in world units
93template<typename GridT, typename PointArrayT>
94inline typename GridT::Ptr
95createPointIndexGrid(const PointArrayT& points, double voxelSize);
96
97
98/// @brief Partition points into a point index grid to accelerate range and
99/// nearest-neighbor searches.
100///
101/// @param points world-space point array conforming to the PointArray interface
102/// @param xform world-to-index-space transform
103template<typename GridT, typename PointArrayT>
104inline typename GridT::Ptr
105createPointIndexGrid(const PointArrayT& points, const math::Transform& xform);
106
107
108/// @brief Return @c true if the given point index grid represents a valid partitioning
109/// of the given point array.
110///
111/// @param points world-space point array conforming to the PointArray interface
112/// @param grid point index grid to validate
113template<typename PointArrayT, typename GridT>
114inline bool
115isValidPartition(const PointArrayT& points, const GridT& grid);
116
117
118/// Repartition the @a points if needed, otherwise return the input @a grid.
119template<typename GridT, typename PointArrayT>
120inline typename GridT::ConstPtr
121getValidPointIndexGrid(const PointArrayT& points, const typename GridT::ConstPtr& grid);
122
123/// Repartition the @a points if needed, otherwise return the input @a grid.
124template<typename GridT, typename PointArrayT>
125inline typename GridT::Ptr
126getValidPointIndexGrid(const PointArrayT& points, const typename GridT::Ptr& grid);
127
128
129////////////////////////////////////////
130
131
132/// Accelerated range and nearest-neighbor searches for point index grids
133template<typename TreeType = PointIndexTree>
135{
137 using LeafNodeType = typename TreeType::LeafNodeType;
138 using ValueType = typename TreeType::ValueType;
139
140
144
145
146 /// @brief Construct an iterator over the indices of the points contained in voxel (i, j, k).
147 /// @param ijk the voxel containing the points over which to iterate
148 /// @param acc an accessor for the grid or tree that holds the point indices
150
151
152 /// @brief Construct an iterator over the indices of the points contained in
153 /// the given bounding box.
154 /// @param bbox the bounding box of the voxels containing the points over which to iterate
155 /// @param acc an accessor for the grid or tree that holds the point indices
156 /// @note The range of the @a bbox is inclusive. Thus, a bounding box with
157 /// min = max is not empty but rather encloses a single voxel.
159
160
161 /// @brief Clear the iterator and update it with the result of the given voxel query.
162 /// @param ijk the voxel containing the points over which to iterate
163 /// @param acc an accessor for the grid or tree that holds the point indices
164 void searchAndUpdate(const Coord& ijk, ConstAccessor& acc);
165
166
167 /// @brief Clear the iterator and update it with the result of the given voxel region query.
168 /// @param bbox the bounding box of the voxels containing the points over which to iterate
169 /// @param acc an accessor for the grid or tree that holds the point indices
170 /// @note The range of the @a bbox is inclusive. Thus, a bounding box with
171 /// min = max is not empty but rather encloses a single voxel.
172 void searchAndUpdate(const CoordBBox& bbox, ConstAccessor& acc);
173
174
175 /// @brief Clear the iterator and update it with the result of the given
176 /// index-space bounding box query.
177 /// @param bbox index-space bounding box
178 /// @param acc an accessor for the grid or tree that holds the point indices
179 /// @param points world-space point array conforming to the PointArray interface
180 /// @param xform linear, uniform-scale transform (i.e., cubical voxels)
181 template<typename PointArray>
182 void searchAndUpdate(const BBoxd& bbox, ConstAccessor& acc,
183 const PointArray& points, const math::Transform& xform);
184
185
186 /// @brief Clear the iterator and update it with the result of the given
187 /// index-space radial query.
188 /// @param center index-space center
189 /// @param radius index-space radius
190 /// @param acc an accessor for the grid or tree that holds the point indices
191 /// @param points world-space point array conforming to the PointArray interface
192 /// @param xform linear, uniform-scale transform (i.e., cubical voxels)
193 /// @param subvoxelAccuracy if true, check individual points against the search region,
194 /// otherwise return all points that reside in voxels that are inside
195 /// or intersect the search region
196 template<typename PointArray>
197 void searchAndUpdate(const Vec3d& center, double radius, ConstAccessor& acc,
198 const PointArray& points, const math::Transform& xform, bool subvoxelAccuracy = true);
199
200
201 /// @brief Clear the iterator and update it with the result of the given
202 /// world-space bounding box query.
203 /// @param bbox world-space bounding box
204 /// @param acc an accessor for the grid or tree that holds the point indices
205 /// @param points world-space point array conforming to the PointArray interface
206 /// @param xform linear, uniform-scale transform (i.e., cubical voxels)
207 template<typename PointArray>
209 const PointArray& points, const math::Transform& xform);
210
211
212 /// @brief Clear the iterator and update it with the result of the given
213 /// world-space radial query.
214 /// @param center world-space center
215 /// @param radius world-space radius
216 /// @param acc an accessor for the grid or tree that holds the point indices
217 /// @param points world-space point array conforming to the PointArray interface
218 /// @param xform linear, uniform-scale transform (i.e., cubical voxels)
219 /// @param subvoxelAccuracy if true, check individual points against the search region,
220 /// otherwise return all points that reside in voxels that are inside
221 /// or intersect the search region
222 template<typename PointArray>
223 void worldSpaceSearchAndUpdate(const Vec3d& center, double radius, ConstAccessor& acc,
224 const PointArray& points, const math::Transform& xform, bool subvoxelAccuracy = true);
225
226
227 /// Reset the iterator to point to the first item.
228 void reset();
229
230 /// Return a const reference to the item to which this iterator is pointing.
231 const ValueType& operator*() const { return *mRange.first; }
232
233 /// @{
234 /// @brief Return @c true if this iterator is not yet exhausted.
235 bool test() const { return mRange.first < mRange.second || mIter != mRangeList.end(); }
236 operator bool() const { return this->test(); }
237 /// @}
238
239 /// Advance iterator to next item.
240 void increment();
241
242 /// Advance iterator to next item.
243 void operator++() { this->increment(); }
244
245
246 /// @brief Advance iterator to next item.
247 /// @return @c true if this iterator is not yet exhausted.
248 bool next();
249
250 /// Return the number of point indices in the iterator range.
251 size_t size() const;
252
253 /// Return @c true if both iterators point to the same element.
254 bool operator==(const PointIndexIterator& p) const { return mRange.first == p.mRange.first; }
255 bool operator!=(const PointIndexIterator& p) const { return !this->operator==(p); }
256
257
258private:
259 using Range = std::pair<const ValueType*, const ValueType*>;
260 using RangeDeque = std::deque<Range>;
261 using RangeDequeCIter = typename RangeDeque::const_iterator;
262 using IndexArray = std::unique_ptr<ValueType[]>;
263
264 void clear();
265
266 // Primary index collection
267 Range mRange;
268 RangeDeque mRangeList;
269 RangeDequeCIter mIter;
270 // Secondary index collection
271 IndexArray mIndexArray;
272 size_t mIndexArraySize;
273}; // struct PointIndexIterator
274
275
276/// @brief Selectively extract and filter point data using a custom filter operator.
277///
278/// @par FilterType example:
279/// @interface FilterType
280/// @code
281/// template<typename T>
282/// struct WeightedAverageAccumulator {
283/// using ValueType = T;
284///
285/// WeightedAverageAccumulator(T const * const array, const T radius)
286/// : mValues(array), mInvRadius(1.0/radius), mWeightSum(0.0), mValueSum(0.0) {}
287///
288/// void reset() { mWeightSum = mValueSum = T(0.0); }
289///
290/// // the following method is invoked by the PointIndexFilter
291/// void operator()(const T distSqr, const size_t pointIndex) {
292/// const T weight = T(1.0) - openvdb::math::Sqrt(distSqr) * mInvRadius;
293/// mWeightSum += weight;
294/// mValueSum += weight * mValues[pointIndex];
295/// }
296///
297/// T result() const { return mWeightSum > T(0.0) ? mValueSum / mWeightSum : T(0.0); }
298///
299/// private:
300/// T const * const mValues;
301/// const T mInvRadius;
302/// T mWeightSum, mValueSum;
303/// }; // struct WeightedAverageAccumulator
304/// @endcode
305template<typename PointArray, typename TreeType = PointIndexTree>
307{
308 using PosType = typename PointArray::PosType;
309 using ScalarType = typename PosType::value_type;
311
312 /// @brief Constructor
313 /// @param points world-space point array conforming to the PointArray interface
314 /// @param tree a point index tree
315 /// @param xform linear, uniform-scale transform (i.e., cubical voxels)
316 PointIndexFilter(const PointArray& points, const TreeType& tree, const math::Transform& xform);
317
318 /// Thread safe copy constructor
320
321 /// @brief Perform a radial search query and apply the given filter
322 /// operator to the selected points.
323 /// @param center world-space center
324 /// @param radius world-space radius
325 /// @param op custom filter operator (see the FilterType example for interface details)
326 template<typename FilterType>
327 void searchAndApply(const PosType& center, ScalarType radius, FilterType& op);
328
329private:
330 PointArray const * const mPoints;
331 ConstAccessor mAcc;
332 const math::Transform mXform;
333 const ScalarType mInvVoxelSize;
335}; // struct PointIndexFilter
336
337
338////////////////////////////////////////
339
340// Internal operators and implementation details
341
342/// @cond OPENVDB_DOCS_INTERNAL
343
344namespace point_index_grid_internal {
345
346template<typename PointArrayT>
347struct ValidPartitioningOp
348{
349 ValidPartitioningOp(std::atomic<bool>& hasChanged,
350 const PointArrayT& points, const math::Transform& xform)
351 : mPoints(&points)
352 , mTransform(&xform)
353 , mHasChanged(&hasChanged)
354 {
355 }
356
357 template <typename LeafT>
358 void operator()(LeafT &leaf, size_t /*leafIndex*/) const
359 {
360 if ((*mHasChanged)) {
361 thread::cancelGroupExecution();
362 return;
363 }
364
365 using IndexArrayT = typename LeafT::IndexArray;
366 using IndexT = typename IndexArrayT::value_type;
367 using PosType = typename PointArrayT::PosType;
368
369 typename LeafT::ValueOnCIter iter;
370 Coord voxelCoord;
371 PosType point;
372
373 const IndexT
374 *begin = static_cast<IndexT*>(nullptr),
375 *end = static_cast<IndexT*>(nullptr);
376
377 for (iter = leaf.cbeginValueOn(); iter; ++iter) {
378
379 if ((*mHasChanged)) break;
380
381 voxelCoord = iter.getCoord();
382 leaf.getIndices(iter.pos(), begin, end);
383
384 while (begin < end) {
385
386 mPoints->getPos(*begin, point);
387 if (voxelCoord != mTransform->worldToIndexCellCentered(point)) {
388 mHasChanged->store(true);
389 break;
390 }
391
392 ++begin;
393 }
394 }
395 }
396
397private:
398 PointArrayT const * const mPoints;
399 math::Transform const * const mTransform;
400 std::atomic<bool> * const mHasChanged;
401};
402
403
404template<typename LeafNodeT>
405struct PopulateLeafNodesOp
406{
407 using IndexT = uint32_t;
408 using Partitioner = PointPartitioner<IndexT, LeafNodeT::LOG2DIM>;
409
410 PopulateLeafNodesOp(std::unique_ptr<LeafNodeT*[]>& leafNodes,
411 const Partitioner& partitioner)
412 : mLeafNodes(leafNodes.get())
413 , mPartitioner(&partitioner)
414 {
415 }
416
417 void operator()(const tbb::blocked_range<size_t>& range) const {
418
419 using VoxelOffsetT = typename Partitioner::VoxelOffsetType;
420
421 size_t maxPointCount = 0;
422 for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
423 maxPointCount = std::max(maxPointCount, mPartitioner->indices(n).size());
424 }
425
426 const IndexT voxelCount = LeafNodeT::SIZE;
427
428 // allocate histogram buffers
429 std::unique_ptr<VoxelOffsetT[]> offsets{new VoxelOffsetT[maxPointCount]};
430 std::unique_ptr<IndexT[]> histogram{new IndexT[voxelCount]};
431
432 VoxelOffsetT const * const voxelOffsets = mPartitioner->voxelOffsets().get();
433
434 for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
435
436 LeafNodeT* node = new LeafNodeT();
437 node->setOrigin(mPartitioner->origin(n));
438
439 typename Partitioner::IndexIterator it = mPartitioner->indices(n);
440
441 const size_t pointCount = it.size();
442 IndexT const * const indices = &*it;
443
444 // local copy of voxel offsets.
445 for (IndexT i = 0; i < pointCount; ++i) {
446 offsets[i] = voxelOffsets[ indices[i] ];
447 }
448
449 // compute voxel-offset histogram
450 memset(&histogram[0], 0, voxelCount * sizeof(IndexT));
451 for (IndexT i = 0; i < pointCount; ++i) {
452 ++histogram[ offsets[i] ];
453 }
454
455 typename LeafNodeT::NodeMaskType& mask = node->getValueMask();
456 typename LeafNodeT::Buffer& buffer = node->buffer();
457
458 // scan histogram (all-prefix-sums)
459 IndexT count = 0, startOffset;
460 for (int i = 0; i < int(voxelCount); ++i) {
461 if (histogram[i] > 0) {
462 startOffset = count;
463 count += histogram[i];
464 histogram[i] = startOffset;
465 mask.setOn(i);
466 }
467 buffer.setValue(i, count);
468 }
469
470 // allocate point-index array
471 node->indices().resize(pointCount);
472 typename LeafNodeT::ValueType * const orderedIndices = node->indices().data();
473
474 // rank and permute
475 for (IndexT i = 0; i < pointCount; ++i) {
476 orderedIndices[ histogram[ offsets[i] ]++ ] = indices[i];
477 }
478
479 mLeafNodes[n] = node;
480 }
481 }
482
483 //////////
484
485 LeafNodeT* * const mLeafNodes;
486 Partitioner const * const mPartitioner;
487};
488
489
490/// Construct a @c PointIndexTree
491template<typename TreeType, typename PointArray>
492inline void
493constructPointTree(TreeType& tree, const math::Transform& xform, const PointArray& points)
494{
495 using LeafType = typename TreeType::LeafNodeType;
496
497 std::unique_ptr<LeafType*[]> leafNodes;
498 size_t leafNodeCount = 0;
499
500 {
501 // Important: Do not disable the cell-centered transform in the PointPartitioner.
502 // This interpretation is assumed in the PointIndexGrid and all related
503 // search algorithms.
504 PointPartitioner<uint32_t, LeafType::LOG2DIM> partitioner;
505 partitioner.construct(points, xform, /*voxelOrder=*/false, /*recordVoxelOffsets=*/true);
506
507 if (!partitioner.usingCellCenteredTransform()) {
508 OPENVDB_THROW(LookupError, "The PointIndexGrid requires a "
509 "cell-centered transform.");
510 }
511
512 leafNodeCount = partitioner.size();
513 leafNodes.reset(new LeafType*[leafNodeCount]);
514
515 const tbb::blocked_range<size_t> range(0, leafNodeCount);
516 tbb::parallel_for(range, PopulateLeafNodesOp<LeafType>(leafNodes, partitioner));
517 }
518
519 tree::ValueAccessor<TreeType> acc(tree);
520 for (size_t n = 0; n < leafNodeCount; ++n) {
521 acc.addLeaf(leafNodes[n]);
522 }
523}
524
525
526////////////////////////////////////////
527
528
529template<typename T>
530inline void
531dequeToArray(const std::deque<T>& d, std::unique_ptr<T[]>& a, size_t& size)
532{
533 size = d.size();
534 a.reset(new T[size]);
535 typename std::deque<T>::const_iterator it = d.begin(), itEnd = d.end();
536 T* item = a.get();
537 for ( ; it != itEnd; ++it, ++item) *item = *it;
538}
539
540
541inline void
542constructExclusiveRegions(std::vector<CoordBBox>& regions,
543 const CoordBBox& bbox, const CoordBBox& ibox)
544{
545 regions.clear();
546 regions.reserve(6);
547 Coord cmin = ibox.min();
548 Coord cmax = ibox.max();
549
550 // left-face bbox
551 regions.push_back(bbox);
552 regions.back().max().z() = cmin.z();
553
554 // right-face bbox
555 regions.push_back(bbox);
556 regions.back().min().z() = cmax.z();
557
558 --cmax.z(); // accounting for cell centered bucketing.
559 ++cmin.z();
560
561 // front-face bbox
562 regions.push_back(bbox);
563 CoordBBox* lastRegion = &regions.back();
564 lastRegion->min().z() = cmin.z();
565 lastRegion->max().z() = cmax.z();
566 lastRegion->max().x() = cmin.x();
567
568 // back-face bbox
569 regions.push_back(*lastRegion);
570 lastRegion = &regions.back();
571 lastRegion->min().x() = cmax.x();
572 lastRegion->max().x() = bbox.max().x();
573
574 --cmax.x();
575 ++cmin.x();
576
577 // bottom-face bbox
578 regions.push_back(*lastRegion);
579 lastRegion = &regions.back();
580 lastRegion->min().x() = cmin.x();
581 lastRegion->max().x() = cmax.x();
582 lastRegion->max().y() = cmin.y();
583
584 // top-face bbox
585 regions.push_back(*lastRegion);
586 lastRegion = &regions.back();
587 lastRegion->min().y() = cmax.y();
588 lastRegion->max().y() = bbox.max().y();
589}
590
591
592template<typename PointArray, typename IndexT>
593struct BBoxFilter
594{
595 using PosType = typename PointArray::PosType;
596 using ScalarType = typename PosType::value_type;
597 using Range = std::pair<const IndexT*, const IndexT*>;
598 using RangeDeque = std::deque<Range>;
599 using IndexDeque = std::deque<IndexT>;
600
601 BBoxFilter(RangeDeque& ranges, IndexDeque& indices, const BBoxd& bbox,
602 const PointArray& points, const math::Transform& xform)
603 : mRanges(ranges)
604 , mIndices(indices)
605 , mRegion(bbox)
606 , mPoints(points)
607 , mMap(*xform.baseMap())
608 {
609 }
610
611 template <typename LeafNodeType>
612 void filterLeafNode(const LeafNodeType& leaf)
613 {
614 typename LeafNodeType::ValueOnCIter iter;
615 const IndexT
616 *begin = static_cast<IndexT*>(nullptr),
617 *end = static_cast<IndexT*>(nullptr);
618 for (iter = leaf.cbeginValueOn(); iter; ++iter) {
619 leaf.getIndices(iter.pos(), begin, end);
620 filterVoxel(iter.getCoord(), begin, end);
621 }
622 }
623
624 void filterVoxel(const Coord&, const IndexT* begin, const IndexT* end)
625 {
626 PosType vec;
627
628 for (; begin < end; ++begin) {
629 mPoints.getPos(*begin, vec);
630
631 if (mRegion.isInside(mMap.applyInverseMap(vec))) {
632 mIndices.push_back(*begin);
633 }
634 }
635 }
636
637private:
638 RangeDeque& mRanges;
639 IndexDeque& mIndices;
640 const BBoxd mRegion;
641 const PointArray& mPoints;
642 const math::MapBase& mMap;
643};
644
645
646template<typename PointArray, typename IndexT>
647struct RadialRangeFilter
648{
649 using PosType = typename PointArray::PosType;
650 using ScalarType = typename PosType::value_type;
651 using Range = std::pair<const IndexT*, const IndexT*>;
652 using RangeDeque = std::deque<Range>;
653 using IndexDeque = std::deque<IndexT>;
654
655 RadialRangeFilter(RangeDeque& ranges, IndexDeque& indices, const Vec3d& xyz, double radius,
656 const PointArray& points, const math::Transform& xform,
657 const double leafNodeDim, const bool subvoxelAccuracy)
658 : mRanges(ranges)
659 , mIndices(indices)
660 , mCenter(xyz)
661 , mWSCenter(xform.indexToWorld(xyz))
662 , mVoxelDist1(ScalarType(0.0))
663 , mVoxelDist2(ScalarType(0.0))
664 , mLeafNodeDist1(ScalarType(0.0))
665 , mLeafNodeDist2(ScalarType(0.0))
666 , mWSRadiusSqr(ScalarType(radius * xform.voxelSize()[0]))
667 , mPoints(points)
668 , mSubvoxelAccuracy(subvoxelAccuracy)
669 {
670 const ScalarType voxelRadius = ScalarType(std::sqrt(3.0) * 0.5);
671 mVoxelDist1 = voxelRadius + ScalarType(radius);
672 mVoxelDist1 *= mVoxelDist1;
673
674 if (radius > voxelRadius) {
675 mVoxelDist2 = ScalarType(radius) - voxelRadius;
676 mVoxelDist2 *= mVoxelDist2;
677 }
678
679 const ScalarType leafNodeRadius = ScalarType(leafNodeDim * std::sqrt(3.0) * 0.5);
680 mLeafNodeDist1 = leafNodeRadius + ScalarType(radius);
681 mLeafNodeDist1 *= mLeafNodeDist1;
682
683 if (radius > leafNodeRadius) {
684 mLeafNodeDist2 = ScalarType(radius) - leafNodeRadius;
685 mLeafNodeDist2 *= mLeafNodeDist2;
686 }
687
688 mWSRadiusSqr *= mWSRadiusSqr;
689 }
690
691 template <typename LeafNodeType>
692 void filterLeafNode(const LeafNodeType& leaf)
693 {
694 {
695 const Coord& ijk = leaf.origin();
696 PosType vec;
697 vec[0] = ScalarType(ijk[0]);
698 vec[1] = ScalarType(ijk[1]);
699 vec[2] = ScalarType(ijk[2]);
700 vec += ScalarType(LeafNodeType::DIM - 1) * 0.5;
701 vec -= mCenter;
702
703 const ScalarType dist = vec.lengthSqr();
704 if (dist > mLeafNodeDist1) return;
705
706 if (mLeafNodeDist2 > 0.0 && dist < mLeafNodeDist2) {
707 const IndexT* begin = &leaf.indices().front();
708 mRanges.push_back(Range(begin, begin + leaf.indices().size()));
709 return;
710 }
711 }
712
713 typename LeafNodeType::ValueOnCIter iter;
714 const IndexT
715 *begin = static_cast<IndexT*>(nullptr),
716 *end = static_cast<IndexT*>(nullptr);
717 for (iter = leaf.cbeginValueOn(); iter; ++iter) {
718 leaf.getIndices(iter.pos(), begin, end);
719 filterVoxel(iter.getCoord(), begin, end);
720 }
721 }
722
723 void filterVoxel(const Coord& ijk, const IndexT* begin, const IndexT* end)
724 {
725 PosType vec;
726
727 {
728 vec[0] = mCenter[0] - ScalarType(ijk[0]);
729 vec[1] = mCenter[1] - ScalarType(ijk[1]);
730 vec[2] = mCenter[2] - ScalarType(ijk[2]);
731
732 const ScalarType dist = vec.lengthSqr();
733 if (dist > mVoxelDist1) return;
734
735 if (!mSubvoxelAccuracy || (mVoxelDist2 > 0.0 && dist < mVoxelDist2)) {
736 if (!mRanges.empty() && mRanges.back().second == begin) {
737 mRanges.back().second = end;
738 } else {
739 mRanges.push_back(Range(begin, end));
740 }
741 return;
742 }
743 }
744
745
746 while (begin < end) {
747 mPoints.getPos(*begin, vec);
748 vec = mWSCenter - vec;
749
750 if (vec.lengthSqr() < mWSRadiusSqr) {
751 mIndices.push_back(*begin);
752 }
753 ++begin;
754 }
755 }
756
757private:
758 RangeDeque& mRanges;
759 IndexDeque& mIndices;
760 const PosType mCenter, mWSCenter;
761 ScalarType mVoxelDist1, mVoxelDist2, mLeafNodeDist1, mLeafNodeDist2, mWSRadiusSqr;
762 const PointArray& mPoints;
763 const bool mSubvoxelAccuracy;
764}; // struct RadialRangeFilter
765
766
767////////////////////////////////////////
768
769
770template<typename RangeFilterType, typename LeafNodeType>
771inline void
772filteredPointIndexSearchVoxels(RangeFilterType& filter,
773 const LeafNodeType& leaf, const Coord& min, const Coord& max)
774{
775 using PointIndexT = typename LeafNodeType::ValueType;
776 Index xPos(0), yPos(0), pos(0);
777 Coord ijk(0);
778
779 const PointIndexT* dataPtr = &leaf.indices().front();
780 PointIndexT beginOffset, endOffset;
781
782 for (ijk[0] = min[0]; ijk[0] <= max[0]; ++ijk[0]) {
783 xPos = (ijk[0] & (LeafNodeType::DIM - 1u)) << (2 * LeafNodeType::LOG2DIM);
784 for (ijk[1] = min[1]; ijk[1] <= max[1]; ++ijk[1]) {
785 yPos = xPos + ((ijk[1] & (LeafNodeType::DIM - 1u)) << LeafNodeType::LOG2DIM);
786 for (ijk[2] = min[2]; ijk[2] <= max[2]; ++ijk[2]) {
787 pos = yPos + (ijk[2] & (LeafNodeType::DIM - 1u));
788
789 beginOffset = (pos == 0 ? PointIndexT(0) : leaf.getValue(pos - 1));
790 endOffset = leaf.getValue(pos);
791
792 if (endOffset > beginOffset) {
793 filter.filterVoxel(ijk, dataPtr + beginOffset, dataPtr + endOffset);
794 }
795 }
796 }
797 }
798}
799
800
801template<typename RangeFilterType, typename ConstAccessor>
802inline void
803filteredPointIndexSearch(RangeFilterType& filter, ConstAccessor& acc, const CoordBBox& bbox)
804{
805 using LeafNodeType = typename ConstAccessor::TreeType::LeafNodeType;
806 Coord ijk(0), ijkMax(0), ijkA(0), ijkB(0);
807 const Coord leafMin = bbox.min() & ~(LeafNodeType::DIM - 1);
808 const Coord leafMax = bbox.max() & ~(LeafNodeType::DIM - 1);
809
810 for (ijk[0] = leafMin[0]; ijk[0] <= leafMax[0]; ijk[0] += LeafNodeType::DIM) {
811 for (ijk[1] = leafMin[1]; ijk[1] <= leafMax[1]; ijk[1] += LeafNodeType::DIM) {
812 for (ijk[2] = leafMin[2]; ijk[2] <= leafMax[2]; ijk[2] += LeafNodeType::DIM) {
813
814 if (const LeafNodeType* leaf = acc.probeConstLeaf(ijk)) {
815 ijkMax = ijk;
816 ijkMax.offset(LeafNodeType::DIM - 1);
817
818 // intersect leaf bbox with search region.
819 ijkA = Coord::maxComponent(bbox.min(), ijk);
820 ijkB = Coord::minComponent(bbox.max(), ijkMax);
821
822 if (ijkA != ijk || ijkB != ijkMax) {
823 filteredPointIndexSearchVoxels(filter, *leaf, ijkA, ijkB);
824 } else { // leaf bbox is inside the search region
825 filter.filterLeafNode(*leaf);
826 }
827 }
828 }
829 }
830 }
831}
832
833
834////////////////////////////////////////
835
836
837template<typename RangeDeque, typename LeafNodeType>
838inline void
839pointIndexSearchVoxels(RangeDeque& rangeList,
840 const LeafNodeType& leaf, const Coord& min, const Coord& max)
841{
842 using PointIndexT = typename LeafNodeType::ValueType;
843 using IntT = typename PointIndexT::IntType;
844 using Range = typename RangeDeque::value_type;
845
846 Index xPos(0), pos(0), zStride = Index(max[2] - min[2]);
847 const PointIndexT* dataPtr = &leaf.indices().front();
848 PointIndexT beginOffset(0), endOffset(0),
849 previousOffset(static_cast<IntT>(leaf.indices().size() + 1u));
850 Coord ijk(0);
851
852 for (ijk[0] = min[0]; ijk[0] <= max[0]; ++ijk[0]) {
853 xPos = (ijk[0] & (LeafNodeType::DIM - 1u)) << (2 * LeafNodeType::LOG2DIM);
854
855 for (ijk[1] = min[1]; ijk[1] <= max[1]; ++ijk[1]) {
856 pos = xPos + ((ijk[1] & (LeafNodeType::DIM - 1u)) << LeafNodeType::LOG2DIM);
857 pos += (min[2] & (LeafNodeType::DIM - 1u));
858
859 beginOffset = (pos == 0 ? PointIndexT(0) : leaf.getValue(pos - 1));
860 endOffset = leaf.getValue(pos+zStride);
861
862 if (endOffset > beginOffset) {
863
864 if (beginOffset == previousOffset) {
865 rangeList.back().second = dataPtr + endOffset;
866 } else {
867 rangeList.push_back(Range(dataPtr + beginOffset, dataPtr + endOffset));
868 }
869
870 previousOffset = endOffset;
871 }
872 }
873 }
874}
875
876
877template<typename RangeDeque, typename ConstAccessor>
878inline void
879pointIndexSearch(RangeDeque& rangeList, ConstAccessor& acc, const CoordBBox& bbox)
880{
881 using LeafNodeType = typename ConstAccessor::TreeType::LeafNodeType;
882 using PointIndexT = typename LeafNodeType::ValueType;
883 using Range = typename RangeDeque::value_type;
884
885 Coord ijk(0), ijkMax(0), ijkA(0), ijkB(0);
886 const Coord leafMin = bbox.min() & ~(LeafNodeType::DIM - 1);
887 const Coord leafMax = bbox.max() & ~(LeafNodeType::DIM - 1);
888
889 for (ijk[0] = leafMin[0]; ijk[0] <= leafMax[0]; ijk[0] += LeafNodeType::DIM) {
890 for (ijk[1] = leafMin[1]; ijk[1] <= leafMax[1]; ijk[1] += LeafNodeType::DIM) {
891 for (ijk[2] = leafMin[2]; ijk[2] <= leafMax[2]; ijk[2] += LeafNodeType::DIM) {
892
893 if (const LeafNodeType* leaf = acc.probeConstLeaf(ijk)) {
894 ijkMax = ijk;
895 ijkMax.offset(LeafNodeType::DIM - 1);
896
897 // intersect leaf bbox with search region.
898 ijkA = Coord::maxComponent(bbox.min(), ijk);
899 ijkB = Coord::minComponent(bbox.max(), ijkMax);
900
901 if (ijkA != ijk || ijkB != ijkMax) {
902 pointIndexSearchVoxels(rangeList, *leaf, ijkA, ijkB);
903 } else {
904 // leaf bbox is inside the search region, add all indices.
905 const PointIndexT* begin = &leaf->indices().front();
906 rangeList.push_back(Range(begin, (begin + leaf->indices().size())));
907 }
908 }
909 }
910 }
911 }
912}
913
914
915} // namespace point_index_grid_internal
916
917/// @endcond
918
919// PointIndexIterator implementation
920
921template<typename TreeType>
922inline
924 : mRange(static_cast<ValueType*>(nullptr), static_cast<ValueType*>(nullptr))
925 , mRangeList()
926 , mIter(mRangeList.begin())
927 , mIndexArray()
928 , mIndexArraySize(0)
929{
930}
931
932
933template<typename TreeType>
934inline
936 : mRange(rhs.mRange)
937 , mRangeList(rhs.mRangeList)
938 , mIter(mRangeList.begin())
939 , mIndexArray()
940 , mIndexArraySize(rhs.mIndexArraySize)
941{
942 if (rhs.mIndexArray) {
943 mIndexArray.reset(new ValueType[mIndexArraySize]);
944 memcpy(mIndexArray.get(), rhs.mIndexArray.get(), mIndexArraySize * sizeof(ValueType));
945 }
946}
947
948
949template<typename TreeType>
952{
953 if (&rhs != this) {
954 mRange = rhs.mRange;
955 mRangeList = rhs.mRangeList;
956 mIter = mRangeList.begin();
957 mIndexArray.reset();
958 mIndexArraySize = rhs.mIndexArraySize;
959
960 if (rhs.mIndexArray) {
961 mIndexArray.reset(new ValueType[mIndexArraySize]);
962 memcpy(mIndexArray.get(), rhs.mIndexArray.get(), mIndexArraySize * sizeof(ValueType));
963 }
964 }
965 return *this;
966}
967
968
969template<typename TreeType>
970inline
972 : mRange(static_cast<ValueType*>(nullptr), static_cast<ValueType*>(nullptr))
973 , mRangeList()
974 , mIter(mRangeList.begin())
975 , mIndexArray()
976 , mIndexArraySize(0)
977{
978 const LeafNodeType* leaf = acc.probeConstLeaf(ijk);
979 if (leaf && leaf->getIndices(ijk, mRange.first, mRange.second)) {
980 mRangeList.push_back(mRange);
981 mIter = mRangeList.begin();
982 }
983}
984
985
986template<typename TreeType>
987inline
989 : mRange(static_cast<ValueType*>(nullptr), static_cast<ValueType*>(nullptr))
990 , mRangeList()
991 , mIter(mRangeList.begin())
992 , mIndexArray()
993 , mIndexArraySize(0)
994{
995 point_index_grid_internal::pointIndexSearch(mRangeList, acc, bbox);
996
997 if (!mRangeList.empty()) {
998 mIter = mRangeList.begin();
999 mRange = mRangeList.front();
1000 }
1001}
1002
1003
1004template<typename TreeType>
1005inline void
1007{
1008 mIter = mRangeList.begin();
1009 if (!mRangeList.empty()) {
1010 mRange = mRangeList.front();
1011 } else if (mIndexArray) {
1012 mRange.first = mIndexArray.get();
1013 mRange.second = mRange.first + mIndexArraySize;
1014 } else {
1015 mRange.first = static_cast<ValueType*>(nullptr);
1016 mRange.second = static_cast<ValueType*>(nullptr);
1017 }
1018}
1019
1020
1021template<typename TreeType>
1022inline void
1024{
1025 ++mRange.first;
1026 if (mRange.first >= mRange.second && mIter != mRangeList.end()) {
1027 ++mIter;
1028 if (mIter != mRangeList.end()) {
1029 mRange = *mIter;
1030 } else if (mIndexArray) {
1031 mRange.first = mIndexArray.get();
1032 mRange.second = mRange.first + mIndexArraySize;
1033 }
1034 }
1035}
1036
1037
1038template<typename TreeType>
1039inline bool
1041{
1042 if (!this->test()) return false;
1043 this->increment();
1044 return this->test();
1045}
1046
1047
1048template<typename TreeType>
1049inline size_t
1051{
1052 size_t count = 0;
1053 typename RangeDeque::const_iterator it = mRangeList.begin();
1054
1055 for ( ; it != mRangeList.end(); ++it) {
1056 count += it->second - it->first;
1057 }
1058
1059 return count + mIndexArraySize;
1060}
1061
1062
1063template<typename TreeType>
1064inline void
1065PointIndexIterator<TreeType>::clear()
1066{
1067 mRange.first = static_cast<ValueType*>(nullptr);
1068 mRange.second = static_cast<ValueType*>(nullptr);
1069 mRangeList.clear();
1070 mIter = mRangeList.end();
1071 mIndexArray.reset();
1072 mIndexArraySize = 0;
1073}
1074
1075
1076template<typename TreeType>
1077inline void
1079{
1080 this->clear();
1081 const LeafNodeType* leaf = acc.probeConstLeaf(ijk);
1082 if (leaf && leaf->getIndices(ijk, mRange.first, mRange.second)) {
1083 mRangeList.push_back(mRange);
1084 mIter = mRangeList.begin();
1085 }
1086}
1087
1088
1089template<typename TreeType>
1090inline void
1092{
1093 this->clear();
1094 point_index_grid_internal::pointIndexSearch(mRangeList, acc, bbox);
1095
1096 if (!mRangeList.empty()) {
1097 mIter = mRangeList.begin();
1098 mRange = mRangeList.front();
1099 }
1100}
1101
1102
1103template<typename TreeType>
1104template<typename PointArray>
1105inline void
1107 const PointArray& points, const math::Transform& xform)
1108{
1109 this->clear();
1110
1111 std::vector<CoordBBox> searchRegions;
1112 CoordBBox region(Coord::round(bbox.min()), Coord::round(bbox.max()));
1113
1114 const Coord dim = region.dim();
1115 const int minExtent = std::min(dim[0], std::min(dim[1], dim[2]));
1116
1117 if (minExtent > 2) {
1118 // collect indices that don't need to be tested
1119 CoordBBox ibox = region;
1120 ibox.expand(-1);
1121
1122 point_index_grid_internal::pointIndexSearch(mRangeList, acc, ibox);
1123
1124 // define regions for the filtered search
1125 ibox.expand(1);
1126 point_index_grid_internal::constructExclusiveRegions(searchRegions, region, ibox);
1127 } else {
1128 searchRegions.push_back(region);
1129 }
1130
1131 // filtered search
1132 std::deque<ValueType> filteredIndices;
1133 point_index_grid_internal::BBoxFilter<PointArray, ValueType>
1134 filter(mRangeList, filteredIndices, bbox, points, xform);
1135
1136 for (size_t n = 0, N = searchRegions.size(); n < N; ++n) {
1137 point_index_grid_internal::filteredPointIndexSearch(filter, acc, searchRegions[n]);
1138 }
1139
1140 point_index_grid_internal::dequeToArray(filteredIndices, mIndexArray, mIndexArraySize);
1141
1142 this->reset();
1143}
1144
1145
1146template<typename TreeType>
1147template<typename PointArray>
1148inline void
1150 ConstAccessor& acc, const PointArray& points, const math::Transform& xform,
1151 bool subvoxelAccuracy)
1152{
1153 this->clear();
1154 std::vector<CoordBBox> searchRegions;
1155
1156 // bounding box
1157 CoordBBox bbox(
1158 Coord::round(Vec3d(center[0] - radius, center[1] - radius, center[2] - radius)),
1159 Coord::round(Vec3d(center[0] + radius, center[1] + radius, center[2] + radius)));
1160 bbox.expand(1);
1161
1162 const double iRadius = radius * double(1.0 / std::sqrt(3.0));
1163 if (iRadius > 2.0) {
1164 // inscribed box
1165 CoordBBox ibox(
1166 Coord::round(Vec3d(center[0] - iRadius, center[1] - iRadius, center[2] - iRadius)),
1167 Coord::round(Vec3d(center[0] + iRadius, center[1] + iRadius, center[2] + iRadius)));
1168 ibox.expand(-1);
1169
1170 // collect indices that don't need to be tested
1171 point_index_grid_internal::pointIndexSearch(mRangeList, acc, ibox);
1172
1173 ibox.expand(1);
1174 point_index_grid_internal::constructExclusiveRegions(searchRegions, bbox, ibox);
1175 } else {
1176 searchRegions.push_back(bbox);
1177 }
1178
1179 // filtered search
1180 std::deque<ValueType> filteredIndices;
1181 const double leafNodeDim = double(TreeType::LeafNodeType::DIM);
1182
1183 using FilterT = point_index_grid_internal::RadialRangeFilter<PointArray, ValueType>;
1184
1185 FilterT filter(mRangeList, filteredIndices,
1186 center, radius, points, xform, leafNodeDim, subvoxelAccuracy);
1187
1188 for (size_t n = 0, N = searchRegions.size(); n < N; ++n) {
1189 point_index_grid_internal::filteredPointIndexSearch(filter, acc, searchRegions[n]);
1190 }
1191
1192 point_index_grid_internal::dequeToArray(filteredIndices, mIndexArray, mIndexArraySize);
1193
1194 this->reset();
1195}
1196
1197
1198template<typename TreeType>
1199template<typename PointArray>
1200inline void
1202 const PointArray& points, const math::Transform& xform)
1203{
1204 this->searchAndUpdate(
1205 BBoxd(xform.worldToIndex(bbox.min()), xform.worldToIndex(bbox.max())), acc, points, xform);
1206}
1207
1208
1209template<typename TreeType>
1210template<typename PointArray>
1211inline void
1213 ConstAccessor& acc, const PointArray& points, const math::Transform& xform,
1214 bool subvoxelAccuracy)
1215{
1216 this->searchAndUpdate(xform.worldToIndex(center),
1217 (radius / xform.voxelSize()[0]), acc, points, xform, subvoxelAccuracy);
1218}
1219
1220
1221////////////////////////////////////////
1222
1223// PointIndexFilter implementation
1224
1225template<typename PointArray, typename TreeType>
1226inline
1228 const PointArray& points, const TreeType& tree, const math::Transform& xform)
1229 : mPoints(&points), mAcc(tree), mXform(xform), mInvVoxelSize(1.0/xform.voxelSize()[0])
1230{
1231}
1232
1233
1234template<typename PointArray, typename TreeType>
1235inline
1237 : mPoints(rhs.mPoints)
1238 , mAcc(rhs.mAcc.tree())
1239 , mXform(rhs.mXform)
1240 , mInvVoxelSize(rhs.mInvVoxelSize)
1241{
1242}
1243
1244
1245template<typename PointArray, typename TreeType>
1246template<typename FilterType>
1247inline void
1249 const PosType& center, ScalarType radius, FilterType& op)
1250{
1251 if (radius * mInvVoxelSize < ScalarType(8.0)) {
1252 mIter.searchAndUpdate(openvdb::CoordBBox(
1253 mXform.worldToIndexCellCentered(center - radius),
1254 mXform.worldToIndexCellCentered(center + radius)), mAcc);
1255 } else {
1256 mIter.worldSpaceSearchAndUpdate(
1257 center, radius, mAcc, *mPoints, mXform, /*subvoxelAccuracy=*/false);
1258 }
1259
1260 const ScalarType radiusSqr = radius * radius;
1261 ScalarType distSqr = 0.0;
1262 PosType pos;
1263 for (; mIter; ++mIter) {
1264 mPoints->getPos(*mIter, pos);
1265 pos -= center;
1266 distSqr = pos.lengthSqr();
1267
1268 if (distSqr < radiusSqr) {
1269 op(distSqr, *mIter);
1270 }
1271 }
1272}
1273
1274
1275////////////////////////////////////////
1276
1277
1278template<typename GridT, typename PointArrayT>
1279inline typename GridT::Ptr
1280createPointIndexGrid(const PointArrayT& points, const math::Transform& xform)
1281{
1282 typename GridT::Ptr grid = GridT::create(typename GridT::ValueType(0));
1283 grid->setTransform(xform.copy());
1284
1285 if (points.size() > 0) {
1286 point_index_grid_internal::constructPointTree(
1287 grid->tree(), grid->transform(), points);
1288 }
1289
1290 return grid;
1291}
1292
1293
1294template<typename GridT, typename PointArrayT>
1295inline typename GridT::Ptr
1296createPointIndexGrid(const PointArrayT& points, double voxelSize)
1297{
1299 return createPointIndexGrid<GridT>(points, *xform);
1300}
1301
1302
1303template<typename PointArrayT, typename GridT>
1304inline bool
1305isValidPartition(const PointArrayT& points, const GridT& grid)
1306{
1308
1309 size_t pointCount = 0;
1310 for (size_t n = 0, N = leafs.leafCount(); n < N; ++n) {
1311 pointCount += leafs.leaf(n).indices().size();
1312 }
1313
1314 if (points.size() != pointCount) {
1315 return false;
1316 }
1317
1318 std::atomic<bool> changed;
1319 changed = false;
1320
1321 point_index_grid_internal::ValidPartitioningOp<PointArrayT>
1322 op(changed, points, grid.transform());
1323
1324 leafs.foreach(op);
1325
1326 return !bool(changed);
1327}
1328
1329
1330template<typename GridT, typename PointArrayT>
1331inline typename GridT::ConstPtr
1332getValidPointIndexGrid(const PointArrayT& points, const typename GridT::ConstPtr& grid)
1333{
1334 if (isValidPartition(points, *grid)) {
1335 return grid;
1336 }
1337
1338 return createPointIndexGrid<GridT>(points, grid->transform());
1339}
1340
1341
1342template<typename GridT, typename PointArrayT>
1343inline typename GridT::Ptr
1344getValidPointIndexGrid(const PointArrayT& points, const typename GridT::Ptr& grid)
1345{
1346 if (isValidPartition(points, *grid)) {
1347 return grid;
1348 }
1349
1350 return createPointIndexGrid<GridT>(points, grid->transform());
1351}
1352
1353
1354////////////////////////////////////////
1355
1356
1357template<typename T, Index Log2Dim>
1358struct PointIndexLeafNode : public tree::LeafNode<T, Log2Dim>
1359{
1362
1363 using ValueType = T;
1364 using IndexArray = std::vector<ValueType>;
1365
1366
1367 IndexArray& indices() { return mIndices; }
1368 const IndexArray& indices() const { return mIndices; }
1369
1370 bool getIndices(const Coord& ijk, const ValueType*& begin, const ValueType*& end) const;
1371 bool getIndices(Index offset, const ValueType*& begin, const ValueType*& end) const;
1372
1373 void setOffsetOn(Index offset, const ValueType& val);
1374 void setOffsetOnly(Index offset, const ValueType& val);
1375
1376 bool isEmpty(const CoordBBox& bbox) const;
1377
1378private:
1379 IndexArray mIndices;
1380
1381 ////////////////////////////////////////
1382
1383 // The following methods had to be copied from the LeafNode class
1384 // to make the derived PointIndexLeafNode class compatible with the tree structure.
1385
1386public:
1389
1390 using BaseLeaf::LOG2DIM;
1391 using BaseLeaf::TOTAL;
1392 using BaseLeaf::DIM;
1395 using BaseLeaf::SIZE;
1396 using BaseLeaf::LEVEL;
1397
1398 /// Default constructor
1399 PointIndexLeafNode() : BaseLeaf(), mIndices() {}
1400
1401 explicit
1402 PointIndexLeafNode(const Coord& coords, const T& value = zeroVal<T>(), bool active = false)
1403 : BaseLeaf(coords, value, active)
1404 , mIndices()
1405 {
1406 }
1407
1409 const T& value = zeroVal<T>(), bool active = false)
1410 : BaseLeaf(PartialCreate(), coords, value, active)
1411 , mIndices()
1412 {
1413 }
1414
1415 /// Deep copy constructor
1416 PointIndexLeafNode(const PointIndexLeafNode& rhs) : BaseLeaf(rhs), mIndices(rhs.mIndices) {}
1417
1418 /// @brief Return @c true if the given node (which may have a different @c ValueType
1419 /// than this node) has the same active value topology as this node.
1420 template<typename OtherType, Index OtherLog2Dim>
1424
1425 /// Check for buffer, state and origin equivalence.
1426 bool operator==(const PointIndexLeafNode& other) const { return BaseLeaf::operator==(other); }
1427
1428 bool operator!=(const PointIndexLeafNode& other) const { return !(other == *this); }
1429
1430 template<MergePolicy Policy> void merge(const PointIndexLeafNode& rhs) {
1431 BaseLeaf::template merge<Policy>(rhs);
1432 }
1433 template<MergePolicy Policy> void merge(const ValueType& tileValue, bool tileActive) {
1434 BaseLeaf::template merge<Policy>(tileValue, tileActive);
1435 }
1436
1437 template<MergePolicy Policy>
1438 void merge(const PointIndexLeafNode& other,
1439 const ValueType& /*bg*/, const ValueType& /*otherBG*/)
1440 {
1441 BaseLeaf::template merge<Policy>(other);
1442 }
1443
1445 template<typename AccessorT>
1447
1448 //@{
1449 /// @brief Return a pointer to this node.
1450 PointIndexLeafNode* touchLeaf(const Coord&) { return this; }
1451 template<typename AccessorT>
1452 PointIndexLeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; }
1453
1454 template<typename NodeT, typename AccessorT>
1455 NodeT* probeNodeAndCache(const Coord&, AccessorT&)
1456 {
1458 if (!(std::is_same<NodeT, PointIndexLeafNode>::value)) return nullptr;
1459 return reinterpret_cast<NodeT*>(this);
1461 }
1462 PointIndexLeafNode* probeLeaf(const Coord&) { return this; }
1463 template<typename AccessorT>
1464 PointIndexLeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; }
1465 //@}
1466
1467 //@{
1468 /// @brief Return a @const pointer to this node.
1469 const PointIndexLeafNode* probeConstLeaf(const Coord&) const { return this; }
1470 template<typename AccessorT>
1471 const PointIndexLeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const {return this;}
1472 template<typename AccessorT>
1473 const PointIndexLeafNode* probeLeafAndCache(const Coord&, AccessorT&) const { return this; }
1474 const PointIndexLeafNode* probeLeaf(const Coord&) const { return this; }
1475 template<typename NodeT, typename AccessorT>
1476 const NodeT* probeConstNodeAndCache(const Coord&, AccessorT&) const
1477 {
1479 if (!(std::is_same<NodeT, PointIndexLeafNode>::value)) return nullptr;
1480 return reinterpret_cast<const NodeT*>(this);
1482 }
1483 //@}
1484
1485
1486 // I/O methods
1487
1488 void readBuffers(std::istream& is, bool fromHalf = false);
1489 void readBuffers(std::istream& is, const CoordBBox&, bool fromHalf = false);
1490 void writeBuffers(std::ostream& os, bool toHalf = false) const;
1491
1492
1493 Index64 memUsage() const;
1494 Index64 memUsageIfLoaded() const;
1495
1496
1497 ////////////////////////////////////////
1498
1499 // Disable all write methods to avoid unintentional changes
1500 // to the point-array offsets.
1501
1503 OPENVDB_ASSERT(false && "Cannot modify voxel values in a PointIndexTree.");
1504 }
1505
1506 void setActiveState(const Coord&, bool) { assertNonmodifiable(); }
1508
1511
1514
1517
1520
1521 void setValueOn(const Coord&, const ValueType&) { assertNonmodifiable(); }
1523
1524 void setValue(const Coord&, const ValueType&) { assertNonmodifiable(); }
1525
1528
1529 template<typename ModifyOp>
1530 void modifyValue(Index, const ModifyOp&) { assertNonmodifiable(); }
1531
1532 template<typename ModifyOp>
1533 void modifyValue(const Coord&, const ModifyOp&) { assertNonmodifiable(); }
1534
1535 template<typename ModifyOp>
1536 void modifyValueAndActiveState(const Coord&, const ModifyOp&) { assertNonmodifiable(); }
1537
1538 void clip(const CoordBBox&, const ValueType&) { assertNonmodifiable(); }
1539
1540 void fill(const CoordBBox&, const ValueType&, bool) { assertNonmodifiable(); }
1541 void fill(const ValueType&) {}
1542 void fill(const ValueType&, bool) { assertNonmodifiable(); }
1543
1544 template<typename AccessorT>
1545 void setValueOnlyAndCache(const Coord&, const ValueType&, AccessorT&) {assertNonmodifiable();}
1546
1547 template<typename ModifyOp, typename AccessorT>
1548 void modifyValueAndActiveStateAndCache(const Coord&, const ModifyOp&, AccessorT&) {
1550 }
1551
1552 template<typename AccessorT>
1553 void setValueOffAndCache(const Coord&, const ValueType&, AccessorT&) { assertNonmodifiable(); }
1554
1555 template<typename AccessorT>
1556 void setActiveStateAndCache(const Coord&, bool, AccessorT&) { assertNonmodifiable(); }
1557
1559
1562
1564
1565protected:
1566 using ValueOn = typename BaseLeaf::ValueOn;
1569 using ChildOn = typename BaseLeaf::ChildOn;
1572
1576
1577 // During topology-only construction, access is needed
1578 // to protected/private members of other template instances.
1579 template<typename, Index> friend struct PointIndexLeafNode;
1580
1584
1585public:
1586 using ValueOnIter = typename BaseLeaf::template ValueIter<
1588 using ValueOnCIter = typename BaseLeaf::template ValueIter<
1590 using ValueOffIter = typename BaseLeaf::template ValueIter<
1592 using ValueOffCIter = typename BaseLeaf::template ValueIter<
1594 using ValueAllIter = typename BaseLeaf::template ValueIter<
1596 using ValueAllCIter = typename BaseLeaf::template ValueIter<
1598 using ChildOnIter = typename BaseLeaf::template ChildIter<
1600 using ChildOnCIter = typename BaseLeaf::template ChildIter<
1602 using ChildOffIter = typename BaseLeaf::template ChildIter<
1604 using ChildOffCIter = typename BaseLeaf::template ChildIter<
1606 using ChildAllIter = typename BaseLeaf::template DenseIter<
1608 using ChildAllCIter = typename BaseLeaf::template DenseIter<
1609 const PointIndexLeafNode, const ValueType, ChildAll>;
1610
1611#define VMASK_ this->getValueMask()
1612 ValueOnCIter cbeginValueOn() const { return ValueOnCIter(VMASK_.beginOn(), this); }
1613 ValueOnCIter beginValueOn() const { return ValueOnCIter(VMASK_.beginOn(), this); }
1614 ValueOnIter beginValueOn() { return ValueOnIter(VMASK_.beginOn(), this); }
1615 ValueOffCIter cbeginValueOff() const { return ValueOffCIter(VMASK_.beginOff(), this); }
1616 ValueOffCIter beginValueOff() const { return ValueOffCIter(VMASK_.beginOff(), this); }
1617 ValueOffIter beginValueOff() { return ValueOffIter(VMASK_.beginOff(), this); }
1618 ValueAllCIter cbeginValueAll() const { return ValueAllCIter(VMASK_.beginDense(), this); }
1619 ValueAllCIter beginValueAll() const { return ValueAllCIter(VMASK_.beginDense(), this); }
1620 ValueAllIter beginValueAll() { return ValueAllIter(VMASK_.beginDense(), this); }
1621
1622 ValueOnCIter cendValueOn() const { return ValueOnCIter(VMASK_.endOn(), this); }
1623 ValueOnCIter endValueOn() const { return ValueOnCIter(VMASK_.endOn(), this); }
1624 ValueOnIter endValueOn() { return ValueOnIter(VMASK_.endOn(), this); }
1625 ValueOffCIter cendValueOff() const { return ValueOffCIter(VMASK_.endOff(), this); }
1626 ValueOffCIter endValueOff() const { return ValueOffCIter(VMASK_.endOff(), this); }
1627 ValueOffIter endValueOff() { return ValueOffIter(VMASK_.endOff(), this); }
1628 ValueAllCIter cendValueAll() const { return ValueAllCIter(VMASK_.endDense(), this); }
1629 ValueAllCIter endValueAll() const { return ValueAllCIter(VMASK_.endDense(), this); }
1630 ValueAllIter endValueAll() { return ValueAllIter(VMASK_.endDense(), this); }
1631
1632 ChildOnCIter cbeginChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
1633 ChildOnCIter beginChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
1634 ChildOnIter beginChildOn() { return ChildOnIter(VMASK_.endOn(), this); }
1635 ChildOffCIter cbeginChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
1636 ChildOffCIter beginChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
1637 ChildOffIter beginChildOff() { return ChildOffIter(VMASK_.endOff(), this); }
1638 ChildAllCIter cbeginChildAll() const { return ChildAllCIter(VMASK_.beginDense(), this); }
1639 ChildAllCIter beginChildAll() const { return ChildAllCIter(VMASK_.beginDense(), this); }
1640 ChildAllIter beginChildAll() { return ChildAllIter(VMASK_.beginDense(), this); }
1641
1642 ChildOnCIter cendChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
1643 ChildOnCIter endChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
1644 ChildOnIter endChildOn() { return ChildOnIter(VMASK_.endOn(), this); }
1645 ChildOffCIter cendChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
1646 ChildOffCIter endChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
1647 ChildOffIter endChildOff() { return ChildOffIter(VMASK_.endOff(), this); }
1648 ChildAllCIter cendChildAll() const { return ChildAllCIter(VMASK_.endDense(), this); }
1649 ChildAllCIter endChildAll() const { return ChildAllCIter(VMASK_.endDense(), this); }
1650 ChildAllIter endChildAll() { return ChildAllIter(VMASK_.endDense(), this); }
1651#undef VMASK_
1652}; // struct PointIndexLeafNode
1653
1654
1655template<typename T, Index Log2Dim>
1656inline bool
1658 const ValueType*& begin, const ValueType*& end) const
1659{
1660 return getIndices(LeafNodeType::coordToOffset(ijk), begin, end);
1661}
1662
1663
1664template<typename T, Index Log2Dim>
1665inline bool
1667 const ValueType*& begin, const ValueType*& end) const
1668{
1669 if (this->isValueMaskOn(offset)) {
1670 const ValueType* dataPtr = &mIndices.front();
1671 begin = dataPtr + (offset == 0 ? ValueType(0) : this->buffer()[offset - 1]);
1672 end = dataPtr + this->buffer()[offset];
1673 return true;
1674 }
1675 return false;
1676}
1677
1678
1679template<typename T, Index Log2Dim>
1680inline void
1682{
1683 this->buffer().setValue(offset, val);
1684 this->setValueMaskOn(offset);
1685}
1686
1687
1688template<typename T, Index Log2Dim>
1689inline void
1691{
1692 this->buffer().setValue(offset, val);
1693}
1694
1695
1696template<typename T, Index Log2Dim>
1697inline bool
1699{
1700 Index xPos, pos, zStride = Index(bbox.max()[2] - bbox.min()[2]);
1701 Coord ijk;
1702
1703 for (ijk[0] = bbox.min()[0]; ijk[0] <= bbox.max()[0]; ++ijk[0]) {
1704 xPos = (ijk[0] & (DIM - 1u)) << (2 * LOG2DIM);
1705
1706 for (ijk[1] = bbox.min()[1]; ijk[1] <= bbox.max()[1]; ++ijk[1]) {
1707 pos = xPos + ((ijk[1] & (DIM - 1u)) << LOG2DIM);
1708 pos += (bbox.min()[2] & (DIM - 1u));
1709
1710 if (this->buffer()[pos+zStride] > (pos == 0 ? T(0) : this->buffer()[pos - 1])) {
1711 return false;
1712 }
1713 }
1714 }
1715
1716 return true;
1717}
1718
1719
1720template<typename T, Index Log2Dim>
1721inline void
1722PointIndexLeafNode<T, Log2Dim>::readBuffers(std::istream& is, bool fromHalf)
1723{
1724 BaseLeaf::readBuffers(is, fromHalf);
1725
1726 Index64 numIndices = Index64(0);
1727 is.read(reinterpret_cast<char*>(&numIndices), sizeof(Index64));
1728
1729 mIndices.resize(size_t(numIndices));
1730 is.read(reinterpret_cast<char*>(mIndices.data()), numIndices * sizeof(T));
1731}
1732
1733
1734template<typename T, Index Log2Dim>
1735inline void
1736PointIndexLeafNode<T, Log2Dim>::readBuffers(std::istream& is, const CoordBBox& bbox, bool fromHalf)
1737{
1738 // Read and clip voxel values.
1739 BaseLeaf::readBuffers(is, bbox, fromHalf);
1740
1741 Index64 numIndices = Index64(0);
1742 is.read(reinterpret_cast<char*>(&numIndices), sizeof(Index64));
1743
1744 const Index64 numBytes = numIndices * sizeof(T);
1745
1746 if (bbox.hasOverlap(this->getNodeBoundingBox())) {
1747 mIndices.resize(size_t(numIndices));
1748 is.read(reinterpret_cast<char*>(mIndices.data()), numBytes);
1749
1750 /// @todo If any voxels were deactivated as a result of clipping in the call to
1751 /// BaseLeaf::readBuffers(), the point index list will need to be regenerated.
1752 } else {
1753 // Read and discard voxel values.
1754 std::unique_ptr<char[]> buf{new char[numBytes]};
1755 is.read(buf.get(), numBytes);
1756 }
1757
1758 // Reserved for future use
1759 Index64 auxDataBytes = Index64(0);
1760 is.read(reinterpret_cast<char*>(&auxDataBytes), sizeof(Index64));
1761 if (auxDataBytes > 0) {
1762 // For now, read and discard any auxiliary data.
1763 std::unique_ptr<char[]> auxData{new char[auxDataBytes]};
1764 is.read(auxData.get(), auxDataBytes);
1765 }
1766}
1767
1768
1769template<typename T, Index Log2Dim>
1770inline void
1771PointIndexLeafNode<T, Log2Dim>::writeBuffers(std::ostream& os, bool toHalf) const
1772{
1773 BaseLeaf::writeBuffers(os, toHalf);
1774
1775 Index64 numIndices = Index64(mIndices.size());
1776 os.write(reinterpret_cast<const char*>(&numIndices), sizeof(Index64));
1777 os.write(reinterpret_cast<const char*>(mIndices.data()), numIndices * sizeof(T));
1778
1779 // Reserved for future use
1780 const Index64 auxDataBytes = Index64(0);
1781 os.write(reinterpret_cast<const char*>(&auxDataBytes), sizeof(Index64));
1782}
1783
1784
1785template<typename T, Index Log2Dim>
1786inline Index64
1788{
1789 return BaseLeaf::memUsage() + Index64((sizeof(T)*mIndices.capacity()) + sizeof(mIndices));
1790}
1791
1792template<typename T, Index Log2Dim>
1793inline Index64
1795{
1796 return BaseLeaf::memUsageIfLoaded() + Index64((sizeof(T)*mIndices.capacity()) + sizeof(mIndices));
1797}
1798
1799} // namespace tools
1800
1801
1802////////////////////////////////////////
1803
1804
1805namespace tree {
1806
1807/// Helper metafunction used to implement LeafNode::SameConfiguration
1808/// (which, as an inner class, can't be independently specialized)
1809template<Index Dim1, typename T2>
1811{
1812 static const bool value = true;
1813};
1814
1815} // namespace tree
1816} // namespace OPENVDB_VERSION_NAME
1817} // namespace openvdb
1818
1819#endif // OPENVDB_TOOLS_POINT_INDEX_GRID_HAS_BEEN_INCLUDED
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition Platform.h:141
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition Platform.h:140
#define VMASK_
Definition PointDataGrid.h:702
Spatially partitions points using a parallel radix-based sorting algorithm.
static Coord round(const Vec3< T > &xyz)
Return xyz rounded to the closest integer coordinates (cell centered conversion).
Definition Coord.h:51
Container class that associates a tree with a transform and metadata.
Definition Grid.h:571
Tag dispatch class that distinguishes constructors during file input.
Definition Types.h:689
const Vec3T & max() const
Return a const reference to the maximum point of this bounding box.
Definition BBox.h:64
const Vec3T & min() const
Return a const reference to the minimum point of this bounding box.
Definition BBox.h:62
Axis-aligned bounding box of signed integer coordinates.
Definition Coord.h:252
void expand(ValueType padding)
Pad this bounding box with the specified padding.
Definition Coord.h:421
const Coord & min() const
Definition Coord.h:324
bool hasOverlap(const CoordBBox &b) const
Return true if the given bounding box overlaps with this bounding box.
Definition Coord.h:415
const Coord & max() const
Definition Coord.h:325
Coord dim() const
Return the dimensions of the coordinates spanned by this bounding box.
Definition Coord.h:383
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
Definition Transform.h:40
Vec3d voxelSize() const
Return the size of a voxel using the linear component of the map.
Definition Transform.h:93
Ptr copy() const
Definition Transform.h:50
Vec3d worldToIndex(const Vec3d &xyz) const
Definition Transform.h:110
SharedPtr< Transform > Ptr
Definition Transform.h:42
static Transform::Ptr createLinearTransform(double voxelSize=1.0)
Create and return a shared pointer to a new transform.
Definition InternalNode.h:35
Base class for iterators over internal and leaf nodes.
Definition Iterator.h:30
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition LeafManager.h:86
LeafType & leaf(size_t leafIdx) const
Return a pointer to the leaf node at index leafIdx in the array.
Definition LeafManager.h:319
void foreach(const LeafOp &op, bool threaded=true, size_t grainSize=1)
Threaded method that applies a user-supplied functor to each leaf node in the LeafManager.
Definition LeafManager.h:484
size_t leafCount() const
Return the number of leaf nodes.
Definition LeafManager.h:288
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim....
Definition LeafNode.h:39
void setValueMaskOn(Index n)
Definition LeafNode.h:893
static const Index NUM_VOXELS
Definition LeafNode.h:53
static const Index DIM
Definition LeafNode.h:51
static const Index LEVEL
Definition LeafNode.h:55
static Index coordToOffset(const Coord &xyz)
Return the linear table offset of the given global or local coordinates.
Definition LeafNode.h:1040
bool hasSameTopology(const LeafNode< OtherType, OtherLog2Dim > *other) const
Return true if the given node (which may have a different ValueType than this node) has the same acti...
Definition LeafNode.h:1497
void writeBuffers(std::ostream &os, bool toHalf=false) const
Write buffers to a stream.
Definition LeafNode.h:1432
Index64 memUsageIfLoaded() const
Definition LeafNode.h:1469
void readBuffers(std::istream &is, bool fromHalf=false)
Read buffers from a stream.
Definition LeafNode.h:1334
static const Index NUM_VALUES
Definition LeafNode.h:52
static const Index LOG2DIM
Definition LeafNode.h:49
bool operator==(const LeafNode &other) const
Check for buffer, state and origin equivalence.
Definition LeafNode.h:1449
static const Index SIZE
Definition LeafNode.h:54
bool isEmpty() const
Return true if this node has no active voxels.
Definition LeafNode.h:151
static const Index TOTAL
Definition LeafNode.h:50
Index64 memUsage() const
Return the memory in bytes occupied by this node.
Definition LeafNode.h:1459
bool isValueMaskOn(Index n) const
Definition LeafNode.h:880
Definition RootNode.h:40
Definition Tree.h:195
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Return a pointer to the leaf node that contains the voxel coordinate xyz. If no LeafNode exists,...
Definition ValueAccessor.h:838
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation.
Definition NodeMasks.h:308
DenseMaskIterator< NodeMask > DenseIterator
Definition NodeMasks.h:350
OnMaskIterator< NodeMask > OnIterator
Definition NodeMasks.h:348
OffMaskIterator< NodeMask > OffIterator
Definition NodeMasks.h:349
Selectively extract and filter point data using a custom filter operator.
Partitions points into BucketLog2Dim aligned buckets using a parallel radix-based sorting algorithm.
Vec3< double > Vec3d
Definition Vec3.h:665
Definition AttributeArray.h:42
Index64 pointCount(const PointDataTreeT &tree, const FilterT &filter=NullFilter(), const bool inCoreOnly=false, const bool threaded=true)
Count the total number of points in a PointDataTree.
Definition PointCountImpl.h:18
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition Composite.h:110
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition Composite.h:106
OutGridT const XformOp bool bool
Definition ValueTransformer.h:610
OutGridT XformOp & op
Definition ValueTransformer.h:140
math::Histogram histogram(const IterT &iter, double minVal, double maxVal, size_t numBins=10, bool threaded=true)
Iterate over a scalar grid and compute a histogram of the values of the voxels that are visited,...
Definition Statistics.h:343
tree::Tree< tree::RootNode< tree::InternalNode< tree::InternalNode< PointIndexLeafNode< PointIndex32, 3 >, 4 >, 5 > > > PointIndexTree
Point index tree configured to match the default OpenVDB tree configuration.
Definition PointIndexGrid.h:57
OutGridT XformOp bool bool MergePolicy merge
Definition ValueTransformer.h:141
GridT::ConstPtr getValidPointIndexGrid(const PointArrayT &points, const typename GridT::ConstPtr &grid)
Repartition the points if needed, otherwise return the input grid.
Definition PointIndexGrid.h:1332
Grid< PointIndexTree > PointIndexGrid
Point index grid.
Definition PointIndexGrid.h:61
GridT::Ptr createPointIndexGrid(const PointArrayT &points, double voxelSize)
Partition points into a point index grid to accelerate range and nearest-neighbor searches.
Definition PointIndexGrid.h:1296
bool isValidPartition(const PointArrayT &points, const GridT &grid)
Return true if the given point index grid represents a valid partitioning of the given point array.
Definition PointIndexGrid.h:1305
Definition PointDataGrid.h:170
ValueAccessorImpl< TreeType, IsSafe, MutexType, openvdb::make_index_sequence< CacheLevels > > ValueAccessor
Default alias for a ValueAccessor. This is simply a helper alias for the generic definition but takes...
Definition ValueAccessor.h:86
Index32 Index
Definition Types.h:54
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:70
math::BBox< Vec3d > BBoxd
Definition Types.h:84
uint64_t Index64
Definition Types.h:53
std::shared_ptr< T > SharedPtr
Definition Types.h:114
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
PointIndexFilter(const PointArray &points, const TreeType &tree, const math::Transform &xform)
Constructor.
Definition PointIndexGrid.h:1227
tree::ValueAccessor< const TreeType > ConstAccessor
Definition PointIndexGrid.h:310
typename PosType::value_type ScalarType
Definition PointIndexGrid.h:309
typename PointArray::PosType PosType
Definition PointIndexGrid.h:308
void searchAndApply(const PosType &center, ScalarType radius, FilterType &op)
Perform a radial search query and apply the given filter operator to the selected points.
Definition PointIndexGrid.h:1248
Accelerated range and nearest-neighbor searches for point index grids.
Definition PointIndexGrid.h:135
void operator++()
Advance iterator to next item.
Definition PointIndexGrid.h:243
PointIndexIterator(const PointIndexIterator &rhs)
Definition PointIndexGrid.h:935
void worldSpaceSearchAndUpdate(const Vec3d &center, double radius, ConstAccessor &acc, const PointArray &points, const math::Transform &xform, bool subvoxelAccuracy=true)
Clear the iterator and update it with the result of the given world-space radial query.
Definition PointIndexGrid.h:1212
void worldSpaceSearchAndUpdate(const BBoxd &bbox, ConstAccessor &acc, const PointArray &points, const math::Transform &xform)
Clear the iterator and update it with the result of the given world-space bounding box query.
Definition PointIndexGrid.h:1201
size_t size() const
Return the number of point indices in the iterator range.
Definition PointIndexGrid.h:1050
typename TreeType::ValueType ValueType
Definition PointIndexGrid.h:138
const ValueType & operator*() const
Return a const reference to the item to which this iterator is pointing.
Definition PointIndexGrid.h:231
PointIndexIterator(const Coord &ijk, ConstAccessor &acc)
Construct an iterator over the indices of the points contained in voxel (i, j, k).
Definition PointIndexGrid.h:971
bool test() const
Return true if this iterator is not yet exhausted.
Definition PointIndexGrid.h:235
PointIndexIterator()
Definition PointIndexGrid.h:923
PointIndexIterator(const CoordBBox &bbox, ConstAccessor &acc)
Construct an iterator over the indices of the points contained in the given bounding box.
Definition PointIndexGrid.h:988
void searchAndUpdate(const BBoxd &bbox, ConstAccessor &acc, const PointArray &points, const math::Transform &xform)
Clear the iterator and update it with the result of the given index-space bounding box query.
Definition PointIndexGrid.h:1106
PointIndexIterator & operator=(const PointIndexIterator &rhs)
Definition PointIndexGrid.h:951
void searchAndUpdate(const Vec3d &center, double radius, ConstAccessor &acc, const PointArray &points, const math::Transform &xform, bool subvoxelAccuracy=true)
Clear the iterator and update it with the result of the given index-space radial query.
Definition PointIndexGrid.h:1149
tree::ValueAccessor< const TreeType > ConstAccessor
Definition PointIndexGrid.h:136
void searchAndUpdate(const CoordBBox &bbox, ConstAccessor &acc)
Clear the iterator and update it with the result of the given voxel region query.
Definition PointIndexGrid.h:1091
bool next()
Advance iterator to next item.
Definition PointIndexGrid.h:1040
typename TreeType::LeafNodeType LeafNodeType
Definition PointIndexGrid.h:137
void reset()
Reset the iterator to point to the first item.
Definition PointIndexGrid.h:1006
bool operator!=(const PointIndexIterator &p) const
Definition PointIndexGrid.h:255
void searchAndUpdate(const Coord &ijk, ConstAccessor &acc)
Clear the iterator and update it with the result of the given voxel query.
Definition PointIndexGrid.h:1078
void increment()
Advance iterator to next item.
Definition PointIndexGrid.h:1023
bool operator==(const PointIndexIterator &p) const
Return true if both iterators point to the same element.
Definition PointIndexGrid.h:254
Definition PointIndexGrid.h:1359
ChildOnCIter cbeginChildOn() const
Definition PointIndexGrid.h:1632
typename BaseLeaf::template ValueIter< MaskDenseIterator, const PointIndexLeafNode, const ValueType, ValueAll > ValueAllCIter
Definition PointIndexGrid.h:1596
void setValueOff(const Coord &, const ValueType &)
Definition PointIndexGrid.h:1515
ChildOnCIter beginChildOn() const
Definition PointIndexGrid.h:1633
PointIndexLeafNode(const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Definition PointIndexGrid.h:1402
ChildOnIter beginChildOn()
Definition PointIndexGrid.h:1634
void merge(const PointIndexLeafNode &other, const ValueType &, const ValueType &)
Definition PointIndexGrid.h:1438
ValueOnIter endValueOn()
Definition PointIndexGrid.h:1624
void setValueOff(const Coord &)
Definition PointIndexGrid.h:1512
typename BaseLeaf::template ChildIter< MaskOffIterator, const PointIndexLeafNode, ChildOff > ChildOffCIter
Definition PointIndexGrid.h:1604
const PointIndexLeafNode * probeConstLeaf(const Coord &) const
Return a const pointer to this node.
Definition PointIndexGrid.h:1469
void fill(const ValueType &)
Definition PointIndexGrid.h:1541
util::NodeMask< Log2Dim > NodeMaskType
Definition PointIndexGrid.h:1388
ValueOffCIter cbeginValueOff() const
Definition PointIndexGrid.h:1615
void merge(const PointIndexLeafNode &rhs)
Definition PointIndexGrid.h:1430
void setValueOff(Index)
Definition PointIndexGrid.h:1513
ChildOnIter endChildOn()
Definition PointIndexGrid.h:1644
ValueAllIter endValueAll()
Definition PointIndexGrid.h:1630
void resetBackground(const ValueType &, const ValueType &)
Definition PointIndexGrid.h:1558
void addLeaf(PointIndexLeafNode *)
Definition PointIndexGrid.h:1444
SharedPtr< PointIndexLeafNode > Ptr
Definition PointIndexGrid.h:1361
const IndexArray & indices() const
Definition PointIndexGrid.h:1368
typename BaseLeaf::template ChildIter< MaskOnIterator, const PointIndexLeafNode, ChildOn > ChildOnCIter
Definition PointIndexGrid.h:1600
void modifyValue(Index, const ModifyOp &)
Definition PointIndexGrid.h:1530
void setValueOn(Index, const ValueType &)
Definition PointIndexGrid.h:1522
typename BaseLeaf::template ValueIter< MaskOffIterator, PointIndexLeafNode, const ValueType, ValueOff > ValueOffIter
Definition PointIndexGrid.h:1590
friend struct PointIndexLeafNode
Definition PointIndexGrid.h:1579
void setValuesOff()
Definition PointIndexGrid.h:1527
ValueAllCIter endValueAll() const
Definition PointIndexGrid.h:1629
typename BaseLeaf::template ValueIter< MaskDenseIterator, PointIndexLeafNode, const ValueType, ValueAll > ValueAllIter
Definition PointIndexGrid.h:1594
const PointIndexLeafNode * probeLeafAndCache(const Coord &, AccessorT &) const
Definition PointIndexGrid.h:1473
ChildOffCIter endChildOff() const
Definition PointIndexGrid.h:1646
void merge(const ValueType &tileValue, bool tileActive)
Definition PointIndexGrid.h:1433
void setValueOff(Index, const ValueType &)
Definition PointIndexGrid.h:1516
PointIndexLeafNode(const PointIndexLeafNode &rhs)
Deep copy constructor.
Definition PointIndexGrid.h:1416
ValueAllCIter cbeginValueAll() const
Definition PointIndexGrid.h:1618
typename BaseLeaf::ChildOff ChildOff
Definition PointIndexGrid.h:1570
void setValueOnly(Index, const ValueType &)
Definition PointIndexGrid.h:1510
tree::LeafNode< T, Log2Dim > BaseLeaf
Definition PointIndexGrid.h:1387
ValueOnCIter beginValueOn() const
Definition PointIndexGrid.h:1613
PointIndexLeafNode< T, Log2Dim > LeafNodeType
Definition PointIndexGrid.h:1360
typename BaseLeaf::ChildOn ChildOn
Definition PointIndexGrid.h:1569
PointIndexLeafNode()
Default constructor.
Definition PointIndexGrid.h:1399
typename BaseLeaf::template ValueIter< MaskOffIterator, const PointIndexLeafNode, const ValueType, ValueOff > ValueOffCIter
Definition PointIndexGrid.h:1592
void signedFloodFill(const ValueType &, const ValueType &)
Definition PointIndexGrid.h:1561
void addLeafAndCache(PointIndexLeafNode *, AccessorT &)
Definition PointIndexGrid.h:1446
const PointIndexLeafNode * probeLeaf(const Coord &) const
Definition PointIndexGrid.h:1474
void setActiveState(Index, bool)
Definition PointIndexGrid.h:1507
void modifyValueAndActiveState(const Coord &, const ModifyOp &)
Definition PointIndexGrid.h:1536
typename BaseLeaf::ChildAll ChildAll
Definition PointIndexGrid.h:1571
void setActiveStateAndCache(const Coord &, bool, AccessorT &)
Definition PointIndexGrid.h:1556
ValueOnCIter cendValueOn() const
Definition PointIndexGrid.h:1622
void setOffsetOnly(Index offset, const ValueType &val)
Definition PointIndexGrid.h:1690
ValueOffCIter beginValueOff() const
Definition PointIndexGrid.h:1616
ChildAllCIter cbeginChildAll() const
Definition PointIndexGrid.h:1638
ChildOffIter endChildOff()
Definition PointIndexGrid.h:1647
void modifyValueAndActiveStateAndCache(const Coord &, const ModifyOp &, AccessorT &)
Definition PointIndexGrid.h:1548
void setValueOnly(const Coord &, const ValueType &)
Definition PointIndexGrid.h:1509
ChildAllIter beginChildAll()
Definition PointIndexGrid.h:1640
static const Index DIM
Definition LeafNode.h:51
PointIndexLeafNode(PartialCreate, const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Definition PointIndexGrid.h:1408
ValueOnIter beginValueOn()
Definition PointIndexGrid.h:1614
NodeT * probeNodeAndCache(const Coord &, AccessorT &)
Definition PointIndexGrid.h:1455
bool operator!=(const PointIndexLeafNode &other) const
Definition PointIndexGrid.h:1428
typename BaseLeaf::template DenseIter< const PointIndexLeafNode, const ValueType, ChildAll > ChildAllCIter
Definition PointIndexGrid.h:1608
PointIndexLeafNode * probeLeaf(const Coord &)
Definition PointIndexGrid.h:1462
PointIndexLeafNode * touchLeafAndCache(const Coord &, AccessorT &)
Definition PointIndexGrid.h:1452
ChildOffCIter cbeginChildOff() const
Definition PointIndexGrid.h:1635
ChildOffIter beginChildOff()
Definition PointIndexGrid.h:1637
ChildOffCIter beginChildOff() const
Definition PointIndexGrid.h:1636
bool operator==(const PointIndexLeafNode &other) const
Check for buffer, state and origin equivalence.
Definition PointIndexGrid.h:1426
ValueOffIter endValueOff()
Definition PointIndexGrid.h:1627
ChildAllCIter endChildAll() const
Definition PointIndexGrid.h:1649
PointIndexLeafNode * probeLeafAndCache(const Coord &, AccessorT &)
Definition PointIndexGrid.h:1464
typename BaseLeaf::template ValueIter< MaskOnIterator, PointIndexLeafNode, const ValueType, ValueOn > ValueOnIter
Definition PointIndexGrid.h:1586
const NodeT * probeConstNodeAndCache(const Coord &, AccessorT &) const
Definition PointIndexGrid.h:1476
void setOffsetOn(Index offset, const ValueType &val)
Definition PointIndexGrid.h:1681
ValueOnCIter cbeginValueOn() const
Definition PointIndexGrid.h:1612
void writeBuffers(std::ostream &os, bool toHalf=false) const
Definition PointIndexGrid.h:1771
ChildOnCIter endChildOn() const
Definition PointIndexGrid.h:1643
ChildOnCIter cendChildOn() const
Definition PointIndexGrid.h:1642
void fill(const ValueType &, bool)
Definition PointIndexGrid.h:1542
ChildAllCIter cendChildAll() const
Definition PointIndexGrid.h:1648
typename BaseLeaf::template ChildIter< MaskOnIterator, PointIndexLeafNode, ChildOn > ChildOnIter
Definition PointIndexGrid.h:1598
void assertNonmodifiable()
Definition PointIndexGrid.h:1502
Index64 memUsageIfLoaded() const
Definition PointIndexGrid.h:1794
typename BaseLeaf::template ChildIter< MaskOffIterator, PointIndexLeafNode, ChildOff > ChildOffIter
Definition PointIndexGrid.h:1602
void setValueOffAndCache(const Coord &, const ValueType &, AccessorT &)
Definition PointIndexGrid.h:1553
ChildAllIter endChildAll()
Definition PointIndexGrid.h:1650
PointIndexLeafNode * touchLeaf(const Coord &)
Return a pointer to this node.
Definition PointIndexGrid.h:1450
typename NodeMaskType::OffIterator MaskOffIterator
Definition PointIndexGrid.h:1574
void readBuffers(std::istream &is, bool fromHalf=false)
Definition PointIndexGrid.h:1722
void setValue(const Coord &, const ValueType &)
Definition PointIndexGrid.h:1524
const PointIndexLeafNode * probeConstLeafAndCache(const Coord &, AccessorT &) const
Definition PointIndexGrid.h:1471
void setValueOn(const Coord &)
Definition PointIndexGrid.h:1518
ValueAllCIter cendValueAll() const
Definition PointIndexGrid.h:1628
typename BaseLeaf::template DenseIter< PointIndexLeafNode, ValueType, ChildAll > ChildAllIter
Definition PointIndexGrid.h:1606
void setValueOn(Index)
Definition PointIndexGrid.h:1519
void negate()
Definition PointIndexGrid.h:1563
ChildAllCIter beginChildAll() const
Definition PointIndexGrid.h:1639
typename BaseLeaf::ValueAll ValueAll
Definition PointIndexGrid.h:1568
void setValuesOn()
Definition PointIndexGrid.h:1526
typename BaseLeaf::ValueOn ValueOn
Definition PointIndexGrid.h:1566
IndexArray & indices()
Definition PointIndexGrid.h:1367
ChildOffCIter cendChildOff() const
Definition PointIndexGrid.h:1645
void setValueOnlyAndCache(const Coord &, const ValueType &, AccessorT &)
Definition PointIndexGrid.h:1545
typename BaseLeaf::template ValueIter< MaskOnIterator, const PointIndexLeafNode, const ValueType, ValueOn > ValueOnCIter
Definition PointIndexGrid.h:1588
typename NodeMaskType::OnIterator MaskOnIterator
Definition PointIndexGrid.h:1573
static const Index LOG2DIM
Definition LeafNode.h:49
void signedFloodFill(const ValueType &)
Definition PointIndexGrid.h:1560
ValueOffIter beginValueOff()
Definition PointIndexGrid.h:1617
void clip(const CoordBBox &, const ValueType &)
Definition PointIndexGrid.h:1538
typename BaseLeaf::ValueOff ValueOff
Definition PointIndexGrid.h:1567
void modifyValue(const Coord &, const ModifyOp &)
Definition PointIndexGrid.h:1533
ValueOffCIter cendValueOff() const
Definition PointIndexGrid.h:1625
Index64 memUsage() const
Definition PointIndexGrid.h:1787
void fill(const CoordBBox &, const ValueType &, bool)
Definition PointIndexGrid.h:1540
ValueOffCIter endValueOff() const
Definition PointIndexGrid.h:1626
T ValueType
Definition PointIndexGrid.h:1363
ValueOnCIter endValueOn() const
Definition PointIndexGrid.h:1623
typename NodeMaskType::DenseIterator MaskDenseIterator
Definition PointIndexGrid.h:1575
bool hasSameTopology(const PointIndexLeafNode< OtherType, OtherLog2Dim > *other) const
Return true if the given node (which may have a different ValueType than this node) has the same acti...
Definition PointIndexGrid.h:1421
ValueAllCIter beginValueAll() const
Definition PointIndexGrid.h:1619
void setActiveState(const Coord &, bool)
Definition PointIndexGrid.h:1506
bool getIndices(const Coord &ijk, const ValueType *&begin, const ValueType *&end) const
Definition PointIndexGrid.h:1657
void setValueOn(const Coord &, const ValueType &)
Definition PointIndexGrid.h:1521
ValueAllIter beginValueAll()
Definition PointIndexGrid.h:1620
std::vector< ValueType > IndexArray
Definition PointIndexGrid.h:1364
Leaf nodes have no children, so their child iterators have no get/set accessors.
Definition LeafNode.h:253
Definition LeafNode.h:920
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:218