GCC Code Coverage Report


Directory: ./
File: openvdb/openvdb/points/PointGroup.h
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 144 147 98.0%
Functions: 26 26 100.0%
Branches: 129 220 58.6%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 /// @author Dan Bailey
5 ///
6 /// @file points/PointGroup.h
7 ///
8 /// @brief Point group manipulation in a VDB Point Grid.
9
10 #ifndef OPENVDB_POINTS_POINT_GROUP_HAS_BEEN_INCLUDED
11 #define OPENVDB_POINTS_POINT_GROUP_HAS_BEEN_INCLUDED
12
13 #include <openvdb/openvdb.h>
14
15 #include "IndexIterator.h" // FilterTraits
16 #include "IndexFilter.h" // FilterTraits
17 #include "AttributeSet.h"
18 #include "PointDataGrid.h"
19 #include "PointAttribute.h"
20 #include "PointCount.h"
21
22 #include <tbb/parallel_reduce.h>
23
24 #include <algorithm>
25 #include <random>
26 #include <string>
27 #include <vector>
28
29 namespace openvdb {
30 OPENVDB_USE_VERSION_NAMESPACE
31 namespace OPENVDB_VERSION_NAME {
32 namespace points {
33
34 /// @brief Delete any group that is not present in the Descriptor.
35 ///
36 /// @param groups the vector of group names.
37 /// @param descriptor the descriptor that holds the group map.
38 inline void deleteMissingPointGroups( std::vector<std::string>& groups,
39 const AttributeSet::Descriptor& descriptor);
40
41 /// @brief Appends a new empty group to the VDB tree.
42 ///
43 /// @param tree the PointDataTree to be appended to.
44 /// @param group name of the new group.
45 template <typename PointDataTreeT>
46 inline void appendGroup(PointDataTreeT& tree,
47 const Name& group);
48
49 /// @brief Appends new empty groups to the VDB tree.
50 ///
51 /// @param tree the PointDataTree to be appended to.
52 /// @param groups names of the new groups.
53 template <typename PointDataTreeT>
54 inline void appendGroups(PointDataTreeT& tree,
55 const std::vector<Name>& groups);
56
57 /// @brief Drops an existing group from the VDB tree.
58 ///
59 /// @param tree the PointDataTree to be dropped from.
60 /// @param group name of the group.
61 /// @param compact compact attributes if possible to reduce memory - if dropping
62 /// more than one group, compacting once at the end will be faster
63 template <typename PointDataTreeT>
64 inline void dropGroup( PointDataTreeT& tree,
65 const Name& group,
66 const bool compact = true);
67
68 /// @brief Drops existing groups from the VDB tree, the tree is compacted after dropping.
69 ///
70 /// @param tree the PointDataTree to be dropped from.
71 /// @param groups names of the groups.
72 template <typename PointDataTreeT>
73 inline void dropGroups( PointDataTreeT& tree,
74 const std::vector<Name>& groups);
75
76 /// @brief Drops all existing groups from the VDB tree, the tree is compacted after dropping.
77 ///
78 /// @param tree the PointDataTree to be dropped from.
79 template <typename PointDataTreeT>
80 inline void dropGroups( PointDataTreeT& tree);
81
82 /// @brief Compacts existing groups of a VDB Tree to use less memory if possible.
83 ///
84 /// @param tree the PointDataTree to be compacted.
85 template <typename PointDataTreeT>
86 inline void compactGroups(PointDataTreeT& tree);
87
88 /// @brief Sets group membership from a PointIndexTree-ordered vector.
89 ///
90 /// @param tree the PointDataTree.
91 /// @param indexTree the PointIndexTree.
92 /// @param membership @c 1 if the point is in the group, 0 otherwise.
93 /// @param group the name of the group.
94 /// @param remove if @c true also perform removal of points from the group.
95 ///
96 /// @note vector<bool> is not thread-safe on concurrent write, so use vector<short> instead
97 template <typename PointDataTreeT, typename PointIndexTreeT>
98 inline void setGroup( PointDataTreeT& tree,
99 const PointIndexTreeT& indexTree,
100 const std::vector<short>& membership,
101 const Name& group,
102 const bool remove = false);
103
104 /// @brief Sets membership for the specified group for all points (on/off).
105 ///
106 /// @param tree the PointDataTree.
107 /// @param group the name of the group.
108 /// @param member true / false for membership of the group.
109 template <typename PointDataTreeT>
110 inline void setGroup( PointDataTreeT& tree,
111 const Name& group,
112 const bool member = true);
113
114 /// @brief Sets group membership based on a provided filter.
115 ///
116 /// @param tree the PointDataTree.
117 /// @param group the name of the group.
118 /// @param filter filter data that is used to create a per-leaf filter
119 template <typename PointDataTreeT, typename FilterT>
120 inline void setGroupByFilter( PointDataTreeT& tree,
121 const Name& group,
122 const FilterT& filter);
123
124
125 ////////////////////////////////////////
126
127 /// @cond OPENVDB_DOCS_INTERNAL
128
129 namespace point_group_internal {
130
131
132 /// Copy a group attribute value from one group offset to another
133 template<typename PointDataTreeType>
134 struct CopyGroupOp {
135
136 using LeafManagerT = typename tree::LeafManager<PointDataTreeType>;
137 using LeafRangeT = typename LeafManagerT::LeafRange;
138 using GroupIndex = AttributeSet::Descriptor::GroupIndex;
139
140 6 CopyGroupOp(const GroupIndex& targetIndex,
141 const GroupIndex& sourceIndex)
142 : mTargetIndex(targetIndex)
143 6 , mSourceIndex(sourceIndex) { }
144
145 6 void operator()(const typename LeafManagerT::LeafRange& range) const {
146
147
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
12 for (auto leaf = range.begin(); leaf; ++leaf) {
148
149 6 GroupHandle sourceGroup = leaf->groupHandle(mSourceIndex);
150 6 GroupWriteHandle targetGroup = leaf->groupWriteHandle(mTargetIndex);
151
152
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
18 for (auto iter = leaf->beginIndexAll(); iter; ++iter) {
153 6 const bool groupOn = sourceGroup.get(*iter);
154 6 targetGroup.set(*iter, groupOn);
155 }
156 }
157 6 }
158
159 //////////
160
161 const GroupIndex mTargetIndex;
162 const GroupIndex mSourceIndex;
163 };
164
165
166 /// Set membership on or off for the specified group
167 template <typename PointDataTreeT, bool Member>
168 struct SetGroupOp
169 {
170 using LeafManagerT = typename tree::LeafManager<PointDataTreeT>;
171 using GroupIndex = AttributeSet::Descriptor::GroupIndex;
172
173 82 SetGroupOp(const AttributeSet::Descriptor::GroupIndex& index)
174
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 72 times.
✗ Branch 5 not taken.
82 : mIndex(index) { }
175
176 312 void operator()(const typename LeafManagerT::LeafRange& range) const
177 {
178
2/2
✓ Branch 1 taken 156 times.
✓ Branch 2 taken 156 times.
624 for (auto leaf = range.begin(); leaf; ++leaf) {
179
180 // obtain the group attribute array
181
182 312 GroupWriteHandle group(leaf->groupWriteHandle(mIndex));
183
184 // set the group value
185
186 312 group.collapse(Member);
187 }
188 312 }
189
190 //////////
191
192 const GroupIndex& mIndex;
193 }; // struct SetGroupOp
194
195
196 template <typename PointDataTreeT, typename PointIndexTreeT, bool Remove>
197 struct SetGroupFromIndexOp
198 {
199 using LeafManagerT = typename tree::LeafManager<PointDataTreeT>;
200 using LeafRangeT = typename LeafManagerT::LeafRange;
201 using PointIndexLeafNode = typename PointIndexTreeT::LeafNodeType;
202 using IndexArray = typename PointIndexLeafNode::IndexArray;
203 using GroupIndex = AttributeSet::Descriptor::GroupIndex;
204 using MembershipArray = std::vector<short>;
205
206 57 SetGroupFromIndexOp(const PointIndexTreeT& indexTree,
207 const MembershipArray& membership,
208 const GroupIndex& index)
209 : mIndexTree(indexTree)
210 , mMembership(membership)
211
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 54 times.
✗ Branch 5 not taken.
57 , mIndex(index) { }
212
213 708 void operator()(const typename LeafManagerT::LeafRange& range) const
214 {
215
2/2
✓ Branch 1 taken 3110 times.
✓ Branch 2 taken 354 times.
6928 for (auto leaf = range.begin(); leaf; ++leaf) {
216
217 // obtain the PointIndexLeafNode (using the origin of the current leaf)
218
219 6220 const PointIndexLeafNode* pointIndexLeaf = mIndexTree.probeConstLeaf(leaf->origin());
220
221
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3108 times.
6220 if (!pointIndexLeaf) continue;
222
223 // obtain the group attribute array
224
225 6216 GroupWriteHandle group(leaf->groupWriteHandle(mIndex));
226
227 // initialise the attribute storage
228
229 Index64 index = 0;
230
231 const IndexArray& indices = pointIndexLeaf->indices();
232
233
2/2
✓ Branch 0 taken 1010321 times.
✓ Branch 1 taken 3108 times.
2026858 for (const Index64 i: indices) {
234 if (Remove) {
235 24 group.set(static_cast<Index>(index), mMembership[i]);
236
2/2
✓ Branch 0 taken 505103 times.
✓ Branch 1 taken 505206 times.
2020618 } else if (mMembership[i] == short(1)) {
237 1010206 group.set(static_cast<Index>(index), short(1));
238 }
239 2020642 index++;
240 }
241
242 // attempt to compact the array
243
244 6216 group.compact();
245 }
246 708 }
247
248 //////////
249
250 const PointIndexTreeT& mIndexTree;
251 const MembershipArray& mMembership;
252 const GroupIndex& mIndex;
253 }; // struct SetGroupFromIndexOp
254
255
256 template <typename PointDataTreeT, typename FilterT, typename IterT = typename PointDataTreeT::LeafNodeType::ValueAllCIter>
257 struct SetGroupByFilterOp
258 {
259 using LeafManagerT = typename tree::LeafManager<PointDataTreeT>;
260 using LeafRangeT = typename LeafManagerT::LeafRange;
261 using LeafNodeT = typename PointDataTreeT::LeafNodeType;
262 using GroupIndex = AttributeSet::Descriptor::GroupIndex;
263
264 5 SetGroupByFilterOp( const GroupIndex& index, const FilterT& filter)
265 : mIndex(index)
266 5 , mFilter(filter) { }
267
268 24 void operator()(const typename LeafManagerT::LeafRange& range) const
269 {
270
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
48 for (auto leaf = range.begin(); leaf; ++leaf) {
271
272 // obtain the group attribute array
273
274 24 GroupWriteHandle group(leaf->groupWriteHandle(mIndex));
275
276 20 auto iter = leaf->template beginIndex<IterT, FilterT>(mFilter);
277
278
3/4
✓ Branch 0 taken 2007 times.
✓ Branch 1 taken 12 times.
✓ Branch 3 taken 2005 times.
✗ Branch 4 not taken.
8052 for (; iter; ++iter) {
279
1/2
✓ Branch 2 taken 2005 times.
✗ Branch 3 not taken.
4014 group.set(*iter, true);
280 }
281
282 // attempt to compact the array
283
284
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
24 group.compact();
285 }
286 24 }
287
288 //////////
289
290 const GroupIndex& mIndex;
291 const FilterT& mFilter; // beginIndex takes a copy of mFilter
292 }; // struct SetGroupByFilterOp
293
294
295 ////////////////////////////////////////
296
297
298 } // namespace point_group_internal
299
300 /// @endcond
301
302 ////////////////////////////////////////
303
304
305 5 inline void deleteMissingPointGroups( std::vector<std::string>& groups,
306 const AttributeSet::Descriptor& descriptor)
307 {
308
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5 times.
11 for (auto it = groups.begin(); it != groups.end();) {
309
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
9 if (!descriptor.hasGroup(*it)) it = groups.erase(it);
310 else ++it;
311 }
312 5 }
313
314
315 ////////////////////////////////////////
316
317
318 template <typename PointDataTreeT>
319
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 148 times.
149 inline void appendGroup(PointDataTreeT& tree, const Name& group)
320 {
321
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 148 times.
149 if (group.empty()) {
322
2/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
4 OPENVDB_THROW(KeyError, "Cannot use an empty group name as a key.");
323 }
324
325 auto iter = tree.cbeginLeaf();
326
327
1/2
✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
157 if (!iter) return;
328
329 const AttributeSet& attributeSet = iter->attributeSet();
330 auto descriptor = attributeSet.descriptorPtr();
331
332 // don't add if group already exists
333
334
3/4
✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 139 times.
148 if (descriptor->hasGroup(group)) return;
335
336
1/2
✓ Branch 1 taken 139 times.
✗ Branch 2 not taken.
139 const bool hasUnusedGroup = descriptor->unusedGroups() > 0;
337
338 // add a new group attribute if there are no unused groups
339
340
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 65 times.
139 if (!hasUnusedGroup) {
341
342 // find a new internal group name
343
344
3/6
✓ Branch 1 taken 74 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 74 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 74 times.
✗ Branch 8 not taken.
148 const Name groupName = descriptor->uniqueName("__group");
345
346
2/4
✓ Branch 1 taken 74 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 74 times.
✗ Branch 5 not taken.
148 descriptor = descriptor->duplicateAppend(groupName, GroupAttributeArray::attributeType());
347
1/2
✓ Branch 1 taken 74 times.
✗ Branch 2 not taken.
74 const size_t pos = descriptor->find(groupName);
348
349 // insert new group attribute
350
351
1/2
✓ Branch 1 taken 74 times.
✗ Branch 2 not taken.
74 tree::LeafManager<PointDataTreeT> leafManager(tree);
352
1/2
✓ Branch 1 taken 74 times.
✗ Branch 2 not taken.
74 leafManager.foreach(
353 6272 [&](typename PointDataTreeT::LeafNodeType& leaf, size_t /*idx*/) {
354 auto expected = leaf.attributeSet().descriptorPtr();
355
2/4
✓ Branch 1 taken 3136 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3136 times.
✗ Branch 4 not taken.
6272 leaf.appendAttribute(*expected, descriptor, pos);
356 }, /*threaded=*/true
357 );
358 }
359 else {
360 // make the descriptor unique before we modify the group map
361
362
1/2
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
130 makeDescriptorUnique(tree);
363 65 descriptor = attributeSet.descriptorPtr();
364 }
365
366 // ensure that there are now available groups
367
368
2/4
✓ Branch 1 taken 139 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 139 times.
139 assert(descriptor->unusedGroups() > 0);
369
370 // find next unused offset
371
372
1/2
✓ Branch 1 taken 139 times.
✗ Branch 2 not taken.
139 const size_t offset = descriptor->unusedGroupOffset();
373
374 // add the group mapping to the descriptor
375
376
1/2
✓ Branch 1 taken 139 times.
✗ Branch 2 not taken.
139 descriptor->setGroup(group, offset);
377
378 // if there was an unused group then we did not need to append a new attribute, so
379 // we must manually clear membership in the new group as its bits may have been
380 // previously set
381
382
3/4
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 74 times.
✓ Branch 3 taken 65 times.
✗ Branch 4 not taken.
139 if (hasUnusedGroup) setGroup(tree, group, false);
383 }
384
385
386 ////////////////////////////////////////
387
388
389 template <typename PointDataTreeT>
390 1 inline void appendGroups(PointDataTreeT& tree,
391 const std::vector<Name>& groups)
392 {
393 // TODO: could be more efficient by appending multiple groups at once
394 // instead of one-by-one, however this is likely not that common a use case
395
396
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (const Name& name : groups) {
397 2 appendGroup(tree, name);
398 }
399 1 }
400
401
402 ////////////////////////////////////////
403
404
405 template <typename PointDataTreeT>
406
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 30 times.
31 inline void dropGroup(PointDataTreeT& tree, const Name& group, const bool compact)
407 {
408 using Descriptor = AttributeSet::Descriptor;
409
410
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 30 times.
31 if (group.empty()) {
411
2/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
4 OPENVDB_THROW(KeyError, "Cannot use an empty group name as a key.");
412 }
413
414 auto iter = tree.cbeginLeaf();
415
416
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 28 times.
30 if (!iter) return;
417
418 const AttributeSet& attributeSet = iter->attributeSet();
419
420 // make the descriptor unique before we modify the group map
421
422 56 makeDescriptorUnique(tree);
423 Descriptor::Ptr descriptor = attributeSet.descriptorPtr();
424
425 // now drop the group
426
427
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 descriptor->dropGroup(group);
428
429
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 22 times.
28 if (compact) {
430
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 compactGroups(tree);
431 }
432 }
433
434
435 ////////////////////////////////////////
436
437
438 template <typename PointDataTreeT>
439 7 inline void dropGroups( PointDataTreeT& tree,
440 const std::vector<Name>& groups)
441 {
442
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 7 times.
17 for (const Name& name : groups) {
443 10 dropGroup(tree, name, /*compact=*/false);
444 }
445
446 // compaction done once for efficiency
447
448 7 compactGroups(tree);
449 7 }
450
451
452 ////////////////////////////////////////
453
454
455 template <typename PointDataTreeT>
456 1 inline void dropGroups( PointDataTreeT& tree)
457 {
458 using Descriptor = AttributeSet::Descriptor;
459
460 auto iter = tree.cbeginLeaf();
461
462
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!iter) return;
463
464 const AttributeSet& attributeSet = iter->attributeSet();
465
466 // make the descriptor unique before we modify the group map
467
468 2 makeDescriptorUnique(tree);
469 Descriptor::Ptr descriptor = attributeSet.descriptorPtr();
470
471
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 descriptor->clearGroups();
472
473 // find all indices for group attribute arrays
474
475
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 std::vector<size_t> indices = attributeSet.groupAttributeIndices();
476
477 // drop these attributes arrays
478
479
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 dropAttributes(tree, indices);
480 }
481
482
483 ////////////////////////////////////////
484
485
486 template <typename PointDataTreeT>
487 15 inline void compactGroups(PointDataTreeT& tree)
488 {
489 using Descriptor = AttributeSet::Descriptor;
490 using GroupIndex = Descriptor::GroupIndex;
491 using LeafManagerT = typename tree::template LeafManager<PointDataTreeT>;
492
493 using point_group_internal::CopyGroupOp;
494
495 auto iter = tree.cbeginLeaf();
496
497
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 2 times.
19 if (!iter) return;
498
499 const AttributeSet& attributeSet = iter->attributeSet();
500
501 // early exit if not possible to compact
502
503
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 4 times.
13 if (!attributeSet.descriptor().canCompactGroups()) return;
504
505 // make the descriptor unique before we modify the group map
506
507 18 makeDescriptorUnique(tree);
508 Descriptor::Ptr descriptor = attributeSet.descriptorPtr();
509
510 // generate a list of group offsets and move them (one-by-one)
511 // TODO: improve this algorithm to move multiple groups per array at once
512 // though this is likely not that common a use case
513
514 Name sourceName;
515 size_t sourceOffset, targetOffset;
516
517
3/4
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 9 times.
15 while (descriptor->requiresGroupMove(sourceName, sourceOffset, targetOffset)) {
518
519
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 const GroupIndex sourceIndex = attributeSet.groupIndex(sourceOffset);
520
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 const GroupIndex targetIndex = attributeSet.groupIndex(targetOffset);
521
522 CopyGroupOp<PointDataTreeT> copy(targetIndex, sourceIndex);
523
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
12 LeafManagerT leafManager(tree);
524
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 tbb::parallel_for(leafManager.leafRange(), copy);
525
526
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 descriptor->setGroup(sourceName, targetOffset);
527 }
528
529 // drop unused attribute arrays
530
531
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 const std::vector<size_t> indices = attributeSet.groupAttributeIndices();
532
533
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
9 const size_t totalAttributesToDrop = descriptor->unusedGroups() / descriptor->groupBits();
534
535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 assert(totalAttributesToDrop <= indices.size());
536
537
1/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
9 const std::vector<size_t> indicesToDrop(indices.end() - totalAttributesToDrop,
538 indices.end());
539
540
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 dropAttributes(tree, indicesToDrop);
541 }
542
543
544 ////////////////////////////////////////
545
546
547 template <typename PointDataTreeT, typename PointIndexTreeT>
548 58 inline void setGroup( PointDataTreeT& tree,
549 const PointIndexTreeT& indexTree,
550 const std::vector<short>& membership,
551 const Name& group,
552 const bool remove)
553 {
554 using Descriptor = AttributeSet::Descriptor;
555 using LeafManagerT = typename tree::LeafManager<PointDataTreeT>;
556 using point_group_internal::SetGroupFromIndexOp;
557
558 auto iter = tree.cbeginLeaf();
559
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (!iter) return;
560
561 const AttributeSet& attributeSet = iter->attributeSet();
562 const Descriptor& descriptor = attributeSet.descriptor();
563
564
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 58 times.
58 if (!descriptor.hasGroup(group)) {
565 OPENVDB_THROW(LookupError, "Group must exist on Tree before defining membership.");
566 }
567
568 {
569 // Check that that the largest index in the PointIndexTree is smaller than the size
570 // of the membership vector. The index tree will be used to lookup membership
571 // values. If the index tree was constructed with nan positions, this index will
572 // differ from the PointDataTree count
573
574 using IndexTreeManager = tree::LeafManager<const PointIndexTreeT>;
575 115 IndexTreeManager leafManager(indexTree);
576
577
1/2
✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
59 const int64_t max = tbb::parallel_reduce(leafManager.leafRange(), -1,
578 408 [](const typename IndexTreeManager::LeafRange& range, int64_t value) -> int64_t {
579
2/2
✓ Branch 1 taken 3109 times.
✓ Branch 2 taken 408 times.
3517 for (auto leaf = range.begin(); leaf; ++leaf) {
580
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 2875 times.
3109 auto it = std::max_element(leaf->indices().begin(), leaf->indices().end());
581
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 2875 times.
3343 value = std::max(value, static_cast<int64_t>(*it));
582 }
583 408 return value;
584 },
585 [](const int64_t a, const int64_t b) {
586 16 return std::max(a, b);
587 }
588 );
589
590
4/4
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 56 times.
58 if (max != -1 && membership.size() <= static_cast<size_t>(max)) {
591
2/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
4 OPENVDB_THROW(IndexError, "Group membership vector size must be larger than "
592 " the maximum index within the provided index tree.");
593 }
594 }
595
596 57 const Descriptor::GroupIndex index = attributeSet.groupIndex(group);
597 114 LeafManagerT leafManager(tree);
598
599 // set membership
600
601
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 54 times.
57 if (remove) {
602 SetGroupFromIndexOp<PointDataTreeT, PointIndexTreeT, true>
603 set(indexTree, membership, index);
604
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 tbb::parallel_for(leafManager.leafRange(), set);
605 }
606 else {
607 SetGroupFromIndexOp<PointDataTreeT, PointIndexTreeT, false>
608 set(indexTree, membership, index);
609
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 tbb::parallel_for(leafManager.leafRange(), set);
610 }
611 }
612
613
614 ////////////////////////////////////////
615
616
617 template <typename PointDataTreeT>
618 82 inline void setGroup( PointDataTreeT& tree,
619 const Name& group,
620 const bool member)
621 {
622 using Descriptor = AttributeSet::Descriptor;
623 using LeafManagerT = typename tree::LeafManager<PointDataTreeT>;
624
625 using point_group_internal::SetGroupOp;
626
627 auto iter = tree.cbeginLeaf();
628
629
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (!iter) return;
630
631 const AttributeSet& attributeSet = iter->attributeSet();
632 const Descriptor& descriptor = attributeSet.descriptor();
633
634
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 82 times.
82 if (!descriptor.hasGroup(group)) {
635 OPENVDB_THROW(LookupError, "Group must exist on Tree before defining membership.");
636 }
637
638 82 const Descriptor::GroupIndex index = attributeSet.groupIndex(group);
639 164 LeafManagerT leafManager(tree);
640
641 // set membership based on member variable
642
643
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 72 times.
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
82 if (member) tbb::parallel_for(leafManager.leafRange(), SetGroupOp<PointDataTreeT, true>(index));
644
1/2
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
72 else tbb::parallel_for(leafManager.leafRange(), SetGroupOp<PointDataTreeT, false>(index));
645 }
646
647
648 ////////////////////////////////////////
649
650
651 template <typename PointDataTreeT, typename FilterT>
652 10 inline void setGroupByFilter( PointDataTreeT& tree,
653 const Name& group,
654 const FilterT& filter)
655 {
656 using Descriptor = AttributeSet::Descriptor;
657 using LeafManagerT = typename tree::LeafManager<PointDataTreeT>;
658
659 using point_group_internal::SetGroupByFilterOp;
660
661 auto iter = tree.cbeginLeaf();
662
663
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
10 if (!iter) return;
664
665 const AttributeSet& attributeSet = iter->attributeSet();
666 const Descriptor& descriptor = attributeSet.descriptor();
667
668
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
10 if (!descriptor.hasGroup(group)) {
669 OPENVDB_THROW(LookupError, "Group must exist on Tree before defining membership.");
670 }
671
672 10 const Descriptor::GroupIndex index = attributeSet.groupIndex(group);
673
674 // set membership using filter
675
676 SetGroupByFilterOp<PointDataTreeT, FilterT> set(index, filter);
677 10 LeafManagerT leafManager(tree);
678
679
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 tbb::parallel_for(leafManager.leafRange(), set);
680 }
681
682
683 ////////////////////////////////////////
684
685
686 template <typename PointDataTreeT>
687 1 inline void setGroupByRandomTarget( PointDataTreeT& tree,
688 const Name& group,
689 const Index64 targetPoints,
690 const unsigned int seed = 0)
691 {
692 using RandomFilter = RandomLeafFilter<PointDataTreeT, std::mt19937>;
693
694 2 RandomFilter filter(tree, targetPoints, seed);
695
696
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 setGroupByFilter<PointDataTreeT, RandomFilter>(tree, group, filter);
697 1 }
698
699
700 ////////////////////////////////////////
701
702
703 template <typename PointDataTreeT>
704 1 inline void setGroupByRandomPercentage( PointDataTreeT& tree,
705 const Name& group,
706 const float percentage = 10.0f,
707 const unsigned int seed = 0)
708 {
709 using RandomFilter = RandomLeafFilter<PointDataTreeT, std::mt19937>;
710
711 1 const int currentPoints = static_cast<int>(pointCount(tree));
712 1 const int targetPoints = int(math::Round((percentage * float(currentPoints))/100.0f));
713
714 2 RandomFilter filter(tree, targetPoints, seed);
715
716
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 setGroupByFilter<PointDataTreeT, RandomFilter>(tree, group, filter);
717 1 }
718
719
720 ////////////////////////////////////////
721
722
723 } // namespace points
724 } // namespace OPENVDB_VERSION_NAME
725 } // namespace openvdb
726
727
728 #endif // OPENVDB_POINTS_POINT_GROUP_HAS_BEEN_INCLUDED
729