1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 #include <openvdb/openvdb.h>
5 #include <openvdb/Exceptions.h>
6 #include <openvdb/math/Math.h>
7 #include <openvdb/math/Stats.h>
8 #include <openvdb/tools/Diagnostics.h>
9 #include <openvdb/tools/Statistics.h>
10 #include <openvdb/tools/LevelSetSphere.h>
11 #include <openvdb/tools/LevelSetUtil.h>
12 
13 #include <gtest/gtest.h>
14 
15 #include <limits>
16 
17 class TestDiagnostics: public ::testing::Test
18 {
19 };
20 
21 
22 ////////////////////////////////////////
23 
TEST_F(TestDiagnostics,testCheck)24 TEST_F(TestDiagnostics, testCheck)
25 {
26     const float val = 1.0f;
27     const float nan = std::numeric_limits<float>::quiet_NaN();
28     const float inf1= std::numeric_limits<float>::infinity();
29     const openvdb::math::Vec3<float> inf2(val, inf1, val);
30 
31     {//test CheckNan
32         openvdb::tools::CheckNan<openvdb::FloatGrid> c;
33         EXPECT_TRUE(!c(val));
34         EXPECT_TRUE( c(nan));
35         EXPECT_TRUE( c(nan));
36         EXPECT_TRUE(!c(inf1));
37         EXPECT_TRUE(!c(inf2));
38     }
39     {//test CheckInf
40         openvdb::tools::CheckInf<openvdb::FloatGrid> c;
41         EXPECT_TRUE(!c(val));
42         EXPECT_TRUE(!c(nan));
43         EXPECT_TRUE(!c(nan));
44         EXPECT_TRUE( c(inf1));
45         EXPECT_TRUE( c(inf2));
46     }
47     {//test CheckFinite
48         openvdb::tools::CheckFinite<openvdb::FloatGrid> c;
49         EXPECT_TRUE(!c(val));
50         EXPECT_TRUE( c(nan));
51         EXPECT_TRUE( c(nan));
52         EXPECT_TRUE( c(inf1));
53         EXPECT_TRUE( c(inf2));
54     }
55     {//test CheckMin
56         openvdb::tools::CheckMin<openvdb::FloatGrid> c(0.0f);
57         EXPECT_TRUE(!c( 0.5f));
58         EXPECT_TRUE(!c( 0.0f));
59         EXPECT_TRUE(!c( 1.0f));
60         EXPECT_TRUE(!c( 1.1f));
61         EXPECT_TRUE( c(-0.1f));
62     }
63     {//test CheckMax
64         openvdb::tools::CheckMax<openvdb::FloatGrid> c(0.0f);
65         EXPECT_TRUE( c( 0.5f));
66         EXPECT_TRUE(!c( 0.0f));
67         EXPECT_TRUE( c( 1.0f));
68         EXPECT_TRUE( c( 1.1f));
69         EXPECT_TRUE(!c(-0.1f));
70     }
71     {//test CheckRange
72         // first check throw on construction from an invalid range
73         EXPECT_THROW(openvdb::tools::CheckRange<openvdb::FloatGrid> c(1.0f, 0.0f),
74                              openvdb::ValueError);
75         openvdb::tools::CheckRange<openvdb::FloatGrid> c(0.0f, 1.0f);
76         EXPECT_TRUE(!c(0.5f));
77         EXPECT_TRUE(!c(0.0f));
78         EXPECT_TRUE(!c(1.0f));
79         EXPECT_TRUE( c(1.1f));
80         EXPECT_TRUE(c(-0.1f));
81     }
82 }//testCheck
83 
TEST_F(TestDiagnostics,testDiagnose)84 TEST_F(TestDiagnostics, testDiagnose)
85 {
86     using namespace openvdb;
87     const float val = 1.0f;
88     const float nan = std::numeric_limits<float>::quiet_NaN();
89     const float inf = std::numeric_limits<float>::infinity();
90 
91     {//empty grid
92         FloatGrid grid;
93         tools::Diagnose<FloatGrid> d(grid);
94         tools::CheckNan<FloatGrid> c;
95         std::string str = d.check(c);
96         //std::cerr << "Empty grid:\n" << str;
97         EXPECT_EQ(std::string(), str);
98         EXPECT_EQ(0, int(d.failureCount()));
99     }
100     {//non-empty grid
101         FloatGrid grid;
102         grid.tree().setValue(Coord(-1,3,6), val);
103         tools::Diagnose<FloatGrid> d(grid);
104         tools::CheckNan<FloatGrid> c;
105         std::string str = d.check(c);
106         //std::cerr << "Non-Empty grid:\n" << str;
107         EXPECT_EQ(std::string(), str);
108         EXPECT_EQ(0, int(d.failureCount()));
109     }
110     {//nan grid
111         FloatGrid grid;
112         grid.tree().setValue(Coord(-1,3,6), nan);
113         tools::Diagnose<FloatGrid> d(grid);
114         tools::CheckNan<FloatGrid> c;
115         std::string str = d.check(c);
116         //std::cerr << "NaN grid:\n" << str;
117         EXPECT_TRUE(!str.empty());
118         EXPECT_EQ(1, int(d.failureCount()));
119     }
120 
121     {//nan and infinite grid
122         FloatGrid grid;
123         grid.tree().setValue(Coord(-1,3,6), nan);
124         grid.tree().setValue(Coord(10,30,60), inf);
125         tools::Diagnose<FloatGrid> d(grid);
126         tools::CheckFinite<FloatGrid> c;
127         std::string str = d.check(c);
128         //std::cerr << "Not Finite grid:\n" << str;
129         EXPECT_TRUE(!str.empty());
130         EXPECT_EQ(2, int(d.failureCount()));
131     }
132     {//out-of-range grid
133         FloatGrid grid(10.0f);
134         grid.tree().setValue(Coord(-1,3,6), 1.0f);
135         grid.tree().setValue(Coord(10,30,60), 1.5);
136         grid.tree().fill(math::CoordBBox::createCube(math::Coord(0),8), 20.0f, true);
137         tools::Diagnose<FloatGrid> d(grid);
138         tools::CheckRange<FloatGrid> c(0.0f, 1.0f);
139         std::string str = d.check(c);
140         //std::cerr << "out-of-range grid:\n" << str;
141         EXPECT_TRUE(!str.empty());
142         EXPECT_EQ(3, int(d.failureCount()));
143     }
144 
145     const float radius = 4.3f;
146     const openvdb::Vec3f center(15.8f, 13.2f, 16.7f);
147     const float voxelSize = 0.1f, width = 2.0f, gamma=voxelSize*width;
148 
149     FloatGrid::Ptr gridSphere =
150         tools::createLevelSetSphere<FloatGrid>(radius, center, voxelSize, width);
151 
152     //gridSphere->print(std::cerr, 2);
153 
154     {// Check min/max of active values
155         math::Extrema ex = tools::extrema(gridSphere->cbeginValueOn());
156         //std::cerr << "Min = " << ex.min() << " max = " << ex.max() << std::endl;
157         EXPECT_TRUE(ex.min() > -voxelSize*width);
158         EXPECT_TRUE(ex.max() <  voxelSize*width);
159 
160     }
161     {// Check min/max of all values
162         math::Extrema ex = tools::extrema(gridSphere->cbeginValueAll());
163         //std::cerr << "Min = " << ex.min() << " max = " << ex.max() << std::endl;
164         EXPECT_TRUE(ex.min() >= -voxelSize*width);
165         EXPECT_TRUE(ex.max() <=  voxelSize*width);
166 
167     }
168     {// check range of all values in a sphere w/o mask
169         tools::CheckRange<FloatGrid, true, true, FloatGrid::ValueAllCIter> c(-gamma, gamma);
170         tools::Diagnose<FloatGrid> d(*gridSphere);
171         std::string str = d.check(c);
172         //std::cerr << "Values out of range:\n" << str;
173         EXPECT_TRUE(str.empty());
174         EXPECT_EQ(0, int(d.valueCount()));
175         EXPECT_EQ(0, int(d.failureCount()));
176     }
177     {// check range of on values in a sphere w/o mask
178         tools::CheckRange<FloatGrid, true, true, FloatGrid::ValueOnCIter> c(-gamma, gamma);
179         tools::Diagnose<FloatGrid> d(*gridSphere);
180         std::string str = d.check(c);
181         //std::cerr << "Values out of range:\n" << str;
182         EXPECT_TRUE(str.empty());
183         EXPECT_EQ(0, int(d.valueCount()));
184         EXPECT_EQ(0, int(d.failureCount()));
185     }
186     {// check range of off tiles in a sphere w/o mask
187         tools::CheckRange<FloatGrid, true, true, FloatGrid::ValueOffCIter> c(-gamma, gamma);
188         tools::Diagnose<FloatGrid> d(*gridSphere);
189         {// check off tile iterator
190             FloatGrid::ValueOffCIter i(gridSphere->tree());
191             i.setMaxDepth(FloatGrid::ValueOffCIter::LEAF_DEPTH - 1);
192             for (; i; ++i) EXPECT_TRUE( math::Abs(*i) <= gamma);
193         }
194         std::string str = d.check(c);
195         //std::cerr << "Values out of range:\n" << str;
196         EXPECT_TRUE(str.empty());
197         EXPECT_EQ(0, int(d.valueCount()));
198         EXPECT_EQ(0, int(d.failureCount()));
199     }
200     {// check range of sphere w/o mask
201         tools::CheckRange<FloatGrid> c(0.0f, gamma);
202         tools::Diagnose<FloatGrid> d(*gridSphere);
203         std::string str = d.check(c);
204         //std::cerr << "Values out of range:\n" << str;
205         EXPECT_TRUE(!str.empty());
206         EXPECT_EQ(0, int(d.valueCount()));
207         EXPECT_TRUE(d.failureCount() <  gridSphere->activeVoxelCount());
208     }
209     {// check range of sphere w mask
210         tools::CheckRange<FloatGrid> c(0.0f, gamma);
211         tools::Diagnose<FloatGrid> d(*gridSphere);
212         std::string str = d.check(c, true);
213         //std::cerr << "Values out of range:\n" << str;
214         EXPECT_TRUE(!str.empty());
215         EXPECT_EQ(d.valueCount(), d.valueCount());
216         EXPECT_TRUE(d.failureCount() <  gridSphere->activeVoxelCount());
217     }
218     {// check min of sphere w/o mask
219         tools::CheckMin<FloatGrid> c(-gamma);
220         tools::Diagnose<FloatGrid> d(*gridSphere);
221         std::string str = d.check(c);
222         //std::cerr << "Min values:\n" << str;
223         EXPECT_EQ(std::string(), str);
224         EXPECT_EQ(0, int(d.valueCount()));
225         EXPECT_EQ(0, int(d.failureCount()));
226     }
227     {// check max of sphere w/o mask
228         tools::CheckMax<FloatGrid> c(gamma);
229         tools::Diagnose<FloatGrid> d(*gridSphere);
230         std::string str = d.check(c);
231         //std::cerr << "MAX values:\n" << str;
232         EXPECT_TRUE(str.empty());
233         EXPECT_EQ(0, int(d.valueCount()));
234         EXPECT_EQ(0, int(d.failureCount()));
235     }
236     {// check norm of gradient of sphere w/o mask
237         tools::CheckEikonal<FloatGrid> c(*gridSphere, 0.97f, 1.03f);
238         tools::Diagnose<FloatGrid> d(*gridSphere);
239         std::string str = d.check(c, false, true, false, false);
240         //std::cerr << "NormGrad:\n" << str;
241         EXPECT_TRUE(str.empty());
242         EXPECT_EQ(0, int(d.valueCount()));
243         EXPECT_EQ(0, int(d.failureCount()));
244     }
245     {// check norm of gradient of sphere w/o mask
246         tools::CheckNormGrad<FloatGrid> c(*gridSphere, 0.75f, 1.25f);
247         tools::Diagnose<FloatGrid> d(*gridSphere);
248         std::string str = d.check(c, false, true, false, false);
249         //std::cerr << "NormGrad:\n" << str;
250         EXPECT_TRUE(str.empty());
251         EXPECT_EQ(0, int(d.valueCount()));
252         EXPECT_EQ(0, int(d.failureCount()));
253     }
254     {// check inactive values
255         tools::CheckMagnitude<FloatGrid, FloatGrid::ValueOffCIter> c(gamma);
256         tools::Diagnose<FloatGrid> d(*gridSphere);
257         std::string str = d.check(c);
258         //std::cerr << "Magnitude:\n" << str;
259         EXPECT_TRUE(str.empty());
260         EXPECT_EQ(0, int(d.valueCount()));
261         EXPECT_EQ(0, int(d.failureCount()));
262     }
263 }// testDiagnose
264 
TEST_F(TestDiagnostics,testCheckLevelSet)265 TEST_F(TestDiagnostics, testCheckLevelSet)
266 {
267     using namespace openvdb;
268     const float radius = 4.3f;
269     const Vec3f center(15.8f, 13.2f, 16.7f);
270     const float voxelSize = 0.1f, width = LEVEL_SET_HALF_WIDTH;
271 
272     FloatGrid::Ptr grid =
273         tools::createLevelSetSphere<FloatGrid>(radius, center, voxelSize, width);
274 
275     //tools::CheckLevelSet<FloatGrid> c(*grid);
276     //std::string str = c.check();
277     std::string str = tools::checkLevelSet(*grid);
278     EXPECT_TRUE(str.empty());
279     //std::cerr << "\n" << str << std::endl;
280 
281     grid->tree().setValue(Coord(0,0,0), voxelSize*(width+0.5f));
282     //str = c.check();
283     str = tools::checkLevelSet(*grid);
284     EXPECT_TRUE(!str.empty());
285     //std::cerr << "\n" << str << std::endl;
286 
287     //str = c.check(6);
288     str = tools::checkLevelSet(*grid, 6);
289     EXPECT_TRUE(str.empty());
290 
291 }// testCheckLevelSet
292 
TEST_F(TestDiagnostics,testCheckFogVolume)293 TEST_F(TestDiagnostics, testCheckFogVolume)
294 {
295     using namespace openvdb;
296     const float radius = 4.3f;
297     const Vec3f center(15.8f, 13.2f, 16.7f);
298     const float voxelSize = 0.1f, width = LEVEL_SET_HALF_WIDTH;
299 
300     FloatGrid::Ptr grid =
301         tools::createLevelSetSphere<FloatGrid>(radius, center, voxelSize, width);
302     tools::sdfToFogVolume(*grid);
303 
304     //tools::CheckFogVolume<FloatGrid> c(*grid);
305     //std::string str = c.check();
306     std::string str = tools::checkFogVolume(*grid);
307     EXPECT_TRUE(str.empty());
308     //std::cerr << "\n" << str << std::endl;
309 
310     grid->tree().setValue(Coord(0,0,0), 1.5f);
311     //str = c.check();
312     str = tools::checkFogVolume(*grid);
313     EXPECT_TRUE(!str.empty());
314     //std::cerr << "\n" << str << std::endl;
315 
316     str = tools::checkFogVolume(*grid, 5);
317     //str = c.check(5);
318     EXPECT_TRUE(str.empty());
319 
320 }// testCheckFogVolume
321 
TEST_F(TestDiagnostics,testUniqueInactiveValues)322 TEST_F(TestDiagnostics, testUniqueInactiveValues)
323 {
324     openvdb::FloatGrid grid;
325 
326     grid.tree().setValueOff(openvdb::Coord(0,0,0), -1);
327     grid.tree().setValueOff(openvdb::Coord(0,0,1), -2);
328     grid.tree().setValueOff(openvdb::Coord(0,1,0), -3);
329     grid.tree().setValue(openvdb::Coord(1,0,0),  1);
330 
331     std::vector<float> values;
332 
333     EXPECT_TRUE(openvdb::tools::uniqueInactiveValues(grid, values, 4));
334 
335     EXPECT_EQ(4, int(values.size()));
336 
337     EXPECT_TRUE(openvdb::math::isApproxEqual(values[0], -3.0f));
338     EXPECT_TRUE(openvdb::math::isApproxEqual(values[1], -2.0f));
339     EXPECT_TRUE(openvdb::math::isApproxEqual(values[2], -1.0f));
340     EXPECT_TRUE(openvdb::math::isApproxEqual(values[3], 0.0f));
341 
342 
343     // test with level set sphere
344     const float radius = 4.3f;
345     const openvdb::Vec3f center(15.8f, 13.2f, 16.7f);
346     const float voxelSize = 0.5f, width = 2.0f;
347 
348     openvdb::FloatGrid::Ptr gridSphere =
349         openvdb::tools::createLevelSetSphere<openvdb::FloatGrid>(radius, center, voxelSize, width);
350 
351     EXPECT_TRUE(openvdb::tools::uniqueInactiveValues(*gridSphere.get(), values, 2));
352 
353     EXPECT_EQ(2, int(values.size()));
354     EXPECT_TRUE(openvdb::math::isApproxEqual(values[0], -voxelSize * width));
355     EXPECT_TRUE(openvdb::math::isApproxEqual(values[1],  voxelSize * width));
356 
357     // test with fog volume
358     openvdb::tools::sdfToFogVolume(*gridSphere);
359 
360     EXPECT_TRUE(openvdb::tools::uniqueInactiveValues(*gridSphere.get(), values, 1));
361 
362     EXPECT_EQ(1, int(values.size()));
363     EXPECT_TRUE(openvdb::math::isApproxEqual(values[0], 0.0f));
364 }
365