OpenVDB  12.0.0
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>
26 #include <openvdb/math/Transform.h>
28 #include <openvdb/tree/LeafNode.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 
44 namespace openvdb {
46 namespace OPENVDB_VERSION_NAME {
47 
48 namespace tree {
49 template<Index, typename> struct SameLeafConfig; // forward declaration
50 }
51 
52 namespace tools {
53 
54 template<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
93 template<typename GridT, typename PointArrayT>
94 inline typename GridT::Ptr
95 createPointIndexGrid(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
103 template<typename GridT, typename PointArrayT>
104 inline typename GridT::Ptr
105 createPointIndexGrid(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
113 template<typename PointArrayT, typename GridT>
114 inline bool
115 isValidPartition(const PointArrayT& points, const GridT& grid);
116 
117 
118 /// Repartition the @a points if needed, otherwise return the input @a grid.
119 template<typename GridT, typename PointArrayT>
120 inline typename GridT::ConstPtr
121 getValidPointIndexGrid(const PointArrayT& points, const typename GridT::ConstPtr& grid);
122 
123 /// Repartition the @a points if needed, otherwise return the input @a grid.
124 template<typename GridT, typename PointArrayT>
125 inline typename GridT::Ptr
126 getValidPointIndexGrid(const PointArrayT& points, const typename GridT::Ptr& grid);
127 
128 
129 ////////////////////////////////////////
130 
131 
132 /// Accelerated range and nearest-neighbor searches for point index grids
133 template<typename TreeType = PointIndexTree>
135 {
137  using LeafNodeType = typename TreeType::LeafNodeType;
138  using ValueType = typename TreeType::ValueType;
139 
140 
143  PointIndexIterator& operator=(const PointIndexIterator& rhs);
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
149  PointIndexIterator(const Coord& ijk, ConstAccessor& acc);
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.
158  PointIndexIterator(const CoordBBox& bbox, ConstAccessor& acc);
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>
208  void worldSpaceSearchAndUpdate(const BBoxd& bbox, ConstAccessor& acc,
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 
258 private:
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
305 template<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 
329 private:
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 
344 namespace point_index_grid_internal {
345 
346 template<typename PointArrayT>
347 struct 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 
397 private:
398  PointArrayT const * const mPoints;
399  math::Transform const * const mTransform;
400  std::atomic<bool> * const mHasChanged;
401 };
402 
403 
404 template<typename LeafNodeT>
405 struct PopulateLeafNodesOp
406 {
407  using IndexT = uint32_t;
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
491 template<typename TreeType, typename PointArray>
492 inline void
493 constructPointTree(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.
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 
520  for (size_t n = 0; n < leafNodeCount; ++n) {
521  acc.addLeaf(leafNodes[n]);
522  }
523 }
524 
525 
526 ////////////////////////////////////////
527 
528 
529 template<typename T>
530 inline void
531 dequeToArray(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 
541 inline void
542 constructExclusiveRegions(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 
592 template<typename PointArray, typename IndexT>
593 struct 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 
637 private:
638  RangeDeque& mRanges;
639  IndexDeque& mIndices;
640  const BBoxd mRegion;
641  const PointArray& mPoints;
642  const math::MapBase& mMap;
643 };
644 
645 
646 template<typename PointArray, typename IndexT>
647 struct 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 
757 private:
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 
770 template<typename RangeFilterType, typename LeafNodeType>
771 inline void
772 filteredPointIndexSearchVoxels(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 
801 template<typename RangeFilterType, typename ConstAccessor>
802 inline void
803 filteredPointIndexSearch(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 
837 template<typename RangeDeque, typename LeafNodeType>
838 inline void
839 pointIndexSearchVoxels(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 
877 template<typename RangeDeque, typename ConstAccessor>
878 inline void
879 pointIndexSearch(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 
921 template<typename TreeType>
922 inline
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 
933 template<typename TreeType>
934 inline
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 
949 template<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 
969 template<typename TreeType>
970 inline
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 
986 template<typename TreeType>
987 inline
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 
1004 template<typename TreeType>
1005 inline 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 
1021 template<typename TreeType>
1022 inline 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 
1038 template<typename TreeType>
1039 inline bool
1041 {
1042  if (!this->test()) return false;
1043  this->increment();
1044  return this->test();
1045 }
1046 
1047 
1048 template<typename TreeType>
1049 inline 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 
1063 template<typename TreeType>
1064 inline void
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 
1076 template<typename TreeType>
1077 inline 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 
1089 template<typename TreeType>
1090 inline 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 
1103 template<typename TreeType>
1104 template<typename PointArray>
1105 inline 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 
1146 template<typename TreeType>
1147 template<typename PointArray>
1148 inline void
1149 PointIndexIterator<TreeType>::searchAndUpdate(const Vec3d& center, double radius,
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 
1198 template<typename TreeType>
1199 template<typename PointArray>
1200 inline 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 
1209 template<typename TreeType>
1210 template<typename PointArray>
1211 inline 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 
1225 template<typename PointArray, typename TreeType>
1226 inline
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 
1234 template<typename PointArray, typename TreeType>
1235 inline
1237  : mPoints(rhs.mPoints)
1238  , mAcc(rhs.mAcc.tree())
1239  , mXform(rhs.mXform)
1240  , mInvVoxelSize(rhs.mInvVoxelSize)
1241 {
1242 }
1243 
1244 
1245 template<typename PointArray, typename TreeType>
1246 template<typename FilterType>
1247 inline 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 
1278 template<typename GridT, typename PointArrayT>
1279 inline typename GridT::Ptr
1280 createPointIndexGrid(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 
1294 template<typename GridT, typename PointArrayT>
1295 inline typename GridT::Ptr
1296 createPointIndexGrid(const PointArrayT& points, double voxelSize)
1297 {
1299  return createPointIndexGrid<GridT>(points, *xform);
1300 }
1301 
1302 
1303 template<typename PointArrayT, typename GridT>
1304 inline bool
1305 isValidPartition(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 
1330 template<typename GridT, typename PointArrayT>
1331 inline typename GridT::ConstPtr
1332 getValidPointIndexGrid(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 
1342 template<typename GridT, typename PointArrayT>
1343 inline typename GridT::Ptr
1344 getValidPointIndexGrid(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 
1357 template<typename T, Index Log2Dim>
1358 struct 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 
1378 private:
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 
1386 public:
1389 
1390  using BaseLeaf::LOG2DIM;
1391  using BaseLeaf::TOTAL;
1392  using BaseLeaf::DIM;
1393  using BaseLeaf::NUM_VALUES;
1394  using BaseLeaf::NUM_VOXELS;
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 
1408  PointIndexLeafNode(PartialCreate, const Coord& coords,
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>
1422  return BaseLeaf::hasSameTopology(other);
1423  }
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>
1446  void addLeafAndCache(PointIndexLeafNode*, 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(); }
1507  void setActiveState(Index, bool) { assertNonmodifiable(); }
1508 
1509  void setValueOnly(const Coord&, const ValueType&) { assertNonmodifiable(); }
1510  void setValueOnly(Index, const ValueType&) { assertNonmodifiable(); }
1511 
1512  void setValueOff(const Coord&) { assertNonmodifiable(); }
1513  void setValueOff(Index) { assertNonmodifiable(); }
1514 
1515  void setValueOff(const Coord&, const ValueType&) { assertNonmodifiable(); }
1516  void setValueOff(Index, const ValueType&) { assertNonmodifiable(); }
1517 
1518  void setValueOn(const Coord&) { assertNonmodifiable(); }
1519  void setValueOn(Index) { assertNonmodifiable(); }
1520 
1521  void setValueOn(const Coord&, const ValueType&) { assertNonmodifiable(); }
1522  void setValueOn(Index, const ValueType&) { assertNonmodifiable(); }
1523 
1524  void setValue(const Coord&, const ValueType&) { assertNonmodifiable(); }
1525 
1526  void setValuesOn() { assertNonmodifiable(); }
1527  void setValuesOff() { assertNonmodifiable(); }
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&) {
1549  assertNonmodifiable();
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 
1558  void resetBackground(const ValueType&, const ValueType&) { assertNonmodifiable(); }
1559 
1560  void signedFloodFill(const ValueType&) { assertNonmodifiable(); }
1561  void signedFloodFill(const ValueType&, const ValueType&) { assertNonmodifiable(); }
1562 
1563  void negate() { assertNonmodifiable(); }
1564 
1565 protected:
1566  using ValueOn = typename BaseLeaf::ValueOn;
1567  using ValueOff = typename BaseLeaf::ValueOff;
1568  using ValueAll = typename BaseLeaf::ValueAll;
1569  using ChildOn = typename BaseLeaf::ChildOn;
1570  using ChildOff = typename BaseLeaf::ChildOff;
1571  using ChildAll = typename BaseLeaf::ChildAll;
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 
1585 public:
1586  using ValueOnIter = typename BaseLeaf::template ValueIter<
1588  using ValueOnCIter = typename BaseLeaf::template ValueIter<
1589  MaskOnIterator, const PointIndexLeafNode, const ValueType, ValueOn>;
1590  using ValueOffIter = typename BaseLeaf::template ValueIter<
1591  MaskOffIterator, PointIndexLeafNode, const ValueType, ValueOff>;
1592  using ValueOffCIter = typename BaseLeaf::template ValueIter<
1593  MaskOffIterator,const PointIndexLeafNode,const ValueType, ValueOff>;
1594  using ValueAllIter = typename BaseLeaf::template ValueIter<
1595  MaskDenseIterator, PointIndexLeafNode, const ValueType, ValueAll>;
1596  using ValueAllCIter = typename BaseLeaf::template ValueIter<
1597  MaskDenseIterator,const PointIndexLeafNode,const ValueType, ValueAll>;
1598  using ChildOnIter = typename BaseLeaf::template ChildIter<
1599  MaskOnIterator, PointIndexLeafNode, ChildOn>;
1600  using ChildOnCIter = typename BaseLeaf::template ChildIter<
1601  MaskOnIterator, const PointIndexLeafNode, ChildOn>;
1602  using ChildOffIter = typename BaseLeaf::template ChildIter<
1603  MaskOffIterator, PointIndexLeafNode, ChildOff>;
1604  using ChildOffCIter = typename BaseLeaf::template ChildIter<
1605  MaskOffIterator, const PointIndexLeafNode, ChildOff>;
1606  using ChildAllIter = typename BaseLeaf::template DenseIter<
1607  PointIndexLeafNode, ValueType, ChildAll>;
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 
1655 template<typename T, Index Log2Dim>
1656 inline bool
1658  const ValueType*& begin, const ValueType*& end) const
1659 {
1660  return getIndices(LeafNodeType::coordToOffset(ijk), begin, end);
1661 }
1662 
1663 
1664 template<typename T, Index Log2Dim>
1665 inline 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 
1679 template<typename T, Index Log2Dim>
1680 inline void
1682 {
1683  this->buffer().setValue(offset, val);
1684  this->setValueMaskOn(offset);
1685 }
1686 
1687 
1688 template<typename T, Index Log2Dim>
1689 inline void
1691 {
1692  this->buffer().setValue(offset, val);
1693 }
1694 
1695 
1696 template<typename T, Index Log2Dim>
1697 inline bool
1698 PointIndexLeafNode<T, Log2Dim>::isEmpty(const CoordBBox& bbox) const
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 
1720 template<typename T, Index Log2Dim>
1721 inline void
1722 PointIndexLeafNode<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 
1734 template<typename T, Index Log2Dim>
1735 inline void
1736 PointIndexLeafNode<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 
1769 template<typename T, Index Log2Dim>
1770 inline void
1771 PointIndexLeafNode<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 
1785 template<typename T, Index Log2Dim>
1786 inline Index64
1788 {
1789  return BaseLeaf::memUsage() + Index64((sizeof(T)*mIndices.capacity()) + sizeof(mIndices));
1790 }
1791 
1792 template<typename T, Index Log2Dim>
1793 inline Index64
1795 {
1796  return BaseLeaf::memUsageIfLoaded() + Index64((sizeof(T)*mIndices.capacity()) + sizeof(mIndices));
1797 }
1798 
1799 } // namespace tools
1800 
1801 
1802 ////////////////////////////////////////
1803 
1804 
1805 namespace tree {
1806 
1807 /// Helper metafunction used to implement LeafNode::SameConfiguration
1808 /// (which, as an inner class, can't be independently specialized)
1809 template<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
PointIndexIterator()
Definition: PointIndexGrid.h:923
ChildOnCIter cbeginChildOn() const
Definition: PointIndexGrid.h:1632
ValueOnCIter cbeginValueOn() const
Definition: PointIndexGrid.h:1612
void setValueOnly(const Coord &, const ValueType &)
Definition: PointIndexGrid.h:1509
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:38
PointIndexLeafNode()
Default constructor.
Definition: PointIndexGrid.h:1399
void addLeaf(PointIndexLeafNode *)
Definition: PointIndexGrid.h:1444
ChildOffCIter endChildOff() const
Definition: PointIndexGrid.h:1646
typename BaseLeaf::template DenseIter< PointIndexLeafNode, ValueType, ChildAll > ChildAllIter
Definition: PointIndexGrid.h:1607
Definition: Tree.h:194
ChildOnCIter beginChildOn() const
Definition: PointIndexGrid.h:1633
ValueOffCIter cbeginValueOff() const
Definition: PointIndexGrid.h:1615
IndexArray & indices()
Definition: PointIndexGrid.h:1367
ValueAllCIter endValueAll() const
Definition: PointIndexGrid.h:1629
bool test() const
Return true if this iterator is not yet exhausted.
Definition: PointIndexGrid.h:235
Base class for iterators over internal and leaf nodes.
Definition: Iterator.h:29
const Vec3T & max() const
Return a const reference to the maximum point of this bounding box.
Definition: BBox.h:64
Definition: Exceptions.h:60
void fill(const CoordBBox &, const ValueType &, bool)
Definition: PointIndexGrid.h:1540
Definition: PointIndexGrid.h:54
The Value Accessor Implementation and API methods. The majoirty of the API matches the API of a compa...
Definition: ValueAccessor.h:68
const PointIndexLeafNode * probeConstLeafAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: PointIndexGrid.h:1471
void setValueOnlyAndCache(const Coord &, const ValueType &, AccessorT &)
Definition: PointIndexGrid.h:1545
void setActiveState(Index, bool)
Definition: PointIndexGrid.h:1507
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
typename BaseLeaf::ValueOff ValueOff
Definition: PointIndexGrid.h:1567
typename BaseLeaf::template ValueIter< MaskDenseIterator, const PointIndexLeafNode, const ValueType, ValueAll > ValueAllCIter
Definition: PointIndexGrid.h:1597
bool operator!=(const PointIndexIterator &p) const
Definition: PointIndexGrid.h:255
Index64 memUsageIfLoaded(const TreeT &tree, bool threaded=true)
Return the deserialized memory usage of this tree. This is not necessarily equal to the current memor...
Definition: Count.h:502
void signedFloodFill(const ValueType &, const ValueType &)
Definition: PointIndexGrid.h:1561
ValueOnCIter endValueOn() const
Definition: PointIndexGrid.h:1623
typename BaseLeaf::template ValueIter< MaskOnIterator, PointIndexLeafNode, const ValueType, ValueOn > ValueOnIter
Definition: PointIndexGrid.h:1587
typename BaseLeaf::template ValueIter< MaskOffIterator, const PointIndexLeafNode, const ValueType, ValueOff > ValueOffCIter
Definition: PointIndexGrid.h:1593
ChildOffIter endChildOff()
Definition: PointIndexGrid.h:1647
uint64_t Index64
Definition: Types.h:53
const PointIndexLeafNode * probeConstLeaf(const Coord &) const
Return a const pointer to this node.
Definition: PointIndexGrid.h:1469
Index64 memUsageIfLoaded() const
Definition: PointIndexGrid.h:1794
bool getIndices(const Coord &ijk, const ValueType *&begin, const ValueType *&end) const
Definition: PointIndexGrid.h:1657
void fill(const ValueType &, bool)
Definition: PointIndexGrid.h:1542
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
PointIndexLeafNode * probeLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: PointIndexGrid.h:1464
const Vec3T & min() const
Return a const reference to the minimum point of this bounding box.
Definition: BBox.h:62
typename BaseLeaf::template ChildIter< MaskOffIterator, const PointIndexLeafNode, ChildOff > ChildOffCIter
Definition: PointIndexGrid.h:1605
math::BBox< Vec3d > BBoxd
Definition: Types.h:84
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation. ...
Definition: NodeMasks.h:307
typename BaseLeaf::template ChildIter< MaskOnIterator, const PointIndexLeafNode, ChildOn > ChildOnCIter
Definition: PointIndexGrid.h:1601
ValueOffCIter beginValueOff() const
Definition: PointIndexGrid.h:1616
Definition: NodeMasks.h:270
bool next()
Advance iterator to next item.
Definition: PointIndexGrid.h:1040
void modifyValue(Index, const ModifyOp &)
Definition: PointIndexGrid.h:1530
Definition: NodeMasks.h:239
bool operator==(const PointIndexLeafNode &other) const
Check for buffer, state and origin equivalence.
Definition: PointIndexGrid.h:1426
void resetBackground(const ValueType &, const ValueType &)
Definition: PointIndexGrid.h:1558
PointIndexLeafNode * probeLeaf(const Coord &)
Return a pointer to this node.
Definition: PointIndexGrid.h:1462
void modifyValueAndActiveStateAndCache(const Coord &, const ModifyOp &, AccessorT &)
Definition: PointIndexGrid.h:1548
void setValueOn(const Coord &, const ValueType &)
Definition: PointIndexGrid.h:1521
typename BaseLeaf::ValueAll ValueAll
Definition: PointIndexGrid.h:1568
ChildAllCIter cendChildAll() const
Definition: PointIndexGrid.h:1648
void writeBuffers(std::ostream &os, bool toHalf=false) const
Definition: PointIndexGrid.h:1771
PointIndexLeafNode(const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Definition: PointIndexGrid.h:1402
Index32 Index
Definition: Types.h:54
typename BaseLeaf::template ChildIter< MaskOffIterator, PointIndexLeafNode, ChildOff > ChildOffIter
Definition: PointIndexGrid.h:1603
Abstract base class for maps.
Definition: Maps.h:134
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:110
ValueOffCIter cendValueOff() const
Definition: PointIndexGrid.h:1625
OutGridT XformOp & op
Definition: ValueTransformer.h:139
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
typename BaseLeaf::ValueOn ValueOn
Definition: PointIndexGrid.h:1566
void increment()
Advance iterator to next item.
Definition: PointIndexGrid.h:1023
void merge(const PointIndexLeafNode &other, const ValueType &, const ValueType &)
Definition: PointIndexGrid.h:1438
ChildOnCIter cendChildOn() const
Definition: PointIndexGrid.h:1642
typename BaseLeaf::ChildOff ChildOff
Definition: PointIndexGrid.h:1570
Spatially partitions points using a parallel radix-based sorting algorithm.
void setValueOn(const Coord &)
Definition: PointIndexGrid.h:1518
ChildOnIter beginChildOn()
Definition: PointIndexGrid.h:1634
Definition: LeafNode.h:213
typename BaseLeaf::template ValueIter< MaskOnIterator, const PointIndexLeafNode, const ValueType, ValueOn > ValueOnCIter
Definition: PointIndexGrid.h:1589
const PointIndexLeafNode * probeLeaf(const Coord &) const
Return a const pointer to this node.
Definition: PointIndexGrid.h:1474
typename BaseLeaf::template ValueIter< MaskOffIterator, PointIndexLeafNode, const ValueType, ValueOff > ValueOffIter
Definition: PointIndexGrid.h:1591
const ValueType & operator*() const
Return a const reference to the item to which this iterator is pointing.
Definition: PointIndexGrid.h:231
Selectively extract and filter point data using a custom filter operator.
bool operator==(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Equality operator, does exact floating point comparisons.
Definition: Vec3.h:474
ValueOnCIter beginValueOn() const
Definition: PointIndexGrid.h:1613
typename NodeMaskType::OnIterator MaskOnIterator
Definition: PointIndexGrid.h:1573
Definition: PointIndexGrid.h:306
size_t size() const
Return the number of point indices in the iterator range.
Definition: PointIndexGrid.h:1050
bool usingCellCenteredTransform() const
Returns true if this point partitioning was constructed using a cell-centered transform.
Definition: PointPartitioner.h:160
void setValueOnly(Index, const ValueType &)
Definition: PointIndexGrid.h:1510
void setValueOff(Index, const ValueType &)
Definition: PointIndexGrid.h:1516
void readBuffers(std::istream &is, bool fromHalf=false)
Definition: PointIndexGrid.h:1722
Definition: NodeMasks.h:208
void addLeafAndCache(PointIndexLeafNode *, AccessorT &)
Definition: PointIndexGrid.h:1446
Index64 memUsage(const TreeT &tree, bool threaded=true)
Return the total amount of memory in bytes occupied by this tree.
Definition: Count.h:493
typename BaseLeaf::ChildAll ChildAll
Definition: PointIndexGrid.h:1571
PointIndexLeafNode * touchLeaf(const Coord &)
Return a pointer to this node.
Definition: PointIndexGrid.h:1450
std::shared_ptr< T > SharedPtr
Definition: Types.h:114
Definition: InternalNode.h:34
#define OPENVDB_ASSERT(X)
Definition: Assert.h:41
SharedPtr< PointIndexLeafNode > Ptr
Definition: PointIndexGrid.h:1361
ValueOnCIter cendValueOn() const
Definition: PointIndexGrid.h:1622
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
typename PointArray::PosType PosType
Definition: PointIndexGrid.h:308
ChildOffCIter beginChildOff() const
Definition: PointIndexGrid.h:1636
PointIndexLeafNode(const PointIndexLeafNode &rhs)
Deep copy constructor.
Definition: PointIndexGrid.h:1416
LeafType & leaf(size_t leafIdx) const
Return a pointer to the leaf node at index leafIdx in the array.
Definition: LeafManager.h:319
std::vector< ValueType > IndexArray
Definition: PointIndexGrid.h:1364
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
void setValuesOn()
Definition: PointIndexGrid.h:1526
#define VMASK_
Definition: PointIndexGrid.h:1611
Definition: PointPartitioner.h:77
Leaf nodes have no children, so their child iterators have no get/set accessors.
Definition: LeafNode.h:251
Accelerated range and nearest-neighbor searches for point index grids.
Definition: PointIndexGrid.h:134
ValueOnIter beginValueOn()
Definition: PointIndexGrid.h:1614
typename NodeMaskType::DenseIterator MaskDenseIterator
Definition: PointIndexGrid.h:1575
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
void merge(const ValueType &tileValue, bool tileActive)
Definition: PointIndexGrid.h:1433
Definition: Exceptions.h:13
void setValueOff(const Coord &, const ValueType &)
Definition: PointIndexGrid.h:1515
void setValue(const Coord &, const ValueType &)
Definition: PointIndexGrid.h:1524
void assertNonmodifiable()
Definition: PointIndexGrid.h:1502
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition: Platform.h:140
typename BaseLeaf::template ChildIter< MaskOnIterator, PointIndexLeafNode, ChildOn > ChildOnIter
Definition: PointIndexGrid.h:1599
typename NodeMaskType::OffIterator MaskOffIterator
Definition: PointIndexGrid.h:1574
Vec3d voxelSize() const
Return the size of a voxel using the linear component of the map.
Definition: Transform.h:93
PointIndexIterator & operator=(const PointIndexIterator &rhs)
Definition: PointIndexGrid.h:951
void merge(const PointIndexLeafNode &rhs)
Definition: PointIndexGrid.h:1430
bool operator==(const PointIndexIterator &p) const
Return true if both iterators point to the same element.
Definition: PointIndexGrid.h:254
T ValueType
Definition: PointIndexGrid.h:1363
Coord worldToIndexCellCentered(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:111
ChildOnCIter endChildOn() const
Definition: PointIndexGrid.h:1643
OutGridT const XformOp bool bool
Definition: ValueTransformer.h:609
ValueOffIter beginValueOff()
Definition: PointIndexGrid.h:1617
SharedPtr< Transform > Ptr
Definition: Transform.h:42
ChildAllIter beginChildAll()
Definition: PointIndexGrid.h:1640
GridT::Ptr getValidPointIndexGrid(const PointArrayT &points, const typename GridT::Ptr &grid)
Repartition the points if needed, otherwise return the input grid.
Definition: PointIndexGrid.h:1344
bool isEmpty() const
Return true if this node has no active voxels.
Definition: LeafNode.h:151
Definition: RootNode.h:39
ValueOffCIter endValueOff() const
Definition: PointIndexGrid.h:1626
void setValuesOff()
Definition: PointIndexGrid.h:1527
ChildOnIter endChildOn()
Definition: PointIndexGrid.h:1644
Vec3d worldToIndex(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:110
void construct(const PointArray &points, const math::Transform &xform, bool voxelOrder=false, bool recordVoxelOffsets=false, bool cellCenteredTransform=true)
Partitions point indices into BucketLog2Dim aligned buckets.
Definition: PointPartitioner.h:1002
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
Ptr copy() const
Definition: Transform.h:50
Definition: LeafNode.h:212
const PointIndexLeafNode * probeLeafAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: PointIndexGrid.h:1473
typename BaseLeaf::template ValueIter< MaskDenseIterator, PointIndexLeafNode, const ValueType, ValueAll > ValueAllIter
Definition: PointIndexGrid.h:1595
ValueAllCIter cbeginValueAll() const
Definition: PointIndexGrid.h:1618
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:141
void setValueOff(const Coord &)
Definition: PointIndexGrid.h:1512
static Transform::Ptr createLinearTransform(double voxelSize=1.0)
Create and return a shared pointer to a new transform.
void reset()
Reset the iterator to point to the first item.
Definition: PointIndexGrid.h:1006
void setActiveState(const Coord &, bool)
Definition: PointIndexGrid.h:1506
typename PosType::value_type ScalarType
Definition: PointIndexGrid.h:309
void setActiveStateAndCache(const Coord &, bool, AccessorT &)
Definition: PointIndexGrid.h:1556
const IndexArray & indices() const
Definition: PointIndexGrid.h:1368
void setValueOn(Index, const ValueType &)
Definition: PointIndexGrid.h:1522
ValueAllIter beginValueAll()
Definition: PointIndexGrid.h:1620
void signedFloodFill(const ValueType &)
Definition: PointIndexGrid.h:1560
void setValueOffAndCache(const Coord &, const ValueType &, AccessorT &)
Definition: PointIndexGrid.h:1553
ValueOnIter endValueOn()
Definition: PointIndexGrid.h:1624
void negate()
Definition: PointIndexGrid.h:1563
void setOffsetOn(Index offset, const ValueType &val)
Definition: PointIndexGrid.h:1681
size_t size() const
Returns the number of buckets.
Definition: PointPartitioner.h:131
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
Definition: Transform.h:39
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
typename TreeType::ValueType ValueType
Definition: PointIndexGrid.h:138
void clip(const CoordBBox &, const ValueType &)
Definition: PointIndexGrid.h:1538
Index64 memUsage() const
Definition: PointIndexGrid.h:1787
const NodeT * probeConstNodeAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: PointIndexGrid.h:1476
bool operator!=(const PointIndexLeafNode &other) const
Definition: PointIndexGrid.h:1428
GridT::Ptr createPointIndexGrid(const PointArrayT &points, const math::Transform &xform)
Partition points into a point index grid to accelerate range and nearest-neighbor searches...
Definition: PointIndexGrid.h:1280
This class manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional auxil...
Definition: LeafManager.h:85
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
PointIndexFilter(const PointArray &points, const TreeType &tree, const math::Transform &xform)
Constructor.
Definition: PointIndexGrid.h:1227
ValueAllIter endValueAll()
Definition: PointIndexGrid.h:1630
void modifyValueAndActiveState(const Coord &, const ModifyOp &)
Definition: PointIndexGrid.h:1536
PointIndexLeafNode(PartialCreate, const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Definition: PointIndexGrid.h:1408
ChildAllCIter beginChildAll() const
Definition: PointIndexGrid.h:1639
typename BaseLeaf::ChildOn ChildOn
Definition: PointIndexGrid.h:1569
ChildAllCIter endChildAll() const
Definition: PointIndexGrid.h:1649
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
ValueOffIter endValueOff()
Definition: PointIndexGrid.h:1627
Vec2< T > maxComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise maximum of the two vectors.
Definition: Vec2.h:513
typename TreeType::LeafNodeType LeafNodeType
Definition: PointIndexGrid.h:137
Vec2< T > minComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise minimum of the two vectors.
Definition: Vec2.h:504
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:106
ChildOffIter beginChildOff()
Definition: PointIndexGrid.h:1637
A LeafManager manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional au...
void setValueOff(Index)
Definition: PointIndexGrid.h:1513
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
ChildAllCIter cbeginChildAll() const
Definition: PointIndexGrid.h:1638
std::vector< Index > IndexArray
Definition: PointMoveImpl.h:88
void operator++()
Advance iterator to next item.
Definition: PointIndexGrid.h:243
NodeT * probeNodeAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: PointIndexGrid.h:1455
ValueAllCIter cendValueAll() const
Definition: PointIndexGrid.h:1628
ValueAllCIter beginValueAll() const
Definition: PointIndexGrid.h:1619
void modifyValue(const Coord &, const ModifyOp &)
Definition: PointIndexGrid.h:1533
Definition: PointDataGrid.h:171
ChildOffCIter cendChildOff() const
Definition: PointIndexGrid.h:1645
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
ChildOffCIter cbeginChildOff() const
Definition: PointIndexGrid.h:1635
PointIndexLeafNode * touchLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: PointIndexGrid.h:1452
void fill(const ValueType &)
Definition: PointIndexGrid.h:1541
typename BaseLeaf::template DenseIter< const PointIndexLeafNode, const ValueType, ChildAll > ChildAllCIter
Definition: PointIndexGrid.h:1609
void setValueOn(Index)
Definition: PointIndexGrid.h:1519
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:218
void setOffsetOnly(Index offset, const ValueType &val)
Definition: PointIndexGrid.h:1690
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:689
ChildAllIter endChildAll()
Definition: PointIndexGrid.h:1650