GCC Code Coverage Report


Directory: ./
File: openvdb/openvdb/points/IndexFilter.h
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 152 153 99.3%
Functions: 36 38 94.7%
Branches: 244 551 44.3%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 /// @file points/IndexFilter.h
5 ///
6 /// @author Dan Bailey
7 ///
8 /// @brief Index filters primarily designed to be used with a FilterIndexIter.
9 ///
10 /// Filters must adhere to the interface described in the example below:
11 /// @code
12 /// struct MyFilter
13 /// {
14 /// // Return true when the filter has been initialized for first use
15 /// bool initialized() { return true; }
16 ///
17 /// // Return index::ALL if all points are valid, index::NONE if no points are valid
18 /// // and index::PARTIAL if some points are valid
19 /// index::State state() { return index::PARTIAL; }
20 ///
21 /// // Return index::ALL if all points in this leaf are valid, index::NONE if no points
22 /// // in this leaf are valid and index::PARTIAL if some points in this leaf are valid
23 /// template <typename LeafT>
24 /// index::State state(const LeafT&) { return index::PARTIAL; }
25 ///
26 /// // Resets the filter to refer to the specified leaf, all subsequent valid() calls
27 /// // will be relative to this leaf until reset() is called with a different leaf.
28 /// // Although a required method, many filters will provide an empty implementation if
29 /// // there is no leaf-specific logic needed.
30 /// template <typename LeafT> void reset(const LeafT&) { }
31 ///
32 /// // Returns true if the filter is valid for the supplied iterator
33 /// template <typename IterT> bool valid(const IterT&) { return true; }
34 /// };
35 /// @endcode
36
37 #ifndef OPENVDB_POINTS_INDEX_FILTER_HAS_BEEN_INCLUDED
38 #define OPENVDB_POINTS_INDEX_FILTER_HAS_BEEN_INCLUDED
39
40 #include <openvdb/version.h>
41 #include <openvdb/Types.h>
42
43 #include <openvdb/math/Transform.h>
44 #include <openvdb/tools/Interpolation.h>
45
46 #include "IndexIterator.h"
47 #include "AttributeArray.h"
48 #include "AttributeGroup.h"
49 #include "AttributeSet.h"
50
51 #include <random> // std::mt19937
52 #include <numeric> // std::iota
53 #include <unordered_map>
54
55
56 class TestIndexFilter;
57
58 namespace openvdb {
59 OPENVDB_USE_VERSION_NAMESPACE
60 namespace OPENVDB_VERSION_NAME {
61 namespace points {
62
63
64 ////////////////////////////////////////
65
66 /// @cond OPENVDB_DOCS_INTERNAL
67
68 namespace index_filter_internal {
69
70
71 // generate a random subset of n indices from the range [0:m]
72 template <typename RandGenT, typename IntType>
73 std::vector<IntType>
74 30 generateRandomSubset(const unsigned int seed, const IntType n, const IntType m)
75 {
76
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 14 times.
30 if (n <= 0) return std::vector<IntType>();
77
78 // fill vector with ascending indices
79 28 std::vector<IntType> values(m);
80 28 std::iota(values.begin(), values.end(), 0);
81
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 11 times.
28 if (n >= m) return values;
82
83 // shuffle indices using random generator
84
85 22 RandGenT randGen(seed);
86 22 std::shuffle(values.begin(), values.end(), randGen);
87
88 // resize the container to n elements
89
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
22 values.resize(n);
90
91 // sort the subset of the indices vector that will be used
92 22 std::sort(values.begin(), values.end());
93
94 return values;
95 }
96
97
98 } // namespace index_filter_internal
99
100 /// @endcond
101
102
103 /// Index filtering on active / inactive state of host voxel
104 template <bool On>
105 class ValueMaskFilter
106 {
107 public:
108 static bool initialized() { return true; }
109 static index::State state() { return index::PARTIAL; }
110 template <typename LeafT>
111 64 static index::State state(const LeafT& leaf)
112 {
113
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 6 times.
64 if (leaf.isDense()) return On ? index::ALL : index::NONE;
114
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24 times.
52 else if (leaf.isEmpty()) return On ? index::NONE : index::ALL;
115 return index::PARTIAL;
116 }
117
118 template <typename LeafT>
119 void reset(const LeafT&) { }
120
121 template <typename IterT>
122 bool valid(const IterT& iter) const
123 {
124
18/36
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 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.
2112 const bool valueOn = iter.isValueOn();
125
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
2 return On ? valueOn : !valueOn;
126 }
127 };
128
129
130 using ActiveFilter = ValueMaskFilter<true>;
131 using InactiveFilter = ValueMaskFilter<false>;
132
133
134 /// Index filtering on multiple group membership for inclusion and exclusion
135 ///
136 /// @note include filters are applied first, then exclude filters
137 class MultiGroupFilter
138 {
139 public:
140 using NameVector = std::vector<Name>;
141 using IndexVector = std::vector<AttributeSet::Descriptor::GroupIndex>;
142 using HandleVector = std::vector<GroupHandle>;
143
144 private:
145 122 static IndexVector namesToIndices(const AttributeSet& attributeSet, const NameVector& names) {
146 IndexVector indices;
147
2/2
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 122 times.
187 for (const auto& name : names) {
148 try {
149
4/6
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 64 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
65 indices.emplace_back(attributeSet.groupIndex(name));
150
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 } catch (LookupError&) {
151 // silently drop group names that don't exist
152 }
153 }
154 122 return indices;
155 }
156
157 public:
158 61 MultiGroupFilter( const NameVector& include,
159 const NameVector& exclude,
160 const AttributeSet& attributeSet)
161 61 : mInclude(MultiGroupFilter::namesToIndices(attributeSet, include))
162
1/2
✓ Branch 2 taken 61 times.
✗ Branch 3 not taken.
61 , mExclude(MultiGroupFilter::namesToIndices(attributeSet, exclude)) { }
163
164 MultiGroupFilter( const IndexVector& include,
165 const IndexVector& exclude)
166 : mInclude(include)
167 , mExclude(exclude) { }
168
169 59046 MultiGroupFilter( const MultiGroupFilter& filter)
170 59046 : mInclude(filter.mInclude)
171 59046 , mExclude(filter.mExclude)
172 59046 , mIncludeHandles(filter.mIncludeHandles)
173 59046 , mExcludeHandles(filter.mExcludeHandles)
174
3/6
✓ Branch 2 taken 59046 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 59046 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 59046 times.
✗ Branch 9 not taken.
59046 , mInitialized(filter.mInitialized) { }
175
176
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 18226 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10866 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5837 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
34931 inline bool initialized() const { return mInitialized; }
177
178 inline index::State state() const
179 {
180
50/240
✓ Branch 0 taken 2905 times.
✓ Branch 1 taken 2902 times.
✓ Branch 2 taken 2901 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 2902 times.
✓ Branch 5 taken 2903 times.
✓ Branch 6 taken 2901 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 2902 times.
✓ Branch 9 taken 2904 times.
✓ Branch 10 taken 2900 times.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 2901 times.
✓ Branch 13 taken 2901 times.
✓ Branch 14 taken 2900 times.
✓ Branch 15 taken 1 times.
✓ Branch 16 taken 2900 times.
✓ Branch 17 taken 2901 times.
✓ Branch 18 taken 2900 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1 times.
✓ Branch 21 taken 3 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 1 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 32 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✓ Branch 64 taken 2 times.
✓ Branch 65 taken 1 times.
✓ Branch 66 taken 1 times.
✓ Branch 67 taken 1 times.
✓ Branch 68 taken 1 times.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✓ Branch 71 taken 1 times.
✓ Branch 72 taken 1 times.
✗ Branch 73 not taken.
✓ Branch 74 taken 1 times.
✗ Branch 75 not taken.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✗ Branch 78 not taken.
✗ Branch 79 not taken.
✗ Branch 80 not taken.
✗ Branch 81 not taken.
✗ Branch 82 not taken.
✗ Branch 83 not taken.
✗ Branch 84 not taken.
✗ Branch 85 not taken.
✗ Branch 86 not taken.
✗ Branch 87 not taken.
✗ Branch 88 not taken.
✗ Branch 89 not taken.
✗ Branch 90 not taken.
✗ Branch 91 not taken.
✗ Branch 92 not taken.
✗ Branch 93 not taken.
✗ Branch 94 not taken.
✗ Branch 95 not taken.
✗ Branch 96 not taken.
✗ Branch 97 not taken.
✗ Branch 98 not taken.
✗ Branch 99 not taken.
✗ Branch 100 not taken.
✗ Branch 101 not taken.
✗ Branch 102 not taken.
✗ Branch 103 not taken.
✗ Branch 104 not taken.
✗ Branch 105 not taken.
✗ Branch 106 not taken.
✗ Branch 107 not taken.
✗ Branch 108 not taken.
✗ Branch 109 not taken.
✗ Branch 110 not taken.
✗ Branch 111 not taken.
✗ Branch 112 not taken.
✗ Branch 113 not taken.
✗ Branch 114 not taken.
✗ Branch 115 not taken.
✗ Branch 116 not taken.
✗ Branch 117 not taken.
✗ Branch 118 not taken.
✗ Branch 119 not taken.
✗ Branch 120 not taken.
✗ Branch 121 not taken.
✗ Branch 122 not taken.
✗ Branch 123 not taken.
✗ Branch 124 not taken.
✗ Branch 125 not taken.
✗ Branch 126 not taken.
✗ Branch 127 not taken.
✗ Branch 128 not taken.
✗ Branch 129 not taken.
✗ Branch 130 not taken.
✗ Branch 131 not taken.
✓ Branch 132 taken 12 times.
✓ Branch 133 taken 6 times.
✓ Branch 134 taken 6 times.
✓ Branch 135 taken 6 times.
✓ Branch 136 taken 6 times.
✓ Branch 137 taken 12 times.
✗ Branch 138 not taken.
✓ Branch 139 taken 6 times.
✓ Branch 140 taken 2 times.
✓ Branch 141 taken 1 times.
✓ Branch 142 taken 1 times.
✓ Branch 143 taken 1 times.
✓ Branch 144 taken 2 times.
✓ Branch 145 taken 1 times.
✓ Branch 146 taken 1 times.
✓ Branch 147 taken 1 times.
✗ Branch 148 not taken.
✓ Branch 149 taken 1 times.
✗ Branch 150 not taken.
✗ Branch 151 not taken.
✓ Branch 152 taken 1 times.
✓ Branch 153 taken 1 times.
✓ Branch 154 taken 1 times.
✗ Branch 155 not taken.
✗ Branch 156 not taken.
✗ Branch 157 not taken.
✗ Branch 158 not taken.
✗ Branch 159 not taken.
✗ Branch 160 not taken.
✗ Branch 161 not taken.
✗ Branch 162 not taken.
✗ Branch 163 not taken.
✗ Branch 164 not taken.
✗ Branch 165 not taken.
✗ Branch 166 not taken.
✗ Branch 167 not taken.
✗ Branch 168 not taken.
✗ Branch 169 not taken.
✗ Branch 170 not taken.
✗ Branch 171 not taken.
✗ Branch 172 not taken.
✗ Branch 173 not taken.
✗ Branch 174 not taken.
✗ Branch 175 not taken.
✗ Branch 176 not taken.
✗ Branch 177 not taken.
✗ Branch 178 not taken.
✗ Branch 179 not taken.
✗ Branch 180 not taken.
✗ Branch 181 not taken.
✗ Branch 182 not taken.
✗ Branch 183 not taken.
✗ Branch 184 not taken.
✗ Branch 185 not taken.
✗ Branch 186 not taken.
✗ Branch 187 not taken.
✗ Branch 188 not taken.
✗ Branch 189 not taken.
✗ Branch 190 not taken.
✗ Branch 191 not taken.
✗ Branch 192 not taken.
✗ Branch 193 not taken.
✗ Branch 194 not taken.
✗ Branch 195 not taken.
✗ Branch 196 not taken.
✗ Branch 197 not taken.
✗ Branch 198 not taken.
✗ Branch 199 not taken.
✗ Branch 200 not taken.
✗ Branch 201 not taken.
✗ Branch 202 not taken.
✗ Branch 203 not taken.
✗ Branch 204 not taken.
✗ Branch 205 not taken.
✗ Branch 206 not taken.
✗ Branch 207 not taken.
✗ Branch 208 not taken.
✗ Branch 209 not taken.
✗ Branch 210 not taken.
✗ Branch 211 not taken.
✗ Branch 212 not taken.
✗ Branch 213 not taken.
✗ Branch 214 not taken.
✗ Branch 215 not taken.
✗ Branch 216 not taken.
✗ Branch 217 not taken.
✗ Branch 218 not taken.
✗ Branch 219 not taken.
✗ Branch 220 not taken.
✗ Branch 221 not taken.
✗ Branch 222 not taken.
✗ Branch 223 not taken.
✗ Branch 224 not taken.
✗ Branch 225 not taken.
✗ Branch 226 not taken.
✗ Branch 227 not taken.
✗ Branch 228 not taken.
✗ Branch 229 not taken.
✗ Branch 230 not taken.
✗ Branch 231 not taken.
✗ Branch 232 not taken.
✗ Branch 233 not taken.
✗ Branch 234 not taken.
✗ Branch 235 not taken.
✗ Branch 236 not taken.
✗ Branch 237 not taken.
✗ Branch 238 not taken.
✗ Branch 239 not taken.
29094 return (mInclude.empty() && mExclude.empty()) ? index::ALL : index::PARTIAL;
181 }
182
183 template <typename LeafT>
184 static index::State state(const LeafT&) { return index::PARTIAL; }
185
186 template <typename LeafT>
187 24092 void reset(const LeafT& leaf) {
188
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24092 times.
24092 mIncludeHandles.clear();
189
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24092 times.
24092 mExcludeHandles.clear();
190
2/2
✓ Branch 0 taken 19576 times.
✓ Branch 1 taken 24092 times.
43668 for (const auto& i : mInclude) {
191 19576 mIncludeHandles.emplace_back(leaf.groupHandle(i));
192 }
193
2/2
✓ Branch 0 taken 6738 times.
✓ Branch 1 taken 24092 times.
30830 for (const auto& i : mExclude) {
194 6738 mExcludeHandles.emplace_back(leaf.groupHandle(i));
195 }
196 24092 mInitialized = true;
197 24092 }
198
199 template <typename IterT>
200 11025523 bool valid(const IterT& iter) const {
201
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4015319 times.
11025523 assert(mInitialized);
202 // accept no include filters as valid
203 bool includeValid = mIncludeHandles.empty();
204
2/2
✓ Branch 0 taken 4015246 times.
✓ Branch 1 taken 2007362 times.
16037892 for (const GroupHandle& handle : mIncludeHandles) {
205
3/3
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 2007295 times.
✓ Branch 3 taken 2007920 times.
10025362 if (handle.getUnsafe(*iter)) {
206 includeValid = true;
207 break;
208 }
209 }
210
2/2
✓ Branch 0 taken 2008038 times.
✓ Branch 1 taken 2007281 times.
11025523 if (!includeValid) return false;
211
2/2
✓ Branch 0 taken 105 times.
✓ Branch 1 taken 2007997 times.
6013284 for (const GroupHandle& handle : mExcludeHandles) {
212
3/3
✓ Branch 1 taken 29 times.
✓ Branch 2 taken 47 times.
✓ Branch 3 taken 29 times.
192 if (handle.getUnsafe(*iter)) return false;
213 }
214 6013092 return true;
215 }
216
217 private:
218 IndexVector mInclude;
219 IndexVector mExclude;
220 HandleVector mIncludeHandles;
221 HandleVector mExcludeHandles;
222 bool mInitialized = false;
223 }; // class MultiGroupFilter
224
225
226 // Random index filtering per leaf
227 template <typename PointDataTreeT, typename RandGenT>
228 class RandomLeafFilter
229 {
230 public:
231 using SeedCountPair = std::pair<Index, Index>;
232 using LeafMap = std::unordered_map<openvdb::Coord, SeedCountPair>;
233
234
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 RandomLeafFilter( const PointDataTreeT& tree,
235 const Index64 targetPoints,
236
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 const unsigned int seed = 0) {
237 Index64 currentPoints = 0;
238
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
9 for (auto iter = tree.cbeginLeaf(); iter; ++iter) {
239
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 currentPoints += iter->pointCount();
240 }
241
242
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 const float factor = targetPoints > currentPoints ? 1.0f : float(targetPoints) / float(currentPoints);
243
244 3 std::mt19937 generator(seed);
245 std::uniform_int_distribution<unsigned int> dist(0, std::numeric_limits<unsigned int>::max() - 1);
246
247 Index32 leafCounter = 0;
248 float totalPointsFloat = 0.0f;
249 int totalPoints = 0;
250
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
7 for (auto iter = tree.cbeginLeaf(); iter; ++iter) {
251 // for the last leaf - use the remaining points to reach the target points
252
3/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 4 times.
6 if (leafCounter + 1 == tree.leafCount()) {
253 2 const int leafPoints = static_cast<int>(targetPoints) - totalPoints;
254 mLeafMap[iter->origin()] = SeedCountPair(dist(generator), leafPoints);
255 break;
256 }
257 4 totalPointsFloat += factor * static_cast<float>(iter->pointCount());
258 const auto leafPoints = static_cast<int>(math::Floor(totalPointsFloat));
259 4 totalPointsFloat -= static_cast<float>(leafPoints);
260 4 totalPoints += leafPoints;
261
262 mLeafMap[iter->origin()] = SeedCountPair(dist(generator), leafPoints);
263
264 leafCounter++;
265 }
266 3 }
267
268
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
10 inline bool initialized() const { return mNextIndex == -1; }
269
270 static index::State state() { return index::PARTIAL; }
271 template <typename LeafT>
272 static index::State state(const LeafT&) { return index::PARTIAL; }
273
274 template <typename LeafT>
275 9 void reset(const LeafT& leaf) {
276 using index_filter_internal::generateRandomSubset;
277
278
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 3 times.
9 auto it = mLeafMap.find(leaf.origin());
279
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (it == mLeafMap.end()) {
280 OPENVDB_THROW(openvdb::KeyError,
281 "Cannot find leaf origin in map for random filter - " << leaf.origin());
282 }
283
284 const SeedCountPair& value = it->second;
285
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
9 const unsigned int seed = static_cast<unsigned int>(value.first);
286 9 const auto total = static_cast<Index>(leaf.pointCount());
287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 mCount = std::min(value.second, total);
288
289 9 mIndices = generateRandomSubset<RandGenT, int>(seed, mCount, total);
290
291 9 mSubsetOffset = -1;
292 9 mNextIndex = -1;
293 9 }
294
295 inline void next() const {
296 2067 mSubsetOffset++;
297
4/4
✓ Branch 0 taken 2011 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 1 times.
2067 mNextIndex = mSubsetOffset >= mCount ?
298 std::numeric_limits<int>::max() :
299 mIndices[mSubsetOffset];
300 2067 }
301
302 template <typename IterT>
303 6000 bool valid(const IterT& iter) const {
304 6000 const int index = *iter;
305
4/4
✓ Branch 0 taken 2016 times.
✓ Branch 1 taken 6100 times.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 100 times.
8267 while (mNextIndex < index) this->next();
306 6000 return mNextIndex == index;
307 }
308
309 protected:
310 friend class ::TestIndexFilter;
311
312 private:
313 LeafMap mLeafMap;
314 std::vector<int> mIndices;
315 int mCount = 0;
316 mutable int mSubsetOffset = -1;
317 mutable int mNextIndex = -1;
318 }; // class RandomLeafFilter
319
320
321 // Hash attribute value for deterministic, but approximate filtering
322 template <typename RandGenT, typename IntType>
323
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 class AttributeHashFilter
324 {
325 public:
326 using Handle = AttributeHandle<IntType>;
327
328 5 AttributeHashFilter(const size_t index,
329 const double percentage,
330 const unsigned int seed = 0)
331 : mIndex(index)
332 , mFactor(percentage / 100.0)
333
5/10
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
5 , mSeed(seed) { }
334
335 2 AttributeHashFilter(const AttributeHashFilter& filter)
336 2 : mIndex(filter.mIndex)
337 2 , mFactor(filter.mFactor)
338
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 , mSeed(filter.mSeed)
339 {
340
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 if (filter.mIdHandle) mIdHandle.reset(new Handle(*filter.mIdHandle));
341 2 }
342
343 inline bool initialized() const { return bool(mIdHandle); }
344
345 static index::State state() { return index::PARTIAL; }
346 template <typename LeafT>
347 static index::State state(const LeafT&) { return index::PARTIAL; }
348
349 template <typename LeafT>
350 9 void reset(const LeafT& leaf) {
351
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 assert(leaf.hasAttribute(mIndex));
352
1/2
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 mIdHandle.reset(new Handle(leaf.constAttributeArray(mIndex)));
353 9 }
354
355 template <typename IterT>
356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 bool valid(const IterT& iter) const {
357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 assert(mIdHandle);
358 16 const IntType id = mIdHandle->get(*iter);
359 16 const unsigned int seed = mSeed + static_cast<unsigned int>(id);
360 16 RandGenT generator(seed);
361 std::uniform_real_distribution<double> dist(0.0, 1.0);
362 16 return dist(generator) < mFactor;
363 }
364
365 private:
366 const size_t mIndex;
367 const double mFactor;
368 const unsigned int mSeed;
369 typename Handle::UniquePtr mIdHandle;
370 }; // class AttributeHashFilter
371
372
373 template <typename LevelSetGridT>
374 class LevelSetFilter
375 {
376 public:
377 using ValueT = typename LevelSetGridT::ValueType;
378 using Handle = AttributeHandle<openvdb::Vec3f>;
379
380
5/10
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
5 LevelSetFilter( const LevelSetGridT& grid,
381 const math::Transform& transform,
382 const ValueT min,
383 const ValueT max)
384 : mAccessor(grid.getConstAccessor())
385 , mLevelSetTransform(grid.transform())
386 , mTransform(transform)
387 , mMin(min)
388
5/10
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
5 , mMax(max) { }
389
390 2 LevelSetFilter(const LevelSetFilter& filter)
391 : mAccessor(filter.mAccessor)
392 2 , mLevelSetTransform(filter.mLevelSetTransform)
393 2 , mTransform(filter.mTransform)
394 2 , mMin(filter.mMin)
395
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 , mMax(filter.mMax)
396 {
397
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 if (filter.mPositionHandle) mPositionHandle.reset(new Handle(*filter.mPositionHandle));
398 2 }
399
400 inline bool initialized() const { return bool(mPositionHandle); }
401
402 static index::State state() { return index::PARTIAL; }
403 template <typename LeafT>
404 static index::State state(const LeafT&) { return index::PARTIAL; }
405
406 template <typename LeafT>
407 10 void reset(const LeafT& leaf) {
408
3/6
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
20 mPositionHandle.reset(new Handle(leaf.constAttributeArray("P")));
409 10 }
410
411 template <typename IterT>
412
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 bool valid(const IterT& iter) const {
413
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 assert(mPositionHandle);
414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 assert(iter);
415
416 12 const openvdb::Coord ijk = iter.getCoord();
417 const openvdb::Vec3f voxelIndexSpace = ijk.asVec3d();
418
419 // Retrieve point position in voxel space
420 12 const openvdb::Vec3f& pointVoxelSpace = mPositionHandle->get(*iter);
421
422 // Compute point position in index space
423 12 const openvdb::Vec3f pointWorldSpace = mTransform.indexToWorld(pointVoxelSpace + voxelIndexSpace);
424 12 const openvdb::Vec3f pointIndexSpace = mLevelSetTransform.worldToIndex(pointWorldSpace);
425
426 // Perform level-set sampling
427 12 const typename LevelSetGridT::ValueType value = tools::BoxSampler::sample(mAccessor, pointIndexSpace);
428
429 // if min is greater than max, we invert so that values are valid outside of the range (not inside)
430 12 const bool invert = mMin > mMax;
431
432
8/10
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 4 times.
12 return invert ? (value < mMax || value > mMin) : (value < mMax && value > mMin);
433 }
434
435 private:
436 // not a reference to ensure const-accessor is unique per-thread
437 const typename LevelSetGridT::ConstAccessor mAccessor;
438 const math::Transform& mLevelSetTransform;
439 const math::Transform& mTransform;
440 const ValueT mMin;
441 const ValueT mMax;
442 Handle::UniquePtr mPositionHandle;
443 }; // class LevelSetFilter
444
445
446 // BBox index filtering
447
6/10
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
9 class BBoxFilter
448 {
449 public:
450 using Handle = AttributeHandle<openvdb::Vec3f>;
451
452 BBoxFilter(const openvdb::math::Transform& transform,
453 const openvdb::BBoxd& bboxWS)
454 6 : mTransform(transform)
455
4/8
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
3 , mBbox(transform.worldToIndex(bboxWS)) { }
456
457 11 BBoxFilter(const BBoxFilter& filter)
458 11 : mTransform(filter.mTransform)
459
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
11 , mBbox(filter.mBbox)
460 {
461
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
11 if (filter.mPositionHandle) mPositionHandle.reset(new Handle(*filter.mPositionHandle));
462 11 }
463
464 inline bool initialized() const { return bool(mPositionHandle); }
465
466 inline index::State state() const
467 {
468 return mBbox.empty() ? index::NONE : index::PARTIAL;
469 }
470 template <typename LeafT>
471 static index::State state(const LeafT&) { return index::PARTIAL; }
472
473 template <typename LeafT>
474 17 void reset(const LeafT& leaf) {
475
3/6
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 17 times.
✗ Branch 8 not taken.
34 mPositionHandle.reset(new Handle(leaf.constAttributeArray("P")));
476 17 }
477
478 template <typename IterT>
479
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
28 bool valid(const IterT& iter) const {
480
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
28 assert(mPositionHandle);
481
482 28 const openvdb::Coord ijk = iter.getCoord();
483 const openvdb::Vec3f voxelIndexSpace = ijk.asVec3d();
484
485 // Retrieve point position in voxel space
486 28 const openvdb::Vec3f& pointVoxelSpace = mPositionHandle->get(*iter);
487
488 // Compute point position in index space
489 const openvdb::Vec3f pointIndexSpace = pointVoxelSpace + voxelIndexSpace;
490
491 28 return mBbox.isInside(pointIndexSpace);
492 }
493
494 private:
495 const openvdb::math::Transform& mTransform;
496 const openvdb::BBoxd mBbox;
497 Handle::UniquePtr mPositionHandle;
498 }; // class BBoxFilter
499
500
501 // Index filtering based on evaluating both sub-filters
502 template <typename T1, typename T2, bool And = true>
503
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
55 class BinaryFilter
504 {
505 public:
506 21 BinaryFilter( const T1& filter1,
507 const T2& filter2)
508 : mFilter1(filter1)
509
7/12
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
11 , mFilter2(filter2) { }
510
511
6/8
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
32 inline bool initialized() const { return mFilter1.initialized() && mFilter2.initialized(); }
512
513
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 6 times.
28 inline index::State state() const
514 {
515 28 return this->computeState(mFilter1.state(), mFilter2.state());
516 }
517 template <typename LeafT>
518 inline index::State state(const LeafT& leaf) const
519 {
520 8 return this->computeState(mFilter1.state(leaf), mFilter2.state(leaf));
521 }
522
523 template <typename LeafT>
524 void reset(const LeafT& leaf) {
525
2/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
17 mFilter1.reset(leaf);
526
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 mFilter2.reset(leaf);
527 19 }
528
529 template <typename IterT>
530 82 bool valid(const IterT& iter) const {
531
6/6
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 55 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 3 times.
214 if (And) return mFilter1.valid(iter) && mFilter2.valid(iter);
532
4/4
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 91 times.
100 return mFilter1.valid(iter) || mFilter2.valid(iter);
533 }
534
535 private:
536 inline index::State computeState( index::State state1,
537 index::State state2) const
538 {
539 if (And) {
540
3/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
29 if (state1 == index::NONE || state2 == index::NONE) return index::NONE;
541
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 19 times.
20 else if (state1 == index::ALL && state2 == index::ALL) return index::ALL;
542 } else {
543
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (state1 == index::NONE && state2 == index::NONE) return index::NONE;
544
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 else if (state1 == index::ALL && state2 == index::ALL) return index::ALL;
545 }
546 return index::PARTIAL;
547 }
548
549 T1 mFilter1;
550 T2 mFilter2;
551 }; // class BinaryFilter
552
553
554 ////////////////////////////////////////
555
556
557 template<typename T>
558 struct FilterTraits {
559 static const bool RequiresCoord = false;
560 };
561 template<>
562 struct FilterTraits<BBoxFilter> {
563 static const bool RequiresCoord = true;
564 };
565 template <typename T>
566 struct FilterTraits<LevelSetFilter<T>> {
567 static const bool RequiresCoord = true;
568 };
569 template <typename T0, typename T1, bool And>
570 struct FilterTraits<BinaryFilter<T0, T1, And>> {
571 static const bool RequiresCoord = FilterTraits<T0>::RequiresCoord ||
572 FilterTraits<T1>::RequiresCoord;
573 };
574
575
576 ////////////////////////////////////////
577
578
579 } // namespace points
580 } // namespace OPENVDB_VERSION_NAME
581 } // namespace openvdb
582
583 #endif // OPENVDB_POINTS_INDEX_FILTER_HAS_BEEN_INCLUDED
584