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;
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);
224 if (!useIndexSpace) {
225 deformer.apply(positionWS, iter);
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(
255 LeafIndex(static_cast<LeafIndex>(idx)), targetOffset, *iter));
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 template <
typename TreeT>
289 using LeafT =
typename TreeT::LeafNodeType;
296 const Index attributeIndex,
299 : mOffsetMap(offsetMap)
300 , mSourceLeafManager(sourceLeafManager)
301 , mAttributeIndex(attributeIndex)
302 , mMoveLeafMap(moveLeafMap)
303 , mMoveLeafIndices(moveLeafIndices) { }
312 , mSortedIndices(sortedIndices)
313 , mMoveIndices(moveIndices)
314 , mOffsets(offsets) { }
316 operator bool()
const {
return bool(mIt); }
321 mEndIndex = endIndex;
333 if (i < mSortedIndices.size()) {
334 return std::get<0>(this->leafIndexTriple(i));
342 return std::get<2>(*mIt);
354 if (mIndex >= mEndIndex || mIndex >= mSortedIndices.size()) {
358 mIt = &this->leafIndexTriple(mIndex);
365 return mMoveIndices[mSortedIndices[i]];
381 if (moveIndices.empty())
return;
382 const IndexArray& sortedIndices = mMoveLeafIndices[idx];
390 auto& targetArray = leaf.attributeArray(mAttributeIndex);
391 targetArray.loadData();
392 targetArray.expand();
396 CopyIterator copyIterator(leaf, sortedIndices, moveIndices, offsets);
401 Index startIndex = 0;
403 for (
size_t i = 1; i <= sortedIndices.size(); i++) {
411 if (newSourceLeafIndex > sourceLeafIndex) {
412 copyIterator.
reset(startIndex, endIndex);
414 const LeafT& sourceLeaf = mSourceLeafManager.leaf(sourceLeafIndex);
415 const auto& sourceArray = sourceLeaf.constAttributeArray(mAttributeIndex);
416 sourceArray.loadData();
418 targetArray.copyValuesUnsafe(sourceArray, copyIterator);
420 sourceLeafIndex = newSourceLeafIndex;
421 startIndex = endIndex;
429 const Index mAttributeIndex;
435 template <
typename TreeT>
438 using LeafT =
typename TreeT::LeafNodeType;
446 const Index attributeIndex,
448 : mOffsetMap(offsetMap)
449 , mSourceIndices(sourceIndices)
450 , mSourceLeafManager(sourceLeafManager)
451 , mAttributeIndex(attributeIndex)
452 , mMoveLeafMap(moveLeafMap) { }
461 , mOffsets(offsets) { }
463 operator bool()
const {
return mIndex < static_cast<int>(mIndices.size()); }
469 return mIndices[mIndex].second;
487 if (moveIndices.empty())
return;
495 assert(idx < mSourceIndices.size());
496 const Index sourceLeafOffset(mSourceIndices[idx]);
497 LeafT& sourceLeaf = mSourceLeafManager.leaf(sourceLeafOffset);
498 const auto& sourceArray = sourceLeaf.constAttributeArray(mAttributeIndex);
499 sourceArray.loadData();
503 auto& targetArray = leaf.attributeArray(mAttributeIndex);
504 targetArray.loadData();
505 targetArray.expand();
510 targetArray.copyValuesUnsafe(sourceArray, copyIterator);
517 const Index mAttributeIndex;
528 template <
typename Po
intDataGr
idT,
typename DeformerT,
typename FilterT>
537 using PointDataTreeT =
typename PointDataGridT::TreeType;
538 using LeafT =
typename PointDataTreeT::LeafNodeType;
541 using namespace point_move_internal;
544 assert(!objectNotInUse);
545 (
void)objectNotInUse;
547 PointDataTreeT& tree = points.tree();
551 auto iter = tree.cbeginLeaf();
557 auto newPoints = point_mask_internal::convertPointsToScalar<PointDataGridT>(
559 auto& newTree = newPoints->tree();
563 LeafManagerT sourceLeafManager(tree);
564 LeafManagerT targetLeafManager(newTree);
567 const auto& existingAttributeSet = points.tree().cbeginLeaf()->attributeSet();
580 auto sourceRange = sourceLeafManager.leafRange();
581 for (
auto leaf = sourceRange.begin(); leaf; ++leaf) {
582 sourceLeafMap.insert({leaf->origin(),
LeafIndex(static_cast<LeafIndex>(leaf.pos()))});
584 auto targetRange = targetLeafManager.leafRange();
585 for (
auto leaf = targetRange.begin(); leaf; ++leaf) {
586 targetLeafMap.insert({leaf->origin(),
LeafIndex(static_cast<LeafIndex>(leaf.pos()))});
594 targetLeafManager.foreach(
595 [&](LeafT& leaf,
size_t idx) {
598 for (
Index i = 1; i < leaf.buffer().size(); i++) {
602 leaf.replaceAttributeSet(
603 new AttributeSet(existingAttributeSet, leaf.getLastValue(), &lock),
606 const auto it = sourceLeafMap.find(leaf.origin());
607 if (it != sourceLeafMap.end()) {
608 sourceIndices[idx] = it->second;
625 BuildMoveMapsOp<DeformerT, PointDataTreeT, NullFilter> op(deformer,
626 globalMoveLeafMap, localMoveLeafMap, targetLeafMap,
627 transform, points.transform(), nullFilter);
628 sourceLeafManager.foreach(op, threaded);
630 BuildMoveMapsOp<DeformerT, PointDataTreeT, FilterT> op(deformer,
631 globalMoveLeafMap, localMoveLeafMap, targetLeafMap,
632 transform, points.transform(),
filter);
633 sourceLeafManager.foreach(op, threaded);
642 targetLeafManager.foreach(
643 [&](LeafT& ,
size_t idx) {
645 if (moveIndices.empty())
return;
647 IndexArray& sortedIndices = globalMoveLeafIndices[idx];
648 sortedIndices.resize(moveIndices.size());
653 const Index& indexI0(std::get<0>(moveIndices[i]));
654 const Index& indexJ0(std::get<0>(moveIndices[j]));
655 if (indexI0 < indexJ0)
return true;
656 if (indexI0 > indexJ0)
return false;
657 return std::get<2>(moveIndices[i]) < std::get<2>(moveIndices[j]);
663 for (
const auto& it : existingAttributeSet.descriptor().map()) {
665 const Index attributeIndex =
static_cast<Index>(it.second);
668 targetLeafManager.foreach(
669 [&offsetMap](
const LeafT& ,
size_t idx) {
676 GlobalMovePointsOp<PointDataTreeT> globalMoveOp(offsetMap,
677 sourceLeafManager, attributeIndex, globalMoveLeafMap, globalMoveLeafIndices);
678 targetLeafManager.foreach(globalMoveOp, threaded);
682 LocalMovePointsOp<PointDataTreeT> localMoveOp(offsetMap,
683 sourceIndices, sourceLeafManager, attributeIndex, localMoveLeafMap);
684 targetLeafManager.foreach(localMoveOp, threaded);
687 points.setTree(newPoints->treePtr());
691 template <
typename Po
intDataGr
idT,
typename DeformerT,
typename FilterT>
698 movePoints(points, points.transform(), deformer,
filter, objectNotInUse, threaded);
705 template <
typename T>
710 template <
typename T>
711 template <
typename Po
intDataGr
idT,
typename DeformerT,
typename FilterT>
715 using TreeT =
typename PointDataGridT::TreeType;
716 using LeafT =
typename TreeT::LeafNodeType;
718 LeafManagerT leafManager(grid.tree());
721 auto& leafs = mCache.leafs;
722 leafs.resize(leafManager.leafCount());
724 const auto& transform = grid.transform();
728 auto cachePositionsOp = [&](
const LeafT& leaf,
size_t idx) {
730 const Index64 totalPointCount = leaf.pointCount();
731 if (totalPointCount == 0)
return;
735 DeformerT newDeformer(deformer);
737 newDeformer.reset(leaf, idx);
741 auto& cache = leafs[idx];
746 const bool useVector = filter.state() ==
index::ALL &&
747 (leaf.isDense() || (leaf.onPointCount() == leaf.pointCount()));
749 cache.vecData.resize(totalPointCount);
752 for (
auto iter = leaf.beginIndexOn(filter); iter; iter++) {
756 Vec3d position = handle->get(*iter) + iter.getCoord().asVec3d();
762 newDeformer.apply(position, iter);
767 newDeformer.apply(position, iter);
773 cache.vecData[*iter] =
static_cast<Vec3T>(position);
776 cache.mapData.insert({*iter,
static_cast<Vec3T>(position)});
782 if (!cache.mapData.empty()) {
783 cache.totalSize =
static_cast<Index>(totalPointCount);
787 leafManager.foreach(cachePositionsOp, threaded);
791 template <
typename T>
792 template <
typename LeafT>
795 if (idx >= mCache.leafs.size()) {
796 if (mCache.leafs.empty()) {
797 throw IndexError(
"No leafs in cache, perhaps CachedDeformer has not been evaluated?");
799 throw IndexError(
"Leaf index is out-of-range of cache leafs.");
802 auto& cache = mCache.leafs[idx];
803 if (!cache.mapData.empty()) {
804 mLeafMap = &cache.mapData;
808 mLeafVec = &cache.vecData;
814 template <
typename T>
815 template <
typename IndexIterT>
821 auto it = mLeafMap->find(*iter);
822 if (it == mLeafMap->end())
return;
828 if (mLeafVec->empty())
return;
829 assert(*iter < mLeafVec->
size());
839 #endif // OPENVDB_POINTS_POINT_MOVE_HAS_BEEN_INCLUDED
Index targetIndex() const
std::vector< AttributeArray * > AttributeArrays
LocalMovePointsOp(LeafOffsetArray &offsetMap, const LeafIndexArray &sourceIndices, LeafManagerT &sourceLeafManager, const Index attributeIndex, const LocalPointIndexMap &moveLeafMap)
void movePoints(PointDataGridT &points, DeformerT &deformer, const FilterT &filter=NullFilter(), future::Advect *objectNotInUse=nullptr, bool threaded=true)
Move points in a PointDataGrid using a custom deformer.
typename tree::LeafManager< TreeT > LeafManagerT
std::vector< IndexPairArray > LocalPointIndexMap
GLuint GLsizei const GLuint const GLintptr * offsets
std::vector< LeafT * > LeafArrayT
#define OPENVDB_USE_VERSION_NAMESPACE
Index sourceIndex() const
GlobalMovePointsOp(LeafOffsetArray &offsetMap, LeafManagerT &sourceLeafManager, const Index attributeIndex, const GlobalPointIndexMap &moveLeafMap, const GlobalPointIndexIndices &moveLeafIndices)
A no-op filter that can be used when iterating over all indices.
void operator()(LeafT &leaf, size_t idx) const
std::vector< LeafIndexArray > LeafOffsetArray
std::tuple< LeafIndex, Index, Index > IndexTriple
static Ptr create(AttributeArray &array, const bool expand=true)
GLuint GLenum GLenum transform
std::vector< IndexPair > IndexPairArray
std::vector< Index > IndexArray
void operator()(LeafT &leaf, size_t idx) const
Index targetIndex() const
std::vector< LeafT * > LeafArrayT
tbb::concurrent_vector< IndexTriple > IndexTripleArray
Index indexOffsetFromVoxel(const Index voxelOffset, const LeafT &leaf, IndexArray &offsets)
CopyIterator & operator++()
CopyIterator & operator++()
CopyIterator(const LeafT &leaf, const IndexPairArray &indices, IndexArray &offsets)
GLsizei GLenum const void * indices
void operator()(LeafT &leaf, size_t idx) const
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
typename TreeT::LeafNodeType LeafT
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
std::pair< Index, Index > IndexPair
std::unordered_map< Coord, LeafIndex > LeafMap
vfloat4 round(const vfloat4 &a)
void reset(Index startIndex, Index endIndex)
std::vector< IndexTripleArray > GlobalPointIndexMap
buffer(size_t sz) FMT_NOEXCEPT
BuildMoveMapsOp(const DeformerT &deformer, GlobalPointIndexMap &globalMoveLeafMap, LocalPointIndexMap &localMoveLeafMap, const LeafMap &targetLeafMap, const math::Transform &targetTransform, const math::Transform &sourceTransform, const FilterT &filter)
typename TreeT::LeafNodeType LeafT
typename tree::LeafManager< TreeT > LeafManagerT
GLuint GLdouble GLdouble GLint GLint const GLdouble * points
static Ptr create(const AttributeArray &array, const bool collapseOnDestruction=true)
std::vector< AttributeArray * > AttributeArrays
Methods for extracting masks from VDB Point grids.
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
Ordered collection of uniquely-named attribute arrays.
typename TreeT::LeafNodeType LeafT
Index leafIndex(Index i) const
CopyIterator(const LeafT &leaf, const IndexArray &sortedIndices, const IndexTripleArray &moveIndices, IndexArray &offsets)
std::vector< LeafT * > LeafArrayT
Index sourceIndex() const
std::vector< IndexArray > GlobalPointIndexIndices
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
void sort(I begin, I end, const Pred &pred)
typename tree::LeafManager< TreeT > LeafManagerT
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
std::vector< LeafIndex > LeafIndexArray
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.