32 #ifndef OPENVDB_POINTS_POINT_MOVE_HAS_BEEN_INCLUDED
33 #define OPENVDB_POINTS_POINT_MOVE_HAS_BEEN_INCLUDED
40 #include <tbb/concurrent_vector.h>
47 #include <unordered_map>
59 namespace future {
struct Advect { }; }
68 template <
typename Po
intDataGr
idT,
typename DeformerT,
typename FilterT = NullFilter>
73 bool threaded =
true);
83 template <
typename Po
intDataGr
idT,
typename DeformerT,
typename FilterT = NullFilter>
89 bool threaded =
true);
104 using LeafMapT = std::unordered_map<LeafIndex, Vec3T>;
134 template <
typename Po
intDataGr
idT,
typename DeformerT,
typename FilterT>
135 void evaluate(PointDataGridT& grid, DeformerT& deformer,
const FilterT& filter,
136 bool threaded =
true);
140 template <
typename LeafT>
141 void reset(
const LeafT& leaf,
size_t idx);
144 template <
typename IndexIterT>
145 void apply(
Vec3d& position,
const IndexIterT& iter)
const;
148 friend class ::TestPointMove;
159 namespace point_move_internal {
174 using LeafMap = std::unordered_map<Coord, LeafIndex>;
177 template <
typename DeformerT,
typename TreeT,
typename FilterT>
180 using LeafT =
typename TreeT::LeafNodeType;
190 const FilterT& filter)
191 : mDeformer(deformer)
192 , mGlobalMoveLeafMap(globalMoveLeafMap)
193 , mLocalMoveLeafMap(localMoveLeafMap)
194 , mTargetLeafMap(targetLeafMap)
195 , mTargetTransform(targetTransform)
196 , mSourceTransform(sourceTransform)
197 , mFilter(filter) { }
201 DeformerT deformer(mDeformer);
202 deformer.reset(leaf, idx);
206 Coord sourceLeafOrigin = leaf.origin();
210 for (
auto iter = leaf.beginIndexOn(mFilter); iter; iter++) {
216 Vec3d positionIS = sourceHandle->get(*iter) + iter.getCoord().asVec3d();
218 deformer.apply(positionIS, iter);
223 Vec3d positionWS = mSourceTransform.indexToWorld(positionIS);
224 if (!useIndexSpace) {
225 deformer.apply(positionWS, iter);
230 positionIS = mTargetTransform.worldToIndex(positionWS);
234 Coord targetVoxel = Coord::round(positionIS);
235 Index targetOffset = LeafT::coordToOffset(targetVoxel);
239 Vec3d voxelPosition(positionIS - targetVoxel.
asVec3d());
240 sourceHandle->set(*iter, voxelPosition);
244 Coord targetLeafOrigin = targetVoxel & ~(LeafT::DIM - 1);
245 assert(mTargetLeafMap.find(targetLeafOrigin) != mTargetLeafMap.end());
246 const LeafIndex targetLeafOffset(mTargetLeafMap.at(targetLeafOrigin));
250 if (targetLeafOrigin == sourceLeafOrigin) {
251 mLocalMoveLeafMap[targetLeafOffset].emplace_back(targetOffset, *iter);
254 mGlobalMoveLeafMap[targetLeafOffset].push_back(
IndexTriple(
261 const DeformerT& mDeformer;
267 const FilterT& mFilter;
270 template <
typename LeafT>
278 Index targetOffset = offsets[voxelOffset]++;
279 if (voxelOffset > 0) {
280 targetOffset +=
static_cast<Index>(leaf.getValue(voxelOffset - 1));
286 #if OPENVDB_ABI_VERSION_NUMBER >= 6
289 template <
typename TreeT>
292 using LeafT =
typename TreeT::LeafNodeType;
299 const Index attributeIndex,
302 : mOffsetMap(offsetMap)
303 , mSourceLeafManager(sourceLeafManager)
304 , mAttributeIndex(attributeIndex)
305 , mMoveLeafMap(moveLeafMap)
306 , mMoveLeafIndices(moveLeafIndices) { }
315 , mSortedIndices(sortedIndices)
316 , mMoveIndices(moveIndices)
317 , mOffsets(offsets) { }
319 operator bool()
const {
return bool(mIt); }
324 mEndIndex = endIndex;
336 if (i < mSortedIndices.size()) {
337 return std::get<0>(this->leafIndexTriple(i));
345 return std::get<2>(*mIt);
357 if (mIndex >= mEndIndex || mIndex >= mSortedIndices.size()) {
361 mIt = &this->leafIndexTriple(mIndex);
368 return mMoveIndices[mSortedIndices[i]];
384 if (moveIndices.empty())
return;
385 const IndexArray& sortedIndices = mMoveLeafIndices[idx];
393 auto& targetArray = leaf.attributeArray(mAttributeIndex);
394 targetArray.loadData();
395 targetArray.expand();
399 CopyIterator copyIterator(leaf, sortedIndices, moveIndices, offsets);
404 Index startIndex = 0;
406 for (
size_t i = 1; i <= sortedIndices.size(); i++) {
414 if (newSourceLeafIndex > sourceLeafIndex) {
415 copyIterator.
reset(startIndex, endIndex);
417 const LeafT& sourceLeaf = mSourceLeafManager.leaf(sourceLeafIndex);
418 const auto& sourceArray = sourceLeaf.constAttributeArray(mAttributeIndex);
419 sourceArray.loadData();
421 targetArray.copyValuesUnsafe(sourceArray, copyIterator);
423 sourceLeafIndex = newSourceLeafIndex;
424 startIndex = endIndex;
431 LeafManagerT& mSourceLeafManager;
432 const Index mAttributeIndex;
438 template <
typename TreeT>
441 using LeafT =
typename TreeT::LeafNodeType;
449 const Index attributeIndex,
451 : mOffsetMap(offsetMap)
452 , mSourceIndices(sourceIndices)
453 , mSourceLeafManager(sourceLeafManager)
454 , mAttributeIndex(attributeIndex)
455 , mMoveLeafMap(moveLeafMap) { }
464 , mOffsets(offsets) { }
466 operator bool()
const {
return mIndex < static_cast<int>(mIndices.size()); }
472 return mIndices[mIndex].second;
490 if (moveIndices.empty())
return;
498 assert(idx < mSourceIndices.size());
499 const Index sourceLeafOffset(mSourceIndices[idx]);
500 LeafT& sourceLeaf = mSourceLeafManager.leaf(sourceLeafOffset);
501 const auto& sourceArray = sourceLeaf.constAttributeArray(mAttributeIndex);
502 sourceArray.loadData();
506 auto& targetArray = leaf.attributeArray(mAttributeIndex);
507 targetArray.loadData();
508 targetArray.expand();
513 targetArray.copyValuesUnsafe(sourceArray, copyIterator);
519 LeafManagerT& mSourceLeafManager;
520 const Index mAttributeIndex;
536 template<
typename ValueType,
typename OpType>
537 struct ArrayProcessor {
538 static inline void call(OpType& op,
const AttributeArray& array) {
540 op.operator()<ValueType>(array);
542 op.template operator()<ValueType>(array);
550 template<
typename ArrayType,
typename OpType>
552 processTypedArray(
const ArrayType& array, OpType& op)
555 using namespace openvdb::math;
556 if (array.template hasValueType<bool>()) ArrayProcessor<bool, OpType>::call(op, array);
557 else if (array.template hasValueType<int16_t>()) ArrayProcessor<int16_t, OpType>::call(op, array);
558 else if (array.template hasValueType<int32_t>()) ArrayProcessor<int32_t, OpType>::call(op, array);
559 else if (array.template hasValueType<int64_t>()) ArrayProcessor<int64_t, OpType>::call(op, array);
560 else if (array.template hasValueType<float>()) ArrayProcessor<float, OpType>::call(op, array);
561 else if (array.template hasValueType<double>()) ArrayProcessor<double, OpType>::call(op, array);
562 else if (array.template hasValueType<Vec3<int32_t>>()) ArrayProcessor<Vec3<int32_t>, OpType>::call(op, array);
563 else if (array.template hasValueType<Vec3<float>>()) ArrayProcessor<Vec3<float>, OpType>::call(op, array);
564 else if (array.template hasValueType<Vec3<double>>()) ArrayProcessor<Vec3<double>, OpType>::call(op, array);
565 else if (array.template hasValueType<GroupType>()) ArrayProcessor<GroupType, OpType>::call(op, array);
566 else if (array.template hasValueType<StringIndexType>()) ArrayProcessor<StringIndexType, OpType>::call(op, array);
567 else if (array.template hasValueType<Mat3<float>>()) ArrayProcessor<Mat3<float>, OpType>::call(op, array);
568 else if (array.template hasValueType<Mat3<double>>()) ArrayProcessor<Mat3<double>, OpType>::call(op, array);
569 else if (array.template hasValueType<Mat4<float>>()) ArrayProcessor<Mat4<float>, OpType>::call(op, array);
570 else if (array.template hasValueType<Mat4<double>>()) ArrayProcessor<Mat4<double>, OpType>::call(op, array);
571 else if (array.template hasValueType<Quat<float>>()) ArrayProcessor<Quat<float>, OpType>::call(op, array);
572 else if (array.template hasValueType<Quat<double>>()) ArrayProcessor<Quat<double>, OpType>::call(op, array);
579 struct AttributeHandles
581 using HandleArray = std::vector<AttributeHandle<int>::Ptr>;
583 AttributeHandles(
const size_t size)
584 : mHandles() { mHandles.reserve(size); }
586 AttributeArray& getArray(
const Index leafOffset)
588 auto* handle =
reinterpret_cast<AttributeWriteHandle<int>*
>(mHandles[leafOffset].get());
590 return handle->array();
593 const AttributeArray& getConstArray(
const Index leafOffset)
const
595 const auto* handle = mHandles[leafOffset].get();
597 return handle->array();
600 template <
typename ValueT>
601 AttributeHandle<ValueT>& getHandle(
const Index leafOffset)
603 auto* handle =
reinterpret_cast<AttributeHandle<ValueT>*
>(mHandles[leafOffset].get());
608 template <
typename ValueT>
609 AttributeWriteHandle<ValueT>& getWriteHandle(
const Index leafOffset)
611 auto* handle =
reinterpret_cast<AttributeWriteHandle<ValueT>*
>(mHandles[leafOffset].get());
619 CacheHandleOp(HandleArray& handles)
620 : mHandles(handles) { }
622 template<
typename ValueT>
623 void operator()(
const AttributeArray& array)
const
625 auto* handleAsInt =
reinterpret_cast<AttributeHandle<int>*
>(
626 new AttributeHandle<ValueT>(array));
627 mHandles.emplace_back(handleAsInt);
631 HandleArray& mHandles;
634 template <
typename LeafRangeT>
635 void cache(
const LeafRangeT& range,
const Index attributeIndex)
637 using namespace openvdb::math;
640 CacheHandleOp op(mHandles);
642 for (
auto leaf = range.begin(); leaf; ++leaf) {
643 const auto& array = leaf->constAttributeArray(attributeIndex);
644 processTypedArray(array, op);
649 HandleArray mHandles;
653 template <
typename TreeT>
654 struct GlobalMovePointsOp
656 using LeafT =
typename TreeT::LeafNodeType;
657 using LeafArrayT = std::vector<LeafT*>;
658 using LeafManagerT =
typename tree::LeafManager<TreeT>;
661 AttributeHandles& targetHandles,
662 AttributeHandles& sourceHandles,
663 const Index attributeIndex,
666 : mOffsetMap(offsetMap)
667 , mTargetHandles(targetHandles)
668 , mSourceHandles(sourceHandles)
669 , mAttributeIndex(attributeIndex)
670 , mMoveLeafMap(moveLeafMap)
671 , mMoveLeafIndices(moveLeafIndices) { }
673 struct PerformTypedMoveOp
675 PerformTypedMoveOp(AttributeHandles& targetHandles, AttributeHandles& sourceHandles,
676 Index targetOffset,
const LeafT& targetLeaf,
679 : mTargetHandles(targetHandles)
680 , mSourceHandles(sourceHandles)
681 , mTargetOffset(targetOffset)
682 , mTargetLeaf(targetLeaf)
685 , mSortedIndices(sortedIndices) { }
687 template<
typename ValueT>
688 void operator()(
const AttributeArray&)
const
690 auto& targetHandle = mTargetHandles.getWriteHandle<ValueT>(mTargetOffset);
691 targetHandle.expand();
693 for (
const auto& index : mSortedIndices) {
694 const auto& it = mIndices[index];
695 const auto& sourceHandle = mSourceHandles.getHandle<ValueT>(std::get<0>(it));
697 for (
Index i = 0; i < sourceHandle.stride(); i++) {
698 ValueT sourceValue = sourceHandle.get(std::get<2>(it), i);
699 targetHandle.set(targetIndex, i, sourceValue);
705 AttributeHandles& mTargetHandles;
706 AttributeHandles& mSourceHandles;
708 const LeafT& mTargetLeaf;
714 void performMove(
Index targetOffset,
const LeafT& targetLeaf,
718 auto& targetArray = mTargetHandles.getArray(targetOffset);
719 targetArray.loadData();
720 targetArray.expand();
722 for (
const auto& index : sortedIndices) {
723 const auto& it = indices[index];
725 const auto& sourceArray = mSourceHandles.getConstArray(std::get<0>(it));
727 const Index sourceOffset = std::get<2>(it);
730 targetArray.set(targetOffset, sourceArray, sourceOffset);
734 void operator()(LeafT& leaf,
size_t aIdx)
const
737 const auto& moveIndices = mMoveLeafMap[aIdx];
738 if (moveIndices.empty())
return;
739 const auto& sortedIndices = mMoveLeafIndices[aIdx];
743 auto& offsets = mOffsetMap[aIdx];
745 const auto& array = leaf.constAttributeArray(mAttributeIndex);
747 PerformTypedMoveOp op(mTargetHandles, mSourceHandles, idx, leaf, offsets,
748 moveIndices, sortedIndices);
749 if (!processTypedArray(array, op)) {
750 this->performMove(idx, leaf, offsets, moveIndices, sortedIndices);
756 AttributeHandles& mTargetHandles;
757 AttributeHandles& mSourceHandles;
758 const Index mAttributeIndex;
764 template <
typename TreeT>
765 struct LocalMovePointsOp
767 using LeafT =
typename TreeT::LeafNodeType;
768 using LeafArrayT = std::vector<LeafT*>;
769 using LeafManagerT =
typename tree::LeafManager<TreeT>;
772 AttributeHandles& targetHandles,
774 AttributeHandles& sourceHandles,
775 const Index attributeIndex,
777 : mOffsetMap(offsetMap)
778 , mTargetHandles(targetHandles)
779 , mSourceIndices(sourceIndices)
780 , mSourceHandles(sourceHandles)
781 , mAttributeIndex(attributeIndex)
782 , mMoveLeafMap(moveLeafMap) { }
784 struct PerformTypedMoveOp
786 PerformTypedMoveOp(AttributeHandles& targetHandles, AttributeHandles& sourceHandles,
787 Index targetOffset,
Index sourceOffset,
const LeafT& targetLeaf,
789 : mTargetHandles(targetHandles)
790 , mSourceHandles(sourceHandles)
791 , mTargetOffset(targetOffset)
792 , mSourceOffset(sourceOffset)
793 , mTargetLeaf(targetLeaf)
795 , mIndices(indices) { }
797 template<
typename ValueT>
798 void operator()(
const AttributeArray&)
const
800 auto& targetHandle = mTargetHandles.getWriteHandle<ValueT>(mTargetOffset);
801 const auto& sourceHandle = mSourceHandles.getHandle<ValueT>(mSourceOffset);
803 targetHandle.expand();
805 for (
const auto& it : mIndices) {
807 for (
Index i = 0; i < sourceHandle.stride(); i++) {
808 ValueT sourceValue = sourceHandle.get(it.second, i);
809 targetHandle.set(targetIndex, i, sourceValue);
815 AttributeHandles& mTargetHandles;
816 AttributeHandles& mSourceHandles;
819 const LeafT& mTargetLeaf;
824 template <
typename ValueT>
825 void performTypedMove(
Index sourceOffset,
Index targetOffset,
const LeafT& targetLeaf,
828 auto& targetHandle = mTargetHandles.getWriteHandle<ValueT>(targetOffset);
829 const auto& sourceHandle = mSourceHandles.getHandle<ValueT>(sourceOffset);
831 targetHandle.expand();
833 for (
const auto& it : indices) {
835 for (
Index i = 0; i < sourceHandle.stride(); i++) {
836 ValueT sourceValue = sourceHandle.get(it.second, i);
837 targetHandle.set(tgtOffset, i, sourceValue);
842 void performMove(
Index targetOffset,
Index sourceOffset,
const LeafT& targetLeaf,
845 auto& targetArray = mTargetHandles.getArray(targetOffset);
846 const auto& sourceArray = mSourceHandles.getConstArray(sourceOffset);
848 for (
const auto& it : indices) {
849 const Index sourceOffset = it.second;
852 targetArray.set(targetOffset, sourceArray, sourceOffset);
856 void operator()(
const LeafT& leaf,
size_t aIdx)
const
859 const auto& moveIndices = mMoveLeafMap.at(aIdx);
860 if (moveIndices.empty())
return;
864 auto& offsets = mOffsetMap[aIdx];
868 assert(aIdx < mSourceIndices.size());
869 const Index sourceOffset(mSourceIndices[aIdx]);
871 const auto& array = leaf.constAttributeArray(mAttributeIndex);
873 PerformTypedMoveOp op(mTargetHandles, mSourceHandles,
874 idx, sourceOffset, leaf, offsets, moveIndices);
875 if (!processTypedArray(array, op)) {
876 this->performMove(idx, sourceOffset, leaf, offsets, moveIndices);
882 AttributeHandles& mTargetHandles;
884 AttributeHandles& mSourceHandles;
885 const Index mAttributeIndex;
890 #endif // OPENVDB_ABI_VERSION_NUMBER >= 6
899 template <
typename Po
intDataGr
idT,
typename DeformerT,
typename FilterT>
903 const FilterT& filter,
908 using PointDataTreeT =
typename PointDataGridT::TreeType;
909 using LeafT =
typename PointDataTreeT::LeafNodeType;
912 using namespace point_move_internal;
915 assert(!objectNotInUse);
916 (void)objectNotInUse;
918 PointDataTreeT& tree = points.tree();
928 auto newPoints = point_mask_internal::convertPointsToScalar<PointDataGrid>(
929 points, transform, filter, deformer, threaded);
930 auto& newTree = newPoints->tree();
934 LeafManagerT sourceLeafManager(tree);
935 LeafManagerT targetLeafManager(newTree);
938 const auto& existingAttributeSet = points.tree().cbeginLeaf()->attributeSet();
951 auto sourceRange = sourceLeafManager.leafRange();
952 for (
auto leaf = sourceRange.begin(); leaf; ++leaf) {
953 sourceLeafMap.insert({leaf->origin(),
LeafIndex(
static_cast<LeafIndex>(leaf.pos()))});
955 auto targetRange = targetLeafManager.leafRange();
956 for (
auto leaf = targetRange.begin(); leaf; ++leaf) {
957 targetLeafMap.insert({leaf->origin(),
LeafIndex(
static_cast<LeafIndex>(leaf.pos()))});
965 targetLeafManager.foreach(
966 [&](LeafT& leaf,
size_t idx) {
968 auto* buffer = leaf.buffer().data();
969 for (
Index i = 1; i < leaf.buffer().size(); i++) {
970 buffer[i] = buffer[i-1] + buffer[i];
973 leaf.replaceAttributeSet(
974 new AttributeSet(existingAttributeSet, leaf.getLastValue(), &lock),
977 const auto it = sourceLeafMap.find(leaf.origin());
978 if (it != sourceLeafMap.end()) {
979 sourceIndices[idx] = it->second;
982 offsetMap[idx].resize(LeafT::SIZE);
996 BuildMoveMapsOp<DeformerT, PointDataTreeT, NullFilter> op(deformer,
997 globalMoveLeafMap, localMoveLeafMap, targetLeafMap,
998 transform, points.transform(), nullFilter);
999 sourceLeafManager.foreach(op, threaded);
1001 BuildMoveMapsOp<DeformerT, PointDataTreeT, FilterT> op(deformer,
1002 globalMoveLeafMap, localMoveLeafMap, targetLeafMap,
1003 transform, points.transform(), filter);
1004 sourceLeafManager.foreach(op, threaded);
1013 targetLeafManager.foreach(
1014 [&](LeafT& ,
size_t idx) {
1016 if (moveIndices.empty())
return;
1018 IndexArray& sortedIndices = globalMoveLeafIndices[idx];
1019 sortedIndices.resize(moveIndices.size());
1020 std::iota(std::begin(sortedIndices), std::end(sortedIndices), 0);
1021 std::sort(std::begin(sortedIndices), std::end(sortedIndices),
1024 const Index& indexI0(std::get<0>(moveIndices[i]));
1025 const Index& indexJ0(std::get<0>(moveIndices[j]));
1026 if (indexI0 < indexJ0) return true;
1027 if (indexI0 > indexJ0) return false;
1028 return std::get<2>(moveIndices[i]) < std::get<2>(moveIndices[j]);
1034 #if OPENVDB_ABI_VERSION_NUMBER < 6
1036 AttributeHandles sourceHandles(sourceLeafManager.leafCount());
1037 AttributeHandles targetHandles(targetLeafManager.leafCount());
1040 for (
const auto& it : existingAttributeSet.descriptor().map()) {
1042 const Index attributeIndex =
static_cast<Index>(it.second);
1045 targetLeafManager.foreach(
1046 [&offsetMap](
const LeafT& ,
size_t idx) {
1047 std::fill(offsetMap[idx].begin(), offsetMap[idx].end(), 0);
1051 #if OPENVDB_ABI_VERSION_NUMBER >= 6
1055 GlobalMovePointsOp<PointDataTreeT> globalMoveOp(offsetMap,
1056 sourceLeafManager, attributeIndex, globalMoveLeafMap, globalMoveLeafIndices);
1057 targetLeafManager.foreach(globalMoveOp, threaded);
1061 LocalMovePointsOp<PointDataTreeT> localMoveOp(offsetMap,
1062 sourceIndices, sourceLeafManager, attributeIndex, localMoveLeafMap);
1063 targetLeafManager.foreach(localMoveOp, threaded);
1067 sourceHandles.cache(sourceLeafManager.leafRange(), attributeIndex);
1068 targetHandles.cache(targetLeafManager.leafRange(), attributeIndex);
1072 GlobalMovePointsOp<PointDataTreeT> globalMoveOp(offsetMap, targetHandles,
1073 sourceHandles, attributeIndex, globalMoveLeafMap, globalMoveLeafIndices);
1074 targetLeafManager.foreach(globalMoveOp, threaded);
1078 LocalMovePointsOp<PointDataTreeT> localMoveOp(offsetMap, targetHandles,
1079 sourceIndices, sourceHandles,
1080 attributeIndex, localMoveLeafMap);
1081 targetLeafManager.foreach(localMoveOp, threaded);
1082 #endif // OPENVDB_ABI_VERSION_NUMBER >= 6
1085 points.setTree(newPoints->treePtr());
1089 template <
typename Po
intDataGr
idT,
typename DeformerT,
typename FilterT>
1091 DeformerT& deformer,
1092 const FilterT& filter,
1096 movePoints(points, points.transform(), deformer, filter, objectNotInUse, threaded);
1103 template <
typename T>
1108 template <
typename T>
1109 template <
typename Po
intDataGr
idT,
typename DeformerT,
typename FilterT>
1113 using TreeT =
typename PointDataGridT::TreeType;
1114 using LeafT =
typename TreeT::LeafNodeType;
1116 LeafManagerT leafManager(grid.tree());
1119 auto& leafs = mCache.leafs;
1120 leafs.resize(leafManager.leafCount());
1122 const auto& transform = grid.transform();
1126 auto cachePositionsOp = [&](
const LeafT& leaf,
size_t idx) {
1128 const Index64 totalPointCount = leaf.pointCount();
1129 if (totalPointCount == 0)
return;
1133 DeformerT newDeformer(deformer);
1135 newDeformer.reset(leaf, idx);
1139 auto& cache = leafs[idx];
1144 const bool useVector = filter.state() ==
index::ALL &&
1145 (leaf.isDense() || (leaf.onPointCount() == leaf.pointCount()));
1147 cache.vecData.resize(totalPointCount);
1150 for (
auto iter = leaf.beginIndexOn(filter); iter; iter++) {
1154 Vec3d position = handle->get(*iter) + iter.getCoord().asVec3d();
1160 newDeformer.apply(position, iter);
1165 newDeformer.apply(position, iter);
1171 cache.vecData[*iter] =
static_cast<Vec3T>(position);
1174 cache.mapData.insert({*iter,
static_cast<Vec3T>(position)});
1180 if (!cache.mapData.empty()) {
1181 cache.totalSize =
static_cast<Index>(totalPointCount);
1185 leafManager.foreach(cachePositionsOp, threaded);
1189 template <
typename T>
1190 template <
typename LeafT>
1193 if (idx >= mCache.leafs.size()) {
1194 if (mCache.leafs.empty()) {
1195 throw IndexError(
"No leafs in cache, perhaps CachedDeformer has not been evaluated?");
1197 throw IndexError(
"Leaf index is out-of-range of cache leafs.");
1200 auto& cache = mCache.leafs[idx];
1201 if (!cache.mapData.empty()) {
1202 mLeafMap = &cache.mapData;
1206 mLeafVec = &cache.vecData;
1212 template <
typename T>
1213 template <
typename IndexIterT>
1219 auto it = mLeafMap->find(*iter);
1220 if (it == mLeafMap->end())
return;
1226 if (mLeafVec->empty())
return;
1227 assert(*iter < mLeafVec->size());
1237 #endif // OPENVDB_POINTS_POINT_MOVE_HAS_BEEN_INCLUDED