16#ifndef OPENVDB_TOOLS_POINT_INDEX_GRID_HAS_BEEN_INCLUDED
17#define OPENVDB_TOOLS_POINT_INDEX_GRID_HAS_BEEN_INCLUDED
19#include "openvdb/thread/Threading.h"
22#include <openvdb/version.h>
31#include <tbb/blocked_range.h>
32#include <tbb/parallel_for.h>
48template<Index,
typename>
struct SameLeafConfig;
53template<
typename T, Index Log2Dim>
struct PointIndexLeafNode;
92template<
typename Gr
idT,
typename Po
intArrayT>
93inline typename GridT::Ptr
102template<
typename Gr
idT,
typename Po
intArrayT>
103inline typename GridT::Ptr
112template<
typename Po
intArrayT,
typename Gr
idT>
118template<
typename Gr
idT,
typename Po
intArrayT>
119inline typename GridT::ConstPtr
123template<
typename Gr
idT,
typename Po
intArrayT>
124inline typename GridT::Ptr
132template<
typename TreeType = Po
intIndexTree>
180 template<
typename Po
intArray>
195 template<
typename Po
intArray>
196 void searchAndUpdate(
const Vec3d& center,
double radius,
ConstAccessor& acc,
206 template<
typename Po
intArray>
221 template<
typename Po
intArray>
222 void worldSpaceSearchAndUpdate(
const Vec3d& center,
double radius,
ConstAccessor& acc,
234 bool test()
const {
return mRange.first < mRange.second || mIter != mRangeList.end(); }
235 operator bool()
const {
return this->test(); }
258 using Range = std::pair<const ValueType*, const ValueType*>;
259 using RangeDeque = std::deque<Range>;
260 using RangeDequeCIter =
typename RangeDeque::const_iterator;
261 using IndexArray = std::unique_ptr<ValueType[]>;
267 RangeDeque mRangeList;
268 RangeDequeCIter mIter;
270 IndexArray mIndexArray;
271 size_t mIndexArraySize;
304template<
typename Po
intArray,
typename TreeType = Po
intIndexTree>
325 template<
typename FilterType>
343namespace point_index_grid_internal {
345template<
typename Po
intArrayT>
346struct ValidPartitioningOp
348 ValidPartitioningOp(std::atomic<bool>& hasChanged,
352 , mHasChanged(&hasChanged)
356 template <
typename LeafT>
357 void operator()(LeafT &leaf,
size_t )
const
359 if ((*mHasChanged)) {
360 thread::cancelGroupExecution();
365 using IndexT =
typename IndexArrayT::value_type;
366 using PosType =
typename PointArrayT::PosType;
368 typename LeafT::ValueOnCIter iter;
373 *begin =
static_cast<IndexT*
>(
nullptr),
374 *end =
static_cast<IndexT*
>(
nullptr);
376 for (iter = leaf.cbeginValueOn(); iter; ++iter) {
378 if ((*mHasChanged))
break;
380 voxelCoord = iter.getCoord();
381 leaf.getIndices(iter.pos(), begin, end);
383 while (begin < end) {
385 mPoints->getPos(*begin, point);
386 if (voxelCoord != mTransform->worldToIndexCellCentered(point)) {
387 mHasChanged->store(
true);
397 PointArrayT
const *
const mPoints;
398 math::Transform
const *
const mTransform;
399 std::atomic<bool> *
const mHasChanged;
403template<
typename LeafNodeT>
404struct PopulateLeafNodesOp
406 using IndexT = uint32_t;
407 using Partitioner = PointPartitioner<IndexT, LeafNodeT::LOG2DIM>;
409 PopulateLeafNodesOp(std::unique_ptr<LeafNodeT*[]>& leafNodes,
410 const Partitioner& partitioner)
411 : mLeafNodes(leafNodes.get())
412 , mPartitioner(&partitioner)
416 void operator()(
const tbb::blocked_range<size_t>& range)
const {
418 using VoxelOffsetT =
typename Partitioner::VoxelOffsetType;
420 size_t maxPointCount = 0;
421 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
422 maxPointCount =
std::max(maxPointCount, mPartitioner->indices(n).size());
425 const IndexT voxelCount = LeafNodeT::SIZE;
428 std::unique_ptr<VoxelOffsetT[]> offsets{
new VoxelOffsetT[maxPointCount]};
429 std::unique_ptr<IndexT[]>
histogram{
new IndexT[voxelCount]};
431 VoxelOffsetT
const *
const voxelOffsets = mPartitioner->voxelOffsets().get();
433 for (
size_t n = range.begin(), N = range.end(); n != N; ++n) {
435 LeafNodeT* node =
new LeafNodeT();
436 node->setOrigin(mPartitioner->origin(n));
438 typename Partitioner::IndexIterator it = mPartitioner->indices(n);
441 IndexT
const *
const indices = &*it;
445 offsets[i] = voxelOffsets[ indices[i] ];
449 memset(&
histogram[0], 0, voxelCount *
sizeof(IndexT));
454 typename LeafNodeT::NodeMaskType& mask = node->getValueMask();
455 typename LeafNodeT::Buffer& buffer = node->buffer();
458 IndexT count = 0, startOffset;
459 for (
int i = 0; i < int(voxelCount); ++i) {
466 buffer.setValue(i, count);
471 typename LeafNodeT::ValueType *
const orderedIndices = node->indices().data();
475 orderedIndices[
histogram[ offsets[i] ]++ ] = indices[i];
478 mLeafNodes[n] = node;
484 LeafNodeT* *
const mLeafNodes;
485 Partitioner
const *
const mPartitioner;
490template<
typename TreeType,
typename Po
intArray>
492constructPointTree(TreeType& tree,
const math::Transform& xform,
const PointArray& points)
494 using LeafType =
typename TreeType::LeafNodeType;
496 std::unique_ptr<LeafType*[]> leafNodes;
497 size_t leafNodeCount = 0;
503 PointPartitioner<uint32_t, LeafType::LOG2DIM> partitioner;
504 partitioner.construct(points, xform,
false,
true);
506 if (!partitioner.usingCellCenteredTransform()) {
508 "cell-centered transform.");
511 leafNodeCount = partitioner.size();
512 leafNodes.reset(
new LeafType*[leafNodeCount]);
514 const tbb::blocked_range<size_t> range(0, leafNodeCount);
515 tbb::parallel_for(range, PopulateLeafNodesOp<LeafType>(leafNodes, partitioner));
518 tree::ValueAccessor<TreeType> acc(tree);
519 for (
size_t n = 0; n < leafNodeCount; ++n) {
520 acc.addLeaf(leafNodes[n]);
530dequeToArray(
const std::deque<T>& d, std::unique_ptr<T[]>& a,
size_t& size)
533 a.reset(
new T[size]);
534 typename std::deque<T>::const_iterator it = d.begin(), itEnd = d.end();
536 for ( ; it != itEnd; ++it, ++item) *item = *it;
541constructExclusiveRegions(std::vector<CoordBBox>& regions,
546 Coord cmin = ibox.min();
547 Coord cmax = ibox.max();
550 regions.push_back(bbox);
551 regions.back().max().z() = cmin.z();
554 regions.push_back(bbox);
555 regions.back().min().z() = cmax.z();
561 regions.push_back(bbox);
563 lastRegion->min().z() = cmin.z();
564 lastRegion->max().z() = cmax.z();
565 lastRegion->max().x() = cmin.x();
568 regions.push_back(*lastRegion);
569 lastRegion = ®ions.back();
570 lastRegion->min().x() = cmax.x();
571 lastRegion->max().x() = bbox.max().x();
577 regions.push_back(*lastRegion);
578 lastRegion = ®ions.back();
579 lastRegion->min().x() = cmin.x();
580 lastRegion->max().x() = cmax.x();
581 lastRegion->max().y() = cmin.y();
584 regions.push_back(*lastRegion);
585 lastRegion = ®ions.back();
586 lastRegion->min().y() = cmax.y();
587 lastRegion->max().y() = bbox.max().y();
591template<
typename Po
intArray,
typename IndexT>
594 using PosType =
typename PointArray::PosType;
595 using ScalarType =
typename PosType::value_type;
596 using Range = std::pair<const IndexT*, const IndexT*>;
597 using RangeDeque = std::deque<Range>;
598 using IndexDeque = std::deque<IndexT>;
600 BBoxFilter(RangeDeque& ranges, IndexDeque& indices,
const BBoxd& bbox,
601 const PointArray& points,
const math::Transform& xform)
606 , mMap(*xform.baseMap())
610 template <
typename LeafNodeType>
611 void filterLeafNode(
const LeafNodeType& leaf)
613 typename LeafNodeType::ValueOnCIter iter;
615 *begin =
static_cast<IndexT*
>(
nullptr),
616 *end =
static_cast<IndexT*
>(
nullptr);
617 for (iter = leaf.cbeginValueOn(); iter; ++iter) {
618 leaf.getIndices(iter.pos(), begin, end);
619 filterVoxel(iter.getCoord(), begin, end);
623 void filterVoxel(
const Coord&,
const IndexT* begin,
const IndexT* end)
627 for (; begin < end; ++begin) {
628 mPoints.getPos(*begin, vec);
630 if (mRegion.isInside(mMap.applyInverseMap(vec))) {
631 mIndices.push_back(*begin);
638 IndexDeque& mIndices;
641 const math::MapBase& mMap;
645template<
typename Po
intArray,
typename IndexT>
646struct RadialRangeFilter
648 using PosType =
typename PointArray::PosType;
649 using ScalarType =
typename PosType::value_type;
650 using Range = std::pair<const IndexT*, const IndexT*>;
651 using RangeDeque = std::deque<Range>;
652 using IndexDeque = std::deque<IndexT>;
654 RadialRangeFilter(RangeDeque& ranges, IndexDeque& indices,
const Vec3d& xyz,
double radius,
655 const PointArray& points,
const math::Transform& xform,
656 const double leafNodeDim,
const bool subvoxelAccuracy)
660 , mWSCenter(xform.indexToWorld(xyz))
661 , mVoxelDist1(ScalarType(0.0))
662 , mVoxelDist2(ScalarType(0.0))
663 , mLeafNodeDist1(ScalarType(0.0))
664 , mLeafNodeDist2(ScalarType(0.0))
665 , mWSRadiusSqr(ScalarType(radius * xform.voxelSize()[0]))
667 , mSubvoxelAccuracy(subvoxelAccuracy)
669 const ScalarType voxelRadius = ScalarType(std::sqrt(3.0) * 0.5);
670 mVoxelDist1 = voxelRadius + ScalarType(radius);
671 mVoxelDist1 *= mVoxelDist1;
673 if (radius > voxelRadius) {
674 mVoxelDist2 = ScalarType(radius) - voxelRadius;
675 mVoxelDist2 *= mVoxelDist2;
678 const ScalarType leafNodeRadius = ScalarType(leafNodeDim * std::sqrt(3.0) * 0.5);
679 mLeafNodeDist1 = leafNodeRadius + ScalarType(radius);
680 mLeafNodeDist1 *= mLeafNodeDist1;
682 if (radius > leafNodeRadius) {
683 mLeafNodeDist2 = ScalarType(radius) - leafNodeRadius;
684 mLeafNodeDist2 *= mLeafNodeDist2;
687 mWSRadiusSqr *= mWSRadiusSqr;
690 template <
typename LeafNodeType>
691 void filterLeafNode(
const LeafNodeType& leaf)
694 const Coord& ijk = leaf.origin();
696 vec[0] = ScalarType(ijk[0]);
697 vec[1] = ScalarType(ijk[1]);
698 vec[2] = ScalarType(ijk[2]);
699 vec += ScalarType(LeafNodeType::DIM - 1) * 0.5;
702 const ScalarType dist = vec.lengthSqr();
703 if (dist > mLeafNodeDist1)
return;
705 if (mLeafNodeDist2 > 0.0 && dist < mLeafNodeDist2) {
706 const IndexT* begin = &leaf.indices().front();
707 mRanges.push_back(Range(begin, begin + leaf.indices().size()));
712 typename LeafNodeType::ValueOnCIter iter;
714 *begin =
static_cast<IndexT*
>(
nullptr),
715 *end =
static_cast<IndexT*
>(
nullptr);
716 for (iter = leaf.cbeginValueOn(); iter; ++iter) {
717 leaf.getIndices(iter.pos(), begin, end);
718 filterVoxel(iter.getCoord(), begin, end);
722 void filterVoxel(
const Coord& ijk,
const IndexT* begin,
const IndexT* end)
727 vec[0] = mCenter[0] - ScalarType(ijk[0]);
728 vec[1] = mCenter[1] - ScalarType(ijk[1]);
729 vec[2] = mCenter[2] - ScalarType(ijk[2]);
731 const ScalarType dist = vec.lengthSqr();
732 if (dist > mVoxelDist1)
return;
734 if (!mSubvoxelAccuracy || (mVoxelDist2 > 0.0 && dist < mVoxelDist2)) {
735 if (!mRanges.empty() && mRanges.back().second == begin) {
736 mRanges.back().second = end;
738 mRanges.push_back(Range(begin, end));
745 while (begin < end) {
746 mPoints.getPos(*begin, vec);
747 vec = mWSCenter - vec;
749 if (vec.lengthSqr() < mWSRadiusSqr) {
750 mIndices.push_back(*begin);
758 IndexDeque& mIndices;
759 const PosType mCenter, mWSCenter;
760 ScalarType mVoxelDist1, mVoxelDist2, mLeafNodeDist1, mLeafNodeDist2, mWSRadiusSqr;
762 const bool mSubvoxelAccuracy;
769template<
typename RangeFilterType,
typename LeafNodeType>
771filteredPointIndexSearchVoxels(RangeFilterType& filter,
772 const LeafNodeType& leaf,
const Coord&
min,
const Coord&
max)
774 using PointIndexT =
typename LeafNodeType::ValueType;
775 Index xPos(0), yPos(0), pos(0);
778 const PointIndexT* dataPtr = &leaf.indices().front();
779 PointIndexT beginOffset, endOffset;
781 for (ijk[0] =
min[0]; ijk[0] <=
max[0]; ++ijk[0]) {
782 xPos = (ijk[0] & (LeafNodeType::DIM - 1u)) << (2 * LeafNodeType::LOG2DIM);
783 for (ijk[1] =
min[1]; ijk[1] <=
max[1]; ++ijk[1]) {
784 yPos = xPos + ((ijk[1] & (LeafNodeType::DIM - 1u)) << LeafNodeType::LOG2DIM);
785 for (ijk[2] =
min[2]; ijk[2] <=
max[2]; ++ijk[2]) {
786 pos = yPos + (ijk[2] & (LeafNodeType::DIM - 1u));
788 beginOffset = (pos == 0 ? PointIndexT(0) : leaf.getValue(pos - 1));
789 endOffset = leaf.getValue(pos);
791 if (endOffset > beginOffset) {
792 filter.filterVoxel(ijk, dataPtr + beginOffset, dataPtr + endOffset);
800template<
typename RangeFilterType,
typename ConstAccessor>
802filteredPointIndexSearch(RangeFilterType& filter, ConstAccessor& acc,
const CoordBBox& bbox)
804 using LeafNodeType =
typename ConstAccessor::TreeType::LeafNodeType;
805 Coord ijk(0), ijkMax(0), ijkA(0), ijkB(0);
806 const Coord leafMin = bbox.min() & ~(LeafNodeType::DIM - 1);
807 const Coord leafMax = bbox.max() & ~(LeafNodeType::DIM - 1);
809 for (ijk[0] = leafMin[0]; ijk[0] <= leafMax[0]; ijk[0] += LeafNodeType::DIM) {
810 for (ijk[1] = leafMin[1]; ijk[1] <= leafMax[1]; ijk[1] += LeafNodeType::DIM) {
811 for (ijk[2] = leafMin[2]; ijk[2] <= leafMax[2]; ijk[2] += LeafNodeType::DIM) {
813 if (
const LeafNodeType* leaf = acc.probeConstLeaf(ijk)) {
815 ijkMax.offset(LeafNodeType::DIM - 1);
821 if (ijkA != ijk || ijkB != ijkMax) {
822 filteredPointIndexSearchVoxels(filter, *leaf, ijkA, ijkB);
824 filter.filterLeafNode(*leaf);
836template<
typename RangeDeque,
typename LeafNodeType>
838pointIndexSearchVoxels(RangeDeque& rangeList,
839 const LeafNodeType& leaf,
const Coord&
min,
const Coord&
max)
841 using PointIndexT =
typename LeafNodeType::ValueType;
842 using IntT =
typename PointIndexT::IntType;
843 using Range =
typename RangeDeque::value_type;
846 const PointIndexT* dataPtr = &leaf.indices().front();
847 PointIndexT beginOffset(0), endOffset(0),
848 previousOffset(
static_cast<IntT
>(leaf.indices().size() + 1u));
851 for (ijk[0] =
min[0]; ijk[0] <=
max[0]; ++ijk[0]) {
852 xPos = (ijk[0] & (LeafNodeType::DIM - 1u)) << (2 * LeafNodeType::LOG2DIM);
854 for (ijk[1] =
min[1]; ijk[1] <=
max[1]; ++ijk[1]) {
855 pos = xPos + ((ijk[1] & (LeafNodeType::DIM - 1u)) << LeafNodeType::LOG2DIM);
856 pos += (
min[2] & (LeafNodeType::DIM - 1u));
858 beginOffset = (pos == 0 ? PointIndexT(0) : leaf.getValue(pos - 1));
859 endOffset = leaf.getValue(pos+zStride);
861 if (endOffset > beginOffset) {
863 if (beginOffset == previousOffset) {
864 rangeList.back().second = dataPtr + endOffset;
866 rangeList.push_back(Range(dataPtr + beginOffset, dataPtr + endOffset));
869 previousOffset = endOffset;
876template<
typename RangeDeque,
typename ConstAccessor>
878pointIndexSearch(RangeDeque& rangeList, ConstAccessor& acc,
const CoordBBox& bbox)
880 using LeafNodeType =
typename ConstAccessor::TreeType::LeafNodeType;
881 using PointIndexT =
typename LeafNodeType::ValueType;
882 using Range =
typename RangeDeque::value_type;
884 Coord ijk(0), ijkMax(0), ijkA(0), ijkB(0);
885 const Coord leafMin = bbox.min() & ~(LeafNodeType::DIM - 1);
886 const Coord leafMax = bbox.max() & ~(LeafNodeType::DIM - 1);
888 for (ijk[0] = leafMin[0]; ijk[0] <= leafMax[0]; ijk[0] += LeafNodeType::DIM) {
889 for (ijk[1] = leafMin[1]; ijk[1] <= leafMax[1]; ijk[1] += LeafNodeType::DIM) {
890 for (ijk[2] = leafMin[2]; ijk[2] <= leafMax[2]; ijk[2] += LeafNodeType::DIM) {
892 if (
const LeafNodeType* leaf = acc.probeConstLeaf(ijk)) {
894 ijkMax.offset(LeafNodeType::DIM - 1);
900 if (ijkA != ijk || ijkB != ijkMax) {
901 pointIndexSearchVoxels(rangeList, *leaf, ijkA, ijkB);
904 const PointIndexT* begin = &leaf->indices().front();
905 rangeList.push_back(Range(begin, (begin + leaf->indices().size())));
920template<
typename TreeType>
925 , mIter(mRangeList.begin())
932template<
typename TreeType>
936 , mRangeList(rhs.mRangeList)
937 , mIter(mRangeList.begin())
939 , mIndexArraySize(rhs.mIndexArraySize)
941 if (rhs.mIndexArray) {
942 mIndexArray.reset(
new ValueType[mIndexArraySize]);
943 memcpy(mIndexArray.get(), rhs.mIndexArray.get(), mIndexArraySize *
sizeof(
ValueType));
948template<
typename TreeType>
954 mRangeList = rhs.mRangeList;
955 mIter = mRangeList.begin();
957 mIndexArraySize = rhs.mIndexArraySize;
959 if (rhs.mIndexArray) {
960 mIndexArray.reset(
new ValueType[mIndexArraySize]);
961 memcpy(mIndexArray.get(), rhs.mIndexArray.get(), mIndexArraySize *
sizeof(
ValueType));
968template<
typename TreeType>
973 , mIter(mRangeList.begin())
978 if (leaf && leaf->getIndices(ijk, mRange.first, mRange.second)) {
979 mRangeList.push_back(mRange);
980 mIter = mRangeList.begin();
985template<
typename TreeType>
990 , mIter(mRangeList.begin())
994 point_index_grid_internal::pointIndexSearch(mRangeList, acc, bbox);
996 if (!mRangeList.empty()) {
997 mIter = mRangeList.begin();
998 mRange = mRangeList.front();
1003template<
typename TreeType>
1007 mIter = mRangeList.begin();
1008 if (!mRangeList.empty()) {
1009 mRange = mRangeList.front();
1010 }
else if (mIndexArray) {
1011 mRange.first = mIndexArray.get();
1012 mRange.second = mRange.first + mIndexArraySize;
1014 mRange.first =
static_cast<ValueType*
>(
nullptr);
1015 mRange.second =
static_cast<ValueType*
>(
nullptr);
1020template<
typename TreeType>
1025 if (mRange.first >= mRange.second && mIter != mRangeList.end()) {
1027 if (mIter != mRangeList.end()) {
1029 }
else if (mIndexArray) {
1030 mRange.first = mIndexArray.get();
1031 mRange.second = mRange.first + mIndexArraySize;
1037template<
typename TreeType>
1041 if (!this->test())
return false;
1043 return this->test();
1047template<
typename TreeType>
1052 typename RangeDeque::const_iterator it = mRangeList.begin();
1054 for ( ; it != mRangeList.end(); ++it) {
1055 count += it->second - it->first;
1058 return count + mIndexArraySize;
1062template<
typename TreeType>
1066 mRange.first =
static_cast<ValueType*
>(
nullptr);
1067 mRange.second =
static_cast<ValueType*
>(
nullptr);
1069 mIter = mRangeList.end();
1070 mIndexArray.reset();
1071 mIndexArraySize = 0;
1075template<
typename TreeType>
1081 if (leaf && leaf->getIndices(ijk, mRange.first, mRange.second)) {
1082 mRangeList.push_back(mRange);
1083 mIter = mRangeList.begin();
1088template<
typename TreeType>
1093 point_index_grid_internal::pointIndexSearch(mRangeList, acc, bbox);
1095 if (!mRangeList.empty()) {
1096 mIter = mRangeList.begin();
1097 mRange = mRangeList.front();
1102template<
typename TreeType>
1103template<
typename Po
intArray>
1110 std::vector<CoordBBox> searchRegions;
1116 if (minExtent > 2) {
1121 point_index_grid_internal::pointIndexSearch(mRangeList, acc, ibox);
1125 point_index_grid_internal::constructExclusiveRegions(searchRegions, region, ibox);
1127 searchRegions.push_back(region);
1131 std::deque<ValueType> filteredIndices;
1132 point_index_grid_internal::BBoxFilter<PointArray, ValueType>
1133 filter(mRangeList, filteredIndices, bbox, points, xform);
1135 for (
size_t n = 0, N = searchRegions.size(); n < N; ++n) {
1136 point_index_grid_internal::filteredPointIndexSearch(filter, acc, searchRegions[n]);
1139 point_index_grid_internal::dequeToArray(filteredIndices, mIndexArray, mIndexArraySize);
1145template<
typename TreeType>
1146template<
typename Po
intArray>
1150 bool subvoxelAccuracy)
1153 std::vector<CoordBBox> searchRegions;
1157 Coord::round(Vec3d(center[0] - radius, center[1] - radius, center[2] - radius)),
1158 Coord::round(Vec3d(center[0] + radius, center[1] + radius, center[2] + radius)));
1161 const double iRadius = radius * double(1.0 / std::sqrt(3.0));
1162 if (iRadius > 2.0) {
1165 Coord::round(Vec3d(center[0] - iRadius, center[1] - iRadius, center[2] - iRadius)),
1166 Coord::round(Vec3d(center[0] + iRadius, center[1] + iRadius, center[2] + iRadius)));
1170 point_index_grid_internal::pointIndexSearch(mRangeList, acc, ibox);
1173 point_index_grid_internal::constructExclusiveRegions(searchRegions, bbox, ibox);
1175 searchRegions.push_back(bbox);
1179 std::deque<ValueType> filteredIndices;
1180 const double leafNodeDim = double(TreeType::LeafNodeType::DIM);
1182 using FilterT = point_index_grid_internal::RadialRangeFilter<PointArray, ValueType>;
1184 FilterT filter(mRangeList, filteredIndices,
1185 center, radius, points, xform, leafNodeDim, subvoxelAccuracy);
1187 for (
size_t n = 0, N = searchRegions.size(); n < N; ++n) {
1188 point_index_grid_internal::filteredPointIndexSearch(filter, acc, searchRegions[n]);
1191 point_index_grid_internal::dequeToArray(filteredIndices, mIndexArray, mIndexArraySize);
1197template<
typename TreeType>
1198template<
typename Po
intArray>
1203 this->searchAndUpdate(
1208template<
typename TreeType>
1209template<
typename Po
intArray>
1213 bool subvoxelAccuracy)
1216 (radius / xform.
voxelSize()[0]), acc, points, xform, subvoxelAccuracy);
1224template<
typename Po
intArray,
typename TreeType>
1228 : mPoints(&points), mAcc(tree), mXform(xform), mInvVoxelSize(1.0/xform.voxelSize()[0])
1233template<
typename Po
intArray,
typename TreeType>
1236 : mPoints(rhs.mPoints)
1237 , mAcc(rhs.mAcc.tree())
1238 , mXform(rhs.mXform)
1239 , mInvVoxelSize(rhs.mInvVoxelSize)
1244template<
typename Po
intArray,
typename TreeType>
1245template<
typename FilterType>
1250 if (radius * mInvVoxelSize <
ScalarType(8.0)) {
1252 mXform.worldToIndexCellCentered(center - radius),
1253 mXform.worldToIndexCellCentered(center + radius)), mAcc);
1255 mIter.worldSpaceSearchAndUpdate(
1256 center, radius, mAcc, *mPoints, mXform,
false);
1259 const ScalarType radiusSqr = radius * radius;
1262 for (; mIter; ++mIter) {
1263 mPoints->getPos(*mIter, pos);
1265 distSqr = pos.lengthSqr();
1267 if (distSqr < radiusSqr) {
1268 op(distSqr, *mIter);
1277template<
typename Gr
idT,
typename Po
intArrayT>
1278inline typename GridT::Ptr
1281 typename GridT::Ptr grid = GridT::create(
typename GridT::ValueType(0));
1282 grid->setTransform(xform.
copy());
1284 if (points.size() > 0) {
1285 point_index_grid_internal::constructPointTree(
1286 grid->tree(), grid->transform(), points);
1293template<
typename Gr
idT,
typename Po
intArrayT>
1294inline typename GridT::Ptr
1298 return createPointIndexGrid<GridT>(points, *xform);
1302template<
typename Po
intArrayT,
typename Gr
idT>
1309 for (
size_t n = 0, N = leafs.
leafCount(); n < N; ++n) {
1317 std::atomic<bool> changed;
1320 point_index_grid_internal::ValidPartitioningOp<PointArrayT>
1321 op(changed, points, grid.transform());
1325 return !bool(changed);
1329template<
typename Gr
idT,
typename Po
intArrayT>
1330inline typename GridT::ConstPtr
1337 return createPointIndexGrid<GridT>(points, grid->transform());
1341template<
typename Gr
idT,
typename Po
intArrayT>
1342inline typename GridT::Ptr
1349 return createPointIndexGrid<GridT>(points, grid->transform());
1356template<
typename T, Index Log2Dim>
1408 const T&
value = zeroVal<T>(),
bool active =
false)
1419 template<
typename OtherType, Index OtherLog2Dim>
1430 BaseLeaf::merge<Policy>(rhs);
1432 template<MergePolicy Policy>
void merge(
const ValueType& tileValue,
bool tileActive) {
1433 BaseLeaf::template merge<Policy>(tileValue, tileActive);
1436 template<MergePolicy Policy>
1440 BaseLeaf::template merge<Policy>(other);
1444 template<
typename AccessorT>
1450 template<
typename AccessorT>
1453 template<
typename NodeT,
typename AccessorT>
1458 return reinterpret_cast<NodeT*
>(
this);
1462 template<
typename AccessorT>
1469 template<
typename AccessorT>
1471 template<
typename AccessorT>
1474 template<
typename NodeT,
typename AccessorT>
1479 return reinterpret_cast<const NodeT*
>(
this);
1487 void readBuffers(std::istream& is,
bool fromHalf =
false);
1489 void writeBuffers(std::ostream& os,
bool toHalf =
false)
const;
1501 assert(
false &&
"Cannot modify voxel values in a PointIndexTree.");
1527 template<
typename ModifyOp>
1530 template<
typename ModifyOp>
1533 template<
typename ModifyOp>
1542 template<
typename AccessorT>
1545 template<
typename ModifyOp,
typename AccessorT>
1550 template<
typename AccessorT>
1553 template<
typename AccessorT>
1609#define VMASK_ this->getValueMask()
1653template<
typename T, Index Log2Dim>
1658 return getIndices(LeafNodeType::coordToOffset(ijk), begin, end);
1662template<
typename T, Index Log2Dim>
1667 if (this->isValueMaskOn(offset)) {
1668 const ValueType* dataPtr = &mIndices.front();
1669 begin = dataPtr + (offset == 0 ?
ValueType(0) : this->buffer()[offset - 1]);
1670 end = dataPtr + this->buffer()[offset];
1677template<
typename T, Index Log2Dim>
1681 this->buffer().setValue(offset, val);
1682 this->setValueMaskOn(offset);
1686template<
typename T, Index Log2Dim>
1690 this->buffer().setValue(offset, val);
1694template<
typename T, Index Log2Dim>
1701 for (ijk[0] = bbox.
min()[0]; ijk[0] <= bbox.
max()[0]; ++ijk[0]) {
1702 xPos = (ijk[0] & (DIM - 1u)) << (2 * LOG2DIM);
1704 for (ijk[1] = bbox.
min()[1]; ijk[1] <= bbox.
max()[1]; ++ijk[1]) {
1705 pos = xPos + ((ijk[1] & (DIM - 1u)) << LOG2DIM);
1706 pos += (bbox.
min()[2] & (DIM - 1u));
1708 if (this->buffer()[pos+zStride] > (pos == 0 ? T(0) : this->buffer()[pos - 1])) {
1718template<
typename T, Index Log2Dim>
1722 BaseLeaf::readBuffers(is, fromHalf);
1725 is.read(
reinterpret_cast<char*
>(&numIndices),
sizeof(
Index64));
1727 mIndices.resize(
size_t(numIndices));
1728 is.read(
reinterpret_cast<char*
>(mIndices.data()), numIndices *
sizeof(T));
1732template<
typename T, Index Log2Dim>
1737 BaseLeaf::readBuffers(is, bbox, fromHalf);
1740 is.read(
reinterpret_cast<char*
>(&numIndices),
sizeof(
Index64));
1742 const Index64 numBytes = numIndices *
sizeof(T);
1744 if (bbox.
hasOverlap(this->getNodeBoundingBox())) {
1745 mIndices.resize(
size_t(numIndices));
1746 is.read(
reinterpret_cast<char*
>(mIndices.data()), numBytes);
1752 std::unique_ptr<char[]> buf{
new char[numBytes]};
1753 is.read(buf.get(), numBytes);
1758 is.read(
reinterpret_cast<char*
>(&auxDataBytes),
sizeof(
Index64));
1759 if (auxDataBytes > 0) {
1761 std::unique_ptr<char[]> auxData{
new char[auxDataBytes]};
1762 is.read(auxData.get(), auxDataBytes);
1767template<
typename T, Index Log2Dim>
1771 BaseLeaf::writeBuffers(os, toHalf);
1774 os.write(
reinterpret_cast<const char*
>(&numIndices),
sizeof(
Index64));
1775 os.write(
reinterpret_cast<const char*
>(mIndices.data()), numIndices *
sizeof(T));
1779 os.write(
reinterpret_cast<const char*
>(&auxDataBytes),
sizeof(
Index64));
1783template<
typename T, Index Log2Dim>
1800template<Index Dim1,
typename T2>
ValueT value
Definition: GridBuilder.h:1287
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
#define VMASK_
Definition: PointIndexGrid.h:1609
Spatially partitions points using a parallel radix-based sorting algorithm.
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:577
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:570
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:248
void expand(ValueType padding)
Pad this bounding box with the specified padding.
Definition: Coord.h:417
const Coord & min() const
Definition: Coord.h:320
bool hasOverlap(const CoordBBox &b) const
Return true if the given bounding box overlaps with this bounding box.
Definition: Coord.h:411
const Coord & max() const
Definition: Coord.h:321
Coord dim() const
Return the dimensions of the coordinates spanned by this bounding box.
Definition: Coord.h:379
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:25
static Coord round(const Vec3< T > &xyz)
Return xyz rounded to the closest integer coordinates (cell centered conversion).
Definition: Coord.h:50
void minComponent(const Coord &other)
Perform a component-wise minimum with the other Coord.
Definition: Coord.h:175
void maxComponent(const Coord &other)
Perform a component-wise maximum with the other Coord.
Definition: Coord.h:183
Definition: InternalNode.h:34
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:85
LeafType & leaf(size_t leafIdx) const
Return a pointer to the leaf node at index leafIdx in the array.
Definition: LeafManager.h:318
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:483
size_t leafCount() const
Return the number of leaf nodes.
Definition: LeafManager.h:287
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim....
Definition: LeafNode.h:38
static const Index NUM_VOXELS
Definition: LeafNode.h:52
static const Index DIM
Definition: LeafNode.h:50
static const Index LEVEL
Definition: LeafNode.h:54
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:1492
static const Index NUM_VALUES
Definition: LeafNode.h:51
static const Index LOG2DIM
Definition: LeafNode.h:48
bool operator==(const LeafNode &other) const
Check for buffer, state and origin equivalence.
Definition: LeafNode.h:1454
static const Index SIZE
Definition: LeafNode.h:53
bool isEmpty() const
Return true if this node has no active voxels.
Definition: LeafNode.h:148
static const Index TOTAL
Definition: LeafNode.h:49
Definition: RootNode.h:39
Definition: ValueAccessor.h:183
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Definition: ValueAccessor.h:384
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.
BBox< Coord > CoordBBox
Definition: NanoVDB.h:1658
bool operator==(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Equality operator, does exact floating point comparisons.
Definition: Vec3.h:477
std::vector< Index > IndexArray
Definition: PointMove.h:161
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: PointCount.h:88
Index32 Index
Definition: Types.h:54
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
Definition: LeafNode.h:211
Leaf nodes have no children, so their child iterators have no get/set accessors.
Definition: LeafNode.h:251
Definition: LeafNode.h:211
Definition: LeafNode.h:211
Definition: LeafNode.h:260
Definition: LeafNode.h:210
Definition: LeafNode.h:219
Definition: LeafNode.h:210
Definition: LeafNode.h:210
Definition: LeafNode.h:923
static const bool value
Definition: LeafNode.h:923
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202