HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NanoVDB.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /*!
5  \file NanoVDB.h
6 
7  \author Ken Museth
8 
9  \date January 8, 2020
10 
11  \brief Implements a light-weight self-contained VDB data-structure in a
12  single file! In other words, this is a significantly watered-down
13  version of the OpenVDB implementation, with few dependencies - so
14  a one-stop-shop for a minimalistic VDB data structure that run on
15  most platforms!
16 
17  \note It is important to note that NanoVDB (by design) is a read-only
18  sparse GPU (and CPU) friendly data structure intended for applications
19  like rendering and collision detection. As such it obviously lacks
20  a lot of the functionality and features of OpenVDB grids. NanoVDB
21  is essentially a compact linearized (or serialized) representation of
22  an OpenVDB tree with getValue methods only. For best performance use
23  the ReadAccessor::getValue method as opposed to the Tree::getValue
24  method. Note that since a ReadAccessor caches previous access patterns
25  it is by design not thread-safe, so use one instantiation per thread
26  (it is very light-weight). Also, it is not safe to copy accessors between
27  the GPU and CPU! In fact, client code should only interface
28  with the API of the Grid class (all other nodes of the NanoVDB data
29  structure can safely be ignored by most client codes)!
30 
31 
32  \warning NanoVDB grids can only be constructed via tools like createNanoGrid
33  or the GridBuilder. This explains why none of the grid nodes defined below
34  have public constructors or destructors.
35 
36  \details Please see the following paper for more details on the data structure:
37  K. Museth, “VDB: High-Resolution Sparse Volumes with Dynamic Topology”,
38  ACM Transactions on Graphics 32(3), 2013, which can be found here:
39  http://www.museth.org/Ken/Publications_files/Museth_TOG13.pdf
40 
41  NanoVDB was first published there: https://dl.acm.org/doi/fullHtml/10.1145/3450623.3464653
42 
43 
44  Overview: This file implements the following fundamental class that when combined
45  forms the backbone of the VDB tree data structure:
46 
47  Coord- a signed integer coordinate
48  Vec3 - a 3D vector
49  Vec4 - a 4D vector
50  BBox - a bounding box
51  Mask - a bitmask essential to the non-root tree nodes
52  Map - an affine coordinate transformation
53  Grid - contains a Tree and a map for world<->index transformations. Use
54  this class as the main API with client code!
55  Tree - contains a RootNode and getValue methods that should only be used for debugging
56  RootNode - the top-level node of the VDB data structure
57  InternalNode - the internal nodes of the VDB data structure
58  LeafNode - the lowest level tree nodes that encode voxel values and state
59  ReadAccessor - implements accelerated random access operations
60 
61  Semantics: A VDB data structure encodes values and (binary) states associated with
62  signed integer coordinates. Values encoded at the leaf node level are
63  denoted voxel values, and values associated with other tree nodes are referred
64  to as tile values, which by design cover a larger coordinate index domain.
65 
66 
67  Memory layout:
68 
69  It's important to emphasize that all the grid data (defined below) are explicitly 32 byte
70  aligned, which implies that any memory buffer that contains a NanoVDB grid must also be at
71  32 byte aligned. That is, the memory address of the beginning of a buffer (see ascii diagram below)
72  must be divisible by 32, i.e. uintptr_t(&buffer)%32 == 0! If this is not the case, the C++ standard
73  says the behaviour is undefined! Normally this is not a concerns on GPUs, because they use 256 byte
74  aligned allocations, but the same cannot be said about the CPU.
75 
76  GridData is always at the very beginning of the buffer immediately followed by TreeData!
77  The remaining nodes and blind-data are allowed to be scattered throughout the buffer,
78  though in practice they are arranged as:
79 
80  GridData: 672 bytes (e.g. magic, checksum, major, flags, index, count, size, name, map, world bbox, voxel size, class, type, offset, count)
81 
82  TreeData: 64 bytes (node counts and byte offsets)
83 
84  ... optional padding ...
85 
86  RootData: size depends on ValueType (index bbox, voxel count, tile count, min/max/avg/standard deviation)
87 
88  Array of: RootData::Tile
89 
90  ... optional padding ...
91 
92  Array of: Upper InternalNodes of size 32^3: bbox, two bit masks, 32768 tile values, and min/max/avg/standard deviation values
93 
94  ... optional padding ...
95 
96  Array of: Lower InternalNodes of size 16^3: bbox, two bit masks, 4096 tile values, and min/max/avg/standard deviation values
97 
98  ... optional padding ...
99 
100  Array of: LeafNodes of size 8^3: bbox, bit masks, 512 voxel values, and min/max/avg/standard deviation values
101 
102 
103  Notation: "]---[" implies it has optional padding, and "][" implies zero padding
104 
105  [GridData(672B)][TreeData(64B)]---[RootData][N x Root::Tile]---[InternalData<5>]---[InternalData<4>]---[LeafData<3>]---[BLINDMETA...]---[BLIND0]---[BLIND1]---etc.
106  ^ ^ ^ ^ ^ ^
107  | | | | | |
108  +-- Start of 32B aligned buffer | | | | +-- Node0::DataType* leafData
109  GridType::DataType* gridData | | | |
110  | | | +-- Node1::DataType* lowerData
111  RootType::DataType* rootData --+ | |
112  | +-- Node2::DataType* upperData
113  |
114  +-- RootType::DataType::Tile* tile
115 
116 */
117 
118 #ifndef NANOVDB_NANOVDB_H_HAS_BEEN_INCLUDED
119 #define NANOVDB_NANOVDB_H_HAS_BEEN_INCLUDED
120 
121 // NANOVDB_MAGIC_NUMBER is currently used for both grids and files (starting with v32.6.0)
122 // NANOVDB_MAGIC_GRID will soon be used exclusively for grids
123 // NANOVDB_MAGIC_FILE will soon be used exclusively for files
124 // NANOVDB_MAGIC_NODE will soon be used exclusively for NodeManager
125 // | : 0 in 30 corresponds to 0 in NanoVDB0
126 #define NANOVDB_MAGIC_NUMBER 0x304244566f6e614eUL // "NanoVDB0" in hex - little endian (uint64_t)
127 #define NANOVDB_MAGIC_GRID 0x314244566f6e614eUL // "NanoVDB1" in hex - little endian (uint64_t)
128 #define NANOVDB_MAGIC_FILE 0x324244566f6e614eUL // "NanoVDB2" in hex - little endian (uint64_t)
129 #define NANOVDB_MAGIC_NODE 0x334244566f6e614eUL // "NanoVDB3" in hex - little endian (uint64_t)
130 #define NANOVDB_MAGIC_MASK 0x00FFFFFFFFFFFFFFUL // use this mask to remove the number
131 //#define NANOVDB_USE_NEW_MAGIC_NUMBERS// used to enable use of the new magic numbers described above
132 
133 #define NANOVDB_MAJOR_VERSION_NUMBER 32 // reflects changes to the ABI and hence also the file format
134 #define NANOVDB_MINOR_VERSION_NUMBER 6 // reflects changes to the API but not ABI
135 #define NANOVDB_PATCH_VERSION_NUMBER 0 // reflects changes that does not affect the ABI or API
136 
137 #define TBB_SUPPRESS_DEPRECATED_MESSAGES 1
138 
139 // This replaces a Coord key at the root level with a single uint64_t
140 #define NANOVDB_USE_SINGLE_ROOT_KEY
141 
142 // This replaces three levels of Coord keys in the ReadAccessor with one Coord
143 //#define NANOVDB_USE_SINGLE_ACCESSOR_KEY
144 
145 // Use this to switch between std::ofstream or FILE implementations
146 //#define NANOVDB_USE_IOSTREAMS
147 
148 // Use this to switch between old and new accessor methods
149 #define NANOVDB_NEW_ACCESSOR_METHODS
150 
151 #define NANOVDB_FPN_BRANCHLESS
152 
153 // Do not change this value! 32 byte alignment is fixed in NanoVDB
154 #define NANOVDB_DATA_ALIGNMENT 32
155 
156 #if !defined(NANOVDB_ALIGN)
157 #define NANOVDB_ALIGN(n) alignas(n)
158 #endif // !defined(NANOVDB_ALIGN)
159 
160 #ifdef __CUDACC_RTC__
161 
162 typedef signed char int8_t;
163 typedef short int16_t;
164 typedef int int32_t;
165 typedef long long int64_t;
166 typedef unsigned char uint8_t;
167 typedef unsigned int uint32_t;
168 typedef unsigned short uint16_t;
169 typedef unsigned long long uint64_t;
170 
171 #define NANOVDB_ASSERT(x)
172 
173 #define UINT64_C(x) (x ## ULL)
174 
175 #else // !__CUDACC_RTC__
176 
177 #include <stdlib.h> // for abs in clang7
178 #include <stdint.h> // for types like int32_t etc
179 #include <stddef.h> // for size_t type
180 #include <cassert> // for assert
181 #include <cstdio> // for snprintf
182 #include <cmath> // for sqrt and fma
183 #include <limits> // for numeric_limits
184 #include <utility>// for std::move
185 #ifdef NANOVDB_USE_IOSTREAMS
186 #include <fstream>// for read/writeUncompressedGrids
187 #endif
188 // All asserts can be disabled here, even for debug builds
189 #if 1
190 #define NANOVDB_ASSERT(x) assert(x)
191 #else
192 #define NANOVDB_ASSERT(x)
193 #endif
194 
195 #if defined(NANOVDB_USE_INTRINSICS) && defined(_MSC_VER)
196 #include <intrin.h>
197 #pragma intrinsic(_BitScanReverse)
198 #pragma intrinsic(_BitScanForward)
199 #pragma intrinsic(_BitScanReverse64)
200 #pragma intrinsic(_BitScanForward64)
201 #endif
202 
203 #endif // __CUDACC_RTC__
204 
205 #if defined(__CUDACC__) || defined(__HIP__)
206 // Only define __hostdev__ when using NVIDIA CUDA or HIP compilers
207 #ifndef __hostdev__
208 #define __hostdev__ __host__ __device__ // Runs on the CPU and GPU, called from the CPU or the GPU
209 #endif
210 #else
211 // Dummy definitions of macros only defined by CUDA and HIP compilers
212 #ifndef __hostdev__
213 #define __hostdev__ // Runs on the CPU and GPU, called from the CPU or the GPU
214 #endif
215 #ifndef __global__
216 #define __global__ // Runs on the GPU, called from the CPU or the GPU
217 #endif
218 #ifndef __device__
219 #define __device__ // Runs on the GPU, called from the GPU
220 #endif
221 #ifndef __host__
222 #define __host__ // Runs on the CPU, called from the CPU
223 #endif
224 
225 #endif // if defined(__CUDACC__) || defined(__HIP__)
226 
227 // The following macro will suppress annoying warnings when nvcc
228 // compiles functions that call (host) intrinsics (which is perfectly valid)
229 #if defined(_MSC_VER) && defined(__CUDACC__)
230 #define NANOVDB_HOSTDEV_DISABLE_WARNING __pragma("hd_warning_disable")
231 #elif defined(__GNUC__) && defined(__CUDACC__)
232 #define NANOVDB_HOSTDEV_DISABLE_WARNING _Pragma("hd_warning_disable")
233 #else
234 #define NANOVDB_HOSTDEV_DISABLE_WARNING
235 #endif
236 
237 // Define compiler warnings that work with all compilers
238 //#if defined(_MSC_VER)
239 //#define NANO_WARNING(msg) _pragma("message" #msg)
240 //#else
241 //#define NANO_WARNING(msg) _Pragma("message" #msg)
242 //#endif
243 
244 // A portable implementation of offsetof - unfortunately it doesn't work with static_assert
245 #define NANOVDB_OFFSETOF(CLASS, MEMBER) ((int)(size_t)((char*)&((CLASS*)0)->MEMBER - (char*)0))
246 
247 namespace nanovdb {
248 
249 // --------------------------> Build types <------------------------------------
250 
251 /// @brief Dummy type for a voxel whose value equals an offset into an external value array
252 class ValueIndex{};
253 
254 /// @brief Dummy type for a voxel whose value equals an offset into an external value array of active values
255 class ValueOnIndex{};
256 
257 /// @brief Like @c ValueIndex but with a mutable mask
259 
260 /// @brief Like @c ValueOnIndex but with a mutable mask
262 
263 /// @brief Dummy type for a voxel whose value equals its binary active state
264 class ValueMask{};
265 
266 /// @brief Dummy type for a 16 bit floating point values (placeholder for IEEE 754 Half)
267 class Half{};
268 
269 /// @brief Dummy type for a 4bit quantization of float point values
270 class Fp4{};
271 
272 /// @brief Dummy type for a 8bit quantization of float point values
273 class Fp8{};
274 
275 /// @brief Dummy type for a 16bit quantization of float point values
276 class Fp16{};
277 
278 /// @brief Dummy type for a variable bit quantization of floating point values
279 class FpN{};
280 
281 /// @brief Dummy type for indexing points into voxels
282 class Point{};
283 
284 // --------------------------> GridType <------------------------------------
285 
286 /// @brief List of types that are currently supported by NanoVDB
287 ///
288 /// @note To expand on this list do:
289 /// 1) Add the new type between Unknown and End in the enum below
290 /// 2) Add the new type to OpenToNanoVDB::processGrid that maps OpenVDB types to GridType
291 /// 3) Verify that the ConvertTrait in NanoToOpenVDB.h works correctly with the new type
292 /// 4) Add the new type to mapToGridType (defined below) that maps NanoVDB types to GridType
293 /// 5) Add the new type to toStr (defined below)
294 enum class GridType : uint32_t { Unknown = 0, // unknown value type - should rarely be used
295  Float = 1, // single precision floating point value
296  Double = 2, // double precision floating point value
297  Int16 = 3, // half precision signed integer value
298  Int32 = 4, // single precision signed integer value
299  Int64 = 5, // double precision signed integer value
300  Vec3f = 6, // single precision floating 3D vector
301  Vec3d = 7, // double precision floating 3D vector
302  Mask = 8, // no value, just the active state
303  Half = 9, // half precision floating point value (placeholder for IEEE 754 Half)
304  UInt32 = 10, // single precision unsigned integer value
305  Boolean = 11, // boolean value, encoded in bit array
306  RGBA8 = 12, // RGBA packed into 32bit word in reverse-order, i.e. R is lowest byte.
307  Fp4 = 13, // 4bit quantization of floating point value
308  Fp8 = 14, // 8bit quantization of floating point value
309  Fp16 = 15, // 16bit quantization of floating point value
310  FpN = 16, // variable bit quantization of floating point value
311  Vec4f = 17, // single precision floating 4D vector
312  Vec4d = 18, // double precision floating 4D vector
313  Index = 19, // index into an external array of active and inactive values
314  OnIndex = 20, // index into an external array of active values
315  IndexMask = 21, // like Index but with a mutable mask
316  OnIndexMask = 22, // like OnIndex but with a mutable mask
317  PointIndex = 23, // voxels encode indices to co-located points
318  Vec3u8 = 24, // 8bit quantization of floating point 3D vector (only as blind data)
319  Vec3u16 = 25, // 16bit quantization of floating point 3D vector (only as blind data)
320  End = 26 }; // should never be used
321 
322 #ifndef __CUDACC_RTC__
323 /// @brief Maps a GridType to a c-string
324 /// @param gridType GridType to be mapped to a string
325 /// @return Retuns a c-string used to describe a GridType
326 inline const char* toStr(GridType gridType)
327 {
328  static const char* LUT[] = {"?", "float", "double", "int16", "int32", "int64", "Vec3f", "Vec3d", "Mask", "Half",
329  "uint32", "bool", "RGBA8", "Float4", "Float8", "Float16", "FloatN", "Vec4f", "Vec4d",
330  "Index", "OnIndex", "IndexMask", "OnIndexMask", "PointIndex", "Vec3u8", "Vec3u16", "End"};
331  static_assert(sizeof(LUT) / sizeof(char*) - 1 == int(GridType::End), "Unexpected size of LUT");
332  return LUT[static_cast<int>(gridType)];
333 }
334 #endif
335 
336 // --------------------------> GridClass <------------------------------------
337 
338 /// @brief Classes (superset of OpenVDB) that are currently supported by NanoVDB
339 enum class GridClass : uint32_t { Unknown = 0,
340  LevelSet = 1, // narrow band level set, e.g. SDF
341  FogVolume = 2, // fog volume, e.g. density
342  Staggered = 3, // staggered MAC grid, e.g. velocity
343  PointIndex = 4, // point index grid
344  PointData = 5, // point data grid
345  Topology = 6, // grid with active states only (no values)
346  VoxelVolume = 7, // volume of geometric cubes, e.g. colors cubes in Minecraft
347  IndexGrid = 8, // grid whose values are offsets, e.g. into an external array
348  TensorGrid = 9, // Index grid for indexing learnable tensor features
349  End = 10 };
350 
351 #ifndef __CUDACC_RTC__
352 /// @brief Retuns a c-string used to describe a GridClass
353 inline const char* toStr(GridClass gridClass)
354 {
355  static const char* LUT[] = {"?", "SDF", "FOG", "MAC", "PNTIDX", "PNTDAT", "TOPO", "VOX", "INDEX", "TENSOR", "END"};
356  static_assert(sizeof(LUT) / sizeof(char*) - 1 == int(GridClass::End), "Unexpected size of LUT");
357  return LUT[static_cast<int>(gridClass)];
358 }
359 #endif
360 
361 // --------------------------> GridFlags <------------------------------------
362 
363 /// @brief Grid flags which indicate what extra information is present in the grid buffer.
364 enum class GridFlags : uint32_t {
365  HasLongGridName = 1 << 0, // grid name is longer than 256 characters
366  HasBBox = 1 << 1, // nodes contain bounding-boxes of active values
367  HasMinMax = 1 << 2, // nodes contain min/max of active values
368  HasAverage = 1 << 3, // nodes contain averages of active values
369  HasStdDeviation = 1 << 4, // nodes contain standard deviations of active values
370  IsBreadthFirst = 1 << 5, // nodes are typically arranged breadth-first in memory
371  End = 1 << 6, // use End - 1 as a mask for the 5 lower bit flags
372 };
373 
374 #ifndef __CUDACC_RTC__
375 /// @brief Retuns a c-string used to describe a GridFlags
376 inline const char* toStr(GridFlags gridFlags)
377 {
378  static const char* LUT[] = {"has long grid name",
379  "has bbox",
380  "has min/max",
381  "has average",
382  "has standard deviation",
383  "is breadth-first",
384  "end"};
385  static_assert(1 << (sizeof(LUT) / sizeof(char*) - 1) == int(GridFlags::End), "Unexpected size of LUT");
386  return LUT[static_cast<int>(gridFlags)];
387 }
388 #endif
389 
390 // --------------------------> GridBlindData enums <------------------------------------
391 
392 /// @brief Blind-data Classes that are currently supported by NanoVDB
393 enum class GridBlindDataClass : uint32_t { Unknown = 0,
394  IndexArray = 1,
395  AttributeArray = 2,
396  GridName = 3,
397  ChannelArray = 4,
398  End = 5 };
399 
400 /// @brief Blind-data Semantics that are currently understood by NanoVDB
401 enum class GridBlindDataSemantic : uint32_t { Unknown = 0,
402  PointPosition = 1, // 3D coordinates in an unknown space
403  PointColor = 2,
404  PointNormal = 3,
405  PointRadius = 4,
406  PointVelocity = 5,
407  PointId = 6,
408  WorldCoords = 7, // 3D coordinates in world space, e.g. (0.056, 0.8, 1,8)
409  GridCoords = 8, // 3D coordinates in grid space, e.g. (1.2, 4.0, 5.7), aka index-space
410  VoxelCoords = 9, // 3D coordinates in voxel space, e.g. (0.2, 0.0, 0.7)
411  End = 10 };
412 
413 // --------------------------> is_same <------------------------------------
414 
415 /// @brief C++11 implementation of std::is_same
416 /// @note When more than two arguments are provided value = T0==T1 || T0==T2 || ...
417 template<typename T0, typename T1, typename ...T>
418 struct is_same
419 {
420  static constexpr bool value = is_same<T0, T1>::value || is_same<T0, T...>::value;
421 };
422 
423 template<typename T0, typename T1>
424 struct is_same<T0, T1>
425 {
426  static constexpr bool value = false;
427 };
428 
429 template<typename T>
430 struct is_same<T, T>
431 {
432  static constexpr bool value = true;
433 };
434 
435 // --------------------------> is_floating_point <------------------------------------
436 
437 /// @brief C++11 implementation of std::is_floating_point
438 template<typename T>
440 {
441  static constexpr bool value = is_same<T, float, double>::value;
442 };
443 
444 // --------------------------> BuildTraits <------------------------------------
445 
446 /// @brief Define static boolean tests for template build types
447 template<typename T>
449 {
450  // check if T is an index type
455  // check if T is a compressed float type with fixed bit precision
456  static constexpr bool is_FpX = is_same<T, Fp4, Fp8, Fp16>::value;
457  // check if T is a compressed float type with fixed or variable bit precision
459  // check if T is a POD float type, i.e float or double
460  static constexpr bool is_float = is_floating_point<T>::value;
461  // check if T is a template specialization of LeafData<T>, i.e. has T mValues[512]
463 }; // BuildTraits
464 
465 // --------------------------> enable_if <------------------------------------
466 
467 /// @brief C++11 implementation of std::enable_if
468 template <bool, typename T = void>
469 struct enable_if
470 {
471 };
472 
473 template <typename T>
474 struct enable_if<true, T>
475 {
476  using type = T;
477 };
478 
479 // --------------------------> disable_if <------------------------------------
480 
481 template<bool, typename T = void>
483 {
484  typedef T type;
485 };
486 
487 template<typename T>
488 struct disable_if<true, T>
489 {
490 };
491 
492 // --------------------------> is_const <------------------------------------
493 
494 template<typename T>
495 struct is_const
496 {
497  static constexpr bool value = false;
498 };
499 
500 template<typename T>
501 struct is_const<const T>
502 {
503  static constexpr bool value = true;
504 };
505 
506 // --------------------------> is_pointer <------------------------------------
507 
508 /// @brief Trait used to identify template parameter that are pointers
509 /// @tparam T Template parameter to be tested
510 template<class T>
512 {
513  static constexpr bool value = false;
514 };
515 
516 /// @brief Template specialization of non-const pointers
517 /// @tparam T Template parameter to be tested
518 template<class T>
519 struct is_pointer<T*>
520 {
521  static constexpr bool value = true;
522 };
523 
524 /// @brief Template specialization of const pointers
525 /// @tparam T Template parameter to be tested
526 template<class T>
527 struct is_pointer<const T*>
528 {
529  static constexpr bool value = true;
530 };
531 
532 // --------------------------> remove_const <------------------------------------
533 
534 /// @brief Trait use to const from type. Default implementation is just a pass-through
535 /// @tparam T Type
536 /// @details remove_pointer<float>::type = float
537 template<typename T>
539 {
540  using type = T;
541 };
542 
543 /// @brief Template specialization of trait class use to remove const qualifier type from a type
544 /// @tparam T Type of the const type
545 /// @details remove_pointer<const float>::type = float
546 template<typename T>
547 struct remove_const<const T>
548 {
549  using type = T;
550 };
551 
552 // --------------------------> remove_reference <------------------------------------
553 
554 /// @brief Trait use to remove reference, i.e. "&", qualifier from a type. Default implementation is just a pass-through
555 /// @tparam T Type
556 /// @details remove_pointer<float>::type = float
557 template <typename T>
558 struct remove_reference {using type = T;};
559 
560 /// @brief Template specialization of trait class use to remove reference, i.e. "&", qualifier from a type
561 /// @tparam T Type of the reference
562 /// @details remove_pointer<float&>::type = float
563 template <typename T>
564 struct remove_reference<T&> {using type = T;};
565 
566 // --------------------------> remove_pointer <------------------------------------
567 
568 /// @brief Trait use to remove pointer, i.e. "*", qualifier from a type. Default implementation is just a pass-through
569 /// @tparam T Type
570 /// @details remove_pointer<float>::type = float
571 template <typename T>
572 struct remove_pointer {using type = T;};
573 
574 /// @brief Template specialization of trait class use to to remove pointer, i.e. "*", qualifier from a type
575 /// @tparam T Type of the pointer
576 /// @details remove_pointer<float*>::type = float
577 template <typename T>
578 struct remove_pointer<T*> {using type = T;};
579 
580 // --------------------------> match_const <------------------------------------
581 
582 /// @brief Trait used to transfer the const-ness of a reference type to another type
583 /// @tparam T Type whose const-ness needs to match the reference type
584 /// @tparam ReferenceT Reference type that is not const
585 /// @details match_const<const int, float>::type = int
586 /// match_const<int, float>::type = int
587 template<typename T, typename ReferenceT>
589 {
590  using type = typename remove_const<T>::type;
591 };
592 
593 /// @brief Template specialization used to transfer the const-ness of a reference type to another type
594 /// @tparam T Type that will adopt the const-ness of the reference type
595 /// @tparam ReferenceT Reference type that is const
596 /// @details match_const<const int, const float>::type = const int
597 /// match_const<int, const float>::type = const int
598 template<typename T, typename ReferenceT>
599 struct match_const<T, const ReferenceT>
600 {
601  using type = const typename remove_const<T>::type;
602 };
603 
604 // --------------------------> is_specialization <------------------------------------
605 
606 /// @brief Metafunction used to determine if the first template
607 /// parameter is a specialization of the class template
608 /// given in the second template parameter.
609 ///
610 /// @details is_specialization<Vec3<float>, Vec3>::value == true;
611 /// is_specialization<Vec3f, Vec3>::value == true;
612 /// is_specialization<std::vector<float>, std::vector>::value == true;
613 template<typename AnyType, template<typename...> class TemplateType>
615 {
616  static const bool value = false;
617 };
618 template<typename... Args, template<typename...> class TemplateType>
619 struct is_specialization<TemplateType<Args...>, TemplateType>
620 {
621  static const bool value = true;
622 };
623 
624 // --------------------------> BuildToValueMap <------------------------------------
625 
626 /// @brief Maps one type (e.g. the build types above) to other (actual) types
627 template<typename T>
629 {
630  using Type = T;
631  using type = T;
632 };
633 
634 template<>
636 {
637  using Type = uint64_t;
638  using type = uint64_t;
639 };
640 
641 template<>
643 {
644  using Type = uint64_t;
645  using type = uint64_t;
646 };
647 
648 template<>
650 {
651  using Type = uint64_t;
652  using type = uint64_t;
653 };
654 
655 template<>
657 {
658  using Type = uint64_t;
659  using type = uint64_t;
660 };
661 
662 template<>
664 {
665  using Type = bool;
666  using type = bool;
667 };
668 
669 template<>
671 {
672  using Type = float;
673  using type = float;
674 };
675 
676 template<>
678 {
679  using Type = float;
680  using type = float;
681 };
682 
683 template<>
685 {
686  using Type = float;
687  using type = float;
688 };
689 
690 template<>
692 {
693  using Type = float;
694  using type = float;
695 };
696 
697 template<>
699 {
700  using Type = float;
701  using type = float;
702 };
703 
704 template<>
706 {
707  using Type = uint64_t;
708  using type = uint64_t;
709 };
710 
711 // --------------------------> utility functions related to alignment <------------------------------------
712 
713 /// @brief return true if the specified pointer is aligned
714 __hostdev__ inline static bool isAligned(const void* p)
715 {
716  return uint64_t(p) % NANOVDB_DATA_ALIGNMENT == 0;
717 }
718 
719 /// @brief return true if the specified pointer is aligned and not NULL
720 __hostdev__ inline static bool isValid(const void* p)
721 {
722  return p != nullptr && uint64_t(p) % NANOVDB_DATA_ALIGNMENT == 0;
723 }
724 
725 /// @brief return the smallest number of bytes that when added to the specified pointer results in an aligned pointer
726 __hostdev__ inline static uint64_t alignmentPadding(const void* p)
727 {
728  NANOVDB_ASSERT(p);
730 }
731 
732 /// @brief offset the specified pointer so it is aligned.
733 template <typename T>
734 __hostdev__ inline static T* alignPtr(T* p)
735 {
736  NANOVDB_ASSERT(p);
737  return reinterpret_cast<T*>( (uint8_t*)p + alignmentPadding(p) );
738 }
739 
740 /// @brief offset the specified const pointer so it is aligned.
741 template <typename T>
742 __hostdev__ inline static const T* alignPtr(const T* p)
743 {
744  NANOVDB_ASSERT(p);
745  return reinterpret_cast<const T*>( (const uint8_t*)p + alignmentPadding(p) );
746 }
747 
748 // --------------------------> PtrDiff <------------------------------------
749 
750 /// @brief Compute the distance, in bytes, between two pointers
751 /// @tparam T1 Type of the first pointer
752 /// @tparam T2 Type of the second pointer
753 /// @param p fist pointer, assumed to NOT be NULL
754 /// @param q second pointer, assumed to NOT be NULL
755 /// @return signed distance between pointer addresses in units of bytes
756 template<typename T1, typename T2>
757 __hostdev__ inline static int64_t PtrDiff(const T1* p, const T2* q)
758 {
759  NANOVDB_ASSERT(p && q);
760  return reinterpret_cast<const char*>(p) - reinterpret_cast<const char*>(q);
761 }
762 
763 // --------------------------> PtrAdd <------------------------------------
764 
765 /// @brief Adds a byte offset of a non-const pointer to produce another non-const pointer
766 /// @tparam DstT Type of the return pointer
767 /// @tparam SrcT Type of the input pointer
768 /// @param p non-const input pointer, assumed to NOT be NULL
769 /// @param offset signed byte offset
770 /// @return a non-const pointer defined as the offset of an input pointer
771 template<typename DstT, typename SrcT>
772 __hostdev__ inline static DstT* PtrAdd(SrcT* p, int64_t offset)
773 {
774  NANOVDB_ASSERT(p);
775  return reinterpret_cast<DstT*>(reinterpret_cast<char*>(p) + offset);
776 }
777 
778 /// @brief Adds a byte offset of a const pointer to produce another const pointer
779 /// @tparam DstT Type of the return pointer
780 /// @tparam SrcT Type of the input pointer
781 /// @param p const input pointer, assumed to NOT be NULL
782 /// @param offset signed byte offset
783 /// @return a const pointer defined as the offset of a const input pointer
784 template<typename DstT, typename SrcT>
785 __hostdev__ inline static const DstT* PtrAdd(const SrcT* p, int64_t offset)
786 {
787  NANOVDB_ASSERT(p);
788  return reinterpret_cast<const DstT*>(reinterpret_cast<const char*>(p) + offset);
789 }
790 
791 // --------------------------> isFloatingPoint(GridType) <------------------------------------
792 
793 /// @brief return true if the GridType maps to a floating point type
794 __hostdev__ inline bool isFloatingPoint(GridType gridType)
795 {
796  return gridType == GridType::Float ||
797  gridType == GridType::Double ||
798  gridType == GridType::Half ||
799  gridType == GridType::Fp4 ||
800  gridType == GridType::Fp8 ||
801  gridType == GridType::Fp16 ||
802  gridType == GridType::FpN;
803 }
804 
805 // --------------------------> isFloatingPointVector(GridType) <------------------------------------
806 
807 /// @brief return true if the GridType maps to a floating point vec3.
809 {
810  return gridType == GridType::Vec3f ||
811  gridType == GridType::Vec3d ||
812  gridType == GridType::Vec4f ||
813  gridType == GridType::Vec4d;
814 }
815 
816 // --------------------------> isInteger(GridType) <------------------------------------
817 
818 /// @brief Return true if the GridType maps to a POD integer type.
819 /// @details These types are used to associate a voxel with a POD integer type
820 __hostdev__ inline bool isInteger(GridType gridType)
821 {
822  return gridType == GridType::Int16 ||
823  gridType == GridType::Int32 ||
824  gridType == GridType::Int64 ||
825  gridType == GridType::UInt32;
826 }
827 
828 // --------------------------> isIndex(GridType) <------------------------------------
829 
830 /// @brief Return true if the GridType maps to a special index type (not a POD integer type).
831 /// @details These types are used to index from a voxel into an external array of values, e.g. sidecar or blind data.
832 __hostdev__ inline bool isIndex(GridType gridType)
833 {
834  return gridType == GridType::Index ||// index both active and inactive values
835  gridType == GridType::OnIndex ||// index active values only
836  gridType == GridType::IndexMask ||// as Index, but with an additional mask
837  gridType == GridType::OnIndexMask;// as OnIndex, but with an additional mask
838 }
839 
840 // --------------------------> memcpy64 <------------------------------------
841 
842 /// @brief copy 64 bit words from @c src to @c dst
843 /// @param dst 64 bit aligned pointer to destination
844 /// @param src 64 bit aligned pointer to source
845 /// @param word_count number of 64 bit words to be copied
846 /// @return destination pointer @c dst
847 /// @warning @c src and @c dst cannot overlap and should both be 64 bit aligned
848 __hostdev__ inline static void* memcpy64(void *dst, const void *src, size_t word_count)
849 {
850  NANOVDB_ASSERT(uint64_t(dst) % 8 == 0 && uint64_t(src) % 8 == 0);
851  auto *d = reinterpret_cast<uint64_t*>(dst), *e = d + word_count;
852  auto *s = reinterpret_cast<const uint64_t*>(src);
853  while (d != e) *d++ = *s++;
854  return dst;
855 }
856 
857 // --------------------------> isValue(GridType, GridClass) <------------------------------------
858 
859 /// @brief return true if the combination of GridType and GridClass is valid.
860 __hostdev__ inline bool isValid(GridType gridType, GridClass gridClass)
861 {
862  if (gridClass == GridClass::LevelSet || gridClass == GridClass::FogVolume) {
863  return isFloatingPoint(gridType);
864  } else if (gridClass == GridClass::Staggered) {
865  return isFloatingPointVector(gridType);
866  } else if (gridClass == GridClass::PointIndex || gridClass == GridClass::PointData) {
867  return gridType == GridType::PointIndex || gridType == GridType::UInt32;
868  } else if (gridClass == GridClass::Topology) {
869  return gridType == GridType::Mask;
870  } else if (gridClass == GridClass::IndexGrid) {
871  return isIndex(gridType);
872  } else if (gridClass == GridClass::VoxelVolume) {
873  return gridType == GridType::RGBA8 || gridType == GridType::Float ||
874  gridType == GridType::Double || gridType == GridType::Vec3f ||
875  gridType == GridType::Vec3d || gridType == GridType::UInt32;
876  }
877  return gridClass < GridClass::End && gridType < GridType::End; // any valid combination
878 }
879 
880 // --------------------------> validation of blind data meta data <------------------------------------
881 
882 /// @brief return true if the combination of GridBlindDataClass, GridBlindDataSemantic and GridType is valid.
883 __hostdev__ inline bool isValid(const GridBlindDataClass& blindClass,
884  const GridBlindDataSemantic& blindSemantics,
885  const GridType& blindType)
886 {
887  bool test = false;
888  switch (blindClass) {
890  test = (blindSemantics == GridBlindDataSemantic::Unknown ||
891  blindSemantics == GridBlindDataSemantic::PointId) &&
892  isInteger(blindType);
893  break;
895  if (blindSemantics == GridBlindDataSemantic::PointPosition ||
896  blindSemantics == GridBlindDataSemantic::WorldCoords) {
897  test = blindType == GridType::Vec3f || blindType == GridType::Vec3d;
898  } else if (blindSemantics == GridBlindDataSemantic::GridCoords) {
899  test = blindType == GridType::Vec3f;
900  } else if (blindSemantics == GridBlindDataSemantic::VoxelCoords) {
901  test = blindType == GridType::Vec3f || blindType == GridType::Vec3u8 || blindType == GridType::Vec3u16;
902  } else {
903  test = blindSemantics != GridBlindDataSemantic::PointId;
904  }
905  break;
907  test = blindSemantics == GridBlindDataSemantic::Unknown && blindType == GridType::Unknown;
908  break;
909  default: // captures blindClass == Unknown and ChannelArray
910  test = blindClass < GridBlindDataClass::End &&
911  blindSemantics < GridBlindDataSemantic::End &&
912  blindType < GridType::End; // any valid combination
913  break;
914  }
915  //if (!test) printf("Invalid combination: GridBlindDataClass=%u, GridBlindDataSemantic=%u, GridType=%u\n",(uint32_t)blindClass, (uint32_t)blindSemantics, (uint32_t)blindType);
916  return test;
917 }
918 
919 // ----------------------------> Version class <-------------------------------------
920 
921 /// @brief Bit-compacted representation of all three version numbers
922 ///
923 /// @details major is the top 11 bits, minor is the 11 middle bits and patch is the lower 10 bits
924 class Version
925 {
926  uint32_t mData; // 11 + 11 + 10 bit packing of major + minor + patch
927 public:
928  /// @brief Default constructor
930  : mData(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER) << 21 |
931  uint32_t(NANOVDB_MINOR_VERSION_NUMBER) << 10 |
933  {
934  }
935  /// @brief Constructor from a raw uint32_t data representation
936  __hostdev__ Version(uint32_t data) : mData(data) {}
937  /// @brief Constructor from major.minor.patch version numbers
938  __hostdev__ Version(uint32_t major, uint32_t minor, uint32_t patch)
939  : mData(major << 21 | minor << 10 | patch)
940  {
941  NANOVDB_ASSERT(major < (1u << 11)); // max value of major is 2047
942  NANOVDB_ASSERT(minor < (1u << 11)); // max value of minor is 2047
943  NANOVDB_ASSERT(patch < (1u << 10)); // max value of patch is 1023
944  }
945  __hostdev__ bool operator==(const Version& rhs) const { return mData == rhs.mData; }
946  __hostdev__ bool operator<( const Version& rhs) const { return mData < rhs.mData; }
947  __hostdev__ bool operator<=(const Version& rhs) const { return mData <= rhs.mData; }
948  __hostdev__ bool operator>( const Version& rhs) const { return mData > rhs.mData; }
949  __hostdev__ bool operator>=(const Version& rhs) const { return mData >= rhs.mData; }
950  __hostdev__ uint32_t id() const { return mData; }
951  __hostdev__ uint32_t getMajor() const { return (mData >> 21) & ((1u << 11) - 1); }
952  __hostdev__ uint32_t getMinor() const { return (mData >> 10) & ((1u << 11) - 1); }
953  __hostdev__ uint32_t getPatch() const { return mData & ((1u << 10) - 1); }
954  __hostdev__ bool isCompatible() const { return this->getMajor() == uint32_t(NANOVDB_MAJOR_VERSION_NUMBER); }
955  /// @brief Returns the difference between major version of this instance and NANOVDB_MAJOR_VERSION_NUMBER
956  /// @return return 0 if the major version equals NANOVDB_MAJOR_VERSION_NUMBER, else a negative age if this
957  /// instance has a smaller major verion (is older), and a positive age if it is newer, i.e. larger.
958  __hostdev__ int age() const {return int(this->getMajor()) - int(NANOVDB_MAJOR_VERSION_NUMBER);}
959 
960 #ifndef __CUDACC_RTC__
961  /// @brief returns a c-string of the semantic version, i.e. major.minor.patch
962  const char* c_str() const
963  {
964  char* buffer = (char*)malloc(4 + 1 + 4 + 1 + 4 + 1); // xxxx.xxxx.xxxx\0
965  snprintf(buffer, 4 + 1 + 4 + 1 + 4 + 1, "%u.%u.%u", this->getMajor(), this->getMinor(), this->getPatch()); // Prevents overflows by enforcing a fixed size of buffer
966  return buffer;
967  }
968 #endif
969 }; // Version
970 
971 // ----------------------------> Various math functions <-------------------------------------
972 
973 //@{
974 /// @brief Pi constant taken from Boost to match old behaviour
975 template<typename T>
976 inline __hostdev__ constexpr T pi()
977 {
978  return 3.141592653589793238462643383279502884e+00;
979 }
980 template<>
981 inline __hostdev__ constexpr float pi()
982 {
983  return 3.141592653589793238462643383279502884e+00F;
984 }
985 template<>
986 inline __hostdev__ constexpr double pi()
987 {
988  return 3.141592653589793238462643383279502884e+00;
989 }
990 template<>
991 inline __hostdev__ constexpr long double pi()
992 {
993  return 3.141592653589793238462643383279502884e+00L;
994 }
995 //@}
996 
997 //@{
998 /// Tolerance for floating-point comparison
999 template<typename T>
1000 struct Tolerance;
1001 template<>
1003 {
1004  __hostdev__ static float value() { return 1e-8f; }
1005 };
1006 template<>
1007 struct Tolerance<double>
1008 {
1009  __hostdev__ static double value() { return 1e-15; }
1010 };
1011 //@}
1012 
1013 //@{
1014 /// Delta for small floating-point offsets
1015 template<typename T>
1016 struct Delta;
1017 template<>
1018 struct Delta<float>
1019 {
1020  __hostdev__ static float value() { return 1e-5f; }
1021 };
1022 template<>
1023 struct Delta<double>
1024 {
1025  __hostdev__ static double value() { return 1e-9; }
1026 };
1027 //@}
1028 
1029 //@{
1030 /// Maximum floating-point values
1031 template<typename T>
1032 struct Maximum;
1033 #if defined(__CUDA_ARCH__) || defined(__HIP__)
1034 template<>
1035 struct Maximum<int>
1036 {
1037  __hostdev__ static int value() { return 2147483647; }
1038 };
1039 template<>
1040 struct Maximum<uint32_t>
1041 {
1042  __hostdev__ static uint32_t value() { return 4294967295u; }
1043 };
1044 template<>
1045 struct Maximum<float>
1046 {
1047  __hostdev__ static float value() { return 1e+38f; }
1048 };
1049 template<>
1050 struct Maximum<double>
1051 {
1052  __hostdev__ static double value() { return 1e+308; }
1053 };
1054 #else
1055 template<typename T>
1056 struct Maximum
1057 {
1058  static T value() { return std::numeric_limits<T>::max(); }
1059 };
1060 #endif
1061 //@}
1062 
1063 template<typename Type>
1064 __hostdev__ inline bool isApproxZero(const Type& x)
1065 {
1066  return !(x > Tolerance<Type>::value()) && !(x < -Tolerance<Type>::value());
1067 }
1068 
1069 template<typename Type>
1071 {
1072  return (a < b) ? a : b;
1073 }
1074 __hostdev__ inline int32_t Min(int32_t a, int32_t b)
1075 {
1076  return int32_t(fminf(float(a), float(b)));
1077 }
1078 __hostdev__ inline uint32_t Min(uint32_t a, uint32_t b)
1079 {
1080  return uint32_t(fminf(float(a), float(b)));
1081 }
1082 __hostdev__ inline float Min(float a, float b)
1083 {
1084  return fminf(a, b);
1085 }
1086 __hostdev__ inline double Min(double a, double b)
1087 {
1088  return fmin(a, b);
1089 }
1090 template<typename Type>
1092 {
1093  return (a > b) ? a : b;
1094 }
1095 
1096 __hostdev__ inline int32_t Max(int32_t a, int32_t b)
1097 {
1098  return int32_t(fmaxf(float(a), float(b)));
1099 }
1100 __hostdev__ inline uint32_t Max(uint32_t a, uint32_t b)
1101 {
1102  return uint32_t(fmaxf(float(a), float(b)));
1103 }
1104 __hostdev__ inline float Max(float a, float b)
1105 {
1106  return fmaxf(a, b);
1107 }
1108 __hostdev__ inline double Max(double a, double b)
1109 {
1110  return fmax(a, b);
1111 }
1112 __hostdev__ inline float Clamp(float x, float a, float b)
1113 {
1114  return Max(Min(x, b), a);
1115 }
1116 __hostdev__ inline double Clamp(double x, double a, double b)
1117 {
1118  return Max(Min(x, b), a);
1119 }
1120 
1121 __hostdev__ inline float Fract(float x)
1122 {
1123  return x - floorf(x);
1124 }
1125 __hostdev__ inline double Fract(double x)
1126 {
1127  return x - floor(x);
1128 }
1129 
1130 __hostdev__ inline int32_t Floor(float x)
1131 {
1132  return int32_t(floorf(x));
1133 }
1134 __hostdev__ inline int32_t Floor(double x)
1135 {
1136  return int32_t(floor(x));
1137 }
1138 
1139 __hostdev__ inline int32_t Ceil(float x)
1140 {
1141  return int32_t(ceilf(x));
1142 }
1143 __hostdev__ inline int32_t Ceil(double x)
1144 {
1145  return int32_t(ceil(x));
1146 }
1147 
1148 template<typename T>
1149 __hostdev__ inline T Pow2(T x)
1150 {
1151  return x * x;
1152 }
1153 
1154 template<typename T>
1155 __hostdev__ inline T Pow3(T x)
1156 {
1157  return x * x * x;
1158 }
1159 
1160 template<typename T>
1161 __hostdev__ inline T Pow4(T x)
1162 {
1163  return Pow2(x * x);
1164 }
1165 template<typename T>
1166 __hostdev__ inline T Abs(T x)
1167 {
1168  return x < 0 ? -x : x;
1169 }
1170 
1171 template<>
1172 __hostdev__ inline float Abs(float x)
1173 {
1174  return fabsf(x);
1175 }
1176 
1177 template<>
1178 __hostdev__ inline double Abs(double x)
1179 {
1180  return fabs(x);
1181 }
1182 
1183 template<>
1184 __hostdev__ inline int Abs(int x)
1185 {
1186  return abs(x);
1187 }
1188 
1189 template<typename CoordT, typename RealT, template<typename> class Vec3T>
1190 __hostdev__ inline CoordT Round(const Vec3T<RealT>& xyz);
1191 
1192 template<typename CoordT, template<typename> class Vec3T>
1193 __hostdev__ inline CoordT Round(const Vec3T<float>& xyz)
1194 {
1195  return CoordT(int32_t(rintf(xyz[0])), int32_t(rintf(xyz[1])), int32_t(rintf(xyz[2])));
1196  //return CoordT(int32_t(roundf(xyz[0])), int32_t(roundf(xyz[1])), int32_t(roundf(xyz[2])) );
1197  //return CoordT(int32_t(floorf(xyz[0] + 0.5f)), int32_t(floorf(xyz[1] + 0.5f)), int32_t(floorf(xyz[2] + 0.5f)));
1198 }
1199 
1200 template<typename CoordT, template<typename> class Vec3T>
1201 __hostdev__ inline CoordT Round(const Vec3T<double>& xyz)
1202 {
1203  return CoordT(int32_t(floor(xyz[0] + 0.5)), int32_t(floor(xyz[1] + 0.5)), int32_t(floor(xyz[2] + 0.5)));
1204 }
1205 
1206 template<typename CoordT, typename RealT, template<typename> class Vec3T>
1207 __hostdev__ inline CoordT RoundDown(const Vec3T<RealT>& xyz)
1208 {
1209  return CoordT(Floor(xyz[0]), Floor(xyz[1]), Floor(xyz[2]));
1210 }
1211 
1212 //@{
1213 /// Return the square root of a floating-point value.
1214 __hostdev__ inline float Sqrt(float x)
1215 {
1216  return sqrtf(x);
1217 }
1218 __hostdev__ inline double Sqrt(double x)
1219 {
1220  return sqrt(x);
1221 }
1222 //@}
1223 
1224 /// Return the sign of the given value as an integer (either -1, 0 or 1).
1225 template<typename T>
1226 __hostdev__ inline T Sign(const T& x)
1227 {
1228  return ((T(0) < x) ? T(1) : T(0)) - ((x < T(0)) ? T(1) : T(0));
1229 }
1230 
1231 template<typename Vec3T>
1232 __hostdev__ inline int MinIndex(const Vec3T& v)
1233 {
1234 #if 0
1235  static const int hashTable[8] = {2, 1, 9, 1, 2, 9, 0, 0}; //9 are dummy values
1236  const int hashKey = ((v[0] < v[1]) << 2) + ((v[0] < v[2]) << 1) + (v[1] < v[2]); // ?*4+?*2+?*1
1237  return hashTable[hashKey];
1238 #else
1239  if (v[0] < v[1] && v[0] < v[2])
1240  return 0;
1241  if (v[1] < v[2])
1242  return 1;
1243  else
1244  return 2;
1245 #endif
1246 }
1247 
1248 template<typename Vec3T>
1249 __hostdev__ inline int MaxIndex(const Vec3T& v)
1250 {
1251 #if 0
1252  static const int hashTable[8] = {2, 1, 9, 1, 2, 9, 0, 0}; //9 are dummy values
1253  const int hashKey = ((v[0] > v[1]) << 2) + ((v[0] > v[2]) << 1) + (v[1] > v[2]); // ?*4+?*2+?*1
1254  return hashTable[hashKey];
1255 #else
1256  if (v[0] > v[1] && v[0] > v[2])
1257  return 0;
1258  if (v[1] > v[2])
1259  return 1;
1260  else
1261  return 2;
1262 #endif
1263 }
1264 
1265 /// @brief round up byteSize to the nearest wordSize, e.g. to align to machine word: AlignUp<sizeof(size_t)(n)
1266 ///
1267 /// @details both wordSize and byteSize are in byte units
1268 template<uint64_t wordSize>
1269 __hostdev__ inline uint64_t AlignUp(uint64_t byteCount)
1270 {
1271  const uint64_t r = byteCount % wordSize;
1272  return r ? byteCount - r + wordSize : byteCount;
1273 }
1274 
1275 // ------------------------------> Coord <--------------------------------------
1276 
1277 // forward declaration so we can define Coord::asVec3s and Coord::asVec3d
1278 template<typename>
1279 class Vec3;
1280 
1281 /// @brief Signed (i, j, k) 32-bit integer coordinate class, similar to openvdb::math::Coord
1282 class Coord
1283 {
1284  int32_t mVec[3]; // private member data - three signed index coordinates
1285 public:
1286  using ValueType = int32_t;
1287  using IndexType = uint32_t;
1288 
1289  /// @brief Initialize all coordinates to zero.
1291  : mVec{0, 0, 0}
1292  {
1293  }
1294 
1295  /// @brief Initializes all coordinates to the given signed integer.
1297  : mVec{n, n, n}
1298  {
1299  }
1300 
1301  /// @brief Initializes coordinate to the given signed integers.
1303  : mVec{i, j, k}
1304  {
1305  }
1306 
1308  : mVec{ptr[0], ptr[1], ptr[2]}
1309  {
1310  }
1311 
1312  __hostdev__ int32_t x() const { return mVec[0]; }
1313  __hostdev__ int32_t y() const { return mVec[1]; }
1314  __hostdev__ int32_t z() const { return mVec[2]; }
1315 
1316  __hostdev__ int32_t& x() { return mVec[0]; }
1317  __hostdev__ int32_t& y() { return mVec[1]; }
1318  __hostdev__ int32_t& z() { return mVec[2]; }
1319 
1320  __hostdev__ static Coord max() { return Coord(int32_t((1u << 31) - 1)); }
1321 
1322  __hostdev__ static Coord min() { return Coord(-int32_t((1u << 31) - 1) - 1); }
1323 
1324  __hostdev__ static size_t memUsage() { return sizeof(Coord); }
1325 
1326  /// @brief Return a const reference to the given Coord component.
1327  /// @warning The argument is assumed to be 0, 1, or 2.
1328  __hostdev__ const ValueType& operator[](IndexType i) const { return mVec[i]; }
1329 
1330  /// @brief Return a non-const reference to the given Coord component.
1331  /// @warning The argument is assumed to be 0, 1, or 2.
1332  __hostdev__ ValueType& operator[](IndexType i) { return mVec[i]; }
1333 
1334  /// @brief Assignment operator that works with openvdb::Coord
1335  template<typename CoordT>
1336  __hostdev__ Coord& operator=(const CoordT& other)
1337  {
1338  static_assert(sizeof(Coord) == sizeof(CoordT), "Mis-matched sizeof");
1339  mVec[0] = other[0];
1340  mVec[1] = other[1];
1341  mVec[2] = other[2];
1342  return *this;
1343  }
1344 
1345  /// @brief Return a new instance with coordinates masked by the given unsigned integer.
1346  __hostdev__ Coord operator&(IndexType n) const { return Coord(mVec[0] & n, mVec[1] & n, mVec[2] & n); }
1347 
1348  // @brief Return a new instance with coordinates left-shifted by the given unsigned integer.
1349  __hostdev__ Coord operator<<(IndexType n) const { return Coord(mVec[0] << n, mVec[1] << n, mVec[2] << n); }
1350 
1351  // @brief Return a new instance with coordinates right-shifted by the given unsigned integer.
1352  __hostdev__ Coord operator>>(IndexType n) const { return Coord(mVec[0] >> n, mVec[1] >> n, mVec[2] >> n); }
1353 
1354  /// @brief Return true if this Coord is lexicographically less than the given Coord.
1355  __hostdev__ bool operator<(const Coord& rhs) const
1356  {
1357  return mVec[0] < rhs[0] ? true
1358  : mVec[0] > rhs[0] ? false
1359  : mVec[1] < rhs[1] ? true
1360  : mVec[1] > rhs[1] ? false
1361  : mVec[2] < rhs[2] ? true : false;
1362  }
1363 
1364  /// @brief Return true if this Coord is lexicographically less or equal to the given Coord.
1365  __hostdev__ bool operator<=(const Coord& rhs) const
1366  {
1367  return mVec[0] < rhs[0] ? true
1368  : mVec[0] > rhs[0] ? false
1369  : mVec[1] < rhs[1] ? true
1370  : mVec[1] > rhs[1] ? false
1371  : mVec[2] <=rhs[2] ? true : false;
1372  }
1373 
1374  // @brief Return true if the Coord components are identical.
1375  __hostdev__ bool operator==(const Coord& rhs) const { return mVec[0] == rhs[0] && mVec[1] == rhs[1] && mVec[2] == rhs[2]; }
1376  __hostdev__ bool operator!=(const Coord& rhs) const { return mVec[0] != rhs[0] || mVec[1] != rhs[1] || mVec[2] != rhs[2]; }
1378  {
1379  mVec[0] &= n;
1380  mVec[1] &= n;
1381  mVec[2] &= n;
1382  return *this;
1383  }
1385  {
1386  mVec[0] <<= n;
1387  mVec[1] <<= n;
1388  mVec[2] <<= n;
1389  return *this;
1390  }
1392  {
1393  mVec[0] >>= n;
1394  mVec[1] >>= n;
1395  mVec[2] >>= n;
1396  return *this;
1397  }
1399  {
1400  mVec[0] += n;
1401  mVec[1] += n;
1402  mVec[2] += n;
1403  return *this;
1404  }
1405  __hostdev__ Coord operator+(const Coord& rhs) const { return Coord(mVec[0] + rhs[0], mVec[1] + rhs[1], mVec[2] + rhs[2]); }
1406  __hostdev__ Coord operator-(const Coord& rhs) const { return Coord(mVec[0] - rhs[0], mVec[1] - rhs[1], mVec[2] - rhs[2]); }
1407  __hostdev__ Coord operator-() const { return Coord(-mVec[0], -mVec[1], -mVec[2]); }
1409  {
1410  mVec[0] += rhs[0];
1411  mVec[1] += rhs[1];
1412  mVec[2] += rhs[2];
1413  return *this;
1414  }
1416  {
1417  mVec[0] -= rhs[0];
1418  mVec[1] -= rhs[1];
1419  mVec[2] -= rhs[2];
1420  return *this;
1421  }
1422 
1423  /// @brief Perform a component-wise minimum with the other Coord.
1425  {
1426  if (other[0] < mVec[0])
1427  mVec[0] = other[0];
1428  if (other[1] < mVec[1])
1429  mVec[1] = other[1];
1430  if (other[2] < mVec[2])
1431  mVec[2] = other[2];
1432  return *this;
1433  }
1434 
1435  /// @brief Perform a component-wise maximum with the other Coord.
1437  {
1438  if (other[0] > mVec[0])
1439  mVec[0] = other[0];
1440  if (other[1] > mVec[1])
1441  mVec[1] = other[1];
1442  if (other[2] > mVec[2])
1443  mVec[2] = other[2];
1444  return *this;
1445  }
1446 #if defined(__CUDACC__) // the following functions only run on the GPU!
1447  __device__ inline Coord& minComponentAtomic(const Coord& other)
1448  {
1449  atomicMin(&mVec[0], other[0]);
1450  atomicMin(&mVec[1], other[1]);
1451  atomicMin(&mVec[2], other[2]);
1452  return *this;
1453  }
1454  __device__ inline Coord& maxComponentAtomic(const Coord& other)
1455  {
1456  atomicMax(&mVec[0], other[0]);
1457  atomicMax(&mVec[1], other[1]);
1458  atomicMax(&mVec[2], other[2]);
1459  return *this;
1460  }
1461 #endif
1462 
1464  {
1465  return Coord(mVec[0] + dx, mVec[1] + dy, mVec[2] + dz);
1466  }
1467 
1468  __hostdev__ Coord offsetBy(ValueType n) const { return this->offsetBy(n, n, n); }
1469 
1470  /// Return true if any of the components of @a a are smaller than the
1471  /// corresponding components of @a b.
1472  __hostdev__ static inline bool lessThan(const Coord& a, const Coord& b)
1473  {
1474  return (a[0] < b[0] || a[1] < b[1] || a[2] < b[2]);
1475  }
1476 
1477  /// @brief Return the largest integer coordinates that are not greater
1478  /// than @a xyz (node centered conversion).
1479  template<typename Vec3T>
1480  __hostdev__ static Coord Floor(const Vec3T& xyz) { return Coord(nanovdb::Floor(xyz[0]), nanovdb::Floor(xyz[1]), nanovdb::Floor(xyz[2])); }
1481 
1482  /// @brief Return a hash key derived from the existing coordinates.
1483  /// @details The hash function is originally taken from the SIGGRAPH paper:
1484  /// "VDB: High-resolution sparse volumes with dynamic topology"
1485  /// and the prime numbers are modified based on the ACM Transactions on Graphics paper:
1486  /// "Real-time 3D reconstruction at scale using voxel hashing" (the second number had a typo!)
1487  template<int Log2N = 3 + 4 + 5>
1488  __hostdev__ uint32_t hash() const { return ((1 << Log2N) - 1) & (mVec[0] * 73856093 ^ mVec[1] * 19349669 ^ mVec[2] * 83492791); }
1489 
1490  /// @brief Return the octant of this Coord
1491  //__hostdev__ size_t octant() const { return (uint32_t(mVec[0])>>31) | ((uint32_t(mVec[1])>>31)<<1) | ((uint32_t(mVec[2])>>31)<<2); }
1492  __hostdev__ uint8_t octant() const { return (uint8_t(bool(mVec[0] & (1u << 31)))) |
1493  (uint8_t(bool(mVec[1] & (1u << 31))) << 1) |
1494  (uint8_t(bool(mVec[2] & (1u << 31))) << 2); }
1495 
1496  /// @brief Return a single precision floating-point vector of this coordinate
1497  __hostdev__ inline Vec3<float> asVec3s() const;
1498 
1499  /// @brief Return a double precision floating-point vector of this coordinate
1500  __hostdev__ inline Vec3<double> asVec3d() const;
1501 
1502  // returns a copy of itself, so it mimics the behaviour of Vec3<T>::round()
1503  __hostdev__ inline Coord round() const { return *this; }
1504 }; // Coord class
1505 
1506 // ----------------------------> Vec3 <--------------------------------------
1507 
1508 /// @brief A simple vector class with three components, similar to openvdb::math::Vec3
1509 template<typename T>
1510 class Vec3
1511 {
1512  T mVec[3];
1513 
1514 public:
1515  static const int SIZE = 3;
1516  static const int size = 3; // in openvdb::math::Tuple
1517  using ValueType = T;
1518  Vec3() = default;
1519  __hostdev__ explicit Vec3(T x)
1520  : mVec{x, x, x}
1521  {
1522  }
1523  __hostdev__ Vec3(T x, T y, T z)
1524  : mVec{x, y, z}
1525  {
1526  }
1527  template<template<class> class Vec3T, class T2>
1528  __hostdev__ Vec3(const Vec3T<T2>& v)
1529  : mVec{T(v[0]), T(v[1]), T(v[2])}
1530  {
1531  static_assert(Vec3T<T2>::size == size, "expected Vec3T::size==3!");
1532  }
1533  template<typename T2>
1534  __hostdev__ explicit Vec3(const Vec3<T2>& v)
1535  : mVec{T(v[0]), T(v[1]), T(v[2])}
1536  {
1537  }
1538  __hostdev__ explicit Vec3(const Coord& ijk)
1539  : mVec{T(ijk[0]), T(ijk[1]), T(ijk[2])}
1540  {
1541  }
1542  __hostdev__ bool operator==(const Vec3& rhs) const { return mVec[0] == rhs[0] && mVec[1] == rhs[1] && mVec[2] == rhs[2]; }
1543  __hostdev__ bool operator!=(const Vec3& rhs) const { return mVec[0] != rhs[0] || mVec[1] != rhs[1] || mVec[2] != rhs[2]; }
1544  template<template<class> class Vec3T, class T2>
1545  __hostdev__ Vec3& operator=(const Vec3T<T2>& rhs)
1546  {
1547  static_assert(Vec3T<T2>::size == size, "expected Vec3T::size==3!");
1548  mVec[0] = rhs[0];
1549  mVec[1] = rhs[1];
1550  mVec[2] = rhs[2];
1551  return *this;
1552  }
1553  __hostdev__ const T& operator[](int i) const { return mVec[i]; }
1554  __hostdev__ T& operator[](int i) { return mVec[i]; }
1555  template<typename Vec3T>
1556  __hostdev__ T dot(const Vec3T& v) const { return mVec[0] * v[0] + mVec[1] * v[1] + mVec[2] * v[2]; }
1557  template<typename Vec3T>
1558  __hostdev__ Vec3 cross(const Vec3T& v) const
1559  {
1560  return Vec3(mVec[1] * v[2] - mVec[2] * v[1],
1561  mVec[2] * v[0] - mVec[0] * v[2],
1562  mVec[0] * v[1] - mVec[1] * v[0]);
1563  }
1565  {
1566  return mVec[0] * mVec[0] + mVec[1] * mVec[1] + mVec[2] * mVec[2]; // 5 flops
1567  }
1568  __hostdev__ T length() const { return Sqrt(this->lengthSqr()); }
1569  __hostdev__ Vec3 operator-() const { return Vec3(-mVec[0], -mVec[1], -mVec[2]); }
1570  __hostdev__ Vec3 operator*(const Vec3& v) const { return Vec3(mVec[0] * v[0], mVec[1] * v[1], mVec[2] * v[2]); }
1571  __hostdev__ Vec3 operator/(const Vec3& v) const { return Vec3(mVec[0] / v[0], mVec[1] / v[1], mVec[2] / v[2]); }
1572  __hostdev__ Vec3 operator+(const Vec3& v) const { return Vec3(mVec[0] + v[0], mVec[1] + v[1], mVec[2] + v[2]); }
1573  __hostdev__ Vec3 operator-(const Vec3& v) const { return Vec3(mVec[0] - v[0], mVec[1] - v[1], mVec[2] - v[2]); }
1574  __hostdev__ Vec3 operator+(const Coord& ijk) const { return Vec3(mVec[0] + ijk[0], mVec[1] + ijk[1], mVec[2] + ijk[2]); }
1575  __hostdev__ Vec3 operator-(const Coord& ijk) const { return Vec3(mVec[0] - ijk[0], mVec[1] - ijk[1], mVec[2] - ijk[2]); }
1576  __hostdev__ Vec3 operator*(const T& s) const { return Vec3(s * mVec[0], s * mVec[1], s * mVec[2]); }
1577  __hostdev__ Vec3 operator/(const T& s) const { return (T(1) / s) * (*this); }
1579  {
1580  mVec[0] += v[0];
1581  mVec[1] += v[1];
1582  mVec[2] += v[2];
1583  return *this;
1584  }
1586  {
1587  mVec[0] += T(ijk[0]);
1588  mVec[1] += T(ijk[1]);
1589  mVec[2] += T(ijk[2]);
1590  return *this;
1591  }
1593  {
1594  mVec[0] -= v[0];
1595  mVec[1] -= v[1];
1596  mVec[2] -= v[2];
1597  return *this;
1598  }
1600  {
1601  mVec[0] -= T(ijk[0]);
1602  mVec[1] -= T(ijk[1]);
1603  mVec[2] -= T(ijk[2]);
1604  return *this;
1605  }
1607  {
1608  mVec[0] *= s;
1609  mVec[1] *= s;
1610  mVec[2] *= s;
1611  return *this;
1612  }
1613  __hostdev__ Vec3& operator/=(const T& s) { return (*this) *= T(1) / s; }
1614  __hostdev__ Vec3& normalize() { return (*this) /= this->length(); }
1615  /// @brief Perform a component-wise minimum with the other Coord.
1617  {
1618  if (other[0] < mVec[0])
1619  mVec[0] = other[0];
1620  if (other[1] < mVec[1])
1621  mVec[1] = other[1];
1622  if (other[2] < mVec[2])
1623  mVec[2] = other[2];
1624  return *this;
1625  }
1626 
1627  /// @brief Perform a component-wise maximum with the other Coord.
1629  {
1630  if (other[0] > mVec[0])
1631  mVec[0] = other[0];
1632  if (other[1] > mVec[1])
1633  mVec[1] = other[1];
1634  if (other[2] > mVec[2])
1635  mVec[2] = other[2];
1636  return *this;
1637  }
1638  /// @brief Return the smallest vector component
1640  {
1641  return mVec[0] < mVec[1] ? (mVec[0] < mVec[2] ? mVec[0] : mVec[2]) : (mVec[1] < mVec[2] ? mVec[1] : mVec[2]);
1642  }
1643  /// @brief Return the largest vector component
1645  {
1646  return mVec[0] > mVec[1] ? (mVec[0] > mVec[2] ? mVec[0] : mVec[2]) : (mVec[1] > mVec[2] ? mVec[1] : mVec[2]);
1647  }
1648  /// @brief Round each component if this Vec<T> up to its integer value
1649  /// @return Return an integer Coord
1650  __hostdev__ Coord floor() const { return Coord(Floor(mVec[0]), Floor(mVec[1]), Floor(mVec[2])); }
1651  /// @brief Round each component if this Vec<T> down to its integer value
1652  /// @return Return an integer Coord
1653  __hostdev__ Coord ceil() const { return Coord(Ceil(mVec[0]), Ceil(mVec[1]), Ceil(mVec[2])); }
1654  /// @brief Round each component if this Vec<T> to its closest integer value
1655  /// @return Return an integer Coord
1657  {
1658  if constexpr(is_same<T, float>::value) {
1659  return Coord(Floor(mVec[0] + 0.5f), Floor(mVec[1] + 0.5f), Floor(mVec[2] + 0.5f));
1660  } else if constexpr(is_same<T, int>::value) {
1661  return Coord(mVec[0], mVec[1], mVec[2]);
1662  } else {
1663  return Coord(Floor(mVec[0] + 0.5), Floor(mVec[1] + 0.5), Floor(mVec[2] + 0.5));
1664  }
1665  }
1666 
1667  /// @brief return a non-const raw constant pointer to array of three vector components
1668  __hostdev__ T* asPointer() { return mVec; }
1669  /// @brief return a const raw constant pointer to array of three vector components
1670  __hostdev__ const T* asPointer() const { return mVec; }
1671 }; // Vec3<T>
1672 
1673 template<typename T1, typename T2>
1674 __hostdev__ inline Vec3<T2> operator*(T1 scalar, const Vec3<T2>& vec)
1675 {
1676  return Vec3<T2>(scalar * vec[0], scalar * vec[1], scalar * vec[2]);
1677 }
1678 template<typename T1, typename T2>
1679 __hostdev__ inline Vec3<T2> operator/(T1 scalar, const Vec3<T2>& vec)
1680 {
1681  return Vec3<T2>(scalar / vec[0], scalar / vec[1], scalar / vec[2]);
1682 }
1683 
1684 //using Vec3R = Vec3<double>;// deprecated
1691 
1692 /// @brief Return a single precision floating-point vector of this coordinate
1694 {
1695  return Vec3f(float(mVec[0]), float(mVec[1]), float(mVec[2]));
1696 }
1697 
1698 /// @brief Return a double precision floating-point vector of this coordinate
1700 {
1701  return Vec3d(double(mVec[0]), double(mVec[1]), double(mVec[2]));
1702 }
1703 
1704 // ----------------------------> Vec4 <--------------------------------------
1705 
1706 /// @brief A simple vector class with four components, similar to openvdb::math::Vec4
1707 template<typename T>
1708 class Vec4
1709 {
1710  T mVec[4];
1711 
1712 public:
1713  static const int SIZE = 4;
1714  static const int size = 4;
1715  using ValueType = T;
1716  Vec4() = default;
1717  __hostdev__ explicit Vec4(T x)
1718  : mVec{x, x, x, x}
1719  {
1720  }
1721  __hostdev__ Vec4(T x, T y, T z, T w)
1722  : mVec{x, y, z, w}
1723  {
1724  }
1725  template<typename T2>
1726  __hostdev__ explicit Vec4(const Vec4<T2>& v)
1727  : mVec{T(v[0]), T(v[1]), T(v[2]), T(v[3])}
1728  {
1729  }
1730  template<template<class> class Vec4T, class T2>
1731  __hostdev__ Vec4(const Vec4T<T2>& v)
1732  : mVec{T(v[0]), T(v[1]), T(v[2]), T(v[3])}
1733  {
1734  static_assert(Vec4T<T2>::size == size, "expected Vec4T::size==4!");
1735  }
1736  __hostdev__ bool operator==(const Vec4& rhs) const { return mVec[0] == rhs[0] && mVec[1] == rhs[1] && mVec[2] == rhs[2] && mVec[3] == rhs[3]; }
1737  __hostdev__ bool operator!=(const Vec4& rhs) const { return mVec[0] != rhs[0] || mVec[1] != rhs[1] || mVec[2] != rhs[2] || mVec[3] != rhs[3]; }
1738  template<template<class> class Vec4T, class T2>
1739  __hostdev__ Vec4& operator=(const Vec4T<T2>& rhs)
1740  {
1741  static_assert(Vec4T<T2>::size == size, "expected Vec4T::size==4!");
1742  mVec[0] = rhs[0];
1743  mVec[1] = rhs[1];
1744  mVec[2] = rhs[2];
1745  mVec[3] = rhs[3];
1746  return *this;
1747  }
1748 
1749  __hostdev__ const T& operator[](int i) const { return mVec[i]; }
1750  __hostdev__ T& operator[](int i) { return mVec[i]; }
1751  template<typename Vec4T>
1752  __hostdev__ T dot(const Vec4T& v) const { return mVec[0] * v[0] + mVec[1] * v[1] + mVec[2] * v[2] + mVec[3] * v[3]; }
1754  {
1755  return mVec[0] * mVec[0] + mVec[1] * mVec[1] + mVec[2] * mVec[2] + mVec[3] * mVec[3]; // 7 flops
1756  }
1757  __hostdev__ T length() const { return Sqrt(this->lengthSqr()); }
1758  __hostdev__ Vec4 operator-() const { return Vec4(-mVec[0], -mVec[1], -mVec[2], -mVec[3]); }
1759  __hostdev__ Vec4 operator*(const Vec4& v) const { return Vec4(mVec[0] * v[0], mVec[1] * v[1], mVec[2] * v[2], mVec[3] * v[3]); }
1760  __hostdev__ Vec4 operator/(const Vec4& v) const { return Vec4(mVec[0] / v[0], mVec[1] / v[1], mVec[2] / v[2], mVec[3] / v[3]); }
1761  __hostdev__ Vec4 operator+(const Vec4& v) const { return Vec4(mVec[0] + v[0], mVec[1] + v[1], mVec[2] + v[2], mVec[3] + v[3]); }
1762  __hostdev__ Vec4 operator-(const Vec4& v) const { return Vec4(mVec[0] - v[0], mVec[1] - v[1], mVec[2] - v[2], mVec[3] - v[3]); }
1763  __hostdev__ Vec4 operator*(const T& s) const { return Vec4(s * mVec[0], s * mVec[1], s * mVec[2], s * mVec[3]); }
1764  __hostdev__ Vec4 operator/(const T& s) const { return (T(1) / s) * (*this); }
1766  {
1767  mVec[0] += v[0];
1768  mVec[1] += v[1];
1769  mVec[2] += v[2];
1770  mVec[3] += v[3];
1771  return *this;
1772  }
1774  {
1775  mVec[0] -= v[0];
1776  mVec[1] -= v[1];
1777  mVec[2] -= v[2];
1778  mVec[3] -= v[3];
1779  return *this;
1780  }
1782  {
1783  mVec[0] *= s;
1784  mVec[1] *= s;
1785  mVec[2] *= s;
1786  mVec[3] *= s;
1787  return *this;
1788  }
1789  __hostdev__ Vec4& operator/=(const T& s) { return (*this) *= T(1) / s; }
1790  __hostdev__ Vec4& normalize() { return (*this) /= this->length(); }
1791  /// @brief Perform a component-wise minimum with the other Coord.
1793  {
1794  if (other[0] < mVec[0])
1795  mVec[0] = other[0];
1796  if (other[1] < mVec[1])
1797  mVec[1] = other[1];
1798  if (other[2] < mVec[2])
1799  mVec[2] = other[2];
1800  if (other[3] < mVec[3])
1801  mVec[3] = other[3];
1802  return *this;
1803  }
1804 
1805  /// @brief Perform a component-wise maximum with the other Coord.
1807  {
1808  if (other[0] > mVec[0])
1809  mVec[0] = other[0];
1810  if (other[1] > mVec[1])
1811  mVec[1] = other[1];
1812  if (other[2] > mVec[2])
1813  mVec[2] = other[2];
1814  if (other[3] > mVec[3])
1815  mVec[3] = other[3];
1816  return *this;
1817  }
1818 }; // Vec4<T>
1819 
1820 template<typename T1, typename T2>
1821 __hostdev__ inline Vec4<T2> operator*(T1 scalar, const Vec4<T2>& vec)
1822 {
1823  return Vec4<T2>(scalar * vec[0], scalar * vec[1], scalar * vec[2], scalar * vec[3]);
1824 }
1825 template<typename T1, typename T2>
1826 __hostdev__ inline Vec4<T2> operator/(T1 scalar, const Vec4<T2>& vec)
1827 {
1828  return Vec4<T2>(scalar / vec[0], scalar / vec[1], scalar / vec[2], scalar / vec[3]);
1829 }
1830 
1835 
1836 
1837 // --------------------------> Rgba8 <------------------------------------
1838 
1839 /// @brief 8-bit red, green, blue, alpha packed into 32 bit unsigned int
1840 class Rgba8
1841 {
1842  union
1843  {
1844  uint8_t c[4]; // 4 integer color channels of red, green, blue and alpha components.
1845  uint32_t packed; // 32 bit packed representation
1846  } mData;
1847 
1848 public:
1849  static const int SIZE = 4;
1850  using ValueType = uint8_t;
1851 
1852  /// @brief Default copy constructor
1853  Rgba8(const Rgba8&) = default;
1854 
1855  /// @brief Default move constructor
1856  Rgba8(Rgba8&&) = default;
1857 
1858  /// @brief Default move assignment operator
1859  /// @return non-const reference to this instance
1860  Rgba8& operator=(Rgba8&&) = default;
1861 
1862  /// @brief Default copy assignment operator
1863  /// @return non-const reference to this instance
1864  Rgba8& operator=(const Rgba8&) = default;
1865 
1866  /// @brief Default ctor initializes all channels to zero
1868  : mData{{0, 0, 0, 0}}
1869  {
1870  static_assert(sizeof(uint32_t) == sizeof(Rgba8), "Unexpected sizeof");
1871  }
1872 
1873  /// @brief integer r,g,b,a ctor where alpha channel defaults to opaque
1874  /// @note all values should be in the range 0u to 255u
1875  __hostdev__ Rgba8(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255u)
1876  : mData{{r, g, b, a}}
1877  {
1878  }
1879 
1880  /// @brief @brief ctor where all channels are initialized to the same value
1881  /// @note value should be in the range 0u to 255u
1882  explicit __hostdev__ Rgba8(uint8_t v)
1883  : mData{{v, v, v, v}}
1884  {
1885  }
1886 
1887  /// @brief floating-point r,g,b,a ctor where alpha channel defaults to opaque
1888  /// @note all values should be in the range 0.0f to 1.0f
1889  __hostdev__ Rgba8(float r, float g, float b, float a = 1.0f)
1890  : mData{{static_cast<uint8_t>(0.5f + r * 255.0f), // round floats to nearest integers
1891  static_cast<uint8_t>(0.5f + g * 255.0f), // double {{}} is needed due to union
1892  static_cast<uint8_t>(0.5f + b * 255.0f),
1893  static_cast<uint8_t>(0.5f + a * 255.0f)}}
1894  {
1895  }
1896 
1897  /// @brief Vec3f r,g,b ctor (alpha channel it set to 1)
1898  /// @note all values should be in the range 0.0f to 1.0f
1899  __hostdev__ Rgba8(const Vec3f& rgb)
1900  : Rgba8(rgb[0], rgb[1], rgb[2])
1901  {
1902  }
1903 
1904  /// @brief Vec4f r,g,b,a ctor
1905  /// @note all values should be in the range 0.0f to 1.0f
1906  __hostdev__ Rgba8(const Vec4f& rgba)
1907  : Rgba8(rgba[0], rgba[1], rgba[2], rgba[3])
1908  {
1909  }
1910 
1911  __hostdev__ bool operator< (const Rgba8& rhs) const { return mData.packed < rhs.mData.packed; }
1912  __hostdev__ bool operator==(const Rgba8& rhs) const { return mData.packed == rhs.mData.packed; }
1913  __hostdev__ float lengthSqr() const
1914  {
1915  return 0.0000153787005f * (float(mData.c[0]) * mData.c[0] +
1916  float(mData.c[1]) * mData.c[1] +
1917  float(mData.c[2]) * mData.c[2]); //1/255^2
1918  }
1919  __hostdev__ float length() const { return sqrtf(this->lengthSqr()); }
1920  /// @brief return n'th color channel as a float in the range 0 to 1
1921  __hostdev__ float asFloat(int n) const { return 0.003921569f*float(mData.c[n]); }// divide by 255
1922  __hostdev__ const uint8_t& operator[](int n) const { return mData.c[n]; }
1923  __hostdev__ uint8_t& operator[](int n) { return mData.c[n]; }
1924  __hostdev__ const uint32_t& packed() const { return mData.packed; }
1925  __hostdev__ uint32_t& packed() { return mData.packed; }
1926  __hostdev__ const uint8_t& r() const { return mData.c[0]; }
1927  __hostdev__ const uint8_t& g() const { return mData.c[1]; }
1928  __hostdev__ const uint8_t& b() const { return mData.c[2]; }
1929  __hostdev__ const uint8_t& a() const { return mData.c[3]; }
1930  __hostdev__ uint8_t& r() { return mData.c[0]; }
1931  __hostdev__ uint8_t& g() { return mData.c[1]; }
1932  __hostdev__ uint8_t& b() { return mData.c[2]; }
1933  __hostdev__ uint8_t& a() { return mData.c[3]; }
1934  __hostdev__ operator Vec3f() const {
1935  return Vec3f(this->asFloat(0), this->asFloat(1), this->asFloat(2));
1936  }
1937  __hostdev__ operator Vec4f() const {
1938  return Vec4f(this->asFloat(0), this->asFloat(1), this->asFloat(2), this->asFloat(3));
1939  }
1940 }; // Rgba8
1941 
1942 using PackedRGBA8 = Rgba8; // for backwards compatibility
1943 
1944 // ----------------------------> TensorTraits <--------------------------------------
1945 
1948 
1949 template<typename T>
1950 struct TensorTraits<T, 0>
1951 {
1952  static const int Rank = 0; // i.e. scalar
1953  static const bool IsScalar = true;
1954  static const bool IsVector = false;
1955  static const int Size = 1;
1956  using ElementType = T;
1957  static T scalar(const T& s) { return s; }
1958 };
1959 
1960 template<typename T>
1961 struct TensorTraits<T, 1>
1962 {
1963  static const int Rank = 1; // i.e. vector
1964  static const bool IsScalar = false;
1965  static const bool IsVector = true;
1966  static const int Size = T::SIZE;
1967  using ElementType = typename T::ValueType;
1968  static ElementType scalar(const T& v) { return v.length(); }
1969 };
1970 
1971 // ----------------------------> FloatTraits <--------------------------------------
1972 
1973 template<typename T, int = sizeof(typename TensorTraits<T>::ElementType)>
1975 {
1976  using FloatType = float;
1977 };
1978 
1979 template<typename T>
1980 struct FloatTraits<T, 8>
1981 {
1982  using FloatType = double;
1983 };
1984 
1985 template<>
1986 struct FloatTraits<bool, 1>
1987 {
1988  using FloatType = bool;
1989 };
1990 
1991 template<>
1992 struct FloatTraits<ValueIndex, 1> // size of empty class in C++ is 1 byte and not 0 byte
1993 {
1994  using FloatType = uint64_t;
1995 };
1996 
1997 template<>
1998 struct FloatTraits<ValueIndexMask, 1> // size of empty class in C++ is 1 byte and not 0 byte
1999 {
2000  using FloatType = uint64_t;
2001 };
2002 
2003 template<>
2004 struct FloatTraits<ValueOnIndex, 1> // size of empty class in C++ is 1 byte and not 0 byte
2005 {
2006  using FloatType = uint64_t;
2007 };
2008 
2009 template<>
2010 struct FloatTraits<ValueOnIndexMask, 1> // size of empty class in C++ is 1 byte and not 0 byte
2011 {
2012  using FloatType = uint64_t;
2013 };
2014 
2015 template<>
2016 struct FloatTraits<ValueMask, 1> // size of empty class in C++ is 1 byte and not 0 byte
2017 {
2018  using FloatType = bool;
2019 };
2020 
2021 template<>
2022 struct FloatTraits<Point, 1> // size of empty class in C++ is 1 byte and not 0 byte
2023 {
2024  using FloatType = double;
2025 };
2026 
2027 // ----------------------------> mapping BuildType -> GridType <--------------------------------------
2028 
2029 /// @brief Maps from a templated build type to a GridType enum
2030 template<typename BuildT>
2032 {
2033  if constexpr(is_same<BuildT, float>::value) { // resolved at compile-time
2034  return GridType::Float;
2035  } else if constexpr(is_same<BuildT, double>::value) {
2036  return GridType::Double;
2037  } else if constexpr(is_same<BuildT, int16_t>::value) {
2038  return GridType::Int16;
2039  } else if constexpr(is_same<BuildT, int32_t>::value) {
2040  return GridType::Int32;
2041  } else if constexpr(is_same<BuildT, int64_t>::value) {
2042  return GridType::Int64;
2043  } else if constexpr(is_same<BuildT, Vec3f>::value) {
2044  return GridType::Vec3f;
2045  } else if constexpr(is_same<BuildT, Vec3d>::value) {
2046  return GridType::Vec3d;
2047  } else if constexpr(is_same<BuildT, uint32_t>::value) {
2048  return GridType::UInt32;
2049  } else if constexpr(is_same<BuildT, ValueMask>::value) {
2050  return GridType::Mask;
2051  } else if constexpr(is_same<BuildT, Half>::value) {
2052  return GridType::Half;
2053  } else if constexpr(is_same<BuildT, ValueIndex>::value) {
2054  return GridType::Index;
2055  } else if constexpr(is_same<BuildT, ValueOnIndex>::value) {
2056  return GridType::OnIndex;
2057  } else if constexpr(is_same<BuildT, ValueIndexMask>::value) {
2058  return GridType::IndexMask;
2059  } else if constexpr(is_same<BuildT, ValueOnIndexMask>::value) {
2060  return GridType::OnIndexMask;
2061  } else if constexpr(is_same<BuildT, bool>::value) {
2062  return GridType::Boolean;
2063  } else if constexpr(is_same<BuildT, Rgba8>::value) {
2064  return GridType::RGBA8;
2065  } else if (is_same<BuildT, Fp4>::value) {
2066  return GridType::Fp4;
2067  } else if constexpr(is_same<BuildT, Fp8>::value) {
2068  return GridType::Fp8;
2069  } else if constexpr(is_same<BuildT, Fp16>::value) {
2070  return GridType::Fp16;
2071  } else if constexpr(is_same<BuildT, FpN>::value) {
2072  return GridType::FpN;
2073  } else if constexpr(is_same<BuildT, Vec4f>::value) {
2074  return GridType::Vec4f;
2075  } else if constexpr(is_same<BuildT, Vec4d>::value) {
2076  return GridType::Vec4d;
2077  } else if (is_same<BuildT, Point>::value) {
2078  return GridType::PointIndex;
2079  } else if constexpr(is_same<BuildT, Vec3u8>::value) {
2080  return GridType::Vec3u8;
2081  } else if constexpr(is_same<BuildT, Vec3u16>::value) {
2082  return GridType::Vec3u16;
2083  }
2084  return GridType::Unknown;
2085 }
2086 
2087 // ----------------------------> mapping BuildType -> GridClass <--------------------------------------
2088 
2089 /// @brief Maps from a templated build type to a GridClass enum
2090 template<typename BuildT>
2092 {
2094  return GridClass::Topology;
2095  } else if (BuildTraits<BuildT>::is_index) {
2096  return GridClass::IndexGrid;
2097  } else if (is_same<BuildT, Rgba8>::value) {
2098  return GridClass::VoxelVolume;
2099  } else if (is_same<BuildT, Point>::value) {
2100  return GridClass::PointIndex;
2101  }
2102  return defaultClass;
2103 }
2104 
2105 // ----------------------------> matMult <--------------------------------------
2106 
2107 /// @brief Multiply a 3x3 matrix and a 3d vector using 32bit floating point arithmetics
2108 /// @note This corresponds to a linear mapping, e.g. scaling, rotation etc.
2109 /// @tparam Vec3T Template type of the input and output 3d vectors
2110 /// @param mat pointer to an array of floats with the 3x3 matrix
2111 /// @param xyz input vector to be multiplied by the matrix
2112 /// @return result of matrix-vector multiplication, i.e. mat x xyz
2113 template<typename Vec3T>
2114 __hostdev__ inline Vec3T matMult(const float* mat, const Vec3T& xyz)
2115 {
2116  return Vec3T(fmaf(static_cast<float>(xyz[0]), mat[0], fmaf(static_cast<float>(xyz[1]), mat[1], static_cast<float>(xyz[2]) * mat[2])),
2117  fmaf(static_cast<float>(xyz[0]), mat[3], fmaf(static_cast<float>(xyz[1]), mat[4], static_cast<float>(xyz[2]) * mat[5])),
2118  fmaf(static_cast<float>(xyz[0]), mat[6], fmaf(static_cast<float>(xyz[1]), mat[7], static_cast<float>(xyz[2]) * mat[8]))); // 6 fmaf + 3 mult = 9 flops
2119 }
2120 
2121 /// @brief Multiply a 3x3 matrix and a 3d vector using 64bit floating point arithmetics
2122 /// @note This corresponds to a linear mapping, e.g. scaling, rotation etc.
2123 /// @tparam Vec3T Template type of the input and output 3d vectors
2124 /// @param mat pointer to an array of floats with the 3x3 matrix
2125 /// @param xyz input vector to be multiplied by the matrix
2126 /// @return result of matrix-vector multiplication, i.e. mat x xyz
2127 template<typename Vec3T>
2128 __hostdev__ inline Vec3T matMult(const double* mat, const Vec3T& xyz)
2129 {
2130  return Vec3T(fma(static_cast<double>(xyz[0]), mat[0], fma(static_cast<double>(xyz[1]), mat[1], static_cast<double>(xyz[2]) * mat[2])),
2131  fma(static_cast<double>(xyz[0]), mat[3], fma(static_cast<double>(xyz[1]), mat[4], static_cast<double>(xyz[2]) * mat[5])),
2132  fma(static_cast<double>(xyz[0]), mat[6], fma(static_cast<double>(xyz[1]), mat[7], static_cast<double>(xyz[2]) * mat[8]))); // 6 fmaf + 3 mult = 9 flops
2133 }
2134 
2135 /// @brief Multiply a 3x3 matrix to a 3d vector and add another 3d vector using 32bit floating point arithmetics
2136 /// @note This corresponds to an affine transformation, i.e a linear mapping followed by a translation. e.g. scale/rotation and translation
2137 /// @tparam Vec3T Template type of the input and output 3d vectors
2138 /// @param mat pointer to an array of floats with the 3x3 matrix
2139 /// @param vec 3d vector to be added AFTER the matrix multiplication
2140 /// @param xyz input vector to be multiplied by the matrix and a translated by @c vec
2141 /// @return result of affine transformation, i.e. (mat x xyz) + vec
2142 template<typename Vec3T>
2143 __hostdev__ inline Vec3T matMult(const float* mat, const float* vec, const Vec3T& xyz)
2144 {
2145  return Vec3T(fmaf(static_cast<float>(xyz[0]), mat[0], fmaf(static_cast<float>(xyz[1]), mat[1], fmaf(static_cast<float>(xyz[2]), mat[2], vec[0]))),
2146  fmaf(static_cast<float>(xyz[0]), mat[3], fmaf(static_cast<float>(xyz[1]), mat[4], fmaf(static_cast<float>(xyz[2]), mat[5], vec[1]))),
2147  fmaf(static_cast<float>(xyz[0]), mat[6], fmaf(static_cast<float>(xyz[1]), mat[7], fmaf(static_cast<float>(xyz[2]), mat[8], vec[2])))); // 9 fmaf = 9 flops
2148 }
2149 
2150 /// @brief Multiply a 3x3 matrix to a 3d vector and add another 3d vector using 64bit floating point arithmetics
2151 /// @note This corresponds to an affine transformation, i.e a linear mapping followed by a translation. e.g. scale/rotation and translation
2152 /// @tparam Vec3T Template type of the input and output 3d vectors
2153 /// @param mat pointer to an array of floats with the 3x3 matrix
2154 /// @param vec 3d vector to be added AFTER the matrix multiplication
2155 /// @param xyz input vector to be multiplied by the matrix and a translated by @c vec
2156 /// @return result of affine transformation, i.e. (mat x xyz) + vec
2157 template<typename Vec3T>
2158 __hostdev__ inline Vec3T matMult(const double* mat, const double* vec, const Vec3T& xyz)
2159 {
2160  return Vec3T(fma(static_cast<double>(xyz[0]), mat[0], fma(static_cast<double>(xyz[1]), mat[1], fma(static_cast<double>(xyz[2]), mat[2], vec[0]))),
2161  fma(static_cast<double>(xyz[0]), mat[3], fma(static_cast<double>(xyz[1]), mat[4], fma(static_cast<double>(xyz[2]), mat[5], vec[1]))),
2162  fma(static_cast<double>(xyz[0]), mat[6], fma(static_cast<double>(xyz[1]), mat[7], fma(static_cast<double>(xyz[2]), mat[8], vec[2])))); // 9 fma = 9 flops
2163 }
2164 
2165 /// @brief Multiply the transposed of a 3x3 matrix and a 3d vector using 32bit floating point arithmetics
2166 /// @note This corresponds to an inverse linear mapping, e.g. inverse scaling, inverse rotation etc.
2167 /// @tparam Vec3T Template type of the input and output 3d vectors
2168 /// @param mat pointer to an array of floats with the 3x3 matrix
2169 /// @param xyz input vector to be multiplied by the transposed matrix
2170 /// @return result of matrix-vector multiplication, i.e. mat^T x xyz
2171 template<typename Vec3T>
2172 __hostdev__ inline Vec3T matMultT(const float* mat, const Vec3T& xyz)
2173 {
2174  return Vec3T(fmaf(static_cast<float>(xyz[0]), mat[0], fmaf(static_cast<float>(xyz[1]), mat[3], static_cast<float>(xyz[2]) * mat[6])),
2175  fmaf(static_cast<float>(xyz[0]), mat[1], fmaf(static_cast<float>(xyz[1]), mat[4], static_cast<float>(xyz[2]) * mat[7])),
2176  fmaf(static_cast<float>(xyz[0]), mat[2], fmaf(static_cast<float>(xyz[1]), mat[5], static_cast<float>(xyz[2]) * mat[8]))); // 6 fmaf + 3 mult = 9 flops
2177 }
2178 
2179 /// @brief Multiply the transposed of a 3x3 matrix and a 3d vector using 64bit floating point arithmetics
2180 /// @note This corresponds to an inverse linear mapping, e.g. inverse scaling, inverse rotation etc.
2181 /// @tparam Vec3T Template type of the input and output 3d vectors
2182 /// @param mat pointer to an array of floats with the 3x3 matrix
2183 /// @param xyz input vector to be multiplied by the transposed matrix
2184 /// @return result of matrix-vector multiplication, i.e. mat^T x xyz
2185 template<typename Vec3T>
2186 __hostdev__ inline Vec3T matMultT(const double* mat, const Vec3T& xyz)
2187 {
2188  return Vec3T(fma(static_cast<double>(xyz[0]), mat[0], fma(static_cast<double>(xyz[1]), mat[3], static_cast<double>(xyz[2]) * mat[6])),
2189  fma(static_cast<double>(xyz[0]), mat[1], fma(static_cast<double>(xyz[1]), mat[4], static_cast<double>(xyz[2]) * mat[7])),
2190  fma(static_cast<double>(xyz[0]), mat[2], fma(static_cast<double>(xyz[1]), mat[5], static_cast<double>(xyz[2]) * mat[8]))); // 6 fmaf + 3 mult = 9 flops
2191 }
2192 
2193 template<typename Vec3T>
2194 __hostdev__ inline Vec3T matMultT(const float* mat, const float* vec, const Vec3T& xyz)
2195 {
2196  return Vec3T(fmaf(static_cast<float>(xyz[0]), mat[0], fmaf(static_cast<float>(xyz[1]), mat[3], fmaf(static_cast<float>(xyz[2]), mat[6], vec[0]))),
2197  fmaf(static_cast<float>(xyz[0]), mat[1], fmaf(static_cast<float>(xyz[1]), mat[4], fmaf(static_cast<float>(xyz[2]), mat[7], vec[1]))),
2198  fmaf(static_cast<float>(xyz[0]), mat[2], fmaf(static_cast<float>(xyz[1]), mat[5], fmaf(static_cast<float>(xyz[2]), mat[8], vec[2])))); // 9 fmaf = 9 flops
2199 }
2200 
2201 template<typename Vec3T>
2202 __hostdev__ inline Vec3T matMultT(const double* mat, const double* vec, const Vec3T& xyz)
2203 {
2204  return Vec3T(fma(static_cast<double>(xyz[0]), mat[0], fma(static_cast<double>(xyz[1]), mat[3], fma(static_cast<double>(xyz[2]), mat[6], vec[0]))),
2205  fma(static_cast<double>(xyz[0]), mat[1], fma(static_cast<double>(xyz[1]), mat[4], fma(static_cast<double>(xyz[2]), mat[7], vec[1]))),
2206  fma(static_cast<double>(xyz[0]), mat[2], fma(static_cast<double>(xyz[1]), mat[5], fma(static_cast<double>(xyz[2]), mat[8], vec[2])))); // 9 fma = 9 flops
2207 }
2208 
2209 // ----------------------------> BBox <-------------------------------------
2210 
2211 // Base-class for static polymorphism (cannot be constructed directly)
2212 template<typename Vec3T>
2213 struct BaseBBox
2214 {
2215  Vec3T mCoord[2];
2216  __hostdev__ bool operator==(const BaseBBox& rhs) const { return mCoord[0] == rhs.mCoord[0] && mCoord[1] == rhs.mCoord[1]; };
2217  __hostdev__ bool operator!=(const BaseBBox& rhs) const { return mCoord[0] != rhs.mCoord[0] || mCoord[1] != rhs.mCoord[1]; };
2218  __hostdev__ const Vec3T& operator[](int i) const { return mCoord[i]; }
2219  __hostdev__ Vec3T& operator[](int i) { return mCoord[i]; }
2220  __hostdev__ Vec3T& min() { return mCoord[0]; }
2221  __hostdev__ Vec3T& max() { return mCoord[1]; }
2222  __hostdev__ const Vec3T& min() const { return mCoord[0]; }
2223  __hostdev__ const Vec3T& max() const { return mCoord[1]; }
2224  __hostdev__ BaseBBox& translate(const Vec3T& xyz)
2225  {
2226  mCoord[0] += xyz;
2227  mCoord[1] += xyz;
2228  return *this;
2229  }
2230  /// @brief Expand this bounding box to enclose point @c xyz.
2231  __hostdev__ BaseBBox& expand(const Vec3T& xyz)
2232  {
2233  mCoord[0].minComponent(xyz);
2234  mCoord[1].maxComponent(xyz);
2235  return *this;
2236  }
2237 
2238  /// @brief Expand this bounding box to enclose the given bounding box.
2240  {
2241  mCoord[0].minComponent(bbox[0]);
2242  mCoord[1].maxComponent(bbox[1]);
2243  return *this;
2244  }
2245 
2246  /// @brief Intersect this bounding box with the given bounding box.
2248  {
2249  mCoord[0].maxComponent(bbox[0]);
2250  mCoord[1].minComponent(bbox[1]);
2251  return *this;
2252  }
2253 
2254  //__hostdev__ BaseBBox expandBy(typename Vec3T::ValueType padding) const
2255  //{
2256  // return BaseBBox(mCoord[0].offsetBy(-padding),mCoord[1].offsetBy(padding));
2257  //}
2258  __hostdev__ bool isInside(const Vec3T& xyz)
2259  {
2260  if (xyz[0] < mCoord[0][0] || xyz[1] < mCoord[0][1] || xyz[2] < mCoord[0][2])
2261  return false;
2262  if (xyz[0] > mCoord[1][0] || xyz[1] > mCoord[1][1] || xyz[2] > mCoord[1][2])
2263  return false;
2264  return true;
2265  }
2266 
2267 protected:
2269  __hostdev__ BaseBBox(const Vec3T& min, const Vec3T& max)
2270  : mCoord{min, max}
2271  {
2272  }
2273 }; // BaseBBox
2274 
2276 struct BBox;
2277 
2278 /// @brief Partial template specialization for floating point coordinate types.
2279 ///
2280 /// @note Min is inclusive and max is exclusive. If min = max the dimension of
2281 /// the bounding box is zero and therefore it is also empty.
2282 template<typename Vec3T>
2283 struct BBox<Vec3T, true> : public BaseBBox<Vec3T>
2284 {
2285  using Vec3Type = Vec3T;
2286  using ValueType = typename Vec3T::ValueType;
2287  static_assert(is_floating_point<ValueType>::value, "Expected a floating point coordinate type");
2289  using BaseT::mCoord;
2290  /// @brief Default construction sets BBox to an empty bbox
2292  : BaseT(Vec3T( Maximum<typename Vec3T::ValueType>::value()),
2293  Vec3T(-Maximum<typename Vec3T::ValueType>::value()))
2294  {
2295  }
2296  __hostdev__ BBox(const Vec3T& min, const Vec3T& max)
2297  : BaseT(min, max)
2298  {
2299  }
2300  __hostdev__ BBox(const Coord& min, const Coord& max)
2301  : BaseT(Vec3T(ValueType(min[0]), ValueType(min[1]), ValueType(min[2])),
2302  Vec3T(ValueType(max[0] + 1), ValueType(max[1] + 1), ValueType(max[2] + 1)))
2303  {
2304  }
2305  __hostdev__ static BBox createCube(const Coord& min, typename Coord::ValueType dim)
2306  {
2307  return BBox(min, min.offsetBy(dim));
2308  }
2309 
2311  : BBox(bbox[0], bbox[1])
2312  {
2313  }
2314  __hostdev__ bool empty() const { return mCoord[0][0] >= mCoord[1][0] ||
2315  mCoord[0][1] >= mCoord[1][1] ||
2316  mCoord[0][2] >= mCoord[1][2]; }
2317  __hostdev__ operator bool() const { return mCoord[0][0] < mCoord[1][0] &&
2318  mCoord[0][1] < mCoord[1][1] &&
2319  mCoord[0][2] < mCoord[1][2]; }
2320  __hostdev__ Vec3T dim() const { return *this ? this->max() - this->min() : Vec3T(0); }
2321  __hostdev__ bool isInside(const Vec3T& p) const
2322  {
2323  return p[0] > mCoord[0][0] && p[1] > mCoord[0][1] && p[2] > mCoord[0][2] &&
2324  p[0] < mCoord[1][0] && p[1] < mCoord[1][1] && p[2] < mCoord[1][2];
2325  }
2326 
2327 }; // BBox<Vec3T, true>
2328 
2329 /// @brief Partial template specialization for integer coordinate types
2330 ///
2331 /// @note Both min and max are INCLUDED in the bbox so dim = max - min + 1. So,
2332 /// if min = max the bounding box contains exactly one point and dim = 1!
2333 template<typename CoordT>
2334 struct BBox<CoordT, false> : public BaseBBox<CoordT>
2335 {
2336  static_assert(is_same<int, typename CoordT::ValueType>::value, "Expected \"int\" coordinate type");
2338  using BaseT::mCoord;
2339  /// @brief Iterator over the domain covered by a BBox
2340  /// @details z is the fastest-moving coordinate.
2341  class Iterator
2342  {
2343  const BBox& mBBox;
2344  CoordT mPos;
2345 
2346  public:
2348  : mBBox(b)
2349  , mPos(b.min())
2350  {
2351  }
2352  __hostdev__ Iterator(const BBox& b, const Coord& p)
2353  : mBBox(b)
2354  , mPos(p)
2355  {
2356  }
2358  {
2359  if (mPos[2] < mBBox[1][2]) { // this is the most common case
2360  ++mPos[2];// increment z
2361  } else if (mPos[1] < mBBox[1][1]) {
2362  mPos[2] = mBBox[0][2];// reset z
2363  ++mPos[1];// increment y
2364  } else if (mPos[0] <= mBBox[1][0]) {
2365  mPos[2] = mBBox[0][2];// reset z
2366  mPos[1] = mBBox[0][1];// reset y
2367  ++mPos[0];// increment x
2368  }
2369  return *this;
2370  }
2371  __hostdev__ Iterator operator++(int)
2372  {
2373  auto tmp = *this;
2374  ++(*this);
2375  return tmp;
2376  }
2377  __hostdev__ bool operator==(const Iterator& rhs) const
2378  {
2379  NANOVDB_ASSERT(mBBox == rhs.mBBox);
2380  return mPos == rhs.mPos;
2381  }
2382  __hostdev__ bool operator!=(const Iterator& rhs) const
2383  {
2384  NANOVDB_ASSERT(mBBox == rhs.mBBox);
2385  return mPos != rhs.mPos;
2386  }
2387  __hostdev__ bool operator<(const Iterator& rhs) const
2388  {
2389  NANOVDB_ASSERT(mBBox == rhs.mBBox);
2390  return mPos < rhs.mPos;
2391  }
2392  __hostdev__ bool operator<=(const Iterator& rhs) const
2393  {
2394  NANOVDB_ASSERT(mBBox == rhs.mBBox);
2395  return mPos <= rhs.mPos;
2396  }
2397  /// @brief Return @c true if the iterator still points to a valid coordinate.
2398  __hostdev__ operator bool() const { return mPos <= mBBox[1]; }
2399  __hostdev__ const CoordT& operator*() const { return mPos; }
2400  }; // Iterator
2401  __hostdev__ Iterator begin() const { return Iterator{*this}; }
2402  __hostdev__ Iterator end() const { return Iterator{*this, CoordT(mCoord[1][0]+1, mCoord[0][1], mCoord[0][2])}; }
2404  : BaseT(CoordT::max(), CoordT::min())
2405  {
2406  }
2407  __hostdev__ BBox(const CoordT& min, const CoordT& max)
2408  : BaseT(min, max)
2409  {
2410  }
2411 
2412  template<typename SplitT>
2413  __hostdev__ BBox(BBox& other, const SplitT&)
2414  : BaseT(other.mCoord[0], other.mCoord[1])
2415  {
2416  NANOVDB_ASSERT(this->is_divisible());
2417  const int n = MaxIndex(this->dim());
2418  mCoord[1][n] = (mCoord[0][n] + mCoord[1][n]) >> 1;
2419  other.mCoord[0][n] = mCoord[1][n] + 1;
2420  }
2421 
2422  __hostdev__ static BBox createCube(const CoordT& min, typename CoordT::ValueType dim)
2423  {
2424  return BBox(min, min.offsetBy(dim - 1));
2425  }
2426 
2428  {
2429  return BBox(CoordT(min), CoordT(max));
2430  }
2431 
2432  __hostdev__ bool is_divisible() const { return mCoord[0][0] < mCoord[1][0] &&
2433  mCoord[0][1] < mCoord[1][1] &&
2434  mCoord[0][2] < mCoord[1][2]; }
2435  /// @brief Return true if this bounding box is empty, e.g. uninitialized
2436  __hostdev__ bool empty() const { return mCoord[0][0] > mCoord[1][0] ||
2437  mCoord[0][1] > mCoord[1][1] ||
2438  mCoord[0][2] > mCoord[1][2]; }
2439  /// @brief Convert this BBox to boolean true if it is not empty
2440  __hostdev__ operator bool() const { return mCoord[0][0] <= mCoord[1][0] &&
2441  mCoord[0][1] <= mCoord[1][1] &&
2442  mCoord[0][2] <= mCoord[1][2]; }
2443  __hostdev__ CoordT dim() const { return *this ? this->max() - this->min() + Coord(1) : Coord(0); }
2444  __hostdev__ uint64_t volume() const
2445  {
2446  auto d = this->dim();
2447  return uint64_t(d[0]) * uint64_t(d[1]) * uint64_t(d[2]);
2448  }
2449  __hostdev__ bool isInside(const CoordT& p) const { return !(CoordT::lessThan(p, this->min()) || CoordT::lessThan(this->max(), p)); }
2450  /// @brief Return @c true if the given bounding box is inside this bounding box.
2451  __hostdev__ bool isInside(const BBox& b) const
2452  {
2453  return !(CoordT::lessThan(b.min(), this->min()) || CoordT::lessThan(this->max(), b.max()));
2454  }
2455 
2456  /// @brief Return @c true if the given bounding box overlaps with this bounding box.
2457  __hostdev__ bool hasOverlap(const BBox& b) const
2458  {
2459  return !(CoordT::lessThan(this->max(), b.min()) || CoordT::lessThan(b.max(), this->min()));
2460  }
2461 
2462  /// @warning This converts a CoordBBox into a floating-point bounding box which implies that max += 1 !
2463  template<typename RealT = double>
2465  {
2466  static_assert(is_floating_point<RealT>::value, "CoordBBox::asReal: Expected a floating point coordinate");
2467  return BBox<Vec3<RealT>>(Vec3<RealT>(RealT(mCoord[0][0]), RealT(mCoord[0][1]), RealT(mCoord[0][2])),
2468  Vec3<RealT>(RealT(mCoord[1][0] + 1), RealT(mCoord[1][1] + 1), RealT(mCoord[1][2] + 1)));
2469  }
2470  /// @brief Return a new instance that is expanded by the specified padding.
2471  __hostdev__ BBox expandBy(typename CoordT::ValueType padding) const
2472  {
2473  return BBox(mCoord[0].offsetBy(-padding), mCoord[1].offsetBy(padding));
2474  }
2475 
2476  /// @brief @brief transform this coordinate bounding box by the specified map
2477  /// @param map mapping of index to world coordinates
2478  /// @return world bounding box
2479  template<typename Map>
2481  {
2482  const Vec3d tmp = map.applyMap(Vec3d(mCoord[0][0], mCoord[0][1], mCoord[0][2]));
2483  BBox<Vec3d> bbox(tmp, tmp);
2484  bbox.expand(map.applyMap(Vec3d(mCoord[0][0], mCoord[0][1], mCoord[1][2])));
2485  bbox.expand(map.applyMap(Vec3d(mCoord[0][0], mCoord[1][1], mCoord[0][2])));
2486  bbox.expand(map.applyMap(Vec3d(mCoord[1][0], mCoord[0][1], mCoord[0][2])));
2487  bbox.expand(map.applyMap(Vec3d(mCoord[1][0], mCoord[1][1], mCoord[0][2])));
2488  bbox.expand(map.applyMap(Vec3d(mCoord[1][0], mCoord[0][1], mCoord[1][2])));
2489  bbox.expand(map.applyMap(Vec3d(mCoord[0][0], mCoord[1][1], mCoord[1][2])));
2490  bbox.expand(map.applyMap(Vec3d(mCoord[1][0], mCoord[1][1], mCoord[1][2])));
2491  return bbox;
2492  }
2493 
2494 #if defined(__CUDACC__) // the following functions only run on the GPU!
2495  __device__ inline BBox& expandAtomic(const CoordT& ijk)
2496  {
2497  mCoord[0].minComponentAtomic(ijk);
2498  mCoord[1].maxComponentAtomic(ijk);
2499  return *this;
2500  }
2501  __device__ inline BBox& expandAtomic(const BBox& bbox)
2502  {
2503  mCoord[0].minComponentAtomic(bbox[0]);
2504  mCoord[1].maxComponentAtomic(bbox[1]);
2505  return *this;
2506  }
2507  __device__ inline BBox& intersectAtomic(const BBox& bbox)
2508  {
2509  mCoord[0].maxComponentAtomic(bbox[0]);
2510  mCoord[1].minComponentAtomic(bbox[1]);
2511  return *this;
2512  }
2513 #endif
2514 }; // BBox<CoordT, false>
2515 
2518 
2519 // -------------------> Find lowest and highest bit in a word <----------------------------
2520 
2521 /// @brief Returns the index of the lowest, i.e. least significant, on bit in the specified 32 bit word
2522 ///
2523 /// @warning Assumes that at least one bit is set in the word, i.e. @a v != uint32_t(0)!
2525 __hostdev__ static inline uint32_t FindLowestOn(uint32_t v)
2526 {
2527  NANOVDB_ASSERT(v);
2528 #if (defined(__CUDA_ARCH__) || defined(__HIP__)) && defined(NANOVDB_USE_INTRINSICS)
2529  return __ffs(v) - 1; // one based indexing
2530 #elif defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS)
2531  unsigned long index;
2532  _BitScanForward(&index, v);
2533  return static_cast<uint32_t>(index);
2534 #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS)
2535  return static_cast<uint32_t>(__builtin_ctzl(v));
2536 #else
2537  //NANO_WARNING("Using software implementation for FindLowestOn(uint32_t v)")
2538  static const unsigned char DeBruijn[32] = {
2539  0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9};
2540 // disable unary minus on unsigned warning
2541 #if defined(_MSC_VER) && !defined(__NVCC__)
2542 #pragma warning(push)
2543 #pragma warning(disable : 4146)
2544 #endif
2545  return DeBruijn[uint32_t((v & -v) * 0x077CB531U) >> 27];
2546 #if defined(_MSC_VER) && !defined(__NVCC__)
2547 #pragma warning(pop)
2548 #endif
2549 
2550 #endif
2551 }
2552 
2553 /// @brief Returns the index of the highest, i.e. most significant, on bit in the specified 32 bit word
2554 ///
2555 /// @warning Assumes that at least one bit is set in the word, i.e. @a v != uint32_t(0)!
2557 __hostdev__ static inline uint32_t FindHighestOn(uint32_t v)
2558 {
2559  NANOVDB_ASSERT(v);
2560 #if (defined(__CUDA_ARCH__) || defined(__HIP__)) && defined(NANOVDB_USE_INTRINSICS)
2561  return sizeof(uint32_t) * 8 - 1 - __clz(v); // Return the number of consecutive high-order zero bits in a 32-bit integer.
2562 #elif defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS)
2563  unsigned long index;
2564  _BitScanReverse(&index, v);
2565  return static_cast<uint32_t>(index);
2566 #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS)
2567  return sizeof(unsigned long) * 8 - 1 - __builtin_clzl(v);
2568 #else
2569  //NANO_WARNING("Using software implementation for FindHighestOn(uint32_t)")
2570  static const unsigned char DeBruijn[32] = {
2571  0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
2572  8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31};
2573  v |= v >> 1; // first round down to one less than a power of 2
2574  v |= v >> 2;
2575  v |= v >> 4;
2576  v |= v >> 8;
2577  v |= v >> 16;
2578  return DeBruijn[uint32_t(v * 0x07C4ACDDU) >> 27];
2579 #endif
2580 }
2581 
2582 /// @brief Returns the index of the lowest, i.e. least significant, on bit in the specified 64 bit word
2583 ///
2584 /// @warning Assumes that at least one bit is set in the word, i.e. @a v != uint32_t(0)!
2586 __hostdev__ static inline uint32_t FindLowestOn(uint64_t v)
2587 {
2588  NANOVDB_ASSERT(v);
2589 #if (defined(__CUDA_ARCH__) || defined(__HIP__)) && defined(NANOVDB_USE_INTRINSICS)
2590  return __ffsll(static_cast<unsigned long long int>(v)) - 1; // one based indexing
2591 #elif defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS)
2592  unsigned long index;
2593  _BitScanForward64(&index, v);
2594  return static_cast<uint32_t>(index);
2595 #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS)
2596  return static_cast<uint32_t>(__builtin_ctzll(v));
2597 #else
2598  //NANO_WARNING("Using software implementation for FindLowestOn(uint64_t)")
2599  static const unsigned char DeBruijn[64] = {
2600  0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
2601  62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
2602  63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
2603  51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12,
2604  };
2605 // disable unary minus on unsigned warning
2606 #if defined(_MSC_VER) && !defined(__NVCC__)
2607 #pragma warning(push)
2608 #pragma warning(disable : 4146)
2609 #endif
2610  return DeBruijn[uint64_t((v & -v) * UINT64_C(0x022FDD63CC95386D)) >> 58];
2611 #if defined(_MSC_VER) && !defined(__NVCC__)
2612 #pragma warning(pop)
2613 #endif
2614 
2615 #endif
2616 }
2617 
2618 /// @brief Returns the index of the highest, i.e. most significant, on bit in the specified 64 bit word
2619 ///
2620 /// @warning Assumes that at least one bit is set in the word, i.e. @a v != uint32_t(0)!
2622 __hostdev__ static inline uint32_t FindHighestOn(uint64_t v)
2623 {
2624  NANOVDB_ASSERT(v);
2625 #if (defined(__CUDA_ARCH__) || defined(__HIP__)) && defined(NANOVDB_USE_INTRINSICS)
2626  return sizeof(unsigned long) * 8 - 1 - __clzll(static_cast<unsigned long long int>(v));
2627 #elif defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS)
2628  unsigned long index;
2629  _BitScanReverse64(&index, v);
2630  return static_cast<uint32_t>(index);
2631 #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS)
2632  return sizeof(unsigned long) * 8 - 1 - __builtin_clzll(v);
2633 #else
2634  const uint32_t* p = reinterpret_cast<const uint32_t*>(&v);
2635  return p[1] ? 32u + FindHighestOn(p[1]) : FindHighestOn(p[0]);
2636 #endif
2637 }
2638 
2639 // ----------------------------> CountOn <--------------------------------------
2640 
2641 /// @return Number of bits that are on in the specified 64-bit word
2643 __hostdev__ inline uint32_t CountOn(uint64_t v)
2644 {
2645 #if (defined(__CUDA_ARCH__) || defined(__HIP__)) && defined(NANOVDB_USE_INTRINSICS)
2646  //#warning Using popcll for CountOn
2647  return __popcll(v);
2648 // __popcnt64 intrinsic support was added in VS 2019 16.8
2649 #elif defined(_MSC_VER) && defined(_M_X64) && (_MSC_VER >= 1928) && defined(NANOVDB_USE_INTRINSICS)
2650  //#warning Using popcnt64 for CountOn
2651  return uint32_t(__popcnt64(v));
2652 #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS)
2653  //#warning Using builtin_popcountll for CountOn
2654  return __builtin_popcountll(v);
2655 #else // use software implementation
2656  //NANO_WARNING("Using software implementation for CountOn")
2657  v = v - ((v >> 1) & uint64_t(0x5555555555555555));
2658  v = (v & uint64_t(0x3333333333333333)) + ((v >> 2) & uint64_t(0x3333333333333333));
2659  return (((v + (v >> 4)) & uint64_t(0xF0F0F0F0F0F0F0F)) * uint64_t(0x101010101010101)) >> 56;
2660 #endif
2661 }
2662 
2663 // ----------------------------> BitFlags <--------------------------------------
2664 
2665 template<int N>
2666 struct BitArray;
2667 template<>
2668 struct BitArray<8>
2669 {
2670  uint8_t mFlags{0};
2671 };
2672 template<>
2673 struct BitArray<16>
2674 {
2675  uint16_t mFlags{0};
2676 };
2677 template<>
2678 struct BitArray<32>
2679 {
2680  uint32_t mFlags{0};
2681 };
2682 template<>
2683 struct BitArray<64>
2684 {
2685  uint64_t mFlags{0};
2686 };
2687 
2688 template<int N>
2689 class BitFlags : public BitArray<N>
2690 {
2691 protected:
2692  using BitArray<N>::mFlags;
2693 
2694 public:
2695  using Type = decltype(mFlags);
2697  BitFlags(std::initializer_list<uint8_t> list)
2698  {
2699  for (auto bit : list)
2700  mFlags |= static_cast<Type>(1 << bit);
2701  }
2702  template<typename MaskT>
2703  BitFlags(std::initializer_list<MaskT> list)
2704  {
2705  for (auto mask : list)
2706  mFlags |= static_cast<Type>(mask);
2707  }
2708  __hostdev__ Type data() const { return mFlags; }
2709  __hostdev__ Type& data() { return mFlags; }
2710  __hostdev__ void initBit(std::initializer_list<uint8_t> list)
2711  {
2712  mFlags = 0u;
2713  for (auto bit : list)
2714  mFlags |= static_cast<Type>(1 << bit);
2715  }
2716  template<typename MaskT>
2717  __hostdev__ void initMask(std::initializer_list<MaskT> list)
2718  {
2719  mFlags = 0u;
2720  for (auto mask : list)
2721  mFlags |= static_cast<Type>(mask);
2722  }
2723  //__hostdev__ Type& data() { return mFlags; }
2724  //__hostdev__ Type data() const { return mFlags; }
2725  __hostdev__ Type getFlags() const { return mFlags & (static_cast<Type>(GridFlags::End) - 1u); } // mask out everything except relevant bits
2726 
2727  __hostdev__ void setOn() { mFlags = ~Type(0u); }
2728  __hostdev__ void setOff() { mFlags = Type(0u); }
2729 
2730  __hostdev__ void setBitOn(uint8_t bit) { mFlags |= static_cast<Type>(1 << bit); }
2731  __hostdev__ void setBitOff(uint8_t bit) { mFlags &= ~static_cast<Type>(1 << bit); }
2732 
2733  __hostdev__ void setBitOn(std::initializer_list<uint8_t> list)
2734  {
2735  for (auto bit : list)
2736  mFlags |= static_cast<Type>(1 << bit);
2737  }
2738  __hostdev__ void setBitOff(std::initializer_list<uint8_t> list)
2739  {
2740  for (auto bit : list)
2741  mFlags &= ~static_cast<Type>(1 << bit);
2742  }
2743 
2744  template<typename MaskT>
2745  __hostdev__ void setMaskOn(MaskT mask) { mFlags |= static_cast<Type>(mask); }
2746  template<typename MaskT>
2747  __hostdev__ void setMaskOff(MaskT mask) { mFlags &= ~static_cast<Type>(mask); }
2748 
2749  template<typename MaskT>
2750  __hostdev__ void setMaskOn(std::initializer_list<MaskT> list)
2751  {
2752  for (auto mask : list)
2753  mFlags |= static_cast<Type>(mask);
2754  }
2755  template<typename MaskT>
2756  __hostdev__ void setMaskOff(std::initializer_list<MaskT> list)
2757  {
2758  for (auto mask : list)
2759  mFlags &= ~static_cast<Type>(mask);
2760  }
2761 
2762  __hostdev__ void setBit(uint8_t bit, bool on) { on ? this->setBitOn(bit) : this->setBitOff(bit); }
2763  template<typename MaskT>
2764  __hostdev__ void setMask(MaskT mask, bool on) { on ? this->setMaskOn(mask) : this->setMaskOff(mask); }
2765 
2766  __hostdev__ bool isOn() const { return mFlags == ~Type(0u); }
2767  __hostdev__ bool isOff() const { return mFlags == Type(0u); }
2768  __hostdev__ bool isBitOn(uint8_t bit) const { return 0 != (mFlags & static_cast<Type>(1 << bit)); }
2769  __hostdev__ bool isBitOff(uint8_t bit) const { return 0 == (mFlags & static_cast<Type>(1 << bit)); }
2770  template<typename MaskT>
2771  __hostdev__ bool isMaskOn(MaskT mask) const { return 0 != (mFlags & static_cast<Type>(mask)); }
2772  template<typename MaskT>
2773  __hostdev__ bool isMaskOff(MaskT mask) const { return 0 == (mFlags & static_cast<Type>(mask)); }
2774  /// @brief return true if any of the masks in the list are on
2775  template<typename MaskT>
2776  __hostdev__ bool isMaskOn(std::initializer_list<MaskT> list) const
2777  {
2778  for (auto mask : list)
2779  if (0 != (mFlags & static_cast<Type>(mask)))
2780  return true;
2781  return false;
2782  }
2783  /// @brief return true if any of the masks in the list are off
2784  template<typename MaskT>
2785  __hostdev__ bool isMaskOff(std::initializer_list<MaskT> list) const
2786  {
2787  for (auto mask : list)
2788  if (0 == (mFlags & static_cast<Type>(mask)))
2789  return true;
2790  return false;
2791  }
2792  /// @brief required for backwards compatibility
2794  {
2795  mFlags = n;
2796  return *this;
2797  }
2798 }; // BitFlags<N>
2799 
2800 // ----------------------------> Mask <--------------------------------------
2801 
2802 /// @brief Bit-mask to encode active states and facilitate sequential iterators
2803 /// and a fast codec for I/O compression.
2804 template<uint32_t LOG2DIM>
2805 class Mask
2806 {
2807 public:
2808  static constexpr uint32_t SIZE = 1U << (3 * LOG2DIM); // Number of bits in mask
2809  static constexpr uint32_t WORD_COUNT = SIZE >> 6; // Number of 64 bit words
2810 
2811  /// @brief Return the memory footprint in bytes of this Mask
2812  __hostdev__ static size_t memUsage() { return sizeof(Mask); }
2813 
2814  /// @brief Return the number of bits available in this Mask
2815  __hostdev__ static uint32_t bitCount() { return SIZE; }
2816 
2817  /// @brief Return the number of machine words used by this Mask
2818  __hostdev__ static uint32_t wordCount() { return WORD_COUNT; }
2819 
2820  /// @brief Return the total number of set bits in this Mask
2821  __hostdev__ uint32_t countOn() const
2822  {
2823  uint32_t sum = 0;
2824  for (const uint64_t *w = mWords, *q = w + WORD_COUNT; w != q; ++w)
2825  sum += CountOn(*w);
2826  return sum;
2827  }
2828 
2829  /// @brief Return the number of lower set bits in mask up to but excluding the i'th bit
2830  inline __hostdev__ uint32_t countOn(uint32_t i) const
2831  {
2832  uint32_t n = i >> 6, sum = CountOn(mWords[n] & ((uint64_t(1) << (i & 63u)) - 1u));
2833  for (const uint64_t* w = mWords; n--; ++w)
2834  sum += CountOn(*w);
2835  return sum;
2836  }
2837 
2838  template<bool On>
2839  class Iterator
2840  {
2841  public:
2843  : mPos(Mask::SIZE)
2844  , mParent(nullptr)
2845  {
2846  }
2847  __hostdev__ Iterator(uint32_t pos, const Mask* parent)
2848  : mPos(pos)
2849  , mParent(parent)
2850  {
2851  }
2852  Iterator(const Iterator&) = default;
2853  Iterator& operator=(const Iterator&) = default;
2854  __hostdev__ uint32_t operator*() const { return mPos; }
2855  __hostdev__ uint32_t pos() const { return mPos; }
2856  __hostdev__ operator bool() const { return mPos != Mask::SIZE; }
2858  {
2859  mPos = mParent->findNext<On>(mPos + 1);
2860  return *this;
2861  }
2863  {
2864  auto tmp = *this;
2865  ++(*this);
2866  return tmp;
2867  }
2868 
2869  private:
2870  uint32_t mPos;
2871  const Mask* mParent;
2872  }; // Member class Iterator
2873 
2875  {
2876  public:
2878  : mPos(pos)
2879  {
2880  }
2881  DenseIterator& operator=(const DenseIterator&) = default;
2882  __hostdev__ uint32_t operator*() const { return mPos; }
2883  __hostdev__ uint32_t pos() const { return mPos; }
2884  __hostdev__ operator bool() const { return mPos != Mask::SIZE; }
2886  {
2887  ++mPos;
2888  return *this;
2889  }
2891  {
2892  auto tmp = *this;
2893  ++mPos;
2894  return tmp;
2895  }
2896 
2897  private:
2898  uint32_t mPos;
2899  }; // Member class DenseIterator
2900 
2903 
2904  __hostdev__ OnIterator beginOn() const { return OnIterator(this->findFirst<true>(), this); }
2905 
2906  __hostdev__ OffIterator beginOff() const { return OffIterator(this->findFirst<false>(), this); }
2907 
2909 
2910  /// @brief Initialize all bits to zero.
2912  {
2913  for (uint32_t i = 0; i < WORD_COUNT; ++i)
2914  mWords[i] = 0;
2915  }
2917  {
2918  const uint64_t v = on ? ~uint64_t(0) : uint64_t(0);
2919  for (uint32_t i = 0; i < WORD_COUNT; ++i)
2920  mWords[i] = v;
2921  }
2922 
2923  /// @brief Copy constructor
2924  __hostdev__ Mask(const Mask& other)
2925  {
2926  for (uint32_t i = 0; i < WORD_COUNT; ++i)
2927  mWords[i] = other.mWords[i];
2928  }
2929 
2930  /// @brief Return a pointer to the list of words of the bit mask
2931  __hostdev__ uint64_t* words() { return mWords; }
2932  __hostdev__ const uint64_t* words() const { return mWords; }
2933 
2934  /// @brief Assignment operator that works with openvdb::util::NodeMask
2935  template<typename MaskT = Mask>
2937  {
2938  static_assert(sizeof(Mask) == sizeof(MaskT), "Mismatching sizeof");
2939  static_assert(WORD_COUNT == MaskT::WORD_COUNT, "Mismatching word count");
2940  static_assert(LOG2DIM == MaskT::LOG2DIM, "Mismatching LOG2DIM");
2941  auto* src = reinterpret_cast<const uint64_t*>(&other);
2942  for (uint64_t *dst = mWords, *end = dst + WORD_COUNT; dst != end; ++dst)
2943  *dst = *src++;
2944  return *this;
2945  }
2946 
2948  {
2949  memcpy64(mWords, other.mWords, WORD_COUNT);
2950  return *this;
2951  }
2952 
2953  __hostdev__ bool operator==(const Mask& other) const
2954  {
2955  for (uint32_t i = 0; i < WORD_COUNT; ++i) {
2956  if (mWords[i] != other.mWords[i])
2957  return false;
2958  }
2959  return true;
2960  }
2961 
2962  __hostdev__ bool operator!=(const Mask& other) const { return !((*this) == other); }
2963 
2964  /// @brief Return true if the given bit is set.
2965  __hostdev__ bool isOn(uint32_t n) const { return 0 != (mWords[n >> 6] & (uint64_t(1) << (n & 63))); }
2966 
2967  /// @brief Return true if the given bit is NOT set.
2968  __hostdev__ bool isOff(uint32_t n) const { return 0 == (mWords[n >> 6] & (uint64_t(1) << (n & 63))); }
2969 
2970  /// @brief Return true if all the bits are set in this Mask.
2971  __hostdev__ bool isOn() const
2972  {
2973  for (uint32_t i = 0; i < WORD_COUNT; ++i)
2974  if (mWords[i] != ~uint64_t(0))
2975  return false;
2976  return true;
2977  }
2978 
2979  /// @brief Return true if none of the bits are set in this Mask.
2980  __hostdev__ bool isOff() const
2981  {
2982  for (uint32_t i = 0; i < WORD_COUNT; ++i)
2983  if (mWords[i] != uint64_t(0))
2984  return false;
2985  return true;
2986  }
2987 
2988  /// @brief Set the specified bit on.
2989  __hostdev__ void setOn(uint32_t n) { mWords[n >> 6] |= uint64_t(1) << (n & 63); }
2990  /// @brief Set the specified bit off.
2991  __hostdev__ void setOff(uint32_t n) { mWords[n >> 6] &= ~(uint64_t(1) << (n & 63)); }
2992 
2993 #if defined(__CUDACC__) // the following functions only run on the GPU!
2994  __device__ inline void setOnAtomic(uint32_t n)
2995  {
2996  atomicOr(reinterpret_cast<unsigned long long int*>(this) + (n >> 6), 1ull << (n & 63));
2997  }
2998  __device__ inline void setOffAtomic(uint32_t n)
2999  {
3000  atomicAnd(reinterpret_cast<unsigned long long int*>(this) + (n >> 6), ~(1ull << (n & 63)));
3001  }
3002  __device__ inline void setAtomic(uint32_t n, bool on)
3003  {
3004  on ? this->setOnAtomic(n) : this->setOffAtomic(n);
3005  }
3006 #endif
3007  /// @brief Set the specified bit on or off.
3008  __hostdev__ void set(uint32_t n, bool on)
3009  {
3010 #if 1 // switch between branchless
3011  auto& word = mWords[n >> 6];
3012  n &= 63;
3013  word &= ~(uint64_t(1) << n);
3014  word |= uint64_t(on) << n;
3015 #else
3016  on ? this->setOn(n) : this->setOff(n);
3017 #endif
3018  }
3019 
3020  /// @brief Set all bits on
3022  {
3023  for (uint32_t i = 0; i < WORD_COUNT; ++i)
3024  mWords[i] = ~uint64_t(0);
3025  }
3026 
3027  /// @brief Set all bits off
3029  {
3030  for (uint32_t i = 0; i < WORD_COUNT; ++i)
3031  mWords[i] = uint64_t(0);
3032  }
3033 
3034  /// @brief Set all bits off
3035  __hostdev__ void set(bool on)
3036  {
3037  const uint64_t v = on ? ~uint64_t(0) : uint64_t(0);
3038  for (uint32_t i = 0; i < WORD_COUNT; ++i)
3039  mWords[i] = v;
3040  }
3041  /// brief Toggle the state of all bits in the mask
3043  {
3044  uint32_t n = WORD_COUNT;
3045  for (auto* w = mWords; n--; ++w)
3046  *w = ~*w;
3047  }
3048  __hostdev__ void toggle(uint32_t n) { mWords[n >> 6] ^= uint64_t(1) << (n & 63); }
3049 
3050  /// @brief Bitwise intersection
3052  {
3053  uint64_t* w1 = mWords;
3054  const uint64_t* w2 = other.mWords;
3055  for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2)
3056  *w1 &= *w2;
3057  return *this;
3058  }
3059  /// @brief Bitwise union
3061  {
3062  uint64_t* w1 = mWords;
3063  const uint64_t* w2 = other.mWords;
3064  for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2)
3065  *w1 |= *w2;
3066  return *this;
3067  }
3068  /// @brief Bitwise difference
3070  {
3071  uint64_t* w1 = mWords;
3072  const uint64_t* w2 = other.mWords;
3073  for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2)
3074  *w1 &= ~*w2;
3075  return *this;
3076  }
3077  /// @brief Bitwise XOR
3079  {
3080  uint64_t* w1 = mWords;
3081  const uint64_t* w2 = other.mWords;
3082  for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2)
3083  *w1 ^= *w2;
3084  return *this;
3085  }
3086 
3088  template<bool ON>
3089  __hostdev__ uint32_t findFirst() const
3090  {
3091  uint32_t n = 0u;
3092  const uint64_t* w = mWords;
3093  for (; n < WORD_COUNT && !(ON ? *w : ~*w); ++w, ++n)
3094  ;
3095  return n < WORD_COUNT ? (n << 6) + FindLowestOn(ON ? *w : ~*w) : SIZE;
3096  }
3097 
3099  template<bool ON>
3100  __hostdev__ uint32_t findNext(uint32_t start) const
3101  {
3102  uint32_t n = start >> 6; // initiate
3103  if (n >= WORD_COUNT)
3104  return SIZE; // check for out of bounds
3105  uint32_t m = start & 63u;
3106  uint64_t b = ON ? mWords[n] : ~mWords[n];
3107  if (b & (uint64_t(1u) << m))
3108  return start; // simple case: start is on/off
3109  b &= ~uint64_t(0u) << m; // mask out lower bits
3110  while (!b && ++n < WORD_COUNT)
3111  b = ON ? mWords[n] : ~mWords[n]; // find next non-zero word
3112  return b ? (n << 6) + FindLowestOn(b) : SIZE; // catch last word=0
3113  }
3114 
3116  template<bool ON>
3117  __hostdev__ uint32_t findPrev(uint32_t start) const
3118  {
3119  uint32_t n = start >> 6; // initiate
3120  if (n >= WORD_COUNT)
3121  return SIZE; // check for out of bounds
3122  uint32_t m = start & 63u;
3123  uint64_t b = ON ? mWords[n] : ~mWords[n];
3124  if (b & (uint64_t(1u) << m))
3125  return start; // simple case: start is on/off
3126  b &= (uint64_t(1u) << m) - 1u; // mask out higher bits
3127  while (!b && n)
3128  b = ON ? mWords[--n] : ~mWords[--n]; // find previous non-zero word
3129  return b ? (n << 6) + FindHighestOn(b) : SIZE; // catch first word=0
3130  }
3131 
3132 private:
3133  uint64_t mWords[WORD_COUNT];
3134 }; // Mask class
3135 
3136 // ----------------------------> Map <--------------------------------------
3137 
3138 /// @brief Defines an affine transform and its inverse represented as a 3x3 matrix and a vec3 translation
3139 struct Map
3140 { // 264B (not 32B aligned!)
3141  float mMatF[9]; // 9*4B <- 3x3 matrix
3142  float mInvMatF[9]; // 9*4B <- 3x3 matrix
3143  float mVecF[3]; // 3*4B <- translation
3144  float mTaperF; // 4B, placeholder for taper value
3145  double mMatD[9]; // 9*8B <- 3x3 matrix
3146  double mInvMatD[9]; // 9*8B <- 3x3 matrix
3147  double mVecD[3]; // 3*8B <- translation
3148  double mTaperD; // 8B, placeholder for taper value
3149 
3150  /// @brief Default constructor for the identity map
3152  : mMatF{1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}
3153  , mInvMatF{1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}
3154  , mVecF{0.0f, 0.0f, 0.0f}
3155  , mTaperF{1.0f}
3156  , mMatD{1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}
3157  , mInvMatD{1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}
3158  , mVecD{0.0, 0.0, 0.0}
3159  , mTaperD{1.0}
3160  {
3161  }
3162  __hostdev__ Map(double s, const Vec3d& t = Vec3d(0.0, 0.0, 0.0))
3163  : mMatF{float(s), 0.0f, 0.0f, 0.0f, float(s), 0.0f, 0.0f, 0.0f, float(s)}
3164  , mInvMatF{1.0f / float(s), 0.0f, 0.0f, 0.0f, 1.0f / float(s), 0.0f, 0.0f, 0.0f, 1.0f / float(s)}
3165  , mVecF{float(t[0]), float(t[1]), float(t[2])}
3166  , mTaperF{1.0f}
3167  , mMatD{s, 0.0, 0.0, 0.0, s, 0.0, 0.0, 0.0, s}
3168  , mInvMatD{1.0 / s, 0.0, 0.0, 0.0, 1.0 / s, 0.0, 0.0, 0.0, 1.0 / s}
3169  , mVecD{t[0], t[1], t[2]}
3170  , mTaperD{1.0}
3171  {
3172  }
3173 
3174  /// @brief Initialize the member data from 3x3 or 4x4 matrices
3175  /// @note This is not _hostdev__ since then MatT=openvdb::Mat4d will produce warnings
3176  template<typename MatT, typename Vec3T>
3177  void set(const MatT& mat, const MatT& invMat, const Vec3T& translate, double taper = 1.0);
3178 
3179  /// @brief Initialize the member data from 4x4 matrices
3180  /// @note The last (4th) row of invMat is actually ignored.
3181  /// This is not _hostdev__ since then Mat4T=openvdb::Mat4d will produce warnings
3182  template<typename Mat4T>
3183  void set(const Mat4T& mat, const Mat4T& invMat, double taper = 1.0) { this->set(mat, invMat, mat[3], taper); }
3184 
3185  template<typename Vec3T>
3186  void set(double scale, const Vec3T& translation, double taper = 1.0);
3187 
3188  /// @brief Apply the forward affine transformation to a vector using 64bit floating point arithmetics.
3189  /// @note Typically this operation is used for the scale, rotation and translation of index -> world mapping
3190  /// @tparam Vec3T Template type of the 3D vector to be mapped
3191  /// @param ijk 3D vector to be mapped - typically floating point index coordinates
3192  /// @return Forward mapping for affine transformation, i.e. (mat x ijk) + translation
3193  template<typename Vec3T>
3194  __hostdev__ Vec3T applyMap(const Vec3T& ijk) const { return matMult(mMatD, mVecD, ijk); }
3195 
3196  /// @brief Apply the forward affine transformation to a vector using 32bit floating point arithmetics.
3197  /// @note Typically this operation is used for the scale, rotation and translation of index -> world mapping
3198  /// @tparam Vec3T Template type of the 3D vector to be mapped
3199  /// @param ijk 3D vector to be mapped - typically floating point index coordinates
3200  /// @return Forward mapping for affine transformation, i.e. (mat x ijk) + translation
3201  template<typename Vec3T>
3202  __hostdev__ Vec3T applyMapF(const Vec3T& ijk) const { return matMult(mMatF, mVecF, ijk); }
3203 
3204  /// @brief Apply the linear forward 3x3 transformation to an input 3d vector using 64bit floating point arithmetics,
3205  /// e.g. scale and rotation WITHOUT translation.
3206  /// @note Typically this operation is used for scale and rotation from index -> world mapping
3207  /// @tparam Vec3T Template type of the 3D vector to be mapped
3208  /// @param ijk 3D vector to be mapped - typically floating point index coordinates
3209  /// @return linear forward 3x3 mapping of the input vector
3210  template<typename Vec3T>
3211  __hostdev__ Vec3T applyJacobian(const Vec3T& ijk) const { return matMult(mMatD, ijk); }
3212 
3213  /// @brief Apply the linear forward 3x3 transformation to an input 3d vector using 32bit floating point arithmetics,
3214  /// e.g. scale and rotation WITHOUT translation.
3215  /// @note Typically this operation is used for scale and rotation from index -> world mapping
3216  /// @tparam Vec3T Template type of the 3D vector to be mapped
3217  /// @param ijk 3D vector to be mapped - typically floating point index coordinates
3218  /// @return linear forward 3x3 mapping of the input vector
3219  template<typename Vec3T>
3220  __hostdev__ Vec3T applyJacobianF(const Vec3T& ijk) const { return matMult(mMatF, ijk); }
3221 
3222  /// @brief Apply the inverse affine mapping to a vector using 64bit floating point arithmetics.
3223  /// @note Typically this operation is used for the world -> index mapping
3224  /// @tparam Vec3T Template type of the 3D vector to be mapped
3225  /// @param xyz 3D vector to be mapped - typically floating point world coordinates
3226  /// @return Inverse affine mapping of the input @c xyz i.e. (xyz - translation) x mat^-1
3227  template<typename Vec3T>
3228  __hostdev__ Vec3T applyInverseMap(const Vec3T& xyz) const
3229  {
3230  return matMult(mInvMatD, Vec3T(xyz[0] - mVecD[0], xyz[1] - mVecD[1], xyz[2] - mVecD[2]));
3231  }
3232 
3233  /// @brief Apply the inverse affine mapping to a vector using 32bit floating point arithmetics.
3234  /// @note Typically this operation is used for the world -> index mapping
3235  /// @tparam Vec3T Template type of the 3D vector to be mapped
3236  /// @param xyz 3D vector to be mapped - typically floating point world coordinates
3237  /// @return Inverse affine mapping of the input @c xyz i.e. (xyz - translation) x mat^-1
3238  template<typename Vec3T>
3239  __hostdev__ Vec3T applyInverseMapF(const Vec3T& xyz) const
3240  {
3241  return matMult(mInvMatF, Vec3T(xyz[0] - mVecF[0], xyz[1] - mVecF[1], xyz[2] - mVecF[2]));
3242  }
3243 
3244  /// @brief Apply the linear inverse 3x3 transformation to an input 3d vector using 64bit floating point arithmetics,
3245  /// e.g. inverse scale and inverse rotation WITHOUT translation.
3246  /// @note Typically this operation is used for scale and rotation from world -> index mapping
3247  /// @tparam Vec3T Template type of the 3D vector to be mapped
3248  /// @param ijk 3D vector to be mapped - typically floating point index coordinates
3249  /// @return linear inverse 3x3 mapping of the input vector i.e. xyz x mat^-1
3250  template<typename Vec3T>
3251  __hostdev__ Vec3T applyInverseJacobian(const Vec3T& xyz) const { return matMult(mInvMatD, xyz); }
3252 
3253  /// @brief Apply the linear inverse 3x3 transformation to an input 3d vector using 32bit floating point arithmetics,
3254  /// e.g. inverse scale and inverse rotation WITHOUT translation.
3255  /// @note Typically this operation is used for scale and rotation from world -> index mapping
3256  /// @tparam Vec3T Template type of the 3D vector to be mapped
3257  /// @param ijk 3D vector to be mapped - typically floating point index coordinates
3258  /// @return linear inverse 3x3 mapping of the input vector i.e. xyz x mat^-1
3259  template<typename Vec3T>
3260  __hostdev__ Vec3T applyInverseJacobianF(const Vec3T& xyz) const { return matMult(mInvMatF, xyz); }
3261 
3262  /// @brief Apply the transposed inverse 3x3 transformation to an input 3d vector using 64bit floating point arithmetics,
3263  /// e.g. inverse scale and inverse rotation WITHOUT translation.
3264  /// @note Typically this operation is used for scale and rotation from world -> index mapping
3265  /// @tparam Vec3T Template type of the 3D vector to be mapped
3266  /// @param ijk 3D vector to be mapped - typically floating point index coordinates
3267  /// @return linear inverse 3x3 mapping of the input vector i.e. xyz x mat^-1
3268  template<typename Vec3T>
3269  __hostdev__ Vec3T applyIJT(const Vec3T& xyz) const { return matMultT(mInvMatD, xyz); }
3270  template<typename Vec3T>
3271  __hostdev__ Vec3T applyIJTF(const Vec3T& xyz) const { return matMultT(mInvMatF, xyz); }
3272 
3273  /// @brief Return a voxels size in each coordinate direction, measured at the origin
3274  __hostdev__ Vec3d getVoxelSize() const { return this->applyMap(Vec3d(1)) - this->applyMap(Vec3d(0)); }
3275 }; // Map
3276 
3277 template<typename MatT, typename Vec3T>
3278 inline void Map::set(const MatT& mat, const MatT& invMat, const Vec3T& translate, double taper)
3279 {
3280  float * mf = mMatF, *vf = mVecF, *mif = mInvMatF;
3281  double *md = mMatD, *vd = mVecD, *mid = mInvMatD;
3282  mTaperF = static_cast<float>(taper);
3283  mTaperD = taper;
3284  for (int i = 0; i < 3; ++i) {
3285  *vd++ = translate[i]; //translation
3286  *vf++ = static_cast<float>(translate[i]); //translation
3287  for (int j = 0; j < 3; ++j) {
3288  *md++ = mat[j][i]; //transposed
3289  *mid++ = invMat[j][i];
3290  *mf++ = static_cast<float>(mat[j][i]); //transposed
3291  *mif++ = static_cast<float>(invMat[j][i]);
3292  }
3293  }
3294 }
3295 
3296 template<typename Vec3T>
3297 inline void Map::set(double dx, const Vec3T& trans, double taper)
3298 {
3299  NANOVDB_ASSERT(dx > 0.0);
3300  const double mat[3][3] = { {dx, 0.0, 0.0}, // row 0
3301  {0.0, dx, 0.0}, // row 1
3302  {0.0, 0.0, dx} }; // row 2
3303  const double idx = 1.0 / dx;
3304  const double invMat[3][3] = { {idx, 0.0, 0.0}, // row 0
3305  {0.0, idx, 0.0}, // row 1
3306  {0.0, 0.0, idx} }; // row 2
3307  this->set(mat, invMat, trans, taper);
3308 }
3309 
3310 // ----------------------------> GridBlindMetaData <--------------------------------------
3311 
3312 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridBlindMetaData
3313 { // 288 bytes
3314  static const int MaxNameSize = 256; // due to NULL termination the maximum length is one less!
3315  int64_t mDataOffset; // byte offset to the blind data, relative to this GridBlindMetaData.
3316  uint64_t mValueCount; // number of blind values, e.g. point count
3317  uint32_t mValueSize;// byte size of each value, e.g. 4 if mDataType=Float and 1 if mDataType=Unknown since that amounts to char
3318  GridBlindDataSemantic mSemantic; // semantic meaning of the data.
3319  GridBlindDataClass mDataClass; // 4 bytes
3320  GridType mDataType; // 4 bytes
3321  char mName[MaxNameSize]; // note this includes the NULL termination
3322  // no padding required for 32 byte alignment
3323 
3324  // disallow copy-construction since methods like blindData and getBlindData uses the this pointer!
3325  GridBlindMetaData(const GridBlindMetaData&) = delete;
3326 
3327  // disallow copy-assignment since methods like blindData and getBlindData uses the this pointer!
3328  const GridBlindMetaData& operator=(const GridBlindMetaData&) = delete;
3329 
3330  __hostdev__ void setBlindData(void* blindData) { mDataOffset = PtrDiff(blindData, this); }
3331 
3332  // unsafe
3333  __hostdev__ const void* blindData() const {return PtrAdd<void>(this, mDataOffset);}
3334 
3335  /// @brief Get a const pointer to the blind data represented by this meta data
3336  /// @tparam BlindDataT Expected value type of the blind data.
3337  /// @return Returns NULL if mGridType!=mapToGridType<BlindDataT>(), else a const point of type BlindDataT.
3338  /// @note Use mDataType=Unknown if BlindDataT is a custom data type unknown to NanoVDB.
3339  template<typename BlindDataT>
3340  __hostdev__ const BlindDataT* getBlindData() const
3341  {
3342  //if (mDataType != mapToGridType<BlindDataT>()) printf("getBlindData mismatch\n");
3343  return mDataType == mapToGridType<BlindDataT>() ? PtrAdd<BlindDataT>(this, mDataOffset) : nullptr;
3344  }
3345 
3346  /// @brief return true if this meta data has a valid combination of semantic, class and value tags
3347  __hostdev__ bool isValid() const
3348  {
3349  auto check = [&]()->bool{
3350  switch (mDataType){
3351  case GridType::Unknown: return mValueSize==1u;// i.e. we encode data as mValueCount chars
3352  case GridType::Float: return mValueSize==4u;
3353  case GridType::Double: return mValueSize==8u;
3354  case GridType::Int16: return mValueSize==2u;
3355  case GridType::Int32: return mValueSize==4u;
3356  case GridType::Int64: return mValueSize==8u;
3357  case GridType::Vec3f: return mValueSize==12u;
3358  case GridType::Vec3d: return mValueSize==24u;
3359  case GridType::Half: return mValueSize==2u;
3360  case GridType::RGBA8: return mValueSize==4u;
3361  case GridType::Fp8: return mValueSize==1u;
3362  case GridType::Fp16: return mValueSize==2u;
3363  case GridType::Vec4f: return mValueSize==16u;
3364  case GridType::Vec4d: return mValueSize==32u;
3365  case GridType::Vec3u8: return mValueSize==3u;
3366  case GridType::Vec3u16: return mValueSize==6u;
3367  default: return true;}// all other combinations are valid
3368  };
3369  return nanovdb::isValid(mDataClass, mSemantic, mDataType) && check();
3370  }
3371 
3372  /// @brief return size in bytes of the blind data represented by this blind meta data
3373  /// @note This size includes possible padding for 32 byte alignment. The actual amount
3374  /// of bind data is mValueCount * mValueSize
3375  __hostdev__ uint64_t blindDataSize() const
3376  {
3377  return AlignUp<NANOVDB_DATA_ALIGNMENT>(mValueCount * mValueSize);
3378  }
3379 }; // GridBlindMetaData
3380 
3381 // ----------------------------> NodeTrait <--------------------------------------
3382 
3383 /// @brief Struct to derive node type from its level in a given
3384 /// grid, tree or root while preserving constness
3385 template<typename GridOrTreeOrRootT, int LEVEL>
3386 struct NodeTrait;
3387 
3388 // Partial template specialization of above Node struct
3389 template<typename GridOrTreeOrRootT>
3390 struct NodeTrait<GridOrTreeOrRootT, 0>
3391 {
3392  static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported");
3393  using Type = typename GridOrTreeOrRootT::LeafNodeType;
3394  using type = typename GridOrTreeOrRootT::LeafNodeType;
3395 };
3396 template<typename GridOrTreeOrRootT>
3397 struct NodeTrait<const GridOrTreeOrRootT, 0>
3398 {
3399  static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported");
3400  using Type = const typename GridOrTreeOrRootT::LeafNodeType;
3401  using type = const typename GridOrTreeOrRootT::LeafNodeType;
3402 };
3403 
3404 template<typename GridOrTreeOrRootT>
3405 struct NodeTrait<GridOrTreeOrRootT, 1>
3406 {
3407  static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported");
3408  using Type = typename GridOrTreeOrRootT::RootNodeType::ChildNodeType::ChildNodeType;
3409  using type = typename GridOrTreeOrRootT::RootNodeType::ChildNodeType::ChildNodeType;
3410 };
3411 template<typename GridOrTreeOrRootT>
3412 struct NodeTrait<const GridOrTreeOrRootT, 1>
3413 {
3414  static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported");
3415  using Type = const typename GridOrTreeOrRootT::RootNodeType::ChildNodeType::ChildNodeType;
3416  using type = const typename GridOrTreeOrRootT::RootNodeType::ChildNodeType::ChildNodeType;
3417 };
3418 template<typename GridOrTreeOrRootT>
3419 struct NodeTrait<GridOrTreeOrRootT, 2>
3420 {
3421  static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported");
3422  using Type = typename GridOrTreeOrRootT::RootNodeType::ChildNodeType;
3423  using type = typename GridOrTreeOrRootT::RootNodeType::ChildNodeType;
3424 };
3425 template<typename GridOrTreeOrRootT>
3426 struct NodeTrait<const GridOrTreeOrRootT, 2>
3427 {
3428  static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported");
3429  using Type = const typename GridOrTreeOrRootT::RootNodeType::ChildNodeType;
3430  using type = const typename GridOrTreeOrRootT::RootNodeType::ChildNodeType;
3431 };
3432 template<typename GridOrTreeOrRootT>
3433 struct NodeTrait<GridOrTreeOrRootT, 3>
3434 {
3435  static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported");
3436  using Type = typename GridOrTreeOrRootT::RootNodeType;
3437  using type = typename GridOrTreeOrRootT::RootNodeType;
3438 };
3439 
3440 template<typename GridOrTreeOrRootT>
3441 struct NodeTrait<const GridOrTreeOrRootT, 3>
3442 {
3443  static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported");
3444  using Type = const typename GridOrTreeOrRootT::RootNodeType;
3445  using type = const typename GridOrTreeOrRootT::RootNodeType;
3446 };
3447 
3448 // ----------------------------> Froward decelerations of random access methods <--------------------------------------
3449 
3450 template<typename BuildT>
3451 struct GetValue;
3452 template<typename BuildT>
3453 struct SetValue;
3454 template<typename BuildT>
3455 struct SetVoxel;
3456 template<typename BuildT>
3457 struct GetState;
3458 template<typename BuildT>
3459 struct GetDim;
3460 template<typename BuildT>
3461 struct GetLeaf;
3462 template<typename BuildT>
3463 struct ProbeValue;
3464 template<typename BuildT>
3466 
3467 // ----------------------------> Grid <--------------------------------------
3468 
3469 /*
3470  The following class and comment is for internal use only
3471 
3472  Memory layout:
3473 
3474  Grid -> 39 x double (world bbox and affine transformation)
3475  Tree -> Root 3 x ValueType + int32_t + N x Tiles (background,min,max,tileCount + tileCount x Tiles)
3476 
3477  N2 upper InternalNodes each with 2 bit masks, N2 tiles, and min/max values
3478 
3479  N1 lower InternalNodes each with 2 bit masks, N1 tiles, and min/max values
3480 
3481  N0 LeafNodes each with a bit mask, N0 ValueTypes and min/max
3482 
3483  Example layout: ("---" implies it has a custom offset, "..." implies zero or more)
3484  [GridData][TreeData]---[RootData][ROOT TILES...]---[InternalData<5>]---[InternalData<4>]---[LeafData<3>]---[BLINDMETA...]---[BLIND0]---[BLIND1]---etc.
3485 */
3486 
3487 /// @brief Struct with all the member data of the Grid (useful during serialization of an openvdb grid)
3488 ///
3489 /// @note The transform is assumed to be affine (so linear) and have uniform scale! So frustum transforms
3490 /// and non-uniform scaling are not supported (primarily because they complicate ray-tracing in index space)
3491 ///
3492 /// @note No client code should (or can) interface with this struct so it can safely be ignored!
3493 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData
3494 { // sizeof(GridData) = 672B
3495  static const int MaxNameSize = 256; // due to NULL termination the maximum length is one less
3496  uint64_t mMagic; // 8B (0) magic to validate it is valid grid data.
3497  uint64_t mChecksum; // 8B (8). Checksum of grid buffer.
3498  Version mVersion; // 4B (16) major, minor, and patch version numbers
3499  BitFlags<32> mFlags; // 4B (20). flags for grid.
3500  uint32_t mGridIndex; // 4B (24). Index of this grid in the buffer
3501  uint32_t mGridCount; // 4B (28). Total number of grids in the buffer
3502  uint64_t mGridSize; // 8B (32). byte count of this entire grid occupied in the buffer.
3503  char mGridName[MaxNameSize]; // 256B (40)
3504  Map mMap; // 264B (296). affine transformation between index and world space in both single and double precision
3505  BBox<Vec3d> mWorldBBox; // 48B (560). floating-point AABB of active values in WORLD SPACE (2 x 3 doubles)
3506  Vec3d mVoxelSize; // 24B (608). size of a voxel in world units
3507  GridClass mGridClass; // 4B (632).
3508  GridType mGridType; // 4B (636).
3509  int64_t mBlindMetadataOffset; // 8B (640). offset to beginning of GridBlindMetaData structures that follow this grid.
3510  uint32_t mBlindMetadataCount; // 4B (648). count of GridBlindMetaData structures that follow this grid.
3511  uint32_t mData0; // 4B (652)
3512  uint64_t mData1, mData2; // 2x8B (656) padding to 32 B alignment. mData1 is use for the total number of values indexed by an IndexGrid
3513  /// @brief Use this method to initiate most member dat
3514  __hostdev__ GridData& operator=(const GridData& other)
3515  {
3516  static_assert(8 * 84 == sizeof(GridData), "GridData has unexpected size");
3517  memcpy64(this, &other, 84);
3518  return *this;
3519  }
3520  __hostdev__ void init(std::initializer_list<GridFlags> list = {GridFlags::IsBreadthFirst},
3521  uint64_t gridSize = 0u,
3522  const Map& map = Map(),
3523  GridType gridType = GridType::Unknown,
3524  GridClass gridClass = GridClass::Unknown)
3525  {
3526 #ifdef NANOVDB_USE_NEW_MAGIC_NUMBERS
3527  mMagic = NANOVDB_MAGIC_GRID;
3528 #else
3529  mMagic = NANOVDB_MAGIC_NUMBER;
3530 #endif
3531  mChecksum = ~uint64_t(0);// all 64 bits ON means checksum is disabled
3532  mVersion = Version();
3533  mFlags.initMask(list);
3534  mGridIndex = 0u;
3535  mGridCount = 1u;
3536  mGridSize = gridSize;
3537  mGridName[0] = '\0';
3538  mMap = map;
3539  mWorldBBox = BBox<Vec3d>();// invalid bbox
3540  mVoxelSize = map.getVoxelSize();
3541  mGridClass = gridClass;
3542  mGridType = gridType;
3543  mBlindMetadataOffset = mGridSize; // i.e. no blind data
3544  mBlindMetadataCount = 0u; // i.e. no blind data
3545  mData0 = 0u; // zero padding
3546  mData1 = 0u; // only used for index and point grids
3547  mData2 = NANOVDB_MAGIC_GRID; // since version 32.6.0 (might be removed in the future)
3548  }
3549  /// @brief return true if the magic number and the version are both valid
3550  __hostdev__ bool isValid() const {
3551  if (mMagic == NANOVDB_MAGIC_GRID || mData2 == NANOVDB_MAGIC_GRID) return true;
3552  bool test = mMagic == NANOVDB_MAGIC_NUMBER;// could be GridData or io::FileHeader
3553  if (test) test = mVersion.isCompatible();
3554  if (test) test = mGridCount > 0u && mGridIndex < mGridCount;
3555  if (test) test = mGridClass < GridClass::End && mGridType < GridType::End;
3556  return test;
3557  }
3558  // Set and unset various bit flags
3559  __hostdev__ void setMinMaxOn(bool on = true) { mFlags.setMask(GridFlags::HasMinMax, on); }
3560  __hostdev__ void setBBoxOn(bool on = true) { mFlags.setMask(GridFlags::HasBBox, on); }
3561  __hostdev__ void setLongGridNameOn(bool on = true) { mFlags.setMask(GridFlags::HasLongGridName, on); }
3562  __hostdev__ void setAverageOn(bool on = true) { mFlags.setMask(GridFlags::HasAverage, on); }
3563  __hostdev__ void setStdDeviationOn(bool on = true) { mFlags.setMask(GridFlags::HasStdDeviation, on); }
3564  __hostdev__ bool setGridName(const char* src)
3565  {
3566  char *dst = mGridName, *end = dst + MaxNameSize;
3567  while (*src != '\0' && dst < end - 1)
3568  *dst++ = *src++;
3569  while (dst < end)
3570  *dst++ = '\0';
3571  return *src == '\0'; // returns true if input grid name is NOT longer than MaxNameSize characters
3572  }
3573  // Affine transformations based on double precision
3574  template<typename Vec3T>
3575  __hostdev__ Vec3T applyMap(const Vec3T& xyz) const { return mMap.applyMap(xyz); } // Pos: index -> world
3576  template<typename Vec3T>
3577  __hostdev__ Vec3T applyInverseMap(const Vec3T& xyz) const { return mMap.applyInverseMap(xyz); } // Pos: world -> index
3578  template<typename Vec3T>
3579  __hostdev__ Vec3T applyJacobian(const Vec3T& xyz) const { return mMap.applyJacobian(xyz); } // Dir: index -> world
3580  template<typename Vec3T>
3581  __hostdev__ Vec3T applyInverseJacobian(const Vec3T& xyz) const { return mMap.applyInverseJacobian(xyz); } // Dir: world -> index
3582  template<typename Vec3T>
3583  __hostdev__ Vec3T applyIJT(const Vec3T& xyz) const { return mMap.applyIJT(xyz); }
3584  // Affine transformations based on single precision
3585  template<typename Vec3T>
3586  __hostdev__ Vec3T applyMapF(const Vec3T& xyz) const { return mMap.applyMapF(xyz); } // Pos: index -> world
3587  template<typename Vec3T>
3588  __hostdev__ Vec3T applyInverseMapF(const Vec3T& xyz) const { return mMap.applyInverseMapF(xyz); } // Pos: world -> index
3589  template<typename Vec3T>
3590  __hostdev__ Vec3T applyJacobianF(const Vec3T& xyz) const { return mMap.applyJacobianF(xyz); } // Dir: index -> world
3591  template<typename Vec3T>
3592  __hostdev__ Vec3T applyInverseJacobianF(const Vec3T& xyz) const { return mMap.applyInverseJacobianF(xyz); } // Dir: world -> index
3593  template<typename Vec3T>
3594  __hostdev__ Vec3T applyIJTF(const Vec3T& xyz) const { return mMap.applyIJTF(xyz); }
3595 
3596  // @brief Return a non-const uint8_t pointer to the tree
3597  __hostdev__ uint8_t* treePtr() { return reinterpret_cast<uint8_t*>(this + 1); }// TreeData is always right after GridData
3598  //__hostdev__ TreeData* treePtr() { return reinterpret_cast<TreeData*>(this + 1); }// TreeData is always right after GridData
3599 
3600  // @brief Return a const uint8_t pointer to the tree
3601  __hostdev__ const uint8_t* treePtr() const { return reinterpret_cast<const uint8_t*>(this + 1); }// TreeData is always right after GridData
3602  //__hostdev__ const TreeData* treePtr() const { return reinterpret_cast<const TreeData*>(this + 1); }// TreeData is always right after GridData
3603 
3604  /// @brief Return a non-const uint8_t pointer to the first node at @c LEVEL
3605  /// @tparam LEVEL of the node. LEVEL 0 means leaf node and LEVEL 3 means root node
3606  /// @warning If not nodes exist at @c LEVEL NULL is returned
3607  template <uint32_t LEVEL>
3608  __hostdev__ const uint8_t* nodePtr() const
3609  {
3610  static_assert(LEVEL >= 0 && LEVEL <= 3, "invalid LEVEL template parameter");
3611  auto *treeData = this->treePtr();
3612  auto nodeOffset = *reinterpret_cast<const uint64_t*>(treeData + 8*LEVEL);// skip LEVEL uint64_t
3613  return nodeOffset ? PtrAdd<uint8_t>(treeData, nodeOffset) : nullptr;
3614  }
3615 
3616  /// @brief Return a non-const uint8_t pointer to the first node at @c LEVEL
3617  /// @tparam LEVEL of the node. LEVEL 0 means leaf node and LEVEL 3 means root node
3618  /// @warning If not nodes exist at @c LEVEL NULL is returned
3619  template <uint32_t LEVEL>
3620  __hostdev__ uint8_t* nodePtr(){return const_cast<uint8_t*>(const_cast<const GridData*>(this)->template nodePtr<LEVEL>());}
3621 
3622  /// @brief Returns a const reference to the blindMetaData at the specified linear offset.
3623  ///
3624  /// @warning The linear offset is assumed to be in the valid range
3625  __hostdev__ const GridBlindMetaData* blindMetaData(uint32_t n) const
3626  {
3627  NANOVDB_ASSERT(n < mBlindMetadataCount);
3628  return PtrAdd<GridBlindMetaData>(this, mBlindMetadataOffset) + n;
3629  }
3630 
3631  __hostdev__ const char* gridName() const
3632  {
3633  if (mFlags.isMaskOn(GridFlags::HasLongGridName)) {// search for first blind meta data that contains a name
3634  NANOVDB_ASSERT(mBlindMetadataCount > 0);
3635  for (uint32_t i = 0; i < mBlindMetadataCount; ++i) {
3636  const auto* metaData = this->blindMetaData(i);// EXTREMELY important to be a pointer
3637  if (metaData->mDataClass == GridBlindDataClass::GridName) {
3638  NANOVDB_ASSERT(metaData->mDataType == GridType::Unknown);
3639  return metaData->template getBlindData<const char>();
3640  }
3641  }
3642  NANOVDB_ASSERT(false); // should never hit this!
3643  }
3644  return mGridName;
3645  }
3646 
3647  /// @brief Return memory usage in bytes for this class only.
3648  __hostdev__ static uint64_t memUsage() { return sizeof(GridData); }
3649 
3650  /// @brief return AABB of active values in world space
3651  __hostdev__ const BBox<Vec3d>& worldBBox() const { return mWorldBBox; }
3652 
3653  /// @brief return AABB of active values in index space
3654  __hostdev__ const CoordBBox& indexBBox() const {return *(const CoordBBox*)(this->nodePtr<3>());}
3655 
3656  /// @brief return the root table has size
3657  __hostdev__ uint32_t rootTableSize() const {
3658  if (const uint8_t *root = this->nodePtr<3>()) {
3659  return *(const uint32_t*)(root + sizeof(CoordBBox));
3660  }
3661  return 0u;
3662  }
3663 
3664  /// @brief test if the grid is empty, e.i the root table has size 0
3665  /// @return true if this grid contains not data whatsoever
3666  __hostdev__ bool isEmpty() const {return this->rootTableSize() == 0u;}
3667 
3668  /// @brief return true if RootData follows TreeData in memory without any extra padding
3669  /// @details TreeData is always following right after GridData, but the same might not be true for RootData
3670  __hostdev__ bool isRootConnected() const { return *(const uint64_t*)((const char*)(this + 1) + 24) == 64u;}
3671 }; // GridData
3672 
3673 // Forward declaration of accelerated random access class
3674 template<typename BuildT, int LEVEL0 = -1, int LEVEL1 = -1, int LEVEL2 = -1>
3676 
3677 template<typename BuildT>
3679 
3680 /// @brief Highest level of the data structure. Contains a tree and a world->index
3681 /// transform (that currently only supports uniform scaling and translation).
3682 ///
3683 /// @note This the API of this class to interface with client code
3684 template<typename TreeT>
3685 class Grid : public GridData
3686 {
3687 public:
3688  using TreeType = TreeT;
3689  using RootType = typename TreeT::RootType;
3691  using UpperNodeType = typename RootNodeType::ChildNodeType;
3692  using LowerNodeType = typename UpperNodeType::ChildNodeType;
3693  using LeafNodeType = typename RootType::LeafNodeType;
3694  using DataType = GridData;
3695  using ValueType = typename TreeT::ValueType;
3696  using BuildType = typename TreeT::BuildType; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool
3697  using CoordType = typename TreeT::CoordType;
3699 
3700  /// @brief Disallow constructions, copy and assignment
3701  ///
3702  /// @note Only a Serializer, defined elsewhere, can instantiate this class
3703  Grid(const Grid&) = delete;
3704  Grid& operator=(const Grid&) = delete;
3705  ~Grid() = delete;
3706 
3707  __hostdev__ Version version() const { return DataType::mVersion; }
3708 
3709  __hostdev__ DataType* data() { return reinterpret_cast<DataType*>(this); }
3710 
3711  __hostdev__ const DataType* data() const { return reinterpret_cast<const DataType*>(this); }
3712 
3713  /// @brief Return memory usage in bytes for this class only.
3714  //__hostdev__ static uint64_t memUsage() { return sizeof(GridData); }
3715 
3716  /// @brief Return the memory footprint of the entire grid, i.e. including all nodes and blind data
3717  __hostdev__ uint64_t gridSize() const { return DataType::mGridSize; }
3718 
3719  /// @brief Return index of this grid in the buffer
3720  __hostdev__ uint32_t gridIndex() const { return DataType::mGridIndex; }
3721 
3722  /// @brief Return total number of grids in the buffer
3723  __hostdev__ uint32_t gridCount() const { return DataType::mGridCount; }
3724 
3725  /// @brief @brief Return the total number of values indexed by this IndexGrid
3726  ///
3727  /// @note This method is only defined for IndexGrid = NanoGrid<ValueIndex || ValueOnIndex || ValueIndexMask || ValueOnIndexMask>
3728  template<typename T = BuildType>
3729  __hostdev__ typename enable_if<BuildTraits<T>::is_index, const uint64_t&>::type
3730  valueCount() const { return DataType::mData1; }
3731 
3732  /// @brief @brief Return the total number of points indexed by this PointGrid
3733  ///
3734  /// @note This method is only defined for PointGrid = NanoGrid<Point>
3735  template<typename T = BuildType>
3736  __hostdev__ typename enable_if<is_same<T, Point>::value, const uint64_t&>::type
3737  pointCount() const { return DataType::mData1; }
3738 
3739  /// @brief Return a const reference to the tree
3740  __hostdev__ const TreeT& tree() const { return *reinterpret_cast<const TreeT*>(this->treePtr()); }
3741 
3742  /// @brief Return a non-const reference to the tree
3743  __hostdev__ TreeT& tree() { return *reinterpret_cast<TreeT*>(this->treePtr()); }
3744 
3745  /// @brief Return a new instance of a ReadAccessor used to access values in this grid
3746  __hostdev__ AccessorType getAccessor() const { return AccessorType(this->tree().root()); }
3747 
3748  /// @brief Return a const reference to the size of a voxel in world units
3749  __hostdev__ const Vec3d& voxelSize() const { return DataType::mVoxelSize; }
3750 
3751  /// @brief Return a const reference to the Map for this grid
3752  __hostdev__ const Map& map() const { return DataType::mMap; }
3753 
3754  /// @brief world to index space transformation
3755  template<typename Vec3T>
3756  __hostdev__ Vec3T worldToIndex(const Vec3T& xyz) const { return this->applyInverseMap(xyz); }
3757 
3758  /// @brief index to world space transformation
3759  template<typename Vec3T>
3760  __hostdev__ Vec3T indexToWorld(const Vec3T& xyz) const { return this->applyMap(xyz); }
3761 
3762  /// @brief transformation from index space direction to world space direction
3763  /// @warning assumes dir to be normalized
3764  template<typename Vec3T>
3765  __hostdev__ Vec3T indexToWorldDir(const Vec3T& dir) const { return this->applyJacobian(dir); }
3766 
3767  /// @brief transformation from world space direction to index space direction
3768  /// @warning assumes dir to be normalized
3769  template<typename Vec3T>
3770  __hostdev__ Vec3T worldToIndexDir(const Vec3T& dir) const { return this->applyInverseJacobian(dir); }
3771 
3772  /// @brief transform the gradient from index space to world space.
3773  /// @details Applies the inverse jacobian transform map.
3774  template<typename Vec3T>
3775  __hostdev__ Vec3T indexToWorldGrad(const Vec3T& grad) const { return this->applyIJT(grad); }
3776 
3777  /// @brief world to index space transformation
3778  template<typename Vec3T>
3779  __hostdev__ Vec3T worldToIndexF(const Vec3T& xyz) const { return this->applyInverseMapF(xyz); }
3780 
3781  /// @brief index to world space transformation
3782  template<typename Vec3T>
3783  __hostdev__ Vec3T indexToWorldF(const Vec3T& xyz) const { return this->applyMapF(xyz); }
3784 
3785  /// @brief transformation from index space direction to world space direction
3786  /// @warning assumes dir to be normalized
3787  template<typename Vec3T>
3788  __hostdev__ Vec3T indexToWorldDirF(const Vec3T& dir) const { return this->applyJacobianF(dir); }
3789 
3790  /// @brief transformation from world space direction to index space direction
3791  /// @warning assumes dir to be normalized
3792  template<typename Vec3T>
3793  __hostdev__ Vec3T worldToIndexDirF(const Vec3T& dir) const { return this->applyInverseJacobianF(dir); }
3794 
3795  /// @brief Transforms the gradient from index space to world space.
3796  /// @details Applies the inverse jacobian transform map.
3797  template<typename Vec3T>
3798  __hostdev__ Vec3T indexToWorldGradF(const Vec3T& grad) const { return DataType::applyIJTF(grad); }
3799 
3800  /// @brief Computes a AABB of active values in world space
3801  //__hostdev__ const BBox<Vec3d>& worldBBox() const { return DataType::mWorldBBox; }
3802 
3803  /// @brief Computes a AABB of active values in index space
3804  ///
3805  /// @note This method is returning a floating point bounding box and not a CoordBBox. This makes
3806  /// it more useful for clipping rays.
3807  //__hostdev__ const BBox<CoordType>& indexBBox() const { return this->tree().bbox(); }
3808 
3809  /// @brief Return the total number of active voxels in this tree.
3810  __hostdev__ uint64_t activeVoxelCount() const { return this->tree().activeVoxelCount(); }
3811 
3812  /// @brief Methods related to the classification of this grid
3813  __hostdev__ bool isValid() const { return DataType::isValid(); }
3814  __hostdev__ const GridType& gridType() const { return DataType::mGridType; }
3815  __hostdev__ const GridClass& gridClass() const { return DataType::mGridClass; }
3816  __hostdev__ bool isLevelSet() const { return DataType::mGridClass == GridClass::LevelSet; }
3817  __hostdev__ bool isFogVolume() const { return DataType::mGridClass == GridClass::FogVolume; }
3818  __hostdev__ bool isStaggered() const { return DataType::mGridClass == GridClass::Staggered; }
3819  __hostdev__ bool isPointIndex() const { return DataType::mGridClass == GridClass::PointIndex; }
3820  __hostdev__ bool isGridIndex() const { return DataType::mGridClass == GridClass::IndexGrid; }
3821  __hostdev__ bool isPointData() const { return DataType::mGridClass == GridClass::PointData; }
3822  __hostdev__ bool isMask() const { return DataType::mGridClass == GridClass::Topology; }
3823  __hostdev__ bool isUnknown() const { return DataType::mGridClass == GridClass::Unknown; }
3824  __hostdev__ bool hasMinMax() const { return DataType::mFlags.isMaskOn(GridFlags::HasMinMax); }
3825  __hostdev__ bool hasBBox() const { return DataType::mFlags.isMaskOn(GridFlags::HasBBox); }
3830 
3831  /// @brief return true if the specified node type is layed out breadth-first in memory and has a fixed size.
3832  /// This allows for sequential access to the nodes.
3833  template<typename NodeT>
3834  __hostdev__ bool isSequential() const { return NodeT::FIXED_SIZE && this->isBreadthFirst(); }
3835 
3836  /// @brief return true if the specified node level is layed out breadth-first in memory and has a fixed size.
3837  /// This allows for sequential access to the nodes.
3838  template<int LEVEL>
3839  __hostdev__ bool isSequential() const { return NodeTrait<TreeT, LEVEL>::type::FIXED_SIZE && this->isBreadthFirst(); }
3840 
3841  /// @brief return true if nodes at all levels can safely be accessed with simple linear offsets
3842  __hostdev__ bool isSequential() const { return UpperNodeType::FIXED_SIZE && LowerNodeType::FIXED_SIZE && LeafNodeType::FIXED_SIZE && this->isBreadthFirst(); }
3843 
3844  /// @brief Return a c-string with the name of this grid
3845  __hostdev__ const char* gridName() const { return DataType::gridName(); }
3846 
3847  /// @brief Return a c-string with the name of this grid, truncated to 255 characters
3848  __hostdev__ const char* shortGridName() const { return DataType::mGridName; }
3849 
3850  /// @brief Return checksum of the grid buffer.
3851  __hostdev__ uint64_t checksum() const { return DataType::mChecksum; }
3852 
3853  /// @brief Return true if this grid is empty, i.e. contains no values or nodes.
3854  //__hostdev__ bool isEmpty() const { return this->tree().isEmpty(); }
3855 
3856  /// @brief Return the count of blind-data encoded in this grid
3857  __hostdev__ uint32_t blindDataCount() const { return DataType::mBlindMetadataCount; }
3858 
3859  /// @brief Return the index of the first blind data with specified name if found, otherwise -1.
3860  __hostdev__ int findBlindData(const char* name) const;
3861 
3862  /// @brief Return the index of the first blind data with specified semantic if found, otherwise -1.
3863  __hostdev__ int findBlindDataForSemantic(GridBlindDataSemantic semantic) const;
3864 
3865  /// @brief Returns a const pointer to the blindData at the specified linear offset.
3866  ///
3867  /// @warning Pointer might be NULL and the linear offset is assumed to be in the valid range
3868  // this method is deprecated !!!!
3869  __hostdev__ const void* blindData(uint32_t n) const
3870  {
3871  printf("\nnanovdb::Grid::blindData is unsafe and hence deprecated! Please use nanovdb::Grid::getBlindData instead.\n\n");
3872  NANOVDB_ASSERT(n < DataType::mBlindMetadataCount);
3873  return this->blindMetaData(n).blindData();
3874  }
3875 
3876  template <typename BlindDataT>
3877  __hostdev__ const BlindDataT* getBlindData(uint32_t n) const
3878  {
3879  if (n >= DataType::mBlindMetadataCount) return nullptr;// index is out of bounds
3880  return this->blindMetaData(n).template getBlindData<BlindDataT>();// NULL if mismatching BlindDataT
3881  }
3882 
3883  template <typename BlindDataT>
3884  __hostdev__ BlindDataT* getBlindData(uint32_t n)
3885  {
3886  if (n >= DataType::mBlindMetadataCount) return nullptr;// index is out of bounds
3887  return const_cast<BlindDataT*>(this->blindMetaData(n).template getBlindData<BlindDataT>());// NULL if mismatching BlindDataT
3888  }
3889 
3890  __hostdev__ const GridBlindMetaData& blindMetaData(uint32_t n) const { return *DataType::blindMetaData(n); }
3891 
3892 private:
3893  static_assert(sizeof(GridData) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(GridData) is misaligned");
3894 }; // Class Grid
3895 
3896 template<typename TreeT>
3898 {
3899  for (uint32_t i = 0, n = this->blindDataCount(); i < n; ++i) {
3900  if (this->blindMetaData(i).mSemantic == semantic)
3901  return int(i);
3902  }
3903  return -1;
3904 }
3905 
3906 template<typename TreeT>
3908 {
3909  auto test = [&](int n) {
3910  const char* str = this->blindMetaData(n).mName;
3911  for (int i = 0; i < GridBlindMetaData::MaxNameSize; ++i) {
3912  if (name[i] != str[i])
3913  return false;
3914  if (name[i] == '\0' && str[i] == '\0')
3915  return true;
3916  }
3917  return true; // all len characters matched
3918  };
3919  for (int i = 0, n = this->blindDataCount(); i < n; ++i)
3920  if (test(i))
3921  return i;
3922  return -1;
3923 }
3924 
3925 // ----------------------------> Tree <--------------------------------------
3926 
3927 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) TreeData
3928 { // sizeof(TreeData) == 64B
3929  int64_t mNodeOffset[4];// 32B, byte offset from this tree to first leaf, lower, upper and root node. A zero offset means no node exists
3930  uint32_t mNodeCount[3]; // 12B, total number of nodes of type: leaf, lower internal, upper internal
3931  uint32_t mTileCount[3]; // 12B, total number of active tile values at the lower internal, upper internal and root node levels
3932  uint64_t mVoxelCount; // 8B, total number of active voxels in the root and all its child nodes.
3933  // No padding since it's always 32B aligned
3934  __hostdev__ TreeData& operator=(const TreeData& other)
3935  {
3936  static_assert(8 * 8 == sizeof(TreeData), "TreeData has unexpected size");
3937  memcpy64(this, &other, 8);
3938  return *this;
3939  }
3940  __hostdev__ void setRoot(const void* root) {mNodeOffset[3] = root ? PtrDiff(root, this) : 0;}
3941  __hostdev__ uint8_t* getRoot() { return mNodeOffset[3] ? PtrAdd<uint8_t>(this, mNodeOffset[3]) : nullptr; }
3942  __hostdev__ const uint8_t* getRoot() const { return mNodeOffset[3] ? PtrAdd<uint8_t>(this, mNodeOffset[3]) : nullptr; }
3943 
3944  template<typename NodeT>
3945  __hostdev__ void setFirstNode(const NodeT* node) {mNodeOffset[NodeT::LEVEL] = node ? PtrDiff(node, this) : 0;}
3946 
3947  __hostdev__ bool isEmpty() const {return mNodeOffset[3] ? *PtrAdd<uint32_t>(this, mNodeOffset[3] + sizeof(BBox<Coord>)) == 0 : true;}
3948 
3949  /// @brief Return the index bounding box of all the active values in this tree, i.e. in all nodes of the tree
3950  __hostdev__ CoordBBox bbox() const {return mNodeOffset[3] ? *PtrAdd<CoordBBox>(this, mNodeOffset[3]) : CoordBBox();}
3951 
3952  /// @brief return true if RootData is layout out immediately after TreeData in memory
3953  __hostdev__ bool isRootNext() const {return mNodeOffset[3] ? mNodeOffset[3] == sizeof(TreeData) : false; }
3954 };// TreeData
3955 
3956 // ----------------------------> GridTree <--------------------------------------
3957 
3958 /// @brief defines a tree type from a grid type while preserving constness
3959 template<typename GridT>
3960 struct GridTree
3961 {
3962  using Type = typename GridT::TreeType;
3963  using type = typename GridT::TreeType;
3964 };
3965 template<typename GridT>
3966 struct GridTree<const GridT>
3967 {
3968  using Type = const typename GridT::TreeType;
3969  using type = const typename GridT::TreeType;
3970 };
3971 
3972 // ----------------------------> Tree <--------------------------------------
3973 
3974 /// @brief VDB Tree, which is a thin wrapper around a RootNode.
3975 template<typename RootT>
3976 class Tree : public TreeData
3977 {
3978  static_assert(RootT::LEVEL == 3, "Tree depth is not supported");
3979  static_assert(RootT::ChildNodeType::LOG2DIM == 5, "Tree configuration is not supported");
3980  static_assert(RootT::ChildNodeType::ChildNodeType::LOG2DIM == 4, "Tree configuration is not supported");
3981  static_assert(RootT::LeafNodeType::LOG2DIM == 3, "Tree configuration is not supported");
3982 
3983 public:
3984  using DataType = TreeData;
3985  using RootType = RootT;
3986  using RootNodeType = RootT;
3987  using UpperNodeType = typename RootNodeType::ChildNodeType;
3988  using LowerNodeType = typename UpperNodeType::ChildNodeType;
3989  using LeafNodeType = typename RootType::LeafNodeType;
3990  using ValueType = typename RootT::ValueType;
3991  using BuildType = typename RootT::BuildType; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool
3992  using CoordType = typename RootT::CoordType;
3994 
3995  using Node3 = RootT;
3996  using Node2 = typename RootT::ChildNodeType;
3997  using Node1 = typename Node2::ChildNodeType;
3999 
4000  /// @brief This class cannot be constructed or deleted
4001  Tree() = delete;
4002  Tree(const Tree&) = delete;
4003  Tree& operator=(const Tree&) = delete;
4004  ~Tree() = delete;
4005 
4006  __hostdev__ DataType* data() { return reinterpret_cast<DataType*>(this); }
4007 
4008  __hostdev__ const DataType* data() const { return reinterpret_cast<const DataType*>(this); }
4009 
4010  /// @brief return memory usage in bytes for the class
4011  __hostdev__ static uint64_t memUsage() { return sizeof(DataType); }
4012 
4014  {
4015  RootT* ptr = reinterpret_cast<RootT*>(DataType::getRoot());
4016  NANOVDB_ASSERT(ptr);
4017  return *ptr;
4018  }
4019 
4020  __hostdev__ const RootT& root() const
4021  {
4022  const RootT* ptr = reinterpret_cast<const RootT*>(DataType::getRoot());
4023  NANOVDB_ASSERT(ptr);
4024  return *ptr;
4025  }
4026 
4027  __hostdev__ AccessorType getAccessor() const { return AccessorType(this->root()); }
4028 
4029  /// @brief Return the value of the given voxel (regardless of state or location in the tree.)
4030  __hostdev__ ValueType getValue(const CoordType& ijk) const { return this->root().getValue(ijk); }
4031  __hostdev__ ValueType getValue(int i, int j, int k) const { return this->root().getValue(CoordType(i, j, k)); }
4032 
4033  /// @brief Return the active state of the given voxel (regardless of state or location in the tree.)
4034  __hostdev__ bool isActive(const CoordType& ijk) const { return this->root().isActive(ijk); }
4035 
4036  /// @brief Return true if this tree is empty, i.e. contains no values or nodes
4037  //__hostdev__ bool isEmpty() const { return this->root().isEmpty(); }
4038 
4039  /// @brief Combines the previous two methods in a single call
4040  __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->root().probeValue(ijk, v); }
4041 
4042  /// @brief Return a const reference to the background value.
4043  __hostdev__ const ValueType& background() const { return this->root().background(); }
4044 
4045  /// @brief Sets the extrema values of all the active values in this tree, i.e. in all nodes of the tree
4046  __hostdev__ void extrema(ValueType& min, ValueType& max) const;
4047 
4048  /// @brief Return a const reference to the index bounding box of all the active values in this tree, i.e. in all nodes of the tree
4049  //__hostdev__ const BBox<CoordType>& bbox() const { return this->root().bbox(); }
4050 
4051  /// @brief Return the total number of active voxels in this tree.
4052  __hostdev__ uint64_t activeVoxelCount() const { return DataType::mVoxelCount; }
4053 
4054  /// @brief Return the total number of active tiles at the specified level of the tree.
4055  ///
4056  /// @details level = 1,2,3 corresponds to active tile count in lower internal nodes, upper
4057  /// internal nodes, and the root level. Note active values at the leaf level are
4058  /// referred to as active voxels (see activeVoxelCount defined above).
4059  __hostdev__ const uint32_t& activeTileCount(uint32_t level) const
4060  {
4061  NANOVDB_ASSERT(level > 0 && level <= 3); // 1, 2, or 3
4062  return DataType::mTileCount[level - 1];
4063  }
4064 
4065  template<typename NodeT>
4066  __hostdev__ uint32_t nodeCount() const
4067  {
4068  static_assert(NodeT::LEVEL < 3, "Invalid NodeT");
4069  return DataType::mNodeCount[NodeT::LEVEL];
4070  }
4071 
4072  __hostdev__ uint32_t nodeCount(int level) const
4073  {
4074  NANOVDB_ASSERT(level < 3);
4075  return DataType::mNodeCount[level];
4076  }
4077 
4078  __hostdev__ uint32_t totalNodeCount() const
4079  {
4080  return DataType::mNodeCount[0] + DataType::mNodeCount[1] + DataType::mNodeCount[2];
4081  }
4082 
4083  /// @brief return a pointer to the first node of the specified type
4084  ///
4085  /// @warning Note it may return NULL if no nodes exist
4086  template<typename NodeT>
4088  {
4089  const int64_t offset = DataType::mNodeOffset[NodeT::LEVEL];
4090  return offset ? PtrAdd<NodeT>(this, offset) : nullptr;
4091  }
4092 
4093  /// @brief return a const pointer to the first node of the specified type
4094  ///
4095  /// @warning Note it may return NULL if no nodes exist
4096  template<typename NodeT>
4097  __hostdev__ const NodeT* getFirstNode() const
4098  {
4099  const int64_t offset = DataType::mNodeOffset[NodeT::LEVEL];
4100  return offset ? PtrAdd<NodeT>(this, offset) : nullptr;
4101  }
4102 
4103  /// @brief return a pointer to the first node at the specified level
4104  ///
4105  /// @warning Note it may return NULL if no nodes exist
4106  template<int LEVEL>
4109  {
4110  return this->template getFirstNode<typename NodeTrait<RootT, LEVEL>::type>();
4111  }
4112 
4113  /// @brief return a const pointer to the first node of the specified level
4114  ///
4115  /// @warning Note it may return NULL if no nodes exist
4116  template<int LEVEL>
4119  {
4120  return this->template getFirstNode<typename NodeTrait<RootT, LEVEL>::type>();
4121  }
4122 
4123  /// @brief Template specializations of getFirstNode
4124  __hostdev__ LeafNodeType* getFirstLeaf() { return this->getFirstNode<LeafNodeType>(); }
4125  __hostdev__ const LeafNodeType* getFirstLeaf() const { return this->getFirstNode<LeafNodeType>(); }
4126  __hostdev__ typename NodeTrait<RootT, 1>::type* getFirstLower() { return this->getFirstNode<1>(); }
4127  __hostdev__ const typename NodeTrait<RootT, 1>::type* getFirstLower() const { return this->getFirstNode<1>(); }
4128  __hostdev__ typename NodeTrait<RootT, 2>::type* getFirstUpper() { return this->getFirstNode<2>(); }
4129  __hostdev__ const typename NodeTrait<RootT, 2>::type* getFirstUpper() const { return this->getFirstNode<2>(); }
4130 
4131  template<typename OpT, typename... ArgsT>
4132  __hostdev__ auto get(const CoordType& ijk, ArgsT&&... args) const
4133  {
4134  return this->root().template get<OpT>(ijk, args...);
4135  }
4136 
4137  template<typename OpT, typename... ArgsT>
4138  __hostdev__ auto set(const CoordType& ijk, ArgsT&&... args)
4139  {
4140  return this->root().template set<OpT>(ijk, args...);
4141  }
4142 
4143 private:
4144  static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(TreeData) is misaligned");
4145 
4146 }; // Tree class
4147 
4148 template<typename RootT>
4150 {
4151  min = this->root().minimum();
4152  max = this->root().maximum();
4153 }
4154 
4155 // --------------------------> RootData <------------------------------------
4156 
4157 /// @brief Struct with all the member data of the RootNode (useful during serialization of an openvdb RootNode)
4158 ///
4159 /// @note No client code should (or can) interface with this struct so it can safely be ignored!
4160 template<typename ChildT>
4161 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) RootData
4162 {
4163  using ValueT = typename ChildT::ValueType;
4164  using BuildT = typename ChildT::BuildType; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool
4165  using CoordT = typename ChildT::CoordType;
4166  using StatsT = typename ChildT::FloatType;
4167  static constexpr bool FIXED_SIZE = false;
4168 
4169  /// @brief Return a key based on the coordinates of a voxel
4170 #ifdef NANOVDB_USE_SINGLE_ROOT_KEY
4171  using KeyT = uint64_t;
4172  template<typename CoordType>
4173  __hostdev__ static KeyT CoordToKey(const CoordType& ijk)
4174  {
4175  static_assert(sizeof(CoordT) == sizeof(CoordType), "Mismatching sizeof");
4176  static_assert(32 - ChildT::TOTAL <= 21, "Cannot use 64 bit root keys");
4177  return (KeyT(uint32_t(ijk[2]) >> ChildT::TOTAL)) | // z is the lower 21 bits
4178  (KeyT(uint32_t(ijk[1]) >> ChildT::TOTAL) << 21) | // y is the middle 21 bits
4179  (KeyT(uint32_t(ijk[0]) >> ChildT::TOTAL) << 42); // x is the upper 21 bits
4180  }
4181  __hostdev__ static CoordT KeyToCoord(const KeyT& key)
4182  {
4183  static constexpr uint64_t MASK = (1u << 21) - 1; // used to mask out 21 lower bits
4184  return CoordT(((key >> 42) & MASK) << ChildT::TOTAL, // x are the upper 21 bits
4185  ((key >> 21) & MASK) << ChildT::TOTAL, // y are the middle 21 bits
4186  (key & MASK) << ChildT::TOTAL); // z are the lower 21 bits
4187  }
4188 #else
4189  using KeyT = CoordT;
4190  __hostdev__ static KeyT CoordToKey(const CoordT& ijk) { return ijk & ~ChildT::MASK; }
4191  __hostdev__ static CoordT KeyToCoord(const KeyT& key) { return key; }
4192 #endif
4193  BBox<CoordT> mBBox; // 24B. AABB of active values in index space.
4194  uint32_t mTableSize; // 4B. number of tiles and child pointers in the root node
4195 
4196  ValueT mBackground; // background value, i.e. value of any unset voxel
4197  ValueT mMinimum; // typically 4B, minimum of all the active values
4198  ValueT mMaximum; // typically 4B, maximum of all the active values
4199  StatsT mAverage; // typically 4B, average of all the active values in this node and its child nodes
4200  StatsT mStdDevi; // typically 4B, standard deviation of all the active values in this node and its child nodes
4201 
4202  /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment
4203  ///
4204  /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members.
4205  __hostdev__ static constexpr uint32_t padding()
4206  {
4207  return sizeof(RootData) - (24 + 4 + 3 * sizeof(ValueT) + 2 * sizeof(StatsT));
4208  }
4209 
4210  struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) Tile
4211  {
4212  template<typename CoordType>
4213  __hostdev__ void setChild(const CoordType& k, const void* ptr, const RootData* data)
4214  {
4215  key = CoordToKey(k);
4216  state = false;
4217  child = PtrDiff(ptr, data);
4218  }
4219  template<typename CoordType, typename ValueType>
4220  __hostdev__ void setValue(const CoordType& k, bool s, const ValueType& v)
4221  {
4222  key = CoordToKey(k);
4223  state = s;
4224  value = v;
4225  child = 0;
4226  }
4227  __hostdev__ bool isChild() const { return child != 0; }
4228  __hostdev__ bool isValue() const { return child == 0; }
4229  __hostdev__ bool isActive() const { return child == 0 && state; }
4230  __hostdev__ CoordT origin() const { return KeyToCoord(key); }
4231  KeyT key; // NANOVDB_USE_SINGLE_ROOT_KEY ? 8B : 12B
4232  int64_t child; // 8B. signed byte offset from this node to the child node. 0 means it is a constant tile, so use value.
4233  uint32_t state; // 4B. state of tile value
4234  ValueT value; // value of tile (i.e. no child node)
4235  }; // Tile
4236 
4237  /// @brief Returns a non-const reference to the tile at the specified linear offset.
4238  ///
4239  /// @warning The linear offset is assumed to be in the valid range
4240  __hostdev__ const Tile* tile(uint32_t n) const
4241  {
4242  NANOVDB_ASSERT(n < mTableSize);
4243  return reinterpret_cast<const Tile*>(this + 1) + n;
4244  }
4245  __hostdev__ Tile* tile(uint32_t n)
4246  {
4247  NANOVDB_ASSERT(n < mTableSize);
4248  return reinterpret_cast<Tile*>(this + 1) + n;
4249  }
4250 
4251  __hostdev__ Tile* probeTile(const CoordT& ijk)
4252  {
4253 #if 1 // switch between linear and binary seach
4254  const auto key = CoordToKey(ijk);
4255  for (Tile *p = reinterpret_cast<Tile*>(this + 1), *q = p + mTableSize; p < q; ++p)
4256  if (p->key == key)
4257  return p;
4258  return nullptr;
4259 #else // do not enable binary search if tiles are not guaranteed to be sorted!!!!!!
4260  int32_t low = 0, high = mTableSize; // low is inclusive and high is exclusive
4261  while (low != high) {
4262  int mid = low + ((high - low) >> 1);
4263  const Tile* tile = &tiles[mid];
4264  if (tile->key == key) {
4265  return tile;
4266  } else if (tile->key < key) {
4267  low = mid + 1;
4268  } else {
4269  high = mid;
4270  }
4271  }
4272  return nullptr;
4273 #endif
4274  }
4275 
4276  __hostdev__ inline const Tile* probeTile(const CoordT& ijk) const
4277  {
4278  return const_cast<RootData*>(this)->probeTile(ijk);
4279  }
4280 
4281  /// @brief Returns a const reference to the child node in the specified tile.
4282  ///
4283  /// @warning A child node is assumed to exist in the specified tile
4284  __hostdev__ ChildT* getChild(const Tile* tile)
4285  {
4286  NANOVDB_ASSERT(tile->child);
4287  return PtrAdd<ChildT>(this, tile->child);
4288  }
4289  __hostdev__ const ChildT* getChild(const Tile* tile) const
4290  {
4291  NANOVDB_ASSERT(tile->child);
4292  return PtrAdd<ChildT>(this, tile->child);
4293  }
4294 
4295  __hostdev__ const ValueT& getMin() const { return mMinimum; }
4296  __hostdev__ const ValueT& getMax() const { return mMaximum; }
4297  __hostdev__ const StatsT& average() const { return mAverage; }
4298  __hostdev__ const StatsT& stdDeviation() const { return mStdDevi; }
4299 
4300  __hostdev__ void setMin(const ValueT& v) { mMinimum = v; }
4301  __hostdev__ void setMax(const ValueT& v) { mMaximum = v; }
4302  __hostdev__ void setAvg(const StatsT& v) { mAverage = v; }
4303  __hostdev__ void setDev(const StatsT& v) { mStdDevi = v; }
4304 
4305  /// @brief This class cannot be constructed or deleted
4306  RootData() = delete;
4307  RootData(const RootData&) = delete;
4308  RootData& operator=(const RootData&) = delete;
4309  ~RootData() = delete;
4310 }; // RootData
4311 
4312 // --------------------------> RootNode <------------------------------------
4313 
4314 /// @brief Top-most node of the VDB tree structure.
4315 template<typename ChildT>
4316 class RootNode : public RootData<ChildT>
4317 {
4318 public:
4319  using DataType = RootData<ChildT>;
4320  using ChildNodeType = ChildT;
4321  using RootType = RootNode<ChildT>; // this allows RootNode to behave like a Tree
4323  using UpperNodeType = ChildT;
4324  using LowerNodeType = typename UpperNodeType::ChildNodeType;
4325  using LeafNodeType = typename ChildT::LeafNodeType;
4326  using ValueType = typename DataType::ValueT;
4327  using FloatType = typename DataType::StatsT;
4328  using BuildType = typename DataType::BuildT; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool
4329 
4330  using CoordType = typename ChildT::CoordType;
4333  using Tile = typename DataType::Tile;
4334  static constexpr bool FIXED_SIZE = DataType::FIXED_SIZE;
4335 
4336  static constexpr uint32_t LEVEL = 1 + ChildT::LEVEL; // level 0 = leaf
4337 
4338  template<typename RootT>
4339  class BaseIter
4340  {
4341  protected:
4345  uint32_t mPos, mSize;
4346  __hostdev__ BaseIter(DataT* data = nullptr, uint32_t n = 0)
4347  : mData(data)
4348  , mPos(0)
4349  , mSize(n)
4350  {
4351  }
4352 
4353  public:
4354  __hostdev__ operator bool() const { return mPos < mSize; }
4355  __hostdev__ uint32_t pos() const { return mPos; }
4356  __hostdev__ void next() { ++mPos; }
4357  __hostdev__ TileT* tile() const { return mData->tile(mPos); }
4359  {
4360  NANOVDB_ASSERT(*this);
4361  return this->tile()->origin();
4362  }
4364  {
4365  NANOVDB_ASSERT(*this);
4366  return this->tile()->origin();
4367  }
4368  }; // Member class BaseIter
4369 
4370  template<typename RootT>
4371  class ChildIter : public BaseIter<RootT>
4372  {
4373  static_assert(is_same<typename remove_const<RootT>::type, RootNode>::value, "Invalid RootT");
4374  using BaseT = BaseIter<RootT>;
4375  using NodeT = typename match_const<ChildT, RootT>::type;
4376 
4377  public:
4379  : BaseT()
4380  {
4381  }
4382  __hostdev__ ChildIter(RootT* parent)
4383  : BaseT(parent->data(), parent->tileCount())
4384  {
4385  NANOVDB_ASSERT(BaseT::mData);
4386  while (*this && !this->tile()->isChild())
4387  this->next();
4388  }
4389  __hostdev__ NodeT& operator*() const
4390  {
4391  NANOVDB_ASSERT(*this);
4392  return *BaseT::mData->getChild(this->tile());
4393  }
4394  __hostdev__ NodeT* operator->() const
4395  {
4396  NANOVDB_ASSERT(*this);
4397  return BaseT::mData->getChild(this->tile());
4398  }
4400  {
4401  NANOVDB_ASSERT(BaseT::mData);
4402  this->next();
4403  while (*this && this->tile()->isValue())
4404  this->next();
4405  return *this;
4406  }
4408  {
4409  auto tmp = *this;
4410  ++(*this);
4411  return tmp;
4412  }
4413  }; // Member class ChildIter
4414 
4417 
4420 
4421  template<typename RootT>
4422  class ValueIter : public BaseIter<RootT>
4423  {
4424  using BaseT = BaseIter<RootT>;
4425 
4426  public:
4428  : BaseT()
4429  {
4430  }
4431  __hostdev__ ValueIter(RootT* parent)
4432  : BaseT(parent->data(), parent->tileCount())
4433  {
4434  NANOVDB_ASSERT(BaseT::mData);
4435  while (*this && this->tile()->isChild())
4436  this->next();
4437  }
4439  {
4440  NANOVDB_ASSERT(*this);
4441  return this->tile()->value;
4442  }
4443  __hostdev__ bool isActive() const
4444  {
4445  NANOVDB_ASSERT(*this);
4446  return this->tile()->state;
4447  }
4449  {
4450  NANOVDB_ASSERT(BaseT::mData);
4451  this->next();
4452  while (*this && this->tile()->isChild())
4453  this->next();
4454  return *this;
4455  }