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