OpenVDB  7.0.0
PointConversion.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
9 
10 #ifndef OPENVDB_POINTS_POINT_CONVERSION_HAS_BEEN_INCLUDED
11 #define OPENVDB_POINTS_POINT_CONVERSION_HAS_BEEN_INCLUDED
12 
13 #include <openvdb/math/Transform.h>
14 
18 
19 #include "AttributeArrayString.h"
20 #include "AttributeSet.h"
21 #include "IndexFilter.h"
22 #include "PointAttribute.h"
23 #include "PointDataGrid.h"
24 #include "PointGroup.h"
25 
26 #include <tbb/parallel_reduce.h>
27 
28 #include <type_traits>
29 
30 namespace openvdb {
32 namespace OPENVDB_VERSION_NAME {
33 namespace points {
34 
35 
52 
53 template<
54  typename CompressionT,
55  typename PointDataGridT,
56  typename PositionArrayT,
57  typename PointIndexGridT>
58 inline typename PointDataGridT::Ptr
59 createPointDataGrid(const PointIndexGridT& pointIndexGrid,
60  const PositionArrayT& positions,
61  const math::Transform& xform,
62  Metadata::Ptr positionDefaultValue = Metadata::Ptr());
63 
64 
74 
75 template <typename CompressionT, typename PointDataGridT, typename ValueT>
76 inline typename PointDataGridT::Ptr
77 createPointDataGrid(const std::vector<ValueT>& positions,
78  const math::Transform& xform,
79  Metadata::Ptr positionDefaultValue = Metadata::Ptr());
80 
81 
93 template <typename PointDataTreeT, typename PointIndexTreeT, typename PointArrayT>
94 inline void
95 populateAttribute( PointDataTreeT& tree,
96  const PointIndexTreeT& pointIndexTree,
97  const openvdb::Name& attributeName,
98  const PointArrayT& data,
99  const Index stride = 1,
100  const bool insertMetadata = true);
101 
111 
112 template <typename PositionAttribute, typename PointDataGridT, typename FilterT = NullFilter>
113 inline void
114 convertPointDataGridPosition( PositionAttribute& positionAttribute,
115  const PointDataGridT& grid,
116  const std::vector<Index64>& pointOffsets,
117  const Index64 startOffset,
118  const FilterT& filter = NullFilter(),
119  const bool inCoreOnly = false);
120 
121 
132 template <typename TypedAttribute, typename PointDataTreeT, typename FilterT = NullFilter>
133 inline void
134 convertPointDataGridAttribute( TypedAttribute& attribute,
135  const PointDataTreeT& tree,
136  const std::vector<Index64>& pointOffsets,
137  const Index64 startOffset,
138  const unsigned arrayIndex,
139  const Index stride = 1,
140  const FilterT& filter = NullFilter(),
141  const bool inCoreOnly = false);
142 
143 
154 
155 template <typename Group, typename PointDataTreeT, typename FilterT = NullFilter>
156 inline void
157 convertPointDataGridGroup( Group& group,
158  const PointDataTreeT& tree,
159  const std::vector<Index64>& pointOffsets,
160  const Index64 startOffset,
161  const AttributeSet::Descriptor::GroupIndex index,
162  const FilterT& filter = NullFilter(),
163  const bool inCoreOnly = false);
164 
177 template<typename PositionWrapper, typename InterrupterT = openvdb::util::NullInterrupter>
178 inline float
179 computeVoxelSize( const PositionWrapper& positions,
180  const uint32_t pointsPerVoxel,
181  const math::Mat4d transform = math::Mat4d::identity(),
182  const Index decimalPlaces = 5,
183  InterrupterT* const interrupter = nullptr);
184 
185 
187 
188 
190 template<typename ValueType>
192 public:
193  using PosType = ValueType;
194  using value_type= ValueType;
195 
196  PointAttributeVector(const std::vector<value_type>& data,
197  const Index stride = 1)
198  : mData(data)
199  , mStride(stride) { }
200 
201  size_t size() const { return mData.size(); }
202  void getPos(size_t n, ValueType& xyz) const { xyz = mData[n]; }
203  void get(ValueType& value, size_t n) const { value = mData[n]; }
204  void get(ValueType& value, size_t n, openvdb::Index m) const { value = mData[n * mStride + m]; }
205 
206 private:
207  const std::vector<value_type>& mData;
208  const Index mStride;
209 }; // PointAttributeVector
210 
211 
213 
214 
215 namespace point_conversion_internal {
216 
217 
218 // ConversionTraits to create the relevant Attribute Handles from a LeafNode
219 template <typename T> struct ConversionTraits
220 {
223  static T zero() { return zeroVal<T>(); }
224  template <typename LeafT>
225  static typename Handle::Ptr handleFromLeaf(LeafT& leaf, Index index) {
226  const AttributeArray& array = leaf.constAttributeArray(index);
227  return Handle::create(array);
228  }
229  template <typename LeafT>
230  static typename WriteHandle::Ptr writeHandleFromLeaf(LeafT& leaf, Index index) {
231  AttributeArray& array = leaf.attributeArray(index);
232  return WriteHandle::create(array);
233  }
234 }; // ConversionTraits
235 template <> struct ConversionTraits<openvdb::Name>
236 {
239  static openvdb::Name zero() { return ""; }
240  template <typename LeafT>
241  static typename Handle::Ptr handleFromLeaf(LeafT& leaf, Index index) {
242  const AttributeArray& array = leaf.constAttributeArray(index);
243  const AttributeSet::Descriptor& descriptor = leaf.attributeSet().descriptor();
244  return Handle::create(array, descriptor.getMetadata());
245  }
246  template <typename LeafT>
247  static typename WriteHandle::Ptr writeHandleFromLeaf(LeafT& leaf, Index index) {
248  AttributeArray& array = leaf.attributeArray(index);
249  const AttributeSet::Descriptor& descriptor = leaf.attributeSet().descriptor();
250  return WriteHandle::create(array, descriptor.getMetadata());
251  }
252 }; // ConversionTraits<openvdb::Name>
253 
254 template< typename PointDataTreeType,
255  typename PointIndexTreeType,
256  typename AttributeListType>
258 
260  using LeafRangeT = typename LeafManagerT::LeafRange;
261  using PointIndexLeafNode = typename PointIndexTreeType::LeafNodeType;
263  using ValueType = typename AttributeListType::value_type;
265 
266  PopulateAttributeOp(const PointIndexTreeType& pointIndexTree,
267  const AttributeListType& data,
268  const size_t index,
269  const Index stride = 1)
270  : mPointIndexTree(pointIndexTree)
271  , mData(data)
272  , mIndex(index)
273  , mStride(stride) { }
274 
275  void operator()(const typename LeafManagerT::LeafRange& range) const {
276 
277  for (auto leaf = range.begin(); leaf; ++leaf) {
278 
279  // obtain the PointIndexLeafNode (using the origin of the current leaf)
280 
281  const PointIndexLeafNode* pointIndexLeaf =
282  mPointIndexTree.probeConstLeaf(leaf->origin());
283 
284  if (!pointIndexLeaf) continue;
285 
286  typename HandleT::Ptr attributeWriteHandle =
287  ConversionTraits<ValueType>::writeHandleFromLeaf(*leaf, static_cast<Index>(mIndex));
288 
289  Index64 index = 0;
290 
291  const IndexArray& indices = pointIndexLeaf->indices();
292 
293  for (const Index64 leafIndex: indices)
294  {
295  ValueType value;
296  for (Index i = 0; i < mStride; i++) {
297  mData.get(value, leafIndex, i);
298  attributeWriteHandle->set(static_cast<Index>(index), i, value);
299  }
300  index++;
301  }
302 
303  // attempt to compact the array
304 
305  attributeWriteHandle->compact();
306  }
307  }
308 
310 
311  const PointIndexTreeType& mPointIndexTree;
312  const AttributeListType& mData;
313  const size_t mIndex;
314  const Index mStride;
315 };
316 
317 template<typename PointDataTreeType, typename Attribute, typename FilterT>
319 
320  using LeafNode = typename PointDataTreeType::LeafNodeType;
321  using ValueType = typename Attribute::ValueType;
322  using HandleT = typename Attribute::Handle;
325  using LeafRangeT = typename LeafManagerT::LeafRange;
326 
327  ConvertPointDataGridPositionOp( Attribute& attribute,
328  const std::vector<Index64>& pointOffsets,
329  const Index64 startOffset,
330  const math::Transform& transform,
331  const size_t index,
332  const FilterT& filter,
333  const bool inCoreOnly)
334  : mAttribute(attribute)
335  , mPointOffsets(pointOffsets)
336  , mStartOffset(startOffset)
337  , mTransform(transform)
338  , mIndex(index)
339  , mFilter(filter)
340  , mInCoreOnly(inCoreOnly)
341  {
342  // only accept Vec3f as ValueType
343  static_assert(VecTraits<ValueType>::Size == 3 &&
344  std::is_floating_point<typename ValueType::ValueType>::value,
345  "ValueType is not Vec3f");
346  }
347 
348  template <typename IterT>
349  void convert(IterT& iter, HandleT& targetHandle,
350  SourceHandleT& sourceHandle, Index64& offset) const
351  {
352  for (; iter; ++iter) {
353  const Vec3d xyz = iter.getCoord().asVec3d();
354  const Vec3d pos = sourceHandle.get(*iter);
355  targetHandle.set(static_cast<Index>(offset++), /*stride=*/0,
356  mTransform.indexToWorld(pos + xyz));
357  }
358  }
359 
360  void operator()(const LeafRangeT& range) const
361  {
362  HandleT pHandle(mAttribute);
363 
364  for (auto leaf = range.begin(); leaf; ++leaf) {
365 
366  assert(leaf.pos() < mPointOffsets.size());
367 
368  if (mInCoreOnly && leaf->buffer().isOutOfCore()) continue;
369 
370  Index64 offset = mStartOffset;
371 
372  if (leaf.pos() > 0) offset += mPointOffsets[leaf.pos() - 1];
373 
374  auto handle = SourceHandleT::create(leaf->constAttributeArray(mIndex));
375 
376  if (mFilter.state() == index::ALL) {
377  auto iter = leaf->beginIndexOn();
378  convert(iter, pHandle, *handle, offset);
379  }
380  else {
381  auto iter = leaf->beginIndexOn(mFilter);
382  convert(iter, pHandle, *handle, offset);
383  }
384  }
385  }
386 
388 
389  Attribute& mAttribute;
390  const std::vector<Index64>& mPointOffsets;
393  const size_t mIndex;
394  const FilterT& mFilter;
395  const bool mInCoreOnly;
396 }; // ConvertPointDataGridPositionOp
397 
398 
399 template<typename PointDataTreeType, typename Attribute, typename FilterT>
401 
402  using LeafNode = typename PointDataTreeType::LeafNodeType;
403  using ValueType = typename Attribute::ValueType;
404  using HandleT = typename Attribute::Handle;
407  using LeafRangeT = typename LeafManagerT::LeafRange;
408 
409  ConvertPointDataGridAttributeOp(Attribute& attribute,
410  const std::vector<Index64>& pointOffsets,
411  const Index64 startOffset,
412  const size_t index,
413  const Index stride,
414  const FilterT& filter,
415  const bool inCoreOnly)
416  : mAttribute(attribute)
417  , mPointOffsets(pointOffsets)
418  , mStartOffset(startOffset)
419  , mIndex(index)
420  , mStride(stride)
421  , mFilter(filter)
422  , mInCoreOnly(inCoreOnly) { }
423 
424  template <typename IterT>
425  void convert(IterT& iter, HandleT& targetHandle,
426  SourceHandleT& sourceHandle, Index64& offset) const
427  {
428  if (sourceHandle.isUniform()) {
429  const ValueType uniformValue(sourceHandle.get(0));
430  for (; iter; ++iter) {
431  for (Index i = 0; i < mStride; i++) {
432  targetHandle.set(static_cast<Index>(offset), i, uniformValue);
433  }
434  offset++;
435  }
436  }
437  else {
438  for (; iter; ++iter) {
439  for (Index i = 0; i < mStride; i++) {
440  targetHandle.set(static_cast<Index>(offset), i,
441  sourceHandle.get(*iter, /*stride=*/i));
442  }
443  offset++;
444  }
445  }
446  }
447 
448  void operator()(const LeafRangeT& range) const
449  {
450  HandleT pHandle(mAttribute);
451 
452  for (auto leaf = range.begin(); leaf; ++leaf) {
453 
454  assert(leaf.pos() < mPointOffsets.size());
455 
456  if (mInCoreOnly && leaf->buffer().isOutOfCore()) continue;
457 
458  Index64 offset = mStartOffset;
459 
460  if (leaf.pos() > 0) offset += mPointOffsets[leaf.pos() - 1];
461 
462  typename SourceHandleT::Ptr handle = ConversionTraits<ValueType>::handleFromLeaf(
463  *leaf, static_cast<Index>(mIndex));
464 
465  if (mFilter.state() == index::ALL) {
466  auto iter = leaf->beginIndexOn();
467  convert(iter, pHandle, *handle, offset);
468  } else {
469  auto iter = leaf->beginIndexOn(mFilter);
470  convert(iter, pHandle, *handle, offset);
471  }
472  }
473  }
474 
476 
477  Attribute& mAttribute;
478  const std::vector<Index64>& mPointOffsets;
480  const size_t mIndex;
481  const Index mStride;
482  const FilterT& mFilter;
483  const bool mInCoreOnly;
484 }; // ConvertPointDataGridAttributeOp
485 
486 template<typename PointDataTreeType, typename Group, typename FilterT>
488 
489  using LeafNode = typename PointDataTreeType::LeafNodeType;
490  using GroupIndex = AttributeSet::Descriptor::GroupIndex;
492  using LeafRangeT = typename LeafManagerT::LeafRange;
493 
495  const std::vector<Index64>& pointOffsets,
496  const Index64 startOffset,
497  const AttributeSet::Descriptor::GroupIndex index,
498  const FilterT& filter,
499  const bool inCoreOnly)
500  : mGroup(group)
501  , mPointOffsets(pointOffsets)
502  , mStartOffset(startOffset)
503  , mIndex(index)
504  , mFilter(filter)
505  , mInCoreOnly(inCoreOnly) { }
506 
507  template <typename IterT>
508  void convert(IterT& iter, const GroupAttributeArray& groupArray, Index64& offset) const
509  {
510  const auto bitmask = static_cast<GroupType>(1 << mIndex.second);
511 
512  if (groupArray.isUniform()) {
513  if (groupArray.get(0) & bitmask) {
514  for (; iter; ++iter) {
515  mGroup.setOffsetOn(static_cast<Index>(offset));
516  offset++;
517  }
518  }
519  }
520  else {
521  for (; iter; ++iter) {
522  if (groupArray.get(*iter) & bitmask) {
523  mGroup.setOffsetOn(static_cast<Index>(offset));
524  }
525  offset++;
526  }
527  }
528  }
529 
530  void operator()(const LeafRangeT& range) const
531  {
532  for (auto leaf = range.begin(); leaf; ++leaf) {
533 
534  assert(leaf.pos() < mPointOffsets.size());
535 
536  if (mInCoreOnly && leaf->buffer().isOutOfCore()) continue;
537 
538  Index64 offset = mStartOffset;
539 
540  if (leaf.pos() > 0) offset += mPointOffsets[leaf.pos() - 1];
541 
542  const AttributeArray& array = leaf->constAttributeArray(mIndex.first);
543  assert(isGroup(array));
544  const GroupAttributeArray& groupArray = GroupAttributeArray::cast(array);
545 
546  if (mFilter.state() == index::ALL) {
547  auto iter = leaf->beginIndexOn();
548  convert(iter, groupArray, offset);
549  }
550  else {
551  auto iter = leaf->beginIndexOn(mFilter);
552  convert(iter, groupArray, offset);
553  }
554  }
555  }
556 
558 
559  Group& mGroup;
560  const std::vector<Index64>& mPointOffsets;
563  const FilterT& mFilter;
564  const bool mInCoreOnly;
565 }; // ConvertPointDataGridGroupOp
566 
567 template<typename PositionArrayT>
569 {
570  CalculatePositionBounds(const PositionArrayT& positions,
571  const math::Mat4d& inverse)
572  : mPositions(positions)
573  , mInverseMat(inverse)
574  , mMin(std::numeric_limits<Real>::max())
575  , mMax(-std::numeric_limits<Real>::max()) {}
576 
578  : mPositions(other.mPositions)
579  , mInverseMat(other.mInverseMat)
580  , mMin(std::numeric_limits<Real>::max())
581  , mMax(-std::numeric_limits<Real>::max()) {}
582 
583  void operator()(const tbb::blocked_range<size_t>& range) {
584  Vec3R pos;
585  for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
586  mPositions.getPos(n, pos);
587  pos = mInverseMat.transform(pos);
588  mMin = math::minComponent(mMin, pos);
589  mMax = math::maxComponent(mMax, pos);
590  }
591  }
592 
593  void join(const CalculatePositionBounds& other) {
594  mMin = math::minComponent(mMin, other.mMin);
595  mMax = math::maxComponent(mMax, other.mMax);
596  }
597 
599  return BBoxd(mMin, mMax);
600  }
601 
602 private:
603  const PositionArrayT& mPositions;
604  const math::Mat4d& mInverseMat;
605  Vec3R mMin, mMax;
606 };
607 
608 } // namespace point_conversion_internal
609 
610 
612 
613 
614 template<typename CompressionT, typename PointDataGridT, typename PositionArrayT, typename PointIndexGridT>
615 inline typename PointDataGridT::Ptr
616 createPointDataGrid(const PointIndexGridT& pointIndexGrid, const PositionArrayT& positions,
617  const math::Transform& xform, Metadata::Ptr positionDefaultValue)
618 {
619  using PointDataTreeT = typename PointDataGridT::TreeType;
620  using LeafT = typename PointDataTree::LeafNodeType;
621  using PointIndexLeafT = typename PointIndexGridT::TreeType::LeafNodeType;
622  using PointIndexT = typename PointIndexLeafT::ValueType;
623  using LeafManagerT = typename tree::LeafManager<PointDataTreeT>;
624  using PositionAttributeT = TypedAttributeArray<Vec3f, CompressionT>;
625 
626  const NamePair positionType = PositionAttributeT::attributeType();
627 
628  // construct the Tree using a topology copy of the PointIndexGrid
629 
630  const auto& pointIndexTree = pointIndexGrid.tree();
631  typename PointDataTreeT::Ptr treePtr(new PointDataTreeT(pointIndexTree));
632 
633  // create attribute descriptor from position type
634 
635  auto descriptor = AttributeSet::Descriptor::create(positionType);
636 
637  // add default value for position if provided
638 
639  if (positionDefaultValue) descriptor->setDefaultValue("P", *positionDefaultValue);
640 
641  // retrieve position index
642 
643  const size_t positionIndex = descriptor->find("P");
644  assert(positionIndex != AttributeSet::INVALID_POS);
645 
646  // acquire registry lock to avoid locking when appending attributes in parallel
647 
649 
650  // populate position attribute
651 
652  LeafManagerT leafManager(*treePtr);
653  leafManager.foreach(
654  [&](LeafT& leaf, size_t /*idx*/) {
655 
656  // obtain the PointIndexLeafNode (using the origin of the current leaf)
657 
658  const auto* pointIndexLeaf = pointIndexTree.probeConstLeaf(leaf.origin());
659  assert(pointIndexLeaf);
660 
661  // initialise the attribute storage
662 
663  Index pointCount(static_cast<Index>(pointIndexLeaf->indices().size()));
664  leaf.initializeAttributes(descriptor, pointCount, &lock);
665 
666  // create write handle for position
667 
668  auto attributeWriteHandle = AttributeWriteHandle<Vec3f, CompressionT>::create(
669  leaf.attributeArray(positionIndex));
670 
671  Index index = 0;
672 
673  const PointIndexT
674  *begin = static_cast<PointIndexT*>(nullptr),
675  *end = static_cast<PointIndexT*>(nullptr);
676 
677  // iterator over every active voxel in the point index leaf
678 
679  for (auto iter = pointIndexLeaf->cbeginValueOn(); iter; ++iter) {
680 
681  // find the voxel center
682 
683  const Coord& ijk = iter.getCoord();
684  const Vec3d& positionCellCenter(ijk.asVec3d());
685 
686  // obtain pointers for this voxel from begin to end in the indices array
687 
688  pointIndexLeaf->getIndices(ijk, begin, end);
689 
690  while (begin < end) {
691 
692  typename PositionArrayT::value_type positionWorldSpace;
693  positions.getPos(*begin, positionWorldSpace);
694 
695  // compute the index-space position and then subtract the voxel center
696 
697  const Vec3d positionIndexSpace = xform.worldToIndex(positionWorldSpace);
698  const Vec3f positionVoxelSpace(positionIndexSpace - positionCellCenter);
699 
700  attributeWriteHandle->set(index++, positionVoxelSpace);
701 
702  ++begin;
703  }
704  }
705  },
706  /*threaded=*/true);
707 
708  auto grid = PointDataGridT::create(treePtr);
709  grid->setTransform(xform.copy());
710  return grid;
711 }
712 
713 
715 
716 
717 template <typename CompressionT, typename PointDataGridT, typename ValueT>
718 inline typename PointDataGridT::Ptr
719 createPointDataGrid(const std::vector<ValueT>& positions,
720  const math::Transform& xform,
721  Metadata::Ptr positionDefaultValue)
722 {
723  const PointAttributeVector<ValueT> pointList(positions);
724 
725  tools::PointIndexGrid::Ptr pointIndexGrid = tools::createPointIndexGrid<tools::PointIndexGrid>(pointList, xform);
726  return createPointDataGrid<CompressionT, PointDataGridT>(*pointIndexGrid, pointList, xform, positionDefaultValue);
727 }
728 
729 
731 
732 
733 template <typename PointDataTreeT, typename PointIndexTreeT, typename PointArrayT>
734 inline void
735 populateAttribute(PointDataTreeT& tree, const PointIndexTreeT& pointIndexTree,
736  const openvdb::Name& attributeName, const PointArrayT& data, const Index stride,
737  const bool insertMetadata)
738 {
740  using ValueType = typename PointArrayT::value_type;
741 
742  auto iter = tree.cbeginLeaf();
743 
744  if (!iter) return;
745 
746  const size_t index = iter->attributeSet().find(attributeName);
747 
748  if (index == AttributeSet::INVALID_POS) {
749  OPENVDB_THROW(KeyError, "Attribute not found to populate - " << attributeName << ".");
750  }
751 
752  if (insertMetadata) {
754  }
755 
756  // populate attribute
757 
758  typename tree::LeafManager<PointDataTreeT> leafManager(tree);
759 
760  PopulateAttributeOp<PointDataTreeT,
761  PointIndexTreeT,
762  PointArrayT> populate(pointIndexTree, data, index, stride);
763  tbb::parallel_for(leafManager.leafRange(), populate);
764 }
765 
766 
768 
769 
770 template <typename PositionAttribute, typename PointDataGridT, typename FilterT>
771 inline void
772 convertPointDataGridPosition( PositionAttribute& positionAttribute,
773  const PointDataGridT& grid,
774  const std::vector<Index64>& pointOffsets,
775  const Index64 startOffset,
776  const FilterT& filter,
777  const bool inCoreOnly)
778 {
779  using TreeType = typename PointDataGridT::TreeType;
780  using LeafManagerT = typename tree::LeafManager<const TreeType>;
781 
783 
784  const TreeType& tree = grid.tree();
785  auto iter = tree.cbeginLeaf();
786 
787  if (!iter) return;
788 
789  const size_t positionIndex = iter->attributeSet().find("P");
790 
791  positionAttribute.expand();
792  LeafManagerT leafManager(tree);
793  ConvertPointDataGridPositionOp<TreeType, PositionAttribute, FilterT> convert(
794  positionAttribute, pointOffsets, startOffset, grid.transform(), positionIndex,
795  filter, inCoreOnly);
796  tbb::parallel_for(leafManager.leafRange(), convert);
797  positionAttribute.compact();
798 }
799 
800 
802 
803 
804 template <typename TypedAttribute, typename PointDataTreeT, typename FilterT>
805 inline void
806 convertPointDataGridAttribute( TypedAttribute& attribute,
807  const PointDataTreeT& tree,
808  const std::vector<Index64>& pointOffsets,
809  const Index64 startOffset,
810  const unsigned arrayIndex,
811  const Index stride,
812  const FilterT& filter,
813  const bool inCoreOnly)
814 {
815  using LeafManagerT = typename tree::LeafManager<const PointDataTreeT>;
816 
818 
819  auto iter = tree.cbeginLeaf();
820 
821  if (!iter) return;
822 
823  attribute.expand();
824  LeafManagerT leafManager(tree);
825  ConvertPointDataGridAttributeOp<PointDataTreeT, TypedAttribute, FilterT> convert(
826  attribute, pointOffsets, startOffset, arrayIndex, stride,
827  filter, inCoreOnly);
828  tbb::parallel_for(leafManager.leafRange(), convert);
829  attribute.compact();
830 }
831 
832 
834 
835 
836 template <typename Group, typename PointDataTreeT, typename FilterT>
837 inline void
839  const PointDataTreeT& tree,
840  const std::vector<Index64>& pointOffsets,
841  const Index64 startOffset,
842  const AttributeSet::Descriptor::GroupIndex index,
843  const FilterT& filter,
844  const bool inCoreOnly)
845 {
846  using LeafManagerT= typename tree::LeafManager<const PointDataTreeT>;
847 
849 
850  auto iter = tree.cbeginLeaf();
851  if (!iter) return;
852 
853  LeafManagerT leafManager(tree);
854  ConvertPointDataGridGroupOp<PointDataTree, Group, FilterT> convert(
855  group, pointOffsets, startOffset, index,
856  filter, inCoreOnly);
857  tbb::parallel_for(leafManager.leafRange(), convert);
858 
859  // must call this after modifying point groups in parallel
860 
861  group.finalize();
862 }
863 
864 template<typename PositionWrapper, typename InterrupterT>
865 inline float
866 computeVoxelSize( const PositionWrapper& positions,
867  const uint32_t pointsPerVoxel,
868  const math::Mat4d transform,
869  const Index decimalPlaces,
870  InterrupterT* const interrupter)
871 {
872  using namespace point_conversion_internal;
873 
874  struct Local {
875 
876  static bool voxelSizeFromVolume(const double volume,
877  const size_t estimatedVoxelCount,
878  float& voxelSize)
879  {
880  // dictated by the math::ScaleMap limit
881  static const double minimumVoxelVolume(3e-15);
882  static const double maximumVoxelVolume(std::numeric_limits<float>::max());
883 
884  double voxelVolume = volume / static_cast<double>(estimatedVoxelCount);
885  bool valid = true;
886 
887  if (voxelVolume < minimumVoxelVolume) {
888  voxelVolume = minimumVoxelVolume;
889  valid = false;
890  }
891  else if (voxelVolume > maximumVoxelVolume) {
892  voxelVolume = maximumVoxelVolume;
893  valid = false;
894  }
895 
896  voxelSize = static_cast<float>(math::Pow(voxelVolume, 1.0/3.0));
897  return valid;
898  }
899 
900  static float truncate(const float voxelSize, Index decPlaces)
901  {
902  float truncatedVoxelSize = voxelSize;
903 
904  // attempt to truncate from decPlaces -> 11
905  for (int i = decPlaces; i < 11; i++) {
906  truncatedVoxelSize = static_cast<float>(math::Truncate(double(voxelSize), i));
907  if (truncatedVoxelSize != 0.0f) break;
908  }
909 
910  return truncatedVoxelSize;
911  }
912  };
913 
914  if (pointsPerVoxel == 0) OPENVDB_THROW(ValueError, "Points per voxel cannot be zero.");
915 
916  // constructed with the default voxel size as specified by openvdb interface values
917 
918  float voxelSize(0.1f);
919 
920  const size_t numPoints = positions.size();
921 
922  // return the default voxel size if we have zero or only 1 point
923 
924  if (numPoints <= 1) return voxelSize;
925 
926  size_t targetVoxelCount(numPoints / size_t(pointsPerVoxel));
927  if (targetVoxelCount == 0) targetVoxelCount++;
928 
929  // calculate the world space, transform-oriented bounding box
930 
931  math::Mat4d inverseTransform = transform.inverse();
932  inverseTransform = math::unit(inverseTransform);
933 
934  tbb::blocked_range<size_t> range(0, numPoints);
935  CalculatePositionBounds<PositionWrapper> calculateBounds(positions, inverseTransform);
936  tbb::parallel_reduce(range, calculateBounds);
937 
938  BBoxd bbox = calculateBounds.getBoundingBox();
939 
940  // return default size if points are coincident
941 
942  if (bbox.min() == bbox.max()) return voxelSize;
943 
944  double volume = bbox.volume();
945 
946  // handle points that are collinear or coplanar by expanding the volume
947 
948  if (math::isApproxZero(volume)) {
949  Vec3d extents = bbox.extents().sorted().reversed();
950  if (math::isApproxZero(extents[1])) {
951  // colinear (maxExtent^3)
952  volume = extents[0]*extents[0]*extents[0];
953  }
954  else {
955  // coplanar (maxExtent*nextMaxExtent^2)
956  volume = extents[0]*extents[1]*extents[1];
957  }
958  }
959 
960  double previousVolume = volume;
961 
962  if (!Local::voxelSizeFromVolume(volume, targetVoxelCount, voxelSize)) {
963  OPENVDB_LOG_DEBUG("Out of range, clamping voxel size.");
964  return voxelSize;
965  }
966 
967  size_t previousVoxelCount(0);
968  size_t voxelCount(1);
969 
970  if (interrupter) interrupter->start("Computing voxel size");
971 
972  while (voxelCount > previousVoxelCount)
973  {
974  math::Transform::Ptr newTransform;
975 
976  if (!math::isIdentity(transform))
977  {
978  // if using a custom transform, pre-scale by coefficients
979  // which define the new voxel size
980 
981  math::Mat4d matrix(transform);
982  matrix.preScale(Vec3d(voxelSize) / math::getScale(matrix));
983  newTransform = math::Transform::createLinearTransform(matrix);
984  }
985  else
986  {
987  newTransform = math::Transform::createLinearTransform(voxelSize);
988  }
989 
990  // create a mask grid of the points from the calculated voxel size
991  // this is the same function call as tools::createPointMask() which has
992  // been duplicated to provide an interrupter
993 
994  MaskGrid::Ptr mask = createGrid<MaskGrid>(false);
995  mask->setTransform(newTransform);
996  tools::PointsToMask<MaskGrid, InterrupterT> pointMaskOp(*mask, interrupter);
997  pointMaskOp.addPoints(positions);
998 
999  if (interrupter && util::wasInterrupted(interrupter)) break;
1000 
1001  previousVoxelCount = voxelCount;
1002  voxelCount = mask->activeVoxelCount();
1003  volume = math::Pow3(voxelSize) * static_cast<float>(voxelCount);
1004 
1005  // stop if no change in the volume or the volume has increased
1006 
1007  if (volume >= previousVolume) break;
1008  previousVolume = volume;
1009 
1010  const float previousVoxelSize = voxelSize;
1011 
1012  // compute the new voxel size and if invalid return the previous value
1013 
1014  if (!Local::voxelSizeFromVolume(volume, targetVoxelCount, voxelSize)) {
1015  voxelSize = previousVoxelSize;
1016  break;
1017  }
1018 
1019  // halt convergence if the voxel size has decreased by less
1020  // than 10% in this iteration
1021 
1022  if (voxelSize / previousVoxelSize > 0.9f) break;
1023  }
1024 
1025  if (interrupter) interrupter->end();
1026 
1027  // truncate the voxel size for readability and return the value
1028 
1029  return Local::truncate(voxelSize, decimalPlaces);
1030 }
1031 
1032 
1034 
1035 
1036 // deprecated functions
1037 
1038 
1039 template <typename PositionAttribute, typename PointDataGridT>
1041 inline void
1042 convertPointDataGridPosition( PositionAttribute& positionAttribute,
1043  const PointDataGridT& grid,
1044  const std::vector<Index64>& pointOffsets,
1045  const Index64 startOffset,
1046  const std::vector<Name>& includeGroups,
1047  const std::vector<Name>& excludeGroups,
1048  const bool inCoreOnly = false)
1049 {
1050  auto leaf = grid.tree().cbeginLeaf();
1051  if (!leaf) return;
1052  MultiGroupFilter filter(includeGroups, excludeGroups, leaf->attributeSet());
1053  convertPointDataGridPosition(positionAttribute, grid, pointOffsets, startOffset,
1054  filter, inCoreOnly);
1055 }
1056 
1057 
1058 template <typename TypedAttribute, typename PointDataTreeT>
1060 inline void
1061 convertPointDataGridAttribute( TypedAttribute& attribute,
1062  const PointDataTreeT& tree,
1063  const std::vector<Index64>& pointOffsets,
1064  const Index64 startOffset,
1065  const unsigned arrayIndex,
1066  const Index stride,
1067  const std::vector<Name>& includeGroups,
1068  const std::vector<Name>& excludeGroups,
1069  const bool inCoreOnly = false)
1070 {
1071  auto leaf = tree.cbeginLeaf();
1072  if (!leaf) return;
1073  MultiGroupFilter filter(includeGroups, excludeGroups, leaf->attributeSet());
1074  convertPointDataGridAttribute(attribute, tree, pointOffsets, startOffset,
1075  arrayIndex, stride, filter, inCoreOnly);
1076 }
1077 
1078 
1079 template <typename Group, typename PointDataTreeT>
1081 inline void
1083  const PointDataTreeT& tree,
1084  const std::vector<Index64>& pointOffsets,
1085  const Index64 startOffset,
1086  const AttributeSet::Descriptor::GroupIndex index,
1087  const std::vector<Name>& includeGroups,
1088  const std::vector<Name>& excludeGroups,
1089  const bool inCoreOnly = false)
1090 {
1091  auto leaf = tree.cbeginLeaf();
1092  if (!leaf) return;
1093  MultiGroupFilter filter(includeGroups, excludeGroups, leaf->attributeSet());
1094  convertPointDataGridGroup(group, tree, pointOffsets, startOffset,
1095  index, filter, inCoreOnly);
1096 }
1097 
1098 
1099 } // namespace points
1100 } // namespace OPENVDB_VERSION_NAME
1101 } // namespace openvdb
1102 
1103 #endif // OPENVDB_POINTS_POINT_CONVERSION_HAS_BEEN_INCLUDED
OPENVDB_DEPRECATED void convertPointDataGridGroup(Group &group, const PointDataTreeT &tree, const std::vector< Index64 > &pointOffsets, const Index64 startOffset, const AttributeSet::Descriptor::GroupIndex index, const std::vector< Name > &includeGroups, const std::vector< Name > &excludeGroups, const bool inCoreOnly=false)
Definition: PointConversion.h:1082
bool isIdentity(const MatType &m)
Determine if a matrix is an identity matrix.
Definition: Mat.h:865
void preScale(const Vec3< T0 > &v)
Definition: Mat4.h:755
const std::vector< Index64 > & mPointOffsets
Definition: PointConversion.h:560
#define OPENVDB_DEPRECATED
Definition: Platform.h:42
const std::vector< Index64 > & mPointOffsets
Definition: PointConversion.h:390
const PointIndexTreeType & mPointIndexTree
Definition: PointConversion.h:311
Mat4< double > Mat4d
Definition: Mat4.h:1334
Vec3< typename MatType::value_type > getScale(const MatType &mat)
Return a Vec3 representing the lengths of the passed matrix&#39;s upper 3×3&#39;s rows.
Definition: Mat.h:638
Vec3< T > sorted() const
Return a vector with the components of this in ascending order.
Definition: Vec3.h:448
void getPos(size_t n, ValueType &xyz) const
Definition: PointConversion.h:202
Vec3< double > Vec3d
Definition: Vec3.h:662
SharedPtr< Grid > Ptr
Definition: Grid.h:574
Space-partitioning acceleration structure for points. Partitions the points into voxels to accelerate...
#define OPENVDB_LOG_DEBUG(message)
In debug builds only, log a debugging message of the form &#39;someVar << "text" << ...&#39;.
Definition: logging.h:263
Index64 pointOffsets(std::vector< Index64 > &pointOffsets, const PointDataTreeT &tree, const FilterT &filter=NullFilter(), const bool inCoreOnly=false, const bool threaded=true)
Populate an array of cumulative point offsets per leaf node.
Definition: PointCount.h:122
Vec2< T > maxComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise maximum of the two vectors.
Definition: Vec2.h:512
Vec3T extents() const
Return the extents of this bounding box, i.e., the length along each axis.
Definition: BBox.h:253
void operator()(const LeafRangeT &range) const
Definition: PointConversion.h:360
Index64 pointCount(const PointDataTreeT &tree, const FilterT &filter=NullFilter(), const bool inCoreOnly=false, const bool threaded=true)
Count the total number of points in a PointDataTree.
Definition: PointCount.h:88
OPENVDB_DEPRECATED void convertPointDataGridPosition(PositionAttribute &positionAttribute, const PointDataGridT &grid, const std::vector< Index64 > &pointOffsets, const Index64 startOffset, const std::vector< Name > &includeGroups, const std::vector< Name > &excludeGroups, const bool inCoreOnly=false)
Definition: PointConversion.h:1042
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:82
std::string Name
Definition: Name.h:17
Base class for storing attribute data.
Definition: AttributeArray.h:92
AttributeSet::Descriptor::GroupIndex GroupIndex
Definition: PointConversion.h:490
typename PointDataTreeType::LeafNodeType LeafNode
Definition: PointConversion.h:402
Definition: Coord.h:587
typename PointDataTreeType::LeafNodeType LeafNode
Definition: PointConversion.h:320
void operator()(const typename LeafManagerT::LeafRange &range) const
Definition: PointConversion.h:275
const Vec3T & min() const
Return a const reference to the minimum point of this bounding box.
Definition: BBox.h:62
typename PointIndexTreeType::LeafNodeType PointIndexLeafNode
Definition: PointConversion.h:261
void addPoints(const PointListT &points, size_t grainSize=1024)
Activates the state of any voxel in the input grid that contains a point.
Definition: PointsToMask.h:123
typename ConversionTraits< ValueType >::WriteHandle HandleT
Definition: PointConversion.h:264
Definition: AttributeArrayString.h:109
typename ConversionTraits< ValueType >::Handle SourceHandleT
Definition: PointConversion.h:405
Definition: Exceptions.h:59
PointAttributeVector(const std::vector< value_type > &data, const Index stride=1)
Definition: PointConversion.h:196
typename tree::LeafManager< const PointDataTreeType > LeafManagerT
Definition: PointConversion.h:491
Ptr copy() const
Definition: Transform.h:50
double Real
Definition: Types.h:37
Definition: IndexIterator.h:43
ConvertPointDataGridGroupOp(Group &group, const std::vector< Index64 > &pointOffsets, const Index64 startOffset, const AttributeSet::Descriptor::GroupIndex index, const FilterT &filter, const bool inCoreOnly)
Definition: PointConversion.h:494
typename LeafManagerT::LeafRange LeafRangeT
Definition: PointConversion.h:407
Definition: AttributeArrayString.h:141
typename tree::LeafManager< const PointDataTreeType > LeafManagerT
Definition: PointConversion.h:324
Typed class for storing attribute data.
Definition: AttributeArray.h:566
const size_t mIndex
Definition: PointConversion.h:313
Point attribute manipulation in a VDB Point Grid.
Point group manipulation in a VDB Point Grid.
typename AttributeListType::value_type ValueType
Definition: PointConversion.h:263
Index filters primarily designed to be used with a FilterIndexIter.
Definition: Exceptions.h:65
std::shared_ptr< StringAttributeHandle > Ptr
Definition: AttributeArrayString.h:112
static Handle::Ptr handleFromLeaf(LeafT &leaf, Index index)
Definition: PointConversion.h:241
PopulateAttributeOp(const PointIndexTreeType &pointIndexTree, const AttributeListType &data, const size_t index, const Index stride=1)
Definition: PointConversion.h:266
ValueType get(Index n, Index m=0) const
Definition: AttributeArray.h:2209
typename PointDataTreeType::LeafNodeType LeafNode
Definition: PointConversion.h:489
Vec3< T > reversed() const
Return the vector (z, y, x)
Definition: Vec3.h:458
uint8_t GroupType
Definition: AttributeGroup.h:23
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:102
bool isGroup(const AttributeArray &array)
Definition: AttributeGroup.h:66
static T zero()
Definition: PointConversion.h:223
BBoxd getBoundingBox() const
Definition: PointConversion.h:598
std::pair< Name, Name > NamePair
Definition: AttributeArray.h:39
const std::vector< Index64 > & mPointOffsets
Definition: PointConversion.h:478
typename LeafManagerT::LeafRange LeafRangeT
Definition: PointConversion.h:325
ValueType PosType
Definition: PointConversion.h:193
void join(const CalculatePositionBounds &other)
Definition: PointConversion.h:593
void operator()(const tbb::blocked_range< size_t > &range)
Definition: PointConversion.h:583
Definition: IndexFilter.h:135
Type Pow3(Type x)
Return x3.
Definition: Math.h:499
typename Attribute::ValueType ValueType
Definition: PointConversion.h:321
const Index mStride
Definition: PointConversion.h:314
Definition: Types.h:181
Definition: Exceptions.h:13
const Vec3T & max() const
Return a const reference to the maximum point of this bounding box.
Definition: BBox.h:64
const math::Transform & mTransform
Definition: PointConversion.h:392
static Handle::Ptr handleFromLeaf(LeafT &leaf, Index index)
Definition: PointConversion.h:225
std::vector< Index > IndexArray
Definition: PointMove.h:161
Write-able version of AttributeHandle.
Definition: AttributeArray.h:920
void operator()(const LeafRangeT &range) const
Definition: PointConversion.h:448
ConvertPointDataGridPositionOp(Attribute &attribute, const std::vector< Index64 > &pointOffsets, const Index64 startOffset, const math::Transform &transform, const size_t index, const FilterT &filter, const bool inCoreOnly)
Definition: PointConversion.h:327
This tool produces a grid where every voxel that contains a point is active. It employes thread-local...
OPENVDB_API void calculateBounds(const Transform &t, const Vec3d &minWS, const Vec3d &maxWS, Vec3d &minIS, Vec3d &maxIS)
Calculate an axis-aligned bounding box in index space from an axis-aligned bounding box in world spac...
OPENVDB_DEPRECATED void convertPointDataGridAttribute(TypedAttribute &attribute, const PointDataTreeT &tree, const std::vector< Index64 > &pointOffsets, const Index64 startOffset, const unsigned arrayIndex, const Index stride, const std::vector< Name > &includeGroups, const std::vector< Name > &excludeGroups, const bool inCoreOnly=false)
Definition: PointConversion.h:1061
This class manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional auxil...
Definition: LeafManager.h:82
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:49
LeafRange leafRange(size_t grainsize=1) const
Return a TBB-compatible LeafRange.
Definition: LeafManager.h:358
typename tree::LeafManager< const PointDataTreeType > LeafManagerT
Definition: PointConversion.h:406
static openvdb::Name zero()
Definition: PointConversion.h:239
MatType unit(const MatType &mat, typename MatType::value_type eps=1.0e-8)
Return a copy of the given matrix with its upper 3×3 rows normalized.
Definition: Mat.h:653
std::shared_ptr< StringAttributeWriteHandle > Ptr
Definition: AttributeArrayString.h:144
Definition: Transform.h:39
Type Pow(Type x, int n)
Return xn.
Definition: Math.h:508
const AttributeListType & mData
Definition: PointConversion.h:312
void convert(IterT &iter, HandleT &targetHandle, SourceHandleT &sourceHandle, Index64 &offset) const
Definition: PointConversion.h:425
SharedPtr< Metadata > Ptr
Definition: Metadata.h:26
typename RootNodeType::LeafNodeType LeafNodeType
Definition: Tree.h:185
Index32 Index
Definition: Types.h:31
ConvertPointDataGridAttributeOp(Attribute &attribute, const std::vector< Index64 > &pointOffsets, const Index64 startOffset, const size_t index, const Index stride, const FilterT &filter, const bool inCoreOnly)
Definition: PointConversion.h:409
Vec3d worldToIndex(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:110
ElementType volume() const
Return the volume enclosed by this bounding box.
Definition: BBox.h:100
PointDataGridT::Ptr createPointDataGrid(const std::vector< ValueT > &positions, const math::Transform &xform, Metadata::Ptr positionDefaultValue=Metadata::Ptr())
Convenience method to create a PointDataGrid from a std::vector of point positions.
Definition: PointConversion.h:719
Definition: AttributeArray.h:849
typename Attribute::ValueType ValueType
Definition: PointConversion.h:403
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
void convert(IterT &iter, const GroupAttributeArray &groupArray, Index64 &offset) const
Definition: PointConversion.h:508
bool isApproxZero(const Type &x)
Return true if x is equal to zero to within the default floating-point comparison tolerance...
Definition: Math.h:293
typename PointIndexLeafNode::IndexArray IndexArray
Definition: PointConversion.h:262
Attribute array storage for string data using Descriptor Metadata.
uint64_t Index64
Definition: Types.h:30
CalculatePositionBounds(const CalculatePositionBounds &other, tbb::split)
Definition: PointConversion.h:577
float computeVoxelSize(const PositionWrapper &positions, const uint32_t pointsPerVoxel, const math::Mat4d transform=math::Mat4d::identity(), const Index decimalPlaces=5, InterrupterT *const interrupter=nullptr)
Definition: PointConversion.h:866
bool isUniform() const override
Return true if this array is stored as a single uniform value.
Definition: AttributeArray.h:718
typename LeafManagerT::LeafRange LeafRangeT
Definition: PointConversion.h:260
ValueType get(Index n) const
Return the value at index n.
Definition: AttributeArray.h:1433
std::shared_ptr< Handle > Ptr
Definition: AttributeArray.h:924
std::shared_ptr< Handle > Ptr
Definition: AttributeArray.h:853
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:154
static WriteHandle::Ptr writeHandleFromLeaf(LeafT &leaf, Index index)
Definition: PointConversion.h:230
Mat4 inverse(T tolerance=0) const
Definition: Mat4.h:504
void populateAttribute(PointDataTreeT &tree, const PointIndexTreeT &pointIndexTree, const openvdb::Name &attributeName, const PointArrayT &data, const Index stride=1, const bool insertMetadata=true)
Stores point attribute data in an existing PointDataGrid attribute.
Definition: PointConversion.h:735
ValueType value_type
Definition: PointConversion.h:194
math::BBox< Vec3d > BBoxd
Definition: Types.h:61
void operator()(const LeafRangeT &range) const
Definition: PointConversion.h:530
Set of Attribute Arrays which tracks metadata about each array.
Vec2< T > minComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise minimum of the two vectors.
Definition: Vec2.h:503
size_t size() const
Definition: PointConversion.h:201
typename LeafManagerT::LeafRange LeafRangeT
Definition: PointConversion.h:492
CalculatePositionBounds(const PositionArrayT &positions, const math::Mat4d &inverse)
Definition: PointConversion.h:570
typename Attribute::Handle HandleT
Definition: PointConversion.h:404
void convert(IterT &iter, HandleT &targetHandle, SourceHandleT &sourceHandle, Index64 &offset) const
Definition: PointConversion.h:349
SharedPtr< Transform > Ptr
Definition: Transform.h:42
Point-partitioner compatible STL vector attribute wrapper for convenience.
Definition: PointConversion.h:191
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:106
typename Attribute::Handle HandleT
Definition: PointConversion.h:322
Makes every voxel of a grid active if it contains a point.
Definition: PointsToMask.h:67
Type Truncate(Type x, unsigned int digits)
Return x truncated to the given number of decimal digits.
Definition: Math.h:817
typename tree::LeafManager< PointDataTreeType > LeafManagerT
Definition: PointConversion.h:259
static WriteHandle::Ptr writeHandleFromLeaf(LeafT &leaf, Index index)
Definition: PointConversion.h:247