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