Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright Contributors to the OpenVDB Project | ||
2 | // SPDX-License-Identifier: MPL-2.0 | ||
3 | /// | ||
4 | /// @file Diagnostics.h | ||
5 | /// | ||
6 | /// @author Ken Museth | ||
7 | /// | ||
8 | /// @brief Various diagnostic tools to identify potential issues with | ||
9 | /// for example narrow-band level sets or fog volumes | ||
10 | /// | ||
11 | #ifndef OPENVDB_TOOLS_DIAGNOSTICS_HAS_BEEN_INCLUDED | ||
12 | #define OPENVDB_TOOLS_DIAGNOSTICS_HAS_BEEN_INCLUDED | ||
13 | |||
14 | #include "openvdb/Grid.h" | ||
15 | #include "openvdb/math/Math.h" | ||
16 | #include "openvdb/math/Vec3.h" | ||
17 | #include "openvdb/math/Stencils.h" | ||
18 | #include "openvdb/math/Operators.h" | ||
19 | #include "openvdb/tree/LeafManager.h" | ||
20 | #include "openvdb/thread/Threading.h" | ||
21 | #include <openvdb/openvdb.h> | ||
22 | |||
23 | #include <tbb/blocked_range.h> | ||
24 | #include <tbb/parallel_reduce.h> | ||
25 | |||
26 | #include <cmath> // for std::isnan(), std::isfinite() | ||
27 | #include <set> | ||
28 | #include <sstream> | ||
29 | #include <string> | ||
30 | #include <type_traits> | ||
31 | #include <vector> | ||
32 | |||
33 | namespace openvdb { | ||
34 | OPENVDB_USE_VERSION_NAMESPACE | ||
35 | namespace OPENVDB_VERSION_NAME { | ||
36 | namespace tools { | ||
37 | |||
38 | //////////////////////////////////////////////////////////////////////////////// | ||
39 | |||
40 | /// @brief Perform checks on a grid to see if it is a valid symmetric, | ||
41 | /// narrow-band level set. | ||
42 | /// | ||
43 | /// @param grid Grid to be checked | ||
44 | /// @param number Number of the checks to be performed (see below) | ||
45 | /// @return string with a message indicating the nature of the | ||
46 | /// issue. If no issue is detected the return string is empty. | ||
47 | /// | ||
48 | /// @details @a number refers to the following ordered list of | ||
49 | /// checks - always starting from the top. | ||
50 | /// Fast checks | ||
51 | /// 1: value type is floating point | ||
52 | /// 2: has level set class type | ||
53 | /// 3: has uniform scale | ||
54 | /// 4: background value is positive and n*dx | ||
55 | /// | ||
56 | /// Slower checks | ||
57 | /// 5: no active tiles | ||
58 | /// 6: all the values are finite, i.e not NaN or infinite | ||
59 | /// 7: active values in range between +-background | ||
60 | /// 8: abs of inactive values = background, i.e. assuming a symmetric | ||
61 | /// narrow band! | ||
62 | /// | ||
63 | /// Relatively slow check (however multithreaded) | ||
64 | /// 9: norm gradient is close to one, i.e. satisfied the Eikonal equation. | ||
65 | template<class GridType> | ||
66 | std::string | ||
67 | checkLevelSet(const GridType& grid, size_t number=9); | ||
68 | |||
69 | //////////////////////////////////////////////////////////////////////////////// | ||
70 | |||
71 | /// @brief Perform checks on a grid to see if it is a valid fog volume. | ||
72 | /// | ||
73 | /// @param grid Grid to be checked | ||
74 | /// @param number Number of the checks to be performed (see below) | ||
75 | /// @return string with a message indicating the nature of the | ||
76 | /// issue. If no issue is detected the return string is empty. | ||
77 | /// | ||
78 | /// @details @a number refers to the following ordered list of | ||
79 | /// checks - always starting from the top. | ||
80 | /// Fast checks | ||
81 | /// 1: value type is floating point | ||
82 | /// 2: has FOG volume class type | ||
83 | /// 3: background value is zero | ||
84 | /// | ||
85 | /// Slower checks | ||
86 | /// 4: all the values are finite, i.e not NaN or infinite | ||
87 | /// 5: inactive values are zero | ||
88 | /// 6: active values are in the range [0,1] | ||
89 | template<class GridType> | ||
90 | std::string | ||
91 | checkFogVolume(const GridType& grid, size_t number=6); | ||
92 | |||
93 | //////////////////////////////////////////////////////////////////////////////// | ||
94 | |||
95 | /// @brief Threaded method to find unique inactive values. | ||
96 | /// | ||
97 | /// @param grid A VDB volume. | ||
98 | /// @param values List of unique inactive values, returned by this method. | ||
99 | /// @param numValues Number of values to look for. | ||
100 | /// @return @c false if the @a grid has more than @a numValues inactive values. | ||
101 | template<class GridType> | ||
102 | bool | ||
103 | uniqueInactiveValues(const GridType& grid, | ||
104 | std::vector<typename GridType::ValueType>& values, size_t numValues); | ||
105 | |||
106 | |||
107 | //////////////////////////////////////////////////////////////////////////////// | ||
108 | |||
109 | /// @brief Checks NaN values | ||
110 | template<typename GridT, typename TreeIterT = typename GridT::ValueOnCIter> | ||
111 | struct CheckNan | ||
112 | { | ||
113 | using ElementType = typename VecTraits<typename GridT::ValueType>::ElementType; | ||
114 | using TileIterT = TreeIterT; | ||
115 | using VoxelIterT = typename tree::IterTraits< | ||
116 | typename TreeIterT::NodeT, typename TreeIterT::ValueIterT>::template | ||
117 | NodeConverter<typename GridT::TreeType::LeafNodeType>::Type; | ||
118 | |||
119 | /// @brief Default constructor | ||
120 | CheckNan() {} | ||
121 | |||
122 | /// Return true if the scalar value is NaN | ||
123 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | inline bool operator()(const ElementType& v) const { return std::isnan(v); } |
124 | |||
125 | /// @brief This allows for vector values to be checked component-wise | ||
126 | template<typename T> | ||
127 | inline typename std::enable_if<VecTraits<T>::IsVec, bool>::type | ||
128 | 1 | operator()(const T& v) const | |
129 | { | ||
130 |
3/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
4 | for (int i=0; i<VecTraits<T>::Size; ++i) if ((*this)(v[i])) return true;//should unroll |
131 | return false; | ||
132 | } | ||
133 | |||
134 | /// @brief Return true if the tile at the iterator location is NaN | ||
135 | bool operator()(const TreeIterT &iter) const { return (*this)(*iter); } | ||
136 | |||
137 | /// @brief Return true if the voxel at the iterator location is NaN | ||
138 | bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); } | ||
139 | |||
140 | /// @brief Return a string describing a failed check. | ||
141 |
1/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1 | std::string str() const { return "NaN"; } |
142 | |||
143 | };// CheckNan | ||
144 | |||
145 | //////////////////////////////////////////////////////////////////////////////// | ||
146 | |||
147 | /// @brief Checks for infinite values, e.g. 1/0 or -1/0 | ||
148 | template <typename GridT, | ||
149 | typename TreeIterT = typename GridT::ValueOnCIter> | ||
150 | struct CheckInf | ||
151 | { | ||
152 | using ElementType = typename VecTraits<typename GridT::ValueType>::ElementType; | ||
153 | using TileIterT = TreeIterT; | ||
154 | using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT, | ||
155 | typename TreeIterT::ValueIterT> ::template NodeConverter< | ||
156 | typename GridT::TreeType::LeafNodeType>::Type; | ||
157 | |||
158 | /// @brief Default constructor | ||
159 | CheckInf() {} | ||
160 | |||
161 | /// Return true if the value is infinite | ||
162 | inline bool operator()(const ElementType& v) const { return std::isinf(v); } | ||
163 | |||
164 | /// Return true if any of the vector components are infinite. | ||
165 | template<typename T> | ||
166 | inline typename std::enable_if<VecTraits<T>::IsVec, bool>::type | ||
167 | 1 | operator()(const T& v) const | |
168 | { | ||
169 |
3/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
|
3 | for (int i=0; i<VecTraits<T>::Size; ++i) if ((*this)(v[i])) return true; |
170 | return false; | ||
171 | } | ||
172 | |||
173 | /// @brief Return true if the tile at the iterator location is infinite | ||
174 | bool operator()(const TreeIterT &iter) const { return (*this)(*iter); } | ||
175 | |||
176 | /// @brief Return true if the tile at the iterator location is infinite | ||
177 | bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); } | ||
178 | |||
179 | /// @brief Return a string describing a failed check. | ||
180 | std::string str() const { return "infinite"; } | ||
181 | };// CheckInf | ||
182 | |||
183 | //////////////////////////////////////////////////////////////////////////////// | ||
184 | |||
185 | /// @brief Checks for both NaN and inf values, i.e. any value that is not finite. | ||
186 | template <typename GridT, | ||
187 | typename TreeIterT = typename GridT::ValueOnCIter> | ||
188 | struct CheckFinite | ||
189 | { | ||
190 | using ElementType = typename VecTraits<typename GridT::ValueType>::ElementType; | ||
191 | using TileIterT = TreeIterT; | ||
192 | using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT, | ||
193 | typename TreeIterT::ValueIterT> ::template NodeConverter< | ||
194 | typename GridT::TreeType::LeafNodeType>::Type; | ||
195 | |||
196 | /// @brief Default constructor | ||
197 | CheckFinite() {} | ||
198 | |||
199 | /// Return true if the value is NOT finite, i.e. it's NaN or infinite | ||
200 |
5/16✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2046464 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 356411 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 6 times.
|
2402884 | inline bool operator()(const ElementType& v) const { return !std::isfinite(v); } |
201 | |||
202 | /// Return true if any of the vector components are NaN or infinite. | ||
203 | template<typename T> | ||
204 | inline typename std::enable_if<VecTraits<T>::IsVec, bool>::type | ||
205 | 1 | operator()(const T& v) const { | |
206 |
3/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
|
3 | for (int i=0; i<VecTraits<T>::Size; ++i) if ((*this)(v[i])) return true; |
207 | return false; | ||
208 | } | ||
209 | |||
210 | /// @brief Return true if the tile at the iterator location is NaN or infinite. | ||
211 | bool operator()(const TreeIterT &iter) const { return (*this)(*iter); } | ||
212 | |||
213 | /// @brief Return true if the tile at the iterator location is NaN or infinite. | ||
214 | bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); } | ||
215 | |||
216 | /// @brief Return a string describing a failed check. | ||
217 |
1/8✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
1 | std::string str() const { return "not finite"; } |
218 | };// CheckFinite | ||
219 | |||
220 | //////////////////////////////////////////////////////////////////////////////// | ||
221 | |||
222 | /// @brief Check that the magnitude of a value, a, is close to a fixed | ||
223 | /// magnitude, b, given a fixed tolerance c. That is | |a| - |b| | <= c | ||
224 | template <typename GridT, | ||
225 | typename TreeIterT = typename GridT::ValueOffCIter> | ||
226 | struct CheckMagnitude | ||
227 | { | ||
228 | using ElementType = typename VecTraits<typename GridT::ValueType>::ElementType; | ||
229 | using TileIterT = TreeIterT; | ||
230 | using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT, | ||
231 | typename TreeIterT::ValueIterT> ::template NodeConverter< | ||
232 | typename GridT::TreeType::LeafNodeType>::Type; | ||
233 | |||
234 | /// @brief Default constructor | ||
235 | 5 | CheckMagnitude(const ElementType& a, | |
236 | const ElementType& t = math::Tolerance<ElementType>::value()) | ||
237 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | : absVal(math::Abs(a)), tolVal(math::Abs(t)) |
238 | { | ||
239 | } | ||
240 | |||
241 | /// Return true if the magnitude of the value is not approximately | ||
242 | /// equal to totVal. | ||
243 | inline bool operator()(const ElementType& v) const | ||
244 | { | ||
245 |
3/16✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 900171 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 290719 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
1190894 | return math::Abs(math::Abs(v) - absVal) > tolVal; |
246 | } | ||
247 | |||
248 | /// Return true if any of the vector components are infinite. | ||
249 | template<typename T> | ||
250 | inline typename std::enable_if<VecTraits<T>::IsVec, bool>::type | ||
251 | operator()(const T& v) const | ||
252 | { | ||
253 | for (int i=0; i<VecTraits<T>::Size; ++i) if ((*this)(v[i])) return true; | ||
254 | return false; | ||
255 | } | ||
256 | |||
257 | /// @brief Return true if the tile at the iterator location is infinite | ||
258 | bool operator()(const TreeIterT &iter) const { return (*this)(*iter); } | ||
259 | |||
260 | /// @brief Return true if the tile at the iterator location is infinite | ||
261 | bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); } | ||
262 | |||
263 | /// @brief Return a string describing a failed check. | ||
264 | ✗ | std::string str() const | |
265 | { | ||
266 | ✗ | std::ostringstream ss; | |
267 | ✗ | ss << "not equal to +/-"<<absVal<<" with a tolerance of "<<tolVal; | |
268 | ✗ | return ss.str(); | |
269 | } | ||
270 | |||
271 | const ElementType absVal, tolVal; | ||
272 | };// CheckMagnitude | ||
273 | |||
274 | //////////////////////////////////////////////////////////////////////////////// | ||
275 | |||
276 | /// @brief Checks a value against a range | ||
277 | template <typename GridT, | ||
278 | bool MinInclusive = true,//is min part of the range? | ||
279 | bool MaxInclusive = true,//is max part of the range? | ||
280 | typename TreeIterT = typename GridT::ValueOnCIter> | ||
281 | struct CheckRange | ||
282 | { | ||
283 | using ElementType = typename VecTraits<typename GridT::ValueType>::ElementType; | ||
284 | using TileIterT = TreeIterT; | ||
285 | using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT, | ||
286 | typename TreeIterT::ValueIterT> ::template NodeConverter< | ||
287 | typename GridT::TreeType::LeafNodeType>::Type; | ||
288 | |||
289 | // @brief Constructor taking a range to be tested against. | ||
290 | 28 | CheckRange(const ElementType& _min, const ElementType& _max) : minVal(_min), maxVal(_max) | |
291 | { | ||
292 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 13 times.
|
28 | if (minVal > maxVal) { |
293 |
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.
|
8 | OPENVDB_THROW(ValueError, "CheckRange: Invalid range (min > max)"); |
294 | } | ||
295 | 26 | } | |
296 | |||
297 | /// Return true if the value is smaller than min or larger than max. | ||
298 | inline bool operator()(const ElementType& v) const | ||
299 | { | ||
300 |
17/34✓ Branch 0 taken 48896 times.
✓ Branch 1 taken 44150 times.
✓ Branch 2 taken 800105 times.
✓ Branch 3 taken 44150 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 339456 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 246410 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 56675 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 56675 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 683 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 6 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 1 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 1 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 1 times.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✓ Branch 33 taken 1 times.
|
1637213 | return (MinInclusive ? v<minVal : v<=minVal) || |
301 |
17/34✗ Branch 0 not taken.
✓ Branch 1 taken 48896 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 800102 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 339456 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 246410 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 56675 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 56675 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 1 times.
✓ Branch 20 taken 1 times.
✓ Branch 21 taken 682 times.
✓ Branch 22 taken 1 times.
✓ Branch 23 taken 5 times.
✓ Branch 24 taken 1 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 1 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
|
1548912 | (MaxInclusive ? v>maxVal : v>=maxVal); |
302 | } | ||
303 | |||
304 | /// Return true if any of the vector components are out of range. | ||
305 | template<typename T> | ||
306 | inline typename std::enable_if<VecTraits<T>::IsVec, bool>::type | ||
307 | operator()(const T& v) const { | ||
308 | for (int i=0; i<VecTraits<T>::Size; ++i) if ((*this)(v[i])) return true; | ||
309 | return false; | ||
310 | } | ||
311 | |||
312 | /// @brief Return true if the voxel at the iterator location is out of range. | ||
313 | bool operator()(const TreeIterT &iter) const { return (*this)(*iter); } | ||
314 | |||
315 | /// @brief Return true if the tile at the iterator location is out of range. | ||
316 | bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); } | ||
317 | |||
318 | /// @brief Return a string describing a failed check. | ||
319 | 14 | std::string str() const | |
320 | { | ||
321 | 28 | std::ostringstream ss; | |
322 | ss << "outside the value range " << (MinInclusive ? "[" : "]") | ||
323 |
3/6✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
|
28 | << minVal << "," << maxVal << (MaxInclusive ? "]" : "["); |
324 | 14 | return ss.str(); | |
325 | } | ||
326 | |||
327 | const ElementType minVal, maxVal; | ||
328 | };// CheckRange | ||
329 | |||
330 | //////////////////////////////////////////////////////////////////////////////// | ||
331 | |||
332 | /// @brief Checks a value against a minimum | ||
333 | template <typename GridT, | ||
334 | typename TreeIterT = typename GridT::ValueOnCIter> | ||
335 | struct CheckMin | ||
336 | { | ||
337 | using ElementType = typename VecTraits<typename GridT::ValueType>::ElementType; | ||
338 | using TileIterT = TreeIterT; | ||
339 | using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT, | ||
340 | typename TreeIterT::ValueIterT> ::template NodeConverter< | ||
341 | typename GridT::TreeType::LeafNodeType>::Type; | ||
342 | |||
343 | // @brief Constructor taking a minimum to be tested against. | ||
344 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | CheckMin(const ElementType& _min) : minVal(_min) {} |
345 | |||
346 | /// Return true if the value is smaller than min. | ||
347 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | inline bool operator()(const ElementType& v) const { return v<minVal; } |
348 | |||
349 | /// Return true if any of the vector components are smaller than min. | ||
350 | template<typename T> | ||
351 | inline typename std::enable_if<VecTraits<T>::IsVec, bool>::type | ||
352 | operator()(const T& v) const { | ||
353 | for (int i=0; i<VecTraits<T>::Size; ++i) if ((*this)(v[i])) return true; | ||
354 | return false; | ||
355 | } | ||
356 | |||
357 | /// @brief Return true if the voxel at the iterator location is smaller than min. | ||
358 | bool operator()(const TreeIterT &iter) const { return (*this)(*iter); } | ||
359 | |||
360 | /// @brief Return true if the tile at the iterator location is smaller than min. | ||
361 | bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); } | ||
362 | |||
363 | /// @brief Return a string describing a failed check. | ||
364 | ✗ | std::string str() const | |
365 | { | ||
366 | ✗ | std::ostringstream ss; | |
367 | ✗ | ss << "smaller than "<<minVal; | |
368 | ✗ | return ss.str(); | |
369 | } | ||
370 | |||
371 | const ElementType minVal; | ||
372 | };// CheckMin | ||
373 | |||
374 | //////////////////////////////////////////////////////////////////////////////// | ||
375 | |||
376 | /// @brief Checks a value against a maximum | ||
377 | template <typename GridT, | ||
378 | typename TreeIterT = typename GridT::ValueOnCIter> | ||
379 | struct CheckMax | ||
380 | { | ||
381 | using ElementType = typename VecTraits<typename GridT::ValueType>::ElementType; | ||
382 | using TileIterT = TreeIterT; | ||
383 | using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT, | ||
384 | typename TreeIterT::ValueIterT> ::template NodeConverter< | ||
385 | typename GridT::TreeType::LeafNodeType>::Type; | ||
386 | |||
387 | /// @brief Constructor taking a maximum to be tested against. | ||
388 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | CheckMax(const ElementType& _max) : maxVal(_max) {} |
389 | |||
390 | /// Return true if the value is larger than max. | ||
391 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | inline bool operator()(const ElementType& v) const { return v>maxVal; } |
392 | |||
393 | /// Return true if any of the vector components are larger than max. | ||
394 | template<typename T> | ||
395 | inline typename std::enable_if<VecTraits<T>::IsVec, bool>::type | ||
396 | operator()(const T& v) const { | ||
397 | for (int i=0; i<VecTraits<T>::Size; ++i) if ((*this)(v[i])) return true; | ||
398 | return false; | ||
399 | } | ||
400 | |||
401 | /// @brief Return true if the tile at the iterator location is larger than max. | ||
402 | bool operator()(const TreeIterT &iter) const { return (*this)(*iter); } | ||
403 | |||
404 | /// @brief Return true if the voxel at the iterator location is larger than max. | ||
405 | bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); } | ||
406 | |||
407 | /// @brief Return a string describing a failed check. | ||
408 | ✗ | std::string str() const | |
409 | { | ||
410 | ✗ | std::ostringstream ss; | |
411 | ✗ | ss << "larger than "<<maxVal; | |
412 | ✗ | return ss.str(); | |
413 | } | ||
414 | |||
415 | const ElementType maxVal; | ||
416 | };// CheckMax | ||
417 | |||
418 | //////////////////////////////////////////////////////////////////////////////// | ||
419 | |||
420 | /// @brief Checks the norm of the gradient against a range, i.e., | ||
421 | /// |∇Φ| ∈ [min, max] | ||
422 | /// | ||
423 | /// @note Internally the test is performed as | ||
424 | /// |∇Φ|² ∈ [min², max²] for optimization reasons. | ||
425 | template<typename GridT, | ||
426 | typename TreeIterT = typename GridT::ValueOnCIter, | ||
427 | math::BiasedGradientScheme GradScheme = math::FIRST_BIAS>//math::WENO5_BIAS> | ||
428 |
7/14✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ 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.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
|
7 | struct CheckNormGrad |
429 | { | ||
430 | using ValueType = typename GridT::ValueType; | ||
431 | static_assert(std::is_floating_point<ValueType>::value, | ||
432 | "openvdb::tools::CheckNormGrad requires a scalar, floating-point grid"); | ||
433 | using TileIterT = TreeIterT; | ||
434 | using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT, | ||
435 | typename TreeIterT::ValueIterT> ::template NodeConverter< | ||
436 | typename GridT::TreeType::LeafNodeType>::Type; | ||
437 | using AccT = typename GridT::ConstAccessor; | ||
438 | |||
439 | /// @brief Constructor taking a grid and a range to be tested against. | ||
440 | 10 | CheckNormGrad(const GridT& grid, const ValueType& _min, const ValueType& _max) | |
441 | : acc(grid.getConstAccessor()) | ||
442 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | , invdx2(ValueType(1.0/math::Pow2(grid.voxelSize()[0]))) |
443 | 10 | , minVal2(_min*_min) | |
444 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | , maxVal2(_max*_max) |
445 | { | ||
446 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if ( !grid.hasUniformVoxels() ) { |
447 | ✗ | OPENVDB_THROW(ValueError, "CheckNormGrad: The transform must have uniform scale"); | |
448 | } | ||
449 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (_min > _max) { |
450 | ✗ | OPENVDB_THROW(ValueError, "CheckNormGrad: Invalid range (min > max)"); | |
451 | } | ||
452 | 10 | } | |
453 | |||
454 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
|
53 | CheckNormGrad(const CheckNormGrad& other) |
455 | : acc(other.acc.tree()) | ||
456 | 53 | , invdx2(other.invdx2) | |
457 | 53 | , minVal2(other.minVal2) | |
458 | 53 | , maxVal2(other.maxVal2) | |
459 | { | ||
460 | 53 | } | |
461 | |||
462 | /// Return true if the value is smaller than min or larger than max. | ||
463 |
2/10✓ Branch 0 taken 3588061 times.
✓ Branch 1 taken 995122 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
4583183 | inline bool operator()(const ValueType& v) const { return v<minVal2 || v>maxVal2; } |
464 | |||
465 | /// @brief Return true if zero is outside the range. | ||
466 | /// @note We assume that the norm of the gradient of a tile is always zero. | ||
467 | inline bool operator()(const TreeIterT&) const { return (*this)(ValueType(0)); } | ||
468 | |||
469 | /// @brief Return true if the norm of the gradient at a voxel | ||
470 | /// location of the iterator is out of range. | ||
471 | 5536921 | inline bool operator()(const VoxelIterT &iter) const | |
472 | { | ||
473 | 5536921 | const Coord ijk = iter.getCoord(); | |
474 |
2/2✓ Branch 1 taken 4583183 times.
✓ Branch 2 taken 953738 times.
|
5536921 | return (*this)(invdx2 * math::ISGradientNormSqrd<GradScheme>::result(acc, ijk)); |
475 | } | ||
476 | |||
477 | /// @brief Return a string describing a failed check. | ||
478 | 3 | std::string str() const | |
479 | { | ||
480 | 6 | std::ostringstream ss; | |
481 |
3/6✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
|
6 | ss << "outside the range of NormGrad ["<<math::Sqrt(minVal2)<<","<<math::Sqrt(maxVal2)<<"]"; |
482 | 3 | return ss.str(); | |
483 | } | ||
484 | |||
485 | AccT acc; | ||
486 | const ValueType invdx2, minVal2, maxVal2; | ||
487 | };// CheckNormGrad | ||
488 | |||
489 | //////////////////////////////////////////////////////////////////////////////// | ||
490 | |||
491 | /// @brief Checks the norm of the gradient at zero-crossing voxels against a range | ||
492 | /// @details CheckEikonal differs from CheckNormGrad in that it only | ||
493 | /// checks the norm of the gradient at voxel locations where the | ||
494 | /// FD-stencil crosses the zero isosurface! | ||
495 | template<typename GridT, | ||
496 | typename TreeIterT = typename GridT::ValueOnCIter, | ||
497 | typename StencilT = math::WenoStencil<GridT> >//math::GradStencil<GridT> | ||
498 | struct CheckEikonal | ||
499 | { | ||
500 | using ValueType = typename GridT::ValueType; | ||
501 | static_assert(std::is_floating_point<ValueType>::value, | ||
502 | "openvdb::tools::CheckEikonal requires a scalar, floating-point grid"); | ||
503 | using TileIterT = TreeIterT; | ||
504 | using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT, | ||
505 | typename TreeIterT::ValueIterT> ::template NodeConverter< | ||
506 | typename GridT::TreeType::LeafNodeType>::Type; | ||
507 | |||
508 | /// @brief Constructor taking a grid and a range to be tested against. | ||
509 | 2 | CheckEikonal(const GridT& grid, const ValueType& _min, const ValueType& _max) | |
510 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | : stencil(grid), minVal(_min), maxVal(_max) |
511 | { | ||
512 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if ( !grid.hasUniformVoxels() ) { |
513 | ✗ | OPENVDB_THROW(ValueError, "CheckEikonal: The transform must have uniform scale"); | |
514 | } | ||
515 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (minVal > maxVal) { |
516 | ✗ | OPENVDB_THROW(ValueError, "CheckEikonal: Invalid range (min > max)"); | |
517 | } | ||
518 | 2 | } | |
519 | |||
520 | 4 | CheckEikonal(const CheckEikonal& other) | |
521 | 2 | : stencil(other.stencil.grid()), minVal(other.minVal), maxVal(other.maxVal) | |
522 | { | ||
523 | } | ||
524 | |||
525 | /// Return true if the value is smaller than min or larger than max. | ||
526 |
1/20✓ Branch 0 taken 76612 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
76612 | inline bool operator()(const ValueType& v) const { return v<minVal || v>maxVal; } |
527 | |||
528 | /// @brief Return true if zero is outside the range. | ||
529 | /// @note We assume that the norm of the gradient of a tile is always zero. | ||
530 | inline bool operator()(const TreeIterT&) const { return (*this)(ValueType(0)); } | ||
531 | |||
532 | /// @brief Return true if the norm of the gradient at a | ||
533 | /// zero-crossing voxel location of the iterator is out of range. | ||
534 | 232732 | inline bool operator()(const VoxelIterT &iter) const | |
535 | { | ||
536 | 232732 | stencil.moveTo(iter); | |
537 |
2/2✓ Branch 0 taken 76612 times.
✓ Branch 1 taken 156120 times.
|
232732 | if (!stencil.zeroCrossing()) return false; |
538 |
1/2✓ Branch 0 taken 76612 times.
✗ Branch 1 not taken.
|
153224 | return (*this)(stencil.normSqGrad()); |
539 | } | ||
540 | |||
541 | /// @brief Return a string describing a failed check. | ||
542 | ✗ | std::string str() const | |
543 | { | ||
544 | ✗ | std::ostringstream ss; | |
545 | ✗ | ss << "outside the range of NormGrad ["<<minVal<<","<<maxVal<<"]"; | |
546 | ✗ | return ss.str(); | |
547 | } | ||
548 | |||
549 | mutable StencilT stencil; | ||
550 | const ValueType minVal, maxVal; | ||
551 | };// CheckEikonal | ||
552 | |||
553 | //////////////////////////////////////////////////////////////////////////////// | ||
554 | |||
555 | /// @brief Checks the divergence against a range | ||
556 | template<typename GridT, | ||
557 | typename TreeIterT = typename GridT::ValueOnCIter, | ||
558 | math::DScheme DiffScheme = math::CD_2ND> | ||
559 | struct CheckDivergence | ||
560 | { | ||
561 | using ValueType = typename GridT::ValueType; | ||
562 | using ElementType = typename VecTraits<ValueType>::ElementType; | ||
563 | static_assert(std::is_floating_point<ElementType>::value, | ||
564 | "openvdb::tools::CheckDivergence requires a floating-point vector grid"); | ||
565 | using TileIterT = TreeIterT; | ||
566 | using VoxelIterT = typename tree::IterTraits<typename TreeIterT::NodeT, | ||
567 | typename TreeIterT::ValueIterT>::template NodeConverter< | ||
568 | typename GridT::TreeType::LeafNodeType>::Type; | ||
569 | using AccT = typename GridT::ConstAccessor; | ||
570 | |||
571 | /// @brief Constructor taking a grid and a range to be tested against. | ||
572 | CheckDivergence(const GridT& grid, | ||
573 | const ValueType& _min, | ||
574 | const ValueType& _max) | ||
575 | : acc(grid.getConstAccessor()) | ||
576 | , invdx(ValueType(1.0/grid.voxelSize()[0])) | ||
577 | , minVal(_min) | ||
578 | , maxVal(_max) | ||
579 | { | ||
580 | if ( !grid.hasUniformVoxels() ) { | ||
581 | OPENVDB_THROW(ValueError, "CheckDivergence: The transform must have uniform scale"); | ||
582 | } | ||
583 | if (minVal > maxVal) { | ||
584 | OPENVDB_THROW(ValueError, "CheckDivergence: Invalid range (min > max)"); | ||
585 | } | ||
586 | } | ||
587 | /// Return true if the value is smaller than min or larger than max. | ||
588 | inline bool operator()(const ElementType& v) const { return v<minVal || v>maxVal; } | ||
589 | |||
590 | /// @brief Return true if zero is outside the range. | ||
591 | /// @note We assume that the divergence of a tile is always zero. | ||
592 | inline bool operator()(const TreeIterT&) const { return (*this)(ElementType(0)); } | ||
593 | |||
594 | /// @brief Return true if the divergence at a voxel location of | ||
595 | /// the iterator is out of range. | ||
596 | inline bool operator()(const VoxelIterT &iter) const | ||
597 | { | ||
598 | const Coord ijk = iter.getCoord(); | ||
599 | return (*this)(invdx * math::ISDivergence<DiffScheme>::result(acc, ijk)); | ||
600 | } | ||
601 | |||
602 | /// @brief Return a string describing a failed check. | ||
603 | std::string str() const | ||
604 | { | ||
605 | std::ostringstream ss; | ||
606 | ss << "outside the range of divergence ["<<minVal<<","<<maxVal<<"]"; | ||
607 | return ss.str(); | ||
608 | } | ||
609 | |||
610 | AccT acc; | ||
611 | const ValueType invdx, minVal, maxVal; | ||
612 | };// CheckDivergence | ||
613 | |||
614 | //////////////////////////////////////////////////////////////////////////////// | ||
615 | |||
616 | /// @brief Performs multithreaded diagnostics of a grid | ||
617 | /// @note More documentation will be added soon! | ||
618 | template <typename GridT> | ||
619 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
9 | class Diagnose |
620 | { | ||
621 | public: | ||
622 | using MaskType = typename GridT::template ValueConverter<bool>::Type; | ||
623 | |||
624 | 64 | Diagnose(const GridT& grid) : mGrid(&grid), mMask(new MaskType()), mCount(0) | |
625 | { | ||
626 |
3/10✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 32 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 32 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
|
64 | mMask->setTransform(grid.transformPtr()->copy()); |
627 | 32 | } | |
628 | |||
629 | template <typename CheckT> | ||
630 | 82 | std::string check(const CheckT& check, | |
631 | bool updateMask = false, | ||
632 | bool checkVoxels = true, | ||
633 | bool checkTiles = true, | ||
634 | bool checkBackground = true) | ||
635 | { | ||
636 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 40 times.
|
82 | typename MaskType::TreeType* mask = updateMask ? &(mMask->tree()) : nullptr; |
637 | 82 | CheckValues<CheckT> cc(mask, mGrid, check); | |
638 | 82 | std::ostringstream ss; | |
639 |
3/4✓ Branch 0 taken 24 times.
✓ Branch 1 taken 17 times.
✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
|
130 | if (checkBackground) ss << cc.checkBackground(); |
640 |
3/4✓ Branch 0 taken 27 times.
✓ Branch 1 taken 14 times.
✓ Branch 3 taken 27 times.
✗ Branch 4 not taken.
|
136 | if (checkTiles) ss << cc.checkTiles(); |
641 |
2/4✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 41 times.
✗ Branch 4 not taken.
|
164 | if (checkVoxels) ss << cc.checkVoxels(); |
642 |
1/2✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
|
82 | mCount += cc.mCount; |
643 | 82 | return ss.str(); | |
644 | } | ||
645 | |||
646 | //@{ | ||
647 | /// @brief Return a boolean mask of all the values | ||
648 | /// (i.e. tiles and/or voxels) that have failed one or | ||
649 | /// more checks. | ||
650 | typename MaskType::ConstPtr mask() const { return mMask; } | ||
651 | typename MaskType::Ptr mask() { return mMask; } | ||
652 | //@} | ||
653 | |||
654 | /// @brief Return the number of values (i.e. background, tiles or | ||
655 | /// voxels) that have failed one or more checks. | ||
656 |
11/22✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 32 not taken.
|
14 | Index64 valueCount() const { return mMask->activeVoxelCount(); } |
657 | |||
658 | /// @brief Return total number of failed checks | ||
659 | /// @note If only one check was performed and the mask was updated | ||
660 | /// failureCount equals valueCount. | ||
661 |
15/30✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 2 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.
|
26 | Index64 failureCount() const { return mCount; } |
662 | |||
663 | /// @brief Return a const reference to the grid | ||
664 | ✗ | const GridT& grid() const { return *mGrid; } | |
665 | |||
666 | /// @brief Clear the mask and error counter | ||
667 | void clear() { mMask = new MaskType(); mCount = 0; } | ||
668 | |||
669 | private: | ||
670 | // disallow copy construction and copy by assignment! | ||
671 | Diagnose(const Diagnose&);// not implemented | ||
672 | Diagnose& operator=(const Diagnose&);// not implemented | ||
673 | |||
674 | const GridT* mGrid; | ||
675 | typename MaskType::Ptr mMask; | ||
676 | Index64 mCount; | ||
677 | |||
678 | /// @brief Private class that performs the multithreaded checks | ||
679 | template <typename CheckT> | ||
680 | struct CheckValues | ||
681 | { | ||
682 | using MaskT = typename MaskType::TreeType; | ||
683 | using LeafT = typename GridT::TreeType::LeafNodeType; | ||
684 | using LeafManagerT = typename tree::LeafManager<const typename GridT::TreeType>; | ||
685 | const bool mOwnsMask; | ||
686 | MaskT* mMask; | ||
687 | const GridT* mGrid; | ||
688 | const CheckT mCheck; | ||
689 | Index64 mCount; | ||
690 | |||
691 | 41 | CheckValues(MaskT* mask, const GridT* grid, const CheckT& check) | |
692 | : mOwnsMask(false) | ||
693 | , mMask(mask) | ||
694 | , mGrid(grid) | ||
695 | , mCheck(check) | ||
696 |
10/23✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 21 taken 1 times.
✗ Branch 22 not taken.
✓ Branch 24 taken 16 times.
✗ Branch 25 not taken.
✓ Branch 27 taken 1 times.
✗ Branch 28 not taken.
✓ Branch 30 taken 3 times.
✗ Branch 31 not taken.
|
41 | , mCount(0) |
697 | { | ||
698 | } | ||
699 | 248 | CheckValues(CheckValues& other, tbb::split) | |
700 | : mOwnsMask(true) | ||
701 | 12 | , mMask(other.mMask ? new MaskT() : nullptr) | |
702 | 248 | , mGrid(other.mGrid) | |
703 | 86 | , mCheck(other.mCheck) | |
704 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 118 times.
|
248 | , mCount(0) |
705 | { | ||
706 | } | ||
707 |
24/128✓ Branch 0 taken 45 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 45 times.
✓ Branch 5 taken 22 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 22 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✓ Branch 25 taken 2 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✓ Branch 28 taken 2 times.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✓ Branch 35 taken 5 times.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✓ Branch 38 taken 5 times.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✓ Branch 45 taken 7 times.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✓ Branch 48 taken 7 times.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✓ Branch 55 taken 42 times.
✗ Branch 56 not taken.
✓ Branch 57 taken 6 times.
✓ Branch 58 taken 36 times.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 72 not taken.
✗ Branch 73 not taken.
✗ Branch 75 not taken.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✗ Branch 78 not taken.
✗ Branch 80 not taken.
✓ Branch 81 taken 5 times.
✗ Branch 82 not taken.
✗ Branch 83 not taken.
✗ Branch 85 not taken.
✗ Branch 86 not taken.
✗ Branch 87 not taken.
✗ Branch 88 not taken.
✗ Branch 90 not taken.
✓ Branch 91 taken 1 times.
✗ Branch 92 not taken.
✗ Branch 93 not taken.
✗ Branch 95 not taken.
✗ Branch 96 not taken.
✗ Branch 97 not taken.
✗ Branch 98 not taken.
✗ Branch 100 not taken.
✓ Branch 101 taken 1 times.
✗ Branch 102 not taken.
✗ Branch 103 not taken.
✗ Branch 105 not taken.
✗ Branch 106 not taken.
✗ Branch 107 not taken.
✗ Branch 108 not taken.
✗ Branch 110 not taken.
✓ Branch 111 taken 7 times.
✗ Branch 112 not taken.
✗ Branch 113 not taken.
✗ Branch 115 not taken.
✗ Branch 116 not taken.
✗ Branch 117 not taken.
✗ Branch 118 not taken.
✗ Branch 120 not taken.
✓ Branch 121 taken 1 times.
✗ Branch 122 not taken.
✗ Branch 123 not taken.
✗ Branch 125 not taken.
✗ Branch 126 not taken.
✗ Branch 127 not taken.
✗ Branch 128 not taken.
✗ Branch 130 not taken.
✓ Branch 131 taken 10 times.
✗ Branch 132 not taken.
✗ Branch 133 not taken.
✗ Branch 135 not taken.
✗ Branch 136 not taken.
✗ Branch 137 not taken.
✗ Branch 138 not taken.
✗ Branch 140 not taken.
✓ Branch 141 taken 1 times.
✗ Branch 142 not taken.
✗ Branch 143 not taken.
✗ Branch 145 not taken.
✗ Branch 146 not taken.
✗ Branch 147 not taken.
✗ Branch 148 not taken.
✗ Branch 150 not taken.
✓ Branch 151 taken 3 times.
✗ Branch 152 not taken.
✗ Branch 153 not taken.
✗ Branch 155 not taken.
✗ Branch 156 not taken.
✗ Branch 157 not taken.
✗ Branch 158 not taken.
|
222 | ~CheckValues() { if (mOwnsMask) delete mMask; } |
708 | |||
709 | 48 | std::string checkBackground() | |
710 | { | ||
711 | 96 | std::ostringstream ss; | |
712 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 16 times.
|
48 | if (mCheck(mGrid->background())) { |
713 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
2 | ++mCount; |
714 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
4 | ss << "Background is " + mCheck.str() << std::endl; |
715 | } | ||
716 | 48 | return ss.str(); | |
717 | } | ||
718 | |||
719 | 54 | std::string checkTiles() | |
720 | { | ||
721 | 108 | std::ostringstream ss; | |
722 | 54 | const Index64 n = mCount; | |
723 |
1/2✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
|
54 | typename CheckT::TileIterT i(mGrid->tree()); |
724 |
2/2✓ Branch 0 taken 761163 times.
✓ Branch 1 taken 27 times.
|
1522434 | for (i.setMaxDepth(GridT::TreeType::RootNodeType::LEVEL - 1); i; ++i) { |
725 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 647130 times.
|
1294260 | if (mCheck(i)) { |
726 | 2 | ++mCount; | |
727 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
2 | if (mMask) mMask->fill(i.getBoundingBox(), true, true); |
728 | } | ||
729 | } | ||
730 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 26 times.
|
54 | if (const Index64 m = mCount - n) { |
731 |
3/7✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
4 | ss << m << " tile" << (m==1 ? " is " : "s are ") + mCheck.str() << std::endl; |
732 | } | ||
733 | 54 | return ss.str(); | |
734 | } | ||
735 | |||
736 | 82 | std::string checkVoxels() | |
737 | { | ||
738 | 164 | std::ostringstream ss; | |
739 |
1/2✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
|
164 | LeafManagerT leafs(mGrid->tree()); |
740 |
1/2✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
|
82 | const Index64 n = mCount; |
741 |
1/2✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
|
82 | tbb::parallel_reduce(leafs.leafRange(), *this); |
742 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 31 times.
|
82 | if (const Index64 m = mCount - n) { |
743 |
5/7✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 3 times.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
|
52 | ss << m << " voxel" << (m==1 ? " is " : "s are ") + mCheck.str() << std::endl; |
744 | } | ||
745 | 82 | return ss.str(); | |
746 | } | ||
747 | |||
748 | 10342 | void operator()(const typename LeafManagerT::LeafRange& r) | |
749 | { | ||
750 | using VoxelIterT = typename CheckT::VoxelIterT; | ||
751 |
2/2✓ Branch 0 taken 145 times.
✓ Branch 1 taken 5026 times.
|
10342 | if (mMask) { |
752 |
2/2✓ Branch 1 taken 663 times.
✓ Branch 2 taken 145 times.
|
1616 | for (typename LeafManagerT::LeafRange::Iterator i=r.begin(); i; ++i) { |
753 | typename MaskT::LeafNodeType* maskLeaf = nullptr; | ||
754 |
2/2✓ Branch 1 taken 93046 times.
✓ Branch 2 taken 663 times.
|
188744 | for (VoxelIterT j = tree::IterTraits<LeafT, VoxelIterT>::begin(*i); j; ++j) { |
755 | ✗ | if (mCheck(j)) { | |
756 | 88300 | ++mCount; | |
757 |
2/2✓ Branch 0 taken 539 times.
✓ Branch 1 taken 43611 times.
|
89378 | if (maskLeaf == nullptr) maskLeaf = mMask->touchLeaf(j.getCoord()); |
758 | 88300 | maskLeaf->setValueOn(j.pos(), true); | |
759 | } | ||
760 | } | ||
761 | } | ||
762 | } else { | ||
763 |
2/2✓ Branch 1 taken 32851 times.
✓ Branch 2 taken 5026 times.
|
75754 | for (typename LeafManagerT::LeafRange::Iterator i=r.begin(); i; ++i) { |
764 |
2/2✓ Branch 1 taken 10332505 times.
✓ Branch 2 taken 32851 times.
|
20796414 | for (VoxelIterT j = tree::IterTraits<LeafT, VoxelIterT>::begin(*i); j; ++j) { |
765 |
3/3✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5081588 times.
✓ Branch 2 taken 3820793 times.
|
17893074 | if (mCheck(j)) ++mCount; |
766 | } | ||
767 | } | ||
768 | } | ||
769 | 10342 | } | |
770 | void join(const CheckValues& other) | ||
771 | { | ||
772 |
9/20✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 43 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 5 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 7 times.
✓ Branch 21 taken 6 times.
✓ Branch 22 taken 36 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
|
124 | if (mMask) mMask->merge(*(other.mMask), openvdb::MERGE_ACTIVE_STATES_AND_NODES); |
773 | 124 | mCount += other.mCount; | |
774 | 124 | } | |
775 | };//End of private class CheckValues | ||
776 | |||
777 | };// End of public class Diagnose | ||
778 | |||
779 | |||
780 | //////////////////////////////////////////////////////////////////////////////// | ||
781 | |||
782 | /// @brief Class that performs various types of checks on narrow-band level sets. | ||
783 | /// | ||
784 | /// @note The most common usage is to simply call CheckLevelSet::check() | ||
785 | template<class GridType> | ||
786 | class CheckLevelSet | ||
787 | { | ||
788 | public: | ||
789 | using ValueType = typename GridType::ValueType; | ||
790 | using MaskType = typename GridType::template ValueConverter<bool>::Type; | ||
791 | |||
792 | 3 | CheckLevelSet(const GridType& grid) : mDiagnose(grid) {} | |
793 | |||
794 | //@{ | ||
795 | /// @brief Return a boolean mask of all the values | ||
796 | /// (i.e. tiles and/or voxels) that have failed one or | ||
797 | /// more checks. | ||
798 | typename MaskType::ConstPtr mask() const { return mDiagnose.mask(); } | ||
799 | typename MaskType::Ptr mask() { return mDiagnose.mask(); } | ||
800 | //@} | ||
801 | |||
802 | /// @brief Return the number of values (i.e. background, tiles or | ||
803 | /// voxels) that have failed one or more checks. | ||
804 | Index64 valueCount() const { return mDiagnose.valueCount(); } | ||
805 | |||
806 | /// @brief Return total number of failed checks | ||
807 | /// @note If only one check was performed and the mask was updated | ||
808 | /// failureCount equals valueCount. | ||
809 | Index64 failureCount() const { return mDiagnose.failureCount(); } | ||
810 | |||
811 | /// @brief Return a const reference to the grid | ||
812 | const GridType& grid() const { return mDiagnose.grid(); } | ||
813 | |||
814 | /// @brief Clear the mask and error counter | ||
815 | void clear() { mDiagnose.clear(); } | ||
816 | |||
817 | /// @brief Return a nonempty message if the grid's value type is a floating point. | ||
818 | /// | ||
819 | /// @note No run-time overhead | ||
820 | static std::string checkValueType() | ||
821 | { | ||
822 | static const bool test = std::is_floating_point<ValueType>::value; | ||
823 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | return test ? "" : "Value type is not floating point\n"; |
824 | } | ||
825 | |||
826 | /// @brief Return message if the grid's class is a level set. | ||
827 | /// | ||
828 | /// @note Small run-time overhead | ||
829 | 6 | std::string checkClassType() const | |
830 | { | ||
831 | 6 | const bool test = mDiagnose.grid().getGridClass() == GRID_LEVEL_SET; | |
832 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
6 | return test ? "" : "Class type is not \"GRID_LEVEL_SET\"\n"; |
833 | } | ||
834 | |||
835 | /// @brief Return a nonempty message if the grid's transform does not have uniform scaling. | ||
836 | /// | ||
837 | /// @note Small run-time overhead | ||
838 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | std::string checkTransform() const |
839 | { | ||
840 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
|
6 | return mDiagnose.grid().hasUniformVoxels() ? "" : "Does not have uniform voxels\n"; |
841 | } | ||
842 | |||
843 | /// @brief Return a nonempty message if the background value is larger than or | ||
844 | /// equal to the halfWidth*voxelSize. | ||
845 | /// | ||
846 | /// @note Small run-time overhead | ||
847 | 6 | std::string checkBackground(Real halfWidth = LEVEL_SET_HALF_WIDTH) const | |
848 | { | ||
849 | 6 | const Real w = mDiagnose.grid().background() / mDiagnose.grid().voxelSize()[0]; | |
850 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
6 | if (w < halfWidth) { |
851 | ✗ | std::ostringstream ss; | |
852 | ✗ | ss << "The background value ("<< mDiagnose.grid().background()<<") is less than " | |
853 | ✗ | << halfWidth << " voxel units\n"; | |
854 | return ss.str(); | ||
855 | } | ||
856 | 6 | return ""; | |
857 | } | ||
858 | |||
859 | /// @brief Return a nonempty message if the grid has no active tile values. | ||
860 | /// | ||
861 | /// @note Medium run-time overhead | ||
862 | 6 | std::string checkTiles() const | |
863 | { | ||
864 | const bool test = mDiagnose.grid().tree().hasActiveTiles(); | ||
865 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
12 | return test ? "Has active tile values\n" : ""; |
866 | } | ||
867 | |||
868 | /// @brief Return a nonempty message if any of the values are not finite. i.e. NaN or inf. | ||
869 | /// | ||
870 | /// @note Medium run-time overhead | ||
871 | std::string checkFinite(bool updateMask = false) | ||
872 | { | ||
873 | CheckFinite<GridType,typename GridType::ValueAllCIter> c; | ||
874 | 3 | return mDiagnose.check(c, updateMask, /*voxel*/true, /*tiles*/true, /*background*/true); | |
875 | } | ||
876 | |||
877 | /// @brief Return a nonempty message if the active voxel values are out-of-range. | ||
878 | /// | ||
879 | /// @note Medium run-time overhead | ||
880 | 4 | std::string checkRange(bool updateMask = false) | |
881 | { | ||
882 | const ValueType& background = mDiagnose.grid().background(); | ||
883 | 4 | CheckRange<GridType> c(-background, background); | |
884 | 4 | return mDiagnose.check(c, updateMask, /*voxel*/true, /*tiles*/false, /*background*/false); | |
885 | } | ||
886 | |||
887 | /// @brief Return a nonempty message if the the inactive values do not have a | ||
888 | /// magnitude equal to the background value. | ||
889 | /// | ||
890 | /// @note Medium run-time overhead | ||
891 | 2 | std::string checkInactiveValues(bool updateMask = false) | |
892 | { | ||
893 | const ValueType& background = mDiagnose.grid().background(); | ||
894 | CheckMagnitude<GridType, typename GridType::ValueOffCIter> c(background); | ||
895 | 2 | return mDiagnose.check(c, updateMask, /*voxel*/true, /*tiles*/true, /*background*/false); | |
896 | } | ||
897 | |||
898 | /// @brief Return a nonempty message if the norm of the gradient of the | ||
899 | /// active voxels is out of the range minV to maxV. | ||
900 | /// | ||
901 | /// @note Significant run-time overhead | ||
902 | 2 | std::string checkEikonal(bool updateMask = false, ValueType minV = 0.5, ValueType maxV = 1.5) | |
903 | { | ||
904 | 2 | CheckEikonal<GridType> c(mDiagnose.grid(), minV, maxV); | |
905 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
4 | return mDiagnose.check(c, updateMask, /*voxel*/true, /*tiles*/false, /*background*/false); |
906 | } | ||
907 | |||
908 | /// @brief Return a nonempty message if an error or issue is detected. Only | ||
909 | /// runs tests with a number lower than or equal to n, where: | ||
910 | /// | ||
911 | /// Fast checks | ||
912 | /// 1: value type is floating point | ||
913 | /// 2: has level set class type | ||
914 | /// 3: has uniform scale | ||
915 | /// 4: background value is positive and n*dx | ||
916 | /// | ||
917 | /// Slower checks | ||
918 | /// 5: no active tiles | ||
919 | /// 6: all the values are finite, i.e not NaN or infinite | ||
920 | /// 7: active values in range between +-background | ||
921 | /// 8: abs of inactive values = background, i.e. assuming a symmetric narrow band! | ||
922 | /// | ||
923 | /// Relatively slow check (however multi-threaded) | ||
924 | /// 9: norm of gradient at zero-crossings is one, i.e. satisfied the Eikonal equation. | ||
925 | 6 | std::string check(size_t n=9, bool updateMask = false) | |
926 | { | ||
927 | std::string str = this->checkValueType(); | ||
928 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
12 | if (str.empty() && n>1) str = this->checkClassType(); |
929 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
12 | if (str.empty() && n>2) str = this->checkTransform(); |
930 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
12 | if (str.empty() && n>3) str = this->checkBackground(); |
931 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
12 | if (str.empty() && n>4) str = this->checkTiles(); |
932 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
12 | if (str.empty() && n>5) str = this->checkFinite(updateMask); |
933 |
4/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
10 | if (str.empty() && n>6) str = this->checkRange(updateMask); |
934 |
5/6✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
8 | if (str.empty() && n>7) str = this->checkInactiveValues(updateMask); |
935 |
5/6✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
8 | if (str.empty() && n>8) str = this->checkEikonal(updateMask); |
936 | 6 | return str; | |
937 | } | ||
938 | |||
939 | private: | ||
940 | // disallow copy construction and copy by assignment! | ||
941 | CheckLevelSet(const CheckLevelSet&);// not implemented | ||
942 | CheckLevelSet& operator=(const CheckLevelSet&);// not implemented | ||
943 | |||
944 | // Member data | ||
945 | Diagnose<GridType> mDiagnose; | ||
946 | };// CheckLevelSet | ||
947 | |||
948 | template<class GridType> | ||
949 | std::string | ||
950 | 6 | checkLevelSet(const GridType& grid, size_t n) | |
951 | { | ||
952 | CheckLevelSet<GridType> c(grid); | ||
953 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
12 | return c.check(n, false); |
954 | } | ||
955 | |||
956 | //////////////////////////////////////////////////////////////////////////////// | ||
957 | |||
958 | /// @brief Class that performs various types of checks on fog volumes. | ||
959 | /// | ||
960 | /// @note The most common usage is to simply call CheckFogVolume::check() | ||
961 | template<class GridType> | ||
962 | class CheckFogVolume | ||
963 | { | ||
964 | public: | ||
965 | using ValueType = typename GridType::ValueType; | ||
966 | using MaskType = typename GridType::template ValueConverter<bool>::Type; | ||
967 | |||
968 | 3 | CheckFogVolume(const GridType& grid) : mDiagnose(grid) {} | |
969 | |||
970 | //@{ | ||
971 | /// @brief Return a boolean mask of all the values | ||
972 | /// (i.e. tiles and/or voxels) that have failed one or | ||
973 | /// more checks. | ||
974 | typename MaskType::ConstPtr mask() const { return mDiagnose.mask(); } | ||
975 | typename MaskType::Ptr mask() { return mDiagnose.mask(); } | ||
976 | //@} | ||
977 | |||
978 | /// @brief Return the number of values (i.e. background, tiles or | ||
979 | /// voxels) that have failed one or more checks. | ||
980 | Index64 valueCount() const { return mDiagnose.valueCount(); } | ||
981 | |||
982 | /// @brief Return total number of failed checks | ||
983 | /// @note If only one check was performed and the mask was updated | ||
984 | /// failureCount equals valueCount. | ||
985 | Index64 failureCount() const { return mDiagnose.failureCount(); } | ||
986 | |||
987 | /// @brief Return a const reference to the grid | ||
988 | const GridType& grid() const { return mDiagnose.grid(); } | ||
989 | |||
990 | /// @brief Clear the mask and error counter | ||
991 | void clear() { mDiagnose.clear(); } | ||
992 | |||
993 | /// @brief Return a nonempty message if the grid's value type is a floating point. | ||
994 | /// | ||
995 | /// @note No run-time overhead | ||
996 | static std::string checkValueType() | ||
997 | { | ||
998 | static const bool test = std::is_floating_point<ValueType>::value; | ||
999 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | return test ? "" : "Value type is not floating point"; |
1000 | } | ||
1001 | |||
1002 | /// @brief Return a nonempty message if the grid's class is a level set. | ||
1003 | /// | ||
1004 | /// @note Small run-time overhead | ||
1005 | 6 | std::string checkClassType() const | |
1006 | { | ||
1007 | 6 | const bool test = mDiagnose.grid().getGridClass() == GRID_FOG_VOLUME; | |
1008 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
6 | return test ? "" : "Class type is not \"GRID_LEVEL_SET\""; |
1009 | } | ||
1010 | |||
1011 | /// @brief Return a nonempty message if the background value is not zero. | ||
1012 | /// | ||
1013 | /// @note Small run-time overhead | ||
1014 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
6 | std::string checkBackground() const |
1015 | { | ||
1016 | if (!math::isApproxZero(mDiagnose.grid().background())) { | ||
1017 | ✗ | std::ostringstream ss; | |
1018 | ✗ | ss << "The background value ("<< mDiagnose.grid().background()<<") is not zero"; | |
1019 | return ss.str(); | ||
1020 | } | ||
1021 | 6 | return ""; | |
1022 | } | ||
1023 | |||
1024 | /// @brief Return a nonempty message if any of the values are not finite. i.e. NaN or inf. | ||
1025 | /// | ||
1026 | /// @note Medium run-time overhead | ||
1027 | std::string checkFinite(bool updateMask = false) | ||
1028 | { | ||
1029 | CheckFinite<GridType,typename GridType::ValueAllCIter> c; | ||
1030 | 3 | return mDiagnose.check(c, updateMask, /*voxel*/true, /*tiles*/true, /*background*/true); | |
1031 | } | ||
1032 | |||
1033 | /// @brief Return a nonempty message if any of the inactive values are not zero. | ||
1034 | /// | ||
1035 | /// @note Medium run-time overhead | ||
1036 | std::string checkInactiveValues(bool updateMask = false) | ||
1037 | { | ||
1038 | CheckMagnitude<GridType, typename GridType::ValueOffCIter> c(0); | ||
1039 | 3 | return mDiagnose.check(c, updateMask, /*voxel*/true, /*tiles*/true, /*background*/true); | |
1040 | } | ||
1041 | |||
1042 | /// @brief Return a nonempty message if the active voxel values | ||
1043 | /// are out-of-range, i.e. not in the range [0,1]. | ||
1044 | /// | ||
1045 | /// @note Medium run-time overhead | ||
1046 | 4 | std::string checkRange(bool updateMask = false) | |
1047 | { | ||
1048 | 4 | CheckRange<GridType> c(0, 1); | |
1049 | 4 | return mDiagnose.check(c, updateMask, /*voxel*/true, /*tiles*/true, /*background*/false); | |
1050 | } | ||
1051 | |||
1052 | /// @brief Return a nonempty message if an error or issue is detected. Only | ||
1053 | /// runs tests with a number lower than or equal to n, where: | ||
1054 | /// | ||
1055 | /// Fast checks | ||
1056 | /// 1: value type is floating point | ||
1057 | /// 2: has FOG volume class type | ||
1058 | /// 3: background value is zero | ||
1059 | /// | ||
1060 | /// Slower checks | ||
1061 | /// 4: all the values are finite, i.e not NaN or infinite | ||
1062 | /// 5: inactive values are zero | ||
1063 | /// 6: active values are in the range [0,1] | ||
1064 | 6 | std::string check(size_t n=6, bool updateMask = false) | |
1065 | { | ||
1066 | std::string str = this->checkValueType(); | ||
1067 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
12 | if (str.empty() && n>1) str = this->checkClassType(); |
1068 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
12 | if (str.empty() && n>2) str = this->checkBackground(); |
1069 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
12 | if (str.empty() && n>3) str = this->checkFinite(updateMask); |
1070 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
12 | if (str.empty() && n>4) str = this->checkInactiveValues(updateMask); |
1071 |
4/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
10 | if (str.empty() && n>5) str = this->checkRange(updateMask); |
1072 | 6 | return str; | |
1073 | } | ||
1074 | |||
1075 | private: | ||
1076 | // disallow copy construction and copy by assignment! | ||
1077 | CheckFogVolume(const CheckFogVolume&);// not implemented | ||
1078 | CheckFogVolume& operator=(const CheckFogVolume&);// not implemented | ||
1079 | |||
1080 | // Member data | ||
1081 | Diagnose<GridType> mDiagnose; | ||
1082 | };// CheckFogVolume | ||
1083 | |||
1084 | template<class GridType> | ||
1085 | std::string | ||
1086 | 6 | checkFogVolume(const GridType& grid, size_t n) | |
1087 | { | ||
1088 | CheckFogVolume<GridType> c(grid); | ||
1089 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
12 | return c.check(n, false); |
1090 | } | ||
1091 | |||
1092 | |||
1093 | //////////////////////////////////////////////////////////////////////////////// | ||
1094 | |||
1095 | // Internal utility objects and implementation details | ||
1096 | |||
1097 | /// @cond OPENVDB_DOCS_INTERNAL | ||
1098 | |||
1099 | namespace diagnostics_internal { | ||
1100 | |||
1101 | |||
1102 | template<typename TreeType> | ||
1103 | 2 | class InactiveVoxelValues | |
1104 | { | ||
1105 | public: | ||
1106 | using LeafArray = tree::LeafManager<TreeType>; | ||
1107 | using ValueType = typename TreeType::ValueType; | ||
1108 | using SetType = std::set<ValueType>; | ||
1109 | |||
1110 | InactiveVoxelValues(LeafArray&, size_t numValues); | ||
1111 | |||
1112 | void runParallel(); | ||
1113 | void runSerial(); | ||
1114 | |||
1115 | void getInactiveValues(SetType&) const; | ||
1116 | |||
1117 | inline InactiveVoxelValues(const InactiveVoxelValues<TreeType>&, tbb::split); | ||
1118 | inline void operator()(const tbb::blocked_range<size_t>&); | ||
1119 | inline void join(const InactiveVoxelValues<TreeType>&); | ||
1120 | |||
1121 | private: | ||
1122 | LeafArray& mLeafArray; | ||
1123 | SetType mInactiveValues; | ||
1124 | size_t mNumValues; | ||
1125 | };// InactiveVoxelValues | ||
1126 | |||
1127 | template<typename TreeType> | ||
1128 | 6 | InactiveVoxelValues<TreeType>::InactiveVoxelValues(LeafArray& leafs, size_t numValues) | |
1129 | : mLeafArray(leafs) | ||
1130 | , mInactiveValues() | ||
1131 | 6 | , mNumValues(numValues) | |
1132 | { | ||
1133 | } | ||
1134 | |||
1135 | template <typename TreeType> | ||
1136 | inline | ||
1137 | 2 | InactiveVoxelValues<TreeType>::InactiveVoxelValues( | |
1138 | const InactiveVoxelValues<TreeType>& rhs, tbb::split) | ||
1139 | 2 | : mLeafArray(rhs.mLeafArray) | |
1140 | , mInactiveValues() | ||
1141 | 2 | , mNumValues(rhs.mNumValues) | |
1142 | { | ||
1143 | } | ||
1144 | |||
1145 | template<typename TreeType> | ||
1146 | void | ||
1147 | 6 | InactiveVoxelValues<TreeType>::runParallel() | |
1148 | { | ||
1149 | 6 | tbb::parallel_reduce(mLeafArray.getRange(), *this); | |
1150 | } | ||
1151 | |||
1152 | |||
1153 | template<typename TreeType> | ||
1154 | void | ||
1155 | InactiveVoxelValues<TreeType>::runSerial() | ||
1156 | { | ||
1157 | (*this)(mLeafArray.getRange()); | ||
1158 | } | ||
1159 | |||
1160 | |||
1161 | template<typename TreeType> | ||
1162 | inline void | ||
1163 | 100 | InactiveVoxelValues<TreeType>::operator()(const tbb::blocked_range<size_t>& range) | |
1164 | { | ||
1165 | typename TreeType::LeafNodeType::ValueOffCIter iter; | ||
1166 | |||
1167 |
3/4✓ Branch 0 taken 50 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 50 times.
✗ Branch 3 not taken.
|
300 | for (size_t n = range.begin(); n < range.end() && !thread::isGroupExecutionCancelled(); ++n) { |
1168 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 19189 times.
✓ Branch 3 taken 50 times.
|
38678 | for (iter = mLeafArray.leaf(n).cbeginValueOff(); iter; ++iter) { |
1169 | 38378 | mInactiveValues.insert(iter.getValue()); | |
1170 | } | ||
1171 | |||
1172 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
|
100 | if (mInactiveValues.size() > mNumValues) { |
1173 | ✗ | thread::cancelGroupExecution(); | |
1174 | } | ||
1175 | } | ||
1176 | } | ||
1177 | |||
1178 | template<typename TreeType> | ||
1179 | inline void | ||
1180 | 4 | InactiveVoxelValues<TreeType>::join(const InactiveVoxelValues<TreeType>& rhs) | |
1181 | { | ||
1182 | 4 | mInactiveValues.insert(rhs.mInactiveValues.begin(), rhs.mInactiveValues.end()); | |
1183 | } | ||
1184 | |||
1185 | template<typename TreeType> | ||
1186 | inline void | ||
1187 | 6 | InactiveVoxelValues<TreeType>::getInactiveValues(SetType& values) const | |
1188 | { | ||
1189 | 6 | values.insert(mInactiveValues.begin(), mInactiveValues.end()); | |
1190 | } | ||
1191 | |||
1192 | |||
1193 | //////////////////////////////////////// | ||
1194 | |||
1195 | |||
1196 | template<typename TreeType> | ||
1197 | 18 | class InactiveTileValues | |
1198 | { | ||
1199 | public: | ||
1200 | using IterRange = tree::IteratorRange<typename TreeType::ValueOffCIter>; | ||
1201 | using ValueType = typename TreeType::ValueType; | ||
1202 | using SetType = std::set<ValueType>; | ||
1203 | |||
1204 | InactiveTileValues(size_t numValues); | ||
1205 | |||
1206 | void runParallel(IterRange&); | ||
1207 | void runSerial(IterRange&); | ||
1208 | |||
1209 | void getInactiveValues(SetType&) const; | ||
1210 | |||
1211 | inline InactiveTileValues(const InactiveTileValues<TreeType>&, tbb::split); | ||
1212 | inline void operator()(IterRange&); | ||
1213 | inline void join(const InactiveTileValues<TreeType>&); | ||
1214 | |||
1215 | private: | ||
1216 | SetType mInactiveValues; | ||
1217 | size_t mNumValues; | ||
1218 | }; | ||
1219 | |||
1220 | |||
1221 | template<typename TreeType> | ||
1222 | 6 | InactiveTileValues<TreeType>::InactiveTileValues(size_t numValues) | |
1223 | : mInactiveValues() | ||
1224 | 6 | , mNumValues(numValues) | |
1225 | { | ||
1226 | } | ||
1227 | |||
1228 | template <typename TreeType> | ||
1229 | inline | ||
1230 | 18 | InactiveTileValues<TreeType>::InactiveTileValues( | |
1231 | const InactiveTileValues<TreeType>& rhs, tbb::split) | ||
1232 | : mInactiveValues() | ||
1233 | 18 | , mNumValues(rhs.mNumValues) | |
1234 | { | ||
1235 | } | ||
1236 | |||
1237 | template<typename TreeType> | ||
1238 | void | ||
1239 | 6 | InactiveTileValues<TreeType>::runParallel(IterRange& range) | |
1240 | { | ||
1241 | 6 | tbb::parallel_reduce(range, *this); | |
1242 | } | ||
1243 | |||
1244 | |||
1245 | template<typename TreeType> | ||
1246 | void | ||
1247 | InactiveTileValues<TreeType>::runSerial(IterRange& range) | ||
1248 | { | ||
1249 | (*this)(range); | ||
1250 | } | ||
1251 | |||
1252 | |||
1253 | template<typename TreeType> | ||
1254 | inline void | ||
1255 | 1056 | InactiveTileValues<TreeType>::operator()(IterRange& range) | |
1256 | { | ||
1257 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 110539 times.
|
221078 | for (; range && !thread::isGroupExecutionCancelled(); ++range) { |
1258 | 221078 | typename TreeType::ValueOffCIter iter = range.iterator(); | |
1259 |
2/2✓ Branch 0 taken 2036533930 times.
✓ Branch 1 taken 110539 times.
|
4073288938 | for (; iter; ++iter) { |
1260 | mInactiveValues.insert(iter.getValue()); | ||
1261 | } | ||
1262 | |||
1263 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 110539 times.
|
221078 | if (mInactiveValues.size() > mNumValues) { |
1264 | ✗ | thread::cancelGroupExecution(); | |
1265 | } | ||
1266 | } | ||
1267 | } | ||
1268 | |||
1269 | template<typename TreeType> | ||
1270 | inline void | ||
1271 | 36 | InactiveTileValues<TreeType>::join(const InactiveTileValues<TreeType>& rhs) | |
1272 | { | ||
1273 | 36 | mInactiveValues.insert(rhs.mInactiveValues.begin(), rhs.mInactiveValues.end()); | |
1274 | } | ||
1275 | |||
1276 | template<typename TreeType> | ||
1277 | inline void | ||
1278 | 6 | InactiveTileValues<TreeType>::getInactiveValues(SetType& values) const | |
1279 | { | ||
1280 | 6 | values.insert(mInactiveValues.begin(), mInactiveValues.end()); | |
1281 | } | ||
1282 | |||
1283 | } // namespace diagnostics_internal | ||
1284 | |||
1285 | /// @endcond | ||
1286 | |||
1287 | //////////////////////////////////////// | ||
1288 | |||
1289 | |||
1290 | template<class GridType> | ||
1291 | bool | ||
1292 | 3 | uniqueInactiveValues(const GridType& grid, | |
1293 | std::vector<typename GridType::ValueType>& values, size_t numValues) | ||
1294 | { | ||
1295 | using TreeType = typename GridType::TreeType; | ||
1296 | using ValueType = typename GridType::ValueType; | ||
1297 | using SetType = std::set<ValueType>; | ||
1298 | |||
1299 | SetType uniqueValues; | ||
1300 | |||
1301 | { // Check inactive voxels | ||
1302 | TreeType& tree = const_cast<TreeType&>(grid.tree()); | ||
1303 | 6 | tree::LeafManager<TreeType> leafs(tree); | |
1304 | 3 | diagnostics_internal::InactiveVoxelValues<TreeType> voxelOp(leafs, numValues); | |
1305 | 3 | voxelOp.runParallel(); | |
1306 | 3 | voxelOp.getInactiveValues(uniqueValues); | |
1307 | } | ||
1308 | |||
1309 | // Check inactive tiles | ||
1310 | 3 | if (uniqueValues.size() <= numValues) { | |
1311 | 3 | typename TreeType::ValueOffCIter iter(grid.tree()); | |
1312 | 3 | iter.setMaxDepth(TreeType::ValueAllIter::LEAF_DEPTH - 1); | |
1313 | 3 | diagnostics_internal::InactiveTileValues<TreeType> tileOp(numValues); | |
1314 | |||
1315 | tree::IteratorRange<typename TreeType::ValueOffCIter> range(iter); | ||
1316 | 3 | tileOp.runParallel(range); | |
1317 | |||
1318 | 3 | tileOp.getInactiveValues(uniqueValues); | |
1319 | } | ||
1320 | |||
1321 | values.clear(); | ||
1322 | 3 | values.reserve(uniqueValues.size()); | |
1323 | |||
1324 | 3 | typename SetType::iterator it = uniqueValues.begin(); | |
1325 | 10 | for ( ; it != uniqueValues.end(); ++it) { | |
1326 | 7 | values.push_back(*it); | |
1327 | } | ||
1328 | |||
1329 | 3 | return values.size() <= numValues; | |
1330 | } | ||
1331 | |||
1332 | |||
1333 | //////////////////////////////////////// | ||
1334 | |||
1335 | |||
1336 | // Explicit Template Instantiation | ||
1337 | |||
1338 | #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION | ||
1339 | |||
1340 | #ifdef OPENVDB_INSTANTIATE_DIAGNOSTICS | ||
1341 | #include <openvdb/util/ExplicitInstantiation.h> | ||
1342 | #endif | ||
1343 | |||
1344 | #define _FUNCTION(TreeT) \ | ||
1345 | std::string checkLevelSet(const Grid<TreeT>&, size_t) | ||
1346 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
1347 | #undef _FUNCTION | ||
1348 | |||
1349 | #define _FUNCTION(TreeT) \ | ||
1350 | std::string checkFogVolume(const Grid<TreeT>&, size_t) | ||
1351 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
1352 | #undef _FUNCTION | ||
1353 | |||
1354 | #define _FUNCTION(TreeT) \ | ||
1355 | bool uniqueInactiveValues(const Grid<TreeT>&, std::vector<TreeT::ValueType>&, size_t) | ||
1356 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
1357 | #undef _FUNCTION | ||
1358 | |||
1359 | #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION | ||
1360 | |||
1361 | |||
1362 | } // namespace tools | ||
1363 | } // namespace OPENVDB_VERSION_NAME | ||
1364 | } // namespace openvdb | ||
1365 | |||
1366 | #endif // OPENVDB_TOOLS_DIAGNOSTICS_HAS_BEEN_INCLUDED | ||
1367 |