GCC Code Coverage Report


Directory: ./
File: openvdb/openvdb/tools/Diagnostics.h
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 226 255 88.6%
Functions: 100 228 43.9%
Branches: 288 715 40.3%

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 /// |&nabla;&Phi;| &isin; [min, max]
422 ///
423 /// @note Internally the test is performed as
424 /// |&nabla;&Phi;|&sup2; &isin; [min&sup2;, max&sup2;] 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