59 #ifndef OPENVDB_POINTS_POINT_MOVE_HAS_BEEN_INCLUDED 60 #define OPENVDB_POINTS_POINT_MOVE_HAS_BEEN_INCLUDED 67 #include <tbb/concurrent_vector.h> 74 #include <unordered_map> 86 namespace future {
struct Advect { }; }
95 template <
typename Po
intDataGr
idT,
typename DeformerT,
typename FilterT = NullFilter>
100 bool threaded =
true);
110 template <
typename Po
intDataGr
idT,
typename DeformerT,
typename FilterT = NullFilter>
111 inline void movePoints(PointDataGridT& points,
116 bool threaded =
true);
124 template <
typename T>
131 using LeafMapT = std::unordered_map<LeafIndex, Vec3T>;
161 template <
typename Po
intDataGr
idT,
typename DeformerT,
typename FilterT>
162 void evaluate(PointDataGridT& grid, DeformerT& deformer,
const FilterT& filter,
163 bool threaded =
true);
167 template <
typename LeafT>
168 void reset(
const LeafT& leaf,
size_t idx);
171 template <
typename IndexIterT>
172 void apply(
Vec3d& position,
const IndexIterT& iter)
const;
175 friend class ::TestPointMove;
187 namespace point_move_internal {
212 template<
typename ValueType,
typename OpType>
216 op.operator()<ValueType>(array);
218 op.template operator()<ValueType>(array);
225 template<
typename ArrayType,
typename OpType>
230 using namespace openvdb::math;
259 : mHandles() { mHandles.reserve(size); }
265 return handle->array();
270 const auto* handle = mHandles[leafOffset].get();
272 return handle->array();
275 template <
typename ValueT>
283 template <
typename ValueT>
295 : mHandles(handles) { }
297 template<
typename ValueT>
302 mHandles.emplace_back(handleAsInt);
309 template <
typename LeafRangeT>
310 void cache(
const LeafRangeT& range,
const Index attributeIndex)
312 using namespace openvdb::math;
317 for (
auto leaf = range.begin(); leaf; ++leaf) {
318 auto& array = leaf->attributeArray(attributeIndex);
324 HandleArray mHandles;
328 template <
typename DeformerT,
typename TreeT,
typename FilterT>
331 using LeafT =
typename TreeT::LeafNodeType;
341 const FilterT& filter)
342 : mDeformer(deformer)
343 , mGlobalMoveLeafMap(globalMoveLeafMap)
344 , mLocalMoveLeafMap(localMoveLeafMap)
345 , mTargetLeafMap(targetLeafMap)
346 , mTargetTransform(targetTransform)
347 , mSourceTransform(sourceTransform)
348 , mFilter(filter) { }
352 DeformerT deformer(mDeformer);
353 deformer.reset(leaf, idx);
357 Coord sourceLeafOrigin = leaf.origin();
361 for (
auto iter = leaf.beginIndexOn(mFilter); iter; iter++) {
367 Vec3d positionIS = sourceHandle->get(*iter) + iter.getCoord().asVec3d();
369 deformer.apply(positionIS, iter);
374 Vec3d positionWS = mSourceTransform.indexToWorld(positionIS);
375 if (!useIndexSpace) {
376 deformer.apply(positionWS, iter);
381 positionIS = mTargetTransform.worldToIndex(positionWS);
386 Index targetOffset = LeafT::coordToOffset(targetVoxel);
390 Vec3d voxelPosition(positionIS - targetVoxel.
asVec3d());
391 sourceHandle->set(*iter, voxelPosition);
395 Coord targetLeafOrigin = targetVoxel & ~(LeafT::DIM - 1);
396 assert(mTargetLeafMap.find(targetLeafOrigin) != mTargetLeafMap.end());
397 const LeafIndex targetLeafOffset(mTargetLeafMap.at(targetLeafOrigin));
401 if (targetLeafOrigin == sourceLeafOrigin) {
402 mLocalMoveLeafMap[targetLeafOffset].emplace_back(targetOffset, *iter);
405 mGlobalMoveLeafMap[targetLeafOffset].push_back(
IndexTriple(
406 LeafIndex(static_cast<LeafIndex>(idx)), targetOffset, *iter));
412 const DeformerT& mDeformer;
418 const FilterT& mFilter;
421 template <
typename LeafT>
429 Index targetOffset = offsets[voxelOffset]++;
430 if (voxelOffset > 0) {
431 targetOffset += static_cast<Index>(leaf.getValue(voxelOffset - 1));
436 template <
typename TreeT>
439 using LeafT =
typename TreeT::LeafNodeType;
446 const Index attributeIndex,
448 : mOffsetMap(offsetMap)
449 , mTargetHandles(targetHandles)
450 , mSourceHandles(sourceHandles)
451 , mAttributeIndex(attributeIndex)
452 , mMoveLeafMap(moveLeafMap) { }
459 : mTargetHandles(targetHandles)
460 , mSourceHandles(sourceHandles)
461 , mTargetOffset(targetOffset)
462 , mTargetLeaf(targetLeaf)
464 , mIndices(indices) { }
466 template<
typename ValueT>
469 auto& targetHandle = mTargetHandles.getWriteHandle<ValueT>(mTargetOffset);
470 targetHandle.expand();
475 std::vector<int> sortedIndices(mIndices.size());
476 std::iota(std::begin(sortedIndices), std::end(sortedIndices), 0);
477 std::sort(std::begin(sortedIndices), std::end(sortedIndices),
480 const Index& indexI0(std::get<0>(mIndices[i]));
481 const Index& indexJ0(std::get<0>(mIndices[j]));
482 if (indexI0 < indexJ0)
return true;
483 if (indexI0 > indexJ0)
return false;
484 return std::get<2>(mIndices[i]) < std::get<2>(mIndices[j]);
488 for (
const auto& index : sortedIndices) {
489 const auto& it = mIndices[index];
490 const auto& sourceHandle = mSourceHandles.getHandle<ValueT>(std::get<0>(it));
492 for (
Index i = 0; i < sourceHandle.stride(); i++) {
493 ValueT sourceValue = sourceHandle.get(std::get<2>(it), i);
494 targetHandle.set(targetIndex, i, sourceValue);
503 const LeafT& mTargetLeaf;
511 auto& targetArray = mTargetHandles.getArray(targetOffset);
513 for (
const auto& it : indices) {
514 const auto& sourceArray = mSourceHandles.getConstArray(std::get<0>(it));
516 targetArray.set(tgtOffset, sourceArray, std::get<2>(it));
522 const Index idx(static_cast<Index>(aIdx));
523 const auto& moveIndices = mMoveLeafMap.at(aIdx);
524 if (moveIndices.empty())
return;
528 auto& offsets = mOffsetMap[aIdx];
530 const auto& array = leaf.constAttributeArray(mAttributeIndex);
532 PerformTypedMoveOp op(mTargetHandles, mSourceHandles, idx, leaf, offsets, moveIndices);
534 this->performMove(idx, leaf, offsets, moveIndices);
542 const Index mAttributeIndex;
546 template <
typename TreeT>
549 using LeafT =
typename TreeT::LeafNodeType;
557 const Index attributeIndex,
559 : mOffsetMap(offsetMap)
560 , mTargetHandles(targetHandles)
561 , mSourceIndices(sourceIndices)
562 , mSourceHandles(sourceHandles)
563 , mAttributeIndex(attributeIndex)
564 , mMoveLeafMap(moveLeafMap) { }
571 : mTargetHandles(targetHandles)
572 , mSourceHandles(sourceHandles)
573 , mTargetOffset(targetOffset)
574 , mSourceOffset(sourceOffset)
575 , mTargetLeaf(targetLeaf)
577 , mIndices(indices) { }
579 template<
typename ValueT>
582 auto& targetHandle = mTargetHandles.getWriteHandle<ValueT>(mTargetOffset);
583 const auto& sourceHandle = mSourceHandles.getHandle<ValueT>(mSourceOffset);
585 targetHandle.expand();
587 for (
const auto& it : mIndices) {
589 for (
Index i = 0; i < sourceHandle.stride(); i++) {
590 ValueT sourceValue = sourceHandle.get(it.second, i);
591 targetHandle.set(targetIndex, i, sourceValue);
601 const LeafT& mTargetLeaf;
606 template <
typename ValueT>
610 auto& targetHandle = mTargetHandles.getWriteHandle<ValueT>(targetOffset);
611 const auto& sourceHandle = mSourceHandles.getHandle<ValueT>(sourceOffset);
613 targetHandle.expand();
615 for (
const auto& it : indices) {
617 for (
Index i = 0; i < sourceHandle.stride(); i++) {
618 ValueT sourceValue = sourceHandle.get(it.second, i);
619 targetHandle.set(tgtOffset, i, sourceValue);
627 auto& targetArray = mTargetHandles.getArray(targetOffset);
628 const auto& sourceArray = mSourceHandles.getConstArray(sourceOffset);
630 for (
const auto& it : indices) {
632 targetArray.set(tgtOffset, sourceArray, it.second);
638 const Index idx(static_cast<Index>(aIdx));
639 const auto& moveIndices = mMoveLeafMap.at(aIdx);
640 if (moveIndices.empty())
return;
644 auto& offsets = mOffsetMap[aIdx];
648 assert(aIdx < mSourceIndices.size());
649 const Index sourceOffset(mSourceIndices[aIdx]);
651 const auto& array = leaf.constAttributeArray(mAttributeIndex);
654 idx, sourceOffset, leaf, offsets, moveIndices);
656 this->performMove(idx, sourceOffset, leaf, offsets, moveIndices);
665 const Index mAttributeIndex;
675 template <
typename Po
intDataGr
idT,
typename DeformerT,
typename FilterT>
679 const FilterT& filter,
684 using PointDataTreeT =
typename PointDataGridT::TreeType;
685 using LeafT =
typename PointDataTreeT::LeafNodeType;
688 using namespace point_move_internal;
691 assert(!objectNotInUse);
692 (void)objectNotInUse;
694 PointDataTreeT& tree = points.tree();
704 auto newPoints = point_mask_internal::convertPointsToScalar<PointDataGrid>(
705 points, transform, filter, deformer, threaded);
706 auto& newTree = newPoints->tree();
710 LeafManagerT sourceLeafManager(tree);
711 LeafManagerT targetLeafManager(newTree);
714 AttributeHandles sourceHandles(sourceLeafManager.leafCount());
715 AttributeHandles targetHandles(targetLeafManager.leafCount());
718 const auto& existingAttributeSet = points.tree().cbeginLeaf()->attributeSet();
731 auto sourceRange = sourceLeafManager.leafRange();
732 for (
auto leaf = sourceRange.begin(); leaf; ++leaf) {
733 sourceLeafMap.insert({leaf->origin(),
LeafIndex(static_cast<LeafIndex>(leaf.pos()))});
735 auto targetRange = targetLeafManager.leafRange();
736 for (
auto leaf = targetRange.begin(); leaf; ++leaf) {
737 targetLeafMap.insert({leaf->origin(),
LeafIndex(static_cast<LeafIndex>(leaf.pos()))});
741 targetLeafManager.foreach(
742 [&](LeafT& leaf,
size_t idx) {
744 auto* buffer = leaf.buffer().data();
745 for (
Index i = 1; i < leaf.buffer().size(); i++) {
746 buffer[i] = buffer[i-1] + buffer[i];
749 leaf.replaceAttributeSet(
new AttributeSet(existingAttributeSet, leaf.getLastValue()),
752 const auto it = sourceLeafMap.find(leaf.origin());
753 if (it != sourceLeafMap.end()) {
754 sourceIndices[idx] = it->second;
757 offsetMap[idx].resize(LeafT::SIZE);
771 BuildMoveMapsOp<DeformerT, PointDataTreeT, NullFilter> op(deformer,
772 globalMoveLeafMap, localMoveLeafMap, targetLeafMap,
773 transform, points.transform(), nullFilter);
774 sourceLeafManager.foreach(op, threaded);
776 BuildMoveMapsOp<DeformerT, PointDataTreeT, FilterT> op(deformer,
777 globalMoveLeafMap, localMoveLeafMap, targetLeafMap,
778 transform, points.transform(), filter);
779 sourceLeafManager.foreach(op, threaded);
782 for (
const auto& it : existingAttributeSet.descriptor().map()) {
784 const Index attributeIndex = static_cast<Index>(it.second);
787 targetLeafManager.foreach(
788 [&offsetMap](
const LeafT& ,
size_t idx) {
789 std::fill(offsetMap[idx].begin(), offsetMap[idx].end(), 0);
795 sourceHandles.cache(sourceLeafManager.leafRange(), attributeIndex);
796 targetHandles.cache(targetLeafManager.leafRange(), attributeIndex);
800 GlobalMovePointsOp<PointDataTreeT> globalMoveOp(offsetMap, targetHandles,
801 sourceHandles, attributeIndex, globalMoveLeafMap);
802 targetLeafManager.foreach(globalMoveOp, threaded);
806 LocalMovePointsOp<PointDataTreeT> localMoveOp(offsetMap, targetHandles,
807 sourceIndices, sourceHandles,
808 attributeIndex, localMoveLeafMap);
809 targetLeafManager.foreach(localMoveOp, threaded);
812 points.setTree(newPoints->treePtr());
816 template <
typename Po
intDataGr
idT,
typename DeformerT,
typename FilterT>
819 const FilterT& filter,
823 movePoints(points, points.transform(), deformer, filter, objectNotInUse, threaded);
830 template <
typename T>
835 template <
typename T>
836 template <
typename Po
intDataGr
idT,
typename DeformerT,
typename FilterT>
840 using TreeT =
typename PointDataGridT::TreeType;
841 using LeafT =
typename TreeT::LeafNodeType;
843 LeafManagerT leafManager(grid.tree());
846 auto& leafs = mCache.leafs;
847 leafs.resize(leafManager.leafCount());
849 const auto& transform = grid.transform();
853 auto cachePositionsOp = [&](
const LeafT& leaf,
size_t idx) {
855 const Index64 totalPointCount = leaf.pointCount();
856 if (totalPointCount == 0)
return;
860 DeformerT newDeformer(deformer);
864 const Index64 vectorThreshold = totalPointCount / 2;
866 newDeformer.reset(leaf, idx);
870 auto& cache = leafs[idx];
875 const bool useVector = filter.state() ==
index::ALL &&
876 (leaf.isDense() || (leaf.onPointCount() > vectorThreshold));
878 cache.vecData.resize(totalPointCount);
881 for (
auto iter = leaf.beginIndexOn(filter); iter; iter++) {
885 Vec3d position = handle->get(*iter) + iter.getCoord().asVec3d();
891 newDeformer.apply(position, iter);
896 newDeformer.apply(position, iter);
902 cache.vecData[*iter] = static_cast<Vec3T>(position);
905 cache.mapData.insert({*iter, static_cast<Vec3T>(position)});
911 if (!useVector && cache.mapData.
size() > vectorThreshold) {
912 cache.vecData.resize(totalPointCount);
913 for (
const auto& it : cache.mapData) {
914 cache.vecData[it.first] = it.second;
916 cache.mapData.clear();
921 if (!cache.mapData.empty()) {
922 cache.totalSize = static_cast<Index>(totalPointCount);
926 leafManager.foreach(cachePositionsOp, threaded);
930 template <
typename T>
931 template <
typename LeafT>
934 if (idx >= mCache.leafs.size()) {
935 if (mCache.leafs.empty()) {
936 throw IndexError(
"No leafs in cache, perhaps CachedDeformer has not been evaluated?");
938 throw IndexError(
"Leaf index is out-of-range of cache leafs.");
941 auto& cache = mCache.leafs[idx];
942 if (!cache.mapData.empty()) {
946 if (cache.mapData.size() > 16 &&
947 cache.totalSize < (cache.mapData.size() * 256)) {
948 if (cache.totalSize < cache.mapData.size()) {
949 throw ValueError(
"Cache total size is not valid.");
951 mLocalLeafVec.resize(cache.totalSize);
952 for (
const auto& it : cache.mapData) {
953 assert(it.first < cache.totalSize);
954 mLocalLeafVec[it.first] = it.second;
956 mLeafVec = &mLocalLeafVec;
960 mLeafMap = &cache.mapData;
965 mLeafVec = &cache.vecData;
971 template <
typename T>
972 template <
typename IndexIterT>
978 auto it = mLeafMap->find(*iter);
979 if (it == mLeafMap->end())
return;
980 position = static_cast<openvdb::Vec3d>(it->second);
985 if (mLeafVec->empty())
return;
986 assert(*iter < mLeafVec->size());
987 position = static_cast<openvdb::Vec3d>((*mLeafVec)[*iter]);
996 #endif // OPENVDB_POINTS_POINT_MOVE_HAS_BEEN_INCLUDED Index indexOffsetFromVoxel(const Index voxelOffset, const LeafT &leaf, IndexArray &offsets)
Definition: PointMove.h:423
std::vector< LeafIndex > LeafIndexArray
Definition: PointMove.h:200
A no-op filter that can be used when iterating over all indices.
Definition: IndexIterator.h:77
4x4 -matrix class.
Definition: Mat3.h:49
AttributeArray & getArray(const Index leafOffset)
Definition: PointMove.h:261
Index32 Index
Definition: Types.h:61
uint64_t Index64
Definition: Types.h:60
typename tree::LeafManager< TreeT > LeafManagerT
Definition: PointMove.h:441
Base class for tree-traversal iterators over all leaf nodes (but not leaf voxels)
Definition: TreeIterator.h:1235
std::map< Coord, LeafIndex > LeafMap
Definition: PointMove.h:202
Write-able version of AttributeHandle.
Definition: AttributeArray.h:903
void performMove(Index targetOffset, Index sourceOffset, const LeafT &targetLeaf, IndexArray &offsets, const IndexPairArray &indices) const
Definition: PointMove.h:624
void operator()(const LeafT &leaf, size_t aIdx) const
Definition: PointMove.h:636
std::vector< IndexPairArray > LocalPointIndexMap
Definition: PointMove.h:196
Cache read and write attribute handles to amortize construction cost.
Definition: PointMove.h:254
std::vector< LeafT * > LeafArrayT
Definition: PointMove.h:550
Vec3< double > Vec3d
Definition: Vec3.h:679
std::vector< Index > IndexArray
Definition: PointMove.h:198
void performTypedMove(Index sourceOffset, Index targetOffset, const LeafT &targetLeaf, IndexArray &offsets, const IndexPairArray &indices) const
Definition: PointMove.h:607
GlobalMovePointsOp(LeafOffsetArray &offsetMap, AttributeHandles &targetHandles, AttributeHandles &sourceHandles, const Index attributeIndex, const GlobalPointIndexMap &moveLeafMap)
Definition: PointMove.h:443
typename TreeT::LeafNodeType LeafT
Definition: PointMove.h:439
3x3 matrix class.
Definition: Mat3.h:55
std::vector< LeafT * > LeafArrayT
Definition: PointMove.h:332
typename TreeT::LeafNodeType LeafT
Definition: PointMove.h:331
AttributeHandle< ValueT > & getHandle(const Index leafOffset)
Definition: PointMove.h:276
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:51
std::vector< IndexTripleArray > GlobalPointIndexMap
Definition: PointMove.h:192
std::vector< LeafIndexArray > LeafOffsetArray
Definition: PointMove.h:201
void operator()(LeafT &leaf, size_t aIdx) const
Definition: PointMove.h:520
static Ptr create(const AttributeArray &array, const bool collapseOnDestruction=true)
Definition: AttributeArray.h:2095
void cache(const LeafRangeT &range, const Index attributeIndex)
Definition: PointMove.h:310
Create a handle and reinterpret cast as an int handle to store.
Definition: PointMove.h:292
LocalMovePointsOp(LeafOffsetArray &offsetMap, AttributeHandles &targetHandles, const LeafIndexArray &sourceIndices, AttributeHandles &sourceHandles, const Index attributeIndex, const LocalPointIndexMap &moveLeafMap)
Definition: PointMove.h:553
AttributeHandles(const size_t size)
Definition: PointMove.h:258
uint32_t Index32
Definition: Types.h:59
Ordered collection of uniquely-named attribute arrays.
Definition: AttributeSet.h:62
AttributeWriteHandle< ValueT > & getWriteHandle(const Index leafOffset)
Definition: PointMove.h:284
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:136
Vec3d asVec3d() const
Definition: Coord.h:170
Definition: PointMove.h:547
bool processTypedArray(const ArrayType &array, OpType &op)
Utility function that, given a generic attribute array, calls a functor with the fully-resolved value...
Definition: PointMove.h:227
Definition: Exceptions.h:40
typename tree::LeafManager< TreeT > LeafManagerT
Definition: PointMove.h:333
const AttributeArray & getConstArray(const Index leafOffset) const
Definition: PointMove.h:268
Definition: Exceptions.h:84
BuildMoveMapsOp(const DeformerT &deformer, GlobalPointIndexMap &globalMoveLeafMap, LocalPointIndexMap &localMoveLeafMap, const LeafMap &targetLeafMap, const math::Transform &targetTransform, const math::Transform &sourceTransform, const FilterT &filter)
Definition: PointMove.h:335
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:110
void performMove(Index targetOffset, const LeafT &targetLeaf, IndexArray &offsets, const IndexTripleArray &indices) const
Definition: PointMove.h:508
typename TreeT::LeafNodeType LeafT
Definition: PointMove.h:549
void operator()(const AttributeArray &array) const
Definition: PointMove.h:298
Methods for extracting masks from VDB Point grids.
void movePoints(PointDataGridT &points, const math::Transform &transform, DeformerT &deformer, const FilterT &filter=NullFilter(), future::Advect *objectNotInUse=nullptr, bool threaded=true)
Move points in a PointDataGrid using a custom deformer and a new transform.
Definition: PointMove.h:676
CacheHandleOp(HandleArray &handles)
Definition: PointMove.h:294
static Coord round(const Vec3< T > &xyz)
Return xyz rounded to the closest integer coordinates (cell centered conversion).
Definition: Coord.h:77
Base class for storing attribute data.
Definition: AttributeArray.h:118
Definition: PointMove.h:329
Definition: AttributeArray.h:832
Definition: IndexIterator.h:70
void operator()(LeafT &leaf, size_t idx) const
Definition: PointMove.h:350
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
std::tuple< LeafIndex, Index, Index > IndexTriple
Definition: PointMove.h:190
tbb::concurrent_vector< IndexTriple > IndexTripleArray
Definition: PointMove.h:191
std::pair< Index, Index > IndexPair
Definition: PointMove.h:194
Index32 LeafIndex
Definition: PointMove.h:120
Definition: PointMove.h:437
Definition: Exceptions.h:92
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:188
Helper class used internally by processTypedArray()
Definition: PointMove.h:213
static void call(OpType &op, const AttributeArray &array)
Definition: PointMove.h:214
typename tree::LeafManager< TreeT > LeafManagerT
Definition: PointMove.h:551
Definition: PointMove.h:86
Index size() const
Definition: AttributeArray.h:855
std::vector< AttributeHandle< int >::Ptr > HandleArray
Definition: PointMove.h:256
std::vector< IndexPair > IndexPairArray
Definition: PointMove.h:195
std::vector< LeafT * > LeafArrayT
Definition: PointMove.h:440