GCC Code Coverage Report


Directory: ./
File: openvdb/openvdb/points/PointDelete.h
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 58 60 96.7%
Functions: 5 5 100.0%
Branches: 59 112 52.7%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 /// @author Nick Avramoussis, Francisco Gochez, Dan Bailey
5 ///
6 /// @file PointDelete.h
7 ///
8 /// @brief Methods for deleting points based on group membership
9
10 #ifndef OPENVDB_POINTS_POINT_DELETE_HAS_BEEN_INCLUDED
11 #define OPENVDB_POINTS_POINT_DELETE_HAS_BEEN_INCLUDED
12
13 #include "PointDataGrid.h"
14 #include "PointGroup.h"
15 #include "IndexIterator.h"
16 #include "IndexFilter.h"
17
18 #include <openvdb/tools/Prune.h>
19 #include <openvdb/tree/LeafManager.h>
20
21 #include <memory>
22 #include <string>
23 #include <vector>
24
25
26 namespace openvdb {
27 OPENVDB_USE_VERSION_NAMESPACE
28 namespace OPENVDB_VERSION_NAME {
29 namespace points {
30
31
32 /// @brief Delete points that are members of specific groups
33 ///
34 /// @details This method will delete points which are members of any of the supplied groups and
35 /// will optionally drop the groups from the tree. An invert flag can be used to
36 /// delete points that belong to none of the groups.
37 ///
38 /// @param pointTree the point tree
39 /// @param groups the groups from which to delete points
40 /// @param invert if enabled, points not belonging to any of the groups will be deleted
41 /// @param drop if enabled and invert is disabled, the groups will be dropped from the tree
42 ///
43 /// @note If the invert flag is true, none of the groups will be dropped after deleting points
44 /// regardless of the value of the drop parameter.
45
46 template <typename PointDataTreeT>
47 inline void deleteFromGroups(PointDataTreeT& pointTree,
48 const std::vector<std::string>& groups,
49 bool invert = false,
50 bool drop = true);
51
52 /// @brief Delete points that are members of a group
53 ///
54 /// @details This method will delete points which are members of the supplied group and will
55 /// optionally drop the group from the tree. An invert flag can be used to
56 /// delete points that belong to none of the groups.
57 ///
58 /// @param pointTree the point tree with the group to delete
59 /// @param group the name of the group to delete
60 /// @param invert if enabled, points not belonging to any of the groups will be deleted
61 /// @param drop if enabled and invert is disabled, the group will be dropped from the tree
62 ///
63 /// @note If the invert flag is true, the group will not be dropped after deleting points
64 /// regardless of the value of the drop parameter.
65
66 template <typename PointDataTreeT>
67 inline void deleteFromGroup(PointDataTreeT& pointTree,
68 const std::string& group,
69 bool invert = false,
70 bool drop = true);
71
72
73 ////////////////////////////////////////
74
75 /// @cond OPENVDB_DOCS_INTERNAL
76
77 namespace point_delete_internal {
78
79
80 struct VectorWrapper
81 {
82 using T = std::vector<std::pair<Index, Index>>;
83
84
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 VectorWrapper(const T& _data) : data(_data) { }
85
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 15 times.
37 operator bool() const { return index < data.size(); }
86 22 VectorWrapper& operator++() { index++; return *this; }
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 Index sourceIndex() const { assert(*this); return data[index].first; }
88
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 Index targetIndex() const { assert(*this); return data[index].second; }
89
90 private:
91 const T& data;
92 T::size_type index = 0;
93 }; // struct VectorWrapper
94
95
96 template <typename PointDataTreeT, typename FilterT>
97 struct DeleteByFilterOp
98 {
99 using LeafManagerT = tree::LeafManager<PointDataTreeT>;
100 using LeafRangeT = typename LeafManagerT::LeafRange;
101 using LeafNodeT = typename PointDataTreeT::LeafNodeType;
102 using ValueType = typename LeafNodeT::ValueType;
103
104 8 DeleteByFilterOp(const FilterT& filter,
105 const AttributeArray::ScopedRegistryLock* lock)
106 : mFilter(filter)
107
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 , mLock(lock) { }
108
109 15 void operator()(const LeafRangeT& range) const
110 {
111 45 for (auto leaf = range.begin(); leaf != range.end(); ++leaf) {
112
113 const size_t newSize =
114
1/2
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 iterCount(leaf->template beginIndexAll<FilterT>(mFilter));
115
116 // if all points are being deleted, clear the leaf attributes
117
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 11 times.
15 if (newSize == 0) {
118 4 leaf->clearAttributes(/*updateValueMask=*/true, mLock);
119 8 continue;
120 }
121
122 // early exit if no points are being deleted
123
124 11 const size_t currentSize = leaf->getLastValue();
125
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7 times.
11 if (newSize == currentSize) continue;
126
127 const AttributeSet& existingAttributeSet = leaf->attributeSet();
128 7 AttributeSet* newAttributeSet = new AttributeSet(
129
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 existingAttributeSet, static_cast<Index>(newSize), mLock);
130 const size_t attributeSetSize = existingAttributeSet.size();
131
132 // cache the attribute arrays for efficiency
133
134 std::vector<AttributeArray*> newAttributeArrays;
135 std::vector<const AttributeArray*> existingAttributeArrays;
136
137
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 7 times.
22 for (size_t i = 0; i < attributeSetSize; i++) {
138
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 AttributeArray* newArray = newAttributeSet->get(i);
139
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 const AttributeArray* existingArray = existingAttributeSet.getConst(i);
140
141
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 if (!newArray->hasConstantStride() || !existingArray->hasConstantStride()) {
142 OPENVDB_THROW(openvdb::NotImplementedError,
143 "Transfer of attribute values for dynamic arrays not currently supported.");
144 }
145
146
3/6
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 15 times.
15 if (newArray->stride() != existingArray->stride()) {
147 OPENVDB_THROW(openvdb::LookupError,
148 "Cannot transfer attribute values with mis-matching strides.");
149 }
150
151
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 newAttributeArrays.push_back(newArray);
152
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 existingAttributeArrays.push_back(existingArray);
153 }
154
155 Index attributeIndex = 0;
156 std::vector<ValueType> endOffsets;
157
158
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 endOffsets.reserve(LeafNodeT::NUM_VALUES);
159
160 // now construct new attribute arrays which exclude data from deleted points
161
162 std::vector<std::pair<Index, Index>> indexMapping;
163
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 indexMapping.reserve(newSize);
164
165
2/2
✓ Branch 1 taken 3584 times.
✓ Branch 2 taken 7 times.
3598 for (auto voxel = leaf->cbeginValueAll(); voxel; ++voxel) {
166
4/6
✓ Branch 1 taken 3584 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3584 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 3584 times.
3594 for (auto iter = leaf->beginIndexVoxel(voxel.getCoord(), mFilter);
167 10 iter; ++iter) {
168
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 indexMapping.emplace_back(*iter, attributeIndex++);
169 }
170
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
3584 endOffsets.push_back(static_cast<ValueType>(attributeIndex));
171 }
172
173
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 7 times.
22 for (size_t i = 0; i < attributeSetSize; i++) {
174 VectorWrapper indexMappingWrapper(indexMapping);
175
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 newAttributeArrays[i]->copyValues(*(existingAttributeArrays[i]), indexMappingWrapper);
176 }
177
178
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 leaf->replaceAttributeSet(newAttributeSet);
179
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 leaf->setOffsets(endOffsets);
180 }
181 15 }
182
183 private:
184 const FilterT& mFilter;
185 const AttributeArray::ScopedRegistryLock* mLock;
186 }; // struct DeleteByFilterOp
187
188 } // namespace point_delete_internal
189
190 /// @endcond
191
192 ////////////////////////////////////////
193
194
195 template <typename PointDataTreeT>
196 8 inline void deleteFromGroups(PointDataTreeT& pointTree,
197 const std::vector<std::string>& groups,
198 bool invert,
199 bool drop)
200 {
201 const typename PointDataTreeT::LeafCIter leafIter = pointTree.cbeginLeaf();
202
203
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (!leafIter) return;
204
205 const openvdb::points::AttributeSet& attributeSet = leafIter->attributeSet();
206 const AttributeSet::Descriptor& descriptor = attributeSet.descriptor();
207 8 std::vector<std::string> availableGroups;
208
209 // determine which of the requested groups exist, and early exit
210 // if none are present in the tree
211
212
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 8 times.
21 for (const auto& groupName : groups) {
213
2/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
13 if (descriptor.hasGroup(groupName)) {
214
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 availableGroups.push_back(groupName);
215 }
216 }
217
218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (availableGroups.empty()) return;
219
220 8 std::vector<std::string> empty;
221 8 std::unique_ptr<MultiGroupFilter> filter;
222
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if (invert) {
223
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 filter.reset(new MultiGroupFilter(groups, empty, leafIter->attributeSet()));
224 }
225 else {
226
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 filter.reset(new MultiGroupFilter(empty, groups, leafIter->attributeSet()));
227 }
228
229 { // acquire registry lock to avoid locking when appending attributes in parallel
230
231
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 AttributeArray::ScopedRegistryLock lock;
232
233
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 tree::LeafManager<PointDataTreeT> leafManager(pointTree);
234 point_delete_internal::DeleteByFilterOp<PointDataTreeT, MultiGroupFilter> deleteOp(
235 *filter, &lock);
236
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 tbb::parallel_for(leafManager.leafRange(), deleteOp);
237 }
238
239 // remove empty leaf nodes
240
241
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 tools::pruneInactive(pointTree);
242
243 // drop the now-empty groups if requested (unless invert = true)
244
245
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (drop && !invert) {
246
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 dropGroups(pointTree, availableGroups);
247 }
248 }
249
250 template <typename PointDataTreeT>
251 5 inline void deleteFromGroup(PointDataTreeT& pointTree,
252 const std::string& group,
253 bool invert,
254 bool drop)
255 {
256 10 std::vector<std::string> groups(1, group);
257
258
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 deleteFromGroups(pointTree, groups, invert, drop);
259 5 }
260
261
262 } // namespace points
263 } // namespace OPENVDB_VERSION_NAME
264 } // namespace openvdb
265
266 #endif // OPENVDB_POINTS_POINT_DELETE_HAS_BEEN_INCLUDED
267