1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 // Uncomment to temporarily disable testing of PNanoVDB
5 //#define DISABLE_PNANOVDB
6
7 #include <iostream>
8 #include <cstdlib>
9 #include <sstream> // for std::stringstream
10 #include <vector>
11 #include <limits.h> // CHAR_BIT
12 #include <algorithm> // for std::is_sorted
13 #include <cmath>
14 #include <cstdlib>
15
16 #include <nanovdb/util/IO.h>
17 #include <nanovdb/util/GridBuilder.h>
18 #include <nanovdb/util/Primitives.h>
19 #include <nanovdb/util/GridStats.h>
20 #include <nanovdb/util/GridValidator.h>
21 #include <nanovdb/util/Ray.h>
22 #include <nanovdb/util/HDDA.h>
23 #include <nanovdb/util/DitherLUT.h>
24 #include <nanovdb/util/SampleFromVoxels.h>
25 #include <nanovdb/util/Stencils.h>
26 #include <nanovdb/util/Range.h>
27 #include <nanovdb/util/ForEach.h>
28 #include <nanovdb/util/Invoke.h>
29 #include <nanovdb/util/Reduce.h>
30 #include <nanovdb/util/GridChecksum.h>
31 #include <nanovdb/util/NodeManager.h>
32 #include "../examples/ex_util/CpuTimer.h"
33
34 #if !defined(_MSC_VER) // does not compile in msvc c++ due to zero-sized arrays.
35 #include <nanovdb/CNanoVDB.h>
36 #endif
37
38 #if !defined(DISABLE_PNANOVDB)
39 #define PNANOVDB_C
40 #include <nanovdb/PNanoVDB.h>
41 #include "pnanovdb_validate_strides.h"
42 #endif
43
44 #include <gtest/gtest.h>
45
46
47 namespace nanovdb {// this namespace is required by gtest
48 std::ostream&
operator <<(std::ostream & os,const Coord & ijk)49 operator<<(std::ostream& os, const Coord& ijk)
50 {
51 os << "(" << ijk[0] << "," << ijk[1] << "," << ijk[2] << ")";
52 return os;
53 }
54
55 std::ostream&
operator <<(std::ostream & os,const CoordBBox & b)56 operator<<(std::ostream& os, const CoordBBox& b)
57 {
58 os << b[0] << " -> " << b[1];
59 return os;
60 }
61
62 template<typename T>
63 std::ostream&
operator <<(std::ostream & os,const Vec3<T> & v)64 operator<<(std::ostream& os, const Vec3<T>& v)
65 {
66 os << "(" << v[0] << "," << v[1] << "," << v[2] << ")";
67 return os;
68 }
69 }// namespace nanovdb
70
71 namespace {
72 template<typename ValueT>
73 struct Sphere
74 {
Sphere__anonfeb603ba0111::Sphere75 Sphere(const nanovdb::Vec3<ValueT>& center,
76 ValueT radius,
77 ValueT voxelSize = 1.0,
78 ValueT halfWidth = 3.0)
79 : mCenter(center)
80 , mRadius(radius)
81 , mVoxelSize(voxelSize)
82 , mBackground(voxelSize * halfWidth)
83 {
84 }
85
background__anonfeb603ba0111::Sphere86 ValueT background() const { return mBackground; }
87
88 /// @brief Only method required by GridBuilder
operator ()__anonfeb603ba0111::Sphere89 ValueT operator()(const nanovdb::Coord& ijk) const
90 {
91 const ValueT dst = this->sdf(ijk);
92 return dst >= mBackground ? mBackground : dst <= -mBackground ? -mBackground : dst;
93 }
operator ()__anonfeb603ba0111::Sphere94 ValueT operator()(const nanovdb::Vec3<ValueT>& p) const
95 {
96 const ValueT dst = this->sdf(p);
97 return dst >= mBackground ? mBackground : dst <= -mBackground ? -mBackground : dst;
98 }
isInside__anonfeb603ba0111::Sphere99 bool isInside(const nanovdb::Coord& ijk) const
100 {
101 return this->sdf(ijk) < 0;
102 }
isOutside__anonfeb603ba0111::Sphere103 bool isOutside(const nanovdb::Coord& ijk) const
104 {
105 return this->sdf(ijk) > 0;
106 }
inNarrowBand__anonfeb603ba0111::Sphere107 bool inNarrowBand(const nanovdb::Coord& ijk) const
108 {
109 const ValueT d = this->sdf(ijk);
110 return d < mBackground && d > -mBackground;
111 }
112
113 private:
sdf__anonfeb603ba0111::Sphere114 ValueT sdf(nanovdb::Vec3<ValueT> xyz) const
115 {
116 xyz *= mVoxelSize;
117 xyz -= mCenter;
118 return xyz.length() - mRadius;
119 }
sdf__anonfeb603ba0111::Sphere120 ValueT sdf(const nanovdb::Coord& ijk) const { return this->sdf(nanovdb::Vec3<ValueT>(ijk[0], ijk[1], ijk[2])); }
121 static_assert(nanovdb::is_floating_point<float>::value, "Sphere: expect floating point");
122 const nanovdb::Vec3<ValueT> mCenter;
123 const ValueT mRadius, mVoxelSize, mBackground;
124 }; // Sphere
125 } // namespace
126
127 // The fixture for testing class.
128 class TestNanoVDB : public ::testing::Test
129 {
130 protected:
TestNanoVDB()131 TestNanoVDB() {}
132
~TestNanoVDB()133 ~TestNanoVDB() override {}
134
135 // If the constructor and destructor are not enough for setting up
136 // and cleaning up each test, you can define the following methods:
137
SetUp()138 void SetUp() override
139 {
140 // Code here will be called immediately after the constructor (right
141 // before each test).
142 }
143
TearDown()144 void TearDown() override
145 {
146 // Code here will be called immediately after each test (right
147 // before the destructor).
148 }
149
getEnvVar(const std::string & name) const150 std::string getEnvVar(const std::string& name) const
151 {
152 const char* str = std::getenv(name.c_str());
153 return str == nullptr ? std::string("") : std::string(str);
154 }
155
156 template<typename T>
printType(const std::string & s)157 void printType(const std::string& s)
158 {
159 const auto n = sizeof(T);
160 std::cerr << "Size of " << s << ": " << n << " bytes which is" << (n % 32 == 0 ? " " : " NOT ") << "32 byte aligned" << std::endl;
161 }
162 nanovdb::CpuTimer<> mTimer;
163 }; // TestNanoVDB
164
165 template <typename T>
166 class TestOffsets : public ::testing::Test
167 {
168 protected:
TestOffsets()169 TestOffsets() {}
170
~TestOffsets()171 ~TestOffsets() override {}
172
SetUp()173 void SetUp() override
174 {
175 }
176
TearDown()177 void TearDown() override
178 {
179 }
180
181 }; // TestOffsets<T>
182
183 using MyTypes = ::testing::Types<float,
184 double,
185 nanovdb::Fp4,
186 nanovdb::Fp8,
187 nanovdb::Fp16,
188 nanovdb::FpN,
189 int16_t,
190 int32_t,
191 int64_t,
192 nanovdb::Vec3f,
193 nanovdb::Vec3d,
194 nanovdb::ValueMask,
195 bool,
196 int16_t,
197 uint32_t>;
198
199 TYPED_TEST_SUITE(TestOffsets, MyTypes);
200
TEST_F(TestNanoVDB,Version)201 TEST_F(TestNanoVDB, Version)
202 {
203 EXPECT_EQ( 4u, sizeof(uint32_t));
204 EXPECT_EQ( 4u, sizeof(nanovdb::Version));
205 {// default constructor
206 nanovdb::Version v;
207 EXPECT_EQ(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER), v.getMajor());
208 EXPECT_EQ(uint32_t(NANOVDB_MINOR_VERSION_NUMBER), v.getMinor());
209 EXPECT_EQ(uint32_t(NANOVDB_PATCH_VERSION_NUMBER), v.getPatch());
210 std::stringstream ss;
211 ss << NANOVDB_MAJOR_VERSION_NUMBER << "."
212 << NANOVDB_MINOR_VERSION_NUMBER << "."
213 << NANOVDB_PATCH_VERSION_NUMBER;
214 auto c_str = v.c_str();
215 EXPECT_EQ(ss.str(), std::string(c_str));
216 std::free(const_cast<char*>(c_str));
217 //std::cerr << v.c_str() << std::endl;
218 }
219 {// detailed constructor
220 const uint32_t major = (1u << 11) - 1;// maximum allowed value
221 const uint32_t minor = (1u << 11) - 1;// maximum allowed value
222 const uint32_t patch = (1u << 10) - 1;// maximum allowed value
223 nanovdb::Version v( major, minor, patch);
224 EXPECT_EQ(major, v.getMajor());
225 EXPECT_EQ(minor, v.getMinor());
226 EXPECT_EQ(patch, v.getPatch());
227 std::stringstream ss;
228 ss << major << "." << minor << "." << patch;
229 auto c_str = v.c_str();
230 EXPECT_EQ(ss.str(), std::string(c_str));
231 std::free(const_cast<char*>(c_str));
232 //std::cerr << v.c_str() << std::endl;
233 }
234 {// smallest possible version number
235 const uint32_t major = 1u;
236 const uint32_t minor = 0u;
237 const uint32_t patch = 0u;
238 nanovdb::Version v( major, minor, patch);
239 EXPECT_EQ(major, v.getMajor());
240 EXPECT_EQ(minor, v.getMinor());
241 EXPECT_EQ(patch, v.getPatch());
242 std::stringstream ss;
243 ss << major << "." << minor << "." << patch;
244 auto c_str = v.c_str();
245 EXPECT_EQ(ss.str(), std::string(c_str));
246 std::free(const_cast<char*>(c_str));
247 //std::cerr << "version.data = " << v.id() << std::endl;
248 }
249 {// test comparison operators
250 EXPECT_EQ( nanovdb::Version(28, 2, 7), nanovdb::Version( 28, 2, 7) );
251 EXPECT_LE( nanovdb::Version(28, 2, 7), nanovdb::Version( 28, 2, 7) );
252 EXPECT_GE( nanovdb::Version(28, 2, 7), nanovdb::Version( 28, 2, 7) );
253 EXPECT_LT( nanovdb::Version(28, 2, 7), nanovdb::Version( 28, 2, 8) );
254 EXPECT_LT( nanovdb::Version(28, 2, 7), nanovdb::Version( 28, 3, 7) );
255 EXPECT_LT( nanovdb::Version(28, 2, 7), nanovdb::Version( 29, 2, 7) );
256 EXPECT_LT( nanovdb::Version(28, 2, 7), nanovdb::Version( 29, 3, 8) );
257 EXPECT_GT( nanovdb::Version(29, 0, 0), nanovdb::Version( 28, 2, 8) );
258 }
259
260 // nanovdb::Version was introduce in 29.0.0! For backwards compatibility with 28.X.X
261 // we need to distinguish between old formats (either uint32_t or two uint16_t) and
262 // the new format (nanovdb::Version which internally stored a single uint32_t).
263 {
264 // Define a struct that memory-maps all three possible representations
265 struct T {
266 union {
267 nanovdb::Version version;
268 uint32_t id;
269 struct {uint16_t major, minor;};
270 };
271 T(uint32_t _major) : id(_major) {}
272 T(uint32_t _major, uint32_t _minor) : major(_major), minor(_minor) {}
273 T(uint32_t _major, uint32_t _minor, uint32_t _patch) : version(_major, _minor, _patch) {}
274 };
275 EXPECT_EQ( sizeof(uint32_t), sizeof(T) );
276 // Verify that T(1,0,0).id() is the smallest instance of Version
277 for (uint32_t major = 1; major < 30; ++major) {
278 for (uint32_t minor = 0; minor < 10; ++minor) {
279 for (uint32_t patch = 0; patch < 10; ++patch) {
280 T tmp(major, minor, patch);
281 EXPECT_LE(T(1,0,0).id, tmp.id);
282 EXPECT_LE(T(1,0,0).version, tmp.version);
283 }
284 }
285 }
286 // Verify that all relevant "uint16_t major,minor" instances are smaller than T(29,0,0)
287 for (uint32_t major = 1; major <= 28; ++major) {
288 for (uint32_t minor = 0; minor < 30; ++minor) {
289 T tmp(major, minor);
290 EXPECT_LT(tmp.id, T(29,0,0).id);
291 EXPECT_LT(tmp.version, T(29,0,0).version);
292 }
293 }
294 // Verify that all relevant "uint32_t major" instances are smaller than T(29,0,0)
295 for (uint32_t major = 1; major <= 28; ++major) {
296 T tmp(major);
297 EXPECT_LT(tmp.id, T(29,0,0).id);
298 EXPECT_LT(tmp.version, T(29,0,0).version);
299 }
300 }
301 }
302
TEST_F(TestNanoVDB,Basic)303 TEST_F(TestNanoVDB, Basic)
304 {
305 { // CHAR_BIT
306 EXPECT_EQ(8, CHAR_BIT);
307 }
308 {
309 std::vector<int> v = {3, 1, 7, 0};
310 EXPECT_FALSE(std::is_sorted(v.begin(), v.end()));
311 std::map<int, void*> m;
312 for (const auto& i : v)
313 m[i] = nullptr;
314 v.clear();
315 for (const auto& i : m)
316 v.push_back(i.first);
317 EXPECT_TRUE(std::is_sorted(v.begin(), v.end()));
318 }
319 {
320 enum tmp { a = 0,
321 b,
322 c,
323 d } t;
324 EXPECT_EQ(sizeof(int), sizeof(t));
325 }
326 {// Check size of io::MetaData
327 EXPECT_EQ(176u, sizeof(nanovdb::io::MetaData));
328 //std::cerr << "sizeof(MetaData) = " << sizeof(nanovdb::io::MetaData) << std::endl;
329 }
330 }
331
TEST_F(TestNanoVDB,Assumptions)332 TEST_F(TestNanoVDB, Assumptions)
333 {
334 struct A
335 {
336 int32_t i;
337 };
338 EXPECT_EQ(sizeof(int32_t), sizeof(A));
339 A a{-1};
340 EXPECT_EQ(-1, a.i);
341 EXPECT_EQ(reinterpret_cast<uint8_t*>(&a), reinterpret_cast<uint8_t*>(&a.i));
342 struct B
343 {
344 A a;
345 };
346 B b{-1};
347 EXPECT_EQ(-1, b.a.i);
348 EXPECT_EQ(reinterpret_cast<uint8_t*>(&b), reinterpret_cast<uint8_t*>(&(b.a)));
349 EXPECT_EQ(reinterpret_cast<uint8_t*>(&(b.a)), reinterpret_cast<uint8_t*>(&(b.a.i)));
350 EXPECT_EQ(nanovdb::AlignUp<32>(48), 64U);
351 EXPECT_EQ(nanovdb::AlignUp<8>(16), 16U);
352 }
353
TEST_F(TestNanoVDB,Magic)354 TEST_F(TestNanoVDB, Magic)
355 {
356 EXPECT_EQ(0x304244566f6e614eUL, NANOVDB_MAGIC_NUMBER); // Magic number: "NanoVDB0" in hex)
357 EXPECT_EQ(0x4e616e6f56444230UL, nanovdb::io::reverseEndianness(NANOVDB_MAGIC_NUMBER));
358
359 // Verify little endian representation
360 const char* str = "NanoVDB0"; // note it's exactly 8 bytes
361 EXPECT_EQ(8u, strlen(str));
362 std::stringstream ss1;
363 ss1 << "0x";
364 for (int i = 7; i >= 0; --i)
365 ss1 << std::hex << unsigned(str[i]);
366 ss1 << "UL";
367 //std::cerr << ss1.str() << std::endl;
368 EXPECT_EQ("0x304244566f6e614eUL", ss1.str());
369
370 uint64_t magic;
371 ss1 >> magic;
372 EXPECT_EQ(magic, NANOVDB_MAGIC_NUMBER);
373
374 // Verify big endian representation
375 std::stringstream ss2;
376 ss2 << "0x";
377 for (size_t i = 0; i < 8; ++i)
378 ss2 << std::hex << unsigned(str[i]);
379 ss2 << "UL";
380 //std::cerr << ss2.str() << std::endl;
381 EXPECT_EQ("0x4e616e6f56444230UL", ss2.str());
382
383 ss2 >> magic;
384 EXPECT_EQ(magic, nanovdb::io::reverseEndianness(NANOVDB_MAGIC_NUMBER));
385 }
386
TEST_F(TestNanoVDB,FindBits)387 TEST_F(TestNanoVDB, FindBits)
388 {
389 for (uint32_t i = 0; i < 32; ++i) {
390 uint32_t word = uint32_t(1) << i;
391 EXPECT_EQ(i, nanovdb::FindLowestOn(word));
392 EXPECT_EQ(i, nanovdb::FindHighestOn(word));
393 }
394 for (uint32_t i = 0; i < 64; ++i) {
395 uint64_t word = uint64_t(1) << i;
396 EXPECT_EQ(i, nanovdb::FindLowestOn(word));
397 EXPECT_EQ(i, nanovdb::FindHighestOn(word));
398 }
399 }
400
TEST_F(TestNanoVDB,CRC32)401 TEST_F(TestNanoVDB, CRC32)
402 {
403 { // test function that uses iterators
404 const std::string s{"The quick brown fox jumps over the lazy dog"};
405 std::stringstream ss;
406 ss << std::hex << std::setw(8) << std::setfill('0') << nanovdb::crc32(s.begin(), s.end());
407 EXPECT_EQ("414fa339", ss.str());
408 }
409 { // test the checksum for a modified string
410 const std::string s{"The quick brown Fox jumps over the lazy dog"};
411 std::stringstream ss;
412 ss << std::hex << std::setw(8) << std::setfill('0') << nanovdb::crc32(s.begin(), s.end());
413 EXPECT_NE("414fa339", ss.str());
414 }
415 { // test function that uses void pointer and byte size
416 const std::string s{"The quick brown fox jumps over the lazy dog"};
417 std::stringstream ss;
418 ss << std::hex << std::setw(8) << std::setfill('0') << nanovdb::crc32(s.data(), s.size());
419 EXPECT_EQ("414fa339", ss.str());
420 }
421 { // test accumulation
422 nanovdb::CRC32 crc;
423 const std::string s1{"The quick brown fox jum"};
424 crc(s1.begin(), s1.end());
425 const std::string s2{"ps over the lazy dog"};
426 crc(s2.begin(), s2.end());
427 std::stringstream ss;
428 ss << std::hex << std::setw(8) << std::setfill('0') << crc.checksum();
429 EXPECT_EQ("414fa339", ss.str());
430 }
431 }
432
TEST_F(TestNanoVDB,Range1D)433 TEST_F(TestNanoVDB, Range1D)
434 {
435 nanovdb::Range1D r1(0, 20, 2);
436 EXPECT_FALSE(r1.empty());
437 EXPECT_EQ(2U, r1.grainsize());
438 EXPECT_EQ(20U, r1.size());
439 EXPECT_EQ(10U, r1.middle());
440 EXPECT_TRUE(r1.is_divisible());
441 EXPECT_EQ(0U, r1.begin());
442 EXPECT_EQ(20U, r1.end());
443
444 nanovdb::Range1D r2(r1, nanovdb::Split());
445
446 EXPECT_FALSE(r1.empty());
447 EXPECT_EQ(2U, r1.grainsize());
448 EXPECT_EQ(10U, r1.size());
449 EXPECT_EQ(5U, r1.middle());
450 EXPECT_TRUE(r1.is_divisible());
451 EXPECT_EQ(0U, r1.begin());
452 EXPECT_EQ(10U, r1.end());
453
454 EXPECT_FALSE(r2.empty());
455 EXPECT_EQ(2U, r2.grainsize());
456 EXPECT_EQ(10U, r2.size());
457 EXPECT_EQ(15U, r2.middle());
458 EXPECT_TRUE(r2.is_divisible());
459 EXPECT_EQ(10U, r2.begin());
460 EXPECT_EQ(20U, r2.end());
461 }
462
TEST_F(TestNanoVDB,Range2D)463 TEST_F(TestNanoVDB, Range2D)
464 {
465 nanovdb::Range<2, int> r1(-20, 20, 1u, 0, 20, 2u);
466
467 EXPECT_FALSE(r1.empty());
468 EXPECT_EQ(1U, r1[0].grainsize());
469 EXPECT_EQ(40U, r1[0].size());
470 EXPECT_EQ(0, r1[0].middle());
471 EXPECT_TRUE(r1[0].is_divisible());
472 EXPECT_EQ(-20, r1[0].begin());
473 EXPECT_EQ(20, r1[0].end());
474
475 EXPECT_EQ(2U, r1[1].grainsize());
476 EXPECT_EQ(20U, r1[1].size());
477 EXPECT_EQ(10, r1[1].middle());
478 EXPECT_TRUE(r1[1].is_divisible());
479 EXPECT_EQ(0, r1[1].begin());
480 EXPECT_EQ(20, r1[1].end());
481
482 nanovdb::Range<2, int> r2(r1, nanovdb::Split());
483
484 EXPECT_FALSE(r1.empty());
485 EXPECT_EQ(1U, r1[0].grainsize());
486 EXPECT_EQ(20U, r1[0].size());
487 EXPECT_EQ(-10, r1[0].middle());
488 EXPECT_TRUE(r1[0].is_divisible());
489 EXPECT_EQ(-20, r1[0].begin());
490 EXPECT_EQ(0, r1[0].end());
491
492 EXPECT_EQ(2U, r1[1].grainsize());
493 EXPECT_EQ(20U, r1[1].size());
494 EXPECT_EQ(10, r1[1].middle());
495 EXPECT_TRUE(r1[1].is_divisible());
496 EXPECT_EQ(0, r1[1].begin());
497 EXPECT_EQ(20, r1[1].end());
498
499 EXPECT_FALSE(r2.empty());
500 EXPECT_EQ(1U, r2[0].grainsize());
501 EXPECT_EQ(20U, r2[0].size());
502 EXPECT_EQ(10, r2[0].middle());
503 EXPECT_TRUE(r2[0].is_divisible());
504 EXPECT_EQ(0, r2[0].begin());
505 EXPECT_EQ(20, r2[0].end());
506
507 EXPECT_EQ(2U, r2[1].grainsize());
508 EXPECT_EQ(20U, r2[1].size());
509 EXPECT_EQ(10, r2[1].middle());
510 EXPECT_TRUE(r2[1].is_divisible());
511 EXPECT_EQ(0, r2[1].begin());
512 EXPECT_EQ(20, r2[1].end());
513 EXPECT_EQ(r1[1], r2[1]);
514 }
515
TEST_F(TestNanoVDB,Range3D)516 TEST_F(TestNanoVDB, Range3D)
517 {
518 nanovdb::Range<3, int> r1(-20, 20, 1u, 0, 20, 2u, 0, 10, 5);
519
520 EXPECT_FALSE(r1.empty());
521 EXPECT_EQ(1U, r1[0].grainsize());
522 EXPECT_EQ(40U, r1[0].size());
523 EXPECT_EQ(0, r1[0].middle());
524 EXPECT_TRUE(r1[0].is_divisible());
525 EXPECT_EQ(-20, r1[0].begin());
526 EXPECT_EQ(20, r1[0].end());
527
528 EXPECT_EQ(2U, r1[1].grainsize());
529 EXPECT_EQ(20U, r1[1].size());
530 EXPECT_EQ(10, r1[1].middle());
531 EXPECT_TRUE(r1[1].is_divisible());
532 EXPECT_EQ(0, r1[1].begin());
533 EXPECT_EQ(20, r1[1].end());
534
535 EXPECT_EQ(5U, r1[2].grainsize());
536 EXPECT_EQ(10U, r1[2].size());
537 EXPECT_EQ(5, r1[2].middle());
538 EXPECT_TRUE(r1[2].is_divisible());
539 EXPECT_EQ(0, r1[2].begin());
540 EXPECT_EQ(10, r1[2].end());
541
542 nanovdb::Range<3, int> r2(r1, nanovdb::Split());
543
544 EXPECT_FALSE(r1.empty());
545 EXPECT_EQ(1U, r1[0].grainsize());
546 EXPECT_EQ(20U, r1[0].size());
547 EXPECT_EQ(-10, r1[0].middle());
548 EXPECT_TRUE(r1[0].is_divisible());
549 EXPECT_EQ(-20, r1[0].begin());
550 EXPECT_EQ(0, r1[0].end());
551
552 EXPECT_EQ(2U, r1[1].grainsize());
553 EXPECT_EQ(20U, r1[1].size());
554 EXPECT_EQ(10, r1[1].middle());
555 EXPECT_TRUE(r1[1].is_divisible());
556 EXPECT_EQ(0, r1[1].begin());
557 EXPECT_EQ(20, r1[1].end());
558
559 EXPECT_EQ(5U, r1[2].grainsize());
560 EXPECT_EQ(10U, r1[2].size());
561 EXPECT_EQ(5, r1[2].middle());
562 EXPECT_TRUE(r1[2].is_divisible());
563 EXPECT_EQ(0, r1[2].begin());
564 EXPECT_EQ(10, r1[2].end());
565
566 EXPECT_FALSE(r2.empty());
567 EXPECT_EQ(1U, r2[0].grainsize());
568 EXPECT_EQ(20U, r2[0].size());
569 EXPECT_EQ(10, r2[0].middle());
570 EXPECT_TRUE(r2[0].is_divisible());
571 EXPECT_EQ(0, r2[0].begin());
572 EXPECT_EQ(20, r2[0].end());
573
574 EXPECT_EQ(2U, r2[1].grainsize());
575 EXPECT_EQ(20U, r2[1].size());
576 EXPECT_EQ(10, r2[1].middle());
577 EXPECT_TRUE(r2[1].is_divisible());
578 EXPECT_EQ(0, r2[1].begin());
579 EXPECT_EQ(20, r2[1].end());
580 EXPECT_EQ(r1[1], r2[1]);
581
582 EXPECT_EQ(5U, r2[2].grainsize());
583 EXPECT_EQ(10U, r2[2].size());
584 EXPECT_EQ(5, r2[2].middle());
585 EXPECT_TRUE(r2[2].is_divisible());
586 EXPECT_EQ(0, r2[2].begin());
587 EXPECT_EQ(10, r2[2].end());
588 EXPECT_EQ(r1[2], r2[2]);
589 }
590
TEST_F(TestNanoVDB,invoke)591 TEST_F(TestNanoVDB, invoke)
592 {
593 const int size = 4;
594 std::vector<int> array(size, 0);
595 for (int i=0; i<size; ++i) {
596 EXPECT_EQ(0, array[i]);
597 }
598 auto kernel0 = [&array](){array[0]=0; };
599 auto kernel1 = [&array](){array[1]=1; };
600 auto kernel2 = [&array](){array[2]=2; };
601 auto kernel3 = [&array](){array[3]=3; };
602 nanovdb::invoke(kernel0, kernel1, kernel2, kernel3);
603 for (int i=0; i<size; ++i) {
604 EXPECT_EQ(i, array[i]);
605 }
606 }
607
TEST_F(TestNanoVDB,forEach)608 TEST_F(TestNanoVDB, forEach)
609 {
610 const int size = 1000;
611 std::vector<int> array(size, 0);
612 for (int i=0; i<size; ++i) {
613 EXPECT_EQ(0, array[i]);
614 }
615 auto kernel = [&array](const nanovdb::Range1D &r){for (auto i=r.begin(); i!=r.end(); ++i) array[i]=i; };
616 nanovdb::forEach(array, kernel);
617 for (int i=0; i<size; ++i) {
618 EXPECT_EQ(i, array[i]);
619 }
620 }
621
TEST_F(TestNanoVDB,reduce)622 TEST_F(TestNanoVDB, reduce)
623 {
624 const int size = 1000;
625 std::vector<int> array(size);
626 int expected = 0;
627 for (int i=0; i<size; ++i) {
628 array[i] = i;
629 expected += i;
630 }
631 const int identity = 0;
632 auto func = [&array](const nanovdb::Range1D &r, int a){for (auto i=r.begin(); i!=r.end(); ++i) a+=array[i]; return a; };
633 auto join = [](int a, int b){return a + b;};
634 EXPECT_EQ(expected, nanovdb::reduce(nanovdb::Range1D(0, size), identity, func, join));
635 EXPECT_EQ(expected, nanovdb::reduce(array, identity, func, join));
636 EXPECT_EQ(expected, nanovdb::reduce(array, 8, identity, func, join));
637 for (int i=0; i<size; ++i) {
638 EXPECT_EQ(i, array[i]);
639 }
640 }
641
TEST_F(TestNanoVDB,DitherLUT)642 TEST_F(TestNanoVDB, DitherLUT)
643 {
644 nanovdb::DitherLUT lut;
645 float min = 1.0f, max = 0.0f;
646 for (int i=-10; i<1024; ++i) {
647 const float offset = lut(i);
648 if (offset < min) min = offset;
649 if (offset > max) max = offset;
650 EXPECT_TRUE( offset > 0.0f);
651 EXPECT_TRUE( offset < 1.0f);
652 }
653 //std::cout << "Dither: min = " << min << ", max = " << max << std::endl;
654 }
655
TEST_F(TestNanoVDB,Rgba8)656 TEST_F(TestNanoVDB, Rgba8)
657 {
658 EXPECT_EQ(sizeof(uint32_t), sizeof(nanovdb::Rgba8));
659 {
660 nanovdb::Rgba8 p;
661 EXPECT_EQ(0u, p[0]);
662 EXPECT_EQ(0u, p[1]);
663 EXPECT_EQ(0u, p[2]);
664 EXPECT_EQ(0u, p[3]);
665 EXPECT_EQ(0u, p.r());
666 EXPECT_EQ(0u, p.g());
667 EXPECT_EQ(0u, p.b());
668 EXPECT_EQ(0u, p.a());
669 EXPECT_EQ(0u, p.packed());
670 EXPECT_EQ(nanovdb::Rgba8(), p);
671 }
672 {
673 nanovdb::Rgba8 p(uint8_t(1));
674 EXPECT_EQ(1u, p[0]);
675 EXPECT_EQ(1u, p[1]);
676 EXPECT_EQ(1u, p[2]);
677 EXPECT_EQ(1u, p[3]);
678 EXPECT_EQ(1u, p.r());
679 EXPECT_EQ(1u, p.g());
680 EXPECT_EQ(1u, p.b());
681 EXPECT_EQ(1u, p.a());
682 EXPECT_LT(nanovdb::Rgba8(), p);
683 }
684 {
685 nanovdb::Rgba8 p(uint8_t(1), uint8_t(2), uint8_t(3), uint8_t(4));
686 EXPECT_EQ(1u, p[0]);
687 EXPECT_EQ(2u, p[1]);
688 EXPECT_EQ(3u, p[2]);
689 EXPECT_EQ(4u, p[3]);
690 EXPECT_EQ(1u, p.r());
691 EXPECT_EQ(2u, p.g());
692 EXPECT_EQ(3u, p.b());
693 EXPECT_EQ(4u, p.a());
694 EXPECT_LT(nanovdb::Rgba8(), p);
695 }
696 {
697 nanovdb::Rgba8 p(uint8_t(255), uint8_t(255), uint8_t(255), uint8_t(255));
698 EXPECT_EQ(255u, p[0]);
699 EXPECT_EQ(255u, p[1]);
700 EXPECT_EQ(255u, p[2]);
701 EXPECT_EQ(255u, p[3]);
702 EXPECT_EQ(255u, p.r());
703 EXPECT_EQ(255u, p.g());
704 EXPECT_EQ(255u, p.b());
705 EXPECT_EQ(255u, p.a());
706 EXPECT_LT(nanovdb::Rgba8(), p);
707 EXPECT_NEAR(p.lengthSqr(), 3.0f, 1e-6);
708 EXPECT_NEAR(p.length(), sqrt(3.0f), 1e-6);
709 }
710 {
711 nanovdb::Rgba8 p(1.0f, 0.0f, 0.0f, 1.0f);
712 EXPECT_EQ(255u, p[0]);
713 EXPECT_EQ(0u, p[1]);
714 EXPECT_EQ(0u, p[2]);
715 EXPECT_EQ(255u, p[3]);
716 EXPECT_EQ(255u, p.r());
717 EXPECT_EQ(0u, p.g());
718 EXPECT_EQ(0u, p.b());
719 EXPECT_EQ(255u, p.a());
720 EXPECT_LT(nanovdb::Rgba8(), p);
721 EXPECT_NEAR(p.lengthSqr(), 1.0f, 1e-6);
722 EXPECT_NEAR(p.length(), 1.0f, 1e-6);
723 }
724 {
725 nanovdb::Rgba8 p(0.0f, 1.0f, 0.5f, 0.1f);
726 EXPECT_EQ(0u, p[0]);
727 EXPECT_EQ(255u, p[1]);
728 EXPECT_EQ(128u, p[2]);
729 EXPECT_EQ(26u, p[3]);
730 EXPECT_EQ(0u, p.r());
731 EXPECT_EQ(255u, p.g());
732 EXPECT_EQ(128u, p.b());
733 EXPECT_EQ(26u, p.a());
734 EXPECT_LT(nanovdb::Rgba8(), p);
735 }
736 }
737
TEST_F(TestNanoVDB,Coord)738 TEST_F(TestNanoVDB, Coord)
739 {
740 EXPECT_EQ(size_t(3 * 4), nanovdb::Coord::memUsage()); // due to padding
741 {
742 nanovdb::Coord ijk;
743 EXPECT_EQ(sizeof(ijk), size_t(3 * 4));
744 EXPECT_EQ(0, ijk[0]);
745 EXPECT_EQ(0, ijk[1]);
746 EXPECT_EQ(0, ijk[2]);
747 EXPECT_EQ(0, ijk.x());
748 EXPECT_EQ(0, ijk.y());
749 EXPECT_EQ(0, ijk.z());
750 }
751 {
752 nanovdb::Coord ijk(1, 2, 3);
753 EXPECT_EQ(1, ijk[0]);
754 EXPECT_EQ(2, ijk[1]);
755 EXPECT_EQ(3, ijk[2]);
756 EXPECT_EQ(1, ijk.x());
757 EXPECT_EQ(2, ijk.y());
758 EXPECT_EQ(3, ijk.z());
759 ijk[1] = 4;
760 EXPECT_EQ(1, ijk[0]);
761 EXPECT_EQ(4, ijk[1]);
762 EXPECT_EQ(3, ijk[2]);
763 ijk.x() += -2;
764 EXPECT_EQ(-1, ijk[0]);
765 EXPECT_EQ(4, ijk[1]);
766 EXPECT_EQ(3, ijk[2]);
767 }
768 { // hash
769 EXPECT_EQ(0, nanovdb::Coord(1, 2, 3).octant());
770 EXPECT_EQ(0, nanovdb::Coord(1, 9, 3).octant());
771 EXPECT_EQ(1, nanovdb::Coord(-1, 2, 3).octant());
772 EXPECT_EQ(2, nanovdb::Coord(1, -2, 3).octant());
773 EXPECT_EQ(3, nanovdb::Coord(-1, -2, 3).octant());
774 EXPECT_EQ(4, nanovdb::Coord(1, 2, -3).octant());
775 EXPECT_EQ(5, nanovdb::Coord(-1, 2, -3).octant());
776 EXPECT_EQ(6, nanovdb::Coord(1, -2, -3).octant());
777 EXPECT_EQ(7, nanovdb::Coord(-1, -2, -3).octant());
778 for (int i = 0; i < 5; ++i)
779 EXPECT_EQ(i / 2, i >> 1);
780 }
781 }
782
TEST_F(TestNanoVDB,BBox)783 TEST_F(TestNanoVDB, BBox)
784 {
785 nanovdb::BBox<nanovdb::Vec3f> bbox;
786 EXPECT_EQ(sizeof(bbox), size_t(2 * 3 * 4));
787 EXPECT_EQ(std::numeric_limits<float>::max(), bbox[0][0]);
788 EXPECT_EQ(std::numeric_limits<float>::max(), bbox[0][1]);
789 EXPECT_EQ(std::numeric_limits<float>::max(), bbox[0][2]);
790 EXPECT_EQ(-std::numeric_limits<float>::max(), bbox[1][0]);
791 EXPECT_EQ(-std::numeric_limits<float>::max(), bbox[1][1]);
792 EXPECT_EQ(-std::numeric_limits<float>::max(), bbox[1][2]);
793 EXPECT_TRUE(bbox.empty());
794
795 bbox.expand(nanovdb::Vec3f(57.0f, -31.0f, 60.0f));
796 EXPECT_TRUE(bbox.empty());
797 EXPECT_EQ(nanovdb::Vec3f(0.0f), bbox.dim());
798 EXPECT_EQ(57.0f, bbox[0][0]);
799 EXPECT_EQ(-31.0f, bbox[0][1]);
800 EXPECT_EQ(60.0f, bbox[0][2]);
801 EXPECT_EQ(57.0f, bbox[1][0]);
802 EXPECT_EQ(-31.0f, bbox[1][1]);
803 EXPECT_EQ(60.0f, bbox[1][2]);
804
805 bbox.expand(nanovdb::Vec3f(58.0f, 0.0f, 62.0f));
806 EXPECT_FALSE(bbox.empty());
807 EXPECT_EQ(nanovdb::Vec3f(1.0f, 31.0f, 2.0f), bbox.dim());
808 EXPECT_EQ(57.0f, bbox[0][0]);
809 EXPECT_EQ(-31.0f, bbox[0][1]);
810 EXPECT_EQ(60.0f, bbox[0][2]);
811 EXPECT_EQ(58.0f, bbox[1][0]);
812 EXPECT_EQ(0.0f, bbox[1][1]);
813 EXPECT_EQ(62.0f, bbox[1][2]);
814 }
815
TEST_F(TestNanoVDB,CoordBBox)816 TEST_F(TestNanoVDB, CoordBBox)
817 {
818 nanovdb::CoordBBox bbox;
819 EXPECT_EQ(sizeof(bbox), size_t(2 * 3 * 4));
820 EXPECT_EQ(std::numeric_limits<int32_t>::max(), bbox[0][0]);
821 EXPECT_EQ(std::numeric_limits<int32_t>::max(), bbox[0][1]);
822 EXPECT_EQ(std::numeric_limits<int32_t>::max(), bbox[0][2]);
823 EXPECT_EQ(std::numeric_limits<int32_t>::min(), bbox[1][0]);
824 EXPECT_EQ(std::numeric_limits<int32_t>::min(), bbox[1][1]);
825 EXPECT_EQ(std::numeric_limits<int32_t>::min(), bbox[1][2]);
826 EXPECT_TRUE(bbox.empty());
827
828 bbox.expand(nanovdb::Coord(57, -31, 60));
829 EXPECT_FALSE(bbox.empty());
830 EXPECT_EQ(nanovdb::Coord(1), bbox.dim());
831 EXPECT_EQ(57, bbox[0][0]);
832 EXPECT_EQ(-31, bbox[0][1]);
833 EXPECT_EQ(60, bbox[0][2]);
834 EXPECT_EQ(57, bbox[1][0]);
835 EXPECT_EQ(-31, bbox[1][1]);
836 EXPECT_EQ(60, bbox[1][2]);
837
838 bbox.expand(nanovdb::Coord(58, 0, 62));
839 EXPECT_FALSE(bbox.empty());
840 EXPECT_EQ(nanovdb::Coord(2, 32, 3), bbox.dim());
841 EXPECT_EQ(57, bbox[0][0]);
842 EXPECT_EQ(-31, bbox[0][1]);
843 EXPECT_EQ(60, bbox[0][2]);
844 EXPECT_EQ(58, bbox[1][0]);
845 EXPECT_EQ(0, bbox[1][1]);
846 EXPECT_EQ(62, bbox[1][2]);
847
848 { // test convert
849 auto bbox2 = bbox.asReal<float>();
850 EXPECT_FALSE(bbox2.empty());
851 EXPECT_EQ(nanovdb::Vec3f(57.0f, -31.0f, 60.0f), bbox2.min());
852 EXPECT_EQ(nanovdb::Vec3f(59.0f, 1.0f, 63.0f), bbox2.max());
853 }
854
855 { // test prefix iterator
856 auto iter = bbox.begin();
857 EXPECT_TRUE(iter);
858 for (int i = bbox.min()[0]; i <= bbox.max()[0]; ++i) {
859 for (int j = bbox.min()[1]; j <= bbox.max()[1]; ++j) {
860 for (int k = bbox.min()[2]; k <= bbox.max()[2]; ++k) {
861 EXPECT_TRUE(bbox.isInside(*iter));
862 EXPECT_TRUE(iter);
863 const auto& ijk = *iter; // note, copy by reference
864 EXPECT_EQ(ijk[0], i);
865 EXPECT_EQ(ijk[1], j);
866 EXPECT_EQ(ijk[2], k);
867 ++iter;
868 }
869 }
870 }
871 EXPECT_FALSE(iter);
872 }
873
874 { // test postfix iterator
875 auto iter = bbox.begin();
876 EXPECT_TRUE(iter);
877 for (int i = bbox.min()[0]; i <= bbox.max()[0]; ++i) {
878 for (int j = bbox.min()[1]; j <= bbox.max()[1]; ++j) {
879 for (int k = bbox.min()[2]; k <= bbox.max()[2]; ++k) {
880 EXPECT_TRUE(iter);
881 const auto ijk = *iter++; // note, copy by value!
882 EXPECT_EQ(ijk[0], i);
883 EXPECT_EQ(ijk[1], j);
884 EXPECT_EQ(ijk[2], k);
885 }
886 }
887 }
888 EXPECT_FALSE(iter);
889 }
890 }
891
TEST_F(TestNanoVDB,Vec3)892 TEST_F(TestNanoVDB, Vec3)
893 {
894 bool test = nanovdb::is_specialization<double, nanovdb::Vec3>::value;
895 EXPECT_FALSE(test);
896 test = nanovdb::TensorTraits<double>::IsVector;
897 EXPECT_FALSE(test);
898 test = nanovdb::is_specialization<nanovdb::Vec3R, nanovdb::Vec3>::value;
899 EXPECT_TRUE(test);
900 test = nanovdb::is_same<double, nanovdb::Vec3R::ValueType>::value;
901 EXPECT_TRUE(test);
902 test = nanovdb::TensorTraits<nanovdb::Vec3R>::IsVector;
903 EXPECT_TRUE(test);
904 test = nanovdb::is_same<double, nanovdb::TensorTraits<nanovdb::Vec3R>::ElementType>::value;
905 EXPECT_TRUE(test);
906 test = nanovdb::is_same<double, nanovdb::FloatTraits<nanovdb::Vec3R>::FloatType>::value;
907 EXPECT_TRUE(test);
908 EXPECT_EQ(size_t(3 * 8), sizeof(nanovdb::Vec3R));
909
910 nanovdb::Vec3R xyz(1.0, 2.0, 3.0);
911 EXPECT_EQ(1.0, xyz[0]);
912 EXPECT_EQ(2.0, xyz[1]);
913 EXPECT_EQ(3.0, xyz[2]);
914
915 xyz[1] = -2.0;
916 EXPECT_EQ(1.0, xyz[0]);
917 EXPECT_EQ(-2.0, xyz[1]);
918 EXPECT_EQ(3.0, xyz[2]);
919
920 EXPECT_EQ(1.0 + 4.0 + 9.0, xyz.lengthSqr());
921 EXPECT_EQ(sqrt(1.0 + 4.0 + 9.0), xyz.length());
922
923 EXPECT_EQ(nanovdb::Vec3f(1, 2, 3), nanovdb::Vec3f(1, 2, 3));
924 EXPECT_NE(nanovdb::Vec3f(1, 2, 3), nanovdb::Vec3f(1, 2, 4));
925
926 {// alignment to largest type
927 EXPECT_EQ(size_t(3 * 4), sizeof(nanovdb::Vec3f));
928 union {uint64_t a; nanovdb::Vec3f b;} c;
929 EXPECT_EQ(2 * sizeof(uint64_t), sizeof(c));
930 EXPECT_EQ(nanovdb::AlignUp<8>(sizeof(nanovdb::Vec3f)), sizeof(c));
931 }
932 }
933
TEST_F(TestNanoVDB,Vec4)934 TEST_F(TestNanoVDB, Vec4)
935 {
936 bool test = nanovdb::is_specialization<double, nanovdb::Vec4>::value;
937 EXPECT_FALSE(test);
938 test = nanovdb::TensorTraits<double>::IsVector;
939 EXPECT_FALSE(test);
940 test = nanovdb::TensorTraits<double>::IsScalar;
941 EXPECT_TRUE(test);
942 int rank = nanovdb::TensorTraits<double>::Rank;
943 EXPECT_EQ(0, rank);
944 rank = nanovdb::TensorTraits<nanovdb::Vec3R>::Rank;
945 EXPECT_EQ(1, rank);
946 test = nanovdb::is_same<double, nanovdb::FloatTraits<float>::FloatType>::value;
947 EXPECT_FALSE(test);
948 test = nanovdb::is_same<double, nanovdb::FloatTraits<double>::FloatType>::value;
949 EXPECT_TRUE(test);
950 test = nanovdb::is_same<float, nanovdb::FloatTraits<uint32_t>::FloatType>::value;
951 EXPECT_TRUE(test);
952 test = nanovdb::is_same<double, nanovdb::FloatTraits<uint64_t>::FloatType>::value;
953 EXPECT_TRUE(test);
954 test = nanovdb::is_specialization<nanovdb::Vec4R, nanovdb::Vec4>::value;
955 EXPECT_TRUE(test);
956 test = nanovdb::is_specialization<nanovdb::Vec3R, nanovdb::Vec4>::value;
957 EXPECT_FALSE(test);
958 test = nanovdb::is_same<double, nanovdb::Vec4R::ValueType>::value;
959 EXPECT_TRUE(test);
960 test = nanovdb::TensorTraits<nanovdb::Vec3R>::IsVector;
961 EXPECT_TRUE(test);
962 test = nanovdb::is_same<double, nanovdb::TensorTraits<nanovdb::Vec4R>::ElementType>::value;
963 EXPECT_TRUE(test);
964 test = nanovdb::is_same<double, nanovdb::TensorTraits<double>::ElementType>::value;
965 EXPECT_TRUE(test);
966 test = nanovdb::is_same<float, nanovdb::TensorTraits<float>::ElementType>::value;
967 EXPECT_TRUE(test);
968 test = nanovdb::is_same<uint32_t, nanovdb::TensorTraits<uint32_t>::ElementType>::value;
969 EXPECT_TRUE(test);
970 test = nanovdb::is_same<double, nanovdb::FloatTraits<nanovdb::Vec4R>::FloatType>::value;
971 EXPECT_TRUE(test);
972 EXPECT_EQ(size_t(4 * 8), sizeof(nanovdb::Vec4R));
973
974 nanovdb::Vec4R xyz(1.0, 2.0, 3.0, 4.0);
975 EXPECT_EQ(1.0, xyz[0]);
976 EXPECT_EQ(2.0, xyz[1]);
977 EXPECT_EQ(3.0, xyz[2]);
978 EXPECT_EQ(4.0, xyz[3]);
979
980 xyz[1] = -2.0;
981 EXPECT_EQ(1.0, xyz[0]);
982 EXPECT_EQ(-2.0, xyz[1]);
983 EXPECT_EQ(3.0, xyz[2]);
984 EXPECT_EQ(4.0, xyz[3]);
985
986 EXPECT_EQ(1.0 + 4.0 + 9.0 + 16.0, xyz.lengthSqr());
987 EXPECT_EQ(sqrt(1.0 + 4.0 + 9.0 + 16.0), xyz.length());
988
989 EXPECT_EQ(nanovdb::Vec4f(1, 2, 3, 4), nanovdb::Vec4f(1, 2, 3, 4));
990 EXPECT_NE(nanovdb::Vec4f(1, 2, 3, 4), nanovdb::Vec4f(1, 2, 3, 5));
991 }// Vec4
992
TEST_F(TestNanoVDB,Extrema)993 TEST_F(TestNanoVDB, Extrema)
994 {
995 { // int
996 nanovdb::Extrema<int> e(-1);
997 EXPECT_EQ(-1, e.min());
998 EXPECT_EQ(-1, e.max());
999 e.add(-2);
1000 e.add(5);
1001 EXPECT_TRUE(e);
1002 EXPECT_EQ(-2, e.min());
1003 EXPECT_EQ(5, e.max());
1004 }
1005 { // float
1006 nanovdb::Extrema<float> e(-1.0f);
1007 EXPECT_EQ(-1.0f, e.min());
1008 EXPECT_EQ(-1.0f, e.max());
1009 e.add(-2.0f);
1010 e.add(5.0f);
1011 EXPECT_TRUE(e);
1012 EXPECT_EQ(-2.0f, e.min());
1013 EXPECT_EQ(5.0f, e.max());
1014 }
1015 { // Vec3f
1016 nanovdb::Extrema<nanovdb::Vec3f> e(nanovdb::Vec3f(1.0f, 1.0f, 0.0f));
1017 EXPECT_EQ(nanovdb::Vec3f(1.0f, 1.0f, 0.0f), e.min());
1018 EXPECT_EQ(nanovdb::Vec3f(1.0f, 1.0f, 0.0f), e.max());
1019 e.add(nanovdb::Vec3f(1.0f, 0.0f, 0.0f));
1020 e.add(nanovdb::Vec3f(1.0f, 1.0f, 1.0f));
1021 EXPECT_TRUE(e);
1022 EXPECT_EQ(nanovdb::Vec3f(1.0f, 0.0f, 0.0f), e.min());
1023 EXPECT_EQ(nanovdb::Vec3f(1.0f, 1.0f, 1.0f), e.max());
1024 }
1025 }
1026
TEST_F(TestNanoVDB,RayEmptyBBox)1027 TEST_F(TestNanoVDB, RayEmptyBBox)
1028 {
1029 using RealT = float;
1030 using Vec3T = nanovdb::Vec3<RealT>;
1031 using CoordT = nanovdb::Coord;
1032 using CoordBBoxT = nanovdb::BBox<CoordT>;
1033 using BBoxT = nanovdb::BBox<Vec3T>;
1034 using RayT = nanovdb::Ray<RealT>;
1035
1036 // test bbox clip
1037 const Vec3T dir(1.0, 0.0, 0.0);
1038 const Vec3T eye(-1.0, 0.5, 0.5);
1039 RealT t0 = 0.0, t1 = 10000.0;
1040 RayT ray(eye, dir, t0, t1);
1041
1042 const CoordBBoxT bbox1;
1043 EXPECT_TRUE(bbox1.empty());
1044 EXPECT_FALSE(ray.intersects(bbox1, t0, t1));
1045
1046 const BBoxT bbox2;
1047 EXPECT_TRUE(bbox2.empty());
1048 EXPECT_FALSE(ray.intersects(bbox2, t0, t1));
1049 }
1050
TEST_F(TestNanoVDB,RayBasic)1051 TEST_F(TestNanoVDB, RayBasic)
1052 {
1053 using RealT = float;
1054 using Vec3T = nanovdb::Vec3<RealT>;
1055 using CoordT = nanovdb::Coord;
1056 using CoordBBoxT = nanovdb::BBox<CoordT>;
1057 using BBoxT = nanovdb::BBox<Vec3T>;
1058 using RayT = nanovdb::Ray<RealT>;
1059
1060 // test bbox clip
1061 const Vec3T dir(1.0, 0.0, 0.0);
1062 const Vec3T eye(-1.0, 0.5, 0.5);
1063 RealT t0 = 0.0, t1 = 10000.0;
1064 RayT ray(eye, dir, t0, t1);
1065
1066 const CoordBBoxT bbox(CoordT(0, 0, 0), CoordT(0, 0, 0)); // only contains a single point (0,0,0)
1067 EXPECT_FALSE(bbox.empty());
1068 EXPECT_EQ(bbox.dim(), CoordT(1, 1, 1));
1069
1070 const BBoxT bbox2(CoordT(0, 0, 0), CoordT(0, 0, 0));
1071 EXPECT_EQ(bbox2, bbox.asReal<float>());
1072 EXPECT_FALSE(bbox2.empty());
1073 EXPECT_EQ(bbox2.dim(), Vec3T(1.0f, 1.0f, 1.0f));
1074 EXPECT_EQ(bbox2[0], Vec3T(0.0f, 0.0f, 0.0f));
1075 EXPECT_EQ(bbox2[1], Vec3T(1.0f, 1.0f, 1.0f));
1076
1077 EXPECT_TRUE(ray.clip(bbox)); // ERROR: how can a non-empty bbox have no intersections!?
1078 //EXPECT_TRUE( ray.clip(bbox.asReal<float>()));// correct!
1079
1080 // intersects the two faces of the box perpendicular to the x-axis!
1081 EXPECT_EQ(1.0f, ray.t0());
1082 EXPECT_EQ(2.0f, ray.t1());
1083 EXPECT_EQ(ray(1.0f), Vec3T(0.0f, 0.5f, 0.5f)); //lower y component of intersection
1084 EXPECT_EQ(ray(2.0f), Vec3T(1.0f, 0.5f, 0.5f)); //higher y component of intersection
1085 } // RayBasic
1086
TEST_F(TestNanoVDB,Ray)1087 TEST_F(TestNanoVDB, Ray)
1088 {
1089 using RealT = float;
1090 using Vec3T = nanovdb::Vec3<RealT>;
1091 using CoordT = nanovdb::Coord;
1092 using CoordBBoxT = nanovdb::BBox<CoordT>;
1093 using BBoxT = nanovdb::BBox<Vec3T>;
1094 using RayT = nanovdb::Ray<RealT>;
1095
1096 // test bbox clip
1097 const Vec3T dir(-1.0, 2.0, 3.0);
1098 const Vec3T eye(2.0, 1.0, 1.0);
1099 RealT t0 = 0.1, t1 = 12589.0;
1100 RayT ray(eye, dir, t0, t1);
1101
1102 // intersects the two faces of the box perpendicular to the y-axis!
1103 EXPECT_TRUE(ray.clip(CoordBBoxT(CoordT(0, 2, 2), CoordT(2, 4, 6))));
1104 //std::cerr << ray(0.5) << ", " << ray(2.0) << std::endl;
1105 EXPECT_EQ(0.5, ray.t0());
1106 EXPECT_EQ(2.0, ray.t1());
1107 EXPECT_EQ(ray(0.5)[1], 2); //lower y component of intersection
1108 EXPECT_EQ(ray(2.0)[1], 5); //higher y component of intersection
1109
1110 ray.reset(eye, dir, t0, t1);
1111 // intersects the lower edge anlong the z-axis of the box
1112 EXPECT_TRUE(ray.clip(BBoxT(Vec3T(1.5, 2.0, 2.0), Vec3T(4.5, 4.0, 6.0))));
1113 //std::cerr << ray(0.5) << ", " << ray(2.0) << std::endl;
1114 EXPECT_EQ(0.5, ray.t0());
1115 EXPECT_EQ(0.5, ray.t1());
1116 EXPECT_EQ(ray(0.5)[0], 1.5); //lower y component of intersection
1117 EXPECT_EQ(ray(0.5)[1], 2.0); //higher y component of intersection
1118
1119 ray.reset(eye, dir, t0, t1);
1120 // no intersections
1121 EXPECT_TRUE(!ray.clip(CoordBBoxT(CoordT(4, 2, 2), CoordT(6, 4, 6))));
1122 EXPECT_EQ(t0, ray.t0());
1123 EXPECT_EQ(t1, ray.t1());
1124 }
1125
TEST_F(TestNanoVDB,HDDA)1126 TEST_F(TestNanoVDB, HDDA)
1127 {
1128 using RealT = float;
1129 using CoordT = nanovdb::Coord;
1130 using RayT = nanovdb::Ray<RealT>;
1131 using Vec3T = RayT::Vec3T;
1132 using DDAT = nanovdb::HDDA<RayT, CoordT>;
1133
1134 { // basic test
1135 const RayT::Vec3T dir(1.0, 0.0, 0.0);
1136 const RayT::Vec3T eye(-1.0, 0.0, 0.0);
1137 const RayT ray(eye, dir);
1138 DDAT dda(ray, 1 << (3 + 4 + 5));
1139 EXPECT_EQ(nanovdb::Delta<RealT>::value(), dda.time());
1140 EXPECT_EQ(1.0, dda.next());
1141 dda.step();
1142 EXPECT_EQ(1.0, dda.time());
1143 EXPECT_EQ(4096 + 1.0, dda.next());
1144 }
1145 { // Check for the notorious +-0 issue!
1146
1147 const Vec3T dir1(1.0, 0.0, 0.0);
1148 const Vec3T eye1(2.0, 0.0, 0.0);
1149 const RayT ray1(eye1, dir1);
1150 DDAT dda1(ray1, 1 << 3);
1151 dda1.step();
1152
1153 const Vec3T dir2(1.0, -0.0, -0.0);
1154 const Vec3T eye2(2.0, 0.0, 0.0);
1155 const RayT ray2(eye2, dir2);
1156 DDAT dda2(ray2, 1 << 3);
1157 dda2.step();
1158
1159 const Vec3T dir3(1.0, -1e-9, -1e-9);
1160 const Vec3T eye3(2.0, 0.0, 0.0);
1161 const RayT ray3(eye3, dir3);
1162 DDAT dda3(ray3, 1 << 3);
1163 dda3.step();
1164
1165 const Vec3T dir4(1.0, -1e-9, -1e-9);
1166 const Vec3T eye4(2.0, 0.0, 0.0);
1167 const RayT ray4(eye3, dir4);
1168 DDAT dda4(ray4, 1 << 3);
1169 dda4.step();
1170
1171 EXPECT_EQ(dda1.time(), dda2.time());
1172 EXPECT_EQ(dda2.time(), dda3.time());
1173 EXPECT_EQ(dda3.time(), dda4.time());
1174 EXPECT_EQ(dda1.next(), dda2.next());
1175 EXPECT_EQ(dda2.next(), dda3.next());
1176 EXPECT_EQ(dda3.next(), dda4.next());
1177 }
1178 { // test voxel traversal along both directions of each axis
1179 const Vec3T eye(0, 0, 0);
1180 for (int s = -1; s <= 1; s += 2) {
1181 for (int a = 0; a < 3; ++a) {
1182 const int d[3] = {s * (a == 0), s * (a == 1), s * (a == 2)};
1183 const Vec3T dir(d[0], d[1], d[2]);
1184 RayT ray(eye, dir);
1185 DDAT dda(ray, 1 << 0);
1186 for (int i = 1; i <= 10; ++i) {
1187 EXPECT_TRUE(dda.step());
1188 EXPECT_EQ(i, dda.time());
1189 }
1190 }
1191 }
1192 }
1193 { // test Node traversal along both directions of each axis
1194 const Vec3T eye(0, 0, 0);
1195
1196 for (int s = -1; s <= 1; s += 2) {
1197 for (int a = 0; a < 3; ++a) {
1198 const int d[3] = {s * (a == 0), s * (a == 1), s * (a == 2)};
1199 const Vec3T dir(d[0], d[1], d[2]);
1200 RayT ray(eye, dir);
1201 DDAT dda(ray, 1 << 3);
1202 for (int i = 1; i <= 10; ++i) {
1203 EXPECT_TRUE(dda.step());
1204 EXPECT_EQ(8 * i, dda.time());
1205 }
1206 }
1207 }
1208 }
1209 { // test accelerated Node traversal along both directions of each axis
1210 const Vec3T eye(0, 0, 0);
1211
1212 for (int s = -1; s <= 1; s += 2) {
1213 for (int a = 0; a < 3; ++a) {
1214 const int d[3] = {s * (a == 0), s * (a == 1), s * (a == 2)};
1215 const Vec3T dir(2.0f * d[0], 2.0f * d[1], 2.0f * d[2]);
1216 RayT ray(eye, dir);
1217 DDAT dda(ray, 1 << 3);
1218 double next = 0;
1219 for (int i = 1; i <= 10; ++i) {
1220 EXPECT_TRUE(dda.step());
1221 EXPECT_EQ(4 * i, dda.time());
1222 if (i > 1) {
1223 EXPECT_EQ(dda.time(), next);
1224 }
1225 next = dda.next();
1226 }
1227 }
1228 }
1229 }
1230 #if 0
1231 if (!this->getEnvVar( "VDB_DATA_PATH" ).empty()) {// bug when ray-tracing dragon model
1232 const Vec3T eye(1563.350342,-390.161621,697.749023);
1233 const Vec3T dir(-0.963871,0.048393,-0.626651);
1234 RayT ray( eye, dir );
1235 auto srcGrid = this->getSrcGrid();
1236 auto handle = nanovdb::openToNanoVDB( *srcGrid );
1237 EXPECT_TRUE( handle );
1238 auto *grid = handle.grid<float>();
1239 EXPECT_TRUE( grid );
1240 EXPECT_TRUE( grid->isLevelSet() );
1241 //ray = ray.applyMapF( map );
1242 auto acc = grid->getAccessor();
1243 CoordT ijk;
1244 float v0;
1245 EXPECT_TRUE(nanovdb::ZeroCrossing( ray, acc, ijk, v0 ) );
1246 std::cerr << "hit with v0 =" << v0 << " background = " << grid->tree().background() << std::endl;
1247 }
1248 #endif
1249 } // HDDA
1250
TEST_F(TestNanoVDB,Mask)1251 TEST_F(TestNanoVDB, Mask)
1252 {
1253 using MaskT = nanovdb::Mask<3>;
1254 EXPECT_EQ(8u, MaskT::wordCount());
1255 EXPECT_EQ(512u, MaskT::bitCount());
1256 EXPECT_EQ(size_t(8 * 8), MaskT::memUsage());
1257
1258 MaskT mask;
1259 EXPECT_EQ(0U, mask.countOn());
1260 EXPECT_TRUE(mask.isOff());
1261 EXPECT_FALSE(mask.isOn());
1262 EXPECT_FALSE(mask.beginOn());
1263 for (uint32_t i = 0; i < MaskT::bitCount(); ++i)
1264 EXPECT_FALSE(mask.isOn(i));
1265
1266 mask.setOn(256);
1267 EXPECT_FALSE(mask.isOff());
1268 EXPECT_FALSE(mask.isOn());
1269 auto iter = mask.beginOn();
1270 EXPECT_TRUE(iter);
1271 EXPECT_EQ(256U, *iter);
1272 EXPECT_FALSE(++iter);
1273 for (uint32_t i = 0; i < MaskT::bitCount(); ++i) {
1274 if (i != 256)
1275 EXPECT_FALSE(mask.isOn(i));
1276 else
1277 EXPECT_TRUE(mask.isOn(i));
1278 }
1279
1280 mask.set(256, false);
1281 EXPECT_TRUE(mask.isOff());
1282 EXPECT_FALSE(mask.isOn());
1283 EXPECT_FALSE(mask.isOn(256));
1284
1285 mask.set(256, true);
1286 EXPECT_FALSE(mask.isOff());
1287 EXPECT_FALSE(mask.isOn());
1288 EXPECT_TRUE(mask.isOn(256));
1289 }
1290
TEST_F(TestNanoVDB,LeafNode)1291 TEST_F(TestNanoVDB, LeafNode)
1292 {
1293 using LeafT = nanovdb::LeafNode<float>;
1294 //EXPECT_FALSE(LeafT::IgnoreValues);
1295 EXPECT_EQ(8u, LeafT::dim());
1296 EXPECT_EQ(512u, LeafT::voxelCount());
1297 EXPECT_EQ(size_t(
1298 3 * 4 + // mBBoxMin
1299 4 * 1 + // mBBoxDif[3] + mFlags
1300 8 * 8 + // mValueMask,
1301 2 * 4 + // mMinimum, mMaximum
1302 2 * 4 + // mAverage, mVariance
1303 512 * 4 // mValues[512]
1304 ),
1305 sizeof(LeafT));
1306 // this particular value type happens to be exactly 32B aligned!
1307 EXPECT_EQ(nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(
1308 3 * 4 + // mBBoxMin
1309 4 * 1 + // mBBoxDif[3] + mFlags
1310 8 * 8 + // mValueMask,
1311 2 * 4 + // mMinimum, mMaximum
1312 2 * 4 + // mAverage, mVariance
1313 512 * 4 // mValues[512]
1314 ),
1315 sizeof(LeafT));
1316
1317 // allocate buffer
1318 std::unique_ptr<uint8_t[]> buffer(new uint8_t[LeafT::memUsage()]);
1319 std::memset(buffer.get(), 0, LeafT::memUsage());
1320 LeafT* leaf = reinterpret_cast<LeafT*>(buffer.get());
1321
1322 { // set members of the leaf node
1323 auto& data = *reinterpret_cast<LeafT::DataType*>(buffer.get());
1324 data.mValueMask.setOff();
1325 auto* values = data.mValues;
1326 for (int i = 0; i < 256; ++i)
1327 *values++ = 0.0f;
1328 for (uint32_t i = 256; i < LeafT::voxelCount(); ++i) {
1329 data.mValueMask.setOn(i);
1330 *values++ = 1.234f;
1331 }
1332 data.mMinimum = 0.0f;
1333 data.mMaximum = 1.234f;
1334 data.mFlags = uint8_t(2);// set bit # 1 on since leaf contains active values
1335 }
1336
1337 EXPECT_TRUE( leaf->isActive() );
1338
1339 { // compute BBox
1340 auto& data = *reinterpret_cast<LeafT::DataType*>(buffer.get());
1341 EXPECT_EQ(8u, data.mValueMask.wordCount());
1342
1343 nanovdb::CoordBBox bbox(nanovdb::Coord(-1), nanovdb::Coord(-1));
1344 uint64_t word = 0u;
1345 for (int i = 0; i < 8; ++i) {
1346 if (uint64_t w = data.mValueMask.getWord<uint64_t>(i)) {
1347 word |= w;
1348 if (bbox[0][0] == -1)
1349 bbox[0][0] = i;
1350 bbox[1][0] = i;
1351 }
1352 }
1353 EXPECT_TRUE(word != 0u);
1354 bbox[0][1] = nanovdb::FindLowestOn(word) >> 3;
1355 bbox[1][1] = nanovdb::FindHighestOn(word) >> 3;
1356
1357 const uint8_t* p = reinterpret_cast<const uint8_t*>(&word);
1358 uint32_t b = p[0] | p[1] | p[2] | p[3] | p[4] | p[5] | p[6] | p[7];
1359 EXPECT_TRUE(b != 0u);
1360 bbox[0][2] = nanovdb::FindLowestOn(b);
1361 bbox[1][2] = nanovdb::FindHighestOn(b);
1362 //std::cerr << bbox << std::endl;
1363 EXPECT_EQ(bbox[0], nanovdb::Coord(4, 0, 0));
1364 EXPECT_EQ(bbox[1], nanovdb::Coord(7, 7, 7));
1365 }
1366
1367 EXPECT_TRUE( leaf->isActive() );
1368
1369 // check values
1370 auto* ptr = reinterpret_cast<LeafT::DataType*>(buffer.get())->mValues;
1371 for (uint32_t i = 0; i < LeafT::voxelCount(); ++i) {
1372 if (i < 256) {
1373 EXPECT_FALSE(leaf->valueMask().isOn(i));
1374 EXPECT_EQ(0.0f, *ptr++);
1375 } else {
1376 EXPECT_TRUE(leaf->valueMask().isOn(i));
1377 EXPECT_EQ(1.234f, *ptr++);
1378 }
1379 }
1380 EXPECT_EQ(0.0f, leaf->minimum());
1381 EXPECT_EQ(1.234f, leaf->maximum());
1382
1383 { // test stand-alone implementation
1384 auto localBBox = [](const LeafT* leaf) {
1385 // static_assert(8u == LeafT::dim(), "Expected dim = 8");
1386 nanovdb::CoordBBox bbox(nanovdb::Coord(-1, 0, 0), nanovdb::Coord(-1, 7, 7));
1387 uint64_t word64 = 0u;
1388 for (int i = 0; i < 8; ++i) {
1389 if (uint64_t w = leaf->valueMask().getWord<uint64_t>(i)) {
1390 word64 |= w;
1391 if (bbox[0][0] == -1)
1392 bbox[0][0] = i; // only set once
1393 bbox[1][0] = i;
1394 }
1395 }
1396 assert(word64);
1397 if (word64 == ~uint64_t(0))
1398 return bbox; // early out of dense leaf
1399 bbox[0][1] = nanovdb::FindLowestOn(word64) >> 3;
1400 bbox[1][1] = nanovdb::FindHighestOn(word64) >> 3;
1401 const uint32_t *p = reinterpret_cast<const uint32_t*>(&word64), word32 = p[0] | p[1];
1402 const uint16_t *q = reinterpret_cast<const uint16_t*>(&word32), word16 = q[0] | q[1];
1403 const uint8_t * b = reinterpret_cast<const uint8_t*>(&word16), byte = b[0] | b[1];
1404 assert(byte);
1405 bbox[0][2] = nanovdb::FindLowestOn(uint32_t(byte));
1406 bbox[1][2] = nanovdb::FindHighestOn(uint32_t(byte));
1407 return bbox;
1408 }; // bboxOp
1409
1410 // test
1411 leaf->data()->mValueMask.setOff();
1412 const nanovdb::Coord min(1, 2, 3), max(5, 6, 7);
1413 leaf->setValue(min, 1.0f);
1414 leaf->setValue(max, 2.0f);
1415 EXPECT_EQ(1.0f, leaf->getValue(min));
1416 EXPECT_EQ(2.0f, leaf->getValue(max));
1417 const auto bbox = localBBox(leaf);
1418 //std::cerr << "bbox = " << bbox << std::endl;
1419 EXPECT_EQ(bbox[0], min);
1420 EXPECT_EQ(bbox[1], max);
1421 }
1422
1423 { // test LeafNode::updateBBox
1424 leaf->data()->mValueMask.setOff();
1425 const nanovdb::Coord min(1, 2, 3), max(5, 6, 7);
1426 leaf->setValue(min, 1.0f);
1427 leaf->setValue(max, 2.0f);
1428 EXPECT_EQ(1.0f, leaf->getValue(min));
1429 EXPECT_EQ(2.0f, leaf->getValue(max));
1430 leaf->updateBBox();
1431 const auto bbox = leaf->bbox();
1432 //std::cerr << "bbox = " << bbox << std::endl;
1433 EXPECT_EQ(bbox[0], min);
1434 EXPECT_EQ(bbox[1], max);
1435 }
1436
1437 } // LeafNode
1438
TEST_F(TestNanoVDB,LeafNodeBool)1439 TEST_F(TestNanoVDB, LeafNodeBool)
1440 {
1441 using LeafT = nanovdb::LeafNode<bool>;
1442 EXPECT_EQ(8u, LeafT::dim());
1443 EXPECT_EQ(512u, LeafT::voxelCount());
1444 EXPECT_EQ(nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(8 * 8 + // mValueMask
1445 8 * 8 + // mMask
1446 3 * 4 + // mBBoxMin
1447 4 * 1), // mBBoxDif[3] + mFlags
1448 sizeof(LeafT));
1449
1450 // allocate buffer
1451 std::unique_ptr<uint8_t[]> buffer(new uint8_t[LeafT::memUsage()]);
1452 LeafT* leaf = reinterpret_cast<LeafT*>(buffer.get());
1453
1454 { // set members of the leaf node
1455 auto& data = *reinterpret_cast<LeafT::DataType*>(buffer.get());
1456 data.mValueMask.setOff();
1457 data.mValues.setOn();
1458
1459 for (uint32_t i = 256; i < LeafT::voxelCount(); ++i) {
1460 data.mValueMask.setOn(i);
1461 data.mValues.setOff(i);
1462 }
1463 }
1464
1465 // check values
1466 for (uint32_t i = 0; i < LeafT::voxelCount(); ++i) {
1467 if (i < 256) {
1468 EXPECT_FALSE(leaf->valueMask().isOn(i));
1469 EXPECT_TRUE(leaf->getValue(i));
1470 } else {
1471 EXPECT_TRUE(leaf->valueMask().isOn(i));
1472 EXPECT_FALSE(leaf->getValue(i));
1473 }
1474 }
1475 EXPECT_EQ(false, leaf->minimum());
1476 EXPECT_EQ(false, leaf->maximum());
1477 } // LeafNodeBool
1478
TEST_F(TestNanoVDB,LeafNodeValueMask)1479 TEST_F(TestNanoVDB, LeafNodeValueMask)
1480 {
1481 using LeafT = nanovdb::LeafNode<nanovdb::ValueMask>;
1482 //EXPECT_TRUE(LeafT::IgnoreValues);
1483 EXPECT_EQ(8u, LeafT::dim());
1484 EXPECT_EQ(512u, LeafT::voxelCount());
1485 EXPECT_EQ(nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(8 * 8 + // mValueMask
1486 3 * 4 + // mBBoxMin
1487 4 * 1), // mBBoxDif[3] + mFlags
1488 sizeof(LeafT));
1489
1490 // allocate buffer
1491 std::unique_ptr<uint8_t[]> buffer(new uint8_t[LeafT::memUsage()]);
1492 LeafT* leaf = reinterpret_cast<LeafT*>(buffer.get());
1493
1494 { // set members of the leaf node
1495 auto& data = *reinterpret_cast<LeafT::DataType*>(buffer.get());
1496 data.mValueMask.setOff();
1497
1498 for (uint32_t i = 256; i < LeafT::voxelCount(); ++i) {
1499 data.mValueMask.setOn(i);
1500 }
1501 }
1502
1503 // check values
1504 for (uint32_t i = 0; i < LeafT::voxelCount(); ++i) {
1505 if (i < 256) {
1506 EXPECT_FALSE(leaf->valueMask().isOn(i));
1507 EXPECT_FALSE(leaf->getValue(i));
1508 } else {
1509 EXPECT_TRUE(leaf->valueMask().isOn(i));
1510 EXPECT_TRUE(leaf->getValue(i));
1511 }
1512 }
1513 EXPECT_EQ(false, leaf->minimum());
1514 EXPECT_EQ(false, leaf->maximum());
1515 } // LeafNodeValueMask
1516
TEST_F(TestNanoVDB,InternalNode)1517 TEST_F(TestNanoVDB, InternalNode)
1518 {
1519 using LeafT = nanovdb::LeafNode<float>;
1520 using NodeT = nanovdb::InternalNode<LeafT>;
1521 EXPECT_EQ(8 * 16u, NodeT::dim());
1522 // 2 x bit-masks tiles Vmin&Vmax offset + bbox + padding
1523 EXPECT_EQ(nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(size_t(2 * (16 * 16 * 16 / 64) * 8 + 16 * 16 * 16 * 8 + 2 * 4 + 4 + 2 * 3 * 4 + 4)), NodeT::memUsage());
1524
1525 // an empty InternalNode
1526 std::unique_ptr<uint8_t[]> buffer(new uint8_t[NodeT::memUsage()]);
1527 NodeT* node = reinterpret_cast<NodeT*>(buffer.get());
1528
1529 { // set members of the node
1530 auto& data = *reinterpret_cast<NodeT::DataType*>(buffer.get());
1531 data.mValueMask.setOff();
1532 data.mChildMask.setOff();
1533 auto* tiles = data.mTable;
1534 for (uint32_t i = 0; i < NodeT::SIZE / 2; ++i, ++tiles)
1535 tiles->value = 0.0f;
1536 for (uint32_t i = NodeT::SIZE / 2; i < NodeT::SIZE; ++i, ++tiles) {
1537 data.mValueMask.setOn(i);
1538 tiles->value = 1.234f;
1539 }
1540 data.mMinimum = 0.0f;
1541 data.mMaximum = 1.234f;
1542 }
1543
1544 // check values
1545 auto* ptr = reinterpret_cast<NodeT::DataType*>(buffer.get())->mTable;
1546 for (uint32_t i = 0; i < NodeT::SIZE; ++i, ++ptr) {
1547 EXPECT_FALSE(node->childMask().isOn(i));
1548 if (i < NodeT::SIZE / 2) {
1549 EXPECT_FALSE(node->valueMask().isOn(i));
1550 EXPECT_EQ(0.0f, ptr->value);
1551 } else {
1552 EXPECT_TRUE(node->valueMask().isOn(i));
1553 EXPECT_EQ(1.234f, ptr->value);
1554 }
1555 }
1556 EXPECT_EQ(0.0f, node->minimum());
1557 EXPECT_EQ(1.234f, node->maximum());
1558 } // InternalNode
1559
TEST_F(TestNanoVDB,InternalNodeValueMask)1560 TEST_F(TestNanoVDB, InternalNodeValueMask)
1561 {
1562 using LeafT = nanovdb::LeafNode<nanovdb::ValueMask>;
1563 using NodeT = nanovdb::InternalNode<LeafT>;
1564 //EXPECT_TRUE(LeafT::IgnoreValues);
1565 //EXPECT_TRUE(NodeT::IgnoreValues);
1566 EXPECT_EQ(8 * 16u, NodeT::dim());
1567
1568 /*
1569 BBox<CoordT> mBBox; // 24B. node bounding box.
1570 uint64_t mFlags; // 8B. node flags.
1571 MaskT mValueMask; // LOG2DIM(5): 4096B, LOG2DIM(4): 512B
1572 MaskT mChildMask; // LOG2DIM(5): 4096B, LOG2DIM(4): 512B
1573
1574 ValueT mMinimum;
1575 ValueT mMaximum;
1576 alignas(32) Tile mTable[1u << (3 * LOG2DIM)];
1577 */
1578 EXPECT_EQ(nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(size_t(24 + 4 + 4 + 512 + 512 + 4 + 4 + (16 * 16 * 16) * 8)), NodeT::memUsage());
1579
1580 // an empty InternalNode
1581 std::unique_ptr<uint8_t[]> buffer(new uint8_t[NodeT::memUsage()]);
1582 NodeT* node = reinterpret_cast<NodeT*>(buffer.get());
1583
1584 { // set members of the node
1585 auto& data = *reinterpret_cast<NodeT::DataType*>(buffer.get());
1586 data.mValueMask.setOff();
1587 data.mChildMask.setOff();
1588 auto* tiles = data.mTable;
1589 for (uint32_t i = 0; i < NodeT::SIZE / 2; ++i, ++tiles)
1590 tiles->value = 0u;
1591 for (uint32_t i = NodeT::SIZE / 2; i < NodeT::SIZE; ++i, ++tiles) {
1592 data.mValueMask.setOn(i);
1593 tiles->value = 1u;
1594 }
1595 data.mMinimum = 0u;
1596 data.mMaximum = 1u;
1597 }
1598
1599 // check values
1600 auto* ptr = reinterpret_cast<NodeT::DataType*>(buffer.get())->mTable;
1601 for (uint32_t i = 0; i < NodeT::SIZE; ++i, ++ptr) {
1602 EXPECT_FALSE(node->childMask().isOn(i));
1603 if (i < NodeT::SIZE / 2) {
1604 EXPECT_FALSE(node->valueMask().isOn(i));
1605 EXPECT_EQ(0u, ptr->value);
1606 } else {
1607 EXPECT_TRUE(node->valueMask().isOn(i));
1608 EXPECT_EQ(1u, ptr->value);
1609 }
1610 }
1611 EXPECT_EQ(0u, node->minimum());
1612 EXPECT_EQ(1u, node->maximum());
1613 } // InternalNodeValueMask
1614
TEST_F(TestNanoVDB,RootNode)1615 TEST_F(TestNanoVDB, RootNode)
1616 {
1617 using NodeT0 = nanovdb::LeafNode<float>;
1618 using NodeT1 = nanovdb::InternalNode<NodeT0>;
1619 using NodeT2 = nanovdb::InternalNode<NodeT1>;
1620 using NodeT3 = nanovdb::RootNode<NodeT2>;
1621 using CoordT = NodeT3::CoordType;
1622 using KeyT = NodeT3::DataType::KeyT;
1623
1624 EXPECT_EQ(nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(sizeof(nanovdb::CoordBBox) + sizeof(uint32_t) + (5 * sizeof(float))), NodeT3::memUsage(0));
1625
1626 // an empty RootNode
1627 std::unique_ptr<uint8_t[]> buffer(new uint8_t[NodeT3::memUsage(0)]);
1628 NodeT3* root = reinterpret_cast<NodeT3*>(buffer.get());
1629
1630 { // set members of the node
1631 auto& data = *reinterpret_cast<NodeT3::DataType*>(buffer.get());
1632 data.mBackground = data.mMinimum = data.mMaximum = 1.234f;
1633 data.mTableSize = 0;
1634 }
1635
1636 EXPECT_EQ(1.234f, root->background());
1637 EXPECT_EQ(1.234f, root->minimum());
1638 EXPECT_EQ(1.234f, root->maximum());
1639 EXPECT_EQ(0u, root->tileCount());
1640 EXPECT_EQ(nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(sizeof(nanovdb::CoordBBox) + sizeof(uint32_t) + (5 * sizeof(float))), root->memUsage()); // background, min, max, tileCount + bbox
1641 EXPECT_EQ(1.234f, root->getValue(CoordT(1, 2, 3)));
1642
1643 { // test RootData::CoordToKey and RotData::KetToCoord
1644 const int dim = NodeT2::DIM;// dimension of the root's child nodes
1645 EXPECT_EQ(4096, dim);
1646 auto coordToKey = [](int i, int j, int k) { return NodeT3::DataType::CoordToKey(CoordT(i, j, k)); };
1647 auto keyToCoord = [](KeyT key) { return NodeT3::DataType::KeyToCoord(key); };
1648 EXPECT_TRUE(coordToKey(0, 0, 0) < coordToKey(dim, 0, 0));
1649 EXPECT_TRUE(coordToKey(0, 0, 0) < coordToKey(0, dim, 0));
1650 EXPECT_TRUE(coordToKey(0, 0, 0) < coordToKey(0, 0, dim));
1651 EXPECT_TRUE(coordToKey(0, 0, 0) == coordToKey(dim-1, dim-1, dim-1));
1652 #ifdef USE_SINGLE_ROOT_KEY
1653 EXPECT_TRUE((std::is_same<uint64_t, KeyT>::value));
1654
1655 EXPECT_EQ(uint64_t(0), coordToKey(0, 0, 0));
1656 EXPECT_EQ(uint64_t(0), coordToKey(dim-1, dim-1, dim-1));
1657
1658 EXPECT_EQ(uint64_t(1), coordToKey(0, 0, dim));
1659 EXPECT_EQ(uint64_t(1), coordToKey(dim-1, dim-1, dim));
1660
1661 EXPECT_EQ(uint64_t(1)<<21, coordToKey(0, dim, 0));
1662 EXPECT_EQ(uint64_t(1)<<21, coordToKey(dim-1, dim, dim-1));
1663
1664 EXPECT_EQ(uint64_t(1)<<42, coordToKey(dim, 0, 0));
1665 EXPECT_EQ(uint64_t(1)<<42, coordToKey(dim, dim-1, dim-1));
1666
1667 EXPECT_EQ(CoordT(0,0,0), keyToCoord(0u));
1668 //std::cerr << "keyToCoord(1u) = " << keyToCoord(1u) << std::endl;
1669 EXPECT_EQ(CoordT(0, 0, dim), keyToCoord(1u));
1670 EXPECT_EQ(CoordT(0, dim, 0), keyToCoord(uint64_t(1)<<21));
1671 EXPECT_EQ(CoordT(dim, 0, 0), keyToCoord(uint64_t(1)<<42));
1672 #endif
1673 }
1674 } // RootNode
1675
TEST_F(TestNanoVDB,Offsets)1676 TEST_F(TestNanoVDB, Offsets)
1677 {
1678 { // check GridData memory alignment, total 672 bytes
1679 /*
1680 static const int MaxNameSize = 256;// due to NULL termination the maximum length is one less
1681 uint64_t mMagic; // 8B magic to validate it is valid grid data.
1682 uint64_t mChecksum; // 8B. Checksum of grid buffer.
1683 Version mVersion;// 4B major, minor, and patch version numbers
1684 uint32_t mFlags; // 4B. flags for grid.
1685 uint32_t mGridIndex;// 4B. Index of this grid in the buffer
1686 uint32_t mGridCount; // 4B. Total number of grids in the buffer
1687 uint64_t mGridSize; // 8B. byte count of this entire grid occupied in the buffer.
1688 char mGridName[MaxNameSize]; // 256B
1689 Map mMap; // 264B. affine transformation between index and world space in both single and double precision
1690 BBox<Vec3R> mWorldBBox; // 48B. floating-point AABB of active values in WORLD SPACE (2 x 3 doubles)
1691 Vec3R mVoxelSize; // 24B. size of a voxel in world units
1692 GridClass mGridClass; // 4B.
1693 GridType mGridType; // 4B.
1694 int64_t mBlindMetadataOffset; // 8B. offset of GridBlindMetaData structures that follow this grid.
1695 uint32_t mBlindMetadataCount; // 4B. count of GridBlindMetaData structures that follow this grid.
1696 */
1697 int offset = 0;
1698 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mMagic), offset);
1699 offset += 8;
1700 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mChecksum), offset);
1701 offset += 8;
1702 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mVersion), offset);
1703 offset += 4;
1704 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mFlags), offset);
1705 offset += 4;
1706 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mGridIndex), offset);
1707 offset += 4;
1708 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mGridCount), offset);
1709 offset += 4;
1710 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mGridSize), offset);
1711 offset += 8;
1712 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mGridName), offset);
1713 offset += 256;
1714 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mMap), offset);
1715 offset += 264;
1716 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mWorldBBox), offset);
1717 offset += 48;
1718 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mVoxelSize), offset);
1719 offset += 24;
1720 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mGridClass), offset);
1721 offset += 4;
1722 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mGridType), offset);
1723 offset += 4;
1724 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mBlindMetadataOffset), offset);
1725 offset += 8;
1726 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mBlindMetadataCount), offset);
1727 offset += 4;
1728 offset = nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(offset);
1729 //std::cerr << "GridData: Offset = " << offset << std::endl;
1730 EXPECT_EQ(offset, (int)sizeof(nanovdb::GridData));
1731 }
1732 {// check TreeData memory alignment, total 64 bytes
1733 /*
1734 uint64_t mNodeOffset[4];//32B, byte offset from this tree to first leaf, lower, upper and root node
1735 uint32_t mNodeCount[3];// 12B, total number of nodes of type: leaf, lower internal, upper internal
1736 uint32_t mTileCount[3];// 12B, total number of tiles of type: leaf, lower internal, upper internal (node, only active tiles!)
1737 uint64_t mVoxelCount;// 8B, total number of active voxels in the root and all its child nodes.
1738 */
1739 int offset = 0;
1740 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::TreeData<>, mNodeOffset), offset);
1741 offset += 4*8;
1742 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::TreeData<>, mNodeCount), offset);
1743 offset += 12;
1744 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::TreeData<>, mTileCount), offset);
1745 offset += 12;
1746 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::TreeData<>, mVoxelCount), offset);
1747 offset += 8;
1748 offset = nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(offset);
1749 //std::cerr << "TreeData: Offset = " << offset << std::endl;
1750 EXPECT_EQ(offset, (int)sizeof(nanovdb::TreeData<>));
1751 }
1752 }
1753
1754 template <typename ValueT>
1755 void checkLeaf(int &offset);
1756
TYPED_TEST(TestOffsets,NanoVDB)1757 TYPED_TEST(TestOffsets, NanoVDB)
1758 {
1759 using ValueType = typename nanovdb::BuildToValueMap<TypeParam>::Type;
1760 using T = typename nanovdb::TensorTraits<ValueType>::ElementType;
1761 using StatsT = typename nanovdb::FloatTraits<ValueType>::FloatType;
1762 static const size_t ALIGNMENT = sizeof(T) > sizeof(StatsT) ? sizeof(T) : sizeof(StatsT);
1763 //std::cerr << "Alignment = " << ALIGNMENT << " sizeof(ValueType) = " << sizeof(ValueType) << std::endl;
1764 {// check memory layout of RootData
1765 using DataT = typename nanovdb::NanoRoot<ValueType>::DataType;
1766 bool test = nanovdb::is_same<StatsT, typename DataT::StatsT>::value;
1767 EXPECT_TRUE(test);
1768 int offsets[] = {
1769 NANOVDB_OFFSETOF(DataT, mBBox),
1770 NANOVDB_OFFSETOF(DataT, mTableSize),
1771 NANOVDB_OFFSETOF(DataT, mBackground),
1772 NANOVDB_OFFSETOF(DataT, mMinimum),
1773 NANOVDB_OFFSETOF(DataT, mMaximum),
1774 NANOVDB_OFFSETOF(DataT, mAverage),
1775 NANOVDB_OFFSETOF(DataT, mStdDevi)
1776 };
1777 //for (int i : offsets) std::cout << i << " ";
1778 const int *p = offsets;
1779 int offset = 0;// first data member
1780 EXPECT_EQ(*p++, offset);// mBBox
1781 offset += 24;// 2 * 3 * 4 bytes = 24 bytes
1782 EXPECT_EQ(*p++, offset);// mTableSize
1783 offset += sizeof(uint32_t);
1784 offset = nanovdb::AlignUp<ALIGNMENT>(offset);
1785 EXPECT_EQ(*p++, offset);// mBackground
1786 offset += sizeof(ValueType);
1787 EXPECT_EQ(*p++, offset);// mMinimum
1788 offset += sizeof(ValueType);
1789 EXPECT_EQ(*p++, offset);// mMaximum
1790 offset += sizeof(ValueType);
1791 offset = nanovdb::AlignUp<ALIGNMENT>(offset);
1792 EXPECT_EQ(*p++, offset);// mAverage
1793 offset += sizeof(StatsT);
1794 offset = nanovdb::AlignUp<ALIGNMENT>(offset);
1795 EXPECT_EQ(*p++, offset);// mStdDevi
1796 offset += sizeof(StatsT);
1797 offset = nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(offset);
1798 EXPECT_EQ(offset, (int)sizeof(DataT));// size of RootData
1799 }
1800 {// check memory layout of upper internal nodes
1801 using DataT = typename nanovdb::NanoUpper<ValueType>::DataType;
1802 bool test = nanovdb::is_same<StatsT, typename DataT::StatsT>::value;
1803 EXPECT_TRUE(test);
1804 int offsets[] = {
1805 NANOVDB_OFFSETOF(DataT, mBBox),
1806 NANOVDB_OFFSETOF(DataT, mFlags),
1807 NANOVDB_OFFSETOF(DataT, mValueMask),
1808 NANOVDB_OFFSETOF(DataT, mChildMask),
1809 NANOVDB_OFFSETOF(DataT, mMinimum),
1810 NANOVDB_OFFSETOF(DataT, mMaximum),
1811 NANOVDB_OFFSETOF(DataT, mAverage),
1812 NANOVDB_OFFSETOF(DataT, mStdDevi),
1813 NANOVDB_OFFSETOF(DataT, mTable),
1814 };
1815 //for (int i : offsets) std::cout << i << " ";
1816 int offset = 0, *p = offsets;
1817 EXPECT_EQ(*p++, offset);
1818 offset += 24;
1819 EXPECT_EQ(*p++, offset);
1820 offset += 8;
1821 EXPECT_EQ(*p++, offset);
1822 offset += 4096;// = 32*32*32/8
1823 EXPECT_EQ(*p++, offset);
1824 offset += 4096;// = 32*32*32/8
1825 EXPECT_EQ(*p++, offset);
1826 offset += sizeof(ValueType);
1827 EXPECT_EQ(*p++, offset);
1828 offset += sizeof(ValueType);
1829 offset = nanovdb::AlignUp<ALIGNMENT>(offset);
1830 EXPECT_EQ(*p++, offset);
1831 offset += sizeof(StatsT);
1832 offset = nanovdb::AlignUp<ALIGNMENT>(offset);
1833 EXPECT_EQ(*p++, offset);
1834 offset += sizeof(StatsT);
1835 offset = nanovdb::AlignUp<32>(offset);
1836 EXPECT_EQ(*p++, offset);
1837 const size_t tile_size = nanovdb::AlignUp<8>(sizeof(ValueType));
1838 EXPECT_EQ(sizeof(typename DataT::Tile), tile_size);
1839 offset += (32*32*32)*tile_size;
1840 offset = nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(offset);
1841 EXPECT_EQ(sizeof(DataT), (size_t)offset);
1842 }
1843 {// check memory lower of upper internal nodes
1844 using DataT = typename nanovdb::NanoLower<ValueType>::DataType;
1845 bool test = nanovdb::is_same<StatsT, typename DataT::StatsT>::value;
1846 EXPECT_TRUE(test);
1847 int offsets[] = {
1848 NANOVDB_OFFSETOF(DataT, mBBox),
1849 NANOVDB_OFFSETOF(DataT, mFlags),
1850 NANOVDB_OFFSETOF(DataT, mValueMask),
1851 NANOVDB_OFFSETOF(DataT, mChildMask),
1852 NANOVDB_OFFSETOF(DataT, mMinimum),
1853 NANOVDB_OFFSETOF(DataT, mMaximum),
1854 NANOVDB_OFFSETOF(DataT, mAverage),
1855 NANOVDB_OFFSETOF(DataT, mStdDevi),
1856 NANOVDB_OFFSETOF(DataT, mTable),
1857 };
1858 //for (int i : offsets) std::cout << i << " ";
1859 int offset = 0, *p = offsets;
1860 EXPECT_EQ(*p++, offset);
1861 offset += 24;
1862 EXPECT_EQ(*p++, offset);
1863 offset += 8;
1864 EXPECT_EQ(*p++, offset);
1865 offset += 512;// = 16*16*16/8
1866 EXPECT_EQ(*p++, offset);
1867 offset += 512;// = 16*16*16/8
1868 EXPECT_EQ(*p++, offset);
1869 offset += sizeof(ValueType);
1870 EXPECT_EQ(*p++, offset);
1871 offset += sizeof(ValueType);
1872 offset = nanovdb::AlignUp<ALIGNMENT>(offset);
1873 EXPECT_EQ(*p++, offset);
1874 offset += sizeof(StatsT);
1875 offset = nanovdb::AlignUp<ALIGNMENT>(offset);
1876 EXPECT_EQ(*p++, offset);
1877 offset += sizeof(StatsT);
1878 offset = nanovdb::AlignUp<32>(offset);
1879 EXPECT_EQ(*p++, offset);
1880 const size_t tile_size = nanovdb::AlignUp<8>(sizeof(ValueType));
1881 EXPECT_EQ(sizeof(typename DataT::Tile), tile_size);
1882 offset += (16*16*16)*tile_size;
1883 offset = nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(offset);
1884 EXPECT_EQ(sizeof(DataT), (size_t)offset);
1885 }
1886 {// check memory of leaf nodes
1887 using DataT = typename nanovdb::LeafNode<ValueType>::DataType;
1888 bool test = nanovdb::is_same<StatsT, typename DataT::FloatType>::value;
1889 EXPECT_TRUE(test);
1890 int offsets[] = {
1891 NANOVDB_OFFSETOF(DataT, mBBoxMin),
1892 NANOVDB_OFFSETOF(DataT, mBBoxDif),
1893 NANOVDB_OFFSETOF(DataT, mFlags),
1894 NANOVDB_OFFSETOF(DataT, mValueMask),
1895 };
1896 //for (int i : offsets) std::cout << i << " ";
1897 int offset = 0, *p = offsets;
1898 EXPECT_EQ(*p++, offset);
1899 offset += 12;
1900 EXPECT_EQ(*p++, offset);
1901 offset += 3;
1902 EXPECT_EQ(*p++, offset);
1903 offset += 1;
1904 EXPECT_EQ(*p++, offset);
1905 offset += 64;// = 8*8*8/8
1906 checkLeaf<ValueType>(offset);
1907 offset = nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(offset);
1908 EXPECT_EQ(sizeof(DataT), (size_t)offset);
1909 }
1910 }// TestOffsets NanoVDB
1911
1912 template<typename ValueType>
checkLeaf(int & offset)1913 void checkLeaf(int &offset)
1914 {
1915 using DataT = typename nanovdb::LeafNode<ValueType>::DataType;
1916 using T = typename nanovdb::TensorTraits<ValueType>::ElementType;
1917 using StatsT = typename nanovdb::FloatTraits<ValueType>::FloatType;
1918 static const size_t ALIGNMENT = sizeof(T) > sizeof(StatsT) ? sizeof(T) : sizeof(StatsT);
1919 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mMinimum), offset);
1920 offset += sizeof(ValueType);
1921 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mMaximum), offset);
1922 offset += sizeof(ValueType);
1923 offset = nanovdb::AlignUp<ALIGNMENT>(offset);
1924 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mAverage), offset);
1925 offset += sizeof(StatsT);
1926 offset = nanovdb::AlignUp<ALIGNMENT>(offset);
1927 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mStdDevi), offset);
1928 offset += sizeof(StatsT);
1929 offset = nanovdb::AlignUp<32>(offset);
1930 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mValues), offset);
1931 offset += (8*8*8)*sizeof(ValueType);
1932 }
1933
1934 template<>
checkLeaf(int & offset)1935 void checkLeaf<bool>(int &offset)
1936 {
1937 using DataT = typename nanovdb::LeafNode<bool>::DataType;
1938 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mValues), offset);
1939 offset += 64;// = 8*8*8/8
1940 }
1941
1942 template<>
checkLeaf(int & offset)1943 void checkLeaf<nanovdb::Fp4>(int &offset)
1944 {
1945 using DataT = typename nanovdb::LeafNode<nanovdb::Fp4>::DataType;
1946 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mMinimum), offset);
1947 offset += sizeof(float);
1948 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mQuantum), offset);
1949 offset += sizeof(float);
1950 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mMin), offset);
1951 offset += sizeof(uint16_t);
1952 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mMax), offset);
1953 offset += sizeof(uint16_t);
1954 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mAvg), offset);
1955 offset += sizeof(uint16_t);
1956 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mDev), offset);
1957 offset += sizeof(uint16_t);
1958 offset = nanovdb::AlignUp<32>(offset);
1959 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mCode), offset);
1960 offset += 256*sizeof(uint8_t);
1961 }
1962
1963 template<>
checkLeaf(int & offset)1964 void checkLeaf<nanovdb::Fp8>(int &offset)
1965 {
1966 using DataT = typename nanovdb::LeafNode<nanovdb::Fp8>::DataType;
1967 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mMinimum), offset);
1968 offset += sizeof(float);
1969 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mQuantum), offset);
1970 offset += sizeof(float);
1971 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mMin), offset);
1972 offset += sizeof(uint16_t);
1973 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mMax), offset);
1974 offset += sizeof(uint16_t);
1975 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mAvg), offset);
1976 offset += sizeof(uint16_t);
1977 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mDev), offset);
1978 offset += sizeof(uint16_t);
1979 offset = nanovdb::AlignUp<32>(offset);
1980 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mCode), offset);
1981 offset += 512*sizeof(uint8_t);
1982 }
1983
1984 template<>
checkLeaf(int & offset)1985 void checkLeaf<nanovdb::Fp16>(int &offset)
1986 {
1987 using DataT = typename nanovdb::LeafNode<nanovdb::Fp16>::DataType;
1988 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mMinimum), offset);
1989 offset += sizeof(float);
1990 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mQuantum), offset);
1991 offset += sizeof(float);
1992 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mMin), offset);
1993 offset += sizeof(uint16_t);
1994 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mMax), offset);
1995 offset += sizeof(uint16_t);
1996 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mAvg), offset);
1997 offset += sizeof(uint16_t);
1998 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mDev), offset);
1999 offset += sizeof(uint16_t);
2000 offset = nanovdb::AlignUp<32>(offset);
2001 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mCode), offset);
2002 offset += 512*sizeof(uint16_t);
2003 }
2004
2005 template<>
checkLeaf(int & offset)2006 void checkLeaf<nanovdb::FpN>(int &offset)
2007 {
2008 using DataT = typename nanovdb::LeafNode<nanovdb::FpN>::DataType;
2009 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mMinimum), offset);
2010 offset += sizeof(float);
2011 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mQuantum), offset);
2012 offset += sizeof(float);
2013 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mMin), offset);
2014 offset += sizeof(uint16_t);
2015 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mMax), offset);
2016 offset += sizeof(uint16_t);
2017 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mAvg), offset);
2018 offset += sizeof(uint16_t);
2019 EXPECT_EQ(NANOVDB_OFFSETOF(DataT, mDev), offset);
2020 offset += sizeof(uint16_t);
2021 offset = nanovdb::AlignUp<32>(offset);
2022 }
2023
2024 template<>
checkLeaf(int &)2025 void checkLeaf<nanovdb::ValueMask>(int &) {}
2026
TEST_F(TestNanoVDB,BasicGrid)2027 TEST_F(TestNanoVDB, BasicGrid)
2028 {
2029 using LeafT = nanovdb::LeafNode<float>;
2030 using NodeT1 = nanovdb::InternalNode<LeafT>;
2031 using NodeT2 = nanovdb::InternalNode<NodeT1>;
2032 using RootT = nanovdb::RootNode<NodeT2>;
2033 using TreeT = nanovdb::Tree<RootT>;
2034 using GridT = nanovdb::Grid<TreeT>;
2035 using CoordT = LeafT::CoordType;
2036
2037 const std::string name("test name");
2038 {
2039 // This is just for visual inspection
2040 /*
2041 this->printType<GridT>("Grid");
2042 this->printType<TreeT>("Tree");
2043 this->printType<NodeT2>("Upper InternalNode");
2044 this->printType<NodeT1>("Lower InternalNode");
2045 this->printType<LeafT>("Leaf");
2046 Old: W/O mAverage and mVariance
2047 Size of Grid: 672 bytes which is 32 byte aligned
2048 Size of Tree: 64 bytes which is 32 byte aligned
2049 Size of Upper InternalNode: 139328 bytes which is 32 byte aligned
2050 Size of Lower InternalNode: 17472 bytes which is 32 byte aligned
2051 Size of Leaf: 2144 bytes which is 32 byte aligned
2052
2053 New: WITH mAverage and mVariance
2054 Size of Grid: 672 bytes which is 32 byte aligned
2055 Size of Tree: 64 bytes which is 32 byte aligned
2056 Size of Upper InternalNode: 139328 bytes which is 32 byte aligned
2057 Size of Lower InternalNode: 17472 bytes which is 32 byte aligned
2058 Size of Leaf: 2144 bytes which is 32 byte aligned
2059 */
2060 }
2061
2062 EXPECT_EQ(sizeof(GridT), nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(8 + 8 + 4 + 4 + 8 + nanovdb::GridData::MaxNameSize + 48 + sizeof(nanovdb::Map) + 24 + 4 + 4 + 8 + 4));
2063 EXPECT_EQ(sizeof(TreeT), nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(4*8 + 3*4 + 3*4 + 8));
2064 EXPECT_EQ(sizeof(TreeT), size_t(4*8 + 3*4 + 3*4 + 8));// should already be 32 byte aligned
2065
2066 size_t bytes[6] = {GridT::memUsage(), TreeT::memUsage(), RootT::memUsage(1), NodeT2::memUsage(), NodeT1::memUsage(), LeafT::memUsage()};
2067 for (int i = 1; i < 6; ++i)
2068 bytes[i] += bytes[i - 1]; // Byte offsets to: tree, root, internal nodes, leafs, total
2069 std::unique_ptr<uint8_t[]> buffer(new uint8_t[bytes[5]]);
2070
2071 // init leaf
2072 LeafT* leaf = reinterpret_cast<LeafT*>(buffer.get() + bytes[4]);
2073 { // set members of the leaf node
2074 auto* data = leaf->data();
2075 data->mValueMask.setOff();
2076 auto* voxels = data->mValues;
2077 for (uint32_t i = 0; i < LeafT::voxelCount() / 2; ++i)
2078 *voxels++ = 0.0f;
2079 for (uint32_t i = LeafT::voxelCount() / 2; i < LeafT::voxelCount(); ++i) {
2080 data->mValueMask.setOn(i);
2081 *voxels++ = 1.0f;
2082 }
2083 data->mMinimum = 1.0f;
2084 data->mMaximum = 1.0f;
2085 }
2086
2087 // lower internal node
2088 NodeT1* node1 = reinterpret_cast<NodeT1*>(buffer.get() + bytes[3]);
2089 { // set members of the internal node
2090 auto *data = node1->data();
2091 data->mValueMask.setOff();
2092 data->mChildMask.setOff();
2093 data->mChildMask.setOn(0);
2094 data->setChild(0, leaf);
2095 for (uint32_t i = 1; i < NodeT1::SIZE / 2; ++i)
2096 data->mTable[i].value = 0.0f;
2097 for (uint32_t i = NodeT1::SIZE / 2; i < NodeT1::SIZE; ++i) {
2098 data->mValueMask.setOn(i);
2099 data->mTable[i].value = 2.0f;
2100 }
2101 data->mMinimum = 1.0f;
2102 data->mMaximum = 2.0f;
2103 EXPECT_EQ(leaf, data->getChild(0));
2104 }
2105
2106 // upper internal node
2107 NodeT2* node2 = reinterpret_cast<NodeT2*>(buffer.get() + bytes[2]);
2108 { // set members of the internal node
2109 auto *data = node2->data();
2110 data->mValueMask.setOff();
2111 data->mChildMask.setOff();
2112 data->mChildMask.setOn(0);
2113 data->setChild(0, node1);
2114 for (uint32_t i = 1; i < NodeT2::SIZE / 2; ++i)
2115 data->mTable[i].value = 0.0f;
2116 for (uint32_t i = NodeT2::SIZE / 2; i < NodeT2::SIZE; ++i) {
2117 data->mValueMask.setOn(i);
2118 data->mTable[i].value = 3.0f;
2119 }
2120 data->mMinimum = 1.0f;
2121 data->mMaximum = 3.0f;
2122 EXPECT_EQ(node1, data->getChild(0));
2123 }
2124
2125 // init root
2126 RootT* root = reinterpret_cast<RootT*>(buffer.get() + bytes[1]);
2127 { // set members of the root node
2128 auto* data = root->data();
2129 data->mBackground = 0.0f;
2130 data->mMinimum = 1.0f;
2131 data->mMaximum = 3.0f;
2132 data->mTableSize = 1;
2133 data->tile(0)->setChild(RootT::CoordType(0), node2, data);
2134 }
2135
2136 // init tree
2137 TreeT* tree = reinterpret_cast<TreeT*>(buffer.get() + bytes[0]);
2138 {
2139 auto* data = tree->data();
2140 data->setRoot(root);
2141 data->setFirstNode(node2);
2142 data->setFirstNode(node1);
2143 data->setFirstNode(leaf);
2144 data->mNodeCount[0] = data->mNodeCount[1] = data->mNodeCount[2] = 1;
2145 }
2146
2147 GridT* grid = reinterpret_cast<GridT*>(buffer.get());
2148 { // init Grid
2149 auto* data = grid->data();
2150 {
2151 const double dx = 2.0, Tx = 0.0, Ty = 0.0, Tz = 0.0;
2152 const double mat[4][4] = {
2153 {dx, 0.0, 0.0, 0.0}, // row 0
2154 {0.0, dx, 0.0, 0.0}, // row 1
2155 {0.0, 0.0, dx, 0.0}, // row 2
2156 {Tx, Ty, Tz, 1.0}, // row 3
2157 };
2158 const double invMat[4][4] = {
2159 {1 / dx, 0.0, 0.0, 0.0}, // row 0
2160 {0.0, 1 / dx, 0.0, 0.0}, // row 1
2161 {0.0, 0.0, 1 / dx, 0.0}, // row 2
2162 {-Tx, -Ty, -Tz, 1.0}, // row 3
2163 };
2164 data->setFlagsOff();
2165 data->setMinMaxOn();
2166 data->mGridIndex = 0;
2167 data->mGridCount = 1;
2168 data->mBlindMetadataOffset = 0;
2169 data->mBlindMetadataCount = 0;
2170 data->mVoxelSize = nanovdb::Vec3R(dx);
2171 data->mMap.set(mat, invMat, 1.0);
2172 data->mGridClass = nanovdb::GridClass::Unknown;
2173 data->mGridType = nanovdb::GridType::Float;
2174 data->mMagic = NANOVDB_MAGIC_NUMBER;
2175 data->mVersion = nanovdb::Version();
2176 memcpy(data->mGridName, name.c_str(), name.size() + 1);
2177 }
2178
2179 EXPECT_EQ(tree, &grid->tree());
2180 const nanovdb::Vec3R p1(1.0, 2.0, 3.0);
2181 const auto p2 = grid->worldToIndex(p1);
2182 EXPECT_EQ(nanovdb::Vec3R(0.5, 1.0, 1.5), p2);
2183 const auto p3 = grid->indexToWorld(p2);
2184 EXPECT_EQ(p1, p3);
2185 {
2186 const double dx = 2.0, Tx = p1[0], Ty = p1[1], Tz = p1[2];
2187 const double mat[4][4] = {
2188 {dx, 0.0, 0.0, 0.0}, // row 0
2189 {0.0, dx, 0.0, 0.0}, // row 1
2190 {0.0, 0.0, dx, 0.0}, // row 2
2191 {Tx, Ty, Tz, 1.0}, // row 3
2192 };
2193 const double invMat[4][4] = {
2194 {1 / dx, 0.0, 0.0, 0.0}, // row 0
2195 {0.0, 1 / dx, 0.0, 0.0}, // row 1
2196 {0.0, 0.0, 1 / dx, 0.0}, // row 2
2197 {-1 / Tx, -1 / Ty, -1 / Tz, 1.0}, // row 3
2198 };
2199 data->mVoxelSize = nanovdb::Vec3R(dx);
2200 data->mMap.set(mat, invMat, 1.0);
2201 }
2202
2203
2204 // Start actual tests
2205
2206 auto const p4 = grid->worldToIndex(p3);
2207 EXPECT_EQ(nanovdb::Vec3R(0.0, 0.0, 0.0), p4);
2208 const auto p5 = grid->indexToWorld(p4);
2209 EXPECT_EQ(p1, p5);
2210 }
2211
2212 { // check leaf node
2213 auto* ptr = reinterpret_cast<LeafT::DataType*>(buffer.get() + bytes[4])->mValues;
2214 for (uint32_t i = 0; i < LeafT::voxelCount(); ++i) {
2215 if (i < 256) {
2216 EXPECT_FALSE(leaf->valueMask().isOn(i));
2217 EXPECT_EQ(0.0f, *ptr++);
2218 } else {
2219 EXPECT_TRUE(leaf->valueMask().isOn(i));
2220 EXPECT_EQ(1.0f, *ptr++);
2221 }
2222 }
2223 EXPECT_EQ(1.0f, leaf->minimum());
2224 EXPECT_EQ(1.0f, leaf->maximum());
2225 EXPECT_EQ(0.0f, leaf->getValue(CoordT(0)));
2226 EXPECT_EQ(1.0f, leaf->getValue(CoordT(8-1)));
2227 }
2228
2229 { // check lower internal node
2230 auto& data = *reinterpret_cast<NodeT1::DataType*>(buffer.get() + bytes[3]);
2231 EXPECT_TRUE(node1->childMask().isOn(0));
2232 for (uint32_t i = 1; i < NodeT1::SIZE; ++i) {
2233 EXPECT_FALSE(node1->childMask().isOn(i));
2234 if (i < NodeT1::SIZE / 2) {
2235 EXPECT_FALSE(node1->valueMask().isOn(i));
2236 EXPECT_EQ(0.0f, data.mTable[i].value);
2237 } else {
2238 EXPECT_TRUE(node1->valueMask().isOn(i));
2239 EXPECT_EQ(2.0f, data.mTable[i].value);
2240 }
2241 }
2242 EXPECT_EQ(1.0f, node1->minimum());
2243 EXPECT_EQ(2.0f, node1->maximum());
2244 EXPECT_EQ(0.0f, node1->getValue(CoordT(0)));
2245 EXPECT_EQ(1.0f, node1->getValue(CoordT(8-1)));
2246 EXPECT_EQ(2.0f, node1->getValue(CoordT(8*16-1)));
2247 }
2248 { // check upper internal node
2249 auto& data = *reinterpret_cast<NodeT2::DataType*>(buffer.get() + bytes[2]);
2250 EXPECT_TRUE(node2->childMask().isOn(0));
2251 for (uint32_t i = 1; i < NodeT2::SIZE; ++i) {
2252 EXPECT_FALSE(node2->childMask().isOn(i));
2253 if (i < NodeT2::SIZE / 2) {
2254 EXPECT_FALSE(node2->valueMask().isOn(i));
2255 EXPECT_EQ(0.0f, data.mTable[i].value);
2256 } else {
2257 EXPECT_TRUE(node2->valueMask().isOn(i));
2258 EXPECT_EQ(3.0f, data.mTable[i].value);
2259 }
2260 }
2261 EXPECT_EQ(1.0f, node2->minimum());
2262 EXPECT_EQ(3.0f, node2->maximum());
2263 EXPECT_EQ(0.0f, node2->getValue(CoordT(0)));
2264 EXPECT_EQ(1.0f, node2->getValue(CoordT(8-1)));
2265 EXPECT_EQ(2.0f, node2->getValue(CoordT(8*16-1)));
2266 EXPECT_EQ(3.0f, node2->getValue(CoordT(8*16*32-1)));
2267 }
2268 { // check root
2269 EXPECT_EQ(0.0f, root->background());
2270 EXPECT_EQ(1.0f, root->minimum());
2271 EXPECT_EQ(3.0f, root->maximum());
2272 EXPECT_EQ(1u, root->tileCount());
2273 EXPECT_EQ(0.0f, root->getValue(CoordT(0)));
2274 EXPECT_EQ(1.0f, root->getValue(CoordT(8-1)));
2275 EXPECT_EQ(2.0f, root->getValue(CoordT(8*16-1)));
2276 EXPECT_EQ(3.0f, root->getValue(CoordT(8*16*32-1)));
2277 }
2278 { // check tree
2279 EXPECT_EQ(0.0f, tree->background());
2280 float a, b;
2281 tree->extrema(a, b);
2282 EXPECT_EQ(1.0f, a);
2283 EXPECT_EQ(3.0f, b);
2284 EXPECT_EQ(0.0f, tree->getValue(CoordT(0)));
2285 EXPECT_EQ(1.0f, tree->getValue(CoordT(8-1)));
2286 EXPECT_EQ(2.0f, tree->getValue(CoordT(8*16-1)));
2287 EXPECT_EQ(3.0f, tree->getValue(CoordT(8*16*32-1)));
2288 EXPECT_EQ(1u, tree->nodeCount<LeafT>());
2289 EXPECT_EQ(1u, tree->nodeCount<NodeT1>());
2290 EXPECT_EQ(1u, tree->nodeCount<NodeT2>());
2291 }
2292 {// check grid
2293 EXPECT_EQ(nanovdb::Version(), grid->version());
2294 EXPECT_EQ(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER), grid->version().getMajor());
2295 EXPECT_EQ(uint32_t(NANOVDB_MINOR_VERSION_NUMBER), grid->version().getMinor());
2296 EXPECT_EQ(uint32_t(NANOVDB_PATCH_VERSION_NUMBER), grid->version().getPatch());
2297 EXPECT_TRUE(grid->isValid());
2298 EXPECT_EQ(grid->gridType(), nanovdb::GridType::Float);
2299 EXPECT_EQ(grid->gridClass(), nanovdb::GridClass::Unknown);
2300 EXPECT_FALSE(grid->isLevelSet());
2301 EXPECT_FALSE(grid->isFogVolume());
2302 EXPECT_FALSE(grid->isStaggered());
2303 EXPECT_FALSE(grid->isPointIndex());
2304 EXPECT_FALSE(grid->isPointData());
2305 EXPECT_FALSE(grid->isMask());
2306 EXPECT_TRUE(grid->isUnknown());
2307 EXPECT_TRUE(grid->hasMinMax());
2308 EXPECT_FALSE(grid->hasBBox());
2309 EXPECT_FALSE(grid->hasLongGridName());
2310 EXPECT_FALSE(grid->hasAverage());
2311 EXPECT_FALSE(grid->hasStdDeviation());
2312 //std::cerr << "\nName = \"" << grid->gridName() << "\"" << std::endl;
2313 EXPECT_EQ(name, std::string(grid->gridName()));
2314 }
2315 {// check ReadAccessor
2316 auto acc = grid->getAccessor();
2317 EXPECT_EQ(0.0f, acc.getValue(CoordT(0)));
2318 EXPECT_EQ(1.0f, acc.getValue(CoordT(8-1)));
2319 EXPECT_EQ(2.0f, acc.getValue(CoordT(8*16-1)));
2320 EXPECT_EQ(3.0f, acc.getValue(CoordT(8*16*32-1)));
2321 EXPECT_FALSE(acc.isActive(CoordT(0)));
2322 EXPECT_TRUE(acc.isActive(CoordT(8-1)));
2323 EXPECT_TRUE(acc.isActive(CoordT(16*8-1)));
2324 EXPECT_TRUE(acc.isActive(CoordT(32*16*8-1)));
2325 }
2326 } // BasicGrid
2327
TEST_F(TestNanoVDB,GridBuilderEmpty)2328 TEST_F(TestNanoVDB, GridBuilderEmpty)
2329 {
2330 { // empty grid
2331 nanovdb::GridBuilder<float> builder(0.0f);
2332 auto srcAcc = builder.getAccessor();
2333 auto handle = builder.getHandle<>(1.0, nanovdb::Vec3d(0.0), "test");
2334 EXPECT_TRUE(handle);
2335 auto* meta = handle.gridMetaData();
2336 EXPECT_TRUE(meta);
2337 EXPECT_TRUE(meta->isEmpty());
2338 EXPECT_EQ("test", std::string(meta->shortGridName()));
2339 EXPECT_EQ(nanovdb::GridType::Float, meta->gridType());
2340 EXPECT_EQ(nanovdb::GridClass::Unknown, meta->gridClass());
2341 EXPECT_EQ(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER), meta->version().getMajor());
2342 EXPECT_EQ(uint32_t(NANOVDB_MINOR_VERSION_NUMBER), meta->version().getMinor());
2343 EXPECT_EQ(uint32_t(NANOVDB_PATCH_VERSION_NUMBER), meta->version().getPatch());
2344 auto* dstGrid = handle.grid<float>();
2345 EXPECT_TRUE(dstGrid);
2346 EXPECT_EQ("test", std::string(dstGrid->gridName()));
2347 EXPECT_EQ(0u, dstGrid->activeVoxelCount());
2348 auto dstAcc = dstGrid->getAccessor();
2349 EXPECT_EQ(0.0f, srcAcc.getValue(nanovdb::Coord(1, 2, 3)));
2350 EXPECT_FALSE(srcAcc.isActive(nanovdb::Coord(1, 2, 3)));
2351 EXPECT_EQ(0.0f, dstAcc.getValue(nanovdb::Coord(1, 2, 3)));
2352 EXPECT_EQ(dstGrid->tree().root().minimum(), 0.0f);
2353 EXPECT_EQ(dstGrid->tree().root().maximum(), 0.0f);
2354 EXPECT_EQ(dstGrid->tree().root().average(), 0.0f);
2355 EXPECT_EQ(dstGrid->tree().root().variance(), 0.0f);
2356 EXPECT_EQ(dstGrid->tree().root().stdDeviation(), 0.0f);
2357 }
2358 } // GridBuilderEmpty
2359
TEST_F(TestNanoVDB,GridBuilderBasic1)2360 TEST_F(TestNanoVDB, GridBuilderBasic1)
2361 {
2362 { // 1 grid point
2363 nanovdb::GridBuilder<float> builder(0.0f);
2364 auto srcAcc = builder.getAccessor();
2365 srcAcc.setValue(nanovdb::Coord(1, 2, 3), 1.0f);
2366 EXPECT_EQ(1.0f, srcAcc.getValue(nanovdb::Coord(1, 2, 3)));
2367 auto handle = builder.getHandle<>();
2368 EXPECT_TRUE(handle);
2369 auto* meta = handle.gridMetaData();
2370 EXPECT_TRUE(meta);
2371 EXPECT_FALSE(meta->isEmpty());
2372 EXPECT_EQ(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER), meta->version().getMajor());
2373 EXPECT_EQ(uint32_t(NANOVDB_MINOR_VERSION_NUMBER), meta->version().getMinor());
2374 EXPECT_EQ(uint32_t(NANOVDB_PATCH_VERSION_NUMBER), meta->version().getPatch());
2375 EXPECT_EQ("", std::string(meta->shortGridName()));
2376 EXPECT_EQ(nanovdb::GridType::Float, meta->gridType());
2377 EXPECT_EQ(nanovdb::GridClass::Unknown, meta->gridClass());
2378 auto* dstGrid = handle.grid<float>();
2379 EXPECT_TRUE(dstGrid);
2380 EXPECT_EQ("", std::string(dstGrid->gridName()));
2381 EXPECT_EQ(nanovdb::Vec3R(1.0), dstGrid->voxelSize());
2382 //EXPECT_EQ(1u, dstGrid->activeVoxelCount());
2383 auto dstAcc = dstGrid->getAccessor();
2384 EXPECT_EQ(1.0f, dstAcc.getValue(nanovdb::Coord(1, 2, 3)));
2385 EXPECT_TRUE(srcAcc.isActive(nanovdb::Coord(1, 2, 3)));
2386 EXPECT_EQ(nanovdb::Coord(1, 2, 3), dstGrid->indexBBox()[0]);
2387 EXPECT_EQ(nanovdb::Coord(1, 2, 3), dstGrid->indexBBox()[1]);
2388 EXPECT_EQ(dstGrid->tree().root().minimum(), 1.0f);// minimum active value
2389 EXPECT_EQ(dstGrid->tree().root().maximum(), 1.0f);// maximum active value
2390 EXPECT_NEAR(dstGrid->tree().root().average(), 1.0f, 1e-6);
2391 EXPECT_NEAR(dstGrid->tree().root().variance(), 0.0f,1e-6);
2392 EXPECT_NEAR(dstGrid->tree().root().stdDeviation(), 0.0f, 1e-6);
2393 }
2394 } // GridBuilderBasic1
2395
TEST_F(TestNanoVDB,GridBuilderBasic2)2396 TEST_F(TestNanoVDB, GridBuilderBasic2)
2397 {
2398 { // 2 grid points
2399 nanovdb::GridBuilder<float> builder(0.0f);
2400 auto srcAcc = builder.getAccessor();
2401 srcAcc.setValue(nanovdb::Coord(1, 2, 3), 1.0f);
2402 srcAcc.setValue(nanovdb::Coord(2, -2, 9),-1.0f);
2403 //srcAcc.setValue(nanovdb::Coord(20,-20,90), 0.0f);// same as background
2404 auto handle = builder.getHandle<>(1.0, nanovdb::Vec3d(0.0), "test");
2405 EXPECT_TRUE(handle);
2406 auto* meta = handle.gridMetaData();
2407 EXPECT_TRUE(meta);
2408 EXPECT_FALSE(meta->isEmpty());
2409 //EXPECT_TRUE(meta->version().isValid());
2410 EXPECT_EQ(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER), meta->version().getMajor());
2411 EXPECT_EQ(uint32_t(NANOVDB_MINOR_VERSION_NUMBER), meta->version().getMinor());
2412 EXPECT_EQ(uint32_t(NANOVDB_PATCH_VERSION_NUMBER), meta->version().getPatch());
2413 EXPECT_EQ("test", std::string(meta->shortGridName()));
2414 EXPECT_EQ(nanovdb::GridType::Float, meta->gridType());
2415 EXPECT_EQ(nanovdb::GridClass::Unknown, meta->gridClass());
2416 auto* dstGrid = handle.grid<float>();
2417 EXPECT_TRUE(dstGrid);
2418 EXPECT_EQ("test", std::string(dstGrid->gridName()));
2419 EXPECT_EQ(2u, dstGrid->activeVoxelCount());
2420 auto dstAcc = dstGrid->getAccessor();
2421 EXPECT_EQ( 1.0f, dstAcc.getValue(nanovdb::Coord(1, 2, 3)));
2422 EXPECT_EQ(-1.0f, dstAcc.getValue(nanovdb::Coord(2, -2, 9)));
2423
2424 const nanovdb::BBox<nanovdb::Vec3R> indexBBox = dstGrid->indexBBox();
2425 EXPECT_DOUBLE_EQ( 1.0, indexBBox[0][0]);
2426 EXPECT_DOUBLE_EQ(-2.0, indexBBox[0][1]);
2427 EXPECT_DOUBLE_EQ( 3.0, indexBBox[0][2]);
2428 EXPECT_DOUBLE_EQ( 3.0, indexBBox[1][0]);
2429 EXPECT_DOUBLE_EQ( 3.0, indexBBox[1][1]);
2430 EXPECT_DOUBLE_EQ(10.0, indexBBox[1][2]);
2431
2432 EXPECT_EQ(nanovdb::Coord(1, -2, 3), dstGrid->indexBBox()[0]);
2433 EXPECT_EQ(nanovdb::Coord(2, 2, 9), dstGrid->indexBBox()[1]);
2434
2435 EXPECT_EQ(dstGrid->tree().root().minimum(),-1.0f);
2436 EXPECT_EQ(dstGrid->tree().root().maximum(), 1.0f);
2437 EXPECT_NEAR(dstGrid->tree().root().average(), 0.0f, 1e-6);
2438 EXPECT_NEAR(dstGrid->tree().root().variance(),1.0f, 1e-6);// Sim (x_i - Avg)^2/N = ((-1)^2 + 1^2)/2 = 1
2439 EXPECT_NEAR(dstGrid->tree().root().stdDeviation(), 1.0f, 1e-6);// stdDev = Sqrt(var)
2440 }
2441 } // GridBuilderBasic2
2442
TEST_F(TestNanoVDB,GridBuilderPrune)2443 TEST_F(TestNanoVDB, GridBuilderPrune)
2444 {
2445 {
2446 nanovdb::GridBuilder<float> builder(0.0f);
2447 auto srcAcc = builder.getAccessor();
2448 const nanovdb::CoordBBox bbox(nanovdb::Coord(0), nanovdb::Coord(8*16-1));
2449 auto func = [](const nanovdb::Coord&) { return 1.0f; };
2450 //auto func = [](const nanovdb::Coord&, float &v) { v = 1.0f; return true; };
2451 builder(func, bbox);
2452 for (auto ijk = bbox.begin(); ijk; ++ijk) {
2453 EXPECT_EQ(1.0f, srcAcc.getValue(*ijk));
2454 EXPECT_TRUE(srcAcc.isActive(*ijk));
2455 }
2456
2457 auto handle = builder.getHandle<>(1.0, nanovdb::Vec3d(0.0), "test");
2458 EXPECT_TRUE(handle);
2459 auto* meta = handle.gridMetaData();
2460 EXPECT_TRUE(meta);
2461 EXPECT_FALSE(meta->isEmpty());
2462 //EXPECT_TRUE(meta->version().isValid());
2463 EXPECT_EQ(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER), meta->version().getMajor());
2464 EXPECT_EQ(uint32_t(NANOVDB_MINOR_VERSION_NUMBER), meta->version().getMinor());
2465 EXPECT_EQ(uint32_t(NANOVDB_PATCH_VERSION_NUMBER), meta->version().getPatch());
2466 EXPECT_EQ("test", std::string(meta->shortGridName()));
2467 EXPECT_EQ(nanovdb::GridType::Float, meta->gridType());
2468 EXPECT_EQ(nanovdb::GridClass::Unknown, meta->gridClass());
2469 auto* dstGrid = handle.grid<float>();
2470 EXPECT_TRUE(dstGrid);
2471 EXPECT_EQ("test", std::string(dstGrid->gridName()));
2472 EXPECT_EQ(512*16*16*16u, dstGrid->activeVoxelCount());//
2473 auto dstAcc = dstGrid->getAccessor();
2474
2475 for (nanovdb::Coord ijk = bbox[0]; ijk[0] <= bbox[1][0]; ++ijk[0]) {
2476 for (ijk[1] = bbox[0][1]; ijk[1] <= bbox[1][1]; ++ijk[1]) {
2477 for (ijk[2] = bbox[0][2]; ijk[2] <= bbox[1][2]; ++ijk[2]) {
2478 EXPECT_EQ(1.0f, dstAcc.getValue(ijk));
2479 }
2480 }
2481 }
2482 EXPECT_EQ( 0.0f, dstAcc.getValue(nanovdb::Coord(2, -2, 9)));
2483
2484 const nanovdb::BBox<nanovdb::Vec3R> indexBBox = dstGrid->indexBBox();
2485 EXPECT_DOUBLE_EQ( 0.0, indexBBox[0][0]);
2486 EXPECT_DOUBLE_EQ( 0.0, indexBBox[0][1]);
2487 EXPECT_DOUBLE_EQ( 0.0, indexBBox[0][2]);
2488 EXPECT_DOUBLE_EQ(8*16.0, indexBBox[1][0]);
2489 EXPECT_DOUBLE_EQ(8*16.0, indexBBox[1][1]);
2490 EXPECT_DOUBLE_EQ(8*16.0, indexBBox[1][2]);
2491
2492 EXPECT_EQ(nanovdb::Coord(0), dstGrid->indexBBox()[0]);
2493 EXPECT_EQ(nanovdb::Coord(8*16-1), dstGrid->indexBBox()[1]);
2494
2495 EXPECT_EQ(0u, dstGrid->tree().nodeCount(0));// all pruned away
2496 EXPECT_EQ(0u, dstGrid->tree().nodeCount(1));// all pruned away
2497 EXPECT_EQ(1u, dstGrid->tree().nodeCount(2));
2498
2499 EXPECT_EQ(dstGrid->tree().root().minimum(), 1.0f);
2500 EXPECT_EQ(dstGrid->tree().root().maximum(), 1.0f);
2501 EXPECT_NEAR(dstGrid->tree().root().average(), 1.0f, 1e-6);
2502 EXPECT_NEAR(dstGrid->tree().root().variance(),0.0f, 1e-6);// Sim (x_i - Avg)^2/N = 0
2503 EXPECT_NEAR(dstGrid->tree().root().stdDeviation(), 0.0f, 1e-6);// stdDev = Sqrt(var)
2504 }
2505 } // GridBuilderPrune
2506
TEST_F(TestNanoVDB,GridBuilder_Vec3f)2507 TEST_F(TestNanoVDB, GridBuilder_Vec3f)
2508 {
2509 using VoxelT = nanovdb::Vec3f;
2510 EXPECT_EQ(nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(12 + 3 + 1 + 2*4 + 64 + 3*(2*4 + 512*4)), sizeof(nanovdb::NanoLeaf<VoxelT>));
2511 { // 3 grid point
2512 nanovdb::GridBuilder<VoxelT> builder(nanovdb::Vec3f(0.0f));
2513 auto srcAcc = builder.getAccessor();
2514 srcAcc.setValue(nanovdb::Coord( 1, 2, 3), nanovdb::Vec3f(1.0f));
2515 srcAcc.setValue(nanovdb::Coord(-10, 20,-50), nanovdb::Vec3f(2.0f));
2516 srcAcc.setValue(nanovdb::Coord( 50,-12, 30), nanovdb::Vec3f(3.0f));
2517 EXPECT_TRUE(srcAcc.isActive(nanovdb::Coord(1, 2, 3)));
2518 EXPECT_TRUE(srcAcc.isValueOn(nanovdb::Coord(1, 2, 3)));
2519 EXPECT_EQ(nanovdb::Vec3f(1.0f), srcAcc.getValue(nanovdb::Coord( 1, 2, 3)));
2520 EXPECT_EQ(nanovdb::Vec3f(2.0f), srcAcc.getValue(nanovdb::Coord(-10, 20,-50)));
2521 EXPECT_EQ(nanovdb::Vec3f(3.0f), srcAcc.getValue(nanovdb::Coord( 50,-12, 30)));
2522
2523 builder.setStats(nanovdb::StatsMode::All);
2524 auto handle = builder.getHandle();
2525
2526 EXPECT_TRUE(handle);
2527 auto* meta = handle.gridMetaData();
2528 EXPECT_TRUE(meta);
2529 EXPECT_FALSE(meta->isEmpty());
2530 EXPECT_EQ(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER), meta->version().getMajor());
2531 EXPECT_EQ(uint32_t(NANOVDB_MINOR_VERSION_NUMBER), meta->version().getMinor());
2532 EXPECT_EQ(uint32_t(NANOVDB_PATCH_VERSION_NUMBER), meta->version().getPatch());
2533 EXPECT_EQ("", std::string(meta->shortGridName()));
2534 EXPECT_EQ(nanovdb::mapToGridType<VoxelT>(), meta->gridType());
2535 EXPECT_EQ(nanovdb::GridClass::Unknown, meta->gridClass());
2536 auto* dstGrid = handle.grid<VoxelT>();
2537 EXPECT_TRUE(dstGrid);
2538 EXPECT_EQ("", std::string(dstGrid->gridName()));
2539 EXPECT_EQ((const char*)handle.data(), (const char*)dstGrid);
2540 EXPECT_EQ(nanovdb::Vec3f(1.0f), dstGrid->tree().root().minimum());
2541 EXPECT_EQ(nanovdb::Vec3f(3.0f), dstGrid->tree().root().maximum());
2542 EXPECT_EQ((nanovdb::Vec3f(1.0f).lengthSqr() +
2543 nanovdb::Vec3f(2.0f).lengthSqr() +
2544 nanovdb::Vec3f(3.0f).lengthSqr())/3.0f, dstGrid->tree().root().average());
2545 EXPECT_TRUE(dstGrid->isBreadthFirst());
2546 using GridT = std::remove_pointer<decltype(dstGrid)>::type;
2547 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node2>());
2548 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node1>());
2549 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node0>());
2550 EXPECT_TRUE(dstGrid->isSequential<2>());
2551 EXPECT_TRUE(dstGrid->isSequential<1>());
2552 EXPECT_TRUE(dstGrid->isSequential<0>());
2553
2554 EXPECT_EQ(nanovdb::Vec3R(1.0), dstGrid->voxelSize());
2555 auto *leaf = dstGrid->tree().root().probeLeaf(nanovdb::Coord(1, 2, 3));
2556 EXPECT_TRUE(leaf);
2557 //std::cerr << leaf->origin() << ", " << leaf->data()->mBBoxMin << std::endl;
2558 EXPECT_EQ(nanovdb::Coord(0,0,0), leaf->origin());
2559 EXPECT_EQ(nanovdb::Coord(1,2,3), leaf->data()->mBBoxMin);
2560
2561 EXPECT_EQ(nanovdb::Vec3f(1.0f), dstGrid->tree().getValue(nanovdb::Coord(1, 2, 3)));
2562 auto dstAcc = dstGrid->getAccessor();
2563 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(1, 2, 3)));
2564 EXPECT_EQ(nanovdb::Vec3f(1.0f), dstAcc.getValue(nanovdb::Coord( 1, 2, 3)));
2565 EXPECT_EQ(nanovdb::Vec3f(2.0f), dstAcc.getValue(nanovdb::Coord(-10, 20,-50)));
2566 EXPECT_EQ(nanovdb::Vec3f(3.0f), dstAcc.getValue(nanovdb::Coord( 50,-12, 30)));
2567 //std::cerr << dstGrid->indexBBox() << std::endl;
2568 EXPECT_EQ(nanovdb::Coord(-10,-12,-50), dstGrid->indexBBox()[0]);
2569 EXPECT_EQ(nanovdb::Coord( 50, 20, 30), dstGrid->indexBBox()[1]);
2570 }
2571 } // GridBuilder_Vec3f
2572
TEST_F(TestNanoVDB,GridBuilder_Vec4f)2573 TEST_F(TestNanoVDB, GridBuilder_Vec4f)
2574 {
2575 using VoxelT = nanovdb::Vec4f;
2576 EXPECT_EQ(nanovdb::AlignUp<NANOVDB_DATA_ALIGNMENT>(12 + 3 + 1 + 2*4 + 64 + 4*(2*4 + 512*4)), sizeof(nanovdb::NanoLeaf<VoxelT>));
2577 { // 3 grid point
2578 nanovdb::GridBuilder<VoxelT> builder(nanovdb::Vec4f(0.0f));
2579 auto srcAcc = builder.getAccessor();
2580 srcAcc.setValue(nanovdb::Coord( 1, 2, 3), nanovdb::Vec4f(1.0f));
2581 srcAcc.setValue(nanovdb::Coord(-10, 20,-50), nanovdb::Vec4f(2.0f));
2582 srcAcc.setValue(nanovdb::Coord( 50,-12, 30), nanovdb::Vec4f(3.0f));
2583 EXPECT_TRUE(srcAcc.isActive(nanovdb::Coord(1, 2, 3)));
2584 EXPECT_TRUE(srcAcc.isValueOn(nanovdb::Coord(1, 2, 3)));
2585 EXPECT_EQ(nanovdb::Vec4f(1.0f), srcAcc.getValue(nanovdb::Coord( 1, 2, 3)));
2586 EXPECT_EQ(nanovdb::Vec4f(2.0f), srcAcc.getValue(nanovdb::Coord(-10, 20,-50)));
2587 EXPECT_EQ(nanovdb::Vec4f(3.0f), srcAcc.getValue(nanovdb::Coord( 50,-12, 30)));
2588
2589 builder.setStats(nanovdb::StatsMode::All);
2590 auto handle = builder.getHandle();
2591
2592 EXPECT_TRUE(handle);
2593 auto* meta = handle.gridMetaData();
2594 EXPECT_TRUE(meta);
2595 EXPECT_FALSE(meta->isEmpty());
2596 EXPECT_EQ(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER), meta->version().getMajor());
2597 EXPECT_EQ(uint32_t(NANOVDB_MINOR_VERSION_NUMBER), meta->version().getMinor());
2598 EXPECT_EQ(uint32_t(NANOVDB_PATCH_VERSION_NUMBER), meta->version().getPatch());
2599 EXPECT_EQ("", std::string(meta->shortGridName()));
2600 EXPECT_EQ(nanovdb::mapToGridType<VoxelT>(), meta->gridType());
2601 EXPECT_EQ(nanovdb::GridClass::Unknown, meta->gridClass());
2602 auto* dstGrid = handle.grid<VoxelT>();
2603 EXPECT_TRUE(dstGrid);
2604 EXPECT_EQ("", std::string(dstGrid->gridName()));
2605 EXPECT_EQ((const char*)handle.data(), (const char*)dstGrid);
2606 EXPECT_EQ(nanovdb::Vec4f(1.0f), dstGrid->tree().root().minimum());
2607 EXPECT_EQ(nanovdb::Vec4f(3.0f), dstGrid->tree().root().maximum());
2608 EXPECT_EQ((nanovdb::Vec4f(1.0f).lengthSqr() +
2609 nanovdb::Vec4f(2.0f).lengthSqr() +
2610 nanovdb::Vec4f(3.0f).lengthSqr())/3.0f, dstGrid->tree().root().average());
2611 EXPECT_TRUE(dstGrid->isBreadthFirst());
2612 using GridT = std::remove_pointer<decltype(dstGrid)>::type;
2613 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node2>());
2614 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node1>());
2615 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node0>());
2616 EXPECT_TRUE(dstGrid->isSequential<2>());
2617 EXPECT_TRUE(dstGrid->isSequential<1>());
2618 EXPECT_TRUE(dstGrid->isSequential<0>());
2619
2620 EXPECT_EQ(nanovdb::Vec3R(1.0), dstGrid->voxelSize());
2621 auto *leaf = dstGrid->tree().root().probeLeaf(nanovdb::Coord(1, 2, 3));
2622 EXPECT_TRUE(leaf);
2623 //std::cerr << leaf->origin() << ", " << leaf->data()->mBBoxMin << std::endl;
2624 EXPECT_EQ(nanovdb::Coord(0,0,0), leaf->origin());
2625 EXPECT_EQ(nanovdb::Coord(1,2,3), leaf->data()->mBBoxMin);
2626
2627 EXPECT_EQ(nanovdb::Vec4f(1.0f), dstGrid->tree().getValue(nanovdb::Coord(1, 2, 3)));
2628 auto dstAcc = dstGrid->getAccessor();
2629 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(1, 2, 3)));
2630 EXPECT_EQ(nanovdb::Vec4f(1.0f), dstAcc.getValue(nanovdb::Coord( 1, 2, 3)));
2631 EXPECT_EQ(nanovdb::Vec4f(2.0f), dstAcc.getValue(nanovdb::Coord(-10, 20,-50)));
2632 EXPECT_EQ(nanovdb::Vec4f(3.0f), dstAcc.getValue(nanovdb::Coord( 50,-12, 30)));
2633 //std::cerr << dstGrid->indexBBox() << std::endl;
2634 EXPECT_EQ(nanovdb::Coord(-10,-12,-50), dstGrid->indexBBox()[0]);
2635 EXPECT_EQ(nanovdb::Coord( 50, 20, 30), dstGrid->indexBBox()[1]);
2636 }
2637 } // GridBuilder_Vec4f
2638
2639
TEST_F(TestNanoVDB,GridBuilder_Fp4)2640 TEST_F(TestNanoVDB, GridBuilder_Fp4)
2641 {
2642 using VoxelT = nanovdb::Fp4;
2643 EXPECT_EQ(96u + 512u/2, sizeof(nanovdb::NanoLeaf<VoxelT>));
2644 { // 3 grid point
2645 nanovdb::GridBuilder<float, VoxelT> builder(0.0f);
2646 auto srcAcc = builder.getAccessor();
2647 srcAcc.setValue(nanovdb::Coord( 1, 2, 3), 1.0f);
2648 srcAcc.setValue(nanovdb::Coord(-10, 20,-50), 2.0f);
2649 srcAcc.setValue(nanovdb::Coord( 50,-12, 30), 3.0f);
2650 EXPECT_TRUE(srcAcc.isActive(nanovdb::Coord(1, 2, 3)));
2651 EXPECT_TRUE(srcAcc.isValueOn(nanovdb::Coord(1, 2, 3)));
2652 EXPECT_EQ(1.0f, srcAcc.getValue(nanovdb::Coord( 1, 2, 3)));
2653 EXPECT_EQ(2.0f, srcAcc.getValue(nanovdb::Coord(-10, 20,-50)));
2654 EXPECT_EQ(3.0f, srcAcc.getValue(nanovdb::Coord( 50,-12, 30)));
2655
2656 builder.setStats(nanovdb::StatsMode::All);
2657 auto handle = builder.getHandle();
2658
2659 EXPECT_TRUE(handle);
2660 auto* meta = handle.gridMetaData();
2661 EXPECT_TRUE(meta);
2662 EXPECT_FALSE(meta->isEmpty());
2663 EXPECT_EQ(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER), meta->version().getMajor());
2664 EXPECT_EQ(uint32_t(NANOVDB_MINOR_VERSION_NUMBER), meta->version().getMinor());
2665 EXPECT_EQ(uint32_t(NANOVDB_PATCH_VERSION_NUMBER), meta->version().getPatch());
2666 EXPECT_EQ("", std::string(meta->shortGridName()));
2667 EXPECT_EQ(nanovdb::mapToGridType<VoxelT>(), meta->gridType());
2668 EXPECT_EQ(nanovdb::GridClass::Unknown, meta->gridClass());
2669 auto* dstGrid = handle.grid<VoxelT>();
2670 EXPECT_TRUE(dstGrid);
2671 EXPECT_EQ("", std::string(dstGrid->gridName()));
2672 EXPECT_EQ((const char*)handle.data(), (const char*)dstGrid);
2673 EXPECT_EQ(1.0f, dstGrid->tree().root().minimum());
2674 EXPECT_EQ(3.0f, dstGrid->tree().root().maximum());
2675 EXPECT_EQ(2.0f, dstGrid->tree().root().average());
2676 EXPECT_TRUE(dstGrid->isBreadthFirst());
2677 using GridT = std::remove_pointer<decltype(dstGrid)>::type;
2678 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node2>());
2679 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node1>());
2680 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node0>());
2681 EXPECT_TRUE(dstGrid->isSequential<2>());
2682 EXPECT_TRUE(dstGrid->isSequential<1>());
2683 EXPECT_TRUE(dstGrid->isSequential<0>());
2684
2685 EXPECT_EQ(nanovdb::Vec3R(1.0), dstGrid->voxelSize());
2686 auto *leaf = dstGrid->tree().root().probeLeaf(nanovdb::Coord(1, 2, 3));
2687 EXPECT_TRUE(leaf);
2688 //std::cerr << leaf->origin() << ", " << leaf->data()->mBBoxMin << std::endl;
2689 EXPECT_EQ(nanovdb::Coord(0,0,0), leaf->origin());
2690 EXPECT_EQ(nanovdb::Coord(1,2,3), leaf->data()->mBBoxMin);
2691 //const auto offset = nanovdb::NanoLeaf<nanovdb::Fp4>::CoordToOffset(nanovdb::Coord(1, 2, 3));
2692 //std::cerr << "offset = " << offset << std::endl;
2693 //std::cerr << "code = " << int(leaf->data()->mCode[offset>>1]) << std::endl;
2694 //std::cerr << "code = " << int(leaf->data()->mCode[offset>>1] >> 4) << std::endl;
2695
2696 EXPECT_EQ(1.0f, dstGrid->tree().getValue(nanovdb::Coord(1, 2, 3)));
2697 auto dstAcc = dstGrid->getAccessor();
2698 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(1, 2, 3)));
2699 EXPECT_EQ(1.0f, dstAcc.getValue(nanovdb::Coord( 1, 2, 3)));
2700 EXPECT_EQ(2.0f, dstAcc.getValue(nanovdb::Coord(-10, 20,-50)));
2701 EXPECT_EQ(3.0f, dstAcc.getValue(nanovdb::Coord( 50,-12, 30)));
2702 //std::cerr << dstGrid->indexBBox() << std::endl;
2703 EXPECT_EQ(nanovdb::Coord(-10,-12,-50), dstGrid->indexBBox()[0]);
2704 EXPECT_EQ(nanovdb::Coord( 50, 20, 30), dstGrid->indexBBox()[1]);
2705 }
2706 {// Sphere
2707 const double voxelSize = 0.1, halfWidth = 3.0;
2708 const float radius = 10.0f;
2709 const nanovdb::Vec3f center(0);
2710 const nanovdb::Vec3d origin(0);
2711 const float tolerance = 0.5f * voxelSize;
2712
2713 auto handle = nanovdb::createLevelSetSphere<float, VoxelT>(radius, center,
2714 voxelSize, halfWidth,
2715 origin, "sphere",
2716 nanovdb::StatsMode::Default,
2717 nanovdb::ChecksumMode::Default,
2718 tolerance,
2719 false);
2720 auto* nanoGrid = handle.grid<VoxelT>();
2721 EXPECT_TRUE(nanoGrid);
2722 Sphere<float> sphere(center, radius, float(voxelSize), float(halfWidth));
2723 auto kernel = [&](const nanovdb::CoordBBox& bbox) {
2724 auto nanoAcc = nanoGrid->getAccessor();
2725 for (auto it = bbox.begin(); it; ++it) {
2726 const nanovdb::Coord p = *it;
2727 EXPECT_NEAR(nanoAcc.getValue(p), sphere(p), tolerance);
2728 }
2729 };
2730 nanovdb::forEach(nanoGrid->indexBBox(), kernel);
2731
2732 nanovdb::io::writeGrid("data/sphere_fp4.nvdb", handle);
2733 handle = nanovdb::io::readGrid("data/sphere_fp4.nvdb");
2734 nanoGrid = handle.grid<VoxelT>();
2735 EXPECT_TRUE(nanoGrid);
2736
2737 nanovdb::forEach(nanoGrid->indexBBox(), kernel);
2738 }
2739 } // GridBuilder_Fp4
2740
TEST_F(TestNanoVDB,GridBuilder_Fp8)2741 TEST_F(TestNanoVDB, GridBuilder_Fp8)
2742 {
2743 using VoxelT = nanovdb::Fp8;
2744 EXPECT_EQ(96u + 512u, sizeof(nanovdb::NanoLeaf<VoxelT>));
2745 { // 3 grid point
2746 nanovdb::GridBuilder<float, VoxelT> builder(0.0f);
2747 auto srcAcc = builder.getAccessor();
2748 srcAcc.setValue(nanovdb::Coord( 1, 2, 3), 1.0f);
2749 srcAcc.setValue(nanovdb::Coord(-10, 20,-50), 2.0f);
2750 srcAcc.setValue(nanovdb::Coord( 50,-12, 30), 3.0f);
2751 EXPECT_TRUE(srcAcc.isActive(nanovdb::Coord(1, 2, 3)));
2752 EXPECT_TRUE(srcAcc.isValueOn(nanovdb::Coord(1, 2, 3)));
2753 EXPECT_EQ(1.0f, srcAcc.getValue(nanovdb::Coord( 1, 2, 3)));
2754 EXPECT_EQ(2.0f, srcAcc.getValue(nanovdb::Coord(-10, 20,-50)));
2755 EXPECT_EQ(3.0f, srcAcc.getValue(nanovdb::Coord( 50,-12, 30)));
2756
2757 builder.setStats(nanovdb::StatsMode::All);
2758 auto handle = builder.getHandle();
2759
2760 EXPECT_TRUE(handle);
2761 auto* meta = handle.gridMetaData();
2762 EXPECT_TRUE(meta);
2763 EXPECT_FALSE(meta->isEmpty());
2764 EXPECT_EQ(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER), meta->version().getMajor());
2765 EXPECT_EQ(uint32_t(NANOVDB_MINOR_VERSION_NUMBER), meta->version().getMinor());
2766 EXPECT_EQ(uint32_t(NANOVDB_PATCH_VERSION_NUMBER), meta->version().getPatch());
2767 EXPECT_EQ("", std::string(meta->shortGridName()));
2768 EXPECT_EQ(nanovdb::mapToGridType<VoxelT>(), meta->gridType());
2769 EXPECT_EQ(nanovdb::GridClass::Unknown, meta->gridClass());
2770 auto* dstGrid = handle.grid<VoxelT>();
2771 EXPECT_TRUE(dstGrid);
2772 EXPECT_EQ("", std::string(dstGrid->gridName()));
2773 EXPECT_EQ((const char*)handle.data(), (const char*)dstGrid);
2774 EXPECT_EQ(1.0f, dstGrid->tree().root().minimum());
2775 EXPECT_EQ(3.0f, dstGrid->tree().root().maximum());
2776 EXPECT_EQ(2.0f, dstGrid->tree().root().average());
2777 EXPECT_TRUE(dstGrid->isBreadthFirst());
2778 using GridT = std::remove_pointer<decltype(dstGrid)>::type;
2779 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node2>());
2780 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node1>());
2781 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node0>());
2782 EXPECT_TRUE(dstGrid->isSequential<2>());
2783 EXPECT_TRUE(dstGrid->isSequential<1>());
2784 EXPECT_TRUE(dstGrid->isSequential<0>());
2785
2786 EXPECT_EQ(nanovdb::Vec3R(1.0), dstGrid->voxelSize());
2787 auto *leaf = dstGrid->tree().root().probeLeaf(nanovdb::Coord(1, 2, 3));
2788 EXPECT_TRUE(leaf);
2789 //std::cerr << leaf->origin() << ", " << leaf->data()->mBBoxMin << std::endl;
2790 EXPECT_EQ(nanovdb::Coord(0,0,0), leaf->origin());
2791 EXPECT_EQ(nanovdb::Coord(1,2,3), leaf->data()->mBBoxMin);
2792 //const auto offset = nanovdb::NanoLeaf<nanovdb::Fp4>::CoordToOffset(nanovdb::Coord(1, 2, 3));
2793 //std::cerr << "offset = " << offset << std::endl;
2794 //std::cerr << "code = " << int(leaf->data()->mCode[offset>>1]) << std::endl;
2795 //std::cerr << "code = " << int(leaf->data()->mCode[offset>>1] >> 4) << std::endl;
2796
2797 EXPECT_EQ(1.0f, dstGrid->tree().getValue(nanovdb::Coord(1, 2, 3)));
2798 auto dstAcc = dstGrid->getAccessor();
2799 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(1, 2, 3)));
2800 EXPECT_EQ(1.0f, dstAcc.getValue(nanovdb::Coord( 1, 2, 3)));
2801 EXPECT_EQ(2.0f, dstAcc.getValue(nanovdb::Coord(-10, 20,-50)));
2802 EXPECT_EQ(3.0f, dstAcc.getValue(nanovdb::Coord( 50,-12, 30)));
2803 //std::cerr << dstGrid->indexBBox() << std::endl;
2804 EXPECT_EQ(nanovdb::Coord(-10,-12,-50), dstGrid->indexBBox()[0]);
2805 EXPECT_EQ(nanovdb::Coord( 50, 20, 30), dstGrid->indexBBox()[1]);
2806 }
2807 {// Sphere
2808 const double voxelSize = 0.1, halfWidth = 3.0;
2809 const float radius = 10.0f;
2810 const nanovdb::Vec3f center(0);
2811 const nanovdb::Vec3d origin(0);
2812 const float tolerance = 0.05f * voxelSize;
2813
2814 auto handle = nanovdb::createLevelSetSphere<float, VoxelT>(radius, center,
2815 voxelSize, halfWidth,
2816 origin, "sphere",
2817 nanovdb::StatsMode::Default,
2818 nanovdb::ChecksumMode::Default,
2819 tolerance,
2820 false);
2821 auto* nanoGrid = handle.grid<VoxelT>();
2822 EXPECT_TRUE(nanoGrid);
2823 Sphere<float> sphere(center, radius, float(voxelSize), float(halfWidth));
2824 auto kernel = [&](const nanovdb::CoordBBox& bbox) {
2825 auto nanoAcc = nanoGrid->getAccessor();
2826 for (auto it = bbox.begin(); it; ++it) {
2827 const nanovdb::Coord p = *it;
2828 EXPECT_NEAR(nanoAcc.getValue(p), sphere(p), tolerance);
2829 }
2830 };
2831 nanovdb::forEach(nanoGrid->indexBBox(), kernel);
2832
2833 nanovdb::io::writeGrid("data/sphere_fp8.nvdb", handle);
2834 handle = nanovdb::io::readGrid("data/sphere_fp8.nvdb");
2835 nanoGrid = handle.grid<VoxelT>();
2836 EXPECT_TRUE(nanoGrid);
2837
2838 nanovdb::forEach(nanoGrid->indexBBox(), kernel);
2839 }
2840 } // GridBuilder_Fp8
2841
TEST_F(TestNanoVDB,GridBuilder_Fp16)2842 TEST_F(TestNanoVDB, GridBuilder_Fp16)
2843 {
2844 using VoxelT = nanovdb::Fp16;
2845 EXPECT_EQ(96u + 512u*2, sizeof(nanovdb::NanoLeaf<VoxelT>));
2846 { // 3 grid point
2847 nanovdb::GridBuilder<float, VoxelT> builder(0.0f);
2848 auto srcAcc = builder.getAccessor();
2849 srcAcc.setValue(nanovdb::Coord( 1, 2, 3), 1.0f);
2850 srcAcc.setValue(nanovdb::Coord(-10, 20,-50), 2.0f);
2851 srcAcc.setValue(nanovdb::Coord( 50,-12, 30), 3.0f);
2852 EXPECT_TRUE(srcAcc.isActive(nanovdb::Coord(1, 2, 3)));
2853 EXPECT_TRUE(srcAcc.isValueOn(nanovdb::Coord(1, 2, 3)));
2854 EXPECT_EQ(1.0f, srcAcc.getValue(nanovdb::Coord( 1, 2, 3)));
2855 EXPECT_EQ(2.0f, srcAcc.getValue(nanovdb::Coord(-10, 20,-50)));
2856 EXPECT_EQ(3.0f, srcAcc.getValue(nanovdb::Coord( 50,-12, 30)));
2857
2858 builder.setStats(nanovdb::StatsMode::All);
2859 auto handle = builder.getHandle();
2860
2861 EXPECT_TRUE(handle);
2862 auto* meta = handle.gridMetaData();
2863 EXPECT_TRUE(meta);
2864 EXPECT_FALSE(meta->isEmpty());
2865 EXPECT_EQ(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER), meta->version().getMajor());
2866 EXPECT_EQ(uint32_t(NANOVDB_MINOR_VERSION_NUMBER), meta->version().getMinor());
2867 EXPECT_EQ(uint32_t(NANOVDB_PATCH_VERSION_NUMBER), meta->version().getPatch());
2868 EXPECT_EQ("", std::string(meta->shortGridName()));
2869 EXPECT_EQ(nanovdb::mapToGridType<VoxelT>(), meta->gridType());
2870 EXPECT_EQ(nanovdb::GridClass::Unknown, meta->gridClass());
2871 auto* dstGrid = handle.grid<VoxelT>();
2872 EXPECT_TRUE(dstGrid);
2873 EXPECT_EQ("", std::string(dstGrid->gridName()));
2874 EXPECT_EQ((const char*)handle.data(), (const char*)dstGrid);
2875 EXPECT_EQ(1.0f, dstGrid->tree().root().minimum());
2876 EXPECT_EQ(3.0f, dstGrid->tree().root().maximum());
2877 EXPECT_EQ(2.0f, dstGrid->tree().root().average());
2878 EXPECT_TRUE(dstGrid->isBreadthFirst());
2879 using GridT = std::remove_pointer<decltype(dstGrid)>::type;
2880 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node2>());
2881 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node1>());
2882 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node0>());
2883 EXPECT_TRUE(dstGrid->isSequential<2>());
2884 EXPECT_TRUE(dstGrid->isSequential<1>());
2885 EXPECT_TRUE(dstGrid->isSequential<0>());
2886
2887 EXPECT_EQ(nanovdb::Vec3R(1.0), dstGrid->voxelSize());
2888 auto *leaf = dstGrid->tree().root().probeLeaf(nanovdb::Coord(1, 2, 3));
2889 EXPECT_TRUE(leaf);
2890 //std::cerr << leaf->origin() << ", " << leaf->data()->mBBoxMin << std::endl;
2891 EXPECT_EQ(nanovdb::Coord(0,0,0), leaf->origin());
2892 EXPECT_EQ(nanovdb::Coord(1,2,3), leaf->data()->mBBoxMin);
2893 //const auto offset = nanovdb::NanoLeaf<nanovdb::Fp4>::CoordToOffset(nanovdb::Coord(1, 2, 3));
2894 //std::cerr << "offset = " << offset << std::endl;
2895 //std::cerr << "code = " << int(leaf->data()->mCode[offset>>1]) << std::endl;
2896 //std::cerr << "code = " << int(leaf->data()->mCode[offset>>1] >> 4) << std::endl;
2897
2898 EXPECT_EQ(1.0f, dstGrid->tree().getValue(nanovdb::Coord(1, 2, 3)));
2899 auto dstAcc = dstGrid->getAccessor();
2900 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(1, 2, 3)));
2901 EXPECT_EQ(1.0f, dstAcc.getValue(nanovdb::Coord( 1, 2, 3)));
2902 EXPECT_EQ(2.0f, dstAcc.getValue(nanovdb::Coord(-10, 20,-50)));
2903 EXPECT_EQ(3.0f, dstAcc.getValue(nanovdb::Coord( 50,-12, 30)));
2904 //std::cerr << dstGrid->indexBBox() << std::endl;
2905 EXPECT_EQ(nanovdb::Coord(-10,-12,-50), dstGrid->indexBBox()[0]);
2906 EXPECT_EQ(nanovdb::Coord( 50, 20, 30), dstGrid->indexBBox()[1]);
2907 }
2908 {// Sphere
2909 const double voxelSize = 0.1, halfWidth = 3.0;
2910 const float radius = 10.0f;
2911 const nanovdb::Vec3f center(0);
2912 const nanovdb::Vec3d origin(0);
2913 const float tolerance = 0.005f * voxelSize;
2914
2915 auto handle = nanovdb::createLevelSetSphere<float, VoxelT>(radius, center,
2916 voxelSize, halfWidth,
2917 origin, "sphere",
2918 nanovdb::StatsMode::Default,
2919 nanovdb::ChecksumMode::Default,
2920 tolerance,
2921 false);
2922 auto* nanoGrid = handle.grid<VoxelT>();
2923 EXPECT_TRUE(nanoGrid);
2924 Sphere<float> sphere(center, radius, float(voxelSize), float(halfWidth));
2925 auto kernel = [&](const nanovdb::CoordBBox& bbox) {
2926 auto nanoAcc = nanoGrid->getAccessor();
2927 for (auto it = bbox.begin(); it; ++it) {
2928 const nanovdb::Coord p = *it;
2929 EXPECT_NEAR(nanoAcc.getValue(p), sphere(p), tolerance);
2930 }
2931 };
2932 nanovdb::forEach(nanoGrid->indexBBox(), kernel);
2933
2934 nanovdb::io::writeGrid("data/sphere_fp16.nvdb", handle);
2935 handle = nanovdb::io::readGrid("data/sphere_fp16.nvdb");
2936 nanoGrid = handle.grid<VoxelT>();
2937 EXPECT_TRUE(nanoGrid);
2938
2939 nanovdb::forEach(nanoGrid->indexBBox(), kernel);
2940 }
2941 } // GridBuilder_Fp16
2942
TEST_F(TestNanoVDB,GridBuilder_FpN_Basic1)2943 TEST_F(TestNanoVDB, GridBuilder_FpN_Basic1)
2944 {
2945 using VoxelT = nanovdb::FpN;
2946 EXPECT_EQ(96u, sizeof(nanovdb::NanoLeaf<VoxelT>));
2947 { // 1 grid point
2948 nanovdb::GridBuilder<float, VoxelT> builder(0.0f);
2949 auto srcAcc = builder.getAccessor();
2950 srcAcc.setValue(nanovdb::Coord( 0, 0, 0), 1.0f);
2951 EXPECT_TRUE(srcAcc.isActive(nanovdb::Coord(0, 0, 0)));
2952 EXPECT_TRUE(srcAcc.isValueOn(nanovdb::Coord(0, 0, 0)));
2953 EXPECT_EQ(1.0f, srcAcc.getValue(nanovdb::Coord( 0, 0, 0)));
2954
2955 builder.setStats(nanovdb::StatsMode::All);
2956 //builder.setVerbose(true);
2957 auto handle = builder.getHandle();
2958
2959 EXPECT_TRUE(handle);
2960 auto* meta = handle.gridMetaData();
2961 EXPECT_TRUE(meta);
2962 EXPECT_FALSE(meta->isEmpty());
2963 EXPECT_EQ(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER), meta->version().getMajor());
2964 EXPECT_EQ(uint32_t(NANOVDB_MINOR_VERSION_NUMBER), meta->version().getMinor());
2965 EXPECT_EQ(uint32_t(NANOVDB_PATCH_VERSION_NUMBER), meta->version().getPatch());
2966 EXPECT_EQ("", std::string(meta->shortGridName()));
2967 EXPECT_EQ(nanovdb::mapToGridType<VoxelT>(), meta->gridType());
2968 EXPECT_EQ(nanovdb::GridClass::Unknown, meta->gridClass());
2969 auto* dstGrid = handle.grid<VoxelT>();
2970 EXPECT_TRUE(dstGrid);
2971 EXPECT_EQ("", std::string(dstGrid->gridName()));
2972 EXPECT_EQ((const char*)handle.data(), (const char*)dstGrid);
2973 EXPECT_EQ(1.0f, dstGrid->tree().getValue(nanovdb::Coord(0, 0, 0)));
2974 EXPECT_EQ(1.0f, dstGrid->tree().root().minimum());
2975 EXPECT_EQ(1.0f, dstGrid->tree().root().maximum());
2976 EXPECT_EQ(1.0f, dstGrid->tree().root().average());
2977 EXPECT_TRUE(dstGrid->isBreadthFirst());
2978 using GridT = std::remove_pointer<decltype(dstGrid)>::type;
2979 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node2>());
2980 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node1>());
2981 EXPECT_FALSE(dstGrid->isSequential<GridT::TreeType::Node0>());
2982 EXPECT_TRUE(dstGrid->isSequential<2>());
2983 EXPECT_TRUE(dstGrid->isSequential<1>());
2984 EXPECT_FALSE(dstGrid->isSequential<0>());
2985
2986 EXPECT_EQ(nanovdb::Vec3R(1.0), dstGrid->voxelSize());
2987 auto *leaf = dstGrid->tree().root().probeLeaf(nanovdb::Coord(0, 0, 0));
2988 EXPECT_TRUE(leaf);
2989 //std::cerr << leaf->origin() << ", " << leaf->data()->mBBoxMin << std::endl;
2990 EXPECT_EQ(nanovdb::Coord(0,0,0), leaf->origin());
2991 EXPECT_EQ(nanovdb::Coord(0,0,0), leaf->data()->mBBoxMin);
2992
2993 EXPECT_EQ(1.0f, dstGrid->tree().getValue(nanovdb::Coord(0, 0, 0)));
2994 auto dstAcc = dstGrid->getAccessor();
2995 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(0, 0, 0)));
2996 EXPECT_EQ(1.0f, dstAcc.getValue(nanovdb::Coord( 0, 0, 0)));
2997 EXPECT_EQ(0.0f, dstAcc.getValue(nanovdb::Coord(-10, 20,-50)));
2998 EXPECT_EQ(0.0f, dstAcc.getValue(nanovdb::Coord( 50,-12, 30)));
2999 //std::cerr << dstGrid->indexBBox() << std::endl;
3000 EXPECT_EQ(nanovdb::Coord(0,0,0), dstGrid->indexBBox()[0]);
3001 EXPECT_EQ(nanovdb::Coord(0,0,0), dstGrid->indexBBox()[1]);
3002 }
3003 }// GridBuilder_FpN_Basic1
3004
TEST_F(TestNanoVDB,GridBuilder_FpN_Basic3)3005 TEST_F(TestNanoVDB, GridBuilder_FpN_Basic3)
3006 {
3007 using VoxelT = nanovdb::FpN;
3008 EXPECT_EQ(96u, sizeof(nanovdb::NanoLeaf<VoxelT>));
3009 { // 3 grid point
3010 nanovdb::GridBuilder<float, VoxelT> builder(0.0f);
3011 auto srcAcc = builder.getAccessor();
3012 srcAcc.setValue(nanovdb::Coord( 1, 2, 3), 1.0f);
3013 srcAcc.setValue(nanovdb::Coord(-10, 20,-50), 2.0f);
3014 srcAcc.setValue(nanovdb::Coord( 50,-12, 30), 3.0f);
3015 EXPECT_TRUE(srcAcc.isActive(nanovdb::Coord(1, 2, 3)));
3016 EXPECT_TRUE(srcAcc.isValueOn(nanovdb::Coord(1, 2, 3)));
3017 EXPECT_EQ(1.0f, srcAcc.getValue(nanovdb::Coord( 1, 2, 3)));
3018 EXPECT_EQ(2.0f, srcAcc.getValue(nanovdb::Coord(-10, 20,-50)));
3019 EXPECT_EQ(3.0f, srcAcc.getValue(nanovdb::Coord( 50,-12, 30)));
3020
3021 builder.setStats(nanovdb::StatsMode::All);
3022 //builder.setVerbose(true);
3023 auto handle = builder.getHandle();
3024
3025 EXPECT_TRUE(handle);
3026 auto* meta = handle.gridMetaData();
3027 EXPECT_TRUE(meta);
3028 EXPECT_FALSE(meta->isEmpty());
3029 EXPECT_EQ(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER), meta->version().getMajor());
3030 EXPECT_EQ(uint32_t(NANOVDB_MINOR_VERSION_NUMBER), meta->version().getMinor());
3031 EXPECT_EQ(uint32_t(NANOVDB_PATCH_VERSION_NUMBER), meta->version().getPatch());
3032 EXPECT_EQ("", std::string(meta->shortGridName()));
3033 EXPECT_EQ(nanovdb::mapToGridType<VoxelT>(), meta->gridType());
3034 EXPECT_EQ(nanovdb::GridClass::Unknown, meta->gridClass());
3035 auto* dstGrid = handle.grid<VoxelT>();
3036 EXPECT_TRUE(dstGrid);
3037 EXPECT_EQ("", std::string(dstGrid->gridName()));
3038 EXPECT_EQ((const char*)handle.data(), (const char*)dstGrid);
3039 EXPECT_EQ(1.0f, dstGrid->tree().root().minimum());
3040 EXPECT_EQ(3.0f, dstGrid->tree().root().maximum());
3041 EXPECT_EQ(2.0f, dstGrid->tree().root().average());
3042 EXPECT_TRUE(dstGrid->isBreadthFirst());
3043 using GridT = std::remove_pointer<decltype(dstGrid)>::type;
3044 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node2>());
3045 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node1>());
3046 EXPECT_FALSE(dstGrid->isSequential<GridT::TreeType::Node0>());
3047 EXPECT_TRUE(dstGrid->isSequential<2>());
3048 EXPECT_TRUE(dstGrid->isSequential<1>());
3049 EXPECT_FALSE(dstGrid->isSequential<0>());
3050
3051 EXPECT_EQ(nanovdb::Vec3R(1.0), dstGrid->voxelSize());
3052 auto *leaf = dstGrid->tree().root().probeLeaf(nanovdb::Coord(1, 2, 3));
3053 EXPECT_TRUE(leaf);
3054 //std::cerr << leaf->origin() << ", " << leaf->data()->mBBoxMin << std::endl;
3055 EXPECT_EQ(nanovdb::Coord(0,0,0), leaf->origin());
3056 EXPECT_EQ(nanovdb::Coord(1,2,3), leaf->data()->mBBoxMin);
3057 //const auto offset = nanovdb::NanoLeaf<nanovdb::Fp4>::CoordToOffset(nanovdb::Coord(1, 2, 3));
3058 //std::cerr << "offset = " << offset << std::endl;
3059 //std::cerr << "code = " << int(leaf->data()->mCode[offset>>1]) << std::endl;
3060 //std::cerr << "code = " << int(leaf->data()->mCode[offset>>1] >> 4) << std::endl;
3061
3062 EXPECT_EQ(1.0f, dstGrid->tree().getValue(nanovdb::Coord(1, 2, 3)));
3063 auto dstAcc = dstGrid->getAccessor();
3064 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(1, 2, 3)));
3065 EXPECT_EQ(1.0f, dstAcc.getValue(nanovdb::Coord( 1, 2, 3)));
3066 EXPECT_EQ(2.0f, dstAcc.getValue(nanovdb::Coord(-10, 20,-50)));
3067 EXPECT_EQ(3.0f, dstAcc.getValue(nanovdb::Coord( 50,-12, 30)));
3068 //std::cerr << dstGrid->indexBBox() << std::endl;
3069 EXPECT_EQ(nanovdb::Coord(-10,-12,-50), dstGrid->indexBBox()[0]);
3070 EXPECT_EQ(nanovdb::Coord( 50, 20, 30), dstGrid->indexBBox()[1]);
3071 }
3072 }// GridBuilder_FpN_Basic3
3073
TEST_F(TestNanoVDB,GridBuilder_FpN_Sphere)3074 TEST_F(TestNanoVDB, GridBuilder_FpN_Sphere)
3075 {
3076 using VoxelT = nanovdb::FpN;
3077 EXPECT_EQ(96u, sizeof(nanovdb::NanoLeaf<VoxelT>));
3078 {// Sphere
3079 const double voxelSize = 0.1, halfWidth = 3.0;
3080 const float radius = 10.0f;
3081 const nanovdb::Vec3f center(0);
3082 const nanovdb::Vec3d origin(0);
3083 const float tolerance = 0.5f * voxelSize;
3084
3085 auto handle = nanovdb::createLevelSetSphere<float, VoxelT>(radius, center,
3086 voxelSize, halfWidth,
3087 origin, "sphere",
3088 nanovdb::StatsMode::Default,
3089 nanovdb::ChecksumMode::Default,
3090 tolerance,
3091 false);
3092 auto* nanoGrid = handle.grid<VoxelT>();
3093 EXPECT_TRUE(nanoGrid);
3094 Sphere<float> sphere(center, radius, float(voxelSize), float(halfWidth));
3095 auto kernel = [&](const nanovdb::CoordBBox& bbox) {
3096 auto nanoAcc = nanoGrid->getAccessor();
3097 for (auto it = bbox.begin(); it; ++it) {
3098 const nanovdb::Coord p = *it;
3099 EXPECT_NEAR(nanoAcc.getValue(p), sphere(p), tolerance);
3100 }
3101 };
3102 nanovdb::forEach(nanoGrid->indexBBox(), kernel);
3103
3104 nanovdb::io::writeGrid("data/sphere_fpN.nvdb", handle);
3105 handle = nanovdb::io::readGrid("data/sphere_fpN.nvdb");
3106 nanoGrid = handle.grid<VoxelT>();
3107 EXPECT_TRUE(nanoGrid);
3108
3109 nanovdb::forEach(nanoGrid->indexBBox(), kernel);
3110 }
3111 } // GridBuilder_FpN_Sphere
3112
TEST_F(TestNanoVDB,NodeManager)3113 TEST_F(TestNanoVDB, NodeManager)
3114 {
3115 { // 1 active voxel
3116 nanovdb::GridBuilder<float> builder(0.0f);
3117 auto srcAcc = builder.getAccessor();
3118 builder.setGridClass(nanovdb::GridClass::LevelSet);
3119 const nanovdb::Coord x0(1, 2, 3), x1(1, 2, 4);
3120 srcAcc.setValue(x1, 1.0f);
3121 auto handle = builder.getHandle<>(1.0, nanovdb::Vec3d(0.0), "test");
3122 EXPECT_TRUE(handle);
3123 auto* dstGrid = handle.grid<float>();
3124 EXPECT_TRUE(dstGrid);
3125 EXPECT_TRUE(dstGrid->isBreadthFirst());
3126 using GridT = std::remove_pointer<decltype(dstGrid)>::type;
3127 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node2>());
3128 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node1>());
3129 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node0>());
3130
3131 auto nodeMgr = nanovdb::createNodeMgr(*dstGrid);
3132 auto leafMgr = nanovdb::createLeafMgr(*dstGrid);
3133 EXPECT_FALSE(nodeMgr.empty());
3134 EXPECT_FALSE(leafMgr.empty());
3135 EXPECT_EQ(1u, nodeMgr.nodeCount(2));
3136 EXPECT_EQ(1u, nodeMgr.nodeCount(1));
3137 EXPECT_EQ(1u, nodeMgr.nodeCount(0));
3138 EXPECT_EQ(1u, leafMgr.size());
3139
3140 EXPECT_EQ(0.0f, nodeMgr.grid()->tree().getValue(x0));
3141 EXPECT_EQ(0.0f, nodeMgr.tree()->getValue(x0));
3142 EXPECT_EQ(0.0f, nodeMgr.root()->getValue(x0));
3143 EXPECT_EQ(0.0f, nodeMgr.upper(0)->getValue(x0));
3144 EXPECT_EQ(0.0f, nodeMgr.lower(0)->getValue(x0));
3145 EXPECT_EQ(0.0f, nodeMgr.leaf(0)->getValue(x0));
3146 EXPECT_EQ(0.0f, leafMgr[0]->getValue(x0));
3147
3148 EXPECT_EQ(1.0f, nodeMgr.grid()->tree().getValue(x1));
3149 EXPECT_EQ(1.0f, nodeMgr.tree()->getValue(x1));
3150 EXPECT_EQ(1.0f, nodeMgr.root()->getValue(x1));
3151 EXPECT_EQ(1.0f, nodeMgr.upper(0)->getValue(x1));
3152 EXPECT_EQ(1.0f, nodeMgr.lower(0)->getValue(x1));
3153 EXPECT_EQ(1.0f, nodeMgr.leaf(0)->getValue(x1));
3154 EXPECT_EQ(1.0f, leafMgr[0]->getValue(x1));
3155
3156 EXPECT_EQ(leafMgr[0], nodeMgr.leaf(0));
3157 EXPECT_EQ(leafMgr[0], dstGrid->tree().getFirstNode< 0 >());
3158 EXPECT_EQ(leafMgr[0], dstGrid->tree().getFirstNode< nanovdb::NanoLeaf<float> >());
3159 EXPECT_EQ(nodeMgr.leaf(0), dstGrid->tree().getFirstNode< nanovdb::NanoLeaf< float> >());
3160 EXPECT_EQ(nodeMgr.lower(0), dstGrid->tree().getFirstNode< nanovdb::NanoLower<float> >());
3161 EXPECT_EQ(nodeMgr.upper(0), dstGrid->tree().getFirstNode< nanovdb::NanoUpper<float> >());
3162 EXPECT_EQ(nodeMgr.leaf(0), dstGrid->tree().getFirstNode< 0 >());
3163 EXPECT_EQ(nodeMgr.lower(0), dstGrid->tree().getFirstNode< 1 >());
3164 EXPECT_EQ(nodeMgr.upper(0), dstGrid->tree().getFirstNode< 2 >());
3165 }
3166 { // 2 active voxels
3167 nanovdb::GridBuilder<float> builder(0.0f, nanovdb::GridClass::LevelSet);
3168 auto srcAcc = builder.getAccessor();
3169 const nanovdb::Coord x0(1, 2, 3), x1(2,-2, 9), x2(1, 2, 4);
3170 srcAcc.setValue(x1, 1.0f);
3171 srcAcc.setValue(x2, 2.0f);
3172 auto handle = builder.getHandle<>(1.0, nanovdb::Vec3d(0.0), "test");
3173 EXPECT_TRUE(handle);
3174 auto* dstGrid = handle.grid<float>();
3175 EXPECT_TRUE(dstGrid);
3176 EXPECT_EQ(1.0f, dstGrid->tree().getValue(x1));
3177 EXPECT_EQ(2.0f, dstGrid->tree().getValue(x2));
3178 EXPECT_TRUE(dstGrid->isBreadthFirst());
3179 using GridT = std::remove_pointer<decltype(dstGrid)>::type;
3180 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node2>());
3181 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node1>());
3182 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node0>());
3183
3184 nanovdb::NodeManager<nanovdb::FloatGrid> nodeMgr;
3185 EXPECT_TRUE(nodeMgr.empty());
3186 nanovdb::NodeManager<nanovdb::FloatGrid> tmp(*dstGrid);
3187 EXPECT_FALSE(tmp.empty());
3188 //mgr = tmp;// fails to compile since assignment operator is deleted
3189 nodeMgr = std::move(tmp);
3190 auto leafMgr = nanovdb::createLeafMgr(*dstGrid);
3191 EXPECT_FALSE(nodeMgr.empty());
3192 EXPECT_FALSE(leafMgr.empty());
3193 EXPECT_EQ(2u, nodeMgr.nodeCount(2));
3194 EXPECT_EQ(2u, nodeMgr.nodeCount(1));
3195 EXPECT_EQ(2u, nodeMgr.nodeCount(0));
3196 EXPECT_EQ(2u, leafMgr.size());
3197
3198 EXPECT_EQ(0.0f, nodeMgr.grid()->tree().getValue(x0));
3199 EXPECT_EQ(0.0f, nodeMgr.tree()->getValue(x0));
3200 EXPECT_EQ(0.0f, nodeMgr.root()->getValue(x0));
3201 EXPECT_EQ(0.0f, nodeMgr.upper(0)->getValue(x0));
3202 EXPECT_EQ(0.0f, nodeMgr.lower(0)->getValue(x0));
3203 EXPECT_EQ(0.0f, nodeMgr.leaf(0)->getValue(x0));
3204 EXPECT_EQ(0.0f, leafMgr[0]->getValue(x0));
3205
3206 EXPECT_EQ(1.0f, nodeMgr.grid()->tree().getValue(x1));
3207 EXPECT_EQ(1.0f, nodeMgr.tree()->getValue(x1));
3208 EXPECT_EQ(1.0f, nodeMgr.root()->getValue(x1));
3209 EXPECT_EQ(1.0f, nodeMgr.upper(0)->getValue(x1));
3210 EXPECT_EQ(1.0f, nodeMgr.lower(0)->getValue(x1));
3211 EXPECT_EQ(1.0f, nodeMgr.leaf(0)->getValue(x1));
3212 EXPECT_EQ(1.0f, leafMgr[0]->getValue(x1));
3213
3214 EXPECT_EQ(2.0f, nodeMgr.grid()->tree().getValue(x2));
3215 EXPECT_EQ(2.0f, nodeMgr.tree()->getValue(x2));
3216 EXPECT_EQ(2.0f, nodeMgr.root()->getValue(x2));
3217 EXPECT_EQ(2.0f, nodeMgr.upper(1)->getValue(x2));
3218 EXPECT_EQ(2.0f, nodeMgr.lower(1)->getValue(x2));
3219 EXPECT_EQ(2.0f, nodeMgr.leaf(1)->getValue(x2));
3220 EXPECT_EQ(2.0f, leafMgr[1]->getValue(x2));
3221
3222 EXPECT_EQ(leafMgr[0], nodeMgr.leaf(0));
3223 EXPECT_EQ(leafMgr[1], nodeMgr.leaf(1));
3224 }
3225 {// random points
3226 const size_t voxelCount = 512;
3227 const int min = -10000, max = 10000;
3228 std::vector<nanovdb::Coord> voxels;
3229 std::srand(98765);
3230 auto op = [&](){return rand() % (max - min) + min;};
3231 while (voxels.size() < voxelCount) {
3232 const nanovdb::Coord ijk(op(), op(), op());
3233 if (voxels.end() == std::find(voxels.begin(), voxels.end(), ijk)) {
3234 voxels.push_back(ijk);
3235 }
3236 }
3237 EXPECT_EQ(voxelCount, voxels.size());
3238 nanovdb::GridBuilder<float> builder(-1.0f, nanovdb::GridClass::LevelSet);
3239 auto srcAcc = builder.getAccessor();
3240 for (size_t i=0; i<voxelCount; ++i) {
3241 srcAcc.setValue(voxels[i], float(i));
3242 }
3243 auto handle = builder.getHandle<>(1.0, nanovdb::Vec3d(0.0), "test");
3244 EXPECT_TRUE(handle);
3245 auto* dstGrid = handle.grid<float>();
3246 EXPECT_TRUE(dstGrid);
3247 EXPECT_TRUE(dstGrid->isBreadthFirst());
3248 using GridT = std::remove_pointer<decltype(dstGrid)>::type;
3249 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node2>());
3250 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node1>());
3251 EXPECT_TRUE(dstGrid->isSequential<GridT::TreeType::Node0>());
3252
3253 auto nodeMgr = nanovdb::createNodeMgr(*dstGrid);
3254 auto leafMgr = nanovdb::createLeafMgr(*dstGrid);
3255 EXPECT_FALSE(nodeMgr.empty());
3256 EXPECT_FALSE(leafMgr.empty());
3257 EXPECT_EQ(nodeMgr.nodeCount(0), leafMgr.size());
3258 auto dstAcc = dstGrid->getAccessor();
3259 for (size_t i=0; i<voxelCount; ++i) {
3260 EXPECT_EQ(float(i), dstAcc.getValue(voxels[i]));
3261 EXPECT_EQ(nodeMgr.leaf(i), leafMgr[i]);
3262 }
3263 }
3264 } // NodeManager
3265
TEST_F(TestNanoVDB,GridBuilderBasicDense)3266 TEST_F(TestNanoVDB, GridBuilderBasicDense)
3267 {
3268 { // dense functor
3269 nanovdb::GridBuilder<float> builder(0.0f, nanovdb::GridClass::LevelSet);
3270 auto srcAcc = builder.getAccessor();
3271 const nanovdb::CoordBBox bbox(nanovdb::Coord(0), nanovdb::Coord(100));
3272 auto func = [](const nanovdb::Coord&) { return 1.0f; };
3273 //auto func = [](const nanovdb::Coord&, float &v) { v = 1.0f; return true; };
3274 builder(func, bbox);
3275 for (auto ijk = bbox.begin(); ijk; ++ijk) {
3276 EXPECT_EQ(1.0f, srcAcc.getValue(*ijk));
3277 EXPECT_TRUE(srcAcc.isActive(*ijk));
3278 }
3279 auto handle = builder.getHandle<>(1.0, nanovdb::Vec3d(0.0), "test");
3280 EXPECT_TRUE(handle);
3281 auto* meta = handle.gridMetaData();
3282 EXPECT_TRUE(meta);
3283 EXPECT_FALSE(meta->isEmpty());
3284 //EXPECT_TRUE(meta->version().isValid());
3285 EXPECT_EQ(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER), meta->version().getMajor());
3286 EXPECT_EQ(uint32_t(NANOVDB_MINOR_VERSION_NUMBER), meta->version().getMinor());
3287 EXPECT_EQ(uint32_t(NANOVDB_PATCH_VERSION_NUMBER), meta->version().getPatch());
3288 EXPECT_EQ("test", std::string(meta->shortGridName()));
3289 EXPECT_EQ(nanovdb::GridType::Float, meta->gridType());
3290 EXPECT_EQ(nanovdb::GridClass::LevelSet, meta->gridClass());
3291 auto* dstGrid = handle.grid<float>();
3292 EXPECT_TRUE(dstGrid);
3293 EXPECT_EQ("test", std::string(dstGrid->gridName()));
3294 const nanovdb::Coord dim = bbox.dim();
3295 EXPECT_EQ(nanovdb::Coord(101), dim);
3296 EXPECT_EQ(101u * 101u * 101u, dstGrid->activeVoxelCount());
3297 auto dstAcc = dstGrid->getAccessor();
3298 for (nanovdb::Coord ijk = bbox[0]; ijk[0] <= bbox[1][0]; ++ijk[0]) {
3299 for (ijk[1] = bbox[0][1]; ijk[1] <= bbox[1][1]; ++ijk[1]) {
3300 for (ijk[2] = bbox[0][2]; ijk[2] <= bbox[1][2]; ++ijk[2]) {
3301 EXPECT_EQ(1.0f, dstAcc.getValue(ijk));
3302 }
3303 }
3304 }
3305 EXPECT_EQ(bbox[0], dstGrid->indexBBox()[0]);
3306 EXPECT_EQ(bbox[1], dstGrid->indexBBox()[1]);
3307
3308 EXPECT_EQ(dstGrid->tree().root().minimum(), 1.0f);// smallest active value
3309 EXPECT_EQ(dstGrid->tree().root().maximum(), 1.0f);// largest active value
3310 EXPECT_EQ(dstGrid->tree().root().average(), 1.0f);
3311 EXPECT_EQ(dstGrid->tree().root().variance(), 0.0f);
3312 EXPECT_EQ(dstGrid->tree().root().stdDeviation(), 0.0f);
3313 }
3314 } // GridBuilderDense
3315
TEST_F(TestNanoVDB,GridBuilderBackground)3316 TEST_F(TestNanoVDB, GridBuilderBackground)
3317 {
3318 {
3319 nanovdb::GridBuilder<float> builder(0.5f);
3320 auto acc = builder.getAccessor();
3321
3322 acc.setValue(nanovdb::Coord(1), 1);
3323 acc.setValue(nanovdb::Coord(2), 0);
3324
3325 EXPECT_EQ(0.5f, acc.getValue(nanovdb::Coord(0)));
3326 EXPECT_FALSE(acc.isActive(nanovdb::Coord(0)));
3327 EXPECT_EQ(1, acc.getValue(nanovdb::Coord(1)));
3328 EXPECT_TRUE(acc.isActive(nanovdb::Coord(1)));
3329 EXPECT_EQ(0, acc.getValue(nanovdb::Coord(2)));
3330 EXPECT_TRUE(acc.isActive(nanovdb::Coord(1)));
3331
3332 auto gridHdl = builder.getHandle<>();
3333 auto grid = gridHdl.grid<float>();
3334 EXPECT_TRUE(grid);
3335 EXPECT_FALSE(grid->isEmpty());
3336 EXPECT_EQ(0.5, grid->tree().getValue(nanovdb::Coord(0)));
3337 EXPECT_EQ(1, grid->tree().getValue(nanovdb::Coord(1)));
3338 EXPECT_EQ(0, grid->tree().getValue(nanovdb::Coord(2)));
3339 }
3340 } // GridBuilderBackground
3341
TEST_F(TestNanoVDB,GridBuilderSphere)3342 TEST_F(TestNanoVDB, GridBuilderSphere)
3343 {
3344 Sphere<float> sphere(nanovdb::Vec3<float>(50), 20.0f);
3345 EXPECT_EQ(3.0f, sphere.background());
3346 EXPECT_EQ(3.0f, sphere(nanovdb::Coord(100)));
3347 EXPECT_EQ(-3.0f, sphere(nanovdb::Coord(50)));
3348 EXPECT_EQ(0.0f, sphere(nanovdb::Coord(50, 50, 70)));
3349 EXPECT_EQ(-1.0f, sphere(nanovdb::Coord(50, 50, 69)));
3350 EXPECT_EQ(2.0f, sphere(nanovdb::Coord(50, 50, 72)));
3351
3352 nanovdb::GridBuilder<float> builder(sphere.background(), nanovdb::GridClass::LevelSet);
3353 auto srcAcc = builder.getAccessor();
3354
3355 const nanovdb::CoordBBox bbox(nanovdb::Coord(-100), nanovdb::Coord(100));
3356 //mTimer.start("GridBulder Sphere");
3357 builder(sphere, bbox);
3358 //mTimer.stop();
3359
3360
3361 auto handle = builder.getHandle<>(1.0, nanovdb::Vec3d(0.0), "test");
3362 EXPECT_TRUE(handle);
3363 EXPECT_EQ(1u, handle.gridCount());
3364 auto* meta = handle.gridMetaData();
3365 EXPECT_TRUE(meta);
3366 EXPECT_EQ("test", std::string(meta->shortGridName()));
3367 EXPECT_EQ(nanovdb::GridType::Float, meta->gridType());
3368 EXPECT_EQ(nanovdb::GridClass::LevelSet, meta->gridClass());
3369 auto* dstGrid = handle.grid<float>();
3370 EXPECT_TRUE(dstGrid);
3371 EXPECT_EQ("test", std::string(dstGrid->gridName()));
3372 EXPECT_TRUE(dstGrid->hasBBox());
3373 EXPECT_TRUE(dstGrid->hasMinMax());
3374 EXPECT_TRUE(dstGrid->hasAverage());
3375 EXPECT_TRUE(dstGrid->hasStdDeviation());
3376
3377 //mTimer.start("GridBulder NodeMananger");
3378 nanovdb::NodeManager<nanovdb::FloatGrid> mgr(*dstGrid);
3379 //mTimer.stop();
3380 EXPECT_EQ(dstGrid->tree().nodeCount(0), mgr.nodeCount(0));
3381 EXPECT_EQ(dstGrid->tree().nodeCount(1), mgr.nodeCount(1));
3382 EXPECT_EQ(dstGrid->tree().nodeCount(2), mgr.nodeCount(2));
3383
3384 //std::cerr << "bbox.min = (" << dstGrid->indexBBox()[0][0] << ", " << dstGrid->indexBBox()[0][1] << ", " << dstGrid->indexBBox()[0][2] << ")" << std::endl;
3385 //std::cerr << "bbox.max = (" << dstGrid->indexBBox()[1][0] << ", " << dstGrid->indexBBox()[1][1] << ", " << dstGrid->indexBBox()[1][2] << ")" << std::endl;
3386
3387 uint64_t count = 0;
3388 auto dstAcc = dstGrid->getAccessor();
3389 for (nanovdb::Coord ijk = bbox[0]; ijk[0] <= bbox[1][0]; ++ijk[0]) {
3390 for (ijk[1] = bbox[0][1]; ijk[1] <= bbox[1][1]; ++ijk[1]) {
3391 for (ijk[2] = bbox[0][2]; ijk[2] <= bbox[1][2]; ++ijk[2]) {
3392 if (dstAcc.isActive(ijk))
3393 ++count;
3394 EXPECT_EQ(sphere(ijk), dstAcc.getValue(ijk));
3395 EXPECT_EQ(srcAcc.getValue(ijk), dstAcc.getValue(ijk));
3396 }
3397 }
3398 }
3399
3400 EXPECT_EQ(count, dstGrid->activeVoxelCount());
3401
3402 } // GridBuilderSphere
3403
TEST_F(TestNanoVDB,createLevelSetSphere)3404 TEST_F(TestNanoVDB, createLevelSetSphere)
3405 {
3406 Sphere<float> sphere(nanovdb::Vec3<float>(50), 20.0f);
3407 EXPECT_EQ(3.0f, sphere.background());
3408 EXPECT_EQ(3.0f, sphere(nanovdb::Coord(100)));
3409 EXPECT_EQ(-3.0f, sphere(nanovdb::Coord(50)));
3410 EXPECT_EQ(0.0f, sphere(nanovdb::Coord(50, 50, 70)));
3411 EXPECT_EQ(-1.0f, sphere(nanovdb::Coord(50, 50, 69)));
3412 EXPECT_EQ(2.0f, sphere(nanovdb::Coord(50, 50, 72)));
3413
3414 auto handle = nanovdb::createLevelSetSphere(20.0f, nanovdb::Vec3f(50),
3415 1.0, 3.0, nanovdb::Vec3d(0), "sphere_20");
3416
3417 const nanovdb::CoordBBox bbox(nanovdb::Coord(0), nanovdb::Coord(100));
3418
3419 EXPECT_TRUE(handle);
3420 EXPECT_EQ(1u, handle.gridCount());
3421 auto* meta = handle.gridMetaData();
3422 EXPECT_TRUE(meta);
3423 EXPECT_EQ("sphere_20", std::string(meta->shortGridName()));
3424 EXPECT_EQ(nanovdb::GridType::Float, meta->gridType());
3425 EXPECT_EQ(nanovdb::GridClass::LevelSet, meta->gridClass());
3426 auto* dstGrid = handle.grid<float>();
3427 EXPECT_TRUE(dstGrid);
3428 EXPECT_EQ("sphere_20", std::string(dstGrid->gridName()));
3429
3430 EXPECT_TRUE(dstGrid->hasBBox());
3431 EXPECT_TRUE(dstGrid->hasMinMax());
3432 EXPECT_TRUE(dstGrid->hasAverage());
3433 EXPECT_TRUE(dstGrid->hasStdDeviation());
3434
3435 EXPECT_NEAR( -3.0f, dstGrid->tree().root().minimum(), 0.04f);
3436 EXPECT_NEAR( 3.0f, dstGrid->tree().root().maximum(), 0.04f);
3437 EXPECT_NEAR( 0.0f, dstGrid->tree().root().average(), 0.3f);
3438 //std::cerr << dstGrid->tree().root().minimum() << std::endl;
3439 //std::cerr << dstGrid->tree().root().maximum() << std::endl;
3440 //std::cerr << dstGrid->tree().root().average() << std::endl;
3441 //std::cerr << dstGrid->tree().root().stdDeviation() << std::endl;
3442
3443
3444 EXPECT_EQ(nanovdb::Coord(50 - 20 - 2), dstGrid->indexBBox()[0]);
3445 EXPECT_EQ(nanovdb::Coord(50 + 20 + 2), dstGrid->indexBBox()[1]);
3446
3447 //std::cerr << "bbox.min = (" << dstGrid->indexBBox()[0][0] << ", " << dstGrid->indexBBox()[0][1] << ", " << dstGrid->indexBBox()[0][2] << ")" << std::endl;
3448 //std::cerr << "bbox.max = (" << dstGrid->indexBBox()[1][0] << ", " << dstGrid->indexBBox()[1][1] << ", " << dstGrid->indexBBox()[1][2] << ")" << std::endl;
3449 uint64_t count = 0;
3450 auto dstAcc = dstGrid->getAccessor();
3451 for (nanovdb::Coord ijk = bbox[0]; ijk[0] <= bbox[1][0]; ++ijk[0]) {
3452 for (ijk[1] = bbox[0][1]; ijk[1] <= bbox[1][1]; ++ijk[1]) {
3453 for (ijk[2] = bbox[0][2]; ijk[2] <= bbox[1][2]; ++ijk[2]) {
3454 if (sphere.inNarrowBand(ijk))
3455 ++count;
3456 EXPECT_EQ(sphere(ijk), dstAcc.getValue(ijk));
3457 EXPECT_EQ(sphere.inNarrowBand(ijk), dstAcc.isActive(ijk));
3458 }
3459 }
3460 }
3461
3462 EXPECT_EQ(count, dstGrid->activeVoxelCount());
3463
3464 } // createLevelSetSphere
3465
TEST_F(TestNanoVDB,createFogVolumeSphere)3466 TEST_F(TestNanoVDB, createFogVolumeSphere)
3467 {
3468 auto handle = nanovdb::createFogVolumeSphere(20.0f, nanovdb::Vec3f(50),
3469 1.0, 3.0, nanovdb::Vec3d(0), "sphere_20");
3470 const nanovdb::CoordBBox bbox(nanovdb::Coord(0), nanovdb::Coord(100));
3471
3472 EXPECT_TRUE(handle);
3473 EXPECT_EQ(1u, handle.gridCount());
3474 auto* meta = handle.gridMetaData();
3475 EXPECT_TRUE(meta);
3476 EXPECT_EQ("sphere_20", std::string(meta->shortGridName()));
3477 EXPECT_EQ(nanovdb::GridType::Float, meta->gridType());
3478 EXPECT_EQ(nanovdb::GridClass::FogVolume, meta->gridClass());
3479 auto* dstGrid = handle.grid<float>();
3480 EXPECT_TRUE(dstGrid);
3481 EXPECT_EQ("sphere_20", std::string(dstGrid->gridName()));
3482 EXPECT_TRUE(dstGrid->hasBBox());
3483 EXPECT_TRUE(dstGrid->hasMinMax());
3484 EXPECT_TRUE(dstGrid->hasAverage());
3485 EXPECT_TRUE(dstGrid->hasStdDeviation());
3486
3487 EXPECT_NEAR( 0.0f, dstGrid->tree().root().minimum(),1e-6);
3488 EXPECT_NEAR( 1.0f, dstGrid->tree().root().maximum(), 1e-6);
3489 EXPECT_NEAR( 0.8f, dstGrid->tree().root().average(), 1e-3);
3490 EXPECT_NEAR( 0.3f, dstGrid->tree().root().stdDeviation(), 1e-2);
3491 //std::cerr << dstGrid->tree().root().minimum() << std::endl;
3492 //std::cerr << dstGrid->tree().root().maximum() << std::endl;
3493 //std::cerr << dstGrid->tree().root().average() << std::endl;
3494 //std::cerr << dstGrid->tree().root().stdDeviation() << std::endl;
3495
3496 //std::cerr << "bbox.min = (" << dstGrid->indexBBox()[0][0] << ", " << dstGrid->indexBBox()[0][1] << ", " << dstGrid->indexBBox()[0][2] << ")" << std::endl;
3497 //std::cerr << "bbox.max = (" << dstGrid->indexBBox()[1][0] << ", " << dstGrid->indexBBox()[1][1] << ", " << dstGrid->indexBBox()[1][2] << ")" << std::endl;
3498
3499 EXPECT_EQ(nanovdb::Coord(50 - 20), dstGrid->indexBBox()[0]);
3500 EXPECT_EQ(nanovdb::Coord(50 + 20), dstGrid->indexBBox()[1]);
3501
3502 Sphere<float> sphere(nanovdb::Vec3<float>(50), 20.0f);
3503 uint64_t count = 0;
3504 auto dstAcc = dstGrid->getAccessor();
3505 for (nanovdb::Coord ijk = bbox[0]; ijk[0] <= bbox[1][0]; ++ijk[0]) {
3506 for (ijk[1] = bbox[0][1]; ijk[1] <= bbox[1][1]; ++ijk[1]) {
3507 for (ijk[2] = bbox[0][2]; ijk[2] <= bbox[1][2]; ++ijk[2]) {
3508 if (sphere(ijk) > 0) {
3509 EXPECT_FALSE(dstAcc.isActive(ijk));
3510 EXPECT_EQ(0, dstAcc.getValue(ijk));
3511 } else {
3512 ++count;
3513 EXPECT_TRUE(dstAcc.isActive(ijk));
3514 EXPECT_TRUE(dstAcc.getValue(ijk) >= 0);
3515 EXPECT_TRUE(dstAcc.getValue(ijk) <= 1);
3516 }
3517 }
3518 }
3519 }
3520
3521 EXPECT_EQ(count, dstGrid->activeVoxelCount());
3522
3523 } // createFogVolumeSphere
3524
TEST_F(TestNanoVDB,createPointSphere)3525 TEST_F(TestNanoVDB, createPointSphere)
3526 {
3527 Sphere<float> sphere(nanovdb::Vec3<float>(0), 100.0f, 1.0f, 1.0f);
3528 EXPECT_EQ(1.0f, sphere.background());
3529 EXPECT_EQ(1.0f, sphere(nanovdb::Coord(101, 0, 0)));
3530 EXPECT_EQ(-1.0f, sphere(nanovdb::Coord(0)));
3531 EXPECT_EQ(0.0f, sphere(nanovdb::Coord(0, 0, 100)));
3532 EXPECT_EQ(-1.0f, sphere(nanovdb::Coord(0, 0, 99)));
3533 EXPECT_EQ(1.0f, sphere(nanovdb::Coord(0, 0, 101)));
3534
3535 auto handle = nanovdb::createPointSphere<float>(1,// pointer per voxel
3536 100.0f,// radius of sphere
3537 nanovdb::Vec3f(0),// center sphere
3538 1.0,// voxel size
3539 nanovdb::Vec3d(0),// origin of grid
3540 "point_sphere");
3541
3542 const nanovdb::CoordBBox bbox(nanovdb::Coord(-100), nanovdb::Coord(100));
3543
3544 EXPECT_TRUE(handle);
3545 EXPECT_EQ(1u, handle.gridCount());
3546 auto* meta = handle.gridMetaData();
3547 EXPECT_TRUE(meta);
3548 EXPECT_EQ("point_sphere", std::string(meta->shortGridName()));
3549 EXPECT_EQ(nanovdb::GridType::UInt32, meta->gridType());
3550 EXPECT_EQ(nanovdb::GridClass::PointData, meta->gridClass());
3551 auto* dstGrid = handle.grid<uint32_t>();
3552 EXPECT_TRUE(dstGrid);
3553 EXPECT_EQ("point_sphere", std::string(dstGrid->gridName()));
3554 EXPECT_TRUE(dstGrid->hasBBox());
3555 EXPECT_TRUE(dstGrid->hasMinMax());
3556 EXPECT_FALSE(dstGrid->hasAverage());
3557 EXPECT_FALSE(dstGrid->hasStdDeviation());
3558
3559 EXPECT_EQ(bbox[0], dstGrid->indexBBox()[0]);
3560 EXPECT_EQ(bbox[1], dstGrid->indexBBox()[1]);
3561
3562 //std::cerr << "bbox.min = (" << dstGrid->indexBBox()[0][0] << ", " << dstGrid->indexBBox()[0][1] << ", " << dstGrid->indexBBox()[0][2] << ")" << std::endl;
3563 //std::cerr << "bbox.max = (" << dstGrid->indexBBox()[1][0] << ", " << dstGrid->indexBBox()[1][1] << ", " << dstGrid->indexBBox()[1][2] << ")" << std::endl;
3564
3565 uint64_t count = 0;
3566 nanovdb::PointAccessor<nanovdb::Vec3f> acc(*dstGrid);
3567 const nanovdb::Vec3f * begin = nullptr, *end = nullptr;
3568 for (nanovdb::Coord ijk = bbox[0]; ijk[0] <= bbox[1][0]; ++ijk[0]) {
3569 for (ijk[1] = bbox[0][1]; ijk[1] <= bbox[1][1]; ++ijk[1]) {
3570 for (ijk[2] = bbox[0][2]; ijk[2] <= bbox[1][2]; ++ijk[2]) {
3571 if (nanovdb::Abs(sphere(ijk)) < 0.5f) {
3572 ++count;
3573 EXPECT_TRUE(acc.isActive(ijk));
3574 EXPECT_TRUE(acc.getValue(ijk) != std::numeric_limits<uint32_t>::max());
3575 EXPECT_EQ(1u, acc.voxelPoints(ijk, begin, end)); // exactly one point per voxel
3576 const nanovdb::Vec3f p = *begin + ijk.asVec3s();// local voxel coordinate + global index coordinates
3577 EXPECT_TRUE(nanovdb::Abs(sphere(p)) <= 1.0f);
3578 } else {
3579 EXPECT_FALSE(acc.isActive(ijk));
3580 EXPECT_TRUE(acc.getValue(ijk) < 512 || acc.getValue(ijk) == std::numeric_limits<uint32_t>::max());
3581 }
3582 }
3583 }
3584 }
3585 EXPECT_EQ(count, dstGrid->activeVoxelCount());
3586 } // createPointSphere
3587
TEST_F(TestNanoVDB,createLevelSetTorus)3588 TEST_F(TestNanoVDB, createLevelSetTorus)
3589 {
3590 auto handle = nanovdb::createLevelSetTorus(100.0f, 50.0f, nanovdb::Vec3f(50),
3591 1.0, 3.0, nanovdb::Vec3d(0), "torus_100");
3592
3593 EXPECT_TRUE(handle);
3594 EXPECT_EQ(1u, handle.gridCount());
3595 auto* meta = handle.gridMetaData();
3596 EXPECT_TRUE(meta);
3597 EXPECT_EQ("torus_100", std::string(meta->shortGridName()));
3598 EXPECT_EQ(nanovdb::GridType::Float, meta->gridType());
3599 EXPECT_EQ(nanovdb::GridClass::LevelSet, meta->gridClass());
3600 auto* dstGrid = handle.grid<float>();
3601 EXPECT_TRUE(dstGrid);
3602 EXPECT_EQ("torus_100", std::string(dstGrid->gridName()));
3603 EXPECT_TRUE(dstGrid->hasBBox());
3604 EXPECT_TRUE(dstGrid->hasMinMax());
3605 EXPECT_TRUE(dstGrid->hasAverage());
3606 EXPECT_TRUE(dstGrid->hasStdDeviation());
3607
3608 EXPECT_EQ(nanovdb::Coord(50 - 100 - 50 - 2, 50 - 50 - 2, 50 - 100 - 50 - 2), dstGrid->indexBBox()[0]);
3609 EXPECT_EQ(nanovdb::Coord(50 + 100 + 50 + 2, 50 + 50 + 2, 50 + 100 + 50 + 2), dstGrid->indexBBox()[1]);
3610
3611 auto dstAcc = dstGrid->getAccessor();
3612 EXPECT_EQ(3.0f, dstAcc.getValue(nanovdb::Coord(50)));
3613 EXPECT_FALSE(dstAcc.isActive(nanovdb::Coord(50)));
3614 EXPECT_EQ(-3.0f, dstAcc.getValue(nanovdb::Coord(150, 50, 50)));
3615 EXPECT_FALSE(dstAcc.isActive(nanovdb::Coord(150, 50, 50)));
3616 EXPECT_EQ(0.0f, dstAcc.getValue(nanovdb::Coord(200, 50, 50)));
3617 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(200, 50, 50)));
3618 EXPECT_EQ(1.0f, dstAcc.getValue(nanovdb::Coord(201, 50, 50)));
3619 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(201, 50, 50)));
3620 EXPECT_EQ(-2.0f, dstAcc.getValue(nanovdb::Coord(198, 50, 50)));
3621 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(198, 50, 50)));
3622
3623 } // createLevelSetTorus
3624
TEST_F(TestNanoVDB,createFogVolumeTorus)3625 TEST_F(TestNanoVDB, createFogVolumeTorus)
3626 {
3627 auto handle = nanovdb::createFogVolumeTorus(100.0f, 50.0f, nanovdb::Vec3f(50),
3628 1.0, 3.0, nanovdb::Vec3d(0), "torus_100");
3629
3630 EXPECT_TRUE(handle);
3631 EXPECT_EQ(1u, handle.gridCount());
3632 auto* meta = handle.gridMetaData();
3633 EXPECT_TRUE(meta);
3634 EXPECT_EQ("torus_100", std::string(meta->shortGridName()));
3635 EXPECT_EQ(nanovdb::GridType::Float, meta->gridType());
3636 EXPECT_EQ(nanovdb::GridClass::FogVolume, meta->gridClass());
3637 auto* dstGrid = handle.grid<float>();
3638 EXPECT_TRUE(dstGrid);
3639 EXPECT_EQ("torus_100", std::string(dstGrid->gridName()));
3640 EXPECT_TRUE(dstGrid->hasBBox());
3641 EXPECT_TRUE(dstGrid->hasMinMax());
3642 EXPECT_TRUE(dstGrid->hasAverage());
3643 EXPECT_TRUE(dstGrid->hasStdDeviation());
3644
3645 //std::cerr << "bbox.min = (" << dstGrid->indexBBox()[0][0] << ", " << dstGrid->indexBBox()[0][1] << ", " << dstGrid->indexBBox()[0][2] << ")" << std::endl;
3646 //std::cerr << "bbox.max = (" << dstGrid->indexBBox()[1][0] << ", " << dstGrid->indexBBox()[1][1] << ", " << dstGrid->indexBBox()[1][2] << ")" << std::endl;
3647
3648 EXPECT_EQ(nanovdb::Coord(50 - 100 - 50, 50 - 50, 50 - 100 - 50), dstGrid->indexBBox()[0]);
3649 EXPECT_EQ(nanovdb::Coord(50 + 100 + 50, 50 + 50, 50 + 100 + 50), dstGrid->indexBBox()[1]);
3650
3651 auto dstAcc = dstGrid->getAccessor();
3652 EXPECT_EQ(0.0f, dstAcc.getValue(nanovdb::Coord(50)));
3653 EXPECT_FALSE(dstAcc.isActive(nanovdb::Coord(50)));
3654 EXPECT_EQ(1.0f, dstAcc.getValue(nanovdb::Coord(150, 50, 50)));
3655 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(150, 50, 50)));
3656 EXPECT_EQ(0.0f, dstAcc.getValue(nanovdb::Coord(200, 50, 50)));
3657 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(200, 50, 50)));
3658 EXPECT_EQ(0.0f, dstAcc.getValue(nanovdb::Coord(201, 50, 50)));
3659 EXPECT_FALSE(dstAcc.isActive(nanovdb::Coord(201, 50, 50)));
3660 EXPECT_EQ(1.0f / 3.0f, dstAcc.getValue(nanovdb::Coord(199, 50, 50)));
3661 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(199, 50, 50)));
3662 EXPECT_EQ(2.0f / 3.0f, dstAcc.getValue(nanovdb::Coord(198, 50, 50)));
3663 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(198, 50, 50)));
3664 } // createFogVolumeTorus
3665
TEST_F(TestNanoVDB,createLevelSetBox)3666 TEST_F(TestNanoVDB, createLevelSetBox)
3667 {
3668 auto handle = nanovdb::createLevelSetBox<float>(40.0f, 60.0f, 80.0f, nanovdb::Vec3f(50),
3669 1.0, 3.0, nanovdb::Vec3d(0), "box");
3670 EXPECT_TRUE(handle);
3671 EXPECT_EQ(1u, handle.gridCount());
3672 auto* meta = handle.gridMetaData();
3673 EXPECT_TRUE(meta);
3674 EXPECT_EQ("box", std::string(meta->shortGridName()));
3675 EXPECT_EQ(nanovdb::GridType::Float, meta->gridType());
3676 EXPECT_EQ(nanovdb::GridClass::LevelSet, meta->gridClass());
3677 auto* dstGrid = handle.grid<float>();
3678 EXPECT_TRUE(dstGrid);
3679 EXPECT_EQ("box", std::string(dstGrid->gridName()));
3680 EXPECT_TRUE(dstGrid->hasBBox());
3681 EXPECT_TRUE(dstGrid->hasMinMax());
3682 EXPECT_TRUE(dstGrid->hasAverage());
3683 EXPECT_TRUE(dstGrid->hasStdDeviation());
3684
3685 EXPECT_EQ(nanovdb::Coord(50 - 20 - 2, 50 - 30 - 2, 50 - 40 - 2), dstGrid->indexBBox()[0]);
3686 EXPECT_EQ(nanovdb::Coord(50 + 20 + 2, 50 + 30 + 2, 50 + 40 + 2), dstGrid->indexBBox()[1]);
3687
3688 auto dstAcc = dstGrid->getAccessor();
3689 EXPECT_EQ(-3.0f, dstAcc.getValue(nanovdb::Coord(50)));
3690 EXPECT_FALSE(dstAcc.isActive(nanovdb::Coord(50)));
3691 EXPECT_EQ(2.0f, dstAcc.getValue(nanovdb::Coord(72, 50, 50)));
3692 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(72, 50, 50)));
3693 EXPECT_EQ(0.0f, dstAcc.getValue(nanovdb::Coord(70, 50, 50)));
3694 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(70, 50, 50)));
3695 EXPECT_EQ(1.0f, dstAcc.getValue(nanovdb::Coord(71, 50, 50)));
3696 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(71, 50, 50)));
3697 EXPECT_EQ(-2.0f, dstAcc.getValue(nanovdb::Coord(68, 50, 50)));
3698 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(68, 50, 50)));
3699
3700 } // createLevelSetBox
3701
TEST_F(TestNanoVDB,createFogVolumeBox)3702 TEST_F(TestNanoVDB, createFogVolumeBox)
3703 {
3704 auto handle = nanovdb::createFogVolumeBox<float>(40.0f, 60.0f, 80.0f, nanovdb::Vec3f(50),
3705 1.0, 3.0, nanovdb::Vec3d(0), "box");
3706 EXPECT_TRUE(handle);
3707 EXPECT_EQ(1u, handle.gridCount());
3708 auto* meta = handle.gridMetaData();
3709 EXPECT_TRUE(meta);
3710 EXPECT_EQ("box", std::string(meta->shortGridName()));
3711 EXPECT_EQ(nanovdb::GridType::Float, meta->gridType());
3712 EXPECT_EQ(nanovdb::GridClass::FogVolume, meta->gridClass());
3713 auto* dstGrid = handle.grid<float>();
3714 EXPECT_TRUE(dstGrid);
3715 EXPECT_EQ("box", std::string(dstGrid->gridName()));
3716 EXPECT_TRUE(dstGrid->hasBBox());
3717 EXPECT_TRUE(dstGrid->hasMinMax());
3718 EXPECT_TRUE(dstGrid->hasAverage());
3719 EXPECT_TRUE(dstGrid->hasStdDeviation());
3720
3721 EXPECT_EQ(nanovdb::Coord(50 - 20, 50 - 30, 50 - 40), dstGrid->indexBBox()[0]);
3722 EXPECT_EQ(nanovdb::Coord(50 + 20, 50 + 30, 50 + 40), dstGrid->indexBBox()[1]);
3723
3724 auto dstAcc = dstGrid->getAccessor();
3725 EXPECT_EQ(1.0f, dstAcc.getValue(nanovdb::Coord(50)));
3726 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(50)));
3727 EXPECT_EQ(0.0f, dstAcc.getValue(nanovdb::Coord(72, 50, 50)));
3728 EXPECT_FALSE(dstAcc.isActive(nanovdb::Coord(72, 50, 50)));
3729 EXPECT_EQ(0.0f, dstAcc.getValue(nanovdb::Coord(70, 50, 50)));
3730 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(70, 50, 50)));
3731 EXPECT_EQ(1.0f / 3.0f, dstAcc.getValue(nanovdb::Coord(69, 50, 50)));
3732 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(69, 50, 50)));
3733 EXPECT_EQ(2.0f / 3.0f, dstAcc.getValue(nanovdb::Coord(68, 50, 50)));
3734 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(68, 50, 50)));
3735
3736 } // createFogVolumeBox
3737
TEST_F(TestNanoVDB,createLevelSetOctahedron)3738 TEST_F(TestNanoVDB, createLevelSetOctahedron)
3739 {
3740 auto handle = nanovdb::createLevelSetOctahedron<float>(100.0f, nanovdb::Vec3f(50),
3741 1.0f, 3.0f, nanovdb::Vec3d(0), "octahedron");
3742 EXPECT_TRUE(handle);
3743 EXPECT_EQ(1u, handle.gridCount());
3744 auto* meta = handle.gridMetaData();
3745 EXPECT_TRUE(meta);
3746 EXPECT_EQ("octahedron", std::string(meta->shortGridName()));
3747 EXPECT_EQ(nanovdb::GridType::Float, meta->gridType());
3748 EXPECT_EQ(nanovdb::GridClass::LevelSet, meta->gridClass());
3749 auto* dstGrid = handle.grid<float>();
3750 EXPECT_TRUE(dstGrid);
3751 EXPECT_EQ("octahedron", std::string(dstGrid->gridName()));
3752 EXPECT_TRUE(dstGrid->hasBBox());
3753 EXPECT_TRUE(dstGrid->hasMinMax());
3754 EXPECT_TRUE(dstGrid->hasAverage());
3755 EXPECT_TRUE(dstGrid->hasStdDeviation());
3756
3757 EXPECT_EQ(nanovdb::Coord(50 - 100/2 - 2), dstGrid->indexBBox()[0]);
3758 EXPECT_EQ(nanovdb::Coord(50 + 100/2 + 2), dstGrid->indexBBox()[1]);
3759
3760 auto dstAcc = dstGrid->getAccessor();
3761 EXPECT_EQ(-3.0f, dstAcc.getValue(nanovdb::Coord(50)));
3762 EXPECT_FALSE(dstAcc.isActive(nanovdb::Coord(50)));
3763 EXPECT_EQ(2.0f, dstAcc.getValue(nanovdb::Coord(102, 50, 50)));
3764 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(102, 50, 50)));
3765 EXPECT_EQ(0.0f, dstAcc.getValue(nanovdb::Coord(100, 50, 50)));
3766 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(100, 50, 50)));
3767 EXPECT_EQ(1.0f, dstAcc.getValue(nanovdb::Coord(101, 50, 50)));
3768 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(101, 50, 50)));
3769 EXPECT_EQ(-nanovdb::Sqrt(4.0f/3.0f), dstAcc.getValue(nanovdb::Coord(98, 50, 50)));
3770 EXPECT_TRUE(dstAcc.isActive(nanovdb::Coord(98, 50, 50)));
3771
3772 } // createLevelSetOctahedron
3773
3774 #if !defined(_MSC_VER)
TEST_F(TestNanoVDB,CNanoVDBSize)3775 TEST_F(TestNanoVDB, CNanoVDBSize)
3776 {
3777 // Verify the sizes of structures are what we expect.
3778 EXPECT_EQ(sizeof(cnanovdb_mask3), sizeof(nanovdb::Mask<3>));
3779 EXPECT_EQ(sizeof(cnanovdb_mask4), sizeof(nanovdb::Mask<4>));
3780 EXPECT_EQ(sizeof(cnanovdb_mask5), sizeof(nanovdb::Mask<5>));
3781 EXPECT_EQ(sizeof(cnanovdb_map), sizeof(nanovdb::Map));
3782 EXPECT_EQ(sizeof(cnanovdb_coord), sizeof(nanovdb::Coord));
3783 EXPECT_EQ(sizeof(cnanovdb_Vec3F), sizeof(nanovdb::Vec3f));
3784
3785 EXPECT_EQ(sizeof(cnanovdb_node0F), sizeof(nanovdb::LeafNode<float>));
3786 EXPECT_EQ(sizeof(cnanovdb_node1F), sizeof(nanovdb::InternalNode<nanovdb::LeafNode<float>>));
3787 EXPECT_EQ(sizeof(cnanovdb_node2F), sizeof(nanovdb::InternalNode<nanovdb::InternalNode<nanovdb::LeafNode<float>>>));
3788 EXPECT_EQ(sizeof(cnanovdb_rootdataF), sizeof(nanovdb::NanoRoot<float>));
3789
3790 EXPECT_EQ(sizeof(cnanovdb_node0F3), sizeof(nanovdb::LeafNode<nanovdb::Vec3f>));
3791 EXPECT_EQ(sizeof(cnanovdb_node1F3), sizeof(nanovdb::InternalNode<nanovdb::LeafNode<nanovdb::Vec3f>>));
3792 EXPECT_EQ(sizeof(cnanovdb_node2F3), sizeof(nanovdb::InternalNode<nanovdb::InternalNode<nanovdb::LeafNode<nanovdb::Vec3f>>>));
3793 EXPECT_EQ(sizeof(cnanovdb_rootdataF3), sizeof(nanovdb::NanoRoot<nanovdb::Vec3f>));
3794 EXPECT_EQ(sizeof(cnanovdb_treedata), sizeof(nanovdb::NanoTree<float>));
3795 EXPECT_EQ(sizeof(cnanovdb_gridblindmetadata), sizeof(nanovdb::GridBlindMetaData));
3796 EXPECT_EQ(sizeof(cnanovdb_griddata), sizeof(nanovdb::NanoGrid<float>));
3797 } // CNanoVDBSize
3798 #endif
3799
3800 #if !defined(DISABLE_PNANOVDB) && !defined(_MSC_VER)
TEST_F(TestNanoVDB,PNanoVDB_Basic)3801 TEST_F(TestNanoVDB, PNanoVDB_Basic)
3802 {
3803 EXPECT_EQ(NANOVDB_MAGIC_NUMBER, PNANOVDB_MAGIC_NUMBER);
3804
3805 EXPECT_EQ(NANOVDB_MAJOR_VERSION_NUMBER, PNANOVDB_MAJOR_VERSION_NUMBER);
3806 EXPECT_EQ(NANOVDB_MINOR_VERSION_NUMBER, PNANOVDB_MINOR_VERSION_NUMBER);
3807 EXPECT_EQ(NANOVDB_PATCH_VERSION_NUMBER, PNANOVDB_PATCH_VERSION_NUMBER);
3808
3809 EXPECT_EQ((int)nanovdb::GridType::Unknown, PNANOVDB_GRID_TYPE_UNKNOWN);
3810 EXPECT_EQ((int)nanovdb::GridType::Float, PNANOVDB_GRID_TYPE_FLOAT);
3811 EXPECT_EQ((int)nanovdb::GridType::Double, PNANOVDB_GRID_TYPE_DOUBLE);
3812 EXPECT_EQ((int)nanovdb::GridType::Int16, PNANOVDB_GRID_TYPE_INT16);
3813 EXPECT_EQ((int)nanovdb::GridType::Int32, PNANOVDB_GRID_TYPE_INT32);
3814 EXPECT_EQ((int)nanovdb::GridType::Int64, PNANOVDB_GRID_TYPE_INT64);
3815 EXPECT_EQ((int)nanovdb::GridType::Vec3f, PNANOVDB_GRID_TYPE_VEC3F);
3816 EXPECT_EQ((int)nanovdb::GridType::Vec3d, PNANOVDB_GRID_TYPE_VEC3D);
3817 EXPECT_EQ((int)nanovdb::GridType::Mask, PNANOVDB_GRID_TYPE_MASK);
3818 EXPECT_EQ((int)nanovdb::GridType::Half, PNANOVDB_GRID_TYPE_HALF);
3819 EXPECT_EQ((int)nanovdb::GridType::UInt32, PNANOVDB_GRID_TYPE_UINT32);
3820 EXPECT_EQ((int)nanovdb::GridType::Boolean, PNANOVDB_GRID_TYPE_BOOLEAN);
3821 EXPECT_EQ((int)nanovdb::GridType::RGBA8, PNANOVDB_GRID_TYPE_RGBA8);
3822 EXPECT_EQ((int)nanovdb::GridType::Fp4, PNANOVDB_GRID_TYPE_FP4);
3823 EXPECT_EQ((int)nanovdb::GridType::Fp8, PNANOVDB_GRID_TYPE_FP8);
3824 EXPECT_EQ((int)nanovdb::GridType::Fp16, PNANOVDB_GRID_TYPE_FP16);
3825 EXPECT_EQ((int)nanovdb::GridType::FpN, PNANOVDB_GRID_TYPE_FPN);
3826 EXPECT_EQ((int)nanovdb::GridType::Vec4f, PNANOVDB_GRID_TYPE_VEC4F);
3827 EXPECT_EQ((int)nanovdb::GridType::Vec4d, PNANOVDB_GRID_TYPE_VEC4D);
3828 EXPECT_EQ((int)nanovdb::GridType::End, PNANOVDB_GRID_TYPE_END);
3829
3830 EXPECT_EQ((int)nanovdb::GridClass::Unknown, PNANOVDB_GRID_CLASS_UNKNOWN);
3831 EXPECT_EQ((int)nanovdb::GridClass::LevelSet, PNANOVDB_GRID_CLASS_LEVEL_SET);
3832 EXPECT_EQ((int)nanovdb::GridClass::FogVolume, PNANOVDB_GRID_CLASS_FOG_VOLUME);
3833 EXPECT_EQ((int)nanovdb::GridClass::Staggered, PNANOVDB_GRID_CLASS_STAGGERED);
3834 EXPECT_EQ((int)nanovdb::GridClass::PointIndex, PNANOVDB_GRID_CLASS_POINT_INDEX);
3835 EXPECT_EQ((int)nanovdb::GridClass::PointData, PNANOVDB_GRID_CLASS_POINT_DATA);
3836 EXPECT_EQ((int)nanovdb::GridClass::Topology, PNANOVDB_GRID_CLASS_TOPOLOGY);
3837 EXPECT_EQ((int)nanovdb::GridClass::VoxelVolume,PNANOVDB_GRID_CLASS_VOXEL_VOLUME);
3838 EXPECT_EQ((int)nanovdb::GridClass::End, PNANOVDB_GRID_CLASS_END);
3839
3840 // check some basic types
3841 EXPECT_EQ(sizeof(pnanovdb_map_t), sizeof(nanovdb::Map));
3842 EXPECT_EQ(sizeof(pnanovdb_coord_t), sizeof(nanovdb::Coord));
3843 EXPECT_EQ(sizeof(pnanovdb_vec3_t), sizeof(nanovdb::Vec3f));
3844
3845 // check nanovdb::Map
3846 EXPECT_EQ((int)sizeof(nanovdb::Map), PNANOVDB_MAP_SIZE);
3847 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::Map, mMatF), PNANOVDB_MAP_OFF_MATF);
3848 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::Map, mInvMatF), PNANOVDB_MAP_OFF_INVMATF);
3849 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::Map, mVecF), PNANOVDB_MAP_OFF_VECF);
3850 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::Map, mTaperF), PNANOVDB_MAP_OFF_TAPERF);
3851 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::Map, mMatD), PNANOVDB_MAP_OFF_MATD);
3852 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::Map, mInvMatD), PNANOVDB_MAP_OFF_INVMATD);
3853 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::Map, mVecD), PNANOVDB_MAP_OFF_VECD);
3854 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::Map, mTaperD), PNANOVDB_MAP_OFF_TAPERD);
3855
3856 EXPECT_EQ((int)sizeof(pnanovdb_map_t), PNANOVDB_MAP_SIZE);
3857 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_map_t, matf), PNANOVDB_MAP_OFF_MATF);
3858 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_map_t, invmatf), PNANOVDB_MAP_OFF_INVMATF);
3859 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_map_t, vecf), PNANOVDB_MAP_OFF_VECF);
3860 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_map_t, taperf), PNANOVDB_MAP_OFF_TAPERF);
3861 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_map_t, matd), PNANOVDB_MAP_OFF_MATD);
3862 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_map_t, invmatd), PNANOVDB_MAP_OFF_INVMATD);
3863 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_map_t, vecd), PNANOVDB_MAP_OFF_VECD);
3864 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_map_t, taperd), PNANOVDB_MAP_OFF_TAPERD);
3865
3866 EXPECT_TRUE(validate_strides(printf));// checks strides and prints out new ones if they have changed
3867 }
3868
3869 template <typename ValueT>
validateLeaf(pnanovdb_grid_type_t grid_type)3870 void validateLeaf(pnanovdb_grid_type_t grid_type)
3871 {
3872 using nodedata0_t = typename nanovdb::LeafData<ValueT, nanovdb::Coord, nanovdb::Mask, 3>;
3873 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mMinimum), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_min);
3874 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mMaximum), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_max);
3875 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mAverage), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_ave);
3876 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mStdDevi), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_stddev);
3877 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mValues), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_table);
3878 }
3879
3880 template <>
validateLeaf(pnanovdb_grid_type_t grid_type)3881 void validateLeaf<nanovdb::Fp4>(pnanovdb_grid_type_t grid_type)
3882 {
3883 using nodedata0_t = typename nanovdb::LeafData<nanovdb::Fp4, nanovdb::Coord, nanovdb::Mask, 3>;
3884 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mMin), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_min);
3885 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mMax), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_max);
3886 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mAvg), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_ave);
3887 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mDev), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_stddev);
3888 }
3889
3890 template <>
validateLeaf(pnanovdb_grid_type_t grid_type)3891 void validateLeaf<nanovdb::Fp8>(pnanovdb_grid_type_t grid_type)
3892 {
3893 using nodedata0_t = typename nanovdb::LeafData<nanovdb::Fp8, nanovdb::Coord, nanovdb::Mask, 3>;
3894 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mMin), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_min);
3895 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mMax), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_max);
3896 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mAvg), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_ave);
3897 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mDev), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_stddev);
3898 }
3899
3900 template <>
validateLeaf(pnanovdb_grid_type_t grid_type)3901 void validateLeaf<nanovdb::Fp16>(pnanovdb_grid_type_t grid_type)
3902 {
3903 using nodedata0_t = typename nanovdb::LeafData<nanovdb::Fp16, nanovdb::Coord, nanovdb::Mask, 3>;
3904 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mMin), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_min);
3905 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mMax), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_max);
3906 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mAvg), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_ave);
3907 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mDev), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_stddev);
3908 }
3909
3910 template <>
validateLeaf(pnanovdb_grid_type_t grid_type)3911 void validateLeaf<nanovdb::FpN>(pnanovdb_grid_type_t grid_type)
3912 {
3913 using nodedata0_t = typename nanovdb::LeafData<nanovdb::FpN, nanovdb::Coord, nanovdb::Mask, 3>;
3914 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mMin), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_min);
3915 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mMax), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_max);
3916 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mAvg), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_ave);
3917 EXPECT_EQ(NANOVDB_OFFSETOF(nodedata0_t, mDev), (int)pnanovdb_grid_type_constants[grid_type].leaf_off_stddev);
3918 }
3919
3920 // template specializations for bool types
3921 template <>
validateLeaf(pnanovdb_grid_type_t grid_type)3922 void validateLeaf<bool>(pnanovdb_grid_type_t grid_type)
3923 {
3924 using nodeLeaf_t = typename nanovdb::LeafData<bool, nanovdb::Coord, nanovdb::Mask, 3>;
3925 using leaf_t = typename nanovdb::LeafNode<bool>;
3926
3927 EXPECT_EQ(sizeof(leaf_t), (pnanovdb_grid_type_constants[grid_type].leaf_size));
3928 EXPECT_EQ(NANOVDB_OFFSETOF(nodeLeaf_t, mBBoxMin), PNANOVDB_LEAF_OFF_BBOX_MIN);
3929 EXPECT_EQ(NANOVDB_OFFSETOF(nodeLeaf_t, mBBoxDif), PNANOVDB_LEAF_OFF_BBOX_DIF_AND_FLAGS);
3930 EXPECT_EQ(NANOVDB_OFFSETOF(nodeLeaf_t, mValueMask), PNANOVDB_LEAF_OFF_VALUE_MASK);
3931 }
3932
3933 // template specializations for nanovdb::ValueMask types
3934 template <>
validateLeaf(pnanovdb_grid_type_t grid_type)3935 void validateLeaf<nanovdb::ValueMask>(pnanovdb_grid_type_t grid_type)
3936 {
3937 using nodeLeaf_t = typename nanovdb::LeafData<nanovdb::ValueMask, nanovdb::Coord, nanovdb::Mask, 3>;
3938 using leaf_t = typename nanovdb::LeafNode<nanovdb::ValueMask>;
3939
3940 EXPECT_EQ(sizeof(leaf_t), (pnanovdb_grid_type_constants[grid_type].leaf_size));
3941 EXPECT_EQ(NANOVDB_OFFSETOF(nodeLeaf_t, mBBoxMin), PNANOVDB_LEAF_OFF_BBOX_MIN);
3942 EXPECT_EQ(NANOVDB_OFFSETOF(nodeLeaf_t, mBBoxDif), PNANOVDB_LEAF_OFF_BBOX_DIF_AND_FLAGS);
3943 EXPECT_EQ(NANOVDB_OFFSETOF(nodeLeaf_t, mValueMask), PNANOVDB_LEAF_OFF_VALUE_MASK);
3944 }
3945
TYPED_TEST(TestOffsets,PNanoVDB)3946 TYPED_TEST(TestOffsets, PNanoVDB)
3947 {
3948 using ValueType = TypeParam;
3949 pnanovdb_grid_type_t grid_type;
3950 if (std::is_same<float, TypeParam>::value) {
3951 grid_type = PNANOVDB_GRID_TYPE_FLOAT;
3952 } else if (std::is_same<double, TypeParam>::value) {
3953 grid_type = PNANOVDB_GRID_TYPE_DOUBLE;
3954 } else if (std::is_same<int16_t, TypeParam>::value) {
3955 grid_type = PNANOVDB_GRID_TYPE_INT16;
3956 } else if (std::is_same<int32_t, TypeParam>::value) {
3957 grid_type = PNANOVDB_GRID_TYPE_INT32;
3958 } else if (std::is_same<int64_t, TypeParam>::value) {
3959 grid_type = PNANOVDB_GRID_TYPE_INT64;
3960 } else if (std::is_same<nanovdb::Vec3f, TypeParam>::value) {
3961 grid_type = PNANOVDB_GRID_TYPE_VEC3F;
3962 } else if (std::is_same<nanovdb::Vec3d, TypeParam>::value) {
3963 grid_type = PNANOVDB_GRID_TYPE_VEC3D;
3964 } else if (std::is_same<uint32_t, TypeParam>::value) {
3965 grid_type = PNANOVDB_GRID_TYPE_UINT32;
3966 } else if (std::is_same<nanovdb::ValueMask, TypeParam>::value) {
3967 grid_type = PNANOVDB_GRID_TYPE_MASK;
3968 } else if (std::is_same<bool, TypeParam>::value) {
3969 grid_type = PNANOVDB_GRID_TYPE_BOOLEAN;
3970 } else if (std::is_same<nanovdb::Fp4, TypeParam>::value) {
3971 grid_type = PNANOVDB_GRID_TYPE_FP4;
3972 } else if (std::is_same<nanovdb::Fp8, TypeParam>::value) {
3973 grid_type = PNANOVDB_GRID_TYPE_FP8;
3974 } else if (std::is_same<nanovdb::Fp16, TypeParam>::value) {
3975 grid_type = PNANOVDB_GRID_TYPE_FP16;
3976 } else if (std::is_same<nanovdb::FpN, TypeParam>::value) {
3977 grid_type = PNANOVDB_GRID_TYPE_FPN;
3978 } else {
3979 EXPECT_TRUE(false);
3980 }
3981 static const uint32_t rootLevel = 3u;
3982 using nodeLeaf_t = typename nanovdb::LeafData<ValueType, nanovdb::Coord, nanovdb::Mask, 3>;
3983 using leaf_t = typename nanovdb::LeafNode<ValueType>;
3984 using nodeLower_t = typename nanovdb::InternalData<leaf_t, leaf_t::LOG2DIM + 1>;
3985 using lower_t = typename nanovdb::InternalNode<leaf_t>;
3986 using nodeUpper_t = typename nanovdb::InternalData<lower_t, lower_t::LOG2DIM + 1>;
3987 using upper_t = typename nanovdb::InternalNode<lower_t>;
3988 using rootdata_t = typename nanovdb::RootData<upper_t>;
3989 using root_t = typename nanovdb::RootNode<upper_t>;
3990 using rootdata_tile_t = typename nanovdb::RootData<upper_t>::Tile;
3991 using root_tile_t = typename nanovdb::RootNode<upper_t>::Tile;
3992 using treedata_t = typename nanovdb::TreeData<rootLevel>;
3993 using tree_t = typename nanovdb::Tree<root_t>;
3994
3995 // grid
3996 EXPECT_EQ((int)sizeof(nanovdb::GridData), PNANOVDB_GRID_SIZE);
3997 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mMagic), PNANOVDB_GRID_OFF_MAGIC);
3998 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mChecksum), PNANOVDB_GRID_OFF_CHECKSUM);
3999 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mVersion), PNANOVDB_GRID_OFF_VERSION);
4000 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mFlags), PNANOVDB_GRID_OFF_FLAGS);
4001 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mGridSize), PNANOVDB_GRID_OFF_GRID_SIZE);
4002 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mGridName), PNANOVDB_GRID_OFF_GRID_NAME);
4003 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mWorldBBox), PNANOVDB_GRID_OFF_WORLD_BBOX);
4004 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mMap), PNANOVDB_GRID_OFF_MAP);
4005 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mVoxelSize), PNANOVDB_GRID_OFF_VOXEL_SIZE);
4006 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mGridClass), PNANOVDB_GRID_OFF_GRID_CLASS);
4007 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mGridType), PNANOVDB_GRID_OFF_GRID_TYPE);
4008 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mBlindMetadataOffset), PNANOVDB_GRID_OFF_BLIND_METADATA_OFFSET);
4009 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridData, mBlindMetadataCount), PNANOVDB_GRID_OFF_BLIND_METADATA_COUNT);
4010
4011 EXPECT_EQ((int)sizeof(pnanovdb_grid_t), PNANOVDB_GRID_SIZE);
4012 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_grid_t, magic), PNANOVDB_GRID_OFF_MAGIC);
4013 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_grid_t, checksum), PNANOVDB_GRID_OFF_CHECKSUM);
4014 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_grid_t, version), PNANOVDB_GRID_OFF_VERSION);
4015 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_grid_t, flags), PNANOVDB_GRID_OFF_FLAGS);
4016 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_grid_t, grid_size), PNANOVDB_GRID_OFF_GRID_SIZE);
4017 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_grid_t, grid_name), PNANOVDB_GRID_OFF_GRID_NAME);
4018 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_grid_t, map), PNANOVDB_GRID_OFF_MAP);
4019 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_grid_t, world_bbox), PNANOVDB_GRID_OFF_WORLD_BBOX);
4020 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_grid_t, voxel_size), PNANOVDB_GRID_OFF_VOXEL_SIZE);
4021 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_grid_t, grid_class), PNANOVDB_GRID_OFF_GRID_CLASS);
4022 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_grid_t, grid_type), PNANOVDB_GRID_OFF_GRID_TYPE);
4023 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_grid_t, blind_metadata_offset), PNANOVDB_GRID_OFF_BLIND_METADATA_OFFSET);
4024 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_grid_t, blind_metadata_count), PNANOVDB_GRID_OFF_BLIND_METADATA_COUNT);
4025
4026 // test GridBlindMetaData
4027 EXPECT_EQ((int)sizeof(nanovdb::GridBlindMetaData), PNANOVDB_GRIDBLINDMETADATA_SIZE);
4028 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridBlindMetaData, mByteOffset), PNANOVDB_GRIDBLINDMETADATA_OFF_BYTE_OFFSET);
4029 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridBlindMetaData, mElementCount), PNANOVDB_GRIDBLINDMETADATA_OFF_ELEMENT_COUNT);
4030 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridBlindMetaData, mFlags), PNANOVDB_GRIDBLINDMETADATA_OFF_FLAGS);
4031 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridBlindMetaData, mSemantic), PNANOVDB_GRIDBLINDMETADATA_OFF_SEMANTIC);
4032 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridBlindMetaData, mDataClass), PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_CLASS);
4033 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridBlindMetaData, mDataType), PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_TYPE);
4034 EXPECT_EQ(NANOVDB_OFFSETOF(nanovdb::GridBlindMetaData, mName), PNANOVDB_GRIDBLINDMETADATA_OFF_NAME);
4035
4036 EXPECT_EQ((int)sizeof(pnanovdb_gridblindmetadata_t), PNANOVDB_GRIDBLINDMETADATA_SIZE);
4037 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_gridblindmetadata_t, byte_offset), PNANOVDB_GRIDBLINDMETADATA_OFF_BYTE_OFFSET);
4038 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_gridblindmetadata_t, element_count), PNANOVDB_GRIDBLINDMETADATA_OFF_ELEMENT_COUNT);
4039 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_gridblindmetadata_t, flags), PNANOVDB_GRIDBLINDMETADATA_OFF_FLAGS);
4040 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_gridblindmetadata_t, semantic), PNANOVDB_GRIDBLINDMETADATA_OFF_SEMANTIC);
4041 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_gridblindmetadata_t, data_class), PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_CLASS);
4042 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_gridblindmetadata_t, data_type), PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_TYPE);
4043 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_gridblindmetadata_t, name), PNANOVDB_GRIDBLINDMETADATA_OFF_NAME);
4044
4045 // test tree
4046 EXPECT_EQ((int)sizeof(tree_t), PNANOVDB_TREE_SIZE);
4047 EXPECT_EQ(NANOVDB_OFFSETOF(treedata_t, mNodeOffset[0]), PNANOVDB_TREE_OFF_NODE_OFFSET_LEAF);
4048 EXPECT_EQ(NANOVDB_OFFSETOF(treedata_t, mNodeOffset[1]), PNANOVDB_TREE_OFF_NODE_OFFSET_LOWER);
4049 EXPECT_EQ(NANOVDB_OFFSETOF(treedata_t, mNodeOffset[2]), PNANOVDB_TREE_OFF_NODE_OFFSET_UPPER);
4050 EXPECT_EQ(NANOVDB_OFFSETOF(treedata_t, mNodeOffset[3]), PNANOVDB_TREE_OFF_NODE_OFFSET_ROOT);
4051 EXPECT_EQ(NANOVDB_OFFSETOF(treedata_t, mNodeCount[0]), PNANOVDB_TREE_OFF_NODE_COUNT_LEAF);
4052 EXPECT_EQ(NANOVDB_OFFSETOF(treedata_t, mNodeCount[1]), PNANOVDB_TREE_OFF_NODE_COUNT_LOWER);
4053 EXPECT_EQ(NANOVDB_OFFSETOF(treedata_t, mNodeCount[2]), PNANOVDB_TREE_OFF_NODE_COUNT_UPPER);
4054 EXPECT_EQ(NANOVDB_OFFSETOF(treedata_t, mTileCount[0]), PNANOVDB_TREE_OFF_TILE_COUNT_LEAF);
4055 EXPECT_EQ(NANOVDB_OFFSETOF(treedata_t, mTileCount[1]), PNANOVDB_TREE_OFF_TILE_COUNT_LOWER);
4056 EXPECT_EQ(NANOVDB_OFFSETOF(treedata_t, mTileCount[2]), PNANOVDB_TREE_OFF_TILE_COUNT_UPPER);
4057 EXPECT_EQ(NANOVDB_OFFSETOF(treedata_t, mVoxelCount), PNANOVDB_TREE_OFF_VOXEL_COUNT);
4058
4059 EXPECT_EQ((int)sizeof(pnanovdb_tree_t), PNANOVDB_TREE_SIZE);
4060 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_tree_t, node_offset_leaf), PNANOVDB_TREE_OFF_NODE_OFFSET_LEAF);
4061 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_tree_t, node_offset_lower), PNANOVDB_TREE_OFF_NODE_OFFSET_LOWER);
4062 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_tree_t, node_offset_upper), PNANOVDB_TREE_OFF_NODE_OFFSET_UPPER);
4063 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_tree_t, node_offset_root), PNANOVDB_TREE_OFF_NODE_OFFSET_ROOT);
4064 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_tree_t, node_count_leaf), PNANOVDB_TREE_OFF_NODE_COUNT_LEAF);
4065 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_tree_t, node_count_lower), PNANOVDB_TREE_OFF_NODE_COUNT_LOWER);
4066 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_tree_t, node_count_upper), PNANOVDB_TREE_OFF_NODE_COUNT_UPPER);
4067 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_tree_t, tile_count_leaf), PNANOVDB_TREE_OFF_TILE_COUNT_LEAF);
4068 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_tree_t, tile_count_lower), PNANOVDB_TREE_OFF_TILE_COUNT_LOWER);
4069 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_tree_t, tile_count_upper), PNANOVDB_TREE_OFF_TILE_COUNT_UPPER);
4070 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_tree_t, voxel_count), PNANOVDB_TREE_OFF_VOXEL_COUNT);
4071
4072 // background value can start at pad1
4073 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_root_t, pad1), PNANOVDB_ROOT_BASE_SIZE);
4074 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_root_t, bbox_min), PNANOVDB_ROOT_OFF_BBOX_MIN);
4075 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_root_t, bbox_max), PNANOVDB_ROOT_OFF_BBOX_MAX);
4076 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_root_t, table_size), PNANOVDB_ROOT_OFF_TABLE_SIZE);
4077
4078 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_root_tile_t, pad1), PNANOVDB_ROOT_TILE_BASE_SIZE);
4079 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_root_tile_t, key), PNANOVDB_ROOT_TILE_OFF_KEY);
4080 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_root_tile_t, child), PNANOVDB_ROOT_TILE_OFF_CHILD);
4081 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_root_tile_t, state), PNANOVDB_ROOT_TILE_OFF_STATE);
4082
4083 EXPECT_EQ((int)sizeof(pnanovdb_upper_t), PNANOVDB_UPPER_BASE_SIZE);
4084 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_upper_t, bbox_min), PNANOVDB_UPPER_OFF_BBOX_MIN);
4085 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_upper_t, bbox_max), PNANOVDB_UPPER_OFF_BBOX_MAX);
4086 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_upper_t, flags), PNANOVDB_UPPER_OFF_FLAGS);
4087 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_upper_t, value_mask), PNANOVDB_UPPER_OFF_VALUE_MASK);
4088 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_upper_t, child_mask), PNANOVDB_UPPER_OFF_CHILD_MASK);
4089
4090 EXPECT_EQ((int)sizeof(pnanovdb_lower_t), PNANOVDB_LOWER_BASE_SIZE);
4091 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_lower_t, bbox_min), PNANOVDB_LOWER_OFF_BBOX_MIN);
4092 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_lower_t, bbox_max), PNANOVDB_LOWER_OFF_BBOX_MAX);
4093 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_lower_t, flags), PNANOVDB_LOWER_OFF_FLAGS);
4094 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_lower_t, value_mask), PNANOVDB_LOWER_OFF_VALUE_MASK);
4095 EXPECT_EQ(NANOVDB_OFFSETOF(pnanovdb_lower_t, child_mask), PNANOVDB_LOWER_OFF_CHILD_MASK);
4096
4097 EXPECT_EQ((uint)sizeof(root_t), (pnanovdb_grid_type_constants[grid_type].root_size));
4098 EXPECT_EQ(NANOVDB_OFFSETOF(rootdata_t, mBBox.mCoord[0]), PNANOVDB_ROOT_OFF_BBOX_MIN);
4099 EXPECT_EQ(NANOVDB_OFFSETOF(rootdata_t, mBBox.mCoord[1]), PNANOVDB_ROOT_OFF_BBOX_MAX);
4100 EXPECT_EQ(NANOVDB_OFFSETOF(rootdata_t, mTableSize), PNANOVDB_ROOT_OFF_TABLE_SIZE);
4101 EXPECT_EQ((uint)NANOVDB_OFFSETOF(rootdata_t, mBackground), pnanovdb_grid_type_constants[grid_type].root_off_background);
4102 EXPECT_EQ((uint)NANOVDB_OFFSETOF(rootdata_t, mMinimum), pnanovdb_grid_type_constants[grid_type].root_off_min);
4103 EXPECT_EQ((uint)NANOVDB_OFFSETOF(rootdata_t, mMaximum), pnanovdb_grid_type_constants[grid_type].root_off_max);
4104 EXPECT_EQ((uint)NANOVDB_OFFSETOF(rootdata_t, mAverage), pnanovdb_grid_type_constants[grid_type].root_off_ave);
4105 EXPECT_EQ((uint)NANOVDB_OFFSETOF(rootdata_t, mStdDevi), pnanovdb_grid_type_constants[grid_type].root_off_stddev);
4106
4107 EXPECT_EQ((uint)sizeof(root_tile_t), (pnanovdb_grid_type_constants[grid_type].root_tile_size));
4108 EXPECT_EQ(NANOVDB_OFFSETOF(rootdata_tile_t, key), PNANOVDB_ROOT_TILE_OFF_KEY);
4109 EXPECT_EQ(NANOVDB_OFFSETOF(rootdata_tile_t, child), PNANOVDB_ROOT_TILE_OFF_CHILD);
4110 EXPECT_EQ(NANOVDB_OFFSETOF(rootdata_tile_t, state), PNANOVDB_ROOT_TILE_OFF_STATE);
4111 EXPECT_EQ((uint)NANOVDB_OFFSETOF(rootdata_tile_t, value), pnanovdb_grid_type_constants[grid_type].root_tile_off_value);
4112
4113 EXPECT_EQ((uint)sizeof(upper_t), (pnanovdb_grid_type_constants[grid_type].upper_size));
4114 EXPECT_EQ(NANOVDB_OFFSETOF(nodeUpper_t, mBBox.mCoord[0]), PNANOVDB_UPPER_OFF_BBOX_MIN);
4115 EXPECT_EQ(NANOVDB_OFFSETOF(nodeUpper_t, mBBox.mCoord[1]), PNANOVDB_UPPER_OFF_BBOX_MAX);
4116 EXPECT_EQ(NANOVDB_OFFSETOF(nodeUpper_t, mFlags), PNANOVDB_UPPER_OFF_FLAGS);
4117 EXPECT_EQ(NANOVDB_OFFSETOF(nodeUpper_t, mValueMask), PNANOVDB_UPPER_OFF_VALUE_MASK);
4118 EXPECT_EQ(NANOVDB_OFFSETOF(nodeUpper_t, mChildMask), PNANOVDB_UPPER_OFF_CHILD_MASK);
4119 EXPECT_EQ((uint)NANOVDB_OFFSETOF(nodeUpper_t, mMinimum), pnanovdb_grid_type_constants[grid_type].upper_off_min);
4120 EXPECT_EQ((uint)NANOVDB_OFFSETOF(nodeUpper_t, mMaximum), pnanovdb_grid_type_constants[grid_type].upper_off_max);
4121 EXPECT_EQ((uint)NANOVDB_OFFSETOF(nodeUpper_t, mAverage), pnanovdb_grid_type_constants[grid_type].upper_off_ave);
4122 EXPECT_EQ((uint)NANOVDB_OFFSETOF(nodeUpper_t, mStdDevi), pnanovdb_grid_type_constants[grid_type].upper_off_stddev);
4123 EXPECT_EQ((uint)NANOVDB_OFFSETOF(nodeUpper_t, mTable), pnanovdb_grid_type_constants[grid_type].upper_off_table);
4124
4125 EXPECT_EQ((uint)sizeof(lower_t), (pnanovdb_grid_type_constants[grid_type].lower_size));
4126 EXPECT_EQ(NANOVDB_OFFSETOF(nodeLower_t, mBBox.mCoord[0]), PNANOVDB_LOWER_OFF_BBOX_MIN);
4127 EXPECT_EQ(NANOVDB_OFFSETOF(nodeLower_t, mBBox.mCoord[1]), PNANOVDB_LOWER_OFF_BBOX_MAX);
4128 EXPECT_EQ(NANOVDB_OFFSETOF(nodeLower_t, mFlags), PNANOVDB_LOWER_OFF_FLAGS);
4129 EXPECT_EQ(NANOVDB_OFFSETOF(nodeLower_t, mValueMask), PNANOVDB_LOWER_OFF_VALUE_MASK);
4130 EXPECT_EQ(NANOVDB_OFFSETOF(nodeLower_t, mChildMask), PNANOVDB_LOWER_OFF_CHILD_MASK);
4131 EXPECT_EQ((uint)NANOVDB_OFFSETOF(nodeLower_t, mMinimum), pnanovdb_grid_type_constants[grid_type].lower_off_min);
4132 EXPECT_EQ((uint)NANOVDB_OFFSETOF(nodeLower_t, mMaximum), pnanovdb_grid_type_constants[grid_type].lower_off_max);
4133 EXPECT_EQ((uint)NANOVDB_OFFSETOF(nodeLower_t, mAverage), pnanovdb_grid_type_constants[grid_type].lower_off_ave);
4134 EXPECT_EQ((uint)NANOVDB_OFFSETOF(nodeLower_t, mStdDevi), pnanovdb_grid_type_constants[grid_type].lower_off_stddev);
4135 EXPECT_EQ((uint)NANOVDB_OFFSETOF(nodeLower_t, mTable), pnanovdb_grid_type_constants[grid_type].lower_off_table);
4136
4137 EXPECT_EQ(8u*sizeof(rootdata_t::mAverage), pnanovdb_grid_type_stat_strides_bits[grid_type]);
4138 EXPECT_EQ(8u*sizeof(rootdata_t::mStdDevi), pnanovdb_grid_type_stat_strides_bits[grid_type]);
4139 EXPECT_EQ(8u*sizeof(nodeUpper_t::mAverage), pnanovdb_grid_type_stat_strides_bits[grid_type]);
4140 EXPECT_EQ(8u*sizeof(nodeUpper_t::mStdDevi), pnanovdb_grid_type_stat_strides_bits[grid_type]);
4141 EXPECT_EQ(8u*sizeof(nodeLower_t::mAverage), pnanovdb_grid_type_stat_strides_bits[grid_type]);
4142 EXPECT_EQ(8u*sizeof(nodeLower_t::mStdDevi), pnanovdb_grid_type_stat_strides_bits[grid_type]);
4143
4144 // leaf nodes
4145 EXPECT_EQ(sizeof(leaf_t), (pnanovdb_grid_type_constants[grid_type].leaf_size));
4146 EXPECT_EQ(NANOVDB_OFFSETOF(nodeLeaf_t, mBBoxMin), PNANOVDB_LEAF_OFF_BBOX_MIN);
4147 EXPECT_EQ(NANOVDB_OFFSETOF(nodeLeaf_t, mBBoxDif), PNANOVDB_LEAF_OFF_BBOX_DIF_AND_FLAGS);
4148 EXPECT_EQ(NANOVDB_OFFSETOF(nodeLeaf_t, mValueMask), PNANOVDB_LEAF_OFF_VALUE_MASK);
4149 validateLeaf<ValueType>(grid_type);
4150 }// PNanoVDB
4151 #endif
4152
TEST_F(TestNanoVDB,GridStats)4153 TEST_F(TestNanoVDB, GridStats)
4154 {
4155 using GridT = nanovdb::NanoGrid<float>;
4156 Sphere<float> sphere(nanovdb::Vec3<float>(50), 50.0f);
4157 nanovdb::GridBuilder<float> builder(sphere.background(), nanovdb::GridClass::LevelSet);
4158 const nanovdb::CoordBBox bbox(nanovdb::Coord(-100), nanovdb::Coord(100));
4159 //mTimer.start("GridBuilder");
4160 builder(sphere, bbox);
4161 //mTimer.stop();
4162 auto handle1 = builder.getHandle<>(1.0, nanovdb::Vec3d(0.0), "test");
4163 auto handle2 = builder.getHandle<>(1.0, nanovdb::Vec3d(0.0), "test");
4164 EXPECT_TRUE(handle1);
4165 EXPECT_TRUE(handle2);
4166 GridT* grid1 = handle1.grid<float>();
4167 GridT* grid2 = handle2.grid<float>();
4168 EXPECT_TRUE(grid1);
4169 EXPECT_TRUE(grid2);
4170
4171 //std::cerr << "grid1 = " << grid1->indexBBox() << ", grid2 = " << grid2->indexBBox() << std::endl;
4172 EXPECT_EQ(grid1->activeVoxelCount(), grid2->activeVoxelCount());
4173 EXPECT_EQ(grid1->worldBBox(), grid2->worldBBox());
4174 EXPECT_EQ(grid1->indexBBox(), grid2->indexBBox());
4175 nanovdb::NodeManager<nanovdb::FloatGrid> mgr1(*grid1);
4176 nanovdb::NodeManager<nanovdb::FloatGrid> mgr2(*grid2);
4177
4178 { // reset stats in grid2
4179 //grid2->tree().data()->mVoxelCount = uint64_t(0);
4180 grid2->data()->mWorldBBox = nanovdb::BBox<nanovdb::Vec3R>();
4181 grid2->tree().root().data()->mBBox = nanovdb::BBox<nanovdb::Coord>();
4182 for (uint32_t i = 0; i < grid2->tree().nodeCount(0); ++i) {
4183 auto* leaf = mgr2.leaf(i);
4184 auto* data = leaf->data();
4185 data->mMinimum = data->mMaximum = 0.0f;
4186 data->mBBoxMin &= ~nanovdb::NanoLeaf<float>::MASK; /// set to origin!
4187 data->mBBoxDif[0] = data->mBBoxDif[1] = data->mBBoxDif[2] = uint8_t(255);
4188 EXPECT_EQ(data->mBBoxDif[0], uint8_t(255));
4189 }
4190 for (uint32_t i = 0; i < grid2->tree().nodeCount(1); ++i) {
4191 auto* node = mgr2.lower(i);
4192 auto* data = node->data();
4193 data->mMinimum = data->mMaximum = 0.0f;
4194 data->mBBox[0] &= ~nanovdb::NanoLower<float>::MASK; /// set to origin!
4195 data->mBBox[1] = nanovdb::Coord(0);
4196 }
4197 for (uint32_t i = 0; i < grid2->tree().nodeCount(2); ++i) {
4198 auto* node = mgr2.upper(i);
4199 auto* data = node->data();
4200 data->mMinimum = data->mMaximum = 0.0f;
4201 data->mBBox[0] &= ~nanovdb::NanoUpper<float>::MASK; /// set to origin!
4202 data->mBBox[1] = nanovdb::Coord(0);
4203 }
4204 }
4205 //std::cerr << "grid1 = " << grid1->indexBBox() << ", grid2 = " << grid2->indexBBox() << std::endl;
4206 //EXPECT_NE(grid1->activeVoxelCount(), grid2->activeVoxelCount());
4207 EXPECT_NE(grid1->indexBBox(), grid2->indexBBox());
4208 EXPECT_NE(grid1->worldBBox(), grid2->worldBBox());
4209
4210 { // check stats in grid2
4211 EXPECT_EQ(grid1->tree().nodeCount(0), grid2->tree().nodeCount(0));
4212
4213 for (uint32_t i = 0; i < grid2->tree().nodeCount(0); ++i) {
4214 auto* leaf1 = mgr1.leaf(i);
4215 auto* leaf2 = mgr2.leaf(i);
4216 EXPECT_NE(leaf1->minimum(), leaf2->minimum());
4217 EXPECT_NE(leaf1->maximum(), leaf2->maximum());
4218 EXPECT_NE(leaf1->bbox(), leaf2->bbox());
4219 }
4220
4221 EXPECT_EQ(grid1->tree().nodeCount(1), grid2->tree().nodeCount(1));
4222 for (uint32_t i = 0; i < grid2->tree().nodeCount(1); ++i) {
4223 auto* node1 = mgr1.lower(i);
4224 auto* node2 = mgr2.lower(i);
4225 EXPECT_NE(node1->minimum(), node2->minimum());
4226 EXPECT_NE(node1->maximum(), node2->maximum());
4227 EXPECT_NE(node1->bbox(), node2->bbox());
4228 }
4229 EXPECT_EQ(grid1->tree().nodeCount(2), grid2->tree().nodeCount(2));
4230 for (uint32_t i = 0; i < grid2->tree().nodeCount(2); ++i) {
4231 auto* node1 = mgr1.upper(i);
4232 auto* node2 = mgr2.upper(i);
4233 EXPECT_NE(node1->minimum(), node2->minimum());
4234 EXPECT_NE(node1->maximum(), node2->maximum());
4235 EXPECT_NE(node1->bbox(), node2->bbox());
4236 }
4237 }
4238
4239 //mTimer.start("GridStats");
4240 nanovdb::gridStats(*grid2);
4241 //mTimer.stop();
4242
4243 { // check stats in grid2
4244 EXPECT_EQ(grid1->tree().nodeCount(0), grid2->tree().nodeCount(0));
4245 for (uint32_t i = 0; i < grid2->tree().nodeCount(0); ++i) {
4246 auto* leaf1 = mgr1.leaf(i);
4247 auto* leaf2 = mgr2.leaf(i);
4248 EXPECT_EQ(leaf1->minimum(), leaf2->minimum());
4249 EXPECT_EQ(leaf1->maximum(), leaf2->maximum());
4250 EXPECT_EQ(leaf1->bbox(), leaf2->bbox());
4251 }
4252 EXPECT_EQ(grid1->tree().nodeCount(1), grid2->tree().nodeCount(1));
4253 for (uint32_t i = 0; i < grid2->tree().nodeCount(1); ++i) {
4254 auto* node1 = mgr1.lower(i);
4255 auto* node2 = mgr2.lower(i);
4256 EXPECT_EQ(node1->minimum(), node2->minimum());
4257 EXPECT_EQ(node1->maximum(), node2->maximum());
4258 EXPECT_EQ(node1->bbox(), node2->bbox());
4259 }
4260 EXPECT_EQ(grid1->tree().nodeCount(2), grid2->tree().nodeCount(2));
4261 for (uint32_t i = 0; i < grid2->tree().nodeCount(2); ++i) {
4262 auto* node1 = mgr1.upper(i);
4263 auto* node2 = mgr2.upper(i);
4264 EXPECT_EQ(node1->minimum(), node2->minimum());
4265 EXPECT_EQ(node1->maximum(), node2->maximum());
4266 EXPECT_EQ(node1->bbox(), node2->bbox());
4267 }
4268 }
4269
4270 //std::cerr << "grid1 = " << grid1->indexBBox() << ", grid2 = " << grid2->indexBBox() << std::endl;
4271 EXPECT_EQ(grid1->activeVoxelCount(), grid2->activeVoxelCount());
4272 EXPECT_EQ(grid1->indexBBox(), grid2->indexBBox());
4273 EXPECT_EQ(grid1->worldBBox(), grid2->worldBBox());
4274
4275 } // GridStats
4276
TEST_F(TestNanoVDB,ScalarSampleFromVoxels)4277 TEST_F(TestNanoVDB, ScalarSampleFromVoxels)
4278 {
4279 // create a grid so sample from
4280 const float dx = 0.5f; // voxel size
4281 auto trilinearWorld = [&](const nanovdb::Vec3d& xyz) -> float {
4282 return 0.34f + 1.6f * xyz[0] + 6.7f * xyz[1] - 3.5f * xyz[2]; // index coordinates
4283 };
4284 auto trilinearIndex = [&](const nanovdb::Coord& ijk) -> float {
4285 return 0.34f + 1.6f * dx * ijk[0] + 6.7f * dx * ijk[1] - 3.5f * dx * ijk[2]; // index coordinates
4286 };
4287
4288 nanovdb::GridBuilder<float> builder(1.0f);
4289 const nanovdb::CoordBBox bbox(nanovdb::Coord(0), nanovdb::Coord(128));
4290 builder(trilinearIndex, bbox);
4291 auto handle = builder.getHandle<>(dx);
4292 EXPECT_TRUE(handle);
4293 EXPECT_EQ(1u, handle.gridCount());
4294 auto* grid = handle.grid<float>();
4295 EXPECT_TRUE(grid);
4296
4297 const nanovdb::Vec3d xyz(13.4, 24.67, 5.23); // in index space
4298 const nanovdb::Coord ijk(13, 25, 5); // in index space (nearest)
4299 const auto exact = trilinearWorld(grid->indexToWorld(xyz));
4300 const auto approx = trilinearIndex(ijk);
4301 //std::cerr << "Trilinear: exact = " << exact << ", approx = " << approx << std::endl;
4302
4303 auto acc = grid->getAccessor();
4304 auto sampler0 = nanovdb::createSampler<0>(grid->tree());
4305 auto sampler1 = nanovdb::createSampler<1>(acc);
4306 auto sampler2 = nanovdb::createSampler<2>(acc);
4307 auto sampler3 = nanovdb::createSampler<3>(acc);
4308 //std::cerr << "0'th order: v = " << sampler0(xyz) << std::endl;
4309 EXPECT_EQ(approx, sampler0(xyz));
4310 EXPECT_NE(exact, sampler0(xyz));
4311 //std::cerr << "1'th order: v = " << sampler1(xyz) << std::endl;
4312 EXPECT_NEAR(exact, sampler1(xyz), 1e-5);
4313 //std::cerr << "2'th order: v = " << sampler2(xyz) << std::endl;
4314 EXPECT_NEAR(exact, sampler2(xyz), 1e-4);
4315 //std::cerr << "3'rd order: v = " << sampler3(xyz) << std::endl;
4316 EXPECT_NEAR(exact, sampler3(xyz), 1e-5);
4317
4318 EXPECT_FALSE(sampler1.zeroCrossing());
4319 const auto gradIndex = sampler1.gradient(xyz); //in index space
4320 EXPECT_NEAR(1.6f, gradIndex[0] / dx, 2e-5);
4321 EXPECT_NEAR(6.7f, gradIndex[1] / dx, 2e-5);
4322 EXPECT_NEAR(-3.5f, gradIndex[2] / dx, 2e-5);
4323 const auto gradWorld = grid->indexToWorldGrad(gradIndex); // in world units
4324 EXPECT_NEAR(1.6f, gradWorld[0], 2e-5);
4325 EXPECT_NEAR(6.7f, gradWorld[1], 2e-5);
4326 EXPECT_NEAR(-3.5f, gradWorld[2], 2e-5);
4327
4328 EXPECT_EQ(grid->tree().getValue(ijk), sampler0.accessor().getValue(ijk));
4329 EXPECT_EQ(grid->tree().getValue(ijk), sampler1.accessor().getValue(ijk));
4330 EXPECT_EQ(grid->tree().getValue(ijk), sampler2.accessor().getValue(ijk));
4331 EXPECT_EQ(grid->tree().getValue(ijk), sampler3.accessor().getValue(ijk));
4332 } // ScalarSampleFromVoxels
4333
TEST_F(TestNanoVDB,VectorSampleFromVoxels)4334 TEST_F(TestNanoVDB, VectorSampleFromVoxels)
4335 {
4336 // create a grid so sample from
4337 const float dx = 0.5f; // voxel size
4338 auto trilinearWorld = [&](const nanovdb::Vec3d& xyz) -> nanovdb::Vec3f {
4339 return nanovdb::Vec3f(0.34f, 1.6f * xyz[0] + 6.7f * xyz[1], -3.5f * xyz[2]); // index coordinates
4340 };
4341 auto trilinearIndex = [&](const nanovdb::Coord& ijk) -> nanovdb::Vec3f {
4342 return nanovdb::Vec3f(0.34f, 1.6f * dx * ijk[0] + 6.7f * dx * ijk[1], -3.5f * dx * ijk[2]); // index coordinates
4343 };
4344
4345 nanovdb::GridBuilder<nanovdb::Vec3f> builder(nanovdb::Vec3f(1.0f));
4346 const nanovdb::CoordBBox bbox(nanovdb::Coord(0), nanovdb::Coord(128));
4347 builder(trilinearIndex, bbox);
4348 auto handle = builder.getHandle<>(dx);
4349 EXPECT_TRUE(handle);
4350 EXPECT_EQ(1u, handle.gridCount());
4351 auto* grid = handle.grid<nanovdb::Vec3f>();
4352 EXPECT_TRUE(grid);
4353
4354 const nanovdb::Vec3d ijk(13.4, 24.67, 5.23); // in index space
4355 const auto exact = trilinearWorld(grid->indexToWorld(ijk));
4356 const auto approx = trilinearIndex(nanovdb::Coord(13, 25, 5));
4357 //std::cerr << "Trilinear: exact = " << exact << ", approx = " << approx << std::endl;
4358
4359 auto acc = grid->getAccessor();
4360 auto sampler0 = nanovdb::createSampler<0>(acc);
4361 //std::cerr << "0'th order: v = " << sampler0(ijk) << std::endl;
4362 EXPECT_EQ(approx, sampler0(ijk));
4363
4364 auto sampler1 = nanovdb::createSampler<1>(acc); // faster since it's using an accessor!!!
4365 //std::cerr << "1'th order: v = " << sampler1(ijk) << std::endl;
4366 for (int i = 0; i < 3; ++i)
4367 EXPECT_NEAR(exact[i], sampler1(ijk)[i], 1e-5);
4368 //EXPECT_FALSE(sampler1.zeroCrossing());// triggeres a static_assert error
4369 //EXPECT_FALSE(sampler1.gradient(grid->indexToWorld(ijk)));// triggeres a static_assert error
4370
4371 nanovdb::SampleFromVoxels<nanovdb::NanoTree<nanovdb::Vec3f>, 3> sampler3(grid->tree());
4372 //auto sampler3 = nanovdb::createSampler<3>( acc );
4373 //std::cerr << "3'rd order: v = " << sampler3(ijk) << std::endl;
4374 for (int i = 0; i < 3; ++i)
4375 EXPECT_NEAR(exact[i], sampler3(ijk)[i], 1e-5);
4376
4377 } // VectorSampleFromVoxels
4378
TEST_F(TestNanoVDB,GridChecksum)4379 TEST_F(TestNanoVDB, GridChecksum)
4380 {
4381 EXPECT_TRUE(nanovdb::ChecksumMode::Disable < nanovdb::ChecksumMode::End);
4382 EXPECT_TRUE(nanovdb::ChecksumMode::Partial < nanovdb::ChecksumMode::End);
4383 EXPECT_TRUE(nanovdb::ChecksumMode::Full < nanovdb::ChecksumMode::End);
4384 EXPECT_TRUE(nanovdb::ChecksumMode::Default < nanovdb::ChecksumMode::End);
4385 EXPECT_NE(nanovdb::ChecksumMode::Disable, nanovdb::ChecksumMode::Partial);
4386 EXPECT_NE(nanovdb::ChecksumMode::Disable, nanovdb::ChecksumMode::Full);
4387 EXPECT_NE(nanovdb::ChecksumMode::Full, nanovdb::ChecksumMode::Partial);
4388 EXPECT_NE(nanovdb::ChecksumMode::Default, nanovdb::ChecksumMode::Disable);
4389 EXPECT_EQ(nanovdb::ChecksumMode::Default, nanovdb::ChecksumMode::Partial);
4390 EXPECT_NE(nanovdb::ChecksumMode::Default, nanovdb::ChecksumMode::Full);
4391
4392 nanovdb::CpuTimer<> timer;
4393 //timer.start("nanovdb::createLevelSetSphere");
4394 auto handle = nanovdb::createLevelSetSphere<float>(100.0f,
4395 nanovdb::Vec3f(50),
4396 1.0,
4397 3.0,
4398 nanovdb::Vec3d(0),
4399 "sphere_20",
4400 nanovdb::StatsMode::Disable,
4401 nanovdb::ChecksumMode::Disable);
4402 //timer.stop();
4403 EXPECT_TRUE(handle);
4404 EXPECT_EQ(1u, handle.gridCount());
4405 auto* grid = handle.grid<float>();
4406 EXPECT_TRUE(grid);
4407
4408 nanovdb::GridChecksum checksum1, checksum2, checksum3;
4409
4410 EXPECT_EQ(checksum1, checksum3);
4411
4412 //timer.start("Partial checksum");
4413 checksum3(*grid, nanovdb::ChecksumMode::Partial);
4414 //timer.stop();
4415
4416 EXPECT_NE(checksum1, checksum3);
4417
4418 //timer.start("Full checksum");
4419 checksum1(*grid, nanovdb::ChecksumMode::Full);
4420 //timer.stop();
4421
4422 checksum2(*grid, nanovdb::ChecksumMode::Full);
4423
4424 EXPECT_EQ(checksum1, checksum2);
4425
4426 auto* leaf = grid->tree().getFirstNode<0>();
4427 EXPECT_EQ(leaf, nanovdb::createLeafMgr(*grid)[0]);
4428
4429 leaf->data()->mValues[0] += 0.00001f; // slightly modify a single voxel value
4430
4431 checksum2(*grid, nanovdb::ChecksumMode::Full);
4432 EXPECT_NE(checksum1, checksum2);
4433
4434 leaf->data()->mValues[0] -= 0.00001f; // change back the single voxel value to it's original value
4435
4436 checksum2(*grid, nanovdb::ChecksumMode::Full);
4437 EXPECT_EQ(checksum1, checksum2);
4438
4439 leaf->data()->mValueMask.toggle(0); // change a single bit in a value mask
4440
4441 checksum2(*grid, nanovdb::ChecksumMode::Full);
4442 EXPECT_NE(checksum1, checksum2);
4443
4444 //timer.start("Incomplete checksum");
4445 checksum2(*grid, nanovdb::ChecksumMode::Partial);
4446 //timer.stop();
4447 EXPECT_EQ(checksum2, checksum3);
4448 } // GridChecksum
4449
TEST_F(TestNanoVDB,GridValidator)4450 TEST_F(TestNanoVDB, GridValidator)
4451 {
4452 nanovdb::CpuTimer<> timer;
4453 //timer.start("nanovdb::createLevelSetSphere");
4454 auto handle = nanovdb::createLevelSetSphere<float>(100.0f,
4455 nanovdb::Vec3f(50),
4456 1.0, 3.0,
4457 nanovdb::Vec3d(0),
4458 "sphere_20",
4459 nanovdb::StatsMode::All,
4460 nanovdb::ChecksumMode::Full);
4461 //timer.stop();
4462 EXPECT_TRUE(handle);
4463 EXPECT_EQ(1u, handle.gridCount());
4464 auto* grid = handle.grid<float>();
4465 EXPECT_TRUE(grid);
4466
4467 //timer.start("isValid - not detailed");
4468 EXPECT_TRUE(nanovdb::isValid(*grid, false, true));
4469 //timer.stop();
4470
4471 //timer.start("isValid - detailed");
4472 EXPECT_TRUE(nanovdb::isValid(*grid, true, true));
4473 //timer.stop();
4474
4475 //timer.start("Full checksum");
4476 auto fastChecksum = nanovdb::checksum(*grid, nanovdb::ChecksumMode::Full);
4477 //timer.stop();
4478 EXPECT_EQ(fastChecksum, nanovdb::checksum(*grid, nanovdb::ChecksumMode::Full));
4479
4480 auto mgr = nanovdb::createLeafMgr(*grid);
4481 auto* leaf = mgr[0];
4482
4483 leaf->data()->mValues[0] += 0.00001f; // slightly modify a single voxel value
4484
4485 EXPECT_NE(fastChecksum, nanovdb::checksum(*grid, nanovdb::ChecksumMode::Full));
4486 EXPECT_FALSE(nanovdb::isValid(*grid, true, false));
4487
4488 leaf->data()->mValues[0] -= 0.00001f; // change back the single voxel value to it's original value
4489
4490 EXPECT_EQ(fastChecksum, nanovdb::checksum(*grid, nanovdb::ChecksumMode::Full));
4491 EXPECT_TRUE(nanovdb::isValid(*grid, true, true));
4492
4493 leaf->data()->mValueMask.toggle(0); // change a singel bit in a value mask
4494
4495 EXPECT_NE(fastChecksum, nanovdb::checksum(*grid, nanovdb::ChecksumMode::Full));
4496 EXPECT_FALSE(nanovdb::isValid(*grid, true, false));
4497 } // GridValidator
4498
TEST_F(TestNanoVDB,RandomReadAccessor)4499 TEST_F(TestNanoVDB, RandomReadAccessor)
4500 {
4501 const float background = 0.0f;
4502 const int voxelCount = 512, min = -10000, max = 10000;
4503 std::srand(98765);
4504 auto op = [&](){return rand() % (max - min) + min;};
4505
4506 for (int i=0; i<10; ++i) {
4507 nanovdb::GridBuilder<float> builder(background);
4508 auto acc = builder.getAccessor();
4509 std::vector<nanovdb::Coord> voxels(voxelCount);
4510 for (int j=0; j<voxelCount; ++j) {
4511 auto &ijk = voxels[j];
4512 ijk[0] = op();
4513 ijk[1] = op();
4514 ijk[2] = op();
4515 acc.setValue(ijk, 1.0f*j);
4516 }
4517 auto gridHdl = builder.getHandle<>();
4518 EXPECT_TRUE(gridHdl);
4519 EXPECT_EQ(1u, gridHdl.gridCount());
4520 auto grid = gridHdl.grid<float>();
4521 EXPECT_TRUE(grid);
4522 const auto &root = grid->tree().root();
4523 #if 1
4524 auto acc0a = nanovdb::createAccessor<>(root);// no node caching
4525 auto acc1a = nanovdb::createAccessor<0>(root);// cache leaf node only
4526 auto acc1b = nanovdb::createAccessor<1>(root);// cache lower internal node only
4527 auto acc1c = nanovdb::createAccessor<2>(root);// cache upper internal node only
4528 auto acc2a = nanovdb::createAccessor<0, 1>(root);// cache leaf and lower internal nodes
4529 auto acc2b = nanovdb::createAccessor<1, 2>(root);// cache lower and upper internal nodes
4530 auto acc2c = nanovdb::createAccessor<0, 2>(root);// cache leaf and upper internal nodes
4531 auto acc3a = nanovdb::createAccessor<0, 1, 2>(root);// cache leaf and both intern node levels
4532 auto acc3b = root.getAccessor();// same as the one above where all levels are cached
4533 auto acc3c = nanovdb::DefaultReadAccessor<float>(root);// same as the one above where all levels are cached
4534 #else
4535 // Alternative (more verbose) way to create accessors
4536 auto acc0a = nanovdb::ReadAccessor<float>(root);// no node caching
4537 auto acc1a = nanovdb::ReadAccessor<float, 0>(root);// cache leaf node only
4538 auto acc1b = nanovdb::ReadAccessor<float, 1>(root);// cache lower internal node only
4539 auto acc1c = nanovdb::ReadAccessor<float, 2>(root);// cache upper internal node only
4540 auto acc2a = nanovdb::ReadAccessor<float, 0, 1>(root);// cache leaf and lower internal nodes
4541 auto acc2b = nanovdb::ReadAccessor<float, 1, 2>(root);// cache lower and upper internal nodes
4542 auto acc2c = nanovdb::ReadAccessor<float, 0, 2>(root);// cache leaf and upper internal nodes
4543 auto acc3a = nanovdb::ReadAccessor<float, 0, 1, 2>(root);// cache leaf and both intern node levels
4544 auto acc3b = nanovdb::DefaultReadAccessor<float>(root);// same as the one above where all levels are cached
4545 #endif
4546 for (int j=0; j<voxelCount; ++j) {
4547 const float v = 1.0f * j;
4548 const auto &ijk = voxels[j];
4549 //if (j<5) std::cerr << ijk << std::endl;
4550 EXPECT_EQ( v, acc0a.getValue(ijk) );
4551 EXPECT_EQ( v, acc1a.getValue(ijk) );
4552 EXPECT_EQ( v, acc1b.getValue(ijk) );
4553 EXPECT_EQ( v, acc1c.getValue(ijk) );
4554 EXPECT_EQ( v, acc2a.getValue(ijk) );
4555 EXPECT_EQ( v, acc2b.getValue(ijk) );
4556 EXPECT_EQ( v, acc2c.getValue(ijk) );
4557 EXPECT_EQ( v, acc3a.getValue(ijk) );
4558 EXPECT_EQ( v, acc3b.getValue(ijk) );
4559 EXPECT_EQ( v, acc3c.getValue(ijk) );
4560 }
4561 }
4562 }
4563
TEST_F(TestNanoVDB,StandardDeviation)4564 TEST_F(TestNanoVDB, StandardDeviation)
4565 {
4566 nanovdb::GridBuilder<float> builder(0.5f);
4567
4568 {
4569 auto acc = builder.getAccessor();
4570 acc.setValue(nanovdb::Coord(-1), 1.0f);
4571 acc.setValue(nanovdb::Coord(0), 2.0f);
4572 acc.setValue(nanovdb::Coord(1), 3.0f);
4573 acc.setValue(nanovdb::Coord(2), 0.0f);
4574 }
4575
4576 auto gridHdl = builder.getHandle<>();
4577 EXPECT_TRUE(gridHdl);
4578 auto grid = gridHdl.grid<float>();
4579 EXPECT_TRUE(grid);
4580 nanovdb::gridStats(*grid);
4581
4582 auto acc = grid->tree().getAccessor();
4583 {
4584 EXPECT_EQ( 1.0f, acc.getValue(nanovdb::Coord(-1)) );
4585 EXPECT_EQ( 2.0f, acc.getValue(nanovdb::Coord( 0)) );
4586 EXPECT_EQ( 3.0f, acc.getValue(nanovdb::Coord( 1)) );
4587 EXPECT_EQ( 0.0f, acc.getValue(nanovdb::Coord( 2)) );
4588 auto nodeInfo = acc.getNodeInfo(nanovdb::Coord(-1));
4589 EXPECT_EQ(nodeInfo.mAverage, 1.f);
4590 EXPECT_EQ(nodeInfo.mLevel, 0u);
4591 EXPECT_EQ(nodeInfo.mDim, 8u);
4592 }
4593 {
4594 auto nodeInfo = acc.getNodeInfo(nanovdb::Coord(1));
4595 EXPECT_EQ(nodeInfo.mAverage, (2.0f + 3.0f) / 3.0f);
4596 auto getStdDev = [&](int n, float a, float b, float c) {
4597 float m = (a + b + c) / n;
4598 float sd = sqrtf(((a - m) * (a - m) +
4599 (b - m) * (b - m) +
4600 (c - m) * (c - m)) /
4601 n);
4602 return sd;
4603 };
4604 EXPECT_NEAR(nodeInfo.mStdDevi, getStdDev(3.0f, 2.0f, 3.0f, 0), 1e-5);
4605 EXPECT_EQ(nodeInfo.mLevel, 0u);
4606 EXPECT_EQ(nodeInfo.mDim, 8u);
4607 }
4608 } // ReadAccessor
4609
TEST_F(TestNanoVDB,BoxStencil)4610 TEST_F(TestNanoVDB, BoxStencil)
4611 {
4612 const float a = 0.54f, b[3]={0.12f, 0.78f,-0.34f};
4613 const nanovdb::Coord min(-17, -10, -8), max(10, 21, 13);
4614 const nanovdb::CoordBBox bbox(min, max), bbox2(min, max.offsetBy(-1));
4615 nanovdb::GridBuilder<float> builder(0.0f);
4616 auto func = [&](const nanovdb::Coord &ijk) {
4617 return a + b[0]*ijk[0] + b[1]*ijk[1] + b[2]*ijk[2];
4618 };
4619 builder(func, bbox);
4620 auto handle = builder.getHandle();
4621 EXPECT_TRUE(handle);
4622 EXPECT_EQ(1u, handle.gridCount());
4623 auto* grid = handle.grid<float>();
4624 EXPECT_TRUE(grid);
4625 auto acc = grid->getAccessor();
4626 for (auto it = bbox.begin(); it; ++it) {
4627 EXPECT_EQ(func(*it), acc.getValue(*it));
4628 }
4629 auto func2 = [&](const nanovdb::Vec3f &xyz) {
4630 return a + b[0]*xyz[0] + b[1]*xyz[1] + b[2]*xyz[2];
4631 };
4632 nanovdb::BoxStencil<nanovdb::FloatGrid> s(*grid);
4633 for (auto it = bbox2.begin(); it; ++it) {
4634 const nanovdb::Coord p = *it;
4635 s.moveTo(p);
4636 const nanovdb::Vec3f xyz(p[0] + 0.12f, p[1] + 0.34f, p[2] + 0.07f);
4637 EXPECT_NEAR(func2(xyz), s.interpolation(xyz), 5e-6f);
4638 const auto grad = s.gradient(xyz);
4639 EXPECT_NEAR( b[0], grad[0], 3e-6f);
4640 EXPECT_NEAR( b[1], grad[1], 3e-6f);
4641 EXPECT_NEAR( b[2], grad[2], 3e-6f);
4642 }
4643 }// BoxStencil
4644
TEST_F(TestNanoVDB,CurvatureStencil)4645 TEST_F(TestNanoVDB, CurvatureStencil)
4646 {
4647 {// test of level set to sphere at (6,8,10) with R=10 and dx=0.5
4648 const float radius = 10.0f;
4649 const nanovdb::Vec3f center(6.0, 8.0, 10.0);//i.e. (12,16,20) in index space
4650 auto handle = nanovdb::createLevelSetSphere<float>(radius,
4651 center,
4652 0.5, // dx
4653 20.0); // half-width so dense inside
4654
4655 EXPECT_TRUE(handle);
4656 EXPECT_EQ(1u, handle.gridCount());
4657 auto* grid = handle.grid<float>();
4658 EXPECT_TRUE(grid);
4659
4660 nanovdb::CurvatureStencil<nanovdb::FloatGrid> cs(*grid);
4661 nanovdb::Coord xyz(20,16,20);//i.e. 8 voxel or 4 world units away from the center
4662 cs.moveTo(xyz);
4663
4664 EXPECT_NEAR(1.0/4.0, cs.meanCurvature(), 0.01);// 1/distance from center
4665 EXPECT_NEAR(1.0/4.0, cs.meanCurvatureNormGrad(), 0.01);// 1/distance from center
4666
4667 EXPECT_NEAR(1.0/16.0, cs.gaussianCurvature(), 0.01);// 1/distance^2 from center
4668 EXPECT_NEAR(1.0/16.0, cs.gaussianCurvatureNormGrad(), 0.01);// 1/distance^2 from center
4669
4670 //std::cerr << cs.gradient() << std::endl;
4671 EXPECT_NEAR( 1.0f, cs.gradient()[0], 1e-6f);
4672 EXPECT_NEAR( 0.0f, cs.gradient()[1], 1e-6f);
4673 EXPECT_NEAR( 0.0f, cs.gradient()[2], 1e-6f);
4674
4675 float mean, gaussian;
4676 cs.curvatures(mean, gaussian);
4677 EXPECT_NEAR(1.0/4.0, mean, 0.01);// 1/distance from center
4678 EXPECT_NEAR(1.0/16.0, gaussian, 0.01);// 1/distance^2 from center
4679
4680 float minCurv, maxCurv;
4681 cs.principalCurvatures(minCurv, maxCurv);
4682 EXPECT_NEAR(1.0/4.0, minCurv, 0.01);// 1/distance from center
4683 EXPECT_NEAR(1.0/4.0, maxCurv, 0.01);// 1/distance from center
4684
4685 xyz = nanovdb::Coord(12,16,10);//i.e. 10 voxel or 5 world units away from the center
4686 cs.moveTo(xyz);
4687 EXPECT_NEAR(1.0/5.0, cs.meanCurvature(), 0.01);// 1/distance from center
4688 EXPECT_NEAR(
4689 1.0/5.0, cs.meanCurvatureNormGrad(), 0.01);// 1/distance from center
4690
4691 EXPECT_NEAR(1.0/25.0, cs.gaussianCurvature(), 0.01);// 1/distance^2 from center
4692 EXPECT_NEAR(
4693 1.0/25.0, cs.gaussianCurvatureNormGrad(), 0.01);// 1/distance^2 from center
4694
4695 cs.principalCurvatures(minCurv, maxCurv);
4696 EXPECT_NEAR(1.0/5.0, minCurv, 0.01);// 1/distance from center
4697 EXPECT_NEAR(1.0/5.0, maxCurv, 0.01);// 1/distance from center
4698 EXPECT_NEAR(
4699 1.0/5.0, minCurv, 0.01);// 1/distance from center
4700 EXPECT_NEAR(
4701 1.0/5.0, maxCurv, 0.01);// 1/distance from center
4702
4703 cs.curvaturesNormGrad(mean, gaussian);
4704 EXPECT_NEAR(1.0/5.0, mean, 0.01);// 1/distance from center
4705 EXPECT_NEAR(1.0/25.0, gaussian, 0.01);// 1/distance^2 from center
4706 }
4707
4708 {// test sparse level set sphere
4709 const double percentage = 0.1/100.0;//i.e. 0.1%
4710 const int dim = 256;
4711
4712 // sparse level set sphere
4713 nanovdb::Vec3f C(0.35f, 0.35f, 0.35f);
4714 double r = 0.15, voxelSize = 1.0/(dim-1);
4715 auto handle = nanovdb::createLevelSetSphere(float(r), C, voxelSize);
4716 EXPECT_TRUE(handle);
4717 EXPECT_EQ(1u, handle.gridCount());
4718 auto* sphere = handle.grid<float>();
4719 EXPECT_TRUE(sphere);
4720
4721 nanovdb::CurvatureStencil<nanovdb::FloatGrid> cs(*sphere);
4722 const auto ijk = nanovdb::RoundDown<nanovdb::Coord>(sphere->worldToIndex(nanovdb::Vec3d(0.35, 0.35, 0.35 + 0.15)));
4723 const nanovdb::Vec3d tmp(ijk[0],ijk[1],ijk[2]);
4724 const double radius = (sphere->indexToWorld(tmp)-nanovdb::Vec3d(0.35)).length();
4725 //std::cerr << "\rRadius = " << radius << std::endl;
4726 //std::cerr << "Index coord =" << ijk << std::endl;
4727 cs.moveTo(ijk);
4728 auto acc = sphere->getAccessor();
4729 auto v = cs.getValue< 0, 0, 0>();
4730 EXPECT_EQ(acc.getValue(ijk.offsetBy( 0, 0, 0)), v);
4731 v = cs.getValue<-1, 0, 0>();
4732 EXPECT_EQ(acc.getValue(ijk.offsetBy(-1, 0, 0)), v);
4733 v = cs.getValue< 1, 0, 0>();
4734 EXPECT_EQ(acc.getValue(ijk.offsetBy( 1, 0, 0)), v);
4735 v = cs.getValue< 0,-1, 0>();
4736 EXPECT_EQ(acc.getValue(ijk.offsetBy( 0, -1, 0)), v);
4737 v = cs.getValue< 0, 1, 0>();
4738 EXPECT_EQ(acc.getValue(ijk.offsetBy( 0, 1, 0)), v);
4739 v = cs.getValue< 0, 0,-1>();
4740 EXPECT_EQ(acc.getValue(ijk.offsetBy( 0, 0, -1)), v);
4741 v = cs.getValue< 0, 0, 1>();
4742 EXPECT_EQ(acc.getValue(ijk.offsetBy( 0, 0, 1)), v);
4743
4744 v = cs.getValue<-1,-1, 0>();
4745 EXPECT_EQ(acc.getValue(ijk.offsetBy(-1, -1, 0)), v);
4746 v = cs.getValue< 1,-1, 0>();
4747 EXPECT_EQ(acc.getValue(ijk.offsetBy( 1, -1, 0)), v);
4748 v = cs.getValue<-1, 1, 0>();
4749 EXPECT_EQ(acc.getValue(ijk.offsetBy(-1, 1, 0)), v);
4750 v = cs.getValue< 1,1, 0>();
4751 EXPECT_EQ(acc.getValue(ijk.offsetBy( 1, 1, 0)), v);
4752
4753 v = cs.getValue<-1, 0, -1>();
4754 EXPECT_EQ(acc.getValue(ijk.offsetBy(-1, 0, -1)), v);
4755 v = cs.getValue< 1, 0, -1>();
4756 EXPECT_EQ(acc.getValue(ijk.offsetBy( 1, 0, -1)), v);
4757 v = cs.getValue<-1, 0, 1>();
4758 EXPECT_EQ(acc.getValue(ijk.offsetBy(-1, 0, 1)), v);
4759 v = cs.getValue< 1, 0, 1>();
4760 EXPECT_EQ(acc.getValue(ijk.offsetBy( 1, 0, 1)), v);
4761
4762 v = cs.getValue< 0, -1, -1>();
4763 EXPECT_EQ(acc.getValue(ijk.offsetBy( 0, -1, -1)), v);
4764 v = cs.getValue< 0, 1, -1>();
4765 EXPECT_EQ(acc.getValue(ijk.offsetBy( 0, 1, -1)), v);
4766 v = cs.getValue< 0, -1, 1>();
4767 EXPECT_EQ(acc.getValue(ijk.offsetBy( 0, -1, 1)), v);
4768 v = cs.getValue< 0, 1, 1>();
4769 EXPECT_EQ(acc.getValue(ijk.offsetBy( 0, 1, 1)), v);
4770
4771 //std::cerr << "Mean curvature = " << cs.meanCurvature() << ", 1/r=" << 1.0/radius << std::endl;
4772 //std::cerr << "Gaussian curvature = " << cs.gaussianCurvature() << ", 1/(r*r)=" << 1.0/(radius*radius) << std::endl;
4773 EXPECT_NEAR(1.0/radius, cs.meanCurvature(), percentage*1.0/radius);
4774 EXPECT_NEAR(1.0/(radius*radius), cs.gaussianCurvature(), percentage*1.0/(radius*radius));
4775 float mean, gauss;
4776 cs.curvatures(mean, gauss);
4777 //std::cerr << "Mean curvature = " << mean << ", 1/r=" << 1.0/radius << std::endl;
4778 //std::cerr << "Gaussian curvature = " << gauss << ", 1/(r*r)=" << 1.0/(radius*radius) << std::endl;
4779 EXPECT_NEAR(1.0/radius, mean, percentage*1.0/radius);
4780 EXPECT_NEAR(1.0/(radius*radius), gauss, percentage*1.0/(radius*radius));
4781 }
4782
4783 }// CurvatureStencil
4784
TEST_F(TestNanoVDB,GradStencil)4785 TEST_F(TestNanoVDB, GradStencil)
4786 {
4787 {// test of level set to sphere at (6,8,10) with R=10 and dx=0.5
4788 const float radius = 10.0f;// 20 voxels
4789 const nanovdb::Vec3f center(6.0, 8.0, 10.0);//i.e. (12,16,20) in index space
4790 auto handle = nanovdb::createLevelSetSphere(radius,
4791 center,
4792 0.5, // dx
4793 20.0);// width, so dense inside
4794
4795 EXPECT_TRUE(handle);
4796 EXPECT_EQ(1u, handle.gridCount());
4797 auto* grid = handle.grid<float>();
4798 EXPECT_TRUE(grid);
4799 EXPECT_EQ(0.5f, grid->voxelSize()[0]);
4800
4801 nanovdb::GradStencil<nanovdb::FloatGrid> cs(*grid);
4802
4803 nanovdb::Coord ijk(12, 16, 20);// on the surface in the +x direction
4804 const nanovdb::Vec3d xyz(ijk[0], ijk[1], ijk[2]);
4805 EXPECT_NEAR(center[0], grid->indexToWorld(xyz)[0], 1e-6);
4806 EXPECT_NEAR(center[1], grid->indexToWorld(xyz)[1], 1e-6);
4807 EXPECT_NEAR(center[2], grid->indexToWorld(xyz)[2], 1e-6);
4808 cs.moveTo(ijk.offsetBy(20, 0, 0));// on the sphere
4809 const float val = cs.getValue<0,0,0>();
4810 EXPECT_NEAR( 0.0f, val, 1e-6);// on the sphere
4811
4812 EXPECT_NEAR( 1.0f, cs.normSqGrad(), 2e-3f);
4813
4814 EXPECT_TRUE( cs.zeroCrossing() );
4815
4816 //std::cerr << cs.gradient() << std::endl;//second order
4817 EXPECT_NEAR( 1.0f, cs.gradient()[0], 1e-6f);
4818 EXPECT_NEAR( 0.0f, cs.gradient()[1], 1e-6f);
4819 EXPECT_NEAR( 0.0f, cs.gradient()[2], 1e-6f);
4820
4821 const nanovdb::Vec3f v(-1, 0, 0);// upwind direction
4822 //std::cerr << cs.gradient(v) << std::endl;// first order
4823 EXPECT_NEAR( 1.0f, cs.gradient(v)[0], 1e-6f);
4824 EXPECT_NEAR( 0.0f, cs.gradient(v)[1], 2.5e-2f);
4825 EXPECT_NEAR( 0.0f, cs.gradient(v)[2], 2.5e-2f);
4826
4827 // mean curvature = 0.5 * laplace of SDF => laplacian = 2 * mean curvature = 2 / radius
4828 //std::cerr << "Laplacian = " << cs.laplacian() << " " << (2/radius) << std::endl;
4829 EXPECT_NEAR(cs.laplacian(), 2/radius, 1e-3);
4830 }
4831 }// GradStencil
4832
TEST_F(TestNanoVDB,WenoStencil)4833 TEST_F(TestNanoVDB, WenoStencil)
4834 {
4835 {// test of level set to sphere at (6,8,10) with R=10 and dx=0.5
4836 const float radius = 10.0f;// 20 voxels
4837 const nanovdb::Vec3f center(6.0, 8.0, 10.0);//i.e. (12,16,20) in index space
4838 auto handle = nanovdb::createLevelSetSphere(radius,
4839 center,
4840 0.5, // dx
4841 20.0);// width, so dense inside
4842
4843 EXPECT_TRUE(handle);
4844 EXPECT_EQ(1u, handle.gridCount());
4845 auto* grid = handle.grid<float>();
4846 EXPECT_TRUE(grid);
4847 EXPECT_EQ(0.5f, grid->voxelSize()[0]);
4848
4849 nanovdb::WenoStencil<nanovdb::FloatGrid> cs(*grid);
4850
4851 nanovdb::Coord ijk(12, 16, 20);// on the surface in the +x direction
4852 const nanovdb::Vec3d xyz(ijk[0], ijk[1], ijk[2]);
4853 EXPECT_NEAR(center[0], grid->indexToWorld(xyz)[0], 1e-6);
4854 EXPECT_NEAR(center[1], grid->indexToWorld(xyz)[1], 1e-6);
4855 EXPECT_NEAR(center[2], grid->indexToWorld(xyz)[2], 1e-6);
4856 cs.moveTo(ijk.offsetBy(20, 0, 0));// on the sphere
4857 const float val = cs.getValue<0,0,0>();
4858 EXPECT_NEAR( 0.0f, val, 1e-6);// on the sphere
4859
4860 EXPECT_NEAR( 1.0f, cs.normSqGrad(), 1e-6f);
4861
4862 EXPECT_TRUE( cs.zeroCrossing() );
4863
4864 //std::cerr << cs.gradient() << std::endl;
4865 EXPECT_NEAR( 1.0f, cs.gradient()[0], 1e-6f);
4866 EXPECT_NEAR( 0.0f, cs.gradient()[1], 1e-6f);
4867 EXPECT_NEAR( 0.0f, cs.gradient()[2], 1e-6f);
4868
4869 const nanovdb::Vec3f v(-1, 0, 0);// upwind direction
4870 //std::cerr << cs.gradient(v) << std::endl;
4871 EXPECT_NEAR( 1.0f, cs.gradient(v)[0], 1e-6f);
4872 EXPECT_NEAR( 0.0f, cs.gradient(v)[1], 1e-6f);
4873 EXPECT_NEAR( 0.0f, cs.gradient(v)[2], 1e-6f);
4874
4875 // mean curvature = 0.5 * laplace of SDF => laplacian = 2 * mean curvature = 2 / radius
4876 //std::cerr << "Laplacian = " << cs.laplacian() << " " << (2/radius) << std::endl;
4877 EXPECT_NEAR(cs.laplacian(), 2/radius, 1e-3);
4878 }
4879 }// WenoStencil
4880
TEST_F(TestNanoVDB,StencilIntersection)4881 TEST_F(TestNanoVDB, StencilIntersection)
4882 {
4883 const nanovdb::Coord ijk(1,4,-9);
4884 nanovdb::GridBuilder<float> builder(0.0f);
4885 auto acc = builder.getAccessor();
4886 acc.setValue(ijk,-1.0f);
4887 int cases = 0;
4888 for (int mx=0; mx<2; ++mx) {
4889 acc.setValue(ijk.offsetBy(-1,0,0), mx ? 1.0f : -1.0f);
4890 for (int px=0; px<2; ++px) {
4891 acc.setValue(ijk.offsetBy(1,0,0), px ? 1.0f : -1.0f);
4892 for (int my=0; my<2; ++my) {
4893 acc.setValue(ijk.offsetBy(0,-1,0), my ? 1.0f : -1.0f);
4894 for (int py=0; py<2; ++py) {
4895 acc.setValue(ijk.offsetBy(0,1,0), py ? 1.0f : -1.0f);
4896 for (int mz=0; mz<2; ++mz) {
4897 acc.setValue(ijk.offsetBy(0,0,-1), mz ? 1.0f : -1.0f);
4898 for (int pz=0; pz<2; ++pz) {
4899 acc.setValue(ijk.offsetBy(0,0,1), pz ? 1.0f : -1.0f);
4900 ++cases;
4901 auto handle = builder.getHandle<>();
4902 EXPECT_TRUE(handle);
4903 auto grid = handle.grid<float>();
4904 EXPECT_TRUE(grid);
4905 EXPECT_EQ(7, int(grid->activeVoxelCount()));
4906 nanovdb::GradStencil<nanovdb::FloatGrid> stencil(*grid);
4907 stencil.moveTo(ijk);
4908 const int count = mx + px + my + py + mz + pz;// number of intersections
4909 EXPECT_TRUE(stencil.intersects() == (count > 0));
4910 auto mask = stencil.intersectionMask();
4911 EXPECT_TRUE(mask.none() == (count == 0));
4912 EXPECT_TRUE(mask.any() == (count > 0));
4913 EXPECT_EQ(count, mask.count());
4914 EXPECT_TRUE(mask.test(0) == mx);
4915 EXPECT_TRUE(mask.test(1) == px);
4916 EXPECT_TRUE(mask.test(2) == my);
4917 EXPECT_TRUE(mask.test(3) == py);
4918 EXPECT_TRUE(mask.test(4) == mz);
4919 EXPECT_TRUE(mask.test(5) == pz);
4920 }//pz
4921 }//mz
4922 }//py
4923 }//my
4924 }//px
4925 }//mx
4926 EXPECT_EQ(64, cases);// = 2^6
4927 }// StencilIntersection
4928
TEST_F(TestNanoVDB,MultiFile)4929 TEST_F(TestNanoVDB, MultiFile)
4930 {
4931 std::vector<nanovdb::GridHandle<>> handles;
4932 { // add an int32_t grid
4933 nanovdb::GridBuilder<int> builder(-1);
4934 auto acc = builder.getAccessor();
4935 acc.setValue(nanovdb::Coord(-256), 10);
4936 handles.push_back(builder.getHandle(1.0, nanovdb::Vec3d(0), "Int32 grid"));
4937 }
4938 { // add an empty int32_t grid
4939 nanovdb::GridBuilder<int> builder(-4);
4940 handles.push_back(builder.getHandle(1.0, nanovdb::Vec3d(0), "Int32 grid, empty"));
4941 }
4942 { // add a Vec3f grid
4943 nanovdb::GridBuilder<nanovdb::Vec3f> builder(nanovdb::Vec3f(0.0f, 0.0f, -1.0f));
4944 builder.setGridClass(nanovdb::GridClass::Staggered);
4945 auto acc = builder.getAccessor();
4946 acc.setValue(nanovdb::Coord(-256), nanovdb::Vec3f(1.0f, 0.0f, 0.0f));
4947 handles.push_back(builder.getHandle(1.0, nanovdb::Vec3d(0), "Float vector grid"));
4948 }
4949 { // add an int64_t grid
4950 nanovdb::GridBuilder<int64_t> builder(0);
4951 auto acc = builder.getAccessor();
4952 acc.setValue(nanovdb::Coord(0), 10);
4953 handles.push_back(builder.getHandle(1.0, nanovdb::Vec3d(0), "Int64 grid"));
4954 }
4955 for (int i = 0; i < 10; ++i) {
4956 const float radius = 100.0f;
4957 const float voxelSize = 1.0f, width = 3.0f;
4958 const nanovdb::Vec3f center(i * 10.0f, 0.0f, 0.0f);
4959 handles.push_back(nanovdb::createLevelSetSphere(radius, center, voxelSize, width,
4960 nanovdb::Vec3d(0), "Level set sphere at (" + std::to_string(i * 10) + ",0,0)"));
4961 }
4962 { // add a double grid
4963 nanovdb::GridBuilder<double> builder(0.0);
4964 builder.setGridClass(nanovdb::GridClass::FogVolume);
4965 auto acc = builder.getAccessor();
4966 acc.setValue(nanovdb::Coord(6000), 1.0);
4967 handles.push_back(builder.getHandle(1.0, nanovdb::Vec3d(0), "Double grid"));
4968 }
4969 #if defined(NANOVDB_USE_BLOSC)
4970 nanovdb::io::writeGrids<nanovdb::HostBuffer, std::vector>("data/multi1.nvdb", handles, nanovdb::io::Codec::BLOSC);
4971 #elif defined(NANOVDB_USE_ZIP)
4972 nanovdb::io::writeGrids<nanovdb::HostBuffer, std::vector>("data/multi1.nvdb", handles, nanovdb::io::Codec::ZIP);
4973 #else
4974 nanovdb::io::writeGrids<nanovdb::HostBuffer, std::vector>("data/multi1.nvdb", handles, nanovdb::io::Codec::NONE);
4975 #endif
4976 { // read grid meta data and test it
4977 //mTimer.start("nanovdb::io::readGridMetaData");
4978 auto meta = nanovdb::io::readGridMetaData("data/multi1.nvdb");
4979 //mTimer.stop();
4980 EXPECT_EQ(15u, meta.size());
4981 EXPECT_EQ(std::string("Double grid"), meta.back().gridName);
4982 }
4983 { // read in32 grid and test values
4984 //mTimer.start("Reading multiple grids from file");
4985 auto handles = nanovdb::io::readGrids("data/multi1.nvdb");
4986 //mTimer.stop();
4987 EXPECT_EQ(15u, handles.size());
4988 auto& handle = handles.front();
4989 EXPECT_EQ(1u, handle.gridCount());
4990 EXPECT_EQ(std::string("Int32 grid"), handle.gridMetaData()->shortGridName());
4991 EXPECT_FALSE(handle.grid<float>());
4992 EXPECT_FALSE(handle.grid<double>());
4993 EXPECT_FALSE(handle.grid<int64_t>());
4994 EXPECT_FALSE(handle.grid<nanovdb::Vec3f>());
4995 EXPECT_FALSE(handle.grid<nanovdb::Vec3d>());
4996 auto* grid = handle.grid<int32_t>();
4997 EXPECT_TRUE(grid);
4998 EXPECT_EQ(1u, grid->activeVoxelCount());
4999 const nanovdb::Coord ijk(-256);
5000 const auto& tree = grid->tree();
5001 EXPECT_EQ(10, tree.getValue(ijk));
5002 EXPECT_EQ(-1, tree.getValue(ijk + nanovdb::Coord(1, 0, 0)));
5003 EXPECT_EQ(10, tree.root().minimum());
5004 EXPECT_EQ(10, tree.root().maximum());
5005 EXPECT_TRUE(grid->tree().isActive(ijk));
5006 EXPECT_FALSE(grid->tree().isActive(nanovdb::Coord( 10, 450, 90)));
5007 EXPECT_FALSE(grid->tree().isActive(nanovdb::Coord(-10,-450,-90)));
5008 EXPECT_FALSE(grid->tree().isActive(ijk + nanovdb::Coord(1, 0, 0)));
5009 const nanovdb::CoordBBox bbox(ijk, ijk);
5010 EXPECT_EQ(bbox, grid->indexBBox());
5011 EXPECT_EQ(handle.gridMetaData()->indexBBox(), grid->indexBBox());
5012 EXPECT_EQ(1u, tree.nodeCount(0));
5013 EXPECT_EQ(1u, tree.nodeCount(1));
5014 EXPECT_EQ(1u, tree.nodeCount(2));
5015 const auto* leaf = tree.getFirstNode<0>();
5016 EXPECT_TRUE(leaf);
5017 EXPECT_EQ(bbox, leaf->bbox());
5018 const auto* node1 = tree.getFirstNode<1>();
5019 EXPECT_TRUE(node1);
5020 EXPECT_EQ(bbox, node1->bbox());
5021 const auto* node2 = tree.getFirstNode<2>();
5022 EXPECT_TRUE(node2);
5023 EXPECT_EQ(bbox, node2->bbox());
5024 EXPECT_FALSE(grid->isLevelSet());
5025 EXPECT_FALSE(grid->isFogVolume());
5026 EXPECT_TRUE(grid->isUnknown());
5027 EXPECT_FALSE(grid->isStaggered());
5028 }
5029 { // read empty in32 grid and test values
5030 //mTimer.start("Reading multiple grids from file");
5031 auto handles = nanovdb::io::readGrids("data/multi1.nvdb");
5032 //mTimer.stop();
5033 EXPECT_EQ(15u, handles.size());
5034 auto& handle = handles[1];
5035 EXPECT_TRUE(handle);
5036 EXPECT_EQ(1u, handle.gridCount());
5037 EXPECT_EQ(std::string("Int32 grid, empty"), handle.gridMetaData()->shortGridName());
5038 EXPECT_FALSE(handle.grid<float>());
5039 EXPECT_FALSE(handle.grid<double>());
5040 EXPECT_FALSE(handle.grid<int64_t>());
5041 EXPECT_FALSE(handle.grid<nanovdb::Vec3f>());
5042 EXPECT_FALSE(handle.grid<nanovdb::Vec3d>());
5043 auto* grid = handle.grid<int32_t>();
5044 EXPECT_TRUE(grid);
5045 EXPECT_EQ(0u, grid->activeVoxelCount());
5046 const nanovdb::Coord ijk(-256);
5047 EXPECT_EQ(-4, grid->tree().getValue(ijk));
5048 EXPECT_EQ(-4, grid->tree().getValue(ijk + nanovdb::Coord(1, 0, 0)));
5049 EXPECT_FALSE(grid->tree().isActive(ijk));
5050 EXPECT_FALSE(grid->tree().isActive(nanovdb::Coord( 10, 450, 90)));
5051 EXPECT_FALSE(grid->tree().isActive(nanovdb::Coord(-10,-450,-90)));
5052 EXPECT_FALSE(grid->tree().isActive(ijk + nanovdb::Coord(1, 0, 0)));
5053 EXPECT_EQ(-4, grid->tree().root().minimum());
5054 EXPECT_EQ(-4, grid->tree().root().maximum());
5055 EXPECT_EQ(nanovdb::Coord(std::numeric_limits<int>::max()), grid->indexBBox().min());
5056 EXPECT_EQ(nanovdb::Coord(std::numeric_limits<int>::min()), grid->indexBBox().max());
5057 EXPECT_EQ(handle.gridMetaData()->indexBBox(), grid->indexBBox());
5058 EXPECT_EQ(0u, grid->tree().nodeCount(0));
5059 EXPECT_EQ(0u, grid->tree().nodeCount(1));
5060 EXPECT_EQ(0u, grid->tree().nodeCount(2));
5061 EXPECT_FALSE(grid->isLevelSet());
5062 EXPECT_FALSE(grid->isFogVolume());
5063 EXPECT_FALSE(grid->isMask());
5064 EXPECT_TRUE(grid->isUnknown());
5065 EXPECT_FALSE(grid->isStaggered());
5066 }
5067 { // read int64 grid and test values
5068 //mTimer.start("Reading multiple grids from file");
5069 auto handles = nanovdb::io::readGrids("data/multi1.nvdb");
5070 //mTimer.stop();
5071 EXPECT_EQ(15u, handles.size());
5072 auto& handle = handles[3];
5073 EXPECT_EQ(1u, handle.gridCount());
5074 EXPECT_TRUE(handle);
5075 EXPECT_EQ(std::string("Int64 grid"), handle.gridMetaData()->shortGridName());
5076 auto* grid = handle.grid<int64_t>();
5077 EXPECT_TRUE(grid);
5078 EXPECT_EQ(handle.gridMetaData()->indexBBox(), grid->indexBBox());
5079 EXPECT_EQ(1u, grid->activeVoxelCount());
5080 const nanovdb::Coord ijk(0);
5081 EXPECT_EQ(10, grid->tree().getValue(ijk));
5082 EXPECT_EQ(0, grid->tree().getValue(ijk + nanovdb::Coord(1, 0, 0)));
5083 EXPECT_EQ(10, grid->tree().root().minimum());
5084 EXPECT_EQ(10, grid->tree().root().maximum());
5085 EXPECT_EQ(nanovdb::CoordBBox(ijk, ijk), grid->indexBBox());
5086 EXPECT_FALSE(grid->isLevelSet());
5087 EXPECT_FALSE(grid->isFogVolume());
5088 EXPECT_TRUE(grid->isUnknown());
5089 EXPECT_FALSE(grid->isStaggered());
5090 }
5091 { // read vec3f grid and test values
5092 auto handles = nanovdb::io::readGrids("data/multi1.nvdb");
5093 EXPECT_EQ(15u, handles.size());
5094 auto& handle = handles[2];
5095 EXPECT_TRUE(handle);
5096 EXPECT_EQ(1u, handle.gridCount());
5097 EXPECT_EQ(std::string("Float vector grid"), handle.gridMetaData()->shortGridName());
5098 auto* grid = handle.grid<nanovdb::Vec3f>();
5099 EXPECT_TRUE(grid);
5100 EXPECT_EQ(1u, grid->activeVoxelCount());
5101 EXPECT_EQ(handle.gridMetaData()->indexBBox(), grid->indexBBox());
5102 const nanovdb::Coord ijk(-256);
5103 EXPECT_EQ(nanovdb::Vec3f(1.0f, 0.0f, 0.0f), grid->tree().getValue(ijk));
5104 EXPECT_EQ(nanovdb::Vec3f(0.0f, 0.0f, -1.0f), grid->tree().getValue(ijk + nanovdb::Coord(1, 0, 0)));
5105 EXPECT_EQ(nanovdb::Vec3f(1.0f, 0.0f, 0.0f), grid->tree().root().minimum());
5106 EXPECT_EQ(nanovdb::Vec3f(1.0f, 0.0f, 0.0f), grid->tree().root().maximum());
5107 EXPECT_EQ(nanovdb::CoordBBox(ijk, ijk), grid->indexBBox());
5108 EXPECT_FALSE(grid->isLevelSet());
5109 EXPECT_FALSE(grid->isFogVolume());
5110 EXPECT_FALSE(grid->isUnknown());
5111 EXPECT_TRUE(grid->isStaggered());
5112 }
5113 { // read double grid and test values
5114 auto handles = nanovdb::io::readGrids("data/multi1.nvdb");
5115 EXPECT_EQ(15u, handles.size());
5116 auto& handle = handles.back();
5117 EXPECT_TRUE(handle);
5118 EXPECT_EQ(1u, handle.gridCount());
5119 EXPECT_EQ(std::string("Double grid"), handle.gridMetaData()->shortGridName());
5120 auto* grid = handle.grid<double>();
5121 EXPECT_TRUE(grid);
5122 EXPECT_EQ(1u, grid->activeVoxelCount());
5123 const nanovdb::Coord ijk(6000);
5124 EXPECT_EQ(1.0, grid->tree().getValue(ijk));
5125 EXPECT_EQ(0.0, grid->tree().getValue(ijk + nanovdb::Coord(1, 0, 0)));
5126 EXPECT_EQ(1.0, grid->tree().root().minimum());
5127 EXPECT_EQ(1.0, grid->tree().root().maximum());
5128 EXPECT_EQ(nanovdb::CoordBBox(ijk, ijk), grid->tree().bbox());
5129 EXPECT_EQ(handle.gridMetaData()->indexBBox(), grid->indexBBox());
5130 EXPECT_FALSE(grid->isLevelSet());
5131 EXPECT_TRUE(grid->isFogVolume());
5132 EXPECT_FALSE(grid->isUnknown());
5133 EXPECT_FALSE(grid->isStaggered());
5134 }
5135 } // MultiFile
5136
TEST_F(TestNanoVDB,HostBuffer)5137 TEST_F(TestNanoVDB, HostBuffer)
5138 {
5139 {// internal memory - HostBuffer
5140 std::vector<nanovdb::GridHandle<> > gridHdls;
5141
5142 // create two grids...
5143 gridHdls.push_back(nanovdb::createLevelSetSphere(100.0f, nanovdb::Vec3f(-20, 0, 0), 1.0, 3.0, nanovdb::Vec3R(0), "spheref"));
5144 gridHdls.push_back(nanovdb::createLevelSetSphere(100.0, nanovdb::Vec3d( 20, 0, 0), 1.0, 3.0, nanovdb::Vec3R(0), "sphered"));
5145
5146 EXPECT_TRUE(gridHdls[0]);
5147 auto* meta0 = gridHdls[0].gridMetaData();
5148 EXPECT_TRUE(meta0);
5149 EXPECT_FALSE(meta0->isEmpty());
5150 EXPECT_EQ("spheref", std::string(meta0->shortGridName()));
5151 EXPECT_EQ(nanovdb::GridType::Float, meta0->gridType());
5152 EXPECT_EQ(nanovdb::GridClass::LevelSet, meta0->gridClass());
5153 auto* grid0 = gridHdls[0].grid<float>();
5154 EXPECT_TRUE(grid0);
5155 auto acc0 = grid0->getAccessor();
5156 EXPECT_EQ(0.0f, acc0.getValue(nanovdb::Coord(-20+100, 0, 0)));
5157
5158 EXPECT_TRUE(gridHdls[1]);
5159 auto* meta1 = gridHdls[1].gridMetaData();
5160 EXPECT_TRUE(meta1);
5161 EXPECT_FALSE(meta1->isEmpty());
5162 EXPECT_EQ("sphered", std::string(meta1->shortGridName()));
5163 EXPECT_EQ(nanovdb::GridType::Double, meta1->gridType());
5164 EXPECT_EQ(nanovdb::GridClass::LevelSet, meta1->gridClass());
5165 auto* grid1 = gridHdls[1].grid<double>();
5166 EXPECT_TRUE(grid1);
5167 auto acc1 = grid1->getAccessor();
5168 EXPECT_EQ(0.0, acc1.getValue(nanovdb::Coord( 20+100, 0, 0)));
5169 }
5170 {// internal memory - bump pool
5171 const size_t poolSize = 1 << 26;// 64 MB
5172 auto pool = nanovdb::HostBuffer::createPool(poolSize);
5173 EXPECT_TRUE(pool.isManaged());
5174 EXPECT_EQ(64ULL * 1024 * 1024, pool.poolSize());
5175 EXPECT_TRUE(pool.isPool());
5176 EXPECT_TRUE(pool.isEmpty());
5177 EXPECT_FALSE(pool.isFull());
5178
5179 std::vector<nanovdb::GridHandle<> > gridHdls;
5180
5181 // create two grids...
5182 gridHdls.push_back(nanovdb::createLevelSetSphere(100.0f, nanovdb::Vec3f(-20, 0, 0), 1.0, 3.0, nanovdb::Vec3R(0), "spheref", nanovdb::StatsMode::BBox, nanovdb::ChecksumMode::Partial, -1.0f, false, pool));
5183 gridHdls.push_back(nanovdb::createLevelSetSphere(100.0, nanovdb::Vec3d( 20, 0, 0), 1.0, 3.0, nanovdb::Vec3R(0), "sphered", nanovdb::StatsMode::BBox, nanovdb::ChecksumMode::Partial, -1.0f, false, pool));
5184
5185 EXPECT_TRUE(gridHdls[0]);
5186 auto* meta0 = gridHdls[0].gridMetaData();
5187 EXPECT_TRUE(meta0);
5188 EXPECT_FALSE(meta0->isEmpty());
5189 EXPECT_EQ("spheref", std::string(meta0->shortGridName()));
5190 EXPECT_EQ(nanovdb::GridType::Float, meta0->gridType());
5191 EXPECT_EQ(nanovdb::GridClass::LevelSet, meta0->gridClass());
5192 auto* grid0 = gridHdls[0].grid<float>();
5193 //printf("Before resize: address of grid0 = %p\n", (void*)grid0);
5194 EXPECT_TRUE(grid0);
5195 auto acc0 = grid0->getAccessor();
5196 EXPECT_EQ(0.0f, acc0.getValue(nanovdb::Coord(-20+100, 0, 0)));
5197
5198 EXPECT_TRUE(gridHdls[1]);
5199 auto* meta1 = gridHdls[1].gridMetaData();
5200 EXPECT_TRUE(meta1);
5201 EXPECT_FALSE(meta1->isEmpty());
5202 EXPECT_EQ("sphered", std::string(meta1->shortGridName()));
5203 EXPECT_EQ(nanovdb::GridType::Double, meta1->gridType());
5204 EXPECT_EQ(nanovdb::GridClass::LevelSet, meta1->gridClass());
5205 auto* grid1 = gridHdls[1].grid<double>();
5206 EXPECT_TRUE(grid1);
5207 auto acc1 = grid1->getAccessor();
5208 EXPECT_EQ(0.0, acc1.getValue(nanovdb::Coord( 20+100, 0, 0)));
5209
5210 pool.resizePool( 2*poolSize );
5211 EXPECT_TRUE(pool.isManaged());
5212 EXPECT_EQ(128ULL * 1024 * 1024, pool.poolSize());
5213 EXPECT_TRUE(pool.isPool());
5214 EXPECT_TRUE(pool.isEmpty());// because this buffer does not use the pool
5215 EXPECT_FALSE(pool.isFull());
5216
5217 EXPECT_TRUE(gridHdls[0]);
5218 meta0 = gridHdls[0].gridMetaData();
5219 EXPECT_TRUE(meta0);
5220 EXPECT_FALSE(meta0->isEmpty());
5221 EXPECT_EQ("spheref", std::string(meta0->shortGridName()));
5222 EXPECT_EQ(nanovdb::GridType::Float, meta0->gridType());
5223 EXPECT_EQ(nanovdb::GridClass::LevelSet, meta0->gridClass());
5224 grid0 = gridHdls[0].grid<float>();
5225 //printf("After resize: address of grid0 = %p\n", (void*)grid0);
5226 EXPECT_TRUE(grid0);
5227 acc0 = grid0->getAccessor();
5228 EXPECT_EQ(0.0f, acc0.getValue(nanovdb::Coord(-20+100, 0, 0)));
5229
5230 EXPECT_TRUE(gridHdls[1]);
5231 meta1 = gridHdls[1].gridMetaData();
5232 EXPECT_TRUE(meta1);
5233 EXPECT_FALSE(meta1->isEmpty());
5234 EXPECT_EQ("sphered", std::string(meta1->shortGridName()));
5235 EXPECT_EQ(nanovdb::GridType::Double, meta1->gridType());
5236 EXPECT_EQ(nanovdb::GridClass::LevelSet, meta1->gridClass());
5237 grid1 = gridHdls[1].grid<double>();
5238 EXPECT_TRUE(grid1);
5239 acc1 = grid1->getAccessor();
5240 EXPECT_EQ(0.0, acc1.getValue(nanovdb::Coord( 20+100, 0, 0)));
5241
5242 pool.reset();
5243 EXPECT_TRUE(pool.isManaged());
5244 EXPECT_EQ(128ULL * 1024 * 1024, pool.poolSize());
5245 EXPECT_TRUE(pool.isPool());
5246 EXPECT_TRUE(pool.isEmpty());// because this buffer does not use the pool
5247 EXPECT_FALSE(pool.isFull());
5248
5249 EXPECT_FALSE(gridHdls[0]);
5250 EXPECT_FALSE(gridHdls[1]);
5251 }
5252 {// insufficient internal memory
5253 const size_t poolSize = 1 << 6;// 64 B
5254 auto pool = nanovdb::HostBuffer::createPool(poolSize);
5255 EXPECT_EQ(64ULL, pool.poolSize());
5256 EXPECT_TRUE(pool.isPool());
5257 EXPECT_TRUE(pool.isEmpty());
5258 EXPECT_FALSE(pool.isFull());
5259
5260 std::vector<nanovdb::GridHandle<> > gridHdls;
5261
5262 // create two grids...
5263 ASSERT_THROW(gridHdls.push_back(nanovdb::createLevelSetSphere( 100.0f, nanovdb::Vec3f(-20, 0, 0), 1.0, 3.0, nanovdb::Vec3d(0), "spheref", nanovdb::StatsMode::BBox, nanovdb::ChecksumMode::Partial, -1.0f, false, pool)), std::runtime_error);
5264 ASSERT_THROW(gridHdls.push_back(nanovdb::createLevelSetSphere( 100.0, nanovdb::Vec3d( 20, 0, 0), 1.0, 3.0, nanovdb::Vec3d(0), "sphered", nanovdb::StatsMode::BBox, nanovdb::ChecksumMode::Partial, -1.0f, false, pool)), std::runtime_error);
5265 }
5266 {// zero internal memory size
5267 ASSERT_THROW(nanovdb::HostBuffer::createPool(0), std::runtime_error);
5268 ASSERT_THROW(nanovdb::HostBuffer::createFull(0), std::runtime_error);
5269 }
5270 {// external memory
5271
5272 const size_t poolSize = 1 << 26;// 64 MB
5273 std::unique_ptr<uint8_t[]> buffer(new uint8_t[poolSize]);
5274 auto pool = nanovdb::HostBuffer::createPool(poolSize, buffer.get());
5275 EXPECT_EQ(64ULL * 1024 * 1024, pool.poolSize());
5276 EXPECT_FALSE(pool.isManaged());
5277 EXPECT_TRUE(pool.isPool());
5278 EXPECT_TRUE(pool.isEmpty());
5279 EXPECT_FALSE(pool.isFull());
5280
5281 std::vector<nanovdb::GridHandle<> > gridHdls;
5282
5283 // create two grids...
5284 gridHdls.push_back(nanovdb::createLevelSetSphere( 100.0f, nanovdb::Vec3f(-20, 0, 0), 1.0, 3.0, nanovdb::Vec3d(0), "spheref", nanovdb::StatsMode::BBox, nanovdb::ChecksumMode::Partial, -1.0f, false, pool));
5285 gridHdls.push_back(nanovdb::createLevelSetSphere( 100.0, nanovdb::Vec3d( 20, 0, 0), 1.0, 3.0, nanovdb::Vec3d(0), "sphered", nanovdb::StatsMode::BBox, nanovdb::ChecksumMode::Partial, -1.0f, false, pool));
5286
5287 EXPECT_TRUE(gridHdls[0]);
5288 auto* meta0 = gridHdls[0].gridMetaData();
5289 EXPECT_TRUE(meta0);
5290 EXPECT_FALSE(meta0->isEmpty());
5291 EXPECT_EQ("spheref", std::string(meta0->shortGridName()));
5292 EXPECT_EQ(nanovdb::GridType::Float, meta0->gridType());
5293 EXPECT_EQ(nanovdb::GridClass::LevelSet, meta0->gridClass());
5294 auto* grid0 = gridHdls[0].grid<float>();
5295 EXPECT_TRUE(grid0);
5296 auto acc0 = grid0->getAccessor();
5297 EXPECT_EQ(0.0f, acc0.getValue(nanovdb::Coord(-20+100, 0, 0)));
5298
5299 EXPECT_TRUE(gridHdls[1]);
5300 auto* meta1 = gridHdls[1].gridMetaData();
5301 EXPECT_TRUE(meta1);
5302 EXPECT_FALSE(meta1->isEmpty());
5303 EXPECT_EQ("sphered", std::string(meta1->shortGridName()));
5304 EXPECT_EQ(nanovdb::GridType::Double, meta1->gridType());
5305 EXPECT_EQ(nanovdb::GridClass::LevelSet, meta1->gridClass());
5306 auto* grid1 = gridHdls[1].grid<double>();
5307 EXPECT_TRUE(grid1);
5308 auto acc1 = grid1->getAccessor();
5309 EXPECT_EQ(0.0, acc1.getValue(nanovdb::Coord( 20+100, 0, 0)));
5310
5311 pool.reset();
5312
5313 EXPECT_FALSE(gridHdls[0]);
5314 EXPECT_FALSE(gridHdls[1]);
5315 }
5316 {// insufficient external memory
5317 const size_t poolSize = 64;// 64 B
5318 uint8_t *data = static_cast<uint8_t*>(std::malloc(poolSize));
5319 auto pool = nanovdb::HostBuffer::createPool(poolSize, data);
5320 EXPECT_EQ(0ULL, pool.size());
5321 EXPECT_EQ(64ULL, pool.poolSize());
5322 EXPECT_EQ(0ULL, pool.poolUsage());
5323 EXPECT_TRUE(pool.isPool());
5324 EXPECT_TRUE(pool.isEmpty());
5325 EXPECT_FALSE(pool.isFull());
5326 EXPECT_FALSE(pool.isManaged());
5327
5328 auto buffer = nanovdb::HostBuffer::create(32, &pool);
5329 EXPECT_EQ(32ULL, buffer.size());
5330 EXPECT_EQ(64ULL, buffer.poolSize());
5331 EXPECT_EQ(32ULL, pool.poolUsage());
5332 EXPECT_FALSE(buffer.isPool());
5333 EXPECT_FALSE(buffer.isEmpty());
5334 EXPECT_FALSE(buffer.isFull());
5335 EXPECT_FALSE(buffer.isManaged());
5336
5337 std::vector<nanovdb::GridHandle<> > gridHdls;
5338
5339 // create two grids...
5340 ASSERT_THROW(gridHdls.push_back(nanovdb::createLevelSetSphere( 100.0f, nanovdb::Vec3f(-20, 0, 0), 1.0, 3.0, nanovdb::Vec3d(0), "spheref", nanovdb::StatsMode::BBox, nanovdb::ChecksumMode::Partial, -1.0f, false, pool)), std::runtime_error);
5341 ASSERT_THROW(gridHdls.push_back(nanovdb::createLevelSetSphere( 100.0, nanovdb::Vec3d( 20, 0, 0), 1.0, 3.0, nanovdb::Vec3d(0), "sphered", nanovdb::StatsMode::BBox, nanovdb::ChecksumMode::Partial, -1.0f, false, pool)), std::runtime_error);
5342
5343 EXPECT_FALSE(pool.isManaged());
5344 pool.resizePool(1<<26);// resize to 64 MB
5345 EXPECT_TRUE(pool.isManaged());
5346 std::free(data);
5347
5348 EXPECT_EQ(0ULL, pool.size());
5349 EXPECT_EQ(1ULL<<26, pool.poolSize());
5350 EXPECT_TRUE(pool.isPool());
5351 EXPECT_TRUE(pool.isEmpty());
5352 EXPECT_FALSE(pool.isFull());
5353 EXPECT_TRUE(pool.isManaged());
5354
5355 EXPECT_EQ(32ULL, buffer.size());
5356 EXPECT_EQ(1ULL<<26, buffer.poolSize());
5357 EXPECT_FALSE(buffer.isPool());
5358 EXPECT_FALSE(buffer.isEmpty());
5359 EXPECT_FALSE(buffer.isFull());
5360 EXPECT_TRUE(buffer.isManaged());
5361
5362 gridHdls.push_back(nanovdb::createLevelSetSphere( 100.0f, nanovdb::Vec3f(-20, 0, 0), 1.0, 3.0, nanovdb::Vec3d(0), "spheref", nanovdb::StatsMode::BBox, nanovdb::ChecksumMode::Partial, -1.0f, false, pool));
5363 gridHdls.push_back(nanovdb::createLevelSetSphere( 100.0, nanovdb::Vec3d( 20, 0, 0), 1.0, 3.0, nanovdb::Vec3d(0), "sphered", nanovdb::StatsMode::BBox, nanovdb::ChecksumMode::Partial, -1.0f, false, pool));
5364
5365 EXPECT_TRUE(gridHdls[0]);
5366 auto* meta0 = gridHdls[0].gridMetaData();
5367 EXPECT_TRUE(meta0);
5368 EXPECT_FALSE(meta0->isEmpty());
5369 EXPECT_EQ("spheref", std::string(meta0->shortGridName()));
5370 EXPECT_EQ(nanovdb::GridType::Float, meta0->gridType());
5371 EXPECT_EQ(nanovdb::GridClass::LevelSet, meta0->gridClass());
5372 auto* grid0 = gridHdls[0].grid<float>();
5373 EXPECT_TRUE(grid0);
5374 auto acc0 = grid0->getAccessor();
5375 EXPECT_EQ(0.0f, acc0.getValue(nanovdb::Coord(-20+100, 0, 0)));
5376
5377 EXPECT_TRUE(gridHdls[1]);
5378 auto* meta1 = gridHdls[1].gridMetaData();
5379 EXPECT_TRUE(meta1);
5380 EXPECT_FALSE(meta1->isEmpty());
5381 EXPECT_EQ("sphered", std::string(meta1->shortGridName()));
5382 EXPECT_EQ(nanovdb::GridType::Double, meta1->gridType());
5383 EXPECT_EQ(nanovdb::GridClass::LevelSet, meta1->gridClass());
5384 auto* grid1 = gridHdls[1].grid<double>();
5385 EXPECT_TRUE(grid1);
5386 auto acc1 = grid1->getAccessor();
5387 EXPECT_EQ(0.0, acc1.getValue(nanovdb::Coord( 20+100, 0, 0)));
5388
5389 pool.reset();
5390 EXPECT_EQ(0ULL, pool.poolUsage());
5391 EXPECT_TRUE(pool.isManaged());
5392
5393 EXPECT_FALSE(gridHdls[0]);
5394 EXPECT_FALSE(gridHdls[1]);
5395 }
5396 {// zero external memory size
5397 const size_t poolSize = 1 << 6;// 64 B
5398 uint8_t *data = static_cast<uint8_t*>(std::malloc(poolSize));
5399 ASSERT_THROW(nanovdb::HostBuffer::createPool(0, data), std::runtime_error);
5400 std::free(data);
5401 }
5402 try {// reading multiple grids into a HostBuffer with external memory
5403 const size_t poolSize = 1 << 27;// 128 MB
5404 std::unique_ptr<uint8_t[]> array(new uint8_t[poolSize]);// scoped buffer
5405 auto pool = nanovdb::HostBuffer::createPool(poolSize, array.get());
5406 EXPECT_EQ(128ULL * 1024 * 1024, pool.poolSize());
5407 auto handles = nanovdb::io::readGrids("data/multi1.nvdb", 0, pool);
5408 EXPECT_EQ(15u, handles.size());
5409 for (auto &h : handles) EXPECT_TRUE(h);
5410 EXPECT_EQ(std::string("Int32 grid"), handles[0].grid<int>()->gridName());
5411 EXPECT_EQ(std::string("Int32 grid, empty"), handles[1].grid<int>()->gridName());
5412 EXPECT_EQ(std::string("Float vector grid"), handles[2].grid<nanovdb::Vec3f>()->gridName());
5413 EXPECT_EQ(std::string("Int64 grid"), handles[3].grid<int64_t>()->gridName());
5414 EXPECT_EQ(std::string("Double grid"), handles[14].grid<double>()->gridName());
5415 pool.reset();
5416 for (auto &h : handles) EXPECT_FALSE(h);
5417 handles = nanovdb::io::readGrids("data/multi1.nvdb", 0, pool);
5418 EXPECT_EQ(15u, handles.size());
5419 for (auto &h : handles) EXPECT_TRUE(h);
5420 EXPECT_EQ(std::string("Int32 grid"), handles[0].grid<int>()->gridName());
5421 EXPECT_EQ(std::string("Int32 grid, empty"), handles[1].grid<int>()->gridName());
5422 EXPECT_EQ(std::string("Float vector grid"), handles[2].grid<nanovdb::Vec3f>()->gridName());
5423 EXPECT_EQ(std::string("Int64 grid"), handles[3].grid<int64_t>()->gridName());
5424 EXPECT_EQ(std::string("Double grid"), handles[14].grid<double>()->gridName());
5425 } catch(const std::exception& e) {
5426 std::cout << "Unable to read \"data/multi1.nvdb\" for unit-test\n" << e.what() << std::endl;
5427 }
5428 }// HostBuffer
5429
main(int argc,char ** argv)5430 int main(int argc, char** argv)
5431 {
5432 ::testing::InitGoogleTest(&argc, argv);
5433 return RUN_ALL_TESTS();
5434 }
5435