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 |