OpenVDB 11.0.0

Loading...
Searching...
No Matches
PointConversionImpl.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, Nick Avramoussis
5///
6/// @file PointConversionImpl.h
7///
8
9#ifndef OPENVDB_POINTS_POINT_CONVERSION_IMPL_HAS_BEEN_INCLUDED
10#define OPENVDB_POINTS_POINT_CONVERSION_IMPL_HAS_BEEN_INCLUDED
11
12 namespace openvdb {
13 OPENVDB_USE_VERSION_NAMESPACE
14 namespace OPENVDB_VERSION_NAME {
15 namespace points {
16
17/// @cond OPENVDB_DOCS_INTERNAL
18
19 namespace point_conversion_internal {
20
21
22// ConversionTraits to create the relevant Attribute Handles from a LeafNode
23 template <typename T> struct ConversionTraits
24{
25 using Handle = AttributeHandle<T, UnknownCodec>;
26 using WriteHandle = AttributeWriteHandle<T, UnknownCodec>;
27 static T zero() { return zeroVal<T>(); }
28 template <typename LeafT>
29 static std::unique_ptr<Handle> handleFromLeaf(const LeafT& leaf, const Index index) {
30 const AttributeArray& array = leaf.constAttributeArray(index);
31 return std::make_unique<Handle>(array);
32 }
33 template <typename LeafT>
34 static std::unique_ptr<WriteHandle> writeHandleFromLeaf(LeafT& leaf, const Index index) {
35 AttributeArray& array = leaf.attributeArray(index);
36 return std::make_unique<WriteHandle>(array);
37 }
38}; // ConversionTraits
39 template <> struct ConversionTraits<openvdb::Name>
40{
41 using Handle = StringAttributeHandle;
42 using WriteHandle = StringAttributeWriteHandle;
43 static openvdb::Name zero() { return ""; }
44 template <typename LeafT>
45 static std::unique_ptr<Handle> handleFromLeaf(const LeafT& leaf, const Index index) {
46 const AttributeArray& array = leaf.constAttributeArray(index);
47 const AttributeSet::Descriptor& descriptor = leaf.attributeSet().descriptor();
48 return std::make_unique<Handle>(array, descriptor.getMetadata());
49 }
50 template <typename LeafT>
51 static std::unique_ptr<WriteHandle> writeHandleFromLeaf(LeafT& leaf, const Index index) {
52 AttributeArray& array = leaf.attributeArray(index);
53 const AttributeSet::Descriptor& descriptor = leaf.attributeSet().descriptor();
54 return std::make_unique<WriteHandle>(array, descriptor.getMetadata());
55 }
56}; // ConversionTraits<openvdb::Name>
57
58 template< typename PointDataTreeType,
59 typename PointIndexTreeType,
60 typename AttributeListType>
61 struct PopulateAttributeOp {
62
63 using LeafManagerT = typename tree::LeafManager<PointDataTreeType>;
64 using LeafRangeT = typename LeafManagerT::LeafRange;
65 using PointIndexLeafNode = typename PointIndexTreeType::LeafNodeType;
66 using IndexArray = typename PointIndexLeafNode::IndexArray;
67 using ValueType = typename AttributeListType::value_type;
68 using HandleT = typename ConversionTraits<ValueType>::WriteHandle;
69
70 PopulateAttributeOp(const PointIndexTreeType& pointIndexTree,
71 const AttributeListType& data,
72 const size_t index,
73 const Index stride = 1)
74 : mPointIndexTree(pointIndexTree)
75 , mData(data)
76 , mIndex(index)
77 , mStride(stride) { }
78
79 void operator()(const typename LeafManagerT::LeafRange& range) const {
80
81 for (auto leaf = range.begin(); leaf; ++leaf) {
82
83 // obtain the PointIndexLeafNode (using the origin of the current leaf)
84
85 const PointIndexLeafNode* pointIndexLeaf =
86 mPointIndexTree.probeConstLeaf(leaf->origin());
87
88 if (!pointIndexLeaf) continue;
89
90 auto attributeWriteHandle =
91 ConversionTraits<ValueType>::writeHandleFromLeaf(*leaf, static_cast<Index>(mIndex));
92
93 Index64 index = 0;
94
95 const IndexArray& indices = pointIndexLeaf->indices();
96
97 for (const Index64 leafIndex: indices)
98 {
99 ValueType value;
100 for (Index i = 0; i < mStride; i++) {
101 mData.get(value, leafIndex, i);
102 attributeWriteHandle->set(static_cast<Index>(index), i, value);
103 }
104 index++;
105 }
106
107 // attempt to compact the array
108
109 attributeWriteHandle->compact();
110 }
111 }
112
113 //////////
114
115 const PointIndexTreeType& mPointIndexTree;
116 const AttributeListType& mData;
117 const size_t mIndex;
118 const Index mStride;
119};
120
121 template<typename PointDataTreeType, typename Attribute, typename FilterT>
122 struct ConvertPointDataGridPositionOp {
123
124 using LeafNode = typename PointDataTreeType::LeafNodeType;
125 using ValueType = typename Attribute::ValueType;
126 using HandleT = typename Attribute::Handle;
127 using SourceHandleT = AttributeHandle<ValueType>;
128 using LeafManagerT = typename tree::LeafManager<const PointDataTreeType>;
129 using LeafRangeT = typename LeafManagerT::LeafRange;
130
131 ConvertPointDataGridPositionOp( Attribute& attribute,
132 const std::vector<Index64>& pointOffsets,
133 const Index64 startOffset,
134 const math::Transform& transform,
135 const size_t index,
136 const FilterT& filter,
137 const bool inCoreOnly)
138 : mAttribute(attribute)
139 , mPointOffsets(pointOffsets)
140 , mStartOffset(startOffset)
141 , mTransform(transform)
142 , mIndex(index)
143 , mFilter(filter)
144 , mInCoreOnly(inCoreOnly)
145 {
146 // only accept Vec3f as ValueType
147 static_assert(VecTraits<ValueType>::Size == 3 &&
148 std::is_floating_point<typename ValueType::ValueType>::value,
149 "ValueType is not Vec3f");
150 }
151
152 template <typename IterT>
153 void convert(IterT& iter, HandleT& targetHandle,
154 SourceHandleT& sourceHandle, Index64& offset) const
155 {
156 for (; iter; ++iter) {
157 const Vec3d xyz = iter.getCoord().asVec3d();
158 const Vec3d pos = sourceHandle.get(*iter);
159 targetHandle.set(static_cast<Index>(offset++), /*stride=*/0,
160 mTransform.indexToWorld(pos + xyz));
161 }
162 }
163
164 void operator()(const LeafRangeT& range) const
165 {
166 HandleT pHandle(mAttribute);
167
168 for (auto leaf = range.begin(); leaf; ++leaf) {
169
170 assert(leaf.pos() < mPointOffsets.size());
171
172 if (mInCoreOnly && leaf->buffer().isOutOfCore()) continue;
173
174 Index64 offset = mStartOffset;
175
176 if (leaf.pos() > 0) offset += mPointOffsets[leaf.pos() - 1];
177
178 auto handle = SourceHandleT::create(leaf->constAttributeArray(mIndex));
179
180 if (mFilter.state() == index::ALL) {
181 auto iter = leaf->beginIndexOn();
182 convert(iter, pHandle, *handle, offset);
183 }
184 else {
185 auto iter = leaf->beginIndexOn(mFilter);
186 convert(iter, pHandle, *handle, offset);
187 }
188 }
189 }
190
191 //////////
192
193 Attribute& mAttribute;
194 const std::vector<Index64>& mPointOffsets;
195 const Index64 mStartOffset;
196 const math::Transform& mTransform;
197 const size_t mIndex;
198 const FilterT& mFilter;
199 const bool mInCoreOnly;
200}; // ConvertPointDataGridPositionOp
201
202
203 template<typename PointDataTreeType, typename Attribute, typename FilterT>
204 struct ConvertPointDataGridAttributeOp {
205
206 using LeafNode = typename PointDataTreeType::LeafNodeType;
207 using ValueType = typename Attribute::ValueType;
208 using HandleT = typename Attribute::Handle;
209 using SourceHandleT = typename ConversionTraits<ValueType>::Handle;
210 using LeafManagerT = typename tree::LeafManager<const PointDataTreeType>;
211 using LeafRangeT = typename LeafManagerT::LeafRange;
212
213 ConvertPointDataGridAttributeOp(Attribute& attribute,
214 const std::vector<Index64>& pointOffsets,
215 const Index64 startOffset,
216 const size_t index,
217 const Index stride,
218 const FilterT& filter,
219 const bool inCoreOnly)
220 : mAttribute(attribute)
221 , mPointOffsets(pointOffsets)
222 , mStartOffset(startOffset)
223 , mIndex(index)
224 , mStride(stride)
225 , mFilter(filter)
226 , mInCoreOnly(inCoreOnly) { }
227
228 template <typename IterT>
229 void convert(IterT& iter, HandleT& targetHandle,
230 SourceHandleT& sourceHandle, Index64& offset) const
231 {
232 if (sourceHandle.isUniform()) {
233 const ValueType uniformValue(sourceHandle.get(0));
234 for (; iter; ++iter) {
235 for (Index i = 0; i < mStride; i++) {
236 targetHandle.set(static_cast<Index>(offset), i, uniformValue);
237 }
238 offset++;
239 }
240 }
241 else {
242 for (; iter; ++iter) {
243 for (Index i = 0; i < mStride; i++) {
244 targetHandle.set(static_cast<Index>(offset), i,
245 sourceHandle.get(*iter, /*stride=*/i));
246 }
247 offset++;
248 }
249 }
250 }
251
252 void operator()(const LeafRangeT& range) const
253 {
254 HandleT pHandle(mAttribute);
255
256 for (auto leaf = range.begin(); leaf; ++leaf) {
257
258 assert(leaf.pos() < mPointOffsets.size());
259
260 if (mInCoreOnly && leaf->buffer().isOutOfCore()) continue;
261
262 Index64 offset = mStartOffset;
263
264 if (leaf.pos() > 0) offset += mPointOffsets[leaf.pos() - 1];
265
266 auto handle = ConversionTraits<ValueType>::handleFromLeaf(
267 *leaf, static_cast<Index>(mIndex));
268
269 if (mFilter.state() == index::ALL) {
270 auto iter = leaf->beginIndexOn();
271 convert(iter, pHandle, *handle, offset);
272 } else {
273 auto iter = leaf->beginIndexOn(mFilter);
274 convert(iter, pHandle, *handle, offset);
275 }
276 }
277 }
278
279 //////////
280
281 Attribute& mAttribute;
282 const std::vector<Index64>& mPointOffsets;
283 const Index64 mStartOffset;
284 const size_t mIndex;
285 const Index mStride;
286 const FilterT& mFilter;
287 const bool mInCoreOnly;
288}; // ConvertPointDataGridAttributeOp
289
290 template<typename PointDataTreeType, typename Group, typename FilterT>
291 struct ConvertPointDataGridGroupOp {
292
293 using LeafNode = typename PointDataTreeType::LeafNodeType;
294 using GroupIndex = AttributeSet::Descriptor::GroupIndex;
295 using LeafManagerT = typename tree::LeafManager<const PointDataTreeType>;
296 using LeafRangeT = typename LeafManagerT::LeafRange;
297
298 ConvertPointDataGridGroupOp(Group& group,
299 const std::vector<Index64>& pointOffsets,
300 const Index64 startOffset,
301 const AttributeSet::Descriptor::GroupIndex index,
302 const FilterT& filter,
303 const bool inCoreOnly)
304 : mGroup(group)
305 , mPointOffsets(pointOffsets)
306 , mStartOffset(startOffset)
307 , mIndex(index)
308 , mFilter(filter)
309 , mInCoreOnly(inCoreOnly) { }
310
311 template <typename IterT>
312 void convert(IterT& iter, const GroupAttributeArray& groupArray, Index64& offset) const
313 {
314 const auto bitmask = static_cast<GroupType>(1 << mIndex.second);
315
316 if (groupArray.isUniform()) {
317 if (groupArray.get(0) & bitmask) {
318 for (; iter; ++iter) {
319 mGroup.setOffsetOn(static_cast<Index>(offset));
320 offset++;
321 }
322 }
323 }
324 else {
325 for (; iter; ++iter) {
326 if (groupArray.get(*iter) & bitmask) {
327 mGroup.setOffsetOn(static_cast<Index>(offset));
328 }
329 offset++;
330 }
331 }
332 }
333
334 void operator()(const LeafRangeT& range) const
335 {
336 for (auto leaf = range.begin(); leaf; ++leaf) {
337
338 assert(leaf.pos() < mPointOffsets.size());
339
340 if (mInCoreOnly && leaf->buffer().isOutOfCore()) continue;
341
342 Index64 offset = mStartOffset;
343
344 if (leaf.pos() > 0) offset += mPointOffsets[leaf.pos() - 1];
345
346 const AttributeArray& array = leaf->constAttributeArray(mIndex.first);
347 assert(isGroup(array));
348 const GroupAttributeArray& groupArray = GroupAttributeArray::cast(array);
349
350 if (mFilter.state() == index::ALL) {
351 auto iter = leaf->beginIndexOn();
352 convert(iter, groupArray, offset);
353 }
354 else {
355 auto iter = leaf->beginIndexOn(mFilter);
356 convert(iter, groupArray, offset);
357 }
358 }
359 }
360
361 //////////
362
363 Group& mGroup;
364 const std::vector<Index64>& mPointOffsets;
365 const Index64 mStartOffset;
366 const GroupIndex mIndex;
367 const FilterT& mFilter;
368 const bool mInCoreOnly;
369}; // ConvertPointDataGridGroupOp
370
371 template<typename PositionArrayT, typename VecT = Vec3R>
372 struct CalculatePositionBounds
373{
374 CalculatePositionBounds(const PositionArrayT& positions,
375 const math::Mat4d& inverse)
376 : mPositions(positions)
377 , mInverseMat(inverse)
378 , mMin(std::numeric_limits<Real>::max())
379 , mMax(-std::numeric_limits<Real>::max()) {}
380
381 CalculatePositionBounds(const CalculatePositionBounds& other, tbb::split)
382 : mPositions(other.mPositions)
383 , mInverseMat(other.mInverseMat)
384 , mMin(std::numeric_limits<Real>::max())
385 , mMax(-std::numeric_limits<Real>::max()) {}
386
387 void operator()(const tbb::blocked_range<size_t>& range) {
388 VecT pos;
389 for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
390 mPositions.getPos(n, pos);
391 pos = mInverseMat.transform(pos);
392 mMin = math::minComponent(mMin, pos);
393 mMax = math::maxComponent(mMax, pos);
394 }
395 }
396
397 void join(const CalculatePositionBounds& other) {
398 mMin = math::minComponent(mMin, other.mMin);
399 mMax = math::maxComponent(mMax, other.mMax);
400 }
401
402 BBoxd getBoundingBox() const {
403 return BBoxd(mMin, mMax);
404 }
405
406 private:
407 const PositionArrayT& mPositions;
408 const math::Mat4d& mInverseMat;
409 VecT mMin, mMax;
410};
411
412} // namespace point_conversion_internal
413
414/// @endcond
415
416////////////////////////////////////////
417
418
419 template<typename CompressionT, typename PointDataGridT, typename PositionArrayT, typename PointIndexGridT>
420 inline typename PointDataGridT::Ptr
421 createPointDataGrid(const PointIndexGridT& pointIndexGrid,
422 const PositionArrayT& positions,
423 const math::Transform& xform,
424 const Metadata* positionDefaultValue)
425{
426 using PointDataTreeT = typename PointDataGridT::TreeType;
427 using LeafT = typename PointDataTreeT::LeafNodeType;
428 using PointIndexLeafT = typename PointIndexGridT::TreeType::LeafNodeType;
429 using PointIndexT = typename PointIndexLeafT::ValueType;
430 using LeafManagerT = typename tree::LeafManager<PointDataTreeT>;
431 using PositionAttributeT = TypedAttributeArray<Vec3f, CompressionT>;
432
433 const NamePair positionType = PositionAttributeT::attributeType();
434
435 // construct the Tree using a topology copy of the PointIndexGrid
436
437 const auto& pointIndexTree = pointIndexGrid.tree();
438 typename PointDataTreeT::Ptr treePtr(new PointDataTreeT(pointIndexTree));
439
440 // create attribute descriptor from position type
441
442 auto descriptor = AttributeSet::Descriptor::create(positionType);
443
444 // add default value for position if provided
445
446 if (positionDefaultValue) descriptor->setDefaultValue("P", *positionDefaultValue);
447
448 // retrieve position index
449
450 const size_t positionIndex = descriptor->find("P");
451 assert(positionIndex != AttributeSet::INVALID_POS);
452
453 // acquire registry lock to avoid locking when appending attributes in parallel
454
455 AttributeArray::ScopedRegistryLock lock;
456
457 // populate position attribute
458
459 LeafManagerT leafManager(*treePtr);
460 leafManager.foreach(
461 [&](LeafT& leaf, size_t /*idx*/) {
462
463 // obtain the PointIndexLeafNode (using the origin of the current leaf)
464
465 const auto* pointIndexLeaf = pointIndexTree.probeConstLeaf(leaf.origin());
466 assert(pointIndexLeaf);
467
468 // initialise the attribute storage
469
470 Index pointCount(static_cast<Index>(pointIndexLeaf->indices().size()));
471 leaf.initializeAttributes(descriptor, pointCount, &lock);
472
473 // create write handle for position
474
475 auto attributeWriteHandle = AttributeWriteHandle<Vec3f, CompressionT>::create(
476 leaf.attributeArray(positionIndex));
477
478 Index index = 0;
479
480 const PointIndexT
481 *begin = static_cast<PointIndexT*>(nullptr),
482 *end = static_cast<PointIndexT*>(nullptr);
483
484 // iterator over every active voxel in the point index leaf
485
486 for (auto iter = pointIndexLeaf->cbeginValueOn(); iter; ++iter) {
487
488 // find the voxel center
489
490 const Coord& ijk = iter.getCoord();
491 const Vec3d& positionCellCenter(ijk.asVec3d());
492
493 // obtain pointers for this voxel from begin to end in the indices array
494
495 pointIndexLeaf->getIndices(ijk, begin, end);
496
497 while (begin < end) {
498
499 typename PositionArrayT::value_type positionWorldSpace;
500 positions.getPos(*begin, positionWorldSpace);
501
502 // compute the index-space position and then subtract the voxel center
503
504 const Vec3d positionIndexSpace = xform.worldToIndex(positionWorldSpace);
505 const Vec3f positionVoxelSpace(positionIndexSpace - positionCellCenter);
506
507 attributeWriteHandle->set(index++, positionVoxelSpace);
508
509 ++begin;
510 }
511 }
512 },
513 /*threaded=*/true);
514
515 auto grid = PointDataGridT::create(treePtr);
516 grid->setTransform(xform.copy());
517 return grid;
518}
519
520
521////////////////////////////////////////
522
523
524 template <typename CompressionT, typename PointDataGridT, typename ValueT>
525 inline typename PointDataGridT::Ptr
526 createPointDataGrid(const std::vector<ValueT>& positions,
527 const math::Transform& xform,
528 const Metadata* positionDefaultValue)
529{
530 const PointAttributeVector<ValueT> pointList(positions);
531
532 tools::PointIndexGrid::Ptr pointIndexGrid =
533 tools::createPointIndexGrid<tools::PointIndexGrid>(pointList, xform);
534 return createPointDataGrid<CompressionT, PointDataGridT>(
535 *pointIndexGrid, pointList, xform, positionDefaultValue);
536}
537
538
539////////////////////////////////////////
540
541
542 template <typename PointDataTreeT, typename PointIndexTreeT, typename PointArrayT>
543 inline void
544 populateAttribute(PointDataTreeT& tree, const PointIndexTreeT& pointIndexTree,
545 const openvdb::Name& attributeName, const PointArrayT& data, const Index stride,
546 const bool insertMetadata)
547{
548 using point_conversion_internal::PopulateAttributeOp;
549 using ValueType = typename PointArrayT::value_type;
550
551 auto iter = tree.cbeginLeaf();
552
553 if (!iter) return;
554
555 const size_t index = iter->attributeSet().find(attributeName);
556
557 if (index == AttributeSet::INVALID_POS) {
558 OPENVDB_THROW(KeyError, "Attribute not found to populate - " << attributeName << ".");
559 }
560
561 if (insertMetadata) {
562 point_attribute_internal::MetadataStorage<PointDataTreeT, ValueType>::add(tree, data);
563 }
564
565 // populate attribute
566
567 typename tree::LeafManager<PointDataTreeT> leafManager(tree);
568
569 PopulateAttributeOp<PointDataTreeT,
570 PointIndexTreeT,
571 PointArrayT> populate(pointIndexTree, data, index, stride);
572 tbb::parallel_for(leafManager.leafRange(), populate);
573}
574
575
576////////////////////////////////////////
577
578
579 template <typename PositionAttribute, typename PointDataGridT, typename FilterT>
580 inline void
581 convertPointDataGridPosition( PositionAttribute& positionAttribute,
582 const PointDataGridT& grid,
583 const std::vector<Index64>& pointOffsets,
584 const Index64 startOffset,
585 const FilterT& filter,
586 const bool inCoreOnly)
587{
588 using TreeType = typename PointDataGridT::TreeType;
589 using LeafManagerT = typename tree::LeafManager<const TreeType>;
590
591 using point_conversion_internal::ConvertPointDataGridPositionOp;
592
593 const TreeType& tree = grid.tree();
594 auto iter = tree.cbeginLeaf();
595
596 if (!iter) return;
597
598 const size_t positionIndex = iter->attributeSet().find("P");
599
600 positionAttribute.expand();
601 LeafManagerT leafManager(tree);
602 ConvertPointDataGridPositionOp<TreeType, PositionAttribute, FilterT> convert(
603 positionAttribute, pointOffsets, startOffset, grid.transform(), positionIndex,
604 filter, inCoreOnly);
605 tbb::parallel_for(leafManager.leafRange(), convert);
606 positionAttribute.compact();
607}
608
609
610////////////////////////////////////////
611
612
613 template <typename TypedAttribute, typename PointDataTreeT, typename FilterT>
614 inline void
615 convertPointDataGridAttribute( TypedAttribute& attribute,
616 const PointDataTreeT& tree,
617 const std::vector<Index64>& pointOffsets,
618 const Index64 startOffset,
619 const unsigned arrayIndex,
620 const Index stride,
621 const FilterT& filter,
622 const bool inCoreOnly)
623{
624 using LeafManagerT = typename tree::LeafManager<const PointDataTreeT>;
625
626 using point_conversion_internal::ConvertPointDataGridAttributeOp;
627
628 auto iter = tree.cbeginLeaf();
629
630 if (!iter) return;
631
632 attribute.expand();
633 LeafManagerT leafManager(tree);
634 ConvertPointDataGridAttributeOp<PointDataTreeT, TypedAttribute, FilterT> convert(
635 attribute, pointOffsets, startOffset, arrayIndex, stride,
636 filter, inCoreOnly);
637 tbb::parallel_for(leafManager.leafRange(), convert);
638 attribute.compact();
639}
640
641
642////////////////////////////////////////
643
644
645 template <typename Group, typename PointDataTreeT, typename FilterT>
646 inline void
647 convertPointDataGridGroup( Group& group,
648 const PointDataTreeT& tree,
649 const std::vector<Index64>& pointOffsets,
650 const Index64 startOffset,
651 const AttributeSet::Descriptor::GroupIndex index,
652 const FilterT& filter,
653 const bool inCoreOnly)
654{
655 using LeafManagerT= typename tree::LeafManager<const PointDataTreeT>;
656
657 using point_conversion_internal::ConvertPointDataGridGroupOp;
658
659 auto iter = tree.cbeginLeaf();
660 if (!iter) return;
661
662 LeafManagerT leafManager(tree);
663 ConvertPointDataGridGroupOp<PointDataTreeT, Group, FilterT> convert(
664 group, pointOffsets, startOffset, index,
665 filter, inCoreOnly);
666 tbb::parallel_for(leafManager.leafRange(), convert);
667
668 // must call this after modifying point groups in parallel
669
670 group.finalize();
671}
672
673 template<typename PositionWrapper, typename InterrupterT, typename VecT>
674 inline float
675 computeVoxelSize( const PositionWrapper& positions,
676 const uint32_t pointsPerVoxel,
677 const math::Mat4d transform,
678 const Index decimalPlaces,
679 InterrupterT* const interrupter)
680{
681 using namespace point_conversion_internal;
682
683 struct Local {
684
685 static bool voxelSizeFromVolume(const double volume,
686 const size_t estimatedVoxelCount,
687 float& voxelSize)
688 {
689 // dictated by the math::ScaleMap limit
690 static const double minimumVoxelVolume(3e-15);
691 static const double maximumVoxelVolume(std::numeric_limits<float>::max());
692
693 double voxelVolume = volume / static_cast<double>(estimatedVoxelCount);
694 bool valid = true;
695
696 if (voxelVolume < minimumVoxelVolume) {
697 voxelVolume = minimumVoxelVolume;
698 valid = false;
699 }
700 else if (voxelVolume > maximumVoxelVolume) {
701 voxelVolume = maximumVoxelVolume;
702 valid = false;
703 }
704
705 voxelSize = static_cast<float>(math::Pow(voxelVolume, 1.0/3.0));
706 return valid;
707 }
708
709 static float truncate(const float voxelSize, Index decPlaces)
710 {
711 float truncatedVoxelSize = voxelSize;
712
713 // attempt to truncate from decPlaces -> 11
714 for (int i = decPlaces; i < 11; i++) {
715 truncatedVoxelSize = static_cast<float>(math::Truncate(double(voxelSize), i));
716 if (truncatedVoxelSize != 0.0f) break;
717 }
718
719 return truncatedVoxelSize;
720 }
721 };
722
723 if (pointsPerVoxel == 0) OPENVDB_THROW(ValueError, "Points per voxel cannot be zero.");
724
725 // constructed with the default voxel size as specified by openvdb interface values
726
727 float voxelSize(0.1f);
728
729 const size_t numPoints = positions.size();
730
731 // return the default voxel size if we have zero or only 1 point
732
733 if (numPoints <= 1) return voxelSize;
734
735 size_t targetVoxelCount(numPoints / size_t(pointsPerVoxel));
736 if (targetVoxelCount == 0) targetVoxelCount++;
737
738 // calculate the world space, transform-oriented bounding box
739
740 math::Mat4d inverseTransform = transform.inverse();
741 inverseTransform = math::unit(inverseTransform);
742
743 tbb::blocked_range<size_t> range(0, numPoints);
744 CalculatePositionBounds<PositionWrapper, VecT> calculateBounds(positions, inverseTransform);
745 tbb::parallel_reduce(range, calculateBounds);
746
747 BBoxd bbox = calculateBounds.getBoundingBox();
748
749 // return default size if points are coincident
750
751 if (bbox.min() == bbox.max()) return voxelSize;
752
753 double volume = bbox.volume();
754
755 // handle points that are collinear or coplanar by expanding the volume
756
757 if (math::isApproxZero(volume)) {
758 Vec3d extents = bbox.extents().sorted().reversed();
759 if (math::isApproxZero(extents[1])) {
760 // colinear (maxExtent^3)
761 volume = extents[0]*extents[0]*extents[0];
762 }
763 else {
764 // coplanar (maxExtent*nextMaxExtent^2)
765 volume = extents[0]*extents[1]*extents[1];
766 }
767 }
768
769 double previousVolume = volume;
770
771 if (!Local::voxelSizeFromVolume(volume, targetVoxelCount, voxelSize)) {
772 OPENVDB_LOG_DEBUG("Out of range, clamping voxel size.");
773 return voxelSize;
774 }
775
776 size_t previousVoxelCount(0);
777 size_t voxelCount(1);
778
779 if (interrupter) interrupter->start("Computing voxel size");
780
781 while (voxelCount > previousVoxelCount)
782 {
783 math::Transform::Ptr newTransform;
784
785 if (!math::isIdentity(transform))
786 {
787 // if using a custom transform, pre-scale by coefficients
788 // which define the new voxel size
789
790 math::Mat4d matrix(transform);
791 matrix.preScale(Vec3d(voxelSize) / math::getScale(matrix));
792 newTransform = math::Transform::createLinearTransform(matrix);
793 }
794 else
795 {
796 newTransform = math::Transform::createLinearTransform(voxelSize);
797 }
798
799 // create a mask grid of the points from the calculated voxel size
800 // this is the same function call as tools::createPointMask() which has
801 // been duplicated to provide an interrupter
802
803 MaskGrid::Ptr mask = createGrid<MaskGrid>(false);
804 mask->setTransform(newTransform);
805 tools::PointsToMask<MaskGrid, InterrupterT> pointMaskOp(*mask, interrupter);
806 pointMaskOp.template addPoints<PositionWrapper, VecT>(positions);
807
808 if (interrupter && util::wasInterrupted(interrupter)) break;
809
810 previousVoxelCount = voxelCount;
811 voxelCount = mask->activeVoxelCount();
812 volume = math::Pow3(voxelSize) * static_cast<float>(voxelCount);
813
814 // stop if no change in the volume or the volume has increased
815
816 if (volume >= previousVolume) break;
817 previousVolume = volume;
818
819 const float previousVoxelSize = voxelSize;
820
821 // compute the new voxel size and if invalid return the previous value
822
823 if (!Local::voxelSizeFromVolume(volume, targetVoxelCount, voxelSize)) {
824 voxelSize = previousVoxelSize;
825 break;
826 }
827
828 // halt convergence if the voxel size has decreased by less
829 // than 10% in this iteration
830
831 if (voxelSize / previousVoxelSize > 0.9f) break;
832 }
833
834 if (interrupter) interrupter->end();
835
836 // truncate the voxel size for readability and return the value
837
838 return Local::truncate(voxelSize, decimalPlaces);
839}
840
841
842////////////////////////////////////////
843
844
845} // namespace points
846} // namespace OPENVDB_VERSION_NAME
847} // namespace openvdb
848
849#endif // OPENVDB_POINTS_POINT_CONVERSION_IMPL_HAS_BEEN_INCLUDED
openvdb::v11_0::Grid::Ptr
SharedPtr< Grid > Ptr
Definition Grid.h:573
openvdb::v11_0::KeyError
Definition Exceptions.h:59
openvdb::v11_0::Metadata
Base class for storing metadata information in a grid.
Definition Metadata.h:24
openvdb::v11_0::ValueError
Definition Exceptions.h:65
openvdb::v11_0::math::BBox< Vec3d >
openvdb::v11_0::math::BBox::max
const Vec3T & max() const
Return a const reference to the maximum point of this bounding box.
Definition BBox.h:64
openvdb::v11_0::math::BBox::volume
ElementType volume() const
Return the volume enclosed by this bounding box.
Definition BBox.h:100
openvdb::v11_0::math::BBox::extents
Vec3T extents() const
Return the extents of this bounding box, i.e., the length along each axis.
Definition BBox.h:253
openvdb::v11_0::math::BBox::min
const Vec3T & min() const
Return a const reference to the minimum point of this bounding box.
Definition BBox.h:62
openvdb::v11_0::math::Coord
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:25
openvdb::v11_0::math::Coord::asVec3d
Vec3d asVec3d() const
Definition Coord.h:143
openvdb::v11_0::math::Mat4< double >
openvdb::v11_0::math::Mat4::preScale
void preScale(const Vec3< T0 > &v)
Definition Mat4.h:736
openvdb::v11_0::math::Mat4::inverse
Mat4 inverse(T tolerance=0) const
Definition Mat4.h:485
openvdb::v11_0::math::Transform
Definition Transform.h:40
openvdb::v11_0::math::Transform::copy
Ptr copy() const
Definition Transform.h:50
openvdb::v11_0::math::Transform::worldToIndex
Vec3d worldToIndex(const Vec3d &xyz) const
Definition Transform.h:110
openvdb::v11_0::math::Transform::Ptr
SharedPtr< Transform > Ptr
Definition Transform.h:42
openvdb::v11_0::math::Vec3
Definition Vec3.h:24
openvdb::v11_0::math::Vec3::sorted
Vec3< T > sorted() const
Return a vector with the components of this in ascending order.
Definition Vec3.h:450
openvdb::v11_0::math::Vec3::reversed
Vec3< T > reversed() const
Return the vector (z, y, x)
Definition Vec3.h:460
openvdb::v11_0::points::AttributeArray::ScopedRegistryLock
Definition AttributeArray.h:119
openvdb::v11_0::points::AttributeSet::Descriptor::GroupIndex
Util::GroupIndex GroupIndex
Definition AttributeSet.h:318
openvdb::v11_0::points::AttributeWriteHandle
Write-able version of AttributeHandle.
Definition AttributeArray.h:904
openvdb::v11_0::points::PointAttributeVector
Point-partitioner compatible STL vector attribute wrapper for convenience.
Definition PointConversion.h:40
openvdb::v11_0::points::TypedAttributeArray
Typed class for storing attribute data.
Definition AttributeArray.h:545
openvdb::v11_0::tools::PointsToMask
Makes every voxel of a grid active if it contains a point.
Definition PointsToMask.h:107
openvdb::v11_0::tree::LeafManager
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition LeafManager.h:85
openvdb::v11_0::tree::LeafManager::tree
const TreeType & tree() const
Return a const reference to tree associated with this manager.
Definition LeafManager.h:302
openvdb::v11_0::tree::LeafManager::leafRange
LeafRange leafRange(size_t grainsize=1) const
Return a TBB-compatible LeafRange.
Definition LeafManager.h:345
OPENVDB_LOG_DEBUG
#define OPENVDB_LOG_DEBUG(message)
In debug builds only, log a debugging message of the form 'someVar << "text" << .....
Definition logging.h:266
nanovdb::GridBlindDataClass::AttributeArray
@ AttributeArray
openvdb::v11_0::math::Vec3d
Vec3< double > Vec3d
Definition Vec3.h:664
openvdb::v11_0::points::point_move_internal::IndexArray
std::vector< Index > IndexArray
Definition PointMoveImpl.h:88
openvdb::v11_0::points::convertPointDataGridGroup
void convertPointDataGridGroup(Group &group, const PointDataTreeT &tree, const std::vector< Index64 > &pointOffsets, const Index64 startOffset, const AttributeSet::Descriptor::GroupIndex index, const FilterT &filter=NullFilter(), const bool inCoreOnly=false)
Convert the group from a PointDataGrid.
Definition PointConversionImpl.h:647
openvdb::v11_0::points::pointOffsets
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 PointCountImpl.h:52
openvdb::v11_0::points::GroupType
uint8_t GroupType
Definition AttributeSet.h:31
openvdb::v11_0::points::computeVoxelSize
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 PointConversionImpl.h:675
openvdb::v11_0::points::pointCount
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 PointCountImpl.h:18
openvdb::v11_0::points::isGroup
bool isGroup(const AttributeArray &array)
Definition AttributeGroup.h:63
openvdb::v11_0::points::GroupAttributeArray
TypedAttributeArray< GroupType, GroupCodec > GroupAttributeArray
Definition AttributeGroup.h:40
openvdb::v11_0::points::createPointDataGrid
PointDataGridT::Ptr createPointDataGrid(const PointIndexGridT &pointIndexGrid, const PositionArrayT &positions, const math::Transform &xform, const Metadata *positionDefaultValue=nullptr)
Localises points with position into a PointDataGrid into two stages: allocation of the leaf attribute...
Definition PointConversionImpl.h:421
openvdb::v11_0::points::convertPointDataGridAttribute
void convertPointDataGridAttribute(TypedAttribute &attribute, const PointDataTreeT &tree, const std::vector< Index64 > &pointOffsets, const Index64 startOffset, const unsigned arrayIndex, const Index stride=1, const FilterT &filter=NullFilter(), const bool inCoreOnly=false)
Convert the attribute from a PointDataGrid.
Definition PointConversionImpl.h:615
openvdb::v11_0::points::convertPointDataGridPosition
void convertPointDataGridPosition(PositionAttribute &positionAttribute, const PointDataGridT &grid, const std::vector< Index64 > &pointOffsets, const Index64 startOffset, const FilterT &filter=NullFilter(), const bool inCoreOnly=false)
Convert the position attribute from a Point Data Grid.
Definition PointConversionImpl.h:581
openvdb::v11_0::points::populateAttribute
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 PointConversionImpl.h:544
openvdb::v11_0::tools::composite::max
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition Composite.h:110
openvdb::v11_0::Name
std::string Name
Definition Name.h:19
openvdb::v11_0::Index
Index32 Index
Definition Types.h:54
openvdb::v11_0::NamePair
std::pair< Name, Name > NamePair
Definition AttributeArray.h:39
openvdb::v11_0::Real
double Real
Definition Types.h:60
openvdb::v11_0::BBoxd
math::BBox< Vec3d > BBoxd
Definition Types.h:84
openvdb::v11_0::Index64
uint64_t Index64
Definition Types.h:53
openvdb
Definition Exceptions.h:13
std
Definition Coord.h:589
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:212