OpenVDB 12.0.0
 
Loading...
Searching...
No Matches
PointMoveImpl.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3
4/// @author Dan Bailey
5///
6/// @file PointMoveImpl.h
7///
8
9#ifndef OPENVDB_POINTS_POINT_MOVE_IMPL_HAS_BEEN_INCLUDED
10#define OPENVDB_POINTS_POINT_MOVE_IMPL_HAS_BEEN_INCLUDED
11
12class TestPointMove;
13
14namespace openvdb {
16namespace OPENVDB_VERSION_NAME {
17namespace points {
18
19// define leaf index in use as 32-bit
21
22
23/// @brief A Deformer that caches the resulting positions from evaluating another Deformer
24template <typename T>
26{
27public:
29 using Vec3T = typename math::Vec3<T>;
30 using LeafVecT = std::vector<Vec3T>;
31 using LeafMapT = std::unordered_map<LeafIndex, Vec3T>;
32
33 // Internal data cache to allow the deformer to offer light-weight copying
34 struct Cache
35 {
36 struct Leaf
37 {
38 /// @brief clear data buffers and reset counter
39 void clear() {
40 vecData.clear();
41 mapData.clear();
42 totalSize = 0;
43 }
44
48 }; // struct Leaf
49
50 std::vector<Leaf> leafs;
51 }; // struct Cache
52
53 /// Cache is expected to be persistent for the lifetime of the CachedDeformer
54 explicit CachedDeformer(Cache& cache);
55
56 /// Caches the result of evaluating the supplied point grid using the deformer and filter
57 /// @param grid the points to be moved
58 /// @param deformer the deformer to apply to the points
59 /// @param filter the point filter to use when evaluating the points
60 /// @param threaded enable or disable threading (threading is enabled by default)
61 template <typename PointDataGridT, typename DeformerT, typename FilterT>
62 void evaluate(PointDataGridT& grid, DeformerT& deformer, const FilterT& filter,
63 bool threaded = true);
64
65 /// Stores pointers to the vector or map and optionally expands the map into a vector
66 /// @throw IndexError if idx is out-of-range of the leafs in the cache
67 template <typename LeafT>
68 void reset(const LeafT& leaf, size_t idx);
69
70 /// Retrieve the new position from the cache
71 template <typename IndexIterT>
72 void apply(Vec3d& position, const IndexIterT& iter) const;
73
74private:
75 friend class ::TestPointMove;
76
77 Cache& mCache;
78 const LeafVecT* mLeafVec = nullptr;
79 const LeafMapT* mLeafMap = nullptr;
80}; // class CachedDeformer
81
82
83////////////////////////////////////////
84
85
86namespace point_move_internal {
87
88using IndexArray = std::vector<Index>;
89
90using IndexTriple = std::tuple<LeafIndex, Index, Index>;
91using IndexTripleArray = tbb::concurrent_vector<IndexTriple>;
92using GlobalPointIndexMap = std::vector<IndexTripleArray>;
93using GlobalPointIndexIndices = std::vector<IndexArray>;
94
95using IndexPair = std::pair<Index, Index>;
96using IndexPairArray = std::vector<IndexPair>;
97using LocalPointIndexMap = std::vector<IndexPairArray>;
98
99using LeafIndexArray = std::vector<LeafIndex>;
100using LeafOffsetArray = std::vector<LeafIndexArray>;
101using LeafMap = std::unordered_map<Coord, LeafIndex>;
102
103
104template <typename DeformerT, typename TreeT, typename FilterT>
106{
107 using LeafT = typename TreeT::LeafNodeType;
108 using LeafArrayT = std::vector<LeafT*>;
110
111 BuildMoveMapsOp(const DeformerT& deformer,
112 GlobalPointIndexMap& globalMoveLeafMap,
113 LocalPointIndexMap& localMoveLeafMap,
114 const LeafMap& targetLeafMap,
115 const math::Transform& targetTransform,
116 const math::Transform& sourceTransform,
117 const FilterT& filter)
118 : mDeformer(deformer)
119 , mGlobalMoveLeafMap(globalMoveLeafMap)
120 , mLocalMoveLeafMap(localMoveLeafMap)
121 , mTargetLeafMap(targetLeafMap)
122 , mTargetTransform(targetTransform)
123 , mSourceTransform(sourceTransform)
124 , mFilter(filter) { }
125
126 void operator()(LeafT& leaf, size_t idx) const
127 {
128 DeformerT deformer(mDeformer);
129 deformer.reset(leaf, idx);
130
131 // determine source leaf node origin and offset in the source leaf vector
132
133 Coord sourceLeafOrigin = leaf.origin();
134
135 auto sourceHandle = AttributeWriteHandle<Vec3f>::create(leaf.attributeArray("P"));
136
137 for (auto iter = leaf.beginIndexOn(mFilter); iter; iter++) {
138
139 const bool useIndexSpace = DeformerTraits<DeformerT>::IndexSpace;
140
141 // extract index-space position and apply index-space deformation (if applicable)
142
143 Vec3d positionIS = sourceHandle->get(*iter) + iter.getCoord().asVec3d();
144 if (useIndexSpace) {
145 deformer.apply(positionIS, iter);
146 }
147
148 // transform to world-space position and apply world-space deformation (if applicable)
149
150 Vec3d positionWS = mSourceTransform.indexToWorld(positionIS);
151 if (!useIndexSpace) {
152 deformer.apply(positionWS, iter);
153 }
154
155 // transform to index-space position of target grid
156
157 positionIS = mTargetTransform.worldToIndex(positionWS);
158
159 // determine target voxel and offset
160
161 Coord targetVoxel = Coord::round(positionIS);
162 Index targetOffset = LeafT::coordToOffset(targetVoxel);
163
164 // set new local position in source transform space (if point has been deformed)
165
166 Vec3d voxelPosition(positionIS - targetVoxel.asVec3d());
167 sourceHandle->set(*iter, voxelPosition);
168
169 // determine target leaf node origin and offset in the target leaf vector
170
171 Coord targetLeafOrigin = targetVoxel & ~(LeafT::DIM - 1);
172 OPENVDB_ASSERT(mTargetLeafMap.find(targetLeafOrigin) != mTargetLeafMap.end());
173 const LeafIndex targetLeafOffset(mTargetLeafMap.at(targetLeafOrigin));
174
175 // insert into move map based on whether point ends up in a new leaf node or not
176
177 if (targetLeafOrigin == sourceLeafOrigin) {
178 mLocalMoveLeafMap[targetLeafOffset].emplace_back(targetOffset, *iter);
179 }
180 else {
181 mGlobalMoveLeafMap[targetLeafOffset].push_back(IndexTriple(
182 LeafIndex(static_cast<LeafIndex>(idx)), targetOffset, *iter));
183 }
184 }
185 }
186
187private:
188 const DeformerT& mDeformer;
189 GlobalPointIndexMap& mGlobalMoveLeafMap;
190 LocalPointIndexMap& mLocalMoveLeafMap;
191 const LeafMap& mTargetLeafMap;
192 const math::Transform& mTargetTransform;
193 const math::Transform& mSourceTransform;
194 const FilterT& mFilter;
195}; // struct BuildMoveMapsOp
196
197template <typename LeafT>
198inline Index
199indexOffsetFromVoxel(const Index voxelOffset, const LeafT& leaf, IndexArray& offsets)
200{
201 // compute the target point index by summing the point index of the previous
202 // voxel with the current number of points added to this voxel, tracked by the
203 // offsets array
204
205 Index targetOffset = offsets[voxelOffset]++;
206 if (voxelOffset > 0) {
207 targetOffset += static_cast<Index>(leaf.getValue(voxelOffset - 1));
208 }
209 return targetOffset;
210}
211
212
213template <typename TreeT>
215{
216 using LeafT = typename TreeT::LeafNodeType;
217 using LeafArrayT = std::vector<LeafT*>;
219 using AttributeArrays = std::vector<AttributeArray*>;
220
222 LeafManagerT& sourceLeafManager,
223 const Index attributeIndex,
224 const GlobalPointIndexMap& moveLeafMap,
225 const GlobalPointIndexIndices& moveLeafIndices)
226 : mOffsetMap(offsetMap)
227 , mSourceLeafManager(sourceLeafManager)
228 , mAttributeIndex(attributeIndex)
229 , mMoveLeafMap(moveLeafMap)
230 , mMoveLeafIndices(moveLeafIndices) { }
231
232 // A CopyIterator is designed to use the indices in a GlobalPointIndexMap for this leaf
233 // and match the interface required for AttributeArray::copyValues()
235 {
236 CopyIterator(const LeafT& leaf, const IndexArray& sortedIndices,
237 const IndexTripleArray& moveIndices, IndexArray& offsets)
238 : mLeaf(leaf)
239 , mSortedIndices(sortedIndices)
240 , mMoveIndices(moveIndices)
241 , mOffsets(offsets) { }
242
243 operator bool() const { return bool(mIt); }
244
245 void reset(Index startIndex, Index endIndex)
246 {
247 mIndex = startIndex;
248 mEndIndex = endIndex;
249 this->advance();
250 }
251
253 {
254 this->advance();
255 return *this;
256 }
257
259 {
260 if (i < mSortedIndices.size()) {
261 return std::get<0>(this->leafIndexTriple(i));
262 }
263 return std::numeric_limits<Index>::max();
264 }
265
267 {
268 OPENVDB_ASSERT(mIt);
269 return std::get<2>(*mIt);
270 }
271
273 {
274 OPENVDB_ASSERT(mIt);
275 return indexOffsetFromVoxel(std::get<1>(*mIt), mLeaf, mOffsets);
276 }
277
278 private:
279 void advance()
280 {
281 if (mIndex >= mEndIndex || mIndex >= mSortedIndices.size()) {
282 mIt = nullptr;
283 }
284 else {
285 mIt = &this->leafIndexTriple(mIndex);
286 }
287 ++mIndex;
288 }
289
290 const IndexTriple& leafIndexTriple(Index i) const
291 {
292 return mMoveIndices[mSortedIndices[i]];
293 }
294
295 private:
296 const LeafT& mLeaf;
297 Index mIndex;
298 Index mEndIndex;
299 const IndexArray& mSortedIndices;
300 const IndexTripleArray& mMoveIndices;
301 IndexArray& mOffsets;
302 const IndexTriple* mIt = nullptr;
303 }; // struct CopyIterator
304
305 void operator()(LeafT& leaf, size_t idx) const
306 {
307 const IndexTripleArray& moveIndices = mMoveLeafMap[idx];
308 if (moveIndices.empty()) return;
309 const IndexArray& sortedIndices = mMoveLeafIndices[idx];
310
311 // extract per-voxel offsets for this leaf
312
313 LeafIndexArray& offsets = mOffsetMap[idx];
314
315 // extract target array and ensure data is out-of-core and non-uniform
316
317 auto& targetArray = leaf.attributeArray(mAttributeIndex);
318 targetArray.loadData();
319 targetArray.expand();
320
321 // perform the copy
322
323 CopyIterator copyIterator(leaf, sortedIndices, moveIndices, offsets);
324
325 // use the sorted indices to track the index of the source leaf
326
327 Index sourceLeafIndex = copyIterator.leafIndex(0);
328 Index startIndex = 0;
329
330 for (size_t i = 1; i <= sortedIndices.size(); i++) {
331 Index endIndex = static_cast<Index>(i);
332 Index newSourceLeafIndex = copyIterator.leafIndex(endIndex);
333
334 // when it changes, do a batch-copy of all the indices that lie within this range
335 // TODO: this step could use nested parallelization for cases where there are a
336 // large number of points being moved per attribute
337
338 if (newSourceLeafIndex > sourceLeafIndex) {
339 copyIterator.reset(startIndex, endIndex);
340
341 const LeafT& sourceLeaf = mSourceLeafManager.leaf(sourceLeafIndex);
342 const auto& sourceArray = sourceLeaf.constAttributeArray(mAttributeIndex);
343 sourceArray.loadData();
344
345 targetArray.copyValuesUnsafe(sourceArray, copyIterator);
346
347 sourceLeafIndex = newSourceLeafIndex;
348 startIndex = endIndex;
349 }
350 }
351 }
352
353private:
354 LeafOffsetArray& mOffsetMap;
355 LeafManagerT& mSourceLeafManager;
356 const Index mAttributeIndex;
357 const GlobalPointIndexMap& mMoveLeafMap;
358 const GlobalPointIndexIndices& mMoveLeafIndices;
359}; // struct GlobalMovePointsOp
360
361
362template <typename TreeT>
364{
365 using LeafT = typename TreeT::LeafNodeType;
366 using LeafArrayT = std::vector<LeafT*>;
368 using AttributeArrays = std::vector<AttributeArray*>;
369
371 const LeafIndexArray& sourceIndices,
372 LeafManagerT& sourceLeafManager,
373 const Index attributeIndex,
374 const LocalPointIndexMap& moveLeafMap)
375 : mOffsetMap(offsetMap)
376 , mSourceIndices(sourceIndices)
377 , mSourceLeafManager(sourceLeafManager)
378 , mAttributeIndex(attributeIndex)
379 , mMoveLeafMap(moveLeafMap) { }
380
381 // A CopyIterator is designed to use the indices in a LocalPointIndexMap for this leaf
382 // and match the interface required for AttributeArray::copyValues()
384 {
385 CopyIterator(const LeafT& leaf, const IndexPairArray& indices, IndexArray& offsets)
386 : mLeaf(leaf)
387 , mIndices(indices)
388 , mOffsets(offsets) { }
389
390 operator bool() const { return mIndex < static_cast<int>(mIndices.size()); }
391
392 CopyIterator& operator++() { ++mIndex; return *this; }
393
395 {
396 return mIndices[mIndex].second;
397 }
398
400 {
401 return indexOffsetFromVoxel(mIndices[mIndex].first, mLeaf, mOffsets);
402 }
403
404 private:
405 const LeafT& mLeaf;
406 const IndexPairArray& mIndices;
407 IndexArray& mOffsets;
408 int mIndex = 0;
409 }; // struct CopyIterator
410
411 void operator()(LeafT& leaf, size_t idx) const
412 {
413 const IndexPairArray& moveIndices = mMoveLeafMap[idx];
414 if (moveIndices.empty()) return;
415
416 // extract per-voxel offsets for this leaf
417
418 LeafIndexArray& offsets = mOffsetMap[idx];
419
420 // extract source array that has the same origin as the target leaf
421
422 OPENVDB_ASSERT(idx < mSourceIndices.size());
423 const Index sourceLeafOffset(mSourceIndices[idx]);
424 LeafT& sourceLeaf = mSourceLeafManager.leaf(sourceLeafOffset);
425 const auto& sourceArray = sourceLeaf.constAttributeArray(mAttributeIndex);
426 sourceArray.loadData();
427
428 // extract target array and ensure data is out-of-core and non-uniform
429
430 auto& targetArray = leaf.attributeArray(mAttributeIndex);
431 targetArray.loadData();
432 targetArray.expand();
433
434 // perform the copy
435
436 CopyIterator copyIterator(leaf, moveIndices, offsets);
437 targetArray.copyValuesUnsafe(sourceArray, copyIterator);
438 }
439
440private:
441 LeafOffsetArray& mOffsetMap;
442 const LeafIndexArray& mSourceIndices;
443 LeafManagerT& mSourceLeafManager;
444 const Index mAttributeIndex;
445 const LocalPointIndexMap& mMoveLeafMap;
446}; // struct LocalMovePointsOp
447
448
449} // namespace point_move_internal
450
451
452////////////////////////////////////////
453
454
455template <typename PointDataGridT, typename DeformerT, typename FilterT>
456inline void movePoints( PointDataGridT& points,
457 const math::Transform& transform,
458 DeformerT& deformer,
459 const FilterT& filter,
460 future::Advect* objectNotInUse,
461 bool threaded)
462{
463 using LeafIndex = point_move_internal::LeafIndex;
464 using PointDataTreeT = typename PointDataGridT::TreeType;
465 using LeafT = typename PointDataTreeT::LeafNodeType;
466 using LeafManagerT = typename tree::LeafManager<PointDataTreeT>;
467
468 using namespace point_move_internal;
469
470 // this object is for future use only
471 OPENVDB_ASSERT(!objectNotInUse);
472 (void)objectNotInUse;
473
474 PointDataTreeT& tree = points.tree();
475
476 // early exit if no LeafNodes
477
478 auto iter = tree.cbeginLeaf();
479
480 if (!iter) return;
481
482 // build voxel topology taking into account any point group deletion
483
484 auto newPoints = point_mask_internal::convertPointsToScalar<PointDataGridT>(
485 points, transform, filter, deformer, threaded);
486 auto& newTree = newPoints->tree();
487
488 // create leaf managers for both trees
489
490 LeafManagerT sourceLeafManager(tree);
491 LeafManagerT targetLeafManager(newTree);
492
493 // extract the existing attribute set
494 const auto& existingAttributeSet = points.tree().cbeginLeaf()->attributeSet();
495
496 // build a coord -> index map for looking up target leafs by origin and a faster
497 // unordered map for finding the source index from a target index
498
499 LeafMap targetLeafMap;
500 LeafIndexArray sourceIndices(targetLeafManager.leafCount(),
501 std::numeric_limits<LeafIndex>::max());
502
503 LeafOffsetArray offsetMap(targetLeafManager.leafCount());
504
505 {
506 LeafMap sourceLeafMap;
507 auto sourceRange = sourceLeafManager.leafRange();
508 for (auto leaf = sourceRange.begin(); leaf; ++leaf) {
509 sourceLeafMap.insert({leaf->origin(), LeafIndex(static_cast<LeafIndex>(leaf.pos()))});
510 }
511 auto targetRange = targetLeafManager.leafRange();
512 for (auto leaf = targetRange.begin(); leaf; ++leaf) {
513 targetLeafMap.insert({leaf->origin(), LeafIndex(static_cast<LeafIndex>(leaf.pos()))});
514 }
515
516 // acquire registry lock to avoid locking when appending attributes in parallel
517
519
520 // perform four independent per-leaf operations in parallel
521 targetLeafManager.foreach(
522 [&](LeafT& leaf, size_t idx) {
523 // map frequency => cumulative histogram
524 auto* buffer = leaf.buffer().data();
525 for (Index i = 1; i < leaf.buffer().size(); i++) {
526 buffer[i] = buffer[i-1] + buffer[i];
527 }
528 // replace attribute set with a copy of the existing one
529 leaf.replaceAttributeSet(
530 new AttributeSet(existingAttributeSet, leaf.getLastValue(), &lock),
531 /*allowMismatchingDescriptors=*/true);
532 // store the index of the source leaf in a corresponding target leaf array
533 const auto it = sourceLeafMap.find(leaf.origin());
534 if (it != sourceLeafMap.end()) {
535 sourceIndices[idx] = it->second;
536 }
537 // allocate offset maps
538 offsetMap[idx].resize(LeafT::SIZE);
539 },
540 threaded);
541 }
542
543 // moving leaf
544
545 GlobalPointIndexMap globalMoveLeafMap(targetLeafManager.leafCount());
546 LocalPointIndexMap localMoveLeafMap(targetLeafManager.leafCount());
547
548 // build global and local move leaf maps and update local positions
549
550 if (filter.state() == index::ALL) {
551 NullFilter nullFilter;
552 BuildMoveMapsOp<DeformerT, PointDataTreeT, NullFilter> op(deformer,
553 globalMoveLeafMap, localMoveLeafMap, targetLeafMap,
554 transform, points.transform(), nullFilter);
555 sourceLeafManager.foreach(op, threaded);
556 } else {
557 BuildMoveMapsOp<DeformerT, PointDataTreeT, FilterT> op(deformer,
558 globalMoveLeafMap, localMoveLeafMap, targetLeafMap,
559 transform, points.transform(), filter);
560 sourceLeafManager.foreach(op, threaded);
561 }
562
563 // build a sorted index vector for each leaf that references the global move map
564 // indices in order of their source leafs and voxels to ensure determinism in the
565 // resulting point orders
566
567 GlobalPointIndexIndices globalMoveLeafIndices(globalMoveLeafMap.size());
568
569 targetLeafManager.foreach(
570 [&](LeafT& /*leaf*/, size_t idx) {
571 const IndexTripleArray& moveIndices = globalMoveLeafMap[idx];
572 if (moveIndices.empty()) return;
573
574 IndexArray& sortedIndices = globalMoveLeafIndices[idx];
575 sortedIndices.resize(moveIndices.size());
576 std::iota(std::begin(sortedIndices), std::end(sortedIndices), 0);
577 std::sort(std::begin(sortedIndices), std::end(sortedIndices),
578 [&](int i, int j)
579 {
580 const Index& indexI0(std::get<0>(moveIndices[i]));
581 const Index& indexJ0(std::get<0>(moveIndices[j]));
582 if (indexI0 < indexJ0) return true;
583 if (indexI0 > indexJ0) return false;
584 return std::get<2>(moveIndices[i]) < std::get<2>(moveIndices[j]);
585 }
586 );
587 },
588 threaded);
589
590 for (const auto& it : existingAttributeSet.descriptor().map()) {
591
592 const Index attributeIndex = static_cast<Index>(it.second);
593
594 // zero offsets
595 targetLeafManager.foreach(
596 [&offsetMap](const LeafT& /*leaf*/, size_t idx) {
597 std::fill(offsetMap[idx].begin(), offsetMap[idx].end(), 0);
598 },
599 threaded);
600
601 // move points between leaf nodes
602
603 GlobalMovePointsOp<PointDataTreeT> globalMoveOp(offsetMap,
604 sourceLeafManager, attributeIndex, globalMoveLeafMap, globalMoveLeafIndices);
605 targetLeafManager.foreach(globalMoveOp, threaded);
606
607 // move points within leaf nodes
608
609 LocalMovePointsOp<PointDataTreeT> localMoveOp(offsetMap,
610 sourceIndices, sourceLeafManager, attributeIndex, localMoveLeafMap);
611 targetLeafManager.foreach(localMoveOp, threaded);
612 }
613
614 points.setTree(newPoints->treePtr());
615}
616
617
618template <typename PointDataGridT, typename DeformerT, typename FilterT>
619inline void movePoints( PointDataGridT& points,
620 DeformerT& deformer,
621 const FilterT& filter,
622 future::Advect* objectNotInUse,
623 bool threaded)
624{
625 movePoints(points, points.transform(), deformer, filter, objectNotInUse, threaded);
626}
627
628
629////////////////////////////////////////
630
631
632template <typename T>
634 : mCache(cache) { }
635
636
637template <typename T>
638template <typename PointDataGridT, typename DeformerT, typename FilterT>
639void CachedDeformer<T>::evaluate(PointDataGridT& grid, DeformerT& deformer, const FilterT& filter,
640 bool threaded)
641{
642 using TreeT = typename PointDataGridT::TreeType;
643 using LeafT = typename TreeT::LeafNodeType;
644 using LeafManagerT = typename tree::LeafManager<TreeT>;
645 LeafManagerT leafManager(grid.tree());
646
647 // initialize cache
648 auto& leafs = mCache.leafs;
649 leafs.resize(leafManager.leafCount());
650
651 const auto& transform = grid.transform();
652
653 // insert deformed positions into the cache
654
655 auto cachePositionsOp = [&](const LeafT& leaf, size_t idx) {
656
657 const Index64 totalPointCount = leaf.pointCount();
658 if (totalPointCount == 0) return;
659
660 // deformer is copied to ensure that it is unique per-thread
661
662 DeformerT newDeformer(deformer);
663
664 newDeformer.reset(leaf, idx);
665
666 auto handle = AttributeHandle<Vec3f>::create(leaf.constAttributeArray("P"));
667
668 auto& cache = leafs[idx];
669 cache.clear();
670
671 // only insert into a vector directly if the filter evaluates all points
672 // and all points are stored in active voxels
673 const bool useVector = filter.state() == index::ALL &&
674 (leaf.isDense() || (leaf.onPointCount() == leaf.pointCount()));
675 if (useVector) {
676 cache.vecData.resize(totalPointCount);
677 }
678
679 for (auto iter = leaf.beginIndexOn(filter); iter; iter++) {
680
681 // extract index-space position and apply index-space deformation (if defined)
682
683 Vec3d position = handle->get(*iter) + iter.getCoord().asVec3d();
684
685 // if deformer is designed to be used in index-space, perform deformation prior
686 // to transforming position to world-space, otherwise perform deformation afterwards
687
689 newDeformer.apply(position, iter);
690 position = transform.indexToWorld(position);
691 }
692 else {
693 position = transform.indexToWorld(position);
694 newDeformer.apply(position, iter);
695 }
696
697 // insert new position into the cache
698
699 if (useVector) {
700 cache.vecData[*iter] = static_cast<Vec3T>(position);
701 }
702 else {
703 cache.mapData.insert({*iter, static_cast<Vec3T>(position)});
704 }
705 }
706
707 // store the total number of points to allow use of an expanded vector on access
708
709 if (!cache.mapData.empty()) {
710 cache.totalSize = static_cast<Index>(totalPointCount);
711 }
712 };
713
714 leafManager.foreach(cachePositionsOp, threaded);
715}
716
717
718template <typename T>
719template <typename LeafT>
720void CachedDeformer<T>::reset(const LeafT& /*leaf*/, size_t idx)
721{
722 if (idx >= mCache.leafs.size()) {
723 if (mCache.leafs.empty()) {
724 throw IndexError("No leafs in cache, perhaps CachedDeformer has not been evaluated?");
725 } else {
726 throw IndexError("Leaf index is out-of-range of cache leafs.");
727 }
728 }
729 auto& cache = mCache.leafs[idx];
730 if (!cache.mapData.empty()) {
731 mLeafMap = &cache.mapData;
732 mLeafVec = nullptr;
733 }
734 else {
735 mLeafVec = &cache.vecData;
736 mLeafMap = nullptr;
737 }
738}
739
740
741template <typename T>
742template <typename IndexIterT>
743void CachedDeformer<T>::apply(Vec3d& position, const IndexIterT& iter) const
744{
745 OPENVDB_ASSERT(*iter >= 0);
746
747 if (mLeafMap) {
748 auto it = mLeafMap->find(*iter);
749 if (it == mLeafMap->end()) return;
750 position = static_cast<openvdb::Vec3d>(it->second);
751 }
752 else {
753 OPENVDB_ASSERT(mLeafVec);
754
755 if (mLeafVec->empty()) return;
756 OPENVDB_ASSERT(*iter < mLeafVec->size());
757 position = static_cast<openvdb::Vec3d>((*mLeafVec)[*iter]);
758 }
759}
760
761
762} // namespace points
763} // namespace OPENVDB_VERSION_NAME
764} // namespace openvdb
765
766#endif // OPENVDB_POINTS_POINT_MOVE_IMPL_HAS_BEEN_INCLUDED
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
static Coord round(const Vec3< T > &xyz)
Return xyz rounded to the closest integer coordinates (cell centered conversion).
Definition Coord.h:51
Definition Exceptions.h:57
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
Vec3d asVec3d() const
Definition Coord.h:144
Definition Transform.h:40
Definition Vec3.h:25
static Ptr create(const AttributeArray &array, const bool collapseOnDestruction=true)
Definition AttributeArray.h:1984
Ordered collection of uniquely-named attribute arrays.
Definition AttributeSet.h:40
static Ptr create(AttributeArray &array, const bool expand=true)
Definition AttributeArray.h:2104
CachedDeformer(Cache &cache)
Cache is expected to be persistent for the lifetime of the CachedDeformer.
Definition PointMoveImpl.h:633
void reset(const LeafT &leaf, size_t idx)
Definition PointMoveImpl.h:720
void apply(Vec3d &position, const IndexIterT &iter) const
Retrieve the new position from the cache.
Definition PointMoveImpl.h:743
point_move_internal::LeafIndex LeafIndex
Definition PointMoveImpl.h:28
std::unordered_map< LeafIndex, Vec3T > LeafMapT
Definition PointMoveImpl.h:31
typename math::Vec3< T > Vec3T
Definition PointMoveImpl.h:29
std::vector< Vec3T > LeafVecT
Definition PointMoveImpl.h:30
void evaluate(PointDataGridT &grid, DeformerT &deformer, const FilterT &filter, bool threaded=true)
Definition PointMoveImpl.h:639
A no-op filter that can be used when iterating over all indices.
Definition IndexIterator.h:52
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition LeafManager.h:86
Vec3< double > Vec3d
Definition Vec3.h:665
@ ALL
Definition IndexIterator.h:44
Definition PointMoveImpl.h:20
Index32 LeafIndex
Definition PointMoveImpl.h:20
std::vector< IndexTripleArray > GlobalPointIndexMap
Definition PointMoveImpl.h:92
std::vector< IndexPair > IndexPairArray
Definition PointMoveImpl.h:96
std::unordered_map< Coord, LeafIndex > LeafMap
Definition PointMoveImpl.h:101
std::vector< IndexPairArray > LocalPointIndexMap
Definition PointMoveImpl.h:97
std::vector< LeafIndex > LeafIndexArray
Definition PointMoveImpl.h:99
std::vector< LeafIndexArray > LeafOffsetArray
Definition PointMoveImpl.h:100
std::vector< IndexArray > GlobalPointIndexIndices
Definition PointMoveImpl.h:93
tbb::concurrent_vector< IndexTriple > IndexTripleArray
Definition PointMoveImpl.h:91
Index indexOffsetFromVoxel(const Index voxelOffset, const LeafT &leaf, IndexArray &offsets)
Definition PointMoveImpl.h:199
std::vector< Index > IndexArray
Definition PointMoveImpl.h:88
std::pair< Index, Index > IndexPair
Definition PointMoveImpl.h:95
std::tuple< LeafIndex, Index, Index > IndexTriple
Definition PointMoveImpl.h:90
Definition AttributeArray.h:42
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.
Definition PointMoveImpl.h:619
Definition PointDataGrid.h:170
Index32 Index
Definition Types.h:54
uint32_t Index32
Definition Types.h:52
uint64_t Index64
Definition Types.h:53
Definition Exceptions.h:13
LeafMapT mapData
Definition PointMoveImpl.h:46
LeafVecT vecData
Definition PointMoveImpl.h:45
Index totalSize
Definition PointMoveImpl.h:47
void clear()
clear data buffers and reset counter
Definition PointMoveImpl.h:39
std::vector< Leaf > leafs
Definition PointMoveImpl.h:50
static const bool IndexSpace
Definition PointMask.h:88
std::vector< LeafT * > LeafArrayT
Definition PointMoveImpl.h:108
void operator()(LeafT &leaf, size_t idx) const
Definition PointMoveImpl.h:126
typename tree::LeafManager< TreeT > LeafManagerT
Definition PointMoveImpl.h:109
typename TreeT::LeafNodeType LeafT
Definition PointMoveImpl.h:107
BuildMoveMapsOp(const DeformerT &deformer, GlobalPointIndexMap &globalMoveLeafMap, LocalPointIndexMap &localMoveLeafMap, const LeafMap &targetLeafMap, const math::Transform &targetTransform, const math::Transform &sourceTransform, const FilterT &filter)
Definition PointMoveImpl.h:111
void reset(Index startIndex, Index endIndex)
Definition PointMoveImpl.h:245
Index leafIndex(Index i) const
Definition PointMoveImpl.h:258
CopyIterator(const LeafT &leaf, const IndexArray &sortedIndices, const IndexTripleArray &moveIndices, IndexArray &offsets)
Definition PointMoveImpl.h:236
std::vector< LeafT * > LeafArrayT
Definition PointMoveImpl.h:217
void operator()(LeafT &leaf, size_t idx) const
Definition PointMoveImpl.h:305
std::vector< AttributeArray * > AttributeArrays
Definition PointMoveImpl.h:219
typename tree::LeafManager< TreeT > LeafManagerT
Definition PointMoveImpl.h:218
typename TreeT::LeafNodeType LeafT
Definition PointMoveImpl.h:216
GlobalMovePointsOp(LeafOffsetArray &offsetMap, LeafManagerT &sourceLeafManager, const Index attributeIndex, const GlobalPointIndexMap &moveLeafMap, const GlobalPointIndexIndices &moveLeafIndices)
Definition PointMoveImpl.h:221
CopyIterator(const LeafT &leaf, const IndexPairArray &indices, IndexArray &offsets)
Definition PointMoveImpl.h:385
std::vector< LeafT * > LeafArrayT
Definition PointMoveImpl.h:366
void operator()(LeafT &leaf, size_t idx) const
Definition PointMoveImpl.h:411
LocalMovePointsOp(LeafOffsetArray &offsetMap, const LeafIndexArray &sourceIndices, LeafManagerT &sourceLeafManager, const Index attributeIndex, const LocalPointIndexMap &moveLeafMap)
Definition PointMoveImpl.h:370
std::vector< AttributeArray * > AttributeArrays
Definition PointMoveImpl.h:368
typename tree::LeafManager< TreeT > LeafManagerT
Definition PointMoveImpl.h:367
typename TreeT::LeafNodeType LeafT
Definition PointMoveImpl.h:365
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:218