GCC Code Coverage Report


Directory: ./
File: openvdb/openvdb/points/PointConversion.h
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 215 216 99.5%
Functions: 65 68 95.6%
Branches: 230 464 49.6%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 /// @author Dan Bailey, Nick Avramoussis
5 ///
6 /// @file points/PointConversion.h
7 ///
8 /// @brief Convert points and attributes to and from VDB Point Data grids.
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
15 #include <openvdb/tools/PointIndexGrid.h>
16 #include <openvdb/tools/PointsToMask.h>
17 #include <openvdb/util/NullInterrupter.h>
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 {
31 OPENVDB_USE_VERSION_NAMESPACE
32 namespace OPENVDB_VERSION_NAME {
33 namespace points {
34
35
36 /// @brief Localises points with position into a @c PointDataGrid into two stages:
37 /// allocation of the leaf attribute data and population of the positions.
38 ///
39 /// @param pointIndexGrid a PointIndexGrid into the points.
40 /// @param positions list of world space point positions.
41 /// @param xform world to index space transform.
42 /// @param positionDefaultValue metadata default position value
43 ///
44 /// @note The position data must be supplied in a Point-Partitioner compatible
45 /// data structure. A convenience PointAttributeVector class is offered.
46 ///
47 /// @note The position data is populated separately to perform world space to
48 /// voxel space conversion and apply quantisation.
49 ///
50 /// @note A @c PointIndexGrid to the points must be supplied to perform this
51 /// operation. Typically this is built implicitly by the PointDataGrid constructor.
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 const Metadata* positionDefaultValue = nullptr);
63
64
65 /// @brief Convenience method to create a @c PointDataGrid from a std::vector of
66 /// point positions.
67 ///
68 /// @param positions list of world space point positions.
69 /// @param xform world to index space transform.
70 /// @param positionDefaultValue metadata default position value
71 ///
72 /// @note This method implicitly wraps the std::vector for a Point-Partitioner compatible
73 /// data structure and creates the required @c PointIndexGrid to the points.
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 const Metadata* positionDefaultValue = nullptr);
80
81
82 /// @brief Stores point attribute data in an existing @c PointDataGrid attribute.
83 ///
84 /// @param tree the PointDataGrid to be populated.
85 /// @param pointIndexTree a PointIndexTree into the points.
86 /// @param attributeName the name of the VDB Points attribute to be populated.
87 /// @param data a wrapper to the attribute data.
88 /// @param stride the stride of the attribute
89 /// @param insertMetadata true if strings are to be automatically inserted as metadata.
90 ///
91 /// @note A @c PointIndexGrid to the points must be supplied to perform this
92 /// operation. This is required to ensure the same point index ordering.
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
102 /// @brief Convert the position attribute from a Point Data Grid
103 ///
104 /// @param positionAttribute the position attribute to be populated.
105 /// @param grid the PointDataGrid to be converted.
106 /// @param pointOffsets a vector of cumulative point offsets for each leaf
107 /// @param startOffset a value to shift all the point offsets by
108 /// @param filter an index filter
109 /// @param inCoreOnly true if out-of-core leaf nodes are to be ignored
110 ///
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
122 /// @brief Convert the attribute from a PointDataGrid
123 ///
124 /// @param attribute the attribute to be populated.
125 /// @param tree the PointDataTree to be converted.
126 /// @param pointOffsets a vector of cumulative point offsets for each leaf.
127 /// @param startOffset a value to shift all the point offsets by
128 /// @param arrayIndex the index in the Descriptor of the array to be converted.
129 /// @param stride the stride of the attribute
130 /// @param filter an index filter
131 /// @param inCoreOnly true if out-of-core leaf nodes are to be ignored
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
144 /// @brief Convert the group from a PointDataGrid
145 ///
146 /// @param group the group to be populated.
147 /// @param tree the PointDataTree to be converted.
148 /// @param pointOffsets a vector of cumulative point offsets for each leaf
149 /// @param startOffset a value to shift all the point offsets by
150 /// @param index the group index to be converted.
151 /// @param filter an index filter
152 /// @param inCoreOnly true if out-of-core leaf nodes are to be ignored
153 ///
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
165 // for internal use only - this traits class extracts T::value_type if defined,
166 // otherwise falls back to using Vec3R
167 namespace internal {
168 template <typename...> using void_t = void;
169 template <typename T, typename = void>
170 struct ValueTypeTraits { using Type = Vec3R; /* default type if T::value_type is not defined*/ };
171 template <typename T>
172 struct ValueTypeTraits <T, void_t<typename T::value_type>> { using Type = typename T::value_type; };
173 } // namespace internal
174
175 /// @ brief Given a container of world space positions and a target points per voxel,
176 /// compute a uniform voxel size that would best represent the storage of the points in a grid.
177 /// This voxel size is typically used for conversion of the points into a PointDataGrid.
178 ///
179 /// @param positions array of world space positions
180 /// @param pointsPerVoxel the target number of points per voxel, must be positive and non-zero
181 /// @param transform voxel size will be computed using this optional transform if provided
182 /// @param decimalPlaces for readability, truncate voxel size to this number of decimals
183 /// @param interrupter an optional interrupter
184 ///
185 /// @note VecT will be PositionWrapper::value_type or Vec3R (if there is no value_type defined)
186 ///
187 /// @note if none or one point provided in positions, the default voxel size of 0.1 will be returned
188 ///
189 template< typename PositionWrapper,
190 typename InterrupterT = openvdb::util::NullInterrupter,
191 typename VecT = typename internal::ValueTypeTraits<PositionWrapper>::Type>
192 inline float
193 computeVoxelSize( const PositionWrapper& positions,
194 const uint32_t pointsPerVoxel,
195 const math::Mat4d transform = math::Mat4d::identity(),
196 const Index decimalPlaces = 5,
197 InterrupterT* const interrupter = nullptr);
198
199
200 ////////////////////////////////////////
201
202
203 /// @brief Point-partitioner compatible STL vector attribute wrapper for convenience
204 template<typename ValueType>
205 class PointAttributeVector {
206 public:
207 using PosType = ValueType;
208 using value_type= ValueType;
209
210 752 PointAttributeVector(const std::vector<value_type>& data,
211 const Index stride = 1)
212 : mData(data)
213
28/54
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 55 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 1 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 1 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 1 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 1 times.
✗ Branch 47 not taken.
✓ Branch 49 taken 1 times.
✗ Branch 50 not taken.
✓ Branch 52 taken 1 times.
✗ Branch 53 not taken.
✓ Branch 55 taken 1 times.
✗ Branch 56 not taken.
✓ Branch 58 taken 1 times.
✗ Branch 59 not taken.
✓ Branch 61 taken 1 times.
✗ Branch 62 not taken.
✓ Branch 64 taken 1 times.
✗ Branch 65 not taken.
✓ Branch 67 taken 1 times.
✗ Branch 68 not taken.
✓ Branch 70 taken 1 times.
✗ Branch 71 not taken.
✓ Branch 73 taken 1 times.
✗ Branch 74 not taken.
✓ Branch 76 taken 1 times.
✗ Branch 77 not taken.
748 , mStride(stride) { }
214
215
12/25
✓ Branch 0 taken 658 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 703 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 703 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 699 times.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
3984 size_t size() const { return mData.size(); }
216
5/14
✓ Branch 0 taken 5092 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 90004 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
95105 void getPos(size_t n, ValueType& xyz) const { xyz = mData[n]; }
217 void get(ValueType& value, size_t n) const { value = mData[n]; }
218 259 void get(ValueType& value, size_t n, openvdb::Index m) const { value = mData[n * mStride + m]; }
219
220 private:
221 const std::vector<value_type>& mData;
222 const Index mStride;
223 }; // PointAttributeVector
224
225
226 ////////////////////////////////////////
227
228 /// @cond OPENVDB_DOCS_INTERNAL
229
230 namespace point_conversion_internal {
231
232
233 // ConversionTraits to create the relevant Attribute Handles from a LeafNode
234 template <typename T> struct ConversionTraits
235 {
236 using Handle = AttributeHandle<T, UnknownCodec>;
237 using WriteHandle = AttributeWriteHandle<T, UnknownCodec>;
238 static T zero() { return zeroVal<T>(); }
239 template <typename LeafT>
240 static std::unique_ptr<Handle> handleFromLeaf(const LeafT& leaf, const Index index) {
241 const AttributeArray& array = leaf.constAttributeArray(index);
242
4/40
✓ Branch 1 taken 5800 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5800 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5407 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
17014 return std::make_unique<Handle>(array);
243 }
244 template <typename LeafT>
245 static std::unique_ptr<WriteHandle> writeHandleFromLeaf(LeafT& leaf, const Index index) {
246
19/40
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 4 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 4 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 8 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 20 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 16 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 4 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 4 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 4 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 8 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 32 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 4 times.
✗ Branch 47 not taken.
✓ Branch 49 taken 44 times.
✗ Branch 50 not taken.
✓ Branch 52 taken 4 times.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✓ Branch 58 taken 12 times.
✗ Branch 59 not taken.
11566 AttributeArray& array = leaf.attributeArray(index);
247
19/40
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 4 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 4 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 8 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 20 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 16 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 4 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 4 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 4 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 8 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 32 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 4 times.
✗ Branch 47 not taken.
✓ Branch 49 taken 44 times.
✗ Branch 50 not taken.
✓ Branch 52 taken 4 times.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✓ Branch 58 taken 12 times.
✗ Branch 59 not taken.
11566 return std::make_unique<WriteHandle>(array);
248 }
249 }; // ConversionTraits
250 template <> struct ConversionTraits<openvdb::Name>
251 {
252 using Handle = StringAttributeHandle;
253 using WriteHandle = StringAttributeWriteHandle;
254 static openvdb::Name zero() { return ""; }
255 template <typename LeafT>
256 5819 static std::unique_ptr<Handle> handleFromLeaf(const LeafT& leaf, const Index index) {
257 5819 const AttributeArray& array = leaf.constAttributeArray(index);
258 const AttributeSet::Descriptor& descriptor = leaf.attributeSet().descriptor();
259 5819 return std::make_unique<Handle>(array, descriptor.getMetadata());
260 }
261 template <typename LeafT>
262 3075 static std::unique_ptr<WriteHandle> writeHandleFromLeaf(LeafT& leaf, const Index index) {
263 3075 AttributeArray& array = leaf.attributeArray(index);
264 const AttributeSet::Descriptor& descriptor = leaf.attributeSet().descriptor();
265 3075 return std::make_unique<WriteHandle>(array, descriptor.getMetadata());
266 }
267 }; // ConversionTraits<openvdb::Name>
268
269 template< typename PointDataTreeType,
270 typename PointIndexTreeType,
271 typename AttributeListType>
272 struct PopulateAttributeOp {
273
274 using LeafManagerT = typename tree::LeafManager<PointDataTreeType>;
275 using LeafRangeT = typename LeafManagerT::LeafRange;
276 using PointIndexLeafNode = typename PointIndexTreeType::LeafNodeType;
277 using IndexArray = typename PointIndexLeafNode::IndexArray;
278 using ValueType = typename AttributeListType::value_type;
279 using HandleT = typename ConversionTraits<ValueType>::WriteHandle;
280
281 47 PopulateAttributeOp(const PointIndexTreeType& pointIndexTree,
282 const AttributeListType& data,
283 const size_t index,
284 const Index stride = 1)
285 : mPointIndexTree(pointIndexTree)
286 , mData(data)
287 , mIndex(index)
288
3/6
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
47 , mStride(stride) { }
289
290 1700 void operator()(const typename LeafManagerT::LeafRange& range) const {
291
292
2/2
✓ Branch 1 taken 14269 times.
✓ Branch 2 taken 873 times.
30192 for (auto leaf = range.begin(); leaf; ++leaf) {
293
294 // obtain the PointIndexLeafNode (using the origin of the current leaf)
295
296 const PointIndexLeafNode* pointIndexLeaf =
297 28492 mPointIndexTree.probeConstLeaf(leaf->origin());
298
299
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14269 times.
28492 if (!pointIndexLeaf) continue;
300
301 11628 auto attributeWriteHandle =
302 28492 ConversionTraits<ValueType>::writeHandleFromLeaf(*leaf, static_cast<Index>(mIndex));
303
304 Index64 index = 0;
305
306 const IndexArray& indices = pointIndexLeaf->indices();
307
308
2/2
✓ Branch 0 taken 3080312 times.
✓ Branch 1 taken 14269 times.
6189049 for (const Index64 leafIndex: indices)
309 {
310 ValueType value;
311
2/2
✓ Branch 0 taken 3160322 times.
✓ Branch 1 taken 3080312 times.
12481134 for (Index i = 0; i < mStride; i++) {
312
1/2
✓ Branch 1 taken 3160322 times.
✗ Branch 2 not taken.
6320577 mData.get(value, leafIndex, i);
313
1/2
✓ Branch 1 taken 3160322 times.
✗ Branch 2 not taken.
6320577 attributeWriteHandle->set(static_cast<Index>(index), i, value);
314 }
315 6160557 index++;
316 }
317
318 // attempt to compact the array
319
320
1/2
✓ Branch 1 taken 14269 times.
✗ Branch 2 not taken.
28492 attributeWriteHandle->compact();
321 }
322 1700 }
323
324 //////////
325
326 const PointIndexTreeType& mPointIndexTree;
327 const AttributeListType& mData;
328 const size_t mIndex;
329 const Index mStride;
330 };
331
332 template<typename PointDataTreeType, typename Attribute, typename FilterT>
333 struct ConvertPointDataGridPositionOp {
334
335 using LeafNode = typename PointDataTreeType::LeafNodeType;
336 using ValueType = typename Attribute::ValueType;
337 using HandleT = typename Attribute::Handle;
338 using SourceHandleT = AttributeHandle<ValueType>;
339 using LeafManagerT = typename tree::LeafManager<const PointDataTreeType>;
340 using LeafRangeT = typename LeafManagerT::LeafRange;
341
342 4 ConvertPointDataGridPositionOp( Attribute& attribute,
343 const std::vector<Index64>& pointOffsets,
344 const Index64 startOffset,
345 const math::Transform& transform,
346 const size_t index,
347 const FilterT& filter,
348 const bool inCoreOnly)
349 : mAttribute(attribute)
350 , mPointOffsets(pointOffsets)
351 , mStartOffset(startOffset)
352 , mTransform(transform)
353 , mIndex(index)
354 , mFilter(filter)
355
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 , mInCoreOnly(inCoreOnly)
356 {
357 // only accept Vec3f as ValueType
358 static_assert(VecTraits<ValueType>::Size == 3 &&
359 std::is_floating_point<typename ValueType::ValueType>::value,
360 "ValueType is not Vec3f");
361 }
362
363 template <typename IterT>
364 17014 void convert(IterT& iter, HandleT& targetHandle,
365 SourceHandleT& sourceHandle, Index64& offset) const
366 {
367
2/2
✓ Branch 0 taken 1540021 times.
✓ Branch 1 taken 8507 times.
3097056 for (; iter; ++iter) {
368 3080042 const Vec3d xyz = iter.getCoord().asVec3d();
369 3080042 const Vec3d pos = sourceHandle.get(*iter);
370 3080042 targetHandle.set(static_cast<Index>(offset++), /*stride=*/0,
371 3080042 mTransform.indexToWorld(pos + xyz));
372 }
373 17014 }
374
375 882 void operator()(const LeafRangeT& range) const
376 {
377 882 HandleT pHandle(mAttribute);
378
379
2/2
✓ Branch 1 taken 8507 times.
✓ Branch 2 taken 441 times.
17896 for (auto leaf = range.begin(); leaf; ++leaf) {
380
381
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8507 times.
17014 assert(leaf.pos() < mPointOffsets.size());
382
383
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 8507 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
17014 if (mInCoreOnly && leaf->buffer().isOutOfCore()) continue;
384
385
2/2
✓ Branch 0 taken 8503 times.
✓ Branch 1 taken 4 times.
17014 Index64 offset = mStartOffset;
386
387
2/2
✓ Branch 0 taken 8503 times.
✓ Branch 1 taken 4 times.
17014 if (leaf.pos() > 0) offset += mPointOffsets[leaf.pos() - 1];
388
389
2/4
✓ Branch 1 taken 8507 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8507 times.
✗ Branch 5 not taken.
17014 auto handle = SourceHandleT::create(leaf->constAttributeArray(mIndex));
390
391
2/2
✓ Branch 0 taken 2900 times.
✓ Branch 1 taken 2900 times.
11600 if (mFilter.state() == index::ALL) {
392
1/2
✓ Branch 1 taken 5607 times.
✗ Branch 2 not taken.
11214 auto iter = leaf->beginIndexOn();
393
1/2
✓ Branch 1 taken 5607 times.
✗ Branch 2 not taken.
11214 convert(iter, pHandle, *handle, offset);
394 }
395 else {
396 auto iter = leaf->beginIndexOn(mFilter);
397
1/2
✓ Branch 1 taken 2900 times.
✗ Branch 2 not taken.
5800 convert(iter, pHandle, *handle, offset);
398 }
399 }
400 882 }
401
402 //////////
403
404 Attribute& mAttribute;
405 const std::vector<Index64>& mPointOffsets;
406 const Index64 mStartOffset;
407 const math::Transform& mTransform;
408 const size_t mIndex;
409 const FilterT& mFilter;
410 const bool mInCoreOnly;
411 }; // ConvertPointDataGridPositionOp
412
413
414 template<typename PointDataTreeType, typename Attribute, typename FilterT>
415 struct ConvertPointDataGridAttributeOp {
416
417 using LeafNode = typename PointDataTreeType::LeafNodeType;
418 using ValueType = typename Attribute::ValueType;
419 using HandleT = typename Attribute::Handle;
420 using SourceHandleT = typename ConversionTraits<ValueType>::Handle;
421 using LeafManagerT = typename tree::LeafManager<const PointDataTreeType>;
422 using LeafRangeT = typename LeafManagerT::LeafRange;
423
424 11 ConvertPointDataGridAttributeOp(Attribute& attribute,
425 const std::vector<Index64>& pointOffsets,
426 const Index64 startOffset,
427 const size_t index,
428 const Index stride,
429 const FilterT& filter,
430 const bool inCoreOnly)
431 : mAttribute(attribute)
432 , mPointOffsets(pointOffsets)
433 , mStartOffset(startOffset)
434 , mIndex(index)
435 , mStride(stride)
436 , mFilter(filter)
437 11 , mInCoreOnly(inCoreOnly) { }
438
439 template <typename IterT>
440 45642 void convert(IterT& iter, HandleT& targetHandle,
441 SourceHandleT& sourceHandle, Index64& offset) const
442 {
443
3/3
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 11740 times.
✓ Branch 2 taken 11006 times.
45642 if (sourceHandle.isUniform()) {
444 12166 const ValueType uniformValue(sourceHandle.get(0));
445
2/2
✓ Branch 0 taken 1500304 times.
✓ Branch 1 taken 6083 times.
3012774 for (; iter; ++iter) {
446
2/2
✓ Branch 0 taken 1500304 times.
✓ Branch 1 taken 1500304 times.
6001216 for (Index i = 0; i < mStride; i++) {
447
1/2
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
3000608 targetHandle.set(static_cast<Index>(offset), i, uniformValue);
448 }
449
1/2
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
3000608 offset++;
450 }
451 }
452 else {
453
2/2
✓ Branch 0 taken 3079759 times.
✓ Branch 1 taken 16738 times.
6192994 for (; iter; ++iter) {
454
2/2
✓ Branch 0 taken 3159759 times.
✓ Branch 1 taken 3079759 times.
12479036 for (Index i = 0; i < mStride; i++) {
455
1/2
✓ Branch 3 taken 1499929 times.
✗ Branch 4 not taken.
9319376 targetHandle.set(static_cast<Index>(offset), i,
456 sourceHandle.get(*iter, /*stride=*/i));
457 }
458 6159518 offset++;
459 }
460 }
461 45642 }
462
463 2266 void operator()(const LeafRangeT& range) const
464 {
465 2266 HandleT pHandle(mAttribute);
466
467
2/2
✓ Branch 1 taken 22821 times.
✓ Branch 2 taken 1133 times.
47908 for (auto leaf = range.begin(); leaf; ++leaf) {
468
469
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22821 times.
45642 assert(leaf.pos() < mPointOffsets.size());
470
471
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 22821 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
45642 if (mInCoreOnly && leaf->buffer().isOutOfCore()) continue;
472
473
2/2
✓ Branch 0 taken 22810 times.
✓ Branch 1 taken 11 times.
45642 Index64 offset = mStartOffset;
474
475
2/2
✓ Branch 0 taken 22810 times.
✓ Branch 1 taken 11 times.
45642 if (leaf.pos() > 0) offset += mPointOffsets[leaf.pos() - 1];
476
477
1/2
✓ Branch 1 taken 5807 times.
✗ Branch 2 not taken.
23228 auto handle = ConversionTraits<ValueType>::handleFromLeaf(
478 45642 *leaf, static_cast<Index>(mIndex));
479
480
2/2
✓ Branch 0 taken 8700 times.
✓ Branch 1 taken 8700 times.
34800 if (mFilter.state() == index::ALL) {
481
1/2
✓ Branch 1 taken 14121 times.
✗ Branch 2 not taken.
28242 auto iter = leaf->beginIndexOn();
482
1/2
✓ Branch 1 taken 14121 times.
✗ Branch 2 not taken.
28242 convert(iter, pHandle, *handle, offset);
483 } else {
484 auto iter = leaf->beginIndexOn(mFilter);
485
1/2
✓ Branch 1 taken 8700 times.
✗ Branch 2 not taken.
17400 convert(iter, pHandle, *handle, offset);
486 }
487 }
488 2266 }
489
490 //////////
491
492 Attribute& mAttribute;
493 const std::vector<Index64>& mPointOffsets;
494 const Index64 mStartOffset;
495 const size_t mIndex;
496 const Index mStride;
497 const FilterT& mFilter;
498 const bool mInCoreOnly;
499 }; // ConvertPointDataGridAttributeOp
500
501 template<typename PointDataTreeType, typename Group, typename FilterT>
502 struct ConvertPointDataGridGroupOp {
503
504 using LeafNode = typename PointDataTreeType::LeafNodeType;
505 using GroupIndex = AttributeSet::Descriptor::GroupIndex;
506 using LeafManagerT = typename tree::LeafManager<const PointDataTreeType>;
507 using LeafRangeT = typename LeafManagerT::LeafRange;
508
509 3 ConvertPointDataGridGroupOp(Group& group,
510 const std::vector<Index64>& pointOffsets,
511 const Index64 startOffset,
512 const AttributeSet::Descriptor::GroupIndex index,
513 const FilterT& filter,
514 const bool inCoreOnly)
515 : mGroup(group)
516 , mPointOffsets(pointOffsets)
517 , mStartOffset(startOffset)
518 , mIndex(index)
519 , mFilter(filter)
520 3 , mInCoreOnly(inCoreOnly) { }
521
522 template <typename IterT>
523 11614 void convert(IterT& iter, const GroupAttributeArray& groupArray, Index64& offset) const
524 {
525
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 5732 times.
11614 const auto bitmask = static_cast<GroupType>(1 << mIndex.second);
526
527
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 5732 times.
11614 if (groupArray.isUniform()) {
528
2/2
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 38 times.
150 if (groupArray.get(0) & bitmask) {
529
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 37 times.
196 for (; iter; ++iter) {
530 122 mGroup.setOffsetOn(static_cast<Index>(offset));
531 122 offset++;
532 }
533 }
534 }
535 else {
536
2/2
✓ Branch 0 taken 1499929 times.
✓ Branch 1 taken 5732 times.
3011322 for (; iter; ++iter) {
537
2/2
✓ Branch 2 taken 999948 times.
✓ Branch 3 taken 499981 times.
2999858 if (groupArray.get(*iter) & bitmask) {
538 1999896 mGroup.setOffsetOn(static_cast<Index>(offset));
539 }
540 2999858 offset++;
541 }
542 }
543 11614 }
544
545 540 void operator()(const LeafRangeT& range) const
546 {
547
2/2
✓ Branch 1 taken 5807 times.
✓ Branch 2 taken 270 times.
12154 for (auto leaf = range.begin(); leaf; ++leaf) {
548
549
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5807 times.
11614 assert(leaf.pos() < mPointOffsets.size());
550
551
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 5807 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
11614 if (mInCoreOnly && leaf->buffer().isOutOfCore()) continue;
552
553
2/2
✓ Branch 0 taken 5804 times.
✓ Branch 1 taken 3 times.
11614 Index64 offset = mStartOffset;
554
555
2/2
✓ Branch 0 taken 5804 times.
✓ Branch 1 taken 3 times.
11614 if (leaf.pos() > 0) offset += mPointOffsets[leaf.pos() - 1];
556
557 11614 const AttributeArray& array = leaf->constAttributeArray(mIndex.first);
558
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5807 times.
11614 assert(isGroup(array));
559 11614 const GroupAttributeArray& groupArray = GroupAttributeArray::cast(array);
560
561
2/2
✓ Branch 0 taken 2900 times.
✓ Branch 1 taken 2900 times.
11600 if (mFilter.state() == index::ALL) {
562 5814 auto iter = leaf->beginIndexOn();
563 5814 convert(iter, groupArray, offset);
564 }
565 else {
566 auto iter = leaf->beginIndexOn(mFilter);
567
1/2
✓ Branch 1 taken 2900 times.
✗ Branch 2 not taken.
5800 convert(iter, groupArray, offset);
568 }
569 }
570 540 }
571
572 //////////
573
574 Group& mGroup;
575 const std::vector<Index64>& mPointOffsets;
576 const Index64 mStartOffset;
577 const GroupIndex mIndex;
578 const FilterT& mFilter;
579 const bool mInCoreOnly;
580 }; // ConvertPointDataGridGroupOp
581
582 template<typename PositionArrayT, typename VecT = Vec3R>
583 struct CalculatePositionBounds
584 {
585 CalculatePositionBounds(const PositionArrayT& positions,
586 const math::Mat4d& inverse)
587 : mPositions(positions)
588 , mInverseMat(inverse)
589 , mMin(std::numeric_limits<Real>::max())
590 32 , mMax(-std::numeric_limits<Real>::max()) {}
591
592 57 CalculatePositionBounds(const CalculatePositionBounds& other, tbb::split)
593 57 : mPositions(other.mPositions)
594 57 , mInverseMat(other.mInverseMat)
595 , mMin(std::numeric_limits<Real>::max())
596 57 , mMax(-std::numeric_limits<Real>::max()) {}
597
598 3482 void operator()(const tbb::blocked_range<size_t>& range) {
599 VecT pos;
600
2/2
✓ Branch 0 taken 1108087 times.
✓ Branch 1 taken 1741 times.
2219656 for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
601 2216174 mPositions.getPos(n, pos);
602 2216174 pos = mInverseMat.transform(pos);
603 2216174 mMin = math::minComponent(mMin, pos);
604 2216174 mMax = math::maxComponent(mMax, pos);
605 }
606 3482 }
607
608 114 void join(const CalculatePositionBounds& other) {
609 114 mMin = math::minComponent(mMin, other.mMin);
610 114 mMax = math::maxComponent(mMax, other.mMax);
611 }
612
613 BBoxd getBoundingBox() const {
614
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 25 times.
30 return BBoxd(mMin, mMax);
615 }
616
617 private:
618 const PositionArrayT& mPositions;
619 const math::Mat4d& mInverseMat;
620 VecT mMin, mMax;
621 };
622
623 } // namespace point_conversion_internal
624
625 /// @endcond
626
627 ////////////////////////////////////////
628
629
630 template<typename CompressionT, typename PointDataGridT, typename PositionArrayT, typename PointIndexGridT>
631 inline typename PointDataGridT::Ptr
632 740 createPointDataGrid(const PointIndexGridT& pointIndexGrid,
633 const PositionArrayT& positions,
634 const math::Transform& xform,
635 const Metadata* positionDefaultValue)
636 {
637 using PointDataTreeT = typename PointDataGridT::TreeType;
638 using LeafT = typename PointDataTreeT::LeafNodeType;
639 using PointIndexLeafT = typename PointIndexGridT::TreeType::LeafNodeType;
640 using PointIndexT = typename PointIndexLeafT::ValueType;
641 using LeafManagerT = typename tree::LeafManager<PointDataTreeT>;
642 using PositionAttributeT = TypedAttributeArray<Vec3f, CompressionT>;
643
644 1480 const NamePair positionType = PositionAttributeT::attributeType();
645
646 // construct the Tree using a topology copy of the PointIndexGrid
647
648 const auto& pointIndexTree = pointIndexGrid.tree();
649
2/4
✓ Branch 1 taken 724 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 724 times.
✗ Branch 5 not taken.
740 typename PointDataTreeT::Ptr treePtr(new PointDataTreeT(pointIndexTree));
650
651 // create attribute descriptor from position type
652
653
1/2
✓ Branch 1 taken 724 times.
✗ Branch 2 not taken.
740 auto descriptor = AttributeSet::Descriptor::create(positionType);
654
655 // add default value for position if provided
656
657
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 724 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
740 if (positionDefaultValue) descriptor->setDefaultValue("P", *positionDefaultValue);
658
659 // retrieve position index
660
661
2/4
✓ Branch 1 taken 724 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 724 times.
✗ Branch 5 not taken.
740 const size_t positionIndex = descriptor->find("P");
662
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 724 times.
740 assert(positionIndex != AttributeSet::INVALID_POS);
663
664 // acquire registry lock to avoid locking when appending attributes in parallel
665
666
1/2
✓ Branch 1 taken 724 times.
✗ Branch 2 not taken.
740 AttributeArray::ScopedRegistryLock lock;
667
668 // populate position attribute
669
670
1/2
✓ Branch 1 taken 724 times.
✗ Branch 2 not taken.
740 LeafManagerT leafManager(*treePtr);
671
1/2
✓ Branch 1 taken 724 times.
✗ Branch 2 not taken.
740 leafManager.foreach(
672
1/2
✓ Branch 2 taken 5090 times.
✗ Branch 3 not taken.
1544957 [&](LeafT& leaf, size_t /*idx*/) {
673
674 // obtain the PointIndexLeafNode (using the origin of the current leaf)
675
676 const auto* pointIndexLeaf = pointIndexTree.probeConstLeaf(leaf.origin());
677
3/8
✗ Branch 0 not taken.
✓ Branch 1 taken 4304 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 26611 times.
30917 assert(pointIndexLeaf);
678
679 // initialise the attribute storage
680
681 30917 Index pointCount(static_cast<Index>(pointIndexLeaf->indices().size()));
682 30917 leaf.initializeAttributes(descriptor, pointCount, &lock);
683
684 // create write handle for position
685
686 30917 auto attributeWriteHandle = AttributeWriteHandle<Vec3f, CompressionT>::create(
687 leaf.attributeArray(positionIndex));
688
689 Index index = 0;
690
691 const PointIndexT
692 30917 *begin = static_cast<PointIndexT*>(nullptr),
693 30917 *end = static_cast<PointIndexT*>(nullptr);
694
695 // iterator over every active voxel in the point index leaf
696
697
6/8
✓ Branch 0 taken 44763 times.
✓ Branch 1 taken 4304 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 366490 times.
✓ Branch 7 taken 26611 times.
442172 for (auto iter = pointIndexLeaf->cbeginValueOn(); iter; ++iter) {
698
699 // find the voxel center
700
701
3/8
✓ Branch 1 taken 44763 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 10 taken 366490 times.
✗ Branch 11 not taken.
411255 const Coord& ijk = iter.getCoord();
702 const Vec3d& positionCellCenter(ijk.asVec3d());
703
704 // obtain pointers for this voxel from begin to end in the indices array
705
706
3/8
✓ Branch 1 taken 44763 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 10 taken 366490 times.
✗ Branch 11 not taken.
411255 pointIndexLeaf->getIndices(ijk, begin, end);
707
708
6/8
✓ Branch 0 taken 95096 times.
✓ Branch 1 taken 44763 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1388025 times.
✓ Branch 7 taken 366490 times.
1894378 while (begin < end) {
709
710 typename PositionArrayT::value_type positionWorldSpace;
711
3/8
✓ Branch 1 taken 95095 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 10 taken 1388025 times.
✗ Branch 11 not taken.
1483122 positions.getPos(*begin, positionWorldSpace);
712
713 // compute the index-space position and then subtract the voxel center
714
715
0/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
1391706 const Vec3d positionIndexSpace = xform.worldToIndex(positionWorldSpace);
716 1483123 const Vec3f positionVoxelSpace(positionIndexSpace - positionCellCenter);
717
718 1483123 attributeWriteHandle->set(index++, positionVoxelSpace);
719
720 1483123 ++begin;
721 }
722 }
723 },
724 /*threaded=*/true);
725
726
2/4
✓ Branch 1 taken 724 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 724 times.
✗ Branch 5 not taken.
1480 auto grid = PointDataGridT::create(treePtr);
727
2/6
✓ Branch 1 taken 724 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 724 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
1480 grid->setTransform(xform.copy());
728 740 return grid;
729 }
730
731
732 ////////////////////////////////////////
733
734
735 template <typename CompressionT, typename PointDataGridT, typename ValueT>
736 inline typename PointDataGridT::Ptr
737 620 createPointDataGrid(const std::vector<ValueT>& positions,
738 const math::Transform& xform,
739 const Metadata* positionDefaultValue)
740 {
741 const PointAttributeVector<ValueT> pointList(positions);
742
743 620 tools::PointIndexGrid::Ptr pointIndexGrid =
744 tools::createPointIndexGrid<tools::PointIndexGrid>(pointList, xform);
745 return createPointDataGrid<CompressionT, PointDataGridT>(
746
1/2
✓ Branch 1 taken 615 times.
✗ Branch 2 not taken.
1240 *pointIndexGrid, pointList, xform, positionDefaultValue);
747 }
748
749
750 ////////////////////////////////////////
751
752
753 template <typename PointDataTreeT, typename PointIndexTreeT, typename PointArrayT>
754 inline void
755 55 populateAttribute(PointDataTreeT& tree, const PointIndexTreeT& pointIndexTree,
756 const openvdb::Name& attributeName, const PointArrayT& data, const Index stride,
757 const bool insertMetadata)
758 {
759 using point_conversion_internal::PopulateAttributeOp;
760 using ValueType = typename PointArrayT::value_type;
761
762 auto iter = tree.cbeginLeaf();
763
764
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
55 if (!iter) return;
765
766 55 const size_t index = iter->attributeSet().find(attributeName);
767
768
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
55 if (index == AttributeSet::INVALID_POS) {
769 OPENVDB_THROW(KeyError, "Attribute not found to populate - " << attributeName << ".");
770 }
771
772
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 if (insertMetadata) {
773 4 point_attribute_internal::MetadataStorage<PointDataTreeT, ValueType>::add(tree, data);
774 }
775
776 // populate attribute
777
778 55 typename tree::LeafManager<PointDataTreeT> leafManager(tree);
779
780 PopulateAttributeOp<PointDataTreeT,
781 PointIndexTreeT,
782 PointArrayT> populate(pointIndexTree, data, index, stride);
783
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
55 tbb::parallel_for(leafManager.leafRange(), populate);
784 }
785
786
787 ////////////////////////////////////////
788
789
790 template <typename PositionAttribute, typename PointDataGridT, typename FilterT>
791 inline void
792 8 convertPointDataGridPosition( PositionAttribute& positionAttribute,
793 const PointDataGridT& grid,
794 const std::vector<Index64>& pointOffsets,
795 const Index64 startOffset,
796 const FilterT& filter,
797 const bool inCoreOnly)
798 {
799 using TreeType = typename PointDataGridT::TreeType;
800 using LeafManagerT = typename tree::LeafManager<const TreeType>;
801
802 using point_conversion_internal::ConvertPointDataGridPositionOp;
803
804 const TreeType& tree = grid.tree();
805 auto iter = tree.cbeginLeaf();
806
807
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
8 if (!iter) return;
808
809
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 const size_t positionIndex = iter->attributeSet().find("P");
810
811 positionAttribute.expand();
812 8 LeafManagerT leafManager(tree);
813 ConvertPointDataGridPositionOp<TreeType, PositionAttribute, FilterT> convert(
814 positionAttribute, pointOffsets, startOffset, grid.transform(), positionIndex,
815 filter, inCoreOnly);
816
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 tbb::parallel_for(leafManager.leafRange(), convert);
817 positionAttribute.compact();
818 }
819
820
821 ////////////////////////////////////////
822
823
824 template <typename TypedAttribute, typename PointDataTreeT, typename FilterT>
825 inline void
826 22 convertPointDataGridAttribute( TypedAttribute& attribute,
827 const PointDataTreeT& tree,
828 const std::vector<Index64>& pointOffsets,
829 const Index64 startOffset,
830 const unsigned arrayIndex,
831 const Index stride,
832 const FilterT& filter,
833 const bool inCoreOnly)
834 {
835 using LeafManagerT = typename tree::LeafManager<const PointDataTreeT>;
836
837 using point_conversion_internal::ConvertPointDataGridAttributeOp;
838
839 auto iter = tree.cbeginLeaf();
840
841
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
22 if (!iter) return;
842
843 attribute.expand();
844 22 LeafManagerT leafManager(tree);
845
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
22 ConvertPointDataGridAttributeOp<PointDataTreeT, TypedAttribute, FilterT> convert(
846 attribute, pointOffsets, startOffset, arrayIndex, stride,
847 filter, inCoreOnly);
848
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
22 tbb::parallel_for(leafManager.leafRange(), convert);
849 attribute.compact();
850 }
851
852
853 ////////////////////////////////////////
854
855
856 template <typename Group, typename PointDataTreeT, typename FilterT>
857 inline void
858 6 convertPointDataGridGroup( Group& group,
859 const PointDataTreeT& tree,
860 const std::vector<Index64>& pointOffsets,
861 const Index64 startOffset,
862 const AttributeSet::Descriptor::GroupIndex index,
863 const FilterT& filter,
864 const bool inCoreOnly)
865 {
866 using LeafManagerT= typename tree::LeafManager<const PointDataTreeT>;
867
868 using point_conversion_internal::ConvertPointDataGridGroupOp;
869
870 auto iter = tree.cbeginLeaf();
871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
6 if (!iter) return;
872
873 6 LeafManagerT leafManager(tree);
874
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 ConvertPointDataGridGroupOp<PointDataTreeT, Group, FilterT> convert(
875 group, pointOffsets, startOffset, index,
876 filter, inCoreOnly);
877
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 tbb::parallel_for(leafManager.leafRange(), convert);
878
879 // must call this after modifying point groups in parallel
880
881 group.finalize();
882 }
883
884 template<typename PositionWrapper, typename InterrupterT, typename VecT>
885 inline float
886 34 computeVoxelSize( const PositionWrapper& positions,
887 const uint32_t pointsPerVoxel,
888 const math::Mat4d transform,
889 const Index decimalPlaces,
890 InterrupterT* const interrupter)
891 {
892 using namespace point_conversion_internal;
893
894 struct Local {
895
896 static bool voxelSizeFromVolume(const double volume,
897 const size_t estimatedVoxelCount,
898 float& voxelSize)
899 {
900 // dictated by the math::ScaleMap limit
901 static const double minimumVoxelVolume(3e-15);
902 static const double maximumVoxelVolume(std::numeric_limits<float>::max());
903
904 130 double voxelVolume = volume / static_cast<double>(estimatedVoxelCount);
905 bool valid = true;
906
907 130 if (voxelVolume < minimumVoxelVolume) {
908 voxelVolume = minimumVoxelVolume;
909 valid = false;
910 }
911 122 else if (voxelVolume > maximumVoxelVolume) {
912 voxelVolume = maximumVoxelVolume;
913 valid = false;
914 }
915
916 130 voxelSize = static_cast<float>(math::Pow(voxelVolume, 1.0/3.0));
917 return valid;
918 }
919
920 static float truncate(const float voxelSize, Index decPlaces)
921 {
922 float truncatedVoxelSize = voxelSize;
923
924 // attempt to truncate from decPlaces -> 11
925 28 for (int i = decPlaces; i < 11; i++) {
926 28 truncatedVoxelSize = static_cast<float>(math::Truncate(double(voxelSize), i));
927 28 if (truncatedVoxelSize != 0.0f) break;
928 }
929
930 return truncatedVoxelSize;
931 }
932 };
933
934 34 if (pointsPerVoxel == 0) OPENVDB_THROW(ValueError, "Points per voxel cannot be zero.");
935
936 // constructed with the default voxel size as specified by openvdb interface values
937
938 float voxelSize(0.1f);
939
940 const size_t numPoints = positions.size();
941
942 // return the default voxel size if we have zero or only 1 point
943
944 34 if (numPoints <= 1) return voxelSize;
945
946 32 size_t targetVoxelCount(numPoints / size_t(pointsPerVoxel));
947 32 if (targetVoxelCount == 0) targetVoxelCount++;
948
949 // calculate the world space, transform-oriented bounding box
950
951 32 math::Mat4d inverseTransform = transform.inverse();
952 32 inverseTransform = math::unit(inverseTransform);
953
954 tbb::blocked_range<size_t> range(0, numPoints);
955 CalculatePositionBounds<PositionWrapper, VecT> calculateBounds(positions, inverseTransform);
956 32 tbb::parallel_reduce(range, calculateBounds);
957
958 BBoxd bbox = calculateBounds.getBoundingBox();
959
960 // return default size if points are coincident
961
962 if (bbox.min() == bbox.max()) return voxelSize;
963
964 double volume = bbox.volume();
965
966 // handle points that are collinear or coplanar by expanding the volume
967
968 if (math::isApproxZero(volume)) {
969 12 Vec3d extents = bbox.extents().sorted().reversed();
970 if (math::isApproxZero(extents[1])) {
971 // colinear (maxExtent^3)
972 8 volume = extents[0]*extents[0]*extents[0];
973 }
974 else {
975 // coplanar (maxExtent*nextMaxExtent^2)
976 4 volume = extents[0]*extents[1]*extents[1];
977 }
978 }
979
980 double previousVolume = volume;
981
982 32 if (!Local::voxelSizeFromVolume(volume, targetVoxelCount, voxelSize)) {
983 OPENVDB_LOG_DEBUG("Out of range, clamping voxel size.");
984 return voxelSize;
985 }
986
987 size_t previousVoxelCount(0);
988 size_t voxelCount(1);
989
990 23 if (interrupter) interrupter->start("Computing voxel size");
991
992 109 while (voxelCount > previousVoxelCount)
993 {
994 104 math::Transform::Ptr newTransform;
995
996 104 if (!math::isIdentity(transform))
997 {
998 // if using a custom transform, pre-scale by coefficients
999 // which define the new voxel size
1000
1001 16 math::Mat4d matrix(transform);
1002 16 matrix.preScale(Vec3d(voxelSize) / math::getScale(matrix));
1003 32 newTransform = math::Transform::createLinearTransform(matrix);
1004 }
1005 else
1006 {
1007 176 newTransform = math::Transform::createLinearTransform(voxelSize);
1008 }
1009
1010 // create a mask grid of the points from the calculated voxel size
1011 // this is the same function call as tools::createPointMask() which has
1012 // been duplicated to provide an interrupter
1013
1014 104 MaskGrid::Ptr mask = createGrid<MaskGrid>(false);
1015 208 mask->setTransform(newTransform);
1016 tools::PointsToMask<MaskGrid, InterrupterT> pointMaskOp(*mask, interrupter);
1017 104 pointMaskOp.template addPoints<PositionWrapper, VecT>(positions);
1018
1019 104 if (interrupter && util::wasInterrupted(interrupter)) break;
1020
1021 previousVoxelCount = voxelCount;
1022 104 voxelCount = mask->activeVoxelCount();
1023 104 volume = math::Pow3(voxelSize) * static_cast<float>(voxelCount);
1024
1025 // stop if no change in the volume or the volume has increased
1026
1027 104 if (volume >= previousVolume) break;
1028 previousVolume = volume;
1029
1030 const float previousVoxelSize = voxelSize;
1031
1032 // compute the new voxel size and if invalid return the previous value
1033
1034 98 if (!Local::voxelSizeFromVolume(volume, targetVoxelCount, voxelSize)) {
1035 voxelSize = previousVoxelSize;
1036 break;
1037 }
1038
1039 // halt convergence if the voxel size has decreased by less
1040 // than 10% in this iteration
1041
1042 96 if (voxelSize / previousVoxelSize > 0.9f) break;
1043 }
1044
1045 23 if (interrupter) interrupter->end();
1046
1047 // truncate the voxel size for readability and return the value
1048
1049 return Local::truncate(voxelSize, decimalPlaces);
1050 }
1051
1052
1053 ////////////////////////////////////////
1054
1055
1056 } // namespace points
1057 } // namespace OPENVDB_VERSION_NAME
1058 } // namespace openvdb
1059
1060 #endif // OPENVDB_POINTS_POINT_CONVERSION_HAS_BEEN_INCLUDED
1061