HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PointMove.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 PointMove.h
7 ///
8 /// @brief Ability to move VDB Points using a custom deformer.
9 ///
10 /// Deformers used when moving points are in world space by default and must adhere
11 /// to the interface described in the example below:
12 /// @code
13 /// struct MyDeformer
14 /// {
15 /// // A reset is performed on each leaf in turn before the points in that leaf are
16 /// // deformed. A leaf and leaf index (standard leaf traversal order) are supplied as
17 /// // the arguments, which matches the functor interface for LeafManager::foreach().
18 /// template <typename LeafNoteType>
19 /// void reset(LeafNoteType& leaf, size_t idx);
20 ///
21 /// // Evaluate the deformer and modify the given position to generate the deformed
22 /// // position. An index iterator is supplied as the argument to allow querying the
23 /// // point offset or containing voxel coordinate.
24 /// template <typename IndexIterT>
25 /// void apply(Vec3d& position, const IndexIterT& iter) const;
26 /// };
27 /// @endcode
28 ///
29 /// @note The DeformerTraits struct (defined in PointMask.h) can be used to configure
30 /// a deformer to evaluate in index space.
31 
32 #ifndef OPENVDB_POINTS_POINT_MOVE_HAS_BEEN_INCLUDED
33 #define OPENVDB_POINTS_POINT_MOVE_HAS_BEEN_INCLUDED
34 
35 #include <openvdb/openvdb.h>
36 
39 
40 #include <tbb/concurrent_vector.h>
41 
42 #include <algorithm>
43 #include <iterator> // for std::begin(), std::end()
44 #include <map>
45 #include <numeric> // for std::iota()
46 #include <tuple>
47 #include <unordered_map>
48 #include <vector>
49 
50 class TestPointMove;
51 
52 
53 namespace openvdb {
55 namespace OPENVDB_VERSION_NAME {
56 namespace points {
57 
58 // dummy object for future use
59 namespace future { struct Advect { }; }
60 
61 
62 /// @brief Move points in a PointDataGrid using a custom deformer
63 /// @param points the PointDataGrid containing the points to be moved.
64 /// @param deformer a custom deformer that defines how to move the points.
65 /// @param filter an optional index filter
66 /// @param objectNotInUse for future use, this object is currently ignored
67 /// @param threaded enable or disable threading (threading is enabled by default)
68 template <typename PointDataGridT, typename DeformerT, typename FilterT = NullFilter>
69 inline void movePoints(PointDataGridT& points,
70  DeformerT& deformer,
71  const FilterT& filter = NullFilter(),
72  future::Advect* objectNotInUse = nullptr,
73  bool threaded = true);
74 
75 
76 /// @brief Move points in a PointDataGrid using a custom deformer and a new transform
77 /// @param points the PointDataGrid containing the points to be moved.
78 /// @param transform target transform to use for the resulting points.
79 /// @param deformer a custom deformer that defines how to move the points.
80 /// @param filter an optional index filter
81 /// @param objectNotInUse for future use, this object is currently ignored
82 /// @param threaded enable or disable threading (threading is enabled by default)
83 template <typename PointDataGridT, typename DeformerT, typename FilterT = NullFilter>
84 inline void movePoints(PointDataGridT& points,
86  DeformerT& deformer,
87  const FilterT& filter = NullFilter(),
88  future::Advect* objectNotInUse = nullptr,
89  bool threaded = true);
90 
91 
92 // define leaf index in use as 32-bit
93 namespace point_move_internal { using LeafIndex = Index32; }
94 
95 
96 /// @brief A Deformer that caches the resulting positions from evaluating another Deformer
97 template <typename T>
99 {
100 public:
102  using Vec3T = typename math::Vec3<T>;
103  using LeafVecT = std::vector<Vec3T>;
104  using LeafMapT = std::unordered_map<LeafIndex, Vec3T>;
105 
106  // Internal data cache to allow the deformer to offer light-weight copying
107  struct Cache
108  {
109  struct Leaf
110  {
111  /// @brief clear data buffers and reset counter
112  void clear() {
113  vecData.clear();
114  mapData.clear();
115  totalSize = 0;
116  }
117 
121  }; // struct Leaf
122 
123  std::vector<Leaf> leafs;
124  }; // struct Cache
125 
126  /// Cache is expected to be persistent for the lifetime of the CachedDeformer
127  explicit CachedDeformer(Cache& cache);
128 
129  /// Caches the result of evaluating the supplied point grid using the deformer and filter
130  /// @param grid the points to be moved
131  /// @param deformer the deformer to apply to the points
132  /// @param filter the point filter to use when evaluating the points
133  /// @param threaded enable or disable threading (threading is enabled by default)
134  template <typename PointDataGridT, typename DeformerT, typename FilterT>
135  void evaluate(PointDataGridT& grid, DeformerT& deformer, const FilterT& filter,
136  bool threaded = true);
137 
138  /// Stores pointers to the vector or map and optionally expands the map into a vector
139  /// @throw IndexError if idx is out-of-range of the leafs in the cache
140  template <typename LeafT>
141  void reset(const LeafT& leaf, size_t idx);
142 
143  /// Retrieve the new position from the cache
144  template <typename IndexIterT>
145  void apply(Vec3d& position, const IndexIterT& iter) const;
146 
147 private:
148  friend class ::TestPointMove;
149 
150  Cache& mCache;
151  const LeafVecT* mLeafVec = nullptr;
152  const LeafMapT* mLeafMap = nullptr;
153 }; // class CachedDeformer
154 
155 
156 ////////////////////////////////////////
157 
158 
159 namespace point_move_internal {
160 
161 using IndexArray = std::vector<Index>;
162 
163 using IndexTriple = std::tuple<LeafIndex, Index, Index>;
164 using IndexTripleArray = tbb::concurrent_vector<IndexTriple>;
165 using GlobalPointIndexMap = std::vector<IndexTripleArray>;
166 using GlobalPointIndexIndices = std::vector<IndexArray>;
167 
168 using IndexPair = std::pair<Index, Index>;
169 using IndexPairArray = std::vector<IndexPair>;
170 using LocalPointIndexMap = std::vector<IndexPairArray>;
171 
172 using LeafIndexArray = std::vector<LeafIndex>;
173 using LeafOffsetArray = std::vector<LeafIndexArray>;
174 using LeafMap = std::unordered_map<Coord, LeafIndex>;
175 
176 
177 template <typename DeformerT, typename TreeT, typename FilterT>
179 {
180  using LeafT = typename TreeT::LeafNodeType;
181  using LeafArrayT = std::vector<LeafT*>;
183 
184  BuildMoveMapsOp(const DeformerT& deformer,
185  GlobalPointIndexMap& globalMoveLeafMap,
186  LocalPointIndexMap& localMoveLeafMap,
187  const LeafMap& targetLeafMap,
188  const math::Transform& targetTransform,
189  const math::Transform& sourceTransform,
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) { }
198 
199  void operator()(LeafT& leaf, size_t idx) const
200  {
201  DeformerT deformer(mDeformer);
202  deformer.reset(leaf, idx);
203 
204  // determine source leaf node origin and offset in the source leaf vector
205 
206  Coord sourceLeafOrigin = leaf.origin();
207 
208  auto sourceHandle = AttributeWriteHandle<Vec3f>::create(leaf.attributeArray("P"));
209 
210  for (auto iter = leaf.beginIndexOn(mFilter); iter; iter++) {
211 
212  const bool useIndexSpace = DeformerTraits<DeformerT>::IndexSpace;
213 
214  // extract index-space position and apply index-space deformation (if applicable)
215 
216  Vec3d positionIS = sourceHandle->get(*iter) + iter.getCoord().asVec3d();
217  if (useIndexSpace) {
218  deformer.apply(positionIS, iter);
219  }
220 
221  // transform to world-space position and apply world-space deformation (if applicable)
222 
223  Vec3d positionWS = mSourceTransform.indexToWorld(positionIS);
224  if (!useIndexSpace) {
225  deformer.apply(positionWS, iter);
226  }
227 
228  // transform to index-space position of target grid
229 
230  positionIS = mTargetTransform.worldToIndex(positionWS);
231 
232  // determine target voxel and offset
233 
234  Coord targetVoxel = Coord::round(positionIS);
235  Index targetOffset = LeafT::coordToOffset(targetVoxel);
236 
237  // set new local position in source transform space (if point has been deformed)
238 
239  Vec3d voxelPosition(positionIS - targetVoxel.asVec3d());
240  sourceHandle->set(*iter, voxelPosition);
241 
242  // determine target leaf node origin and offset in the target leaf vector
243 
244  Coord targetLeafOrigin = targetVoxel & ~(LeafT::DIM - 1);
245  assert(mTargetLeafMap.find(targetLeafOrigin) != mTargetLeafMap.end());
246  const LeafIndex targetLeafOffset(mTargetLeafMap.at(targetLeafOrigin));
247 
248  // insert into move map based on whether point ends up in a new leaf node or not
249 
250  if (targetLeafOrigin == sourceLeafOrigin) {
251  mLocalMoveLeafMap[targetLeafOffset].emplace_back(targetOffset, *iter);
252  }
253  else {
254  mGlobalMoveLeafMap[targetLeafOffset].push_back(IndexTriple(
255  LeafIndex(static_cast<LeafIndex>(idx)), targetOffset, *iter));
256  }
257  }
258  }
259 
260 private:
261  const DeformerT& mDeformer;
262  GlobalPointIndexMap& mGlobalMoveLeafMap;
263  LocalPointIndexMap& mLocalMoveLeafMap;
264  const LeafMap& mTargetLeafMap;
265  const math::Transform& mTargetTransform;
266  const math::Transform& mSourceTransform;
267  const FilterT& mFilter;
268 }; // struct BuildMoveMapsOp
269 
270 template <typename LeafT>
271 inline Index
272 indexOffsetFromVoxel(const Index voxelOffset, const LeafT& leaf, IndexArray& offsets)
273 {
274  // compute the target point index by summing the point index of the previous
275  // voxel with the current number of points added to this voxel, tracked by the
276  // offsets array
277 
278  Index targetOffset = offsets[voxelOffset]++;
279  if (voxelOffset > 0) {
280  targetOffset += static_cast<Index>(leaf.getValue(voxelOffset - 1));
281  }
282  return targetOffset;
283 }
284 
285 
286 #if OPENVDB_ABI_VERSION_NUMBER >= 6
287 
288 
289 template <typename TreeT>
290 struct GlobalMovePointsOp
291 {
292  using LeafT = typename TreeT::LeafNodeType;
293  using LeafArrayT = std::vector<LeafT*>;
294  using LeafManagerT = typename tree::LeafManager<TreeT>;
295  using AttributeArrays = std::vector<AttributeArray*>;
296 
298  LeafManagerT& sourceLeafManager,
299  const Index attributeIndex,
300  const GlobalPointIndexMap& moveLeafMap,
301  const GlobalPointIndexIndices& moveLeafIndices)
302  : mOffsetMap(offsetMap)
303  , mSourceLeafManager(sourceLeafManager)
304  , mAttributeIndex(attributeIndex)
305  , mMoveLeafMap(moveLeafMap)
306  , mMoveLeafIndices(moveLeafIndices) { }
307 
308  // A CopyIterator is designed to use the indices in a GlobalPointIndexMap for this leaf
309  // and match the interface required for AttributeArray::copyValues()
310  struct CopyIterator
311  {
312  CopyIterator(const LeafT& leaf, const IndexArray& sortedIndices,
313  const IndexTripleArray& moveIndices, IndexArray& offsets)
314  : mLeaf(leaf)
315  , mSortedIndices(sortedIndices)
316  , mMoveIndices(moveIndices)
317  , mOffsets(offsets) { }
318 
319  operator bool() const { return bool(mIt); }
320 
321  void reset(Index startIndex, Index endIndex)
322  {
323  mIndex = startIndex;
324  mEndIndex = endIndex;
325  this->advance();
326  }
327 
328  CopyIterator& operator++()
329  {
330  this->advance();
331  return *this;
332  }
333 
334  Index leafIndex(Index i) const
335  {
336  if (i < mSortedIndices.size()) {
337  return std::get<0>(this->leafIndexTriple(i));
338  }
340  }
341 
342  Index sourceIndex() const
343  {
344  assert(mIt);
345  return std::get<2>(*mIt);
346  }
347 
348  Index targetIndex() const
349  {
350  assert(mIt);
351  return indexOffsetFromVoxel(std::get<1>(*mIt), mLeaf, mOffsets);
352  }
353 
354  private:
355  void advance()
356  {
357  if (mIndex >= mEndIndex || mIndex >= mSortedIndices.size()) {
358  mIt = nullptr;
359  }
360  else {
361  mIt = &this->leafIndexTriple(mIndex);
362  }
363  ++mIndex;
364  }
365 
366  const IndexTriple& leafIndexTriple(Index i) const
367  {
368  return mMoveIndices[mSortedIndices[i]];
369  }
370 
371  private:
372  const LeafT& mLeaf;
373  Index mIndex;
374  Index mEndIndex;
375  const IndexArray& mSortedIndices;
376  const IndexTripleArray& mMoveIndices;
377  IndexArray& mOffsets;
378  const IndexTriple* mIt = nullptr;
379  }; // struct CopyIterator
380 
381  void operator()(LeafT& leaf, size_t idx) const
382  {
383  const IndexTripleArray& moveIndices = mMoveLeafMap[idx];
384  if (moveIndices.empty()) return;
385  const IndexArray& sortedIndices = mMoveLeafIndices[idx];
386 
387  // extract per-voxel offsets for this leaf
388 
389  LeafIndexArray& offsets = mOffsetMap[idx];
390 
391  // extract target array and ensure data is out-of-core and non-uniform
392 
393  auto& targetArray = leaf.attributeArray(mAttributeIndex);
394  targetArray.loadData();
395  targetArray.expand();
396 
397  // perform the copy
398 
399  CopyIterator copyIterator(leaf, sortedIndices, moveIndices, offsets);
400 
401  // use the sorted indices to track the index of the source leaf
402 
403  Index sourceLeafIndex = copyIterator.leafIndex(0);
404  Index startIndex = 0;
405 
406  for (size_t i = 1; i <= sortedIndices.size(); i++) {
407  Index endIndex = static_cast<Index>(i);
408  Index newSourceLeafIndex = copyIterator.leafIndex(endIndex);
409 
410  // when it changes, do a batch-copy of all the indices that lie within this range
411  // TODO: this step could use nested parallelization for cases where there are a
412  // large number of points being moved per attribute
413 
414  if (newSourceLeafIndex > sourceLeafIndex) {
415  copyIterator.reset(startIndex, endIndex);
416 
417  const LeafT& sourceLeaf = mSourceLeafManager.leaf(sourceLeafIndex);
418  const auto& sourceArray = sourceLeaf.constAttributeArray(mAttributeIndex);
419  sourceArray.loadData();
420 
421  targetArray.copyValuesUnsafe(sourceArray, copyIterator);
422 
423  sourceLeafIndex = newSourceLeafIndex;
424  startIndex = endIndex;
425  }
426  }
427  }
428 
429 private:
430  LeafOffsetArray& mOffsetMap;
431  LeafManagerT& mSourceLeafManager;
432  const Index mAttributeIndex;
433  const GlobalPointIndexMap& mMoveLeafMap;
434  const GlobalPointIndexIndices& mMoveLeafIndices;
435 }; // struct GlobalMovePointsOp
436 
437 
438 template <typename TreeT>
439 struct LocalMovePointsOp
440 {
441  using LeafT = typename TreeT::LeafNodeType;
442  using LeafArrayT = std::vector<LeafT*>;
443  using LeafManagerT = typename tree::LeafManager<TreeT>;
444  using AttributeArrays = std::vector<AttributeArray*>;
445 
447  const LeafIndexArray& sourceIndices,
448  LeafManagerT& sourceLeafManager,
449  const Index attributeIndex,
450  const LocalPointIndexMap& moveLeafMap)
451  : mOffsetMap(offsetMap)
452  , mSourceIndices(sourceIndices)
453  , mSourceLeafManager(sourceLeafManager)
454  , mAttributeIndex(attributeIndex)
455  , mMoveLeafMap(moveLeafMap) { }
456 
457  // A CopyIterator is designed to use the indices in a LocalPointIndexMap for this leaf
458  // and match the interface required for AttributeArray::copyValues()
459  struct CopyIterator
460  {
461  CopyIterator(const LeafT& leaf, const IndexPairArray& indices, IndexArray& offsets)
462  : mLeaf(leaf)
463  , mIndices(indices)
464  , mOffsets(offsets) { }
465 
466  operator bool() const { return mIndex < static_cast<int>(mIndices.size()); }
467 
468  CopyIterator& operator++() { ++mIndex; return *this; }
469 
470  Index sourceIndex() const
471  {
472  return mIndices[mIndex].second;
473  }
474 
475  Index targetIndex() const
476  {
477  return indexOffsetFromVoxel(mIndices[mIndex].first, mLeaf, mOffsets);
478  }
479 
480  private:
481  const LeafT& mLeaf;
482  const IndexPairArray& mIndices;
483  IndexArray& mOffsets;
484  int mIndex = 0;
485  }; // struct CopyIterator
486 
487  void operator()(LeafT& leaf, size_t idx) const
488  {
489  const IndexPairArray& moveIndices = mMoveLeafMap[idx];
490  if (moveIndices.empty()) return;
491 
492  // extract per-voxel offsets for this leaf
493 
494  LeafIndexArray& offsets = mOffsetMap[idx];
495 
496  // extract source array that has the same origin as the target leaf
497 
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();
503 
504  // extract target array and ensure data is out-of-core and non-uniform
505 
506  auto& targetArray = leaf.attributeArray(mAttributeIndex);
507  targetArray.loadData();
508  targetArray.expand();
509 
510  // perform the copy
511 
512  CopyIterator copyIterator(leaf, moveIndices, offsets);
513  targetArray.copyValuesUnsafe(sourceArray, copyIterator);
514  }
515 
516 private:
517  LeafOffsetArray& mOffsetMap;
518  const LeafIndexArray& mSourceIndices;
519  LeafManagerT& mSourceLeafManager;
520  const Index mAttributeIndex;
521  const LocalPointIndexMap& mMoveLeafMap;
522 }; // struct LocalMovePointsOp
523 
524 
525 #else
526 
527 
528 // The following infrastructure - ArrayProcessor, PerformTypedMoveOp, processTypedArray()
529 // is required to improve AttributeArray copying performance beyond using the virtual function
530 // AttributeArray::set(Index, AttributeArray&, Index). An ABI=6 addition to AttributeArray
531 // improves this by introducing an AttributeArray::copyValues() method to significantly
532 // simplify this logic without incurring the same virtual function cost.
533 
534 
535 /// Helper class used internally by processTypedArray()
536 template<typename ValueType, typename OpType>
538  static inline void call(OpType& op, const AttributeArray& array) {
539  op.template operator()<ValueType>(array);
540  }
541 };
542 
543 
544 /// @brief Utility function that, given a generic attribute array,
545 /// calls a functor with the fully-resolved value type of the array
546 template<typename ArrayType, typename OpType>
547 bool
548 processTypedArray(const ArrayType& array, OpType& op)
549 {
550  using namespace openvdb;
551  using namespace openvdb::math;
552  if (array.template hasValueType<bool>()) ArrayProcessor<bool, OpType>::call(op, array);
553  else if (array.template hasValueType<int16_t>()) ArrayProcessor<int16_t, OpType>::call(op, array);
554  else if (array.template hasValueType<int32_t>()) ArrayProcessor<int32_t, OpType>::call(op, array);
555  else if (array.template hasValueType<int64_t>()) ArrayProcessor<int64_t, OpType>::call(op, array);
556  else if (array.template hasValueType<float>()) ArrayProcessor<float, OpType>::call(op, array);
557  else if (array.template hasValueType<double>()) ArrayProcessor<double, OpType>::call(op, array);
558  else if (array.template hasValueType<Vec3<int32_t>>()) ArrayProcessor<Vec3<int32_t>, OpType>::call(op, array);
559  else if (array.template hasValueType<Vec3<float>>()) ArrayProcessor<Vec3<float>, OpType>::call(op, array);
560  else if (array.template hasValueType<Vec3<double>>()) ArrayProcessor<Vec3<double>, OpType>::call(op, array);
561  else if (array.template hasValueType<GroupType>()) ArrayProcessor<GroupType, OpType>::call(op, array);
562  else if (array.template hasValueType<Index>()) ArrayProcessor<Index, OpType>::call(op, array);
563  else if (array.template hasValueType<Mat3<float>>()) ArrayProcessor<Mat3<float>, OpType>::call(op, array);
564  else if (array.template hasValueType<Mat3<double>>()) ArrayProcessor<Mat3<double>, OpType>::call(op, array);
565  else if (array.template hasValueType<Mat4<float>>()) ArrayProcessor<Mat4<float>, OpType>::call(op, array);
566  else if (array.template hasValueType<Mat4<double>>()) ArrayProcessor<Mat4<double>, OpType>::call(op, array);
567  else if (array.template hasValueType<Quat<float>>()) ArrayProcessor<Quat<float>, OpType>::call(op, array);
568  else if (array.template hasValueType<Quat<double>>()) ArrayProcessor<Quat<double>, OpType>::call(op, array);
569  else return false;
570  return true;
571 }
572 
573 
574 /// Cache read and write attribute handles to amortize construction cost
576 {
577  using HandleArray = std::vector<AttributeHandle<int>::Ptr>;
578 
579  AttributeHandles(const size_t size)
580  : mHandles() { mHandles.reserve(size); }
581 
582  AttributeArray& getArray(const Index leafOffset)
583  {
584  auto* handle = reinterpret_cast<AttributeWriteHandle<int>*>(mHandles[leafOffset].get());
585  assert(handle);
586  return handle->array();
587  }
588 
589  const AttributeArray& getConstArray(const Index leafOffset) const
590  {
591  const auto* handle = mHandles[leafOffset].get();
592  assert(handle);
593  return handle->array();
594  }
595 
596  template <typename ValueT>
598  {
599  auto* handle = reinterpret_cast<AttributeHandle<ValueT>*>(mHandles[leafOffset].get());
600  assert(handle);
601  return *handle;
602  }
603 
604  template <typename ValueT>
606  {
607  auto* handle = reinterpret_cast<AttributeWriteHandle<ValueT>*>(mHandles[leafOffset].get());
608  assert(handle);
609  return *handle;
610  }
611 
612  /// Create a handle and reinterpret cast as an int handle to store
614  {
616  : mHandles(handles) { }
617 
618  template<typename ValueT>
619  void operator()(const AttributeArray& array) const
620  {
621  auto* handleAsInt = reinterpret_cast<AttributeHandle<int>*>(
623  mHandles.emplace_back(handleAsInt);
624  }
625 
626  private:
627  HandleArray& mHandles;
628  }; // struct CacheHandleOp
629 
630  template <typename LeafRangeT>
631  void cache(const LeafRangeT& range, const Index attributeIndex)
632  {
633  using namespace openvdb::math;
634 
635  mHandles.clear();
636  CacheHandleOp op(mHandles);
637 
638  for (auto leaf = range.begin(); leaf; ++leaf) {
639  const auto& array = leaf->constAttributeArray(attributeIndex);
641  }
642  }
643 
644 private:
645  HandleArray mHandles;
646 }; // struct AttributeHandles
647 
648 
649 template <typename TreeT>
651 {
652  using LeafT = typename TreeT::LeafNodeType;
653  using LeafArrayT = std::vector<LeafT*>;
655 
657  AttributeHandles& targetHandles,
658  AttributeHandles& sourceHandles,
659  const Index attributeIndex,
660  const GlobalPointIndexMap& moveLeafMap,
661  const GlobalPointIndexIndices& moveLeafIndices)
662  : mOffsetMap(offsetMap)
663  , mTargetHandles(targetHandles)
664  , mSourceHandles(sourceHandles)
665  , mAttributeIndex(attributeIndex)
666  , mMoveLeafMap(moveLeafMap)
667  , mMoveLeafIndices(moveLeafIndices) { }
668 
670  {
671  PerformTypedMoveOp(AttributeHandles& targetHandles, AttributeHandles& sourceHandles,
672  Index targetOffset, const LeafT& targetLeaf,
673  IndexArray& offsets, const IndexTripleArray& indices,
674  const IndexArray& sortedIndices)
675  : mTargetHandles(targetHandles)
676  , mSourceHandles(sourceHandles)
677  , mTargetOffset(targetOffset)
678  , mTargetLeaf(targetLeaf)
679  , mOffsets(offsets)
680  , mIndices(indices)
681  , mSortedIndices(sortedIndices) { }
682 
683  template<typename ValueT>
684  void operator()(const AttributeArray&) const
685  {
686  auto& targetHandle = mTargetHandles.getWriteHandle<ValueT>(mTargetOffset);
687  targetHandle.expand();
688 
689  for (const auto& index : mSortedIndices) {
690  const auto& it = mIndices[index];
691  const auto& sourceHandle = mSourceHandles.getHandle<ValueT>(std::get<0>(it));
692  const Index targetIndex = indexOffsetFromVoxel(std::get<1>(it), mTargetLeaf, mOffsets);
693  for (Index i = 0; i < sourceHandle.stride(); i++) {
694  ValueT sourceValue = sourceHandle.get(std::get<2>(it), i);
695  targetHandle.set(targetIndex, i, sourceValue);
696  }
697  }
698  }
699 
700  private:
701  AttributeHandles& mTargetHandles;
702  AttributeHandles& mSourceHandles;
703  Index mTargetOffset;
704  const LeafT& mTargetLeaf;
705  IndexArray& mOffsets;
706  const IndexTripleArray& mIndices;
707  const IndexArray& mSortedIndices;
708  }; // struct PerformTypedMoveOp
709 
710  void performMove(Index targetOffset, const LeafT& targetLeaf,
711  IndexArray& offsets, const IndexTripleArray& indices,
712  const IndexArray& sortedIndices) const
713  {
714  auto& targetArray = mTargetHandles.getArray(targetOffset);
715  targetArray.loadData();
716  targetArray.expand();
717 
718  for (const auto& index : sortedIndices) {
719  const auto& it = indices[index];
720 
721  const auto& sourceArray = mSourceHandles.getConstArray(std::get<0>(it));
722 
723  const Index sourceOffset = std::get<2>(it);
724  const Index targetOffset = indexOffsetFromVoxel(std::get<1>(it), targetLeaf, offsets);
725 
726  targetArray.set(targetOffset, sourceArray, sourceOffset);
727  }
728  }
729 
730  void operator()(LeafT& leaf, size_t aIdx) const
731  {
732  const Index idx(static_cast<Index>(aIdx));
733  const auto& moveIndices = mMoveLeafMap[aIdx];
734  if (moveIndices.empty()) return;
735  const auto& sortedIndices = mMoveLeafIndices[aIdx];
736 
737  // extract per-voxel offsets for this leaf
738 
739  auto& offsets = mOffsetMap[aIdx];
740 
741  const auto& array = leaf.constAttributeArray(mAttributeIndex);
742 
743  PerformTypedMoveOp op(mTargetHandles, mSourceHandles, idx, leaf, offsets,
744  moveIndices, sortedIndices);
745  if (!processTypedArray(array, op)) {
746  this->performMove(idx, leaf, offsets, moveIndices, sortedIndices);
747  }
748  }
749 
750 private:
751  LeafOffsetArray& mOffsetMap;
752  AttributeHandles& mTargetHandles;
753  AttributeHandles& mSourceHandles;
754  const Index mAttributeIndex;
755  const GlobalPointIndexMap& mMoveLeafMap;
756  const GlobalPointIndexIndices& mMoveLeafIndices;
757 }; // struct GlobalMovePointsOp
758 
759 
760 template <typename TreeT>
762 {
763  using LeafT = typename TreeT::LeafNodeType;
764  using LeafArrayT = std::vector<LeafT*>;
766 
768  AttributeHandles& targetHandles,
769  const LeafIndexArray& sourceIndices,
770  AttributeHandles& sourceHandles,
771  const Index attributeIndex,
772  const LocalPointIndexMap& moveLeafMap)
773  : mOffsetMap(offsetMap)
774  , mTargetHandles(targetHandles)
775  , mSourceIndices(sourceIndices)
776  , mSourceHandles(sourceHandles)
777  , mAttributeIndex(attributeIndex)
778  , mMoveLeafMap(moveLeafMap) { }
779 
781  {
782  PerformTypedMoveOp(AttributeHandles& targetHandles, AttributeHandles& sourceHandles,
783  Index targetOffset, Index sourceOffset, const LeafT& targetLeaf,
784  IndexArray& offsets, const IndexPairArray& indices)
785  : mTargetHandles(targetHandles)
786  , mSourceHandles(sourceHandles)
787  , mTargetOffset(targetOffset)
788  , mSourceOffset(sourceOffset)
789  , mTargetLeaf(targetLeaf)
790  , mOffsets(offsets)
791  , mIndices(indices) { }
792 
793  template<typename ValueT>
794  void operator()(const AttributeArray&) const
795  {
796  auto& targetHandle = mTargetHandles.getWriteHandle<ValueT>(mTargetOffset);
797  const auto& sourceHandle = mSourceHandles.getHandle<ValueT>(mSourceOffset);
798 
799  targetHandle.expand();
800 
801  for (const auto& it : mIndices) {
802  const Index targetIndex = indexOffsetFromVoxel(it.first, mTargetLeaf, mOffsets);
803  for (Index i = 0; i < sourceHandle.stride(); i++) {
804  ValueT sourceValue = sourceHandle.get(it.second, i);
805  targetHandle.set(targetIndex, i, sourceValue);
806  }
807  }
808  }
809 
810  private:
811  AttributeHandles& mTargetHandles;
812  AttributeHandles& mSourceHandles;
813  Index mTargetOffset;
814  Index mSourceOffset;
815  const LeafT& mTargetLeaf;
816  IndexArray& mOffsets;
817  const IndexPairArray& mIndices;
818  }; // struct PerformTypedMoveOp
819 
820  template <typename ValueT>
821  void performTypedMove(Index sourceOffset, Index targetOffset, const LeafT& targetLeaf,
822  IndexArray& offsets, const IndexPairArray& indices) const
823  {
824  auto& targetHandle = mTargetHandles.getWriteHandle<ValueT>(targetOffset);
825  const auto& sourceHandle = mSourceHandles.getHandle<ValueT>(sourceOffset);
826 
827  targetHandle.expand();
828 
829  for (const auto& it : indices) {
830  const Index tgtOffset = indexOffsetFromVoxel(it.first, targetLeaf, offsets);
831  for (Index i = 0; i < sourceHandle.stride(); i++) {
832  ValueT sourceValue = sourceHandle.get(it.second, i);
833  targetHandle.set(tgtOffset, i, sourceValue);
834  }
835  }
836  }
837 
838  void performMove(Index targetOffset, Index sourceOffset, const LeafT& targetLeaf,
839  IndexArray& offsets, const IndexPairArray& indices) const
840  {
841  auto& targetArray = mTargetHandles.getArray(targetOffset);
842  const auto& sourceArray = mSourceHandles.getConstArray(sourceOffset);
843 
844  for (const auto& it : indices) {
845  const Index sourceOffset = it.second;
846  const Index targetOffset = indexOffsetFromVoxel(it.first, targetLeaf, offsets);
847 
848  targetArray.set(targetOffset, sourceArray, sourceOffset);
849  }
850  }
851 
852  void operator()(const LeafT& leaf, size_t aIdx) const
853  {
854  const Index idx(static_cast<Index>(aIdx));
855  const auto& moveIndices = mMoveLeafMap.at(aIdx);
856  if (moveIndices.empty()) return;
857 
858  // extract target leaf and per-voxel offsets for this leaf
859 
860  auto& offsets = mOffsetMap[aIdx];
861 
862  // extract source leaf that has the same origin as the target leaf (if any)
863 
864  assert(aIdx < mSourceIndices.size());
865  const Index sourceOffset(mSourceIndices[aIdx]);
866 
867  const auto& array = leaf.constAttributeArray(mAttributeIndex);
868 
869  PerformTypedMoveOp op(mTargetHandles, mSourceHandles,
870  idx, sourceOffset, leaf, offsets, moveIndices);
871  if (!processTypedArray(array, op)) {
872  this->performMove(idx, sourceOffset, leaf, offsets, moveIndices);
873  }
874  }
875 
876 private:
877  LeafOffsetArray& mOffsetMap;
878  AttributeHandles& mTargetHandles;
879  const LeafIndexArray& mSourceIndices;
880  AttributeHandles& mSourceHandles;
881  const Index mAttributeIndex;
882  const LocalPointIndexMap& mMoveLeafMap;
883 }; // struct LocalMovePointsOp
884 
885 
886 #endif // OPENVDB_ABI_VERSION_NUMBER >= 6
887 
888 
889 } // namespace point_move_internal
890 
891 
892 ////////////////////////////////////////
893 
894 
895 template <typename PointDataGridT, typename DeformerT, typename FilterT>
896 inline void movePoints( PointDataGridT& points,
897  const math::Transform& transform,
898  DeformerT& deformer,
899  const FilterT& filter,
900  future::Advect* objectNotInUse,
901  bool threaded)
902 {
904  using PointDataTreeT = typename PointDataGridT::TreeType;
905  using LeafT = typename PointDataTreeT::LeafNodeType;
906  using LeafManagerT = typename tree::LeafManager<PointDataTreeT>;
907 
908  using namespace point_move_internal;
909 
910  // this object is for future use only
911  assert(!objectNotInUse);
912  (void)objectNotInUse;
913 
914  PointDataTreeT& tree = points.tree();
915 
916  // early exit if no LeafNodes
917 
918  PointDataTree::LeafCIter iter = tree.cbeginLeaf();
919 
920  if (!iter) return;
921 
922  // build voxel topology taking into account any point group deletion
923 
924  auto newPoints = point_mask_internal::convertPointsToScalar<PointDataGrid>(
925  points, transform, filter, deformer, threaded);
926  auto& newTree = newPoints->tree();
927 
928  // create leaf managers for both trees
929 
930  LeafManagerT sourceLeafManager(tree);
931  LeafManagerT targetLeafManager(newTree);
932 
933  // extract the existing attribute set
934  const auto& existingAttributeSet = points.tree().cbeginLeaf()->attributeSet();
935 
936  // build a coord -> index map for looking up target leafs by origin and a faster
937  // unordered map for finding the source index from a target index
938 
939  LeafMap targetLeafMap;
940  LeafIndexArray sourceIndices(targetLeafManager.leafCount(),
942 
943  LeafOffsetArray offsetMap(targetLeafManager.leafCount());
944 
945  {
946  LeafMap sourceLeafMap;
947  auto sourceRange = sourceLeafManager.leafRange();
948  for (auto leaf = sourceRange.begin(); leaf; ++leaf) {
949  sourceLeafMap.insert({leaf->origin(), LeafIndex(static_cast<LeafIndex>(leaf.pos()))});
950  }
951  auto targetRange = targetLeafManager.leafRange();
952  for (auto leaf = targetRange.begin(); leaf; ++leaf) {
953  targetLeafMap.insert({leaf->origin(), LeafIndex(static_cast<LeafIndex>(leaf.pos()))});
954  }
955 
956  // acquire registry lock to avoid locking when appending attributes in parallel
957 
959 
960  // perform four independent per-leaf operations in parallel
961  targetLeafManager.foreach(
962  [&](LeafT& leaf, size_t idx) {
963  // map frequency => cumulative histogram
964  auto* buffer = leaf.buffer().data();
965  for (Index i = 1; i < leaf.buffer().size(); i++) {
966  buffer[i] = buffer[i-1] + buffer[i];
967  }
968  // replace attribute set with a copy of the existing one
969  leaf.replaceAttributeSet(
970  new AttributeSet(existingAttributeSet, leaf.getLastValue(), &lock),
971  /*allowMismatchingDescriptors=*/true);
972  // store the index of the source leaf in a corresponding target leaf array
973  const auto it = sourceLeafMap.find(leaf.origin());
974  if (it != sourceLeafMap.end()) {
975  sourceIndices[idx] = it->second;
976  }
977  // allocate offset maps
978  offsetMap[idx].resize(LeafT::SIZE);
979  },
980  threaded);
981  }
982 
983  // moving leaf
984 
985  GlobalPointIndexMap globalMoveLeafMap(targetLeafManager.leafCount());
986  LocalPointIndexMap localMoveLeafMap(targetLeafManager.leafCount());
987 
988  // build global and local move leaf maps and update local positions
989 
990  if (filter.state() == index::ALL) {
991  NullFilter nullFilter;
992  BuildMoveMapsOp<DeformerT, PointDataTreeT, NullFilter> op(deformer,
993  globalMoveLeafMap, localMoveLeafMap, targetLeafMap,
994  transform, points.transform(), nullFilter);
995  sourceLeafManager.foreach(op, threaded);
996  } else {
997  BuildMoveMapsOp<DeformerT, PointDataTreeT, FilterT> op(deformer,
998  globalMoveLeafMap, localMoveLeafMap, targetLeafMap,
999  transform, points.transform(), filter);
1000  sourceLeafManager.foreach(op, threaded);
1001  }
1002 
1003  // build a sorted index vector for each leaf that references the global move map
1004  // indices in order of their source leafs and voxels to ensure determinism in the
1005  // resulting point orders
1006 
1007  GlobalPointIndexIndices globalMoveLeafIndices(globalMoveLeafMap.size());
1008 
1009  targetLeafManager.foreach(
1010  [&](LeafT& /*leaf*/, size_t idx) {
1011  const IndexTripleArray& moveIndices = globalMoveLeafMap[idx];
1012  if (moveIndices.empty()) return;
1013 
1014  IndexArray& sortedIndices = globalMoveLeafIndices[idx];
1015  sortedIndices.resize(moveIndices.size());
1016  std::iota(std::begin(sortedIndices), std::end(sortedIndices), 0);
1017  std::sort(std::begin(sortedIndices), std::end(sortedIndices),
1018  [&](int i, int j)
1019  {
1020  const Index& indexI0(std::get<0>(moveIndices[i]));
1021  const Index& indexJ0(std::get<0>(moveIndices[j]));
1022  if (indexI0 < indexJ0) return true;
1023  if (indexI0 > indexJ0) return false;
1024  return std::get<2>(moveIndices[i]) < std::get<2>(moveIndices[j]);
1025  }
1026  );
1027  },
1028  threaded);
1029 
1030 #if OPENVDB_ABI_VERSION_NUMBER < 6
1031  // initialize attribute handles
1032  AttributeHandles sourceHandles(sourceLeafManager.leafCount());
1033  AttributeHandles targetHandles(targetLeafManager.leafCount());
1034 #endif
1035 
1036  for (const auto& it : existingAttributeSet.descriptor().map()) {
1037 
1038  const Index attributeIndex = static_cast<Index>(it.second);
1039 
1040  // zero offsets
1041  targetLeafManager.foreach(
1042  [&offsetMap](const LeafT& /*leaf*/, size_t idx) {
1043  std::fill(offsetMap[idx].begin(), offsetMap[idx].end(), 0);
1044  },
1045  threaded);
1046 
1047 #if OPENVDB_ABI_VERSION_NUMBER >= 6
1048 
1049  // move points between leaf nodes
1050 
1051  GlobalMovePointsOp<PointDataTreeT> globalMoveOp(offsetMap,
1052  sourceLeafManager, attributeIndex, globalMoveLeafMap, globalMoveLeafIndices);
1053  targetLeafManager.foreach(globalMoveOp, threaded);
1054 
1055  // move points within leaf nodes
1056 
1057  LocalMovePointsOp<PointDataTreeT> localMoveOp(offsetMap,
1058  sourceIndices, sourceLeafManager, attributeIndex, localMoveLeafMap);
1059  targetLeafManager.foreach(localMoveOp, threaded);
1060 #else
1061  // cache attribute handles
1062 
1063  sourceHandles.cache(sourceLeafManager.leafRange(), attributeIndex);
1064  targetHandles.cache(targetLeafManager.leafRange(), attributeIndex);
1065 
1066  // move points between leaf nodes
1067 
1068  GlobalMovePointsOp<PointDataTreeT> globalMoveOp(offsetMap, targetHandles,
1069  sourceHandles, attributeIndex, globalMoveLeafMap, globalMoveLeafIndices);
1070  targetLeafManager.foreach(globalMoveOp, threaded);
1071 
1072  // move points within leaf nodes
1073 
1074  LocalMovePointsOp<PointDataTreeT> localMoveOp(offsetMap, targetHandles,
1075  sourceIndices, sourceHandles,
1076  attributeIndex, localMoveLeafMap);
1077  targetLeafManager.foreach(localMoveOp, threaded);
1078 #endif // OPENVDB_ABI_VERSION_NUMBER >= 6
1079  }
1080 
1081  points.setTree(newPoints->treePtr());
1082 }
1083 
1084 
1085 template <typename PointDataGridT, typename DeformerT, typename FilterT>
1086 inline void movePoints( PointDataGridT& points,
1087  DeformerT& deformer,
1088  const FilterT& filter,
1089  future::Advect* objectNotInUse,
1090  bool threaded)
1091 {
1092  movePoints(points, points.transform(), deformer, filter, objectNotInUse, threaded);
1093 }
1094 
1095 
1096 ////////////////////////////////////////
1097 
1098 
1099 template <typename T>
1101  : mCache(cache) { }
1102 
1103 
1104 template <typename T>
1105 template <typename PointDataGridT, typename DeformerT, typename FilterT>
1106 void CachedDeformer<T>::evaluate(PointDataGridT& grid, DeformerT& deformer, const FilterT& filter,
1107  bool threaded)
1108 {
1109  using TreeT = typename PointDataGridT::TreeType;
1110  using LeafT = typename TreeT::LeafNodeType;
1111  using LeafManagerT = typename tree::LeafManager<TreeT>;
1112  LeafManagerT leafManager(grid.tree());
1113 
1114  // initialize cache
1115  auto& leafs = mCache.leafs;
1116  leafs.resize(leafManager.leafCount());
1117 
1118  const auto& transform = grid.transform();
1119 
1120  // insert deformed positions into the cache
1121 
1122  auto cachePositionsOp = [&](const LeafT& leaf, size_t idx) {
1123 
1124  const Index64 totalPointCount = leaf.pointCount();
1125  if (totalPointCount == 0) return;
1126 
1127  // deformer is copied to ensure that it is unique per-thread
1128 
1129  DeformerT newDeformer(deformer);
1130 
1131  newDeformer.reset(leaf, idx);
1132 
1133  auto handle = AttributeHandle<Vec3f>::create(leaf.constAttributeArray("P"));
1134 
1135  auto& cache = leafs[idx];
1136  cache.clear();
1137 
1138  // only insert into a vector directly if the filter evaluates all points
1139  // and all points are stored in active voxels
1140  const bool useVector = filter.state() == index::ALL &&
1141  (leaf.isDense() || (leaf.onPointCount() == leaf.pointCount()));
1142  if (useVector) {
1143  cache.vecData.resize(totalPointCount);
1144  }
1145 
1146  for (auto iter = leaf.beginIndexOn(filter); iter; iter++) {
1147 
1148  // extract index-space position and apply index-space deformation (if defined)
1149 
1150  Vec3d position = handle->get(*iter) + iter.getCoord().asVec3d();
1151 
1152  // if deformer is designed to be used in index-space, perform deformation prior
1153  // to transforming position to world-space, otherwise perform deformation afterwards
1154 
1156  newDeformer.apply(position, iter);
1157  position = transform.indexToWorld(position);
1158  }
1159  else {
1160  position = transform.indexToWorld(position);
1161  newDeformer.apply(position, iter);
1162  }
1163 
1164  // insert new position into the cache
1165 
1166  if (useVector) {
1167  cache.vecData[*iter] = static_cast<Vec3T>(position);
1168  }
1169  else {
1170  cache.mapData.insert({*iter, static_cast<Vec3T>(position)});
1171  }
1172  }
1173 
1174  // store the total number of points to allow use of an expanded vector on access
1175 
1176  if (!cache.mapData.empty()) {
1177  cache.totalSize = static_cast<Index>(totalPointCount);
1178  }
1179  };
1180 
1181  leafManager.foreach(cachePositionsOp, threaded);
1182 }
1183 
1184 
1185 template <typename T>
1186 template <typename LeafT>
1187 void CachedDeformer<T>::reset(const LeafT& /*leaf*/, size_t idx)
1188 {
1189  if (idx >= mCache.leafs.size()) {
1190  if (mCache.leafs.empty()) {
1191  throw IndexError("No leafs in cache, perhaps CachedDeformer has not been evaluated?");
1192  } else {
1193  throw IndexError("Leaf index is out-of-range of cache leafs.");
1194  }
1195  }
1196  auto& cache = mCache.leafs[idx];
1197  if (!cache.mapData.empty()) {
1198  mLeafMap = &cache.mapData;
1199  mLeafVec = nullptr;
1200  }
1201  else {
1202  mLeafVec = &cache.vecData;
1203  mLeafMap = nullptr;
1204  }
1205 }
1206 
1207 
1208 template <typename T>
1209 template <typename IndexIterT>
1210 void CachedDeformer<T>::apply(Vec3d& position, const IndexIterT& iter) const
1211 {
1212  assert(*iter >= 0);
1213 
1214  if (mLeafMap) {
1215  auto it = mLeafMap->find(*iter);
1216  if (it == mLeafMap->end()) return;
1217  position = static_cast<openvdb::Vec3d>(it->second);
1218  }
1219  else {
1220  assert(mLeafVec);
1221 
1222  if (mLeafVec->empty()) return;
1223  assert(*iter < mLeafVec->size());
1224  position = static_cast<openvdb::Vec3d>((*mLeafVec)[*iter]);
1225  }
1226 }
1227 
1228 
1229 } // namespace points
1230 } // namespace OPENVDB_VERSION_NAME
1231 } // namespace openvdb
1232 
1233 #endif // OPENVDB_POINTS_POINT_MOVE_HAS_BEEN_INCLUDED
vint4 max(const vint4 &a, const vint4 &b)
Definition: simd.h:4703
GLenum GLint * range
Definition: glew.h:3500
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: PointMove.h:1086
GLsizeiptr size
Definition: glew.h:1681
Vec3d indexToWorld(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:108
void cache(const LeafRangeT &range, const Index attributeIndex)
Definition: PointMove.h:631
Helper class used internally by processTypedArray()
Definition: PointMove.h:537
FMT_CONSTEXPR auto begin(const C &c) -> decltype(c.begin())
Definition: format.h:251
GLuint GLenum GLenum transform
Definition: glew.h:14742
GLuint index
Definition: glew.h:1814
ImageBuf OIIO_API fill(cspan< float > values, ROI roi, int nthreads=0)
GLuint GLsizei const GLuint const GLintptr * offsets
Definition: glew.h:4117
std::unordered_map< LeafIndex, Vec3T > LeafMapT
Definition: PointMove.h:104
const GLint * first
Definition: glew.h:1528
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:166
AttributeHandle< ValueT > & getHandle(const Index leafOffset)
Definition: PointMove.h:597
void apply(Vec3d &position, const IndexIterT &iter) const
Retrieve the new position from the cache.
Definition: PointMove.h:1210
GLboolean reset
Definition: glew.h:4959
GlobalMovePointsOp(LeafOffsetArray &offsetMap, AttributeHandles &targetHandles, AttributeHandles &sourceHandles, const Index attributeIndex, const GlobalPointIndexMap &moveLeafMap, const GlobalPointIndexIndices &moveLeafIndices)
Definition: PointMove.h:656
A no-op filter that can be used when iterating over all indices.
Definition: IndexIterator.h:50
std::tuple< LeafIndex, Index, Index > IndexTriple
Definition: PointMove.h:163
static Ptr create(AttributeArray &array, const bool expand=true)
Cache read and write attribute handles to amortize construction cost.
Definition: PointMove.h:575
LocalMovePointsOp(LeafOffsetArray &offsetMap, AttributeHandles &targetHandles, const LeafIndexArray &sourceIndices, AttributeHandles &sourceHandles, const Index attributeIndex, const LocalPointIndexMap &moveLeafMap)
Definition: PointMove.h:767
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glew.h:2981
Base class for storing attribute data.
void performTypedMove(Index sourceOffset, Index targetOffset, const LeafT &targetLeaf, IndexArray &offsets, const IndexPairArray &indices) const
Definition: PointMove.h:821
void reset(const LeafT &leaf, size_t idx)
Definition: PointMove.h:1187
CachedDeformer(Cache &cache)
Cache is expected to be persistent for the lifetime of the CachedDeformer.
Definition: PointMove.h:1100
tbb::concurrent_vector< IndexTriple > IndexTripleArray
Definition: PointMove.h:164
Index indexOffsetFromVoxel(const Index voxelOffset, const LeafT &leaf, IndexArray &offsets)
Definition: PointMove.h:272
void clear()
clear data buffers and reset counter
Definition: PointMove.h:112
A Deformer that caches the resulting positions from evaluating another Deformer.
Definition: PointMove.h:98
GLuint buffer
Definition: glew.h:1680
Deformer Traits for optionally configuring deformers to be applied in index-space. The default is world-space.
Definition: PointMask.h:76
GLuint GLuint GLsizei GLenum const void * indices
Definition: glew.h:1253
GLuint GLuint end
Definition: glew.h:1253
void
Definition: png.h:1083
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:82
void evaluate(PointDataGridT &grid, DeformerT &deformer, const FilterT &filter, bool threaded=true)
Definition: PointMove.h:1106
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:548
void performMove(Index targetOffset, const LeafT &targetLeaf, IndexArray &offsets, const IndexTripleArray &indices, const IndexArray &sortedIndices) const
Definition: PointMove.h:710
std::unordered_map< Coord, LeafIndex > LeafMap
Definition: PointMove.h:174
Create a handle and reinterpret cast as an int handle to store.
Definition: PointMove.h:613
vfloat4 round(const vfloat4 &a)
Definition: simd.h:7186
AttributeWriteHandle< ValueT > & getWriteHandle(const Index leafOffset)
Definition: PointMove.h:605
std::vector< IndexTripleArray > GlobalPointIndexMap
Definition: PointMove.h:165
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:184
void performMove(Index targetOffset, Index sourceOffset, const LeafT &targetLeaf, IndexArray &offsets, const IndexPairArray &indices) const
Definition: PointMove.h:838
static Ptr create(const AttributeArray &array, const bool collapseOnDestruction=true)
static void call(OpType &op, const AttributeArray &array)
Definition: PointMove.h:538
const AttributeArray & getConstArray(const Index leafOffset) const
Definition: PointMove.h:589
PerformTypedMoveOp(AttributeHandles &targetHandles, AttributeHandles &sourceHandles, Index targetOffset, Index sourceOffset, const LeafT &targetLeaf, IndexArray &offsets, const IndexPairArray &indices)
Definition: PointMove.h:782
GLuint GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glew.h:3446
Methods for extracting masks from VDB Point grids.
Ordered collection of uniquely-named attribute arrays.
Definition: AttributeSet.h:38
PerformTypedMoveOp(AttributeHandles &targetHandles, AttributeHandles &sourceHandles, Index targetOffset, const LeafT &targetLeaf, IndexArray &offsets, const IndexTripleArray &indices, const IndexArray &sortedIndices)
Definition: PointMove.h:671
#define SIZE
Definition: simple.C:40
GLenum array
Definition: glew.h:9066
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:112
void sort(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7334
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
Base class for tree-traversal iterators over all leaf nodes (but not leaf voxels) ...