HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PointMoveImpl.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-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 
12 class TestPointMove;
13 
14 namespace openvdb {
16 namespace OPENVDB_VERSION_NAME {
17 namespace points {
18 
19 // define leaf index in use as 32-bit
20 namespace point_move_internal { using LeafIndex = Index32; }
21 
22 
23 /// @brief A Deformer that caches the resulting positions from evaluating another Deformer
24 template <typename T>
26 {
27 public:
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 
74 private:
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 
86 namespace point_move_internal {
87 
88 using IndexArray = std::vector<Index>;
89 
90 using IndexTriple = std::tuple<LeafIndex, Index, Index>;
91 using IndexTripleArray = tbb::concurrent_vector<IndexTriple>;
92 using GlobalPointIndexMap = std::vector<IndexTripleArray>;
93 using GlobalPointIndexIndices = std::vector<IndexArray>;
94 
95 using IndexPair = std::pair<Index, Index>;
96 using IndexPairArray = std::vector<IndexPair>;
97 using LocalPointIndexMap = std::vector<IndexPairArray>;
98 
99 using LeafIndexArray = std::vector<LeafIndex>;
100 using LeafOffsetArray = std::vector<LeafIndexArray>;
101 using LeafMap = std::unordered_map<Coord, LeafIndex>;
102 
103 
104 template <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  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 
187 private:
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 
197 template <typename LeafT>
198 inline Index
199 indexOffsetFromVoxel(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 
213 template <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  }
264  }
265 
267  {
268  assert(mIt);
269  return std::get<2>(*mIt);
270  }
271 
273  {
274  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 
353 private:
354  LeafOffsetArray& mOffsetMap;
355  LeafManagerT& mSourceLeafManager;
356  const Index mAttributeIndex;
357  const GlobalPointIndexMap& mMoveLeafMap;
358  const GlobalPointIndexIndices& mMoveLeafIndices;
359 }; // struct GlobalMovePointsOp
360 
361 
362 template <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  {
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  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 
440 private:
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 
455 template <typename PointDataGridT, typename DeformerT, typename FilterT>
456 inline void movePoints( PointDataGridT& points,
457  const math::Transform& transform,
458  DeformerT& deformer,
459  const FilterT& filter,
460  future::Advect* objectNotInUse,
461  bool threaded)
462 {
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  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(),
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 
618 template <typename PointDataGridT, typename DeformerT, typename FilterT>
619 inline 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 
632 template <typename T>
634  : mCache(cache) { }
635 
636 
637 template <typename T>
638 template <typename PointDataGridT, typename DeformerT, typename FilterT>
639 void 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 
718 template <typename T>
719 template <typename LeafT>
720 void 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 
741 template <typename T>
742 template <typename IndexIterT>
743 void CachedDeformer<T>::apply(Vec3d& position, const IndexIterT& iter) const
744 {
745  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  assert(mLeafVec);
754 
755  if (mLeafVec->empty()) return;
756  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
GLint first
Definition: glcorearb.h:405
LocalMovePointsOp(LeafOffsetArray &offsetMap, const LeafIndexArray &sourceIndices, LeafManagerT &sourceLeafManager, const Index attributeIndex, const LocalPointIndexMap &moveLeafMap)
GLsizei GLenum const void * indices
Definition: glcorearb.h:406
GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glad.h:2676
Vec3d indexToWorld(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:108
void
Definition: png.h:1083
std::unordered_map< LeafIndex, Vec3T > LeafMapT
Definition: PointMoveImpl.h:31
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:239
void apply(Vec3d &position, const IndexIterT &iter) const
Retrieve the new position from the cache.
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.
Definition: IndexIterator.h:50
std::tuple< LeafIndex, Index, Index > IndexTriple
Definition: PointMoveImpl.h:90
static Ptr create(AttributeArray &array, const bool expand=true)
FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, const fill_t< Char > &fill) -> OutputIt
Definition: format.h:1262
GLuint GLsizei const GLuint const GLintptr * offsets
Definition: glcorearb.h:2621
Definition: core.h:760
void reset(const LeafT &leaf, size_t idx)
CachedDeformer(Cache &cache)
Cache is expected to be persistent for the lifetime of the CachedDeformer.
tbb::concurrent_vector< IndexTriple > IndexTripleArray
Definition: PointMoveImpl.h:91
Index indexOffsetFromVoxel(const Index voxelOffset, const LeafT &leaf, IndexArray &offsets)
void clear()
clear data buffers and reset counter
Definition: PointMoveImpl.h:39
A Deformer that caches the resulting positions from evaluating another Deformer.
Definition: PointMoveImpl.h:25
Deformer Traits for optionally configuring deformers to be applied in index-space. The default is world-space.
Definition: PointMask.h:85
GLuint GLuint end
Definition: glcorearb.h:475
CopyIterator(const LeafT &leaf, const IndexPairArray &indices, IndexArray &offsets)
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:84
void movePoints(PointDataGridT &points, const math::Transform &transform, DeformerT &deformer, const FilterT &filter, future::Advect *objectNotInUse, bool threaded)
Move points in a PointDataGrid using a custom deformer and a new transform.
void evaluate(PointDataGridT &grid, DeformerT &deformer, const FilterT &filter, bool threaded=true)
std::unordered_map< Coord, LeafIndex > LeafMap
vfloat4 round(const vfloat4 &a)
Definition: simd.h:7436
GA_API const UT_StringHolder transform
buffer(size_t sz) FMT_NOEXCEPT
Definition: core.h:769
BuildMoveMapsOp(const DeformerT &deformer, GlobalPointIndexMap &globalMoveLeafMap, LocalPointIndexMap &localMoveLeafMap, const LeafMap &targetLeafMap, const math::Transform &targetTransform, const math::Transform &sourceTransform, const FilterT &filter)
GLint j
Definition: glad.h:2733
GLsizeiptr size
Definition: glcorearb.h:664
static Ptr create(const AttributeArray &array, const bool collapseOnDestruction=true)
SIM_API const UT_StringHolder position
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
Ordered collection of uniquely-named attribute arrays.
Definition: AttributeSet.h:38
CopyIterator(const LeafT &leaf, const IndexArray &sortedIndices, const IndexTripleArray &moveIndices, IndexArray &offsets)
#define SIZE
Definition: simple.C:41
Vec3d worldToIndex(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:110
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:119
void sort(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7334
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glcorearb.h:1297
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.
Definition: node.h:483