25 #ifndef OPENVDB_TOOLS_PARTICLE_ATLAS_HAS_BEEN_INCLUDED
26 #define OPENVDB_TOOLS_PARTICLE_ATLAS_HAS_BEEN_INCLUDED
36 #include <tbb/blocked_range.h>
37 #include <tbb/parallel_for.h>
38 #include <tbb/parallel_reduce.h>
82 template<
typename Po
intIndexGr
idType = Po
intIndexGr
id>
95 ParticleAtlas() : mIndexGridArray(), mMinRadiusArray(), mMaxRadiusArray() {}
102 template<
typename ParticleArrayType>
103 void construct(
const ParticleArrayType& particles,
double minVoxelSize,
size_t maxLevels = 50);
110 template<
typename ParticleArrayType>
111 static Ptr create(
const ParticleArrayType& particles,
112 double minVoxelSize,
size_t maxLevels = 50);
115 size_t levels()
const {
return mIndexGridArray.size(); }
117 bool empty()
const {
return mIndexGridArray.empty(); }
134 std::vector<PointIndexGridPtr> mIndexGridArray;
135 std::vector<double> mMinRadiusArray, mMaxRadiusArray;
150 template<
typename Po
intIndexGr
idType>
153 using TreeType =
typename PointIndexGridType::TreeType;
167 template<
typename ParticleArrayType>
168 void worldSpaceSearchAndUpdate(
const Vec3d&
center,
double radius,
169 const ParticleArrayType& particles);
175 template<
typename ParticleArrayType>
176 void worldSpaceSearchAndUpdate(
const BBoxd& bbox,
const ParticleArrayType& particles);
179 size_t levels()
const {
return mAtlas->levels(); }
183 void updateFromLevel(
size_t level);
193 bool test()
const {
return mRange.first < mRange.second || mIter != mRangeList.end(); }
194 operator bool()
const {
return this->
test(); }
220 using Range = std::pair<const IndexType*, const IndexType*>;
221 using RangeDeque = std::deque<Range>;
222 using RangeDequeCIter =
typename RangeDeque::const_iterator;
223 using IndexArray = std::unique_ptr<IndexType[]>;
226 std::unique_ptr<ConstAccessorPtr[]> mAccessorList;
230 RangeDeque mRangeList;
231 RangeDequeCIter mIter;
233 IndexArray mIndexArray;
234 size_t mIndexArraySize, mAccessorListSize;
244 namespace particle_atlas_internal {
247 template<
typename ParticleArrayT>
248 struct ComputeExtremas
250 using PosType =
typename ParticleArrayT::PosType;
253 ComputeExtremas(
const ParticleArrayT& particles)
254 : particleArray(&particles)
255 , minRadius(std::numeric_limits<ScalarType>::
max())
256 , maxRadius(-std::numeric_limits<ScalarType>::
max())
260 ComputeExtremas(ComputeExtremas& rhs,
tbb::split)
261 : particleArray(rhs.particleArray)
262 , minRadius(std::numeric_limits<ScalarType>::
max())
263 , maxRadius(-std::numeric_limits<ScalarType>::
max())
267 void operator()(
const tbb::blocked_range<size_t>&
range) {
269 ScalarType radius, tmpMin = minRadius, tmpMax = maxRadius;
271 for (
size_t n = range.begin(),
N = range.
end();
n !=
N; ++
n) {
272 particleArray->getRadius(
n, radius);
277 minRadius =
std::min(minRadius, tmpMin);
278 maxRadius =
std::max(maxRadius, tmpMax);
281 void join(
const ComputeExtremas& rhs) {
282 minRadius =
std::min(minRadius, rhs.minRadius);
283 maxRadius =
std::max(maxRadius, rhs.maxRadius);
286 ParticleArrayT
const *
const particleArray;
287 ScalarType minRadius, maxRadius;
291 template<
typename ParticleArrayT,
typename Po
intIndex>
292 struct SplittableParticleArray
294 using Ptr = SharedPtr<SplittableParticleArray>;
295 using ConstPtr = SharedPtr<const SplittableParticleArray>;
298 using PosType =
typename ParticleArray::PosType;
301 SplittableParticleArray(
const ParticleArrayT& particles)
302 : mIndexMap(), mParticleArray(&particles), mSize(particles.
size())
307 SplittableParticleArray(
const ParticleArrayT& particles,
double minR,
double maxR)
308 : mIndexMap(), mParticleArray(&particles), mSize(particles.
size())
310 mMinRadius = ScalarType(minR);
311 mMaxRadius = ScalarType(maxR);
314 const ParticleArrayT& particleArray()
const {
return *mParticleArray; }
316 size_t size()
const {
return mSize; }
318 void getPos(
size_t n, PosType& xyz)
const
319 {
return mParticleArray->getPos(getGlobalIndex(n), xyz); }
320 void getRadius(
size_t n, ScalarType& radius)
const
321 {
return mParticleArray->getRadius(getGlobalIndex(n), radius); }
323 ScalarType minRadius()
const {
return mMinRadius; }
324 ScalarType maxRadius()
const {
return mMaxRadius; }
326 size_t getGlobalIndex(
size_t n)
const {
return mIndexMap ? size_t(mIndexMap[n]) : n; }
330 Ptr
split(ScalarType maxRadiusLimit) {
332 if (mMaxRadius < maxRadiusLimit)
return Ptr();
334 std::unique_ptr<bool[]>
mask{
new bool[mSize]};
337 MaskParticles(*
this,
mask, maxRadiusLimit));
339 Ptr output(
new SplittableParticleArray(*
this,
mask));
340 if (output->size() == 0)
return Ptr();
343 for (
size_t n = 0,
N = mSize; n <
N; ++
n) {
344 newSize += size_t(!
mask[n]);
347 std::unique_ptr<PointIndex[]> newIndexMap{
new PointIndex[newSize]};
349 setIndexMap(newIndexMap,
mask,
false);
352 mIndexMap.swap(newIndexMap);
361 SplittableParticleArray(
const SplittableParticleArray&);
362 SplittableParticleArray&
operator=(
const SplittableParticleArray&);
365 SplittableParticleArray(
const SplittableParticleArray& other,
366 const std::unique_ptr<
bool[]>&
mask)
367 : mIndexMap(), mParticleArray(&other.particleArray()), mSize(0)
369 for (
size_t n = 0, N = other.size(); n <
N; ++
n) {
370 mSize += size_t(
mask[n]);
374 mIndexMap.reset(
new PointIndex[mSize]);
375 other.setIndexMap(mIndexMap,
mask,
true);
381 struct MaskParticles {
382 MaskParticles(
const SplittableParticleArray& particles,
383 const std::unique_ptr<
bool[]>&
mask, ScalarType radius)
384 : particleArray(&particles)
386 , radiusLimit(radius)
390 void operator()(
const tbb::blocked_range<size_t>& range)
const {
391 const ScalarType maxRadius = radiusLimit;
393 for (
size_t n = range.begin(), N = range.end(); n !=
N; ++
n) {
394 particleArray->getRadius(n, radius);
395 particleMask[
n] = !(radius < maxRadius);
399 SplittableParticleArray
const *
const particleArray;
400 bool *
const particleMask;
401 ScalarType
const radiusLimit;
404 inline void updateExtremas() {
405 ComputeExtremas<SplittableParticleArray> op(*
this);
406 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, mSize), op);
407 mMinRadius = op.minRadius;
408 mMaxRadius = op.maxRadius;
411 void setIndexMap(std::unique_ptr<PointIndex[]>& newIndexMap,
412 const std::unique_ptr<
bool[]>&
mask,
bool maskValue)
const
414 if (mIndexMap.get() !=
nullptr) {
416 for (
size_t idx = 0, n = 0, N = mSize; n <
N; ++
n) {
417 if (
mask[n] == maskValue) newIndexMap[idx++] = indices[
n];
420 for (
size_t idx = 0, n = 0, N = mSize; n <
N; ++
n) {
421 if (
mask[n] == maskValue) {
422 newIndexMap[idx++] =
PointIndex(static_cast<typename PointIndex::IntType>(n));
431 std::unique_ptr<PointIndex[]> mIndexMap;
432 ParticleArrayT
const *
const mParticleArray;
434 ScalarType mMinRadius, mMaxRadius;
438 template<
typename ParticleArrayType,
typename Po
intIndexLeafNodeType>
439 struct RemapIndices {
441 RemapIndices(
const ParticleArrayType& particles, std::vector<PointIndexLeafNodeType*>& nodes)
442 : mParticles(&particles)
443 , mNodes(nodes.empty() ? nullptr : &nodes.front())
447 void operator()(
const tbb::blocked_range<size_t>& range)
const
450 for (
size_t n = range.begin(), N = range.end(); n !=
N; ++
n) {
452 PointIndexLeafNodeType& node = *mNodes[
n];
453 const size_t numIndices = node.indices().size();
455 if (numIndices > 0) {
456 PointIndexType*
begin = &node.indices().front();
457 const PointIndexType*
end = begin + numIndices;
459 while (begin < end) {
460 *begin = PointIndexType(static_cast<typename PointIndexType::IntType>(
461 mParticles->getGlobalIndex(*begin)));
468 ParticleArrayType
const *
const mParticles;
469 PointIndexLeafNodeType *
const *
const mNodes;
473 template<
typename ParticleArrayType,
typename IndexT>
474 struct RadialRangeFilter
476 using PosType =
typename ParticleArrayType::PosType;
479 using Range = std::pair<const IndexT*, const IndexT*>;
480 using RangeDeque = std::deque<Range>;
481 using IndexDeque = std::deque<IndexT>;
483 RadialRangeFilter(RangeDeque& ranges, IndexDeque& indices,
const PosType& xyz,
484 ScalarType radius,
const ParticleArrayType& particles,
bool hasUniformRadius =
false)
489 , mParticles(&particles)
490 , mHasUniformRadius(hasUniformRadius)
492 if (mHasUniformRadius) {
493 ScalarType uniformRadius;
494 mParticles->getRadius(0, uniformRadius);
495 mRadius = mRadius + uniformRadius;
500 template <
typename LeafNodeType>
501 void filterLeafNode(
const LeafNodeType& leaf)
503 const size_t numIndices = leaf.indices().size();
504 if (numIndices > 0) {
505 const IndexT* begin = &leaf.indices().front();
506 filterVoxel(leaf.origin(),
begin, begin + numIndices);
510 void filterVoxel(
const Coord&,
const IndexT* begin,
const IndexT*
end)
514 if (mHasUniformRadius) {
516 const ScalarType searchRadiusSqr = mRadius;
518 while (begin < end) {
519 mParticles->getPos(
size_t(*begin), pos);
520 const ScalarType distSqr = (mCenter - pos).lengthSqr();
521 if (distSqr < searchRadiusSqr) {
522 mIndices.push_back(*begin);
527 while (begin < end) {
528 const size_t idx = size_t(*begin);
529 mParticles->getPos(idx, pos);
532 mParticles->getRadius(idx, radius);
534 ScalarType searchRadiusSqr = mRadius + radius;
535 searchRadiusSqr *= searchRadiusSqr;
537 const ScalarType distSqr = (mCenter - pos).lengthSqr();
539 if (distSqr < searchRadiusSqr) {
540 mIndices.push_back(*begin);
549 RadialRangeFilter(
const RadialRangeFilter&);
550 RadialRangeFilter&
operator=(
const RadialRangeFilter&);
553 IndexDeque& mIndices;
554 PosType
const mCenter;
556 ParticleArrayType
const *
const mParticles;
557 bool const mHasUniformRadius;
561 template<
typename ParticleArrayType,
typename IndexT>
564 using PosType =
typename ParticleArrayType::PosType;
567 using Range = std::pair<const IndexT*, const IndexT*>;
568 using RangeDeque = std::deque<Range>;
569 using IndexDeque = std::deque<IndexT>;
571 BBoxFilter(RangeDeque& ranges, IndexDeque& indices,
572 const BBoxd& bbox,
const ParticleArrayType& particles,
bool hasUniformRadius =
false)
575 , mBBox(PosType(bbox.
min()), PosType(bbox.
max()))
576 , mCenter(mBBox.getCenter())
577 , mParticles(&particles)
578 , mHasUniformRadius(hasUniformRadius)
579 , mUniformRadiusSqr(ScalarType(0.0))
581 if (mHasUniformRadius) {
582 mParticles->getRadius(0, mUniformRadiusSqr);
583 mUniformRadiusSqr *= mUniformRadiusSqr;
587 template <
typename LeafNodeType>
588 void filterLeafNode(
const LeafNodeType& leaf)
590 const size_t numIndices = leaf.indices().size();
591 if (numIndices > 0) {
592 const IndexT* begin = &leaf.indices().front();
593 filterVoxel(leaf.origin(),
begin, begin + numIndices);
597 void filterVoxel(
const Coord&,
const IndexT* begin,
const IndexT* end)
601 if (mHasUniformRadius) {
602 const ScalarType radiusSqr = mUniformRadiusSqr;
604 while (begin < end) {
606 mParticles->getPos(
size_t(*begin), pos);
607 if (mBBox.isInside(pos)) {
608 mIndices.push_back(*begin++);
612 const ScalarType distSqr = pointToBBoxDistSqr(pos);
613 if (!(distSqr > radiusSqr)) {
614 mIndices.push_back(*begin);
621 while (begin < end) {
623 const size_t idx = size_t(*begin);
624 mParticles->getPos(idx, pos);
625 if (mBBox.isInside(pos)) {
626 mIndices.push_back(*begin++);
631 mParticles->getRadius(idx, radius);
632 const ScalarType distSqr = pointToBBoxDistSqr(pos);
633 if (!(distSqr > (radius * radius))) {
634 mIndices.push_back(*begin);
643 BBoxFilter(
const BBoxFilter&);
644 BBoxFilter&
operator=(
const BBoxFilter&);
646 ScalarType pointToBBoxDistSqr(
const PosType& pos)
const
648 ScalarType distSqr = ScalarType(0.0);
650 for (
int i = 0; i < 3; ++i) {
652 const ScalarType
a = pos[i];
654 ScalarType
b = mBBox.min()[i];
656 ScalarType delta = b -
a;
657 distSqr += delta * delta;
662 ScalarType delta = a -
b;
663 distSqr += delta * delta;
671 IndexDeque& mIndices;
672 math::BBox<PosType>
const mBBox;
673 PosType
const mCenter;
674 ParticleArrayType
const *
const mParticles;
675 bool const mHasUniformRadius;
676 ScalarType mUniformRadiusSqr;
687 template<
typename Po
intIndexGr
idType>
688 template<
typename ParticleArrayType>
691 const ParticleArrayType& particles,
double minVoxelSize,
size_t maxLevels)
693 using SplittableParticleArray =
694 typename particle_atlas_internal::SplittableParticleArray<ParticleArrayType, IndexType>;
695 using SplittableParticleArrayPtr =
typename SplittableParticleArray::Ptr;
696 using ScalarType =
typename ParticleArrayType::ScalarType;
700 particle_atlas_internal::ComputeExtremas<ParticleArrayType> extremas(particles);
701 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, particles.size()), extremas);
702 const double firstMin = extremas.minRadius;
703 const double firstMax = extremas.maxRadius;
704 const double firstVoxelSize =
std::max(minVoxelSize, firstMin);
706 if (!(firstMax < (firstVoxelSize *
double(2.0))) && maxLevels > 1) {
708 std::vector<SplittableParticleArrayPtr>
levels;
709 levels.push_back(SplittableParticleArrayPtr(
710 new SplittableParticleArray(particles, firstMin, firstMax)));
712 std::vector<double> voxelSizeArray;
713 voxelSizeArray.push_back(firstVoxelSize);
715 for (
size_t n = 0; n < maxLevels; ++
n) {
717 const double maxParticleRadius = double(levels.back()->maxRadius());
718 const double particleRadiusLimit = voxelSizeArray.back() * double(2.0);
719 if (maxParticleRadius < particleRadiusLimit)
break;
721 SplittableParticleArrayPtr newLevel =
722 levels.back()->split(ScalarType(particleRadiusLimit));
723 if (!newLevel)
break;
725 levels.push_back(newLevel);
726 voxelSizeArray.push_back(
double(newLevel->minRadius()));
729 size_t numPoints = 0;
731 using PointIndexTreeType =
typename PointIndexGridType::TreeType;
732 using PointIndexLeafNodeType =
typename PointIndexTreeType::LeafNodeType;
734 std::vector<PointIndexLeafNodeType*> nodes;
736 for (
size_t n = 0, N = levels.size(); n <
N; ++
n) {
738 const SplittableParticleArray& particleArray = *levels[
n];
740 numPoints += particleArray.size();
742 mMinRadiusArray.push_back(
double(particleArray.minRadius()));
743 mMaxRadiusArray.push_back(
double(particleArray.maxRadius()));
746 createPointIndexGrid<PointIndexGridType>(particleArray, voxelSizeArray[
n]);
749 grid->tree().getNodes(nodes);
752 particle_atlas_internal::RemapIndices<SplittableParticleArray,
753 PointIndexLeafNodeType>(particleArray, nodes));
755 mIndexGridArray.push_back(grid);
759 mMinRadiusArray.push_back(firstMin);
760 mMaxRadiusArray.push_back(firstMax);
761 mIndexGridArray.push_back(
762 createPointIndexGrid<PointIndexGridType>(particles, firstVoxelSize));
767 template<
typename Po
intIndexGr
idType>
768 template<
typename ParticleArrayType>
771 const ParticleArrayType& particles,
double minVoxelSize,
size_t maxLevels)
774 ret->construct(particles, minVoxelSize, maxLevels);
783 template<
typename Po
intIndexGr
idType>
790 , mIter(mRangeList.begin())
793 , mAccessorListSize(atlas.
levels())
795 if (mAccessorListSize > 0) {
796 mAccessorList.reset(
new ConstAccessorPtr[mAccessorListSize]);
797 for (
size_t n = 0, N = mAccessorListSize; n <
N; ++
n) {
798 mAccessorList[
n].reset(
new ConstAccessor(atlas.
pointIndexGrid(n).tree()));
804 template<
typename Po
intIndexGr
idType>
808 mIter = mRangeList.begin();
809 if (!mRangeList.empty()) {
810 mRange = mRangeList.front();
811 }
else if (mIndexArray) {
812 mRange.first = mIndexArray.get();
813 mRange.second = mRange.first + mIndexArraySize;
815 mRange.first =
static_cast<IndexType*
>(
nullptr);
816 mRange.second =
static_cast<IndexType*
>(
nullptr);
821 template<
typename Po
intIndexGr
idType>
826 if (mRange.first >= mRange.second && mIter != mRangeList.end()) {
828 if (mIter != mRangeList.end()) {
830 }
else if (mIndexArray) {
831 mRange.first = mIndexArray.get();
832 mRange.second = mRange.first + mIndexArraySize;
838 template<
typename Po
intIndexGr
idType>
842 if (!this->
test())
return false;
848 template<
typename Po
intIndexGr
idType>
853 typename RangeDeque::const_iterator it =
854 mRangeList.begin(), end = mRangeList.end();
856 for ( ; it !=
end; ++it) {
857 count += it->second - it->first;
860 return count + mIndexArraySize;
864 template<
typename Po
intIndexGr
idType>
868 mRange.first =
static_cast<IndexType*
>(
nullptr);
869 mRange.second =
static_cast<IndexType*
>(
nullptr);
871 mIter = mRangeList.end();
877 template<
typename Po
intIndexGr
idType>
881 using TreeT =
typename PointIndexGridType::TreeType;
882 using LeafNodeType =
typename TreeType::LeafNodeType;
886 if (mAccessorListSize > 0) {
887 const size_t levelIdx =
std::min(mAccessorListSize - 1, level);
889 const TreeT& tree = mAtlas->pointIndexGrid(levelIdx).tree();
891 std::vector<const LeafNodeType*> nodes;
892 tree.getNodes(nodes);
894 for (
size_t n = 0, N = nodes.size(); n <
N; ++
n) {
896 const LeafNodeType& node = *nodes[
n];
897 const size_t numIndices = node.indices().size();
899 if (numIndices > 0) {
900 const IndexType* begin = &node.indices().front();
901 mRangeList.push_back(Range(begin, (begin + numIndices)));
910 template<
typename Po
intIndexGr
idType>
911 template<
typename ParticleArrayType>
914 const Vec3d&
center,
double radius,
const ParticleArrayType& particles)
916 using PosType =
typename ParticleArrayType::PosType;
917 using ScalarType =
typename ParticleArrayType::ScalarType;
923 std::deque<IndexType> filteredIndices;
924 std::vector<CoordBBox> searchRegions;
926 const double iRadius = radius * double(1.0 /
std::sqrt(3.0));
928 const Vec3d ibMin(center[0] - iRadius, center[1] - iRadius, center[2] - iRadius);
929 const Vec3d ibMax(center[0] + iRadius, center[1] + iRadius, center[2] + iRadius);
931 const Vec3d bMin(center[0] - radius, center[1] - radius, center[2] - radius);
932 const Vec3d bMax(center[0] + radius, center[1] + radius, center[2] + radius);
934 const PosType pos = PosType(center);
935 const ScalarType
dist = ScalarType(radius);
937 for (
size_t n = 0, N = mAccessorListSize; n <
N; ++
n) {
939 const double maxRadius = mAtlas->maxRadius(n);
942 const openvdb::math::Transform& xform = mAtlas->pointIndexGrid(n).transform();
947 xform.worldToIndexCellCentered(ibMin),
948 xform.worldToIndexCellCentered(ibMax));
950 inscribedRegion.expand(-1);
953 point_index_grid_internal::pointIndexSearch(mRangeList, acc, inscribedRegion);
955 searchRegions.clear();
958 xform.worldToIndexCellCentered(bMin - maxRadius),
959 xform.worldToIndexCellCentered(bMax + maxRadius));
961 inscribedRegion.expand(1);
962 point_index_grid_internal::constructExclusiveRegions(
963 searchRegions, region, inscribedRegion);
965 using FilterType = particle_atlas_internal::RadialRangeFilter<ParticleArrayType, IndexType>;
966 FilterType filter(mRangeList, filteredIndices, pos, dist, particles, uniformRadius);
968 for (
size_t i = 0, I = searchRegions.size(); i < I; ++i) {
969 point_index_grid_internal::filteredPointIndexSearch(filter, acc, searchRegions[i]);
973 point_index_grid_internal::dequeToArray(filteredIndices, mIndexArray, mIndexArraySize);
979 template<
typename Po
intIndexGr
idType>
980 template<
typename ParticleArrayType>
983 const BBoxd& bbox,
const ParticleArrayType& particles)
987 std::deque<IndexType> filteredIndices;
988 std::vector<CoordBBox> searchRegions;
990 for (
size_t n = 0, N = mAccessorListSize; n <
N; ++
n) {
992 const double maxRadius = mAtlas->maxRadius(n);
994 const openvdb::math::Transform& xform = mAtlas->pointIndexGrid(n).transform();
999 xform.worldToIndexCellCentered(bbox.
min()),
1000 xform.worldToIndexCellCentered(bbox.
max()));
1002 inscribedRegion.expand(-1);
1005 point_index_grid_internal::pointIndexSearch(mRangeList, acc, inscribedRegion);
1007 searchRegions.clear();
1010 xform.worldToIndexCellCentered(bbox.
min() -
maxRadius),
1011 xform.worldToIndexCellCentered(bbox.
max() +
maxRadius));
1013 inscribedRegion.expand(1);
1014 point_index_grid_internal::constructExclusiveRegions(
1015 searchRegions, region, inscribedRegion);
1017 using FilterType = particle_atlas_internal::BBoxFilter<ParticleArrayType, IndexType>;
1018 FilterType filter(mRangeList, filteredIndices, bbox, particles, uniformRadius);
1020 for (
size_t i = 0, I = searchRegions.size(); i < I; ++i) {
1021 point_index_grid_internal::filteredPointIndexSearch(filter, acc, searchRegions[i]);
1025 point_index_grid_internal::dequeToArray(filteredIndices, mIndexArray, mIndexArraySize);
1035 #endif // OPENVDB_TOOLS_PARTICLE_ATLAS_HAS_BEEN_INCLUDED
void parallel_for(int64_t start, int64_t end, std::function< void(int64_t index)> &&task, parallel_options opt=parallel_options(0, Split_Y, 1))
GA_API const UT_StringHolder dist
cvex test(vector P=0;int unbound=3;export float s=0;export vector Cf=0;)
GLsizei GLenum const void * indices
Provides accelerated range and nearest-neighbor searches for particles that are partitioned using the...
std::unique_ptr< ConstAccessor > ConstAccessorPtr
size_t size() const
Return the number of point indices in the iterator range.
vfloat4 sqrt(const vfloat4 &a)
GLboolean GLboolean GLboolean GLboolean a
#define OPENVDB_USE_VERSION_NAMESPACE
SharedPtr< ParticleAtlas > Ptr
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
The Value Accessor Implementation and API methods. The majoirty of the API matches the API of a compa...
Selectively extract and filter point data using a custom filter operator.
PointIndexGridType & pointIndexGrid(size_t n)
Returns the PointIndexGrid that represents the given level n.
void updateFromLevel(size_t level)
Clear the iterator and update it with all particles that reside at the given resolution level...
std::shared_ptr< T > SharedPtr
SYS_FORCE_INLINE const_iterator end() const
bool operator==(const BaseDimensions< T > &a, const BaseDimensions< Y > &b)
double minRadius(size_t n) const
Returns minimum particle radius for level n.
void operator++()
Advance iterator to next item.
SharedPtr< const ParticleAtlas > ConstPtr
bool isApproxEqual(const Type &a, const Type &b, const Type &tolerance)
Return true if a is equal to b to within the given tolerance.
const Vec3T & min() const
Return a const reference to the minimum point of this bounding box.
const IndexType & operator*() const
Return a const reference to the item to which this iterator is pointing.
Iterator(const ParticleAtlas &atlas)
Construct an iterator from the given atlas.
size_t levels() const
Returns the number of resolution levels.
const PointIndexGridType & pointIndexGrid(size_t n) const
Returns the PointIndexGrid that represents the given level n.
void construct(const ParticleArrayType &particles, double minVoxelSize, size_t maxLevels=50)
Partitions particle indices.
static Ptr create(const ParticleArrayType &particles, double minVoxelSize, size_t maxLevels=50)
Create a new ParticleAtlas from the given particles.
auto get(const UT_ARTIterator< T > &it) -> decltype(it.key())
typename PointIndexGridType::TreeType TreeType
bool empty() const
true if the container size is 0, false otherwise.
size_t levels() const
Returns the total number of resolution levels.
Partition particles and performs range and nearest-neighbor searches.
GLboolean GLboolean GLboolean b
const Vec3T & max() const
Return a const reference to the maximum point of this bounding box.
bool next()
Advance iterator to next item.
void worldSpaceSearchAndUpdate(const Vec3d ¢er, double radius, const ParticleArrayType &particles)
Clear the iterator and update it with the result of the given world-space radial query.
Space-partitioning acceleration structure for points. Partitions the points into voxels to accelerate...
LeafData & operator=(const LeafData &)=delete
void reset()
Reset the iterator to point to the first item.
math::BBox< Vec3d > BBoxd
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
GA_API const UT_StringHolder N
bool test() const
Return true if this iterator is not yet exhausted.
typename PointIndexGridType::ValueType IndexType
double maxRadius(size_t n) const
Returns maximum particle radius for level n.
void OIIO_UTIL_API split(string_view str, std::vector< string_view > &result, string_view sep=string_view(), int maxsplit=-1)
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
bool operator!=(const Iterator &p) const
bool operator==(const Iterator &p) const
Return true if both iterators point to the same element.
void increment()
Advance iterator to next item.
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
typename PointIndexGridType::Ptr PointIndexGridPtr
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.