HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GridBuilder.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 GridBuilder.h
6 
7  \author Ken Museth
8 
9  \date June 26, 2020
10 
11  \brief This file defines a minimum set of tree nodes and tools that
12  can be used (instead of OpenVDB) to build nanovdb grids on the CPU.
13 */
14 
15 #ifndef NANOVDB_GRID_BUILDER_H_HAS_BEEN_INCLUDED
16 #define NANOVDB_GRID_BUILDER_H_HAS_BEEN_INCLUDED
17 
18 #include <iostream>
19 
20 #include <map>
21 #include <limits>
22 #include <sstream> // for stringstream
23 #include <vector>
24 #include <cstring> // for memcpy
25 #include <mutex>
26 #include <array>
27 #include <atomic>
28 
29 #include <nanovdb/NanoVDB.h>
30 #include "Range.h"
31 #include "ForEach.h"
32 
33 namespace nanovdb {
34 
35 namespace build {
36 
37 // ----------------------------> Froward decelerations of random access methods <--------------------------------------
38 
39 template <typename T> struct GetValue;
40 template <typename T> struct SetValue;
41 template <typename T> struct TouchLeaf;
42 template <typename T> struct GetState;
43 template <typename T> struct ProbeValue;
44 
45 // ----------------------------> RootNode <--------------------------------------
46 
47 template<typename ChildT>
48 struct RootNode
49 {
50  using ValueType = typename ChildT::ValueType;
51  using BuildType = typename ChildT::BuildType;
52  using ChildNodeType = ChildT;
53  using LeafNodeType = typename ChildT::LeafNodeType;
54  static constexpr uint32_t LEVEL = 1 + ChildT::LEVEL; // level 0 = leaf
55  struct Tile {
56  Tile(ChildT* c = nullptr) : child(c) {}
57  Tile(const ValueType& v, bool s) : child(nullptr), value(v), state(s) {}
58  bool isChild() const { return child!=nullptr; }
59  bool isValue() const { return child==nullptr; }
60  bool isActive() const { return child==nullptr && state; }
61  ChildT* child;
63  bool state;
64  };
65  using MapT = std::map<Coord, Tile>;
68 
69  Tile* probeTile(const Coord &ijk) {
70  auto iter = mTable.find(CoordToKey(ijk));
71  return iter == mTable.end() ? nullptr : &(iter->second);
72  }
73 
74  const Tile* probeTile(const Coord &ijk) const {
75  auto iter = mTable.find(CoordToKey(ijk));
76  return iter == mTable.end() ? nullptr : &(iter->second);
77  }
78 
80  {
81  const RootNode *mParent;
82  typename MapT::const_iterator mIter;
83  public:
84  ChildIterator() : mParent(nullptr), mIter() {}
85  ChildIterator(const RootNode *parent) : mParent(parent), mIter(parent->mTable.begin()) {
86  while (mIter!=parent->mTable.end() && mIter->second.child==nullptr) ++mIter;
87  }
88  ChildIterator& operator=(const ChildIterator&) = default;
89  ChildT& operator*() const {NANOVDB_ASSERT(*this); return *mIter->second.child;}
90  ChildT* operator->() const {NANOVDB_ASSERT(*this); return mIter->second.child;}
91  Coord getOrigin() const { NANOVDB_ASSERT(*this); return mIter->first;}
92  Coord getCoord() const { NANOVDB_ASSERT(*this); return mIter->first;}
93  operator bool() const {return mParent && mIter!=mParent->mTable.end();}
95  NANOVDB_ASSERT(mParent);
96  ++mIter;
97  while (mIter!=mParent->mTable.end() && mIter->second.child==nullptr) ++mIter;
98  return *this;
99  }
101  auto tmp = *this;
102  ++(*this);
103  return tmp;
104  }
105  uint32_t pos() const {
106  NANOVDB_ASSERT(mParent);
107  return uint32_t(std::distance(mParent->mTable.begin(), mIter));
108  }
109  }; // Member class ChildIterator
110 
111  ChildIterator cbeginChild() const {return ChildIterator(this);}
112  ChildIterator cbeginChildOn() const {return ChildIterator(this);}// match openvdb
113 
115  {
116  const RootNode *mParent;
117  typename MapT::const_iterator mIter;
118  public:
119  ValueIterator() : mParent(nullptr), mIter() {}
120  ValueIterator(const RootNode *parent) : mParent(parent), mIter(parent->mTable.begin()) {
121  while (mIter!=parent->mTable.end() && mIter->second.child!=nullptr) ++mIter;
122  }
123  ValueIterator& operator=(const ValueIterator&) = default;
124  ValueType operator*() const {NANOVDB_ASSERT(*this); return mIter->second.value;}
125  bool isActive() const {NANOVDB_ASSERT(*this); return mIter->second.state;}
126  Coord getOrigin() const { NANOVDB_ASSERT(*this); return mIter->first;}
127  Coord getCoord() const { NANOVDB_ASSERT(*this); return mIter->first;}
128  operator bool() const {return mParent && mIter!=mParent->mTable.end();}
130  NANOVDB_ASSERT(mParent);
131  ++mIter;
132  while (mIter!=mParent->mTable.end() && mIter->second.child!=nullptr) ++mIter;
133  return *this;;
134  }
136  auto tmp = *this;
137  ++(*this);
138  return tmp;
139  }
140  uint32_t pos() const {
141  NANOVDB_ASSERT(mParent);
142  return uint32_t(std::distance(mParent->mTable.begin(), mIter));
143  }
144  }; // Member class ValueIterator
145 
146  ValueIterator beginValue() {return ValueIterator(this);}
147  ValueIterator cbeginValueAll() const {return ValueIterator(this);}
148 
150  {
151  const RootNode *mParent;
152  typename MapT::const_iterator mIter;
153  public:
154  ValueOnIterator() : mParent(nullptr), mIter() {}
155  ValueOnIterator(const RootNode *parent) : mParent(parent), mIter(parent->mTable.begin()) {
156  while (mIter!=parent->mTable.end() && (mIter->second.child!=nullptr || !mIter->second.state)) ++mIter;
157  }
158  ValueOnIterator& operator=(const ValueOnIterator&) = default;
159  ValueType operator*() const {NANOVDB_ASSERT(*this); return mIter->second.value;}
160  Coord getOrigin() const { NANOVDB_ASSERT(*this); return mIter->first;}
161  Coord getCoord() const { NANOVDB_ASSERT(*this); return mIter->first;}
162  operator bool() const {return mParent && mIter!=mParent->mTable.end();}
164  NANOVDB_ASSERT(mParent);
165  ++mIter;
166  while (mIter!=mParent->mTable.end() && (mIter->second.child!=nullptr || !mIter->second.state)) ++mIter;
167  return *this;;
168  }
170  auto tmp = *this;
171  ++(*this);
172  return tmp;
173  }
174  uint32_t pos() const {
175  NANOVDB_ASSERT(mParent);
176  return uint32_t(std::distance(mParent->mTable.begin(), mIter));
177  }
178  }; // Member class ValueOnIterator
179 
180  ValueOnIterator beginValueOn() {return ValueOnIterator(this);}
181  ValueOnIterator cbeginValueOn() const {return ValueOnIterator(this);}
182 
184  {
185  const RootNode *mParent;
186  typename MapT::const_iterator mIter;
187  public:
188  TileIterator() : mParent(nullptr), mIter() {}
189  TileIterator(const RootNode *parent) : mParent(parent), mIter(parent->mTable.begin()) {
190  NANOVDB_ASSERT(mParent);
191  }
192  TileIterator& operator=(const TileIterator&) = default;
193  const Tile& operator*() const {NANOVDB_ASSERT(*this); return mIter->second;}
194  const Tile* operator->() const {NANOVDB_ASSERT(*this); return &(mIter->second);}
195  Coord getOrigin() const { NANOVDB_ASSERT(*this); return mIter->first;}
196  Coord getCoord() const { NANOVDB_ASSERT(*this); return mIter->first;}
197  operator bool() const {return mParent && mIter!=mParent->mTable.end();}
198  const ChildT* probeChild(ValueType &value) {
199  NANOVDB_ASSERT(*this);
200  const ChildT *child = mIter->second.child;
201  if (child==nullptr) value = mIter->second.value;
202  return child;
203  }
204  bool isValueOn() const {return mIter->second.child==nullptr && mIter->second.state;}
206  NANOVDB_ASSERT(mParent);
207  ++mIter;
208  return *this;
209  }
211  auto tmp = *this;
212  ++(*this);
213  return tmp;
214  }
215  uint32_t pos() const {
216  NANOVDB_ASSERT(mParent);
217  return uint32_t(std::distance(mParent->mTable.begin(), mIter));
218  }
219  }; // Member class TileIterator
220 
221  TileIterator beginTile() {return TileIterator(this);}
222  TileIterator cbeginChildAll() const {return TileIterator(this);}
223 
224  //class DenseIterator : public TileIterator
225 
226  RootNode(const ValueType& background) : mBackground(background) {}
227  RootNode(const RootNode&) = delete; // disallow copy-construction
228  RootNode(RootNode&&) = default; // allow move construction
229  RootNode& operator=(const RootNode&) = delete; // disallow copy assignment
230  RootNode& operator=(RootNode&&) = default; // allow move assignment
231 
232  ~RootNode() { this->clear(); }
233 
234  uint32_t tileCount() const { return uint32_t(mTable.size()); }
235  uint32_t getTableSize() const { return uint32_t(mTable.size()); }// match openvdb
236  const ValueType& background() const {return mBackground;}
237 
238  void nodeCount(std::array<size_t,3> &count) const
239  {
240  for (auto it = this->cbeginChild(); it; ++it) {
241  count[ChildT::LEVEL] += 1;
242  it->nodeCount(count);
243  }
244  }
245 
246  bool empty() const { return mTable.empty(); }
247 
248  void clear()
249  {
250  for (auto iter = mTable.begin(); iter != mTable.end(); ++iter) delete iter->second.child;
251  mTable.clear();
252  }
253 
254  static Coord CoordToKey(const Coord& ijk) { return ijk & ~ChildT::MASK; }
255 
256 #ifdef NANOVDB_NEW_ACCESSOR_METHODS
257  template<typename OpT, typename... ArgsT>
258  auto get(const Coord& ijk, ArgsT&&... args) const
259  {
260  if (const Tile *tile = this->probeTile(ijk)) {
261  if (auto *child = tile->child) return child->template get<OpT>(ijk, args...);
262  return OpT::get(*tile, args...);
263  }
264  return OpT::get(*this, args...);
265  }
266  template<typename OpT, typename... ArgsT>
267  auto set(const Coord& ijk, ArgsT&&... args)
268  {
269  ChildT* child = nullptr;
270  const Coord key = CoordToKey(ijk);
271  auto iter = mTable.find(key);
272  if (iter == mTable.end()) {
273  child = new ChildT(ijk, mBackground, false);
274  mTable[key] = Tile(child);
275  } else if (iter->second.child != nullptr) {
276  child = iter->second.child;
277  } else {
278  child = new ChildT(ijk, iter->second.value, iter->second.state);
279  iter->second.child = child;
280  }
281  NANOVDB_ASSERT(child);
282  return child->template set<OpT>(ijk, args...);
283  }
284  template<typename OpT, typename AccT, typename... ArgsT>
285  auto getAndCache(const Coord& ijk, const AccT& acc, ArgsT&&... args) const
286  {
287  if (const Tile *tile = this->probeTile(ijk)) {
288  if (auto *child = tile->child) {
289  acc.insert(ijk, child);
290  return child->template get<OpT>(ijk, args...);
291  }
292  return OpT::get(*tile, args...);
293  }
294  return OpT::get(*this, args...);
295  }
296 
297  template<typename OpT, typename AccT, typename... ArgsT>
298  auto setAndCache(const Coord& ijk, const AccT& acc, ArgsT&&... args)
299  {
300  ChildT* child = nullptr;
301  const Coord key = CoordToKey(ijk);
302  auto iter = mTable.find(key);
303  if (iter == mTable.end()) {
304  child = new ChildT(ijk, mBackground, false);
305  mTable[key] = Tile(child);
306  } else if (iter->second.child != nullptr) {
307  child = iter->second.child;
308  } else {
309  child = new ChildT(ijk, iter->second.value, iter->second.state);
310  iter->second.child = child;
311  }
312  NANOVDB_ASSERT(child);
313  acc.insert(ijk, child);
314  return child->template setAndCache<OpT>(ijk, acc, args...);
315  }
316  ValueType getValue(const Coord& ijk) const {return this->template get<GetValue<BuildType>>(ijk);}
317  ValueType getValue(int i, int j, int k) const {return this->template get<GetValue<BuildType>>(Coord(i,j,k));}
318  ValueType operator()(const Coord& ijk) const {return this->template get<GetValue<BuildType>>(ijk);}
319  ValueType operator()(int i, int j, int k) const {return this->template get<GetValue<BuildType>>(Coord(i,j,k));}
320  void setValue(const Coord& ijk, const ValueType& value) {this->template set<SetValue<BuildType>>(ijk, value);}
321  bool probeValue(const Coord& ijk, ValueType& value) const {return this->template get<ProbeValue<BuildType>>(ijk, value);}
322  bool isActive(const Coord& ijk) const {return this->template get<GetState<BuildType>>(ijk);}
323 #else
324  ValueType getValue(const Coord& ijk) const
325  {
326 #if 1
327  if (auto *tile = this->probeTile(ijk)) return tile->child ? tile->child->getValue(ijk) : tile->value;
328  return mBackground;
329 #else
330  auto iter = mTable.find(CoordToKey(ijk));
331  if (iter == mTable.end()) {
332  return mBackground;
333  } else if (iter->second.child) {
334  return iter->second.child->getValue(ijk);
335  } else {
336  return iter->second.value;
337  }
338 #endif
339  }
340  ValueType getValue(int i, int j, int k) const {return this->getValue(Coord(i,j,k));}
341 
342  void setValue(const Coord& ijk, const ValueType& value)
343  {
344  ChildT* child = nullptr;
345  const Coord key = CoordToKey(ijk);
346  auto iter = mTable.find(key);
347  if (iter == mTable.end()) {
348  child = new ChildT(ijk, mBackground, false);
349  mTable[key] = Tile(child);
350  } else if (iter->second.child != nullptr) {
351  child = iter->second.child;
352  } else {
353  child = new ChildT(ijk, iter->second.value, iter->second.state);
354  iter->second.child = child;
355  }
356  NANOVDB_ASSERT(child);
357  child->setValue(ijk, value);
358  }
359 
360  template<typename AccT>
361  bool isActiveAndCache(const Coord& ijk, AccT& acc) const
362  {
363  auto iter = mTable.find(CoordToKey(ijk));
364  if (iter == mTable.end())
365  return false;
366  if (iter->second.child) {
367  acc.insert(ijk, iter->second.child);
368  return iter->second.child->isActiveAndCache(ijk, acc);
369  }
370  return iter->second.state;
371  }
372 
373  template<typename AccT>
374  ValueType getValueAndCache(const Coord& ijk, AccT& acc) const
375  {
376  auto iter = mTable.find(CoordToKey(ijk));
377  if (iter == mTable.end())
378  return mBackground;
379  if (iter->second.child) {
380  acc.insert(ijk, iter->second.child);
381  return iter->second.child->getValueAndCache(ijk, acc);
382  }
383  return iter->second.value;
384  }
385 
386  template<typename AccT>
387  void setValueAndCache(const Coord& ijk, const ValueType& value, AccT& acc)
388  {
389  ChildT* child = nullptr;
390  const Coord key = CoordToKey(ijk);
391  auto iter = mTable.find(key);
392  if (iter == mTable.end()) {
393  child = new ChildT(ijk, mBackground, false);
394  mTable[key] = Tile(child);
395  } else if (iter->second.child != nullptr) {
396  child = iter->second.child;
397  } else {
398  child = new ChildT(ijk, iter->second.value, iter->second.state);
399  iter->second.child = child;
400  }
401  NANOVDB_ASSERT(child);
402  acc.insert(ijk, child);
403  child->setValueAndCache(ijk, value, acc);
404  }
405  template<typename AccT>
406  void setValueOnAndCache(const Coord& ijk, AccT& acc)
407  {
408  ChildT* child = nullptr;
409  const Coord key = CoordToKey(ijk);
410  auto iter = mTable.find(key);
411  if (iter == mTable.end()) {
412  child = new ChildT(ijk, mBackground, false);
413  mTable[key] = Tile(child);
414  } else if (iter->second.child != nullptr) {
415  child = iter->second.child;
416  } else {
417  child = new ChildT(ijk, iter->second.value, iter->second.state);
418  iter->second.child = child;
419  }
420  NANOVDB_ASSERT(child);
421  acc.insert(ijk, child);
422  child->setValueOnAndCache(ijk, acc);
423  }
424  template<typename AccT>
425  void touchLeafAndCache(const Coord &ijk, AccT& acc)
426  {
427  ChildT* child = nullptr;
428  const Coord key = CoordToKey(ijk);
429  auto iter = mTable.find(key);
430  if (iter == mTable.end()) {
431  child = new ChildT(ijk, mBackground, false);
432  mTable[key] = Tile(child);
433  } else if (iter->second.child != nullptr) {
434  child = iter->second.child;
435  } else {
436  child = new ChildT(ijk, iter->second.value, iter->second.state);
437  iter->second.child = child;
438  }
439  acc.insert(ijk, child);
440  child->touchLeafAndCache(ijk, acc);
441  }
442 #endif// NANOVDB_NEW_ACCESSOR_METHODS
443 
444  template<typename NodeT>
445  uint32_t nodeCount() const
446  {
447  static_assert(is_same<ValueType, typename NodeT::ValueType>::value, "Root::getNodes: Invalid type");
448  static_assert(NodeT::LEVEL < LEVEL, "Root::getNodes: LEVEL error");
449  uint32_t sum = 0;
450  for (auto iter = mTable.begin(); iter != mTable.end(); ++iter) {
451  if (iter->second.child == nullptr) continue; // skip tiles
452  if constexpr(is_same<NodeT, ChildT>::value) { //resolved at compile-time
453  ++sum;
454  } else {
455  sum += iter->second.child->template nodeCount<NodeT>();
456  }
457  }
458  return sum;
459  }
460 
461  template<typename NodeT>
462  void getNodes(std::vector<NodeT*>& array)
463  {
464  static_assert(is_same<ValueType, typename NodeT::ValueType>::value, "Root::getNodes: Invalid type");
465  static_assert(NodeT::LEVEL < LEVEL, "Root::getNodes: LEVEL error");
466  for (auto iter = mTable.begin(); iter != mTable.end(); ++iter) {
467  if (iter->second.child == nullptr)
468  continue;
469  if constexpr(is_same<NodeT, ChildT>::value) { //resolved at compile-time
470  array.push_back(reinterpret_cast<NodeT*>(iter->second.child));
471  } else {
472  iter->second.child->getNodes(array);
473  }
474  }
475  }
476 
477  void addChild(ChildT*& child)
478  {
479  NANOVDB_ASSERT(child);
480  const Coord key = CoordToKey(child->mOrigin);
481  auto iter = mTable.find(key);
482  if (iter != mTable.end() && iter->second.child != nullptr) { // existing child node
483  delete iter->second.child;
484  iter->second.child = child;
485  } else {
486  mTable[key] = Tile(child);
487  }
488  child = nullptr;
489  }
490 
491  /// @brief Add a tile containing voxel (i, j, k) at the specified tree level,
492  /// creating a new branch if necessary. Delete any existing lower-level nodes
493  /// that contain (x, y, z).
494  /// @tparam level tree level at which the tile is inserted. Must be 1, 2 or 3.
495  /// @param ijk Index coordinate that map to the tile being inserted
496  /// @param value Value of the tile
497  /// @param state Binary state of the tile
498  template <uint32_t level>
499  void addTile(const Coord& ijk, const ValueType& value, bool state)
500  {
501  static_assert(level > 0 && level <= LEVEL, "invalid template value of level");
502  const Coord key = CoordToKey(ijk);
503  auto iter = mTable.find(key);
504  if constexpr(level == LEVEL) {
505  if (iter == mTable.end()) {
506  mTable[key] = Tile(value, state);
507  } else if (iter->second.child == nullptr) {
508  iter->second.value = value;
509  iter->second.state = state;
510  } else {
511  delete iter->second.child;
512  iter->second.child = nullptr;
513  iter->second.value = value;
514  iter->second.state = state;
515  }
516  } else if constexpr(level < LEVEL) {
517  ChildT* child = nullptr;
518  if (iter == mTable.end()) {
519  child = new ChildT(ijk, mBackground, false);
520  mTable[key] = Tile(child);
521  } else if (iter->second.child != nullptr) {
522  child = iter->second.child;
523  } else {
524  child = new ChildT(ijk, iter->second.value, iter->second.state);
525  iter->second.child = child;
526  }
527  child->template addTile<level>(ijk, value, state);
528  }
529  }
530 
531  template<typename NodeT>
532  void addNode(NodeT*& node)
533  {
534  if constexpr(is_same<NodeT, ChildT>::value) { //resolved at compile-time
535  this->addChild(reinterpret_cast<ChildT*&>(node));
536  } else {
537  ChildT* child = nullptr;
538  const Coord key = CoordToKey(node->mOrigin);
539  auto iter = mTable.find(key);
540  if (iter == mTable.end()) {
541  child = new ChildT(node->mOrigin, mBackground, false);
542  mTable[key] = Tile(child);
543  } else if (iter->second.child != nullptr) {
544  child = iter->second.child;
545  } else {
546  child = new ChildT(node->mOrigin, iter->second.value, iter->second.state);
547  iter->second.child = child;
548  }
549  child->addNode(node);
550  }
551  }
552 
553  void merge(RootNode &other)
554  {
555  for (auto iter1 = other.mTable.begin(); iter1 != other.mTable.end(); ++iter1) {
556  if (iter1->second.child == nullptr) continue;// ignore input tiles
557  auto iter2 = mTable.find(iter1->first);
558  if (iter2 == mTable.end() || iter2->second.child == nullptr) {
559  mTable[iter1->first] = Tile(iter1->second.child);
560  iter1->second.child = nullptr;
561  } else {
562  iter2->second.child->merge(*iter1->second.child);
563  }
564  }
565  other.clear();
566  }
567 
568  template<typename T>
570  signedFloodFill(T outside);
571 
572 }; // build::RootNode
573 
574 //================================================================================================
575 
576 template<typename ChildT>
577 template<typename T>
580 {
581  std::map<Coord, ChildT*> nodeKeys;
582  for (auto iter = mTable.begin(); iter != mTable.end(); ++iter) {
583  if (iter->second.child == nullptr)
584  continue;
585  nodeKeys.insert(std::pair<Coord, ChildT*>(iter->first, iter->second.child));
586  }
587 
588  // We employ a simple z-scanline algorithm that inserts inactive tiles with
589  // the inside value if they are sandwiched between inside child nodes only!
590  auto b = nodeKeys.begin(), e = nodeKeys.end();
591  if (b == e)
592  return;
593  for (auto a = b++; b != e; ++a, ++b) {
594  Coord d = b->first - a->first; // delta of neighboring coordinates
595  if (d[0] != 0 || d[1] != 0 || d[2] == int(ChildT::DIM))
596  continue; // not same z-scanline or neighbors
597  const ValueType fill[] = {a->second->getLastValue(), b->second->getFirstValue()};
598  if (!(fill[0] < 0) || !(fill[1] < 0))
599  continue; // scanline isn't inside
600  Coord c = a->first + Coord(0u, 0u, ChildT::DIM);
601  for (; c[2] != b->first[2]; c[2] += ChildT::DIM) {
602  const Coord key = RootNode<ChildT>::CoordToKey(c);
603  mTable[key] = typename RootNode<ChildT>::Tile(-outside, false); // inactive tile
604  }
605  }
606 } // build::RootNode::signedFloodFill
607 
608 // ----------------------------> InternalNode <--------------------------------------
609 
610 template<typename ChildT>
612 {
613  using ValueType = typename ChildT::ValueType;
614  using BuildType = typename ChildT::BuildType;
615  using ChildNodeType = ChildT;
616  using LeafNodeType = typename ChildT::LeafNodeType;
617  static constexpr uint32_t LOG2DIM = ChildT::LOG2DIM + 1;
618  static constexpr uint32_t TOTAL = LOG2DIM + ChildT::TOTAL; //dimension in index space
619  static constexpr uint32_t DIM = 1u << TOTAL;
620  static constexpr uint32_t SIZE = 1u << (3 * LOG2DIM); //number of tile values (or child pointers)
621  static constexpr uint32_t MASK = DIM - 1;
622  static constexpr uint32_t LEVEL = 1 + ChildT::LEVEL; // level 0 = leaf
623  static constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node
625  template<bool On>
626  using MaskIterT = typename MaskT::template Iterator<On>;
628 
629  struct Tile {
630  Tile(ChildT* c = nullptr) : child(c) {}
631  Tile(const ValueType& v) : value(v) {}
632  union{
633  ChildT* child;
635  };
636  };
641 
642  union {
644  uint64_t mDstOffset;
645  };
646 
647  /// @brief Visits child nodes of this node only
648  class ChildIterator : public MaskIterT<true>
649  {
650  using BaseT = MaskIterT<true>;
651  const InternalNode *mParent;
652  public:
653  ChildIterator() : BaseT(), mParent(nullptr) {}
654  ChildIterator(const InternalNode* parent) : BaseT(parent->mChildMask.beginOn()), mParent(parent) {}
655  ChildIterator& operator=(const ChildIterator&) = default;
656  const ChildT& operator*() const {NANOVDB_ASSERT(*this); return *mParent->mTable[BaseT::pos()].child;}
657  const ChildT* operator->() const {NANOVDB_ASSERT(*this); return mParent->mTable[BaseT::pos()].child;}
658  Coord getCoord() const { NANOVDB_ASSERT(*this); return (*this)->origin();}
659  }; // Member class ChildIterator
660 
662  ChildIterator cbeginChildOn() const {return ChildIterator(this);}// match openvdb
663 
664  /// @brief Visits all tile values in this node, i.e. both inactive and active tiles
665  class ValueIterator : public MaskIterT<false>
666  {
667  using BaseT = MaskIterT<false>;
668  const InternalNode *mParent;
669  public:
670  ValueIterator() : BaseT(), mParent(nullptr) {}
671  ValueIterator(const InternalNode* parent) : BaseT(parent->mChildMask.beginOff()), mParent(parent) {}
672  ValueIterator& operator=(const ValueIterator&) = default;
673  ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->mTable[BaseT::pos()].value;}
674  Coord getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BaseT::pos());}
675  bool isActive() const { NANOVDB_ASSERT(*this); return mParent->mValueMask.isOn(BaseT::pos());}
676  }; // Member class ValueIterator
677 
680 
681  /// @brief Visits active tile values of this node only
682  class ValueOnIterator : public MaskIterT<true>
683  {
684  using BaseT = MaskIterT<true>;
685  const InternalNode *mParent;
686  public:
687  ValueOnIterator() : BaseT(), mParent(nullptr) {}
688  ValueOnIterator(const InternalNode* parent) : BaseT(parent->mValueMask.beginOn()), mParent(parent) {}
689  ValueOnIterator& operator=(const ValueOnIterator&) = default;
690  ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->mTable[BaseT::pos()].value;}
691  Coord getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BaseT::pos());}
692  }; // Member class ValueOnIterator
693 
696 
697  /// @brief Visits all tile values and child nodes of this node
699  {
700  using BaseT = typename MaskT::DenseIterator;
701  const InternalNode *mParent;
702  public:
703  DenseIterator() : BaseT(), mParent(nullptr) {}
704  DenseIterator(const InternalNode* parent) : BaseT(0), mParent(parent) {}
705  DenseIterator& operator=(const DenseIterator&) = default;
706  ChildT* probeChild(ValueType& value) const
707  {
708  NANOVDB_ASSERT(mParent && bool(*this));
709  ChildT *child = nullptr;
710  if (mParent->mChildMask.isOn(BaseT::pos())) {
711  child = mParent->mTable[BaseT::pos()].child;
712  } else {
713  value = mParent->mTable[BaseT::pos()].value;
714  }
715  return child;
716  }
717  Coord getCoord() const { NANOVDB_ASSERT(mParent && bool(*this)); return mParent->offsetToGlobalCoord(BaseT::pos());}
718  }; // Member class DenseIterator
719 
721  DenseIterator cbeginChildAll() const {return DenseIterator(this);}// matches openvdb
722 
723  InternalNode(const Coord& origin, const ValueType& value, bool state)
724  : mOrigin(origin & ~MASK)
725  , mValueMask(state)
726  , mChildMask()
727  , mDstOffset(0)
728  {
729  for (uint32_t i = 0; i < SIZE; ++i) mTable[i].value = value;
730  }
731  InternalNode(const InternalNode&) = delete; // disallow copy-construction
732  InternalNode(InternalNode&&) = delete; // disallow move construction
733  InternalNode& operator=(const InternalNode&) = delete; // disallow copy assignment
734  InternalNode& operator=(InternalNode&&) = delete; // disallow move assignment
736  {
737  for (auto iter = mChildMask.beginOn(); iter; ++iter) {
738  delete mTable[*iter].child;
739  }
740  }
741  const MaskT& getValueMask() const {return mValueMask;}
742  const MaskT& valueMask() const {return mValueMask;}
743  const MaskT& getChildMask() const {return mChildMask;}
744  const MaskT& childMask() const {return mChildMask;}
745  const Coord& origin() const {return mOrigin;}
746 
747  void nodeCount(std::array<size_t,3> &count) const
748  {
749  count[ChildT::LEVEL] += mChildMask.countOn();
750  if constexpr(ChildT::LEVEL>0) {
751  for (auto it = const_cast<InternalNode*>(this)->beginChild(); it; ++it) it->nodeCount(count);
752  }
753  }
754 
755  static uint32_t CoordToOffset(const Coord& ijk)
756  {
757  return (((ijk[0] & int32_t(MASK)) >> ChildT::TOTAL) << (2 * LOG2DIM)) +
758  (((ijk[1] & int32_t(MASK)) >> ChildT::TOTAL) << (LOG2DIM)) +
759  ((ijk[2] & int32_t(MASK)) >> ChildT::TOTAL);
760  }
761 
762  static Coord OffsetToLocalCoord(uint32_t n)
763  {
764  NANOVDB_ASSERT(n < SIZE);
765  const uint32_t m = n & ((1 << 2 * LOG2DIM) - 1);
766  return Coord(n >> 2 * LOG2DIM, m >> LOG2DIM, m & ((1 << LOG2DIM) - 1));
767  }
768 
769  void localToGlobalCoord(Coord& ijk) const
770  {
771  ijk <<= ChildT::TOTAL;
772  ijk += mOrigin;
773  }
774 
775  Coord offsetToGlobalCoord(uint32_t n) const
776  {
778  this->localToGlobalCoord(ijk);
779  return ijk;
780  }
781 
782  ValueType getFirstValue() const { return mChildMask.isOn(0) ? mTable[0].child->getFirstValue() : mTable[0].value; }
783  ValueType getLastValue() const { return mChildMask.isOn(SIZE - 1) ? mTable[SIZE - 1].child->getLastValue() : mTable[SIZE - 1].value; }
784 
785  template<typename OpT, typename... ArgsT>
786  auto get(const Coord& ijk, ArgsT&&... args) const
787  {
788  const uint32_t n = CoordToOffset(ijk);
789  if (mChildMask.isOn(n)) return mTable[n].child->template get<OpT>(ijk, args...);
790  return OpT::get(*this, n, args...);
791  }
792 
793  template<typename OpT, typename... ArgsT>
794  auto set(const Coord& ijk, ArgsT&&... args)
795  {
796  const uint32_t n = CoordToOffset(ijk);
797  ChildT* child = nullptr;
798  if (mChildMask.isOn(n)) {
799  child = mTable[n].child;
800  } else {
801  child = new ChildT(ijk, mTable[n].value, mValueMask.isOn(n));
802  mTable[n].child = child;
803  mChildMask.setOn(n);
804  }
805  NANOVDB_ASSERT(child);
806  return child->template set<OpT>(ijk, args...);
807  }
808 
809  template<typename OpT, typename AccT, typename... ArgsT>
810  auto getAndCache(const Coord& ijk, const AccT& acc, ArgsT&&... args) const
811  {
812  const uint32_t n = CoordToOffset(ijk);
813  if (mChildMask.isOff(n)) return OpT::get(*this, n, args...);
814  ChildT* child = mTable[n].child;
815  acc.insert(ijk, child);
816  if constexpr(ChildT::LEVEL == 0) {
817  return child->template get<OpT>(ijk, args...);
818  } else {
819  return child->template getAndCache<OpT>(ijk, acc, args...);
820  }
821  }
822 
823  template<typename OpT, typename AccT, typename... ArgsT>
824  auto setAndCache(const Coord& ijk, const AccT& acc, ArgsT&&... args)
825  {
826  const uint32_t n = CoordToOffset(ijk);
827  ChildT* child = nullptr;
828  if (mChildMask.isOn(n)) {
829  child = mTable[n].child;
830  } else {
831  child = new ChildT(ijk, mTable[n].value, mValueMask.isOn(n));
832  mTable[n].child = child;
833  mChildMask.setOn(n);
834  }
835  NANOVDB_ASSERT(child);
836  acc.insert(ijk, child);
837  if constexpr(ChildT::LEVEL == 0) {
838  return child->template set<OpT>(ijk, args...);
839  } else {
840  return child->template setAndCache<OpT>(ijk, acc, args...);
841  }
842  }
843 
844 #ifdef NANOVDB_NEW_ACCESSOR_METHODS
845  ValueType getValue(const Coord& ijk) const {return this->template get<GetValue<BuildType>>(ijk);}
846  LeafNodeType& setValue(const Coord& ijk, const ValueType& value){return this->template set<SetValue<BuildType>>(ijk, value);}
847 #else
848  ValueType getValue(const Coord& ijk) const
849  {
850  const uint32_t n = CoordToOffset(ijk);
851  if (mChildMask.isOn(n)) {
852  return mTable[n].child->getValue(ijk);
853  }
854  return mTable[n].value;
855  }
856  void setValue(const Coord& ijk, const ValueType& value)
857  {
858  const uint32_t n = CoordToOffset(ijk);
859  ChildT* child = nullptr;
860  if (mChildMask.isOn(n)) {
861  child = mTable[n].child;
862  } else {
863  child = new ChildT(ijk, mTable[n].value, mValueMask.isOn(n));
864  mTable[n].child = child;
865  mChildMask.setOn(n);
866  }
867  child->setValue(ijk, value);
868  }
869 
870  template<typename AccT>
871  ValueType getValueAndCache(const Coord& ijk, AccT& acc) const
872  {
873  const uint32_t n = CoordToOffset(ijk);
874  if (mChildMask.isOn(n)) {
875  acc.insert(ijk, const_cast<ChildT*>(mTable[n].child));
876  return mTable[n].child->getValueAndCache(ijk, acc);
877  }
878  return mTable[n].value;
879  }
880 
881  template<typename AccT>
882  void setValueAndCache(const Coord& ijk, const ValueType& value, AccT& acc)
883  {
884  const uint32_t n = CoordToOffset(ijk);
885  ChildT* child = nullptr;
886  if (mChildMask.isOn(n)) {
887  child = mTable[n].child;
888  } else {
889  child = new ChildT(ijk, mTable[n].value, mValueMask.isOn(n));
890  mTable[n].child = child;
891  mChildMask.setOn(n);
892  }
893  acc.insert(ijk, child);
894  child->setValueAndCache(ijk, value, acc);
895  }
896 
897  template<typename AccT>
898  void setValueOnAndCache(const Coord& ijk, AccT& acc)
899  {
900  const uint32_t n = CoordToOffset(ijk);
901  ChildT* child = nullptr;
902  if (mChildMask.isOn(n)) {
903  child = mTable[n].child;
904  } else {
905  child = new ChildT(ijk, mTable[n].value, mValueMask.isOn(n));
906  mTable[n].child = child;
907  mChildMask.setOn(n);
908  }
909  acc.insert(ijk, child);
910  child->setValueOnAndCache(ijk, acc);
911  }
912 
913  template<typename AccT>
914  void touchLeafAndCache(const Coord &ijk, AccT& acc)
915  {
916  const uint32_t n = CoordToOffset(ijk);
917  ChildT* child = nullptr;
918  if (mChildMask.isOn(n)) {
919  child = mTable[n].child;
920  } else {
921  child = new ChildT(ijk, mTable[n].value, mValueMask.isOn(n));
922  mTable[n].child = child;
923  mChildMask.setOn(n);
924  }
925  acc.insert(ijk, child);
926  if constexpr(LEVEL>1) child->touchLeafAndCache(ijk, acc);
927  }
928  template<typename AccT>
929  bool isActiveAndCache(const Coord& ijk, AccT& acc) const
930  {
931  const uint32_t n = CoordToOffset(ijk);
932  if (mChildMask.isOn(n)) {
933  acc.insert(ijk, const_cast<ChildT*>(mTable[n].child));
934  return mTable[n].child->isActiveAndCache(ijk, acc);
935  }
936  return mValueMask.isOn(n);
937  }
938 #endif
939 
940  template<typename NodeT>
941  uint32_t nodeCount() const
942  {
943  static_assert(is_same<ValueType, typename NodeT::ValueType>::value, "Node::getNodes: Invalid type");
944  NANOVDB_ASSERT(NodeT::LEVEL < LEVEL);
945  uint32_t sum = 0;
946  if constexpr(is_same<NodeT, ChildT>::value) { // resolved at compile-time
947  sum += mChildMask.countOn();
948  } else if constexpr(LEVEL>1) {
949  for (auto iter = mChildMask.beginOn(); iter; ++iter) {
950  sum += mTable[*iter].child->template nodeCount<NodeT>();
951  }
952  }
953  return sum;
954  }
955 
956  template<typename NodeT>
957  void getNodes(std::vector<NodeT*>& array)
958  {
959  static_assert(is_same<ValueType, typename NodeT::ValueType>::value, "Node::getNodes: Invalid type");
960  NANOVDB_ASSERT(NodeT::LEVEL < LEVEL);
961  for (auto iter = mChildMask.beginOn(); iter; ++iter) {
962  if constexpr(is_same<NodeT, ChildT>::value) { // resolved at compile-time
963  array.push_back(reinterpret_cast<NodeT*>(mTable[*iter].child));
964  } else if constexpr(LEVEL>1) {
965  mTable[*iter].child->getNodes(array);
966  }
967  }
968  }
969 
970  void addChild(ChildT*& child)
971  {
972  NANOVDB_ASSERT(child && (child->mOrigin & ~MASK) == this->mOrigin);
973  const uint32_t n = CoordToOffset(child->mOrigin);
974  if (mChildMask.isOn(n)) {
975  delete mTable[n].child;
976  } else {
977  mChildMask.setOn(n);
978  }
979  mTable[n].child = child;
980  child = nullptr;
981  }
982 
983  /// @brief Add a tile containing voxel (i, j, k) at the specified tree level,
984  /// creating a new branch if necessary. Delete any existing lower-level nodes
985  /// that contain (x, y, z).
986  /// @tparam level tree level at which the tile is inserted. Must be 1 or 2.
987  /// @param ijk Index coordinate that map to the tile being inserted
988  /// @param value Value of the tile
989  /// @param state Binary state of the tile
990  template <uint32_t level>
991  void addTile(const Coord& ijk, const ValueType& value, bool state)
992  {
993  static_assert(level > 0 && level <= LEVEL, "invalid template value of level");
994  const uint32_t n = CoordToOffset(ijk);
995  if constexpr(level == LEVEL) {
996  if (mChildMask.isOn(n)) {
997  delete mTable[n].child;
998  mTable[n] = Tile(value);
999  } else {
1000  mValueMask.set(n, state);
1001  mTable[n].value = value;
1002  }
1003  } else if constexpr(level < LEVEL) {
1004  ChildT* child = nullptr;
1005  if (mChildMask.isOn(n)) {
1006  child = mTable[n].child;
1007  } else {
1008  child = new ChildT(ijk, value, state);
1009  mTable[n].child = child;
1010  mChildMask.setOn(n);
1011  }
1012  child->template addTile<level>(ijk, value, state);
1013  }
1014  }
1015 
1016  template<typename NodeT>
1017  void addNode(NodeT*& node)
1018  {
1019  if constexpr(is_same<NodeT, ChildT>::value) { //resolved at compile-time
1020  this->addChild(reinterpret_cast<ChildT*&>(node));
1021  } else if constexpr(LEVEL>1) {
1022  const uint32_t n = CoordToOffset(node->mOrigin);
1023  ChildT* child = nullptr;
1024  if (mChildMask.isOn(n)) {
1025  child = mTable[n].child;
1026  } else {
1027  child = new ChildT(node->mOrigin, mTable[n].value, mValueMask.isOn(n));
1028  mTable[n].child = child;
1029  mChildMask.setOn(n);
1030  }
1031  child->addNode(node);
1032  }
1033  }
1034 
1035  void merge(InternalNode &other)
1036  {
1037  for (auto iter = other.mChildMask.beginOn(); iter; ++iter) {
1038  const uint32_t n = *iter;
1039  if (mChildMask.isOn(n)) {
1040  mTable[n].child->merge(*other.mTable[n].child);
1041  } else {
1042  mTable[n].child = other.mTable[n].child;
1043  other.mChildMask.setOff(n);
1044  mChildMask.setOn(n);
1045  }
1046  }
1047  }
1048 
1049  template<typename T>
1051  signedFloodFill(T outside);
1052 
1053 }; // build::InternalNode
1054 
1055 //================================================================================================
1056 
1057 template<typename ChildT>
1058 template<typename T>
1061 {
1062  const uint32_t first = *mChildMask.beginOn();
1063  if (first < NUM_VALUES) {
1064  bool xInside = mTable[first].child->getFirstValue() < 0;
1065  bool yInside = xInside, zInside = xInside;
1066  for (uint32_t x = 0; x != (1 << LOG2DIM); ++x) {
1067  const uint32_t x00 = x << (2 * LOG2DIM); // offset for block(x, 0, 0)
1068  if (mChildMask.isOn(x00)) {
1069  xInside = mTable[x00].child->getLastValue() < 0;
1070  }
1071  yInside = xInside;
1072  for (uint32_t y = 0; y != (1u << LOG2DIM); ++y) {
1073  const uint32_t xy0 = x00 + (y << LOG2DIM); // offset for block(x, y, 0)
1074  if (mChildMask.isOn(xy0))
1075  yInside = mTable[xy0].child->getLastValue() < 0;
1076  zInside = yInside;
1077  for (uint32_t z = 0; z != (1 << LOG2DIM); ++z) {
1078  const uint32_t xyz = xy0 + z; // offset for block(x, y, z)
1079  if (mChildMask.isOn(xyz)) {
1080  zInside = mTable[xyz].child->getLastValue() < 0;
1081  } else {
1082  mTable[xyz].value = zInside ? -outside : outside;
1083  }
1084  }
1085  }
1086  }
1087  }
1088 } // build::InternalNode::signedFloodFill
1089 
1090 // ----------------------------> LeafNode <--------------------------------------
1091 
1092 template<typename BuildT>
1093 struct LeafNode
1094 {
1095  using BuildType = BuildT;
1098  static constexpr uint32_t LOG2DIM = 3;
1099  static constexpr uint32_t TOTAL = LOG2DIM; // needed by parent nodes
1100  static constexpr uint32_t DIM = 1u << TOTAL;
1101  static constexpr uint32_t SIZE = 1u << 3 * LOG2DIM; // total number of voxels represented by this node
1102  static constexpr uint32_t MASK = DIM - 1; // mask for bit operations
1103  static constexpr uint32_t LEVEL = 0; // level 0 = leaf
1104  static constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node
1106  template<bool ON>
1107  using MaskIterT = typename Mask<LOG2DIM>::template Iterator<ON>;
1109 
1113  union {
1115  uint64_t mDstOffset;
1116  };
1117 
1118  /// @brief Visits all active values in a leaf node
1119  class ValueOnIterator : public MaskIterT<true>
1120  {
1121  using BaseT = MaskIterT<true>;
1122  const LeafNode *mParent;
1123  public:
1124  ValueOnIterator() : BaseT(), mParent(nullptr) {}
1125  ValueOnIterator(const LeafNode* parent) : BaseT(parent->mValueMask.beginOn()), mParent(parent) {}
1126  ValueOnIterator& operator=(const ValueOnIterator&) = default;
1127  ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->mValues[BaseT::pos()];}
1128  Coord getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BaseT::pos());}
1129  }; // Member class ValueOnIterator
1130 
1131  ValueOnIterator beginValueOn() {return ValueOnIterator(this);}
1132  ValueOnIterator cbeginValueOn() const {return ValueOnIterator(this);}
1133 
1134  /// @brief Visits all inactive values in a leaf node
1135  class ValueOffIterator : public MaskIterT<false>
1136  {
1137  using BaseT = MaskIterT<false>;
1138  const LeafNode *mParent;
1139  public:
1140  ValueOffIterator() : BaseT(), mParent(nullptr) {}
1141  ValueOffIterator(const LeafNode* parent) : BaseT(parent->mValueMask.beginOff()), mParent(parent) {}
1142  ValueOffIterator& operator=(const ValueOffIterator&) = default;
1143  ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->mValues[BaseT::pos()];}
1144  Coord getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BaseT::pos());}
1145  }; // Member class ValueOffIterator
1146 
1147  ValueOffIterator beginValueOff() {return ValueOffIterator(this);}
1148  ValueOffIterator cbeginValueOff() const {return ValueOffIterator(this);}
1149 
1150  /// @brief Visits all values in a leaf node, i.e. both active and inactive values
1152  {
1153  const LeafNode *mParent;
1154  uint32_t mPos;
1155  public:
1156  ValueIterator() : mParent(nullptr), mPos(1u << 3 * LOG2DIM) {}
1157  ValueIterator(const LeafNode* parent) : mParent(parent), mPos(0) {NANOVDB_ASSERT(parent);}
1158  ValueIterator& operator=(const ValueIterator&) = default;
1159  ValueType operator*() const { NANOVDB_ASSERT(*this); return mParent->mValues[mPos];}
1160  Coord getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(mPos);}
1161  bool isActive() const { NANOVDB_ASSERT(*this); return mParent->isActive(mPos);}
1162  operator bool() const {return mPos < SIZE;}
1163  ValueIterator& operator++() {++mPos; return *this;}
1165  auto tmp = *this;
1166  ++(*this);
1167  return tmp;
1168  }
1169  }; // Member class ValueIterator
1170 
1171  ValueIterator beginValue() {return ValueIterator(this);}
1172  ValueIterator cbeginValueAll() const {return ValueIterator(this);}
1173 
1174  LeafNode(const Coord& ijk, const ValueType& value, bool state)
1175  : mOrigin(ijk & ~MASK)
1176  , mValueMask(state) //invalid
1177  , mDstOffset(0)
1178  {
1180  uint32_t n = SIZE;
1181  while (n--) {
1182  *target++ = value;
1183  }
1184  }
1185  LeafNode(const LeafNode&) = delete; // disallow copy-construction
1186  LeafNode(LeafNode&&) = delete; // disallow move construction
1187  LeafNode& operator=(const LeafNode&) = delete; // disallow copy assignment
1188  LeafNode& operator=(LeafNode&&) = delete; // disallow move assignment
1189  ~LeafNode() = default;
1190 
1191  const Mask<LOG2DIM>& getValueMask() const {return mValueMask;}
1192  const Mask<LOG2DIM>& valueMask() const {return mValueMask;}
1193  const Coord& origin() const {return mOrigin;}
1194 
1195  /// @brief Return the linear offset corresponding to the given coordinate
1196  static uint32_t CoordToOffset(const Coord& ijk)
1197  {
1198  return ((ijk[0] & int32_t(MASK)) << (2 * LOG2DIM)) +
1199  ((ijk[1] & int32_t(MASK)) << LOG2DIM) +
1200  (ijk[2] & int32_t(MASK));
1201  }
1202 
1203  static Coord OffsetToLocalCoord(uint32_t n)
1204  {
1205  NANOVDB_ASSERT(n < SIZE);
1206  const int32_t m = n & ((1 << 2 * LOG2DIM) - 1);
1207  return Coord(n >> 2 * LOG2DIM, m >> LOG2DIM, m & int32_t(MASK));
1208  }
1209 
1210  void localToGlobalCoord(Coord& ijk) const
1211  {
1212  ijk += mOrigin;
1213  }
1214 
1215  Coord offsetToGlobalCoord(uint32_t n) const
1216  {
1218  this->localToGlobalCoord(ijk);
1219  return ijk;
1220  }
1221 
1222  ValueType getFirstValue() const { return mValues[0]; }
1223  ValueType getLastValue() const { return mValues[SIZE - 1]; }
1224  const ValueType& getValue(uint32_t i) const {return mValues[i];}
1225  const ValueType& getValue(const Coord& ijk) const {return mValues[CoordToOffset(ijk)];}
1226 
1227  template<typename OpT, typename... ArgsT>
1228  auto get(const Coord& ijk, ArgsT&&... args) const {return OpT::get(*this, CoordToOffset(ijk), args...);}
1229 
1230  template<typename OpT, typename... ArgsT>
1231  auto set(const Coord& ijk, ArgsT&&... args) {return OpT::set(*this, CoordToOffset(ijk), args...);}
1232 
1233 #ifndef NANOVDB_NEW_ACCESSOR_METHODS
1234  template<typename AccT>
1235  const ValueType& getValueAndCache(const Coord& ijk, const AccT&) const
1236  {
1237  return mValues[CoordToOffset(ijk)];
1238  }
1239 
1240  template<typename AccT>
1241  void setValueAndCache(const Coord& ijk, const ValueType& value, const AccT&)
1242  {
1243  const uint32_t n = CoordToOffset(ijk);
1244  mValueMask.setOn(n);
1245  mValues[n] = value;
1246  }
1247 
1248  template<typename AccT>
1249  void setValueOnAndCache(const Coord& ijk, const AccT&)
1250  {
1251  const uint32_t n = CoordToOffset(ijk);
1252  mValueMask.setOn(n);
1253  }
1254 
1255  template<typename AccT>
1256  bool isActiveAndCache(const Coord& ijk, const AccT&) const
1257  {
1258  return mValueMask.isOn(CoordToOffset(ijk));
1259  }
1260 #endif
1261 
1262  void setValue(uint32_t n, const ValueType& value)
1263  {
1264  mValueMask.setOn(n);
1265  mValues[n] = value;
1266  }
1267  void setValue(const Coord& ijk, const ValueType& value){this->setValue(CoordToOffset(ijk), value);}
1268 
1269  void merge(LeafNode &other)
1270  {
1271  other.mValueMask -= mValueMask;
1272  for (auto iter = other.mValueMask.beginOn(); iter; ++iter) {
1273  const uint32_t n = *iter;
1274  mValues[n] = other.mValues[n];
1275  }
1276  mValueMask |= other.mValueMask;
1277  }
1278 
1279  template<typename T>
1281  signedFloodFill(T outside);
1282 
1283 }; // build::LeafNode<T>
1284 
1285 //================================================================================================
1286 
1287 template <>
1289 {
1290  using ValueType = bool;
1293  static constexpr uint32_t LOG2DIM = 3;
1294  static constexpr uint32_t TOTAL = LOG2DIM; // needed by parent nodes
1295  static constexpr uint32_t DIM = 1u << TOTAL;
1296  static constexpr uint32_t SIZE = 1u << 3 * LOG2DIM; // total number of voxels represented by this node
1297  static constexpr uint32_t MASK = DIM - 1; // mask for bit operations
1298  static constexpr uint32_t LEVEL = 0; // level 0 = leaf
1299  static constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node
1301  template<bool ON>
1302  using MaskIterT = typename Mask<LOG2DIM>::template Iterator<ON>;
1304 
1307  union {
1309  uint64_t mDstOffset;
1310  };
1311 
1312  /// @brief Visits all active values in a leaf node
1313  class ValueOnIterator : public MaskIterT<true>
1314  {
1315  using BaseT = MaskIterT<true>;
1316  const LeafNode *mParent;
1317  public:
1318  ValueOnIterator() : BaseT(), mParent(nullptr) {}
1319  ValueOnIterator(const LeafNode* parent) : BaseT(parent->mValueMask.beginOn()), mParent(parent) {}
1320  ValueOnIterator& operator=(const ValueOnIterator&) = default;
1321  bool operator*() const {NANOVDB_ASSERT(*this); return true;}
1322  Coord getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BaseT::pos());}
1323  }; // Member class ValueOnIterator
1324 
1325  ValueOnIterator beginValueOn() {return ValueOnIterator(this);}
1326  ValueOnIterator cbeginValueOn() const {return ValueOnIterator(this);}
1327 
1328  /// @brief Visits all inactive values in a leaf node
1329  class ValueOffIterator : public MaskIterT<false>
1330  {
1331  using BaseT = MaskIterT<false>;
1332  const LeafNode *mParent;
1333  public:
1334  ValueOffIterator() : BaseT(), mParent(nullptr) {}
1335  ValueOffIterator(const LeafNode* parent) : BaseT(parent->mValueMask.beginOff()), mParent(parent) {}
1336  ValueOffIterator& operator=(const ValueOffIterator&) = default;
1337  bool operator*() const {NANOVDB_ASSERT(*this); return false;}
1338  Coord getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BaseT::pos());}
1339  }; // Member class ValueOffIterator
1340 
1341  ValueOffIterator beginValueOff() {return ValueOffIterator(this);}
1342  ValueOffIterator cbeginValueOff() const {return ValueOffIterator(this);}
1343 
1344  /// @brief Visits all values in a leaf node, i.e. both active and inactive values
1345  class ValueIterator
1346  {
1347  const LeafNode *mParent;
1348  uint32_t mPos;
1349  public:
1350  ValueIterator() : mParent(nullptr), mPos(1u << 3 * LOG2DIM) {}
1351  ValueIterator(const LeafNode* parent) : mParent(parent), mPos(0) {NANOVDB_ASSERT(parent);}
1352  ValueIterator(const ValueIterator&) = default;
1353  ValueIterator& operator=(const ValueIterator&) = default;
1354  bool operator*() const { NANOVDB_ASSERT(*this); return mParent->mValueMask.isOn(mPos);}
1355  Coord getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(mPos);}
1356  bool isActive() const { NANOVDB_ASSERT(*this); return mParent->mValueMask.isOn(mPos);}
1357  operator bool() const {return mPos < SIZE;}
1358  ValueIterator& operator++() {++mPos; return *this;}
1360  auto tmp = *this;
1361  ++(*this);
1362  return tmp;
1363  }
1364  }; // Member class ValueIterator
1365 
1366  ValueIterator beginValue() {return ValueIterator(this);}
1367  ValueIterator cbeginValueAll() const {return ValueIterator(this);}
1368 
1369  LeafNode(const Coord& ijk, const ValueType&, bool state)
1370  : mOrigin(ijk & ~MASK)
1371  , mValueMask(state) //invalid
1372  , mDstOffset(0)
1373  {
1374  }
1375  LeafNode(const LeafNode&) = delete; // disallow copy-construction
1376  LeafNode(LeafNode&&) = delete; // disallow move construction
1377  LeafNode& operator=(const LeafNode&) = delete; // disallow copy assignment
1378  LeafNode& operator=(LeafNode&&) = delete; // disallow move assignment
1379  ~LeafNode() = default;
1380 
1381  const Mask<LOG2DIM>& valueMask() const {return mValueMask;}
1382  const Mask<LOG2DIM>& getValueMask() const {return mValueMask;}
1383  const Coord& origin() const {return mOrigin;}
1384 
1385  /// @brief Return the linear offset corresponding to the given coordinate
1386  static uint32_t CoordToOffset(const Coord& ijk)
1387  {
1388  return ((ijk[0] & int32_t(MASK)) << (2 * LOG2DIM)) +
1389  ((ijk[1] & int32_t(MASK)) << LOG2DIM) +
1390  (ijk[2] & int32_t(MASK));
1391  }
1392 
1393  static Coord OffsetToLocalCoord(uint32_t n)
1394  {
1395  NANOVDB_ASSERT(n < SIZE);
1396  const int32_t m = n & ((1 << 2 * LOG2DIM) - 1);
1397  return Coord(n >> 2 * LOG2DIM, m >> LOG2DIM, m & int32_t(MASK));
1398  }
1399 
1400  void localToGlobalCoord(Coord& ijk) const {ijk += mOrigin;}
1401 
1402  Coord offsetToGlobalCoord(uint32_t n) const
1403  {
1405  this->localToGlobalCoord(ijk);
1406  return ijk;
1407  }
1408 
1409  bool getFirstValue() const { return mValueMask.isOn(0); }
1410  bool getLastValue() const { return mValueMask.isOn(SIZE - 1); }
1411  bool getValue(uint32_t i) const {return mValueMask.isOn(i);}
1412  bool getValue(const Coord& ijk) const {return mValueMask.isOn(CoordToOffset(ijk));}
1413 
1414  template<typename OpT, typename... ArgsT>
1415  auto get(const Coord& ijk, ArgsT&&... args) const {return OpT::get(*this, CoordToOffset(ijk), args...);}
1416 
1417  template<typename OpT, typename... ArgsT>
1418  auto set(const Coord& ijk, ArgsT&&... args) {return OpT::set(*this, CoordToOffset(ijk), args...);}
1419 
1420 #ifndef NANOVDB_NEW_ACCESSOR_METHODS
1421  template<typename AccT>
1422  bool getValueAndCache(const Coord& ijk, const AccT&) const
1423  {
1424  return mValueMask.isOn(CoordToOffset(ijk));
1425  }
1426 
1427  template<typename AccT>
1428  void setValueAndCache(const Coord& ijk, bool, const AccT&)
1429  {
1430  const uint32_t n = CoordToOffset(ijk);
1431  mValueMask.setOn(n);
1432  }
1433 
1434  template<typename AccT>
1435  void setValueOnAndCache(const Coord& ijk, const AccT&)
1436  {
1437  const uint32_t n = CoordToOffset(ijk);
1438  mValueMask.setOn(n);
1439  }
1440 
1441  template<typename AccT>
1442  bool isActiveAndCache(const Coord& ijk, const AccT&) const
1443  {
1444  return mValueMask.isOn(CoordToOffset(ijk));
1445  }
1446 #endif
1447 
1448  void setValue(uint32_t n, bool) {mValueMask.setOn(n);}
1449  void setValue(const Coord& ijk) {mValueMask.setOn(CoordToOffset(ijk));}
1450 
1451  void merge(LeafNode &other)
1452  {
1453  mValueMask |= other.mValueMask;
1454  }
1455 
1456 }; // build::LeafNode<ValueMask>
1457 
1458 //================================================================================================
1459 
1460 template <>
1461 struct LeafNode<bool>
1462 {
1463  using ValueType = bool;
1466  static constexpr uint32_t LOG2DIM = 3;
1467  static constexpr uint32_t TOTAL = LOG2DIM; // needed by parent nodes
1468  static constexpr uint32_t DIM = 1u << TOTAL;
1469  static constexpr uint32_t SIZE = 1u << 3 * LOG2DIM; // total number of voxels represented by this node
1470  static constexpr uint32_t MASK = DIM - 1; // mask for bit operations
1471  static constexpr uint32_t LEVEL = 0; // level 0 = leaf
1472  static constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node
1474  template<bool ON>
1475  using MaskIterT = typename Mask<LOG2DIM>::template Iterator<ON>;
1477 
1480  union {
1482  uint64_t mDstOffset;
1483  };
1484 
1485  /// @brief Visits all active values in a leaf node
1486  class ValueOnIterator : public MaskIterT<true>
1487  {
1488  using BaseT = MaskIterT<true>;
1489  const LeafNode *mParent;
1490  public:
1491  ValueOnIterator() : BaseT(), mParent(nullptr) {}
1492  ValueOnIterator(const LeafNode* parent) : BaseT(parent->mValueMask.beginOn()), mParent(parent) {}
1493  ValueOnIterator& operator=(const ValueOnIterator&) = default;
1494  bool operator*() const {NANOVDB_ASSERT(*this); return mParent->mValues.isOn(BaseT::pos());}
1495  Coord getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BaseT::pos());}
1496  }; // Member class ValueOnIterator
1497 
1498  ValueOnIterator beginValueOn() {return ValueOnIterator(this);}
1499  ValueOnIterator cbeginValueOn() const {return ValueOnIterator(this);}
1500 
1501  /// @brief Visits all inactive values in a leaf node
1502  class ValueOffIterator : public MaskIterT<false>
1503  {
1504  using BaseT = MaskIterT<false>;
1505  const LeafNode *mParent;
1506  public:
1507  ValueOffIterator() : BaseT(), mParent(nullptr) {}
1508  ValueOffIterator(const LeafNode* parent) : BaseT(parent->mValueMask.beginOff()), mParent(parent) {}
1509  ValueOffIterator& operator=(const ValueOffIterator&) = default;
1510  bool operator*() const {NANOVDB_ASSERT(*this); return mParent->mValues.isOn(BaseT::pos());}
1511  Coord getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BaseT::pos());}
1512  }; // Member class ValueOffIterator
1513 
1514  ValueOffIterator beginValueOff() {return ValueOffIterator(this);}
1515  ValueOffIterator cbeginValueOff() const {return ValueOffIterator(this);}
1516 
1517  /// @brief Visits all values in a leaf node, i.e. both active and inactive values
1518  class ValueIterator
1519  {
1520  const LeafNode *mParent;
1521  uint32_t mPos;
1522  public:
1523  ValueIterator() : mParent(nullptr), mPos(1u << 3 * LOG2DIM) {}
1524  ValueIterator(const LeafNode* parent) : mParent(parent), mPos(0) {NANOVDB_ASSERT(parent);}
1525  ValueIterator(const ValueIterator&) = default;
1526  ValueIterator& operator=(const ValueIterator&) = default;
1527  bool operator*() const { NANOVDB_ASSERT(*this); return mParent->mValues.isOn(mPos);}
1528  Coord getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(mPos);}
1529  bool isActive() const { NANOVDB_ASSERT(*this); return mParent->mValueMask.isOn(mPos);}
1530  operator bool() const {return mPos < SIZE;}
1531  ValueIterator& operator++() {++mPos; return *this;}
1533  auto tmp = *this;
1534  ++(*this);
1535  return tmp;
1536  }
1537  }; // Member class ValueIterator
1538 
1539  ValueIterator beginValue() {return ValueIterator(this);}
1540  ValueIterator cbeginValueAll() const {return ValueIterator(this);}
1541 
1542  LeafNode(const Coord& ijk, bool value, bool state)
1543  : mOrigin(ijk & ~MASK)
1544  , mValueMask(state)
1545  , mValues(value)
1546  , mDstOffset(0)
1547  {
1548  }
1549  LeafNode(const LeafNode&) = delete; // disallow copy-construction
1550  LeafNode(LeafNode&&) = delete; // disallow move construction
1551  LeafNode& operator=(const LeafNode&) = delete; // disallow copy assignment
1552  LeafNode& operator=(LeafNode&&) = delete; // disallow move assignment
1553  ~LeafNode() = default;
1554 
1555  const Mask<LOG2DIM>& valueMask() const {return mValueMask;}
1556  const Mask<LOG2DIM>& getValueMask() const {return mValueMask;}
1557  const Coord& origin() const {return mOrigin;}
1558 
1559  /// @brief Return the linear offset corresponding to the given coordinate
1560  static uint32_t CoordToOffset(const Coord& ijk)
1561  {
1562  return ((ijk[0] & int32_t(MASK)) << (2 * LOG2DIM)) +
1563  ((ijk[1] & int32_t(MASK)) << LOG2DIM) +
1564  (ijk[2] & int32_t(MASK));
1565  }
1566 
1567  static Coord OffsetToLocalCoord(uint32_t n)
1568  {
1569  NANOVDB_ASSERT(n < SIZE);
1570  const int32_t m = n & ((1 << 2 * LOG2DIM) - 1);
1571  return Coord(n >> 2 * LOG2DIM, m >> LOG2DIM, m & int32_t(MASK));
1572  }
1573 
1574  void localToGlobalCoord(Coord& ijk) const
1575  {
1576  ijk += mOrigin;
1577  }
1578 
1579  Coord offsetToGlobalCoord(uint32_t n) const
1580  {
1582  this->localToGlobalCoord(ijk);
1583  return ijk;
1584  }
1585  bool getFirstValue() const { return mValues.isOn(0); }
1586  bool getLastValue() const { return mValues.isOn(SIZE - 1); }
1587 
1588  bool getValue(uint32_t i) const {return mValues.isOn(i);}
1589  bool getValue(const Coord& ijk) const
1590  {
1591  return mValues.isOn(CoordToOffset(ijk));
1592  }
1593 #ifndef NANOVDB_NEW_ACCESSOR_METHODS
1594  template<typename AccT>
1595  bool isActiveAndCache(const Coord& ijk, const AccT&) const
1596  {
1597  return mValueMask.isOn(CoordToOffset(ijk));
1598  }
1599 
1600  template<typename AccT>
1601  bool getValueAndCache(const Coord& ijk, const AccT&) const
1602  {
1603  return mValues.isOn(CoordToOffset(ijk));
1604  }
1605 
1606  template<typename AccT>
1607  void setValueAndCache(const Coord& ijk, bool value, const AccT&)
1608  {
1609  const uint32_t n = CoordToOffset(ijk);
1610  mValueMask.setOn(n);
1611  mValues.setOn(n);
1612  }
1613 
1614  template<typename AccT>
1615  void setValueOnAndCache(const Coord& ijk, const AccT&)
1616  {
1617  const uint32_t n = CoordToOffset(ijk);
1618  mValueMask.setOn(n);
1619  }
1620 #endif
1621 
1622  void setValue(uint32_t n, bool value)
1623  {
1624  mValueMask.setOn(n);
1625  mValues.set(n, value);
1626  }
1627  void setValue(const Coord& ijk, bool value) {return this->setValue(CoordToOffset(ijk), value);}
1628 
1629  void merge(LeafNode &other)
1630  {
1631  mValues |= other.mValues;
1632  mValueMask |= other.mValueMask;
1633  }
1634 
1635 }; // build::LeafNode<bool>
1636 
1637 //================================================================================================
1638 
1639 template<typename BuildT>
1640 template<typename T>
1643 {
1644  const uint32_t first = *mValueMask.beginOn();
1645  if (first < SIZE) {
1646  bool xInside = mValues[first] < 0, yInside = xInside, zInside = xInside;
1647  for (uint32_t x = 0; x != DIM; ++x) {
1648  const uint32_t x00 = x << (2 * LOG2DIM);
1649  if (mValueMask.isOn(x00))
1650  xInside = mValues[x00] < 0; // element(x, 0, 0)
1651  yInside = xInside;
1652  for (uint32_t y = 0; y != DIM; ++y) {
1653  const uint32_t xy0 = x00 + (y << LOG2DIM);
1654  if (mValueMask.isOn(xy0))
1655  yInside = mValues[xy0] < 0; // element(x, y, 0)
1656  zInside = yInside;
1657  for (uint32_t z = 0; z != (1 << LOG2DIM); ++z) {
1658  const uint32_t xyz = xy0 + z; // element(x, y, z)
1659  if (mValueMask.isOn(xyz)) {
1660  zInside = mValues[xyz] < 0;
1661  } else {
1662  mValues[xyz] = zInside ? -outside : outside;
1663  }
1664  }
1665  }
1666  }
1667  }
1668 } // build::LeafNode<T>::signedFloodFill
1669 
1670 // ----------------------------> ValueAccessor <--------------------------------------
1671 
1672 template<typename BuildT>
1674 {
1681 
1683  : mRoot(root)
1685  , mNode{nullptr, nullptr, nullptr}
1686  {
1687  }
1688  ValueAccessor(ValueAccessor&&) = default; // allow move construction
1689  ValueAccessor(const ValueAccessor&) = delete; // disallow copy construction
1690  ValueType getValue(int i, int j, int k) const {return this->getValue(Coord(i,j,k));}
1691  template<typename NodeT>
1692  bool isCached(const Coord& ijk) const
1693  {
1694  return (ijk[0] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][0] &&
1695  (ijk[1] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][1] &&
1696  (ijk[2] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][2];
1697  }
1698 
1699  template <typename OpT, typename... ArgsT>
1700  auto get(const Coord& ijk, ArgsT&&... args) const
1701  {
1702  if (this->template isCached<LeafT>(ijk)) {
1703  return ((const LeafT*)mNode[0])->template get<OpT>(ijk, args...);
1704  } else if (this->template isCached<Node1>(ijk)) {
1705  return ((const Node1*)mNode[1])->template getAndCache<OpT>(ijk, *this, args...);
1706  } else if (this->template isCached<Node2>(ijk)) {
1707  return ((const Node2*)mNode[2])->template getAndCache<OpT>(ijk, *this, args...);
1708  }
1709  return mRoot.template getAndCache<OpT>(ijk, *this, args...);
1710  }
1711 
1712  template <typename OpT, typename... ArgsT>
1713  auto set(const Coord& ijk, ArgsT&&... args) const
1714  {
1715  if (this->template isCached<LeafT>(ijk)) {
1716  return ((LeafT*)mNode[0])->template set<OpT>(ijk, args...);
1717  } else if (this->template isCached<Node1>(ijk)) {
1718  return ((Node1*)mNode[1])->template setAndCache<OpT>(ijk, *this, args...);
1719  } else if (this->template isCached<Node2>(ijk)) {
1720  return ((Node2*)mNode[2])->template setAndCache<OpT>(ijk, *this, args...);
1721  }
1722  return mRoot.template setAndCache<OpT>(ijk, *this, args...);
1723  }
1724 
1725 #ifdef NANOVDB_NEW_ACCESSOR_METHODS
1726  ValueType getValue(const Coord& ijk) const {return this->template get<GetValue<BuildT>>(ijk);}
1727  LeafT* setValue(const Coord& ijk, const ValueType& value) {return this->template set<SetValue<BuildT>>(ijk, value);}
1728  LeafT* setValueOn(const Coord& ijk) {return this->template set<SetValue<BuildT>>(ijk);}
1729  LeafT& touchLeaf(const Coord& ijk) {return this->template set<TouchLeaf<BuildT>>(ijk);}
1730  bool isActive(const Coord& ijk) const {return this->template get<GetState<BuildT>>(ijk);}
1731 #else
1732  ValueType getValue(const Coord& ijk) const
1733  {
1734  if (this->template isCached<LeafT>(ijk)) {
1735  return ((LeafT*)mNode[0])->getValueAndCache(ijk, *this);
1736  } else if (this->template isCached<Node1>(ijk)) {
1737  return ((Node1*)mNode[1])->getValueAndCache(ijk, *this);
1738  } else if (this->template isCached<Node2>(ijk)) {
1739  return ((Node2*)mNode[2])->getValueAndCache(ijk, *this);
1740  }
1741  return mRoot.getValueAndCache(ijk, *this);
1742  }
1743 
1744  /// @brief Sets value in a leaf node and returns it.
1745  LeafT* setValue(const Coord& ijk, const ValueType& value)
1746  {
1747  if (this->template isCached<LeafT>(ijk)) {
1748  ((LeafT*)mNode[0])->setValueAndCache(ijk, value, *this);
1749  } else if (this->template isCached<Node1>(ijk)) {
1750  ((Node1*)mNode[1])->setValueAndCache(ijk, value, *this);
1751  } else if (this->template isCached<Node2>(ijk)) {
1752  ((Node2*)mNode[2])->setValueAndCache(ijk, value, *this);
1753  } else {
1754  mRoot.setValueAndCache(ijk, value, *this);
1755  }
1756  NANOVDB_ASSERT(this->isCached<LeafT>(ijk));
1757  return (LeafT*)mNode[0];
1758  }
1759  void setValueOn(const Coord& ijk)
1760  {
1761  if (this->template isCached<LeafT>(ijk)) {
1762  ((LeafT*)mNode[0])->setValueOnAndCache(ijk, *this);
1763  } else if (this->template isCached<Node1>(ijk)) {
1764  ((Node1*)mNode[1])->setValueOnAndCache(ijk, *this);
1765  } else if (this->template isCached<Node2>(ijk)) {
1766  ((Node2*)mNode[2])->setValueOnAndCache(ijk, *this);
1767  } else {
1768  mRoot.setValueOnAndCache(ijk, *this);
1769  }
1770  }
1771  void touchLeaf(const Coord& ijk) const
1772  {
1773  if (this->template isCached<LeafT>(ijk)) {
1774  return;
1775  } else if (this->template isCached<Node1>(ijk)) {
1776  ((Node1*)mNode[1])->touchLeafAndCache(ijk, *this);
1777  } else if (this->template isCached<Node2>(ijk)) {
1778  ((Node2*)mNode[2])->touchLeafAndCache(ijk, *this);
1779  } else {
1780  mRoot.touchLeafAndCache(ijk, *this);
1781  }
1782  }
1783  bool isActive(const Coord& ijk) const
1784  {
1785  if (this->template isCached<LeafT>(ijk)) {
1786  return ((LeafT*)mNode[0])->isActiveAndCache(ijk, *this);
1787  } else if (this->template isCached<Node1>(ijk)) {
1788  return ((Node1*)mNode[1])->isActiveAndCache(ijk, *this);
1789  } else if (this->template isCached<Node2>(ijk)) {
1790  return ((Node2*)mNode[2])->isActiveAndCache(ijk, *this);
1791  }
1792  return mRoot.isActiveAndCache(ijk, *this);
1793  }
1794 #endif
1795 
1796  bool isValueOn(const Coord& ijk) const { return this->isActive(ijk); }
1797  template<typename NodeT>
1798  void insert(const Coord& ijk, NodeT* node) const
1799  {
1800  mKeys[NodeT::LEVEL] = ijk & ~NodeT::MASK;
1801  mNode[NodeT::LEVEL] = node;
1802  }
1804  mutable Coord mKeys[3];
1805  mutable void* mNode[3];
1806 }; // build::ValueAccessor<BuildT>
1807 
1808 // ----------------------------> Tree <--------------------------------------
1809 
1810 template<typename BuildT>
1811 struct Tree
1812 {
1820 
1822  std::mutex mMutex;
1823 
1824  Tree(const ValueType &background) : mRoot(background) {}
1825  Tree(const Tree&) = delete; // disallow copy construction
1826  Tree(Tree&&) = delete; // disallow move construction
1827  Tree& tree() {return *this;}
1828  RootNodeType& root() {return mRoot;}
1829  ValueType getValue(const Coord& ijk) const {return mRoot.getValue(ijk);}
1830  ValueType getValue(int i, int j, int k) const {return this->getValue(Coord(i,j,k));}
1831  void setValue(const Coord& ijk, const ValueType &value) {mRoot.setValue(ijk, value);}
1832  std::array<size_t,3> nodeCount() const
1833  {
1834  std::array<size_t, 3> count{0,0,0};
1836  return count;
1837  }
1838  /// @brief regular accessor for thread-safe reading and non-thread-safe writing
1840  /// @brief special accessor for thread-safe writing only
1842 };// build::Tree<BuildT>
1843 
1844 // ----------------------------> Tree::WriteAccessor <--------------------------------------
1845 
1846 template<typename BuildT>
1847 struct Tree<BuildT>::WriteAccessor
1848 {
1850  using ValueType = typename AccT::ValueType;
1851  using LeafT = typename AccT::LeafT;
1852  using Node1 = typename AccT::Node1;
1853  using Node2 = typename AccT::Node2;
1855 
1856  WriteAccessor(RootNodeType& parent, std::mutex &mx)
1857  : mParent(parent)
1858  , mRoot(parent.mBackground)
1859  , mAcc(mRoot)
1860  , mMutex(mx)
1861  {
1862  }
1863  WriteAccessor(const WriteAccessor&) = delete; // disallow copy construction
1864  WriteAccessor(WriteAccessor&&) = default; // allow move construction
1865  ~WriteAccessor() { this->merge(); }
1866  void merge()
1867  {
1868  mMutex.lock();
1869  mParent.merge(mRoot);
1870  mMutex.unlock();
1871  }
1872  inline void setValueOn(const Coord& ijk) {mAcc.setValueOn(ijk);}
1873  inline void setValue(const Coord& ijk, const ValueType &value) {mAcc.setValue(ijk, value);}
1874 
1875  RootNodeType &mParent, mRoot;
1877  std::mutex &mMutex;
1878 }; // build::Tree<BuildT>::WriteAccessor
1879 
1880 // ----------------------------> Grid <--------------------------------------
1881 
1882 template<typename BuildT>
1883 struct Grid : public Tree<BuildT>
1884 {
1885  using BuildType = BuildT;
1892 
1897 
1898  Grid(const ValueType &background, const std::string &name = "", GridClass gClass = GridClass::Unknown)
1899  : TreeType(background)
1900  , mGridClass(gClass)
1901  , mGridType(mapToGridType<BuildT>())
1902  , mName(name)
1903  {
1904  mMap.set(1.0, Vec3d(0.0), 1.0);
1905  }
1906  TreeType& tree() {return *this;}
1907  const GridType& gridType() const { return mGridType; }
1908  const GridClass& gridClass() const { return mGridClass; }
1909  const Map& map() const { return mMap; }
1910  void setTransform(double scale=1.0, const Vec3d &translation = Vec3d(0.0)) {mMap.set(scale, translation, 1.0);}
1911  const std::string& gridName() const { return mName; }
1912  const std::string& getName() const { return mName; }
1913  void setName(const std::string &name) { mName = name; }
1914  /// @brief Sets grids values in domain of the @a bbox to those returned by the specified @a func with the
1915  /// expected signature [](const Coord&)->ValueType.
1916  ///
1917  /// @note If @a func returns a value equal to the background value of the input grid at a
1918  /// specific voxel coordinate, then the active state of that coordinate is off! Else the value
1919  /// value is set and the active state is on. This is done to allow for sparse grids to be generated.
1920  ///
1921  /// @param func Functor used to evaluate the grid values in the @a bbox
1922  /// @param bbox Coordinate bounding-box over which the grid values will be set.
1923  /// @param delta Specifies a lower threshold value for rendering (optional). Typically equals the voxel size
1924  /// for level sets and otherwise it's zero.
1925  template <typename Func>
1926  void operator()(const Func& func, const CoordBBox& bbox, ValueType delta = ValueType(0));
1927 };// build::Grid
1928 
1929 template <typename BuildT>
1930 template <typename Func>
1931 void Grid<BuildT>::operator()(const Func& func, const CoordBBox& bbox, ValueType delta)
1932 {
1933  auto &root = this->tree().root();
1934 #if __cplusplus >= 201703L
1935  static_assert(is_same<ValueType, typename std::invoke_result<Func,const Coord&>::type>::value, "GridBuilder: mismatched ValueType");
1936 #else// invoke_result was introduced in C++17 and result_of was removed in C++20
1937  static_assert(is_same<ValueType, typename std::result_of<Func(const Coord&)>::type>::value, "GridBuilder: mismatched ValueType");
1938 #endif
1939  const CoordBBox leafBBox(bbox[0] >> Node0::TOTAL, bbox[1] >> Node0::TOTAL);
1940  std::mutex mutex;
1941  forEach(leafBBox, [&](const CoordBBox& b) {
1942  Node0* leaf = nullptr;
1943  for (auto it = b.begin(); it; ++it) {
1944  Coord min(*it << Node0::TOTAL), max(min + Coord(Node0::DIM - 1));
1945  const CoordBBox b(min.maxComponent(bbox.min()),
1946  max.minComponent(bbox.max()));// crop
1947  if (leaf == nullptr) {
1948  leaf = new Node0(b[0], root.mBackground, false);
1949  } else {
1950  leaf->mOrigin = b[0] & ~Node0::MASK;
1951  NANOVDB_ASSERT(leaf->mValueMask.isOff());
1952  }
1953  leaf->mDstOffset = 0;// no prune
1954  for (auto ijk = b.begin(); ijk; ++ijk) {
1955  const auto v = func(*ijk);// call functor
1956  if (v != root.mBackground) leaf->setValue(*ijk, v);// don't insert background values
1957  }
1958  if (!leaf->mValueMask.isOff()) {// has active values
1959  if (leaf->mValueMask.isOn()) {// only active values
1960  const auto first = leaf->getFirstValue();
1961  int n=1;
1962  while (n<512) {// 8^3 = 512
1963  if (leaf->mValues[n++] != first) break;
1964  }
1965  if (n == 512) leaf->mDstOffset = 1;// prune below
1966  }
1967  std::lock_guard<std::mutex> guard(mutex);
1968  NANOVDB_ASSERT(leaf != nullptr);
1969  root.addNode(leaf);
1970  NANOVDB_ASSERT(leaf == nullptr);
1971  }
1972  }// loop over sub-part of leafBBox
1973  if (leaf) delete leaf;
1974  });
1975 
1976  // Prune leaf and tile nodes
1977  for (auto it2 = root.mTable.begin(); it2 != root.mTable.end(); ++it2) {
1978  if (auto *upper = it2->second.child) {//upper level internal node
1979  for (auto it1 = upper->mChildMask.beginOn(); it1; ++it1) {
1980  auto *lower = upper->mTable[*it1].child;// lower level internal node
1981  for (auto it0 = lower->mChildMask.beginOn(); it0; ++it0) {
1982  auto *leaf = lower->mTable[*it0].child;// leaf nodes
1983  if (leaf->mDstOffset) {
1984  lower->mTable[*it0].value = leaf->getFirstValue();
1985  lower->mChildMask.setOff(*it0);
1986  lower->mValueMask.setOn(*it0);
1987  delete leaf;
1988  }
1989  }// loop over leaf nodes
1990  if (lower->mChildMask.isOff()) {//only tiles
1991  const auto first = lower->getFirstValue();
1992  int n=1;
1993  while (n < 4096) {// 16^3 = 4096
1994  if (lower->mTable[n++].value != first) break;
1995  }
1996  if (n == 4096) {// identical tile values so prune
1997  upper->mTable[*it1].value = first;
1998  upper->mChildMask.setOff(*it1);
1999  upper->mValueMask.setOn(*it1);
2000  delete lower;
2001  }
2002  }
2003  }// loop over lower internal nodes
2004  if (upper->mChildMask.isOff()) {//only tiles
2005  const auto first = upper->getFirstValue();
2006  int n=1;
2007  while (n < 32768) {// 32^3 = 32768
2008  if (upper->mTable[n++].value != first) break;
2009  }
2010  if (n == 32768) {// identical tile values so prune
2011  it2->second.value = first;
2012  it2->second.state = upper->mValueMask.isOn();
2013  it2->second.child = nullptr;
2014  delete upper;
2015  }
2016  }
2017  }// is child node of the root
2018  }// loop over root table
2019 }// build::Grid::operator()
2020 
2021 //================================================================================================
2022 
2023 template <typename T>
2025 template <typename T>
2027 template <typename T>
2029 template <typename T>
2031 template <typename T>
2033 
2051 
2052 // ----------------------------> NodeManager <--------------------------------------
2053 
2054 // GridT can be openvdb::Grid and nanovdb::build::Grid
2055 template <typename GridT>
2057 {
2058 public:
2059 
2060  using ValueType = typename GridT::ValueType;
2061  using BuildType = typename GridT::BuildType;
2062  using GridType = GridT;
2063  using TreeType = typename GridT::TreeType;
2064  using RootNodeType = typename TreeType::RootNodeType;
2065  static_assert(RootNodeType::LEVEL == 3, "NodeManager expected LEVEL=3");
2066  using Node2 = typename RootNodeType::ChildNodeType;
2067  using Node1 = typename Node2::ChildNodeType;
2068  using Node0 = typename Node1::ChildNodeType;
2069 
2070  NodeManager(GridT &grid) : mGrid(grid) {this->init();}
2071  void init()
2072  {
2073  mArray0.clear();
2074  mArray1.clear();
2075  mArray2.clear();
2076  auto counts = mGrid.tree().nodeCount();
2077  mArray0.reserve(counts[0]);
2078  mArray1.reserve(counts[1]);
2079  mArray2.reserve(counts[2]);
2080 
2081  for (auto it2 = mGrid.tree().root().cbeginChildOn(); it2; ++it2) {
2082  Node2 &upper = const_cast<Node2&>(*it2);
2083  mArray2.emplace_back(&upper);
2084  for (auto it1 = upper.cbeginChildOn(); it1; ++it1) {
2085  Node1 &lower = const_cast<Node1&>(*it1);
2086  mArray1.emplace_back(&lower);
2087  for (auto it0 = lower.cbeginChildOn(); it0; ++it0) {
2088  Node0 &leaf = const_cast<Node0&>(*it0);
2089  mArray0.emplace_back(&leaf);
2090  }// loop over leaf nodes
2091  }// loop over lower internal nodes
2092  }// loop over root node
2093  }
2094 
2095  /// @brief Return the number of tree nodes at the specified level
2096  /// @details 0 is leaf, 1 is lower internal, and 2 is upper internal level
2097  uint64_t nodeCount(int level) const
2098  {
2099  NANOVDB_ASSERT(level==0 || level==1 || level==2);
2100  return level==0 ? mArray0.size() : level==1 ? mArray1.size() : mArray2.size();
2101  }
2102 
2103  template <int LEVEL>
2104  typename enable_if<LEVEL==0, Node0&>::type node(int i) {return *mArray0[i];}
2105  template <int LEVEL>
2106  typename enable_if<LEVEL==0, const Node0&>::type node(int i) const {return *mArray0[i];}
2107  template <int LEVEL>
2108  typename enable_if<LEVEL==1, Node1&>::type node(int i) {return *mArray1[i];}
2109  template <int LEVEL>
2110  typename enable_if<LEVEL==1, const Node1&>::type node(int i) const {return *mArray1[i];}
2111  template <int LEVEL>
2112  typename enable_if<LEVEL==2, Node2&>::type node(int i) {return *mArray2[i];}
2113  template <int LEVEL>
2114  typename enable_if<LEVEL==2, const Node2&>::type node(int i) const {return *mArray2[i];}
2115 
2116  /// @brief Return the i'th leaf node with respect to breadth-first ordering
2117  const Node0& leaf(uint32_t i) const { return *mArray0[i]; }
2118  Node0& leaf(uint32_t i) { return *mArray0[i]; }
2119  uint64_t leafCount() const {return mArray0.size();}
2120 
2121  /// @brief Return the i'th lower internal node with respect to breadth-first ordering
2122  const Node1& lower(uint32_t i) const { return *mArray1[i]; }
2123  Node1& lower(uint32_t i) { return *mArray1[i]; }
2124  uint64_t lowerCount() const {return mArray1.size();}
2125 
2126  /// @brief Return the i'th upper internal node with respect to breadth-first ordering
2127  const Node2& upper(uint32_t i) const { return *mArray2[i]; }
2128  Node2& upper(uint32_t i) { return *mArray2[i]; }
2129  uint64_t upperCount() const {return mArray2.size();}
2130 
2131  RootNodeType& root() {return mGrid.tree().root();}
2132  const RootNodeType& root() const {return mGrid.tree().root();}
2133 
2134  TreeType& tree() {return mGrid.tree();}
2135  const TreeType& tree() const {return mGrid.tree();}
2136 
2137  GridType& grid() {return mGrid;}
2138  const GridType& grid() const {return mGrid;}
2139 
2140 protected:
2141 
2142  GridT &mGrid;
2143  std::vector<Node0*> mArray0; // leaf nodes
2144  std::vector<Node1*> mArray1; // lower internal nodes
2145  std::vector<Node2*> mArray2; // upper internal nodes
2146 
2147 };// NodeManager
2148 
2149 template <typename NodeManagerT>
2151 sdfToLevelSet(NodeManagerT &mgr)
2152 {
2153  mgr.grid().mGridClass = GridClass::LevelSet;
2154  // Note that the bottom-up flood filling is essential
2155  const auto outside = mgr.root().mBackground;
2156  forEach(0, mgr.leafCount(), 8, [&](const Range1D& r) {
2157  for (auto i = r.begin(); i != r.end(); ++i) mgr.leaf(i).signedFloodFill(outside);
2158  });
2159  forEach(0, mgr.lowerCount(), 1, [&](const Range1D& r) {
2160  for (auto i = r.begin(); i != r.end(); ++i) mgr.lower(i).signedFloodFill(outside);
2161  });
2162  forEach(0, mgr.upperCount(), 1, [&](const Range1D& r) {
2163  for (auto i = r.begin(); i != r.end(); ++i) mgr.upper(i).signedFloodFill(outside);
2164  });
2165  mgr.root().signedFloodFill(outside);
2166 }// sdfToLevelSet
2167 
2168 template <typename NodeManagerT>
2169 void levelSetToFog(NodeManagerT &mgr, bool rebuild = true)
2170 {
2171  using ValueType = typename NodeManagerT::ValueType;
2172  mgr.grid().mGridClass = GridClass::FogVolume;
2173  const ValueType d = -mgr.root().mBackground, w = 1.0f / d;
2174  std::atomic_bool prune{false};
2175  auto op = [&](ValueType& v) -> bool {
2176  if (v > ValueType(0)) {
2177  v = ValueType(0);
2178  return false;
2179  }
2180  v = v > d ? v * w : ValueType(1);
2181  return true;
2182  };
2183  forEach(0, mgr.leafCount(), 8, [&](const Range1D& r) {
2184  for (auto i = r.begin(); i != r.end(); ++i) {
2185  auto& leaf = mgr.leaf(i);
2186  for (uint32_t i = 0; i < 512u; ++i) leaf.mValueMask.set(i, op(leaf.mValues[i]));
2187  }
2188  });
2189  forEach(0, mgr.lowerCount(), 1, [&](const Range1D& r) {
2190  for (auto i = r.begin(); i != r.end(); ++i) {
2191  auto& node = mgr.lower(i);
2192  for (uint32_t i = 0; i < 4096u; ++i) {
2193  if (node.mChildMask.isOn(i)) {
2194  auto* leaf = node.mTable[i].child;
2195  if (leaf->mValueMask.isOff()) {// prune leaf node
2196  node.mTable[i].value = leaf->getFirstValue();
2197  node.mChildMask.setOff(i);
2198  delete leaf;
2199  prune = true;
2200  }
2201  } else {
2202  node.mValueMask.set(i, op(node.mTable[i].value));
2203  }
2204  }
2205  }
2206  });
2207  forEach(0, mgr.upperCount(), 1, [&](const Range1D& r) {
2208  for (auto i = r.begin(); i != r.end(); ++i) {
2209  auto& node = mgr.upper(i);
2210  for (uint32_t i = 0; i < 32768u; ++i) {
2211  if (node.mChildMask.isOn(i)) {// prune lower internal node
2212  auto* child = node.mTable[i].child;
2213  if (child->mChildMask.isOff() && child->mValueMask.isOff()) {
2214  node.mTable[i].value = child->getFirstValue();
2215  node.mChildMask.setOff(i);
2216  delete child;
2217  prune = true;
2218  }
2219  } else {
2220  node.mValueMask.set(i, op(node.mTable[i].value));
2221  }
2222  }
2223  }
2224  });
2225 
2226  for (auto it = mgr.root().mTable.begin(); it != mgr.root().mTable.end(); ++it) {
2227  auto* child = it->second.child;
2228  if (child == nullptr) {
2229  it->second.state = op(it->second.value);
2230  } else if (child->mChildMask.isOff() && child->mValueMask.isOff()) {
2231  it->second.value = child->getFirstValue();
2232  it->second.state = false;
2233  it->second.child = nullptr;
2234  delete child;
2235  prune = true;
2236  }
2237  }
2238  if (rebuild && prune) mgr.init();
2239 }// levelSetToFog
2240 
2241 // ----------------------------> Implementations of random access methods <--------------------------------------
2242 
2243 template <typename T>
2244 struct TouchLeaf {
2245  static BuildLeaf<T>& set(BuildLeaf<T> &leaf, uint32_t) {return leaf;}
2246 };// TouchLeaf<BuildT>
2247 
2248 /// @brief Implements Tree::getValue(Coord), i.e. return the value associated with a specific coordinate @c ijk.
2249 /// @tparam BuildT Build type of the grid being called
2250 /// @details The value at a coordinate maps to the background, a tile value or a leaf value.
2251 template <typename T>
2252 struct GetValue {
2253  static auto get(const BuildRoot<T> &root) {return root.mBackground;}
2254  static auto get(const BuildTile<T> &tile) {return tile.value;}
2255  static auto get(const BuildUpper<T> &node, uint32_t n) {return node.mTable[n].value;}
2256  static auto get(const BuildLower<T> &node, uint32_t n) {return node.mTable[n].value;}
2257  static auto get(const BuildLeaf<T> &leaf, uint32_t n) {return leaf.getValue(n);}
2258 };// GetValue<T>
2259 
2260 /// @brief Implements Tree::isActive(Coord)
2261 /// @tparam T Build type of the grid being called
2262 template <typename T>
2263 struct GetState {
2264  static bool get(const BuildRoot<T>&) {return false;}
2265  static bool get(const BuildTile<T> &tile) {return tile.state;}
2266  static bool get(const BuildUpper<T> &node, uint32_t n) {return node.mValueMask.isOn(n);}
2267  static bool get(const BuildLower<T> &node, uint32_t n) {return node.mValueMask.isOn(n);}
2268  static bool get(const BuildLeaf<T> &leaf, uint32_t n) {return leaf.mValueMask.isOn(n);}
2269 };// GetState<T>
2270 
2271 /// @brief Set the value and its state at the leaf level mapped to by ijk, and create the leaf node and branch if needed.
2272 /// @tparam T BuildType of the corresponding tree
2273 template <typename T>
2274 struct SetValue {
2275  static BuildLeaf<T>* set(BuildLeaf<T> &leaf, uint32_t n) {
2276  leaf.mValueMask.setOn(n);// always set the active bit
2277  return &leaf;
2278  }
2279  static BuildLeaf<T>* set(BuildLeaf<T> &leaf, uint32_t n, const typename BuildLeaf<T>::ValueType &v) {
2280  leaf.setValue(n, v);
2281  return &leaf;
2282  }
2283 };// SetValue<T>
2284 
2285 /// @brief Implements Tree::probeLeaf(Coord)
2286 /// @tparam T Build type of the grid being called
2287 template <typename T>
2288 struct ProbeValue {
2290  static bool get(const BuildRoot<T> &root, ValueT &v) {
2291  v = root.mBackground;
2292  return false;
2293  }
2294  static bool get(const BuildTile<T> &tile, ValueT &v) {
2295  v = tile.value;
2296  return tile.state;
2297  }
2298  static bool get(const BuildUpper<T> &node, uint32_t n, ValueT &v) {
2299  v = node.mTable[n].value;
2300  return node.mValueMask.isOn(n);
2301  }
2302  static bool get(const BuildLower<T> &node, uint32_t n, ValueT &v) {
2303  v = node.mTable[n].value;
2304  return node.mValueMask.isOn(n);
2305  }
2306  static bool get(const BuildLeaf<T> &leaf, uint32_t n, ValueT &v) {
2307  v = leaf.getValue(n);
2308  return leaf.isActive(n);
2309  }
2310 };// ProbeValue<T>
2311 
2312 } // namespace build
2313 
2314 } // namespace nanovdb
2315 
2316 #endif // NANOVDB_GRID_BUILDER_H_HAS_BEEN_INCLUDED
void getNodes(std::vector< NodeT * > &array)
Definition: GridBuilder.h:957
ValueOnIterator beginValueOn()
Definition: GridBuilder.h:1131
static constexpr uint32_t SIZE
Definition: GridBuilder.h:620
void setValueAndCache(const Coord &ijk, bool value, const AccT &)
Definition: GridBuilder.h:1607
ChildIterator cbeginChildOn() const
Definition: GridBuilder.h:662
uint64_t upperCount() const
Definition: GridBuilder.h:2129
const Mask< LOG2DIM > & valueMask() const
Definition: GridBuilder.h:1555
static constexpr uint32_t LEVEL
Definition: GridBuilder.h:1103
uint32_t tileCount() const
Definition: GridBuilder.h:234
GLint first
Definition: glcorearb.h:405
const MaskT & valueMask() const
Definition: GridBuilder.h:742
bool isActiveAndCache(const Coord &ijk, const AccT &) const
Definition: GridBuilder.h:1256
std::enable_if< std::is_floating_point< T >::value >::type signedFloodFill(T outside)
Definition: GridBuilder.h:579
static constexpr uint32_t MASK
Definition: GridBuilder.h:1102
ValueType getValue(const Coord &ijk) const
Definition: GridBuilder.h:1829
std::string upper(string_view a)
Return an all-upper case version of a (locale-independent).
Definition: strutil.h:402
InternalNode(const Coord &origin, const ValueType &value, bool state)
Definition: GridBuilder.h:723
void addChild(ChildT *&child)
Definition: GridBuilder.h:970
typename DataType::Tile Tile
Definition: NanoVDB.h:4333
LeafNode(const Coord &ijk, const ValueType &value, bool state)
Definition: GridBuilder.h:1174
bool isActiveAndCache(const Coord &ijk, AccT &acc) const
Definition: GridBuilder.h:929
TileIterator & operator=(const TileIterator &)=default
RootNodeType & root()
Definition: GridBuilder.h:1828
ValueOffIterator beginValueOff()
Definition: GridBuilder.h:1147
typename GridT::TreeType TreeType
Definition: GridBuilder.h:2063
ChildIterator beginChild()
Definition: GridBuilder.h:661
Bit-mask to encode active states and facilitate sequential iterators and a fast codec for I/O compres...
Definition: NanoVDB.h:2805
Signed (i, j, k) 32-bit integer coordinate class, similar to openvdb::math::Coord.
Definition: NanoVDB.h:1282
void setValueAndCache(const Coord &ijk, const ValueType &value, const AccT &)
Definition: GridBuilder.h:1241
DenseIterator & operator=(const DenseIterator &)=default
const Mask< LOG2DIM > & valueMask() const
Definition: GridBuilder.h:1192
const MaskT & getChildMask() const
Definition: GridBuilder.h:743
static BuildLeaf< T > & set(BuildLeaf< T > &leaf, uint32_t)
Definition: GridBuilder.h:2245
ChildIterator & operator=(const ChildIterator &)=default
DenseIterator beginDense()
Definition: GridBuilder.h:720
ValueOnIterator cbeginValueOn() const
Definition: GridBuilder.h:181
void localToGlobalCoord(Coord &ijk) const
Definition: GridBuilder.h:1574
void setValueOnAndCache(const Coord &ijk, const AccT &)
Definition: GridBuilder.h:1615
enable_if< LEVEL==1, const Node1 & >::type node(int i) const
Definition: GridBuilder.h:2110
std::vector< Node2 * > mArray2
Definition: GridBuilder.h:2145
bool isActiveAndCache(const Coord &ijk, const AccT &) const
Definition: GridBuilder.h:1442
DenseIterator cbeginChildAll() const
Definition: GridBuilder.h:721
static uint32_t CoordToOffset(const Coord &ijk)
Definition: GridBuilder.h:755
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:294
ValueType getFirstValue() const
Definition: GridBuilder.h:1222
void setValueOnAndCache(const Coord &ijk, const AccT &)
Definition: GridBuilder.h:1435
ValueIterator beginValue()
Definition: GridBuilder.h:146
GridClass
Classes (superset of OpenVDB) that are currently supported by NanoVDB.
Definition: NanoVDB.h:339
ValueOnIterator cbeginValueOn() const
Definition: GridBuilder.h:1326
const GLdouble * v
Definition: glcorearb.h:837
void touchLeafAndCache(const Coord &ijk, AccT &acc)
Definition: GridBuilder.h:425
ValueOnIterator & operator=(const ValueOnIterator &)=default
typename GridT::BuildType BuildType
Definition: GridBuilder.h:2061
GLsizei const GLchar *const * string
Definition: glcorearb.h:814
GLsizei const GLfloat * value
Definition: glcorearb.h:824
std::enable_if< std::is_floating_point< T >::value >::type signedFloodFill(T outside)
Definition: GridBuilder.h:1642
typename ChildT::ValueType ValueType
Definition: GridBuilder.h:613
ValueType getValue(int i, int j, int k) const
Definition: GridBuilder.h:340
static Coord CoordToKey(const Coord &ijk)
Definition: GridBuilder.h:254
const GridType & grid() const
Definition: GridBuilder.h:2138
Visits all values in a leaf node, i.e. both active and inactive values.
Definition: GridBuilder.h:1151
typename GridT::ValueType ValueType
Definition: GridBuilder.h:2060
bool getValue(const Coord &ijk) const
Definition: GridBuilder.h:1412
void setValue(const Coord &ijk, const ValueType &value)
Definition: GridBuilder.h:1873
typename Node2::LeafNodeType LeafNodeType
Definition: GridBuilder.h:53
static constexpr uint32_t LEVEL
Definition: GridBuilder.h:622
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:848
ValueType getValueAndCache(const Coord &ijk, AccT &acc) const
Definition: GridBuilder.h:374
ValueOffIterator cbeginValueOff() const
Definition: GridBuilder.h:1148
bool isActive(const Coord &ijk) const
Definition: GridBuilder.h:1783
Visits all tile values in this node, i.e. both inactive and active tiles.
Definition: GridBuilder.h:665
GLint level
Definition: glcorearb.h:108
typename RootNodeType::LeafNodeType LeafNodeType
Definition: GridBuilder.h:1680
ValueOffIterator beginValueOff()
Definition: GridBuilder.h:1514
__hostdev__ uint64_t first(uint32_t i) const
Definition: NanoVDB.h:5975
bool isActiveAndCache(const Coord &ijk, AccT &acc) const
Definition: GridBuilder.h:361
static constexpr uint32_t MASK
Definition: GridBuilder.h:621
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
const Node1 & lower(uint32_t i) const
Return the i'th lower internal node with respect to breadth-first ordering.
Definition: GridBuilder.h:2122
GLdouble s
Definition: glad.h:3009
Tree(const ValueType &background)
Definition: GridBuilder.h:1824
uint32_t nodeCount() const
Definition: GridBuilder.h:941
typename NanoNode< nanovdb::ValueMask, 0 >::Type NanoLeafT
Definition: GridBuilder.h:1108
__hostdev__ Coord & minComponent(const Coord &other)
Perform a component-wise minimum with the other Coord.
Definition: NanoVDB.h:1424
LeafNode(const Coord &ijk, const ValueType &, bool state)
Definition: GridBuilder.h:1369
void insert(const Coord &ijk, NodeT *node) const
Definition: GridBuilder.h:1798
Implements Tree::probeLeaf(Coord)
Definition: NanoVDB.h:3463
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
ValueOnIterator beginValueOn()
Definition: GridBuilder.h:180
void setValue(const Coord &ijk, const ValueType &value)
Definition: GridBuilder.h:1831
Maps one type (e.g. the build types above) to other (actual) types.
Definition: NanoVDB.h:628
__hostdev__ void setOff(uint32_t n)
Set the specified bit off.
Definition: NanoVDB.h:2991
void setValueOn(const Coord &ijk)
Definition: GridBuilder.h:1872
**But if you need a or simply need to know when the task has note that the like this
Definition: thread.h:617
MaskT< LOG2DIM > mValues
Definition: NanoVDB.h:5739
GLint y
Definition: glcorearb.h:103
ValueType getValue(const Coord &ijk) const
Definition: GridBuilder.h:324
const Node2 & upper(uint32_t i) const
Return the i'th upper internal node with respect to breadth-first ordering.
Definition: GridBuilder.h:2127
ValueType getValue(const Coord &ijk) const
Definition: GridBuilder.h:848
typename BuildLeaf< T >::ValueType ValueT
Definition: GridBuilder.h:2289
void localToGlobalCoord(Coord &ijk) const
Definition: GridBuilder.h:769
void forEach(RangeT range, const FuncT &func)
simple wrapper for tbb::parallel_for with a naive std fallback
Definition: ForEach.h:40
ValueIterator(const InternalNode *parent)
Definition: GridBuilder.h:671
void setValueOnAndCache(const Coord &ijk, AccT &acc)
Definition: GridBuilder.h:898
__hostdev__ void setOn(uint32_t n)
Set the specified bit on.
Definition: NanoVDB.h:2989
const ValueType & getValue(const Coord &ijk) const
Definition: GridBuilder.h:1225
Visits active tile values of this node only.
Definition: GridBuilder.h:682
InternalNode & operator=(const InternalNode &)=delete
typename RootNodeType::ChildNodeType Node2
Definition: GridBuilder.h:2066
void getNodes(std::vector< NodeT * > &array)
Definition: GridBuilder.h:462
uint64_t leafCount() const
Definition: GridBuilder.h:2119
const ValueType & background() const
Definition: GridBuilder.h:236
typename ChildT::LeafNodeType LeafNodeType
Definition: GridBuilder.h:616
ValueIterator & operator=(const ValueIterator &)=default
const std::string & gridName() const
Definition: GridBuilder.h:1911
bool isActiveAndCache(const Coord &ijk, const AccT &) const
Definition: GridBuilder.h:1595
ChildIterator cbeginChildOn() const
Definition: GridBuilder.h:112
#define NANOVDB_ASSERT(x)
Definition: NanoVDB.h:190
FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, const fill_t< Char > &fill) -> OutputIt
Definition: format.h:1262
ValueIterator cbeginValueAll() const
Definition: GridBuilder.h:1367
__hostdev__ OnIterator beginOn() const
Definition: NanoVDB.h:2904
static Coord OffsetToLocalCoord(uint32_t n)
Definition: GridBuilder.h:762
typename NanoNode< BuildType, 0 >::Type NanoLeafT
Definition: GridBuilder.h:1476
void nodeCount(std::array< size_t, 3 > &count) const
Definition: GridBuilder.h:747
ValueOffIterator cbeginValueOff() const
Definition: GridBuilder.h:1342
void setValueOnAndCache(const Coord &ijk, const AccT &)
Definition: GridBuilder.h:1249
typename BuildToValueMap< BuildT >::type ValueType
Definition: GridBuilder.h:1813
void setTransform(double scale=1.0, const Vec3d &translation=Vec3d(0.0))
Definition: GridBuilder.h:1910
Visits all active values in a leaf node.
Definition: GridBuilder.h:1119
ValueOnIterator cbeginValueOn() const
Definition: GridBuilder.h:1132
static constexpr uint32_t SIZE
Definition: GridBuilder.h:1101
A unified wrapper for tbb::parallel_for and a naive std::thread fallback.
const GridClass & gridClass() const
Definition: GridBuilder.h:1908
void setValue(const Coord &ijk, const ValueType &value)
Definition: GridBuilder.h:856
typename NanoNode< BuildType, 0 >::Type NanoLeafT
Definition: GridBuilder.h:1303
LeafNode(const Coord &ijk, bool value, bool state)
Definition: GridBuilder.h:1542
ValueIterator & operator=(const ValueIterator &)=default
static Coord OffsetToLocalCoord(uint32_t n)
Definition: GridBuilder.h:1567
ValueOffIterator cbeginValueOff() const
Definition: GridBuilder.h:1515
void addChild(ChildT *&child)
Definition: GridBuilder.h:477
typename Node2::BuildType BuildType
Definition: GridBuilder.h:51
void set(const MatT &mat, const MatT &invMat, const Vec3T &translate, double taper=1.0)
Initialize the member data from 3x3 or 4x4 matrices.
Definition: NanoVDB.h:3278
bool getValue(const Coord &ijk) const
Definition: GridBuilder.h:1589
GA_API const UT_StringHolder scale
static Coord OffsetToLocalCoord(uint32_t n)
Definition: GridBuilder.h:1393
const Mask< LOG2DIM > & valueMask() const
Definition: GridBuilder.h:1381
typename BuildToValueMap< BuildT >::type ValueType
Definition: GridBuilder.h:1886
__hostdev__ void set(uint32_t n, bool on)
Set the specified bit on or off.
Definition: NanoVDB.h:3008
GLdouble n
Definition: glcorearb.h:2008
void setValue(const Coord &ijk, bool value)
Definition: GridBuilder.h:1627
typename TreeType::RootNodeType RootNodeType
Definition: GridBuilder.h:2064
bool getValue(uint32_t i) const
Definition: GridBuilder.h:1588
std::map< Coord, Tile > MapT
Definition: GridBuilder.h:65
TileIterator(const RootNode *parent)
Definition: GridBuilder.h:189
void setValueAndCache(const Coord &ijk, const ValueType &value, AccT &acc)
Definition: GridBuilder.h:387
build::LeafNode< BuildT > LeafT
Definition: GridBuilder.h:1676
enable_if< LEVEL==1, Node1 & >::type node(int i)
Definition: GridBuilder.h:2108
typename Node2::ValueType ValueType
Definition: GridBuilder.h:50
__hostdev__ bool isOff(uint32_t n) const
Return true if the given bit is NOT set.
Definition: NanoVDB.h:2968
void merge(RootNode &other)
Definition: GridBuilder.h:553
Node2 & upper(uint32_t i)
Definition: GridBuilder.h:2128
Implements a light-weight self-contained VDB data-structure in a single file! In other words...
ValueType getLastValue() const
Definition: GridBuilder.h:1223
static constexpr uint64_t NUM_VALUES
Definition: GridBuilder.h:1104
ValueOnIterator & operator=(const ValueOnIterator &)=default
void setValueAndCache(const Coord &ijk, bool, const AccT &)
Definition: GridBuilder.h:1428
RootNode(const ValueType &background)
Definition: GridBuilder.h:226
typename ChildT::BuildType BuildType
Definition: GridBuilder.h:614
const ValueType & getValue(uint32_t i) const
Definition: GridBuilder.h:1224
const std::string & getName() const
Definition: GridBuilder.h:1912
static constexpr uint32_t TOTAL
Definition: GridBuilder.h:618
auto setAndCache(const Coord &ijk, const AccT &acc, ArgsT &&...args)
Definition: GridBuilder.h:824
typename Mask< LOG2DIM >::template Iterator< ON > MaskIterT
Definition: GridBuilder.h:1302
ValueIterator & operator=(const ValueIterator &)=default
ChildT * probeChild(ValueType &value) const
Definition: GridBuilder.h:706
Tile(ChildT *c=nullptr)
Definition: GridBuilder.h:56
void merge(LeafNode &other)
Definition: GridBuilder.h:1629
__hostdev__ uint32_t countOn() const
Return the total number of set bits in this Mask.
Definition: NanoVDB.h:2821
auto set(const Coord &ijk, ArgsT &&...args) const
Definition: GridBuilder.h:1713
WriteAccessor getWriteAccessor()
special accessor for thread-safe writing only
Definition: GridBuilder.h:1841
LeafNode & operator=(const LeafNode &)=delete
uint32_t getTableSize() const
Definition: GridBuilder.h:235
const ChildT * probeChild(ValueType &value)
Definition: GridBuilder.h:198
ValueIterator(const RootNode *parent)
Definition: GridBuilder.h:120
std::array< size_t, 3 > nodeCount() const
Definition: GridBuilder.h:1832
void addNode(NodeT *&node)
Definition: GridBuilder.h:1017
Defines an affine transform and its inverse represented as a 3x3 matrix and a vec3 translation...
Definition: NanoVDB.h:3139
const RootNodeType & root() const
Definition: GridBuilder.h:2132
void levelSetToFog(NodeManagerT &mgr, bool rebuild=true)
Definition: GridBuilder.h:2169
ValueIterator beginValue()
Definition: GridBuilder.h:678
ValueIterator cbeginValueAll() const
Definition: GridBuilder.h:679
static BuildLeaf< T > * set(BuildLeaf< T > &leaf, uint32_t n)
Definition: GridBuilder.h:2275
ValueType getValue(int i, int j, int k) const
Definition: GridBuilder.h:1830
const Mask< LOG2DIM > & getValueMask() const
Definition: GridBuilder.h:1556
uint64_t nodeCount(int level) const
Return the number of tree nodes at the specified level.
Definition: GridBuilder.h:2097
auto get(const UT_ARTIterator< T > &it) -> decltype(it.key())
Definition: UT_ARTMap.h:1073
void setValue(const Coord &ijk, const ValueType &value)
Definition: GridBuilder.h:342
Visits all inactive values in a leaf node.
Definition: GridBuilder.h:1135
GLenum target
Definition: glcorearb.h:1667
static uint32_t CoordToOffset(const Coord &ijk)
Return the linear offset corresponding to the given coordinate.
Definition: GridBuilder.h:1560
RootNodeType mRoot
Definition: GridBuilder.h:1819
static constexpr uint32_t LEVEL
Definition: GridBuilder.h:54
auto set(const Coord &ijk, ArgsT &&...args)
Definition: GridBuilder.h:1231
typename Mask< LOG2DIM >::template Iterator< ON > MaskIterT
Definition: GridBuilder.h:1475
static constexpr uint32_t TOTAL
Definition: GridBuilder.h:1099
static constexpr uint32_t DIM
Definition: GridBuilder.h:1100
ValueType getValueAndCache(const Coord &ijk, AccT &acc) const
Definition: GridBuilder.h:871
Implements Tree::getValue(Coord), i.e. return the value associated with a specific coordinate ijk...
Definition: NanoVDB.h:3451
GLuint const GLchar * name
Definition: glcorearb.h:786
Custom Range class that is compatible with the tbb::blocked_range classes.
__hostdev__ bool isOn(uint32_t n) const
Return true if the given bit is set.
Definition: NanoVDB.h:2965
Maximum floating-point values.
Definition: NanoVDB.h:1032
Visits child nodes of this node only.
Definition: GridBuilder.h:648
static constexpr uint32_t LOG2DIM
Definition: GridBuilder.h:617
bool getValueAndCache(const Coord &ijk, const AccT &) const
Definition: GridBuilder.h:1422
typename BuildToValueMap< BuildT >::type ValueType
Definition: GridBuilder.h:1675
static constexpr uint32_t DIM
Definition: GridBuilder.h:619
void setValue(uint32_t n, bool value)
Definition: GridBuilder.h:1622
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
GLint GLenum GLint x
Definition: glcorearb.h:409
static uint32_t CoordToOffset(const Coord &ijk)
Return the linear offset corresponding to the given coordinate.
Definition: GridBuilder.h:1196
ValueOnIterator & operator=(const ValueOnIterator &)=default
void addNode(NodeT *&node)
Definition: GridBuilder.h:532
ValueIterator cbeginValueAll() const
Definition: GridBuilder.h:147
Grid(const ValueType &background, const std::string &name="", GridClass gClass=GridClass::Unknown)
Definition: GridBuilder.h:1898
ValueType getFirstValue() const
Definition: GridBuilder.h:782
void merge(InternalNode &other)
Definition: GridBuilder.h:1035
MaskT< LOG2DIM > mValueMask
Definition: NanoVDB.h:5738
DenseIterator(const InternalNode *parent)
Definition: GridBuilder.h:704
void localToGlobalCoord(Coord &ijk) const
Definition: GridBuilder.h:1400
void touchLeaf(const Coord &ijk) const
Definition: GridBuilder.h:1771
void setValueOn(const Coord &ijk)
Definition: GridBuilder.h:1759
const Tile * probeTile(const Coord &ijk) const
Definition: GridBuilder.h:74
Node1 & lower(uint32_t i)
Definition: GridBuilder.h:2123
ChildIterator(const RootNode *parent)
Definition: GridBuilder.h:85
WriteAccessor(RootNodeType &parent, std::mutex &mx)
Definition: GridBuilder.h:1856
Implements Tree::isActive(Coord)
Definition: NanoVDB.h:3457
uint32_t nodeCount() const
Definition: GridBuilder.h:445
Implements Tree::isActive(Coord)
Definition: GridBuilder.h:42
const Mask< LOG2DIM > & getValueMask() const
Definition: GridBuilder.h:1382
bool isValueOn(const Coord &ijk) const
Definition: GridBuilder.h:1796
Node0 & leaf(uint32_t i)
Definition: GridBuilder.h:2118
uint64_t lowerCount() const
Definition: GridBuilder.h:2124
GLint j
Definition: glad.h:2733
void setValue(const Coord &ijk, const ValueType &value)
Definition: GridBuilder.h:1267
ValueOnIterator cbeginValueOn() const
Definition: GridBuilder.h:695
ValueOnIterator beginValueOn()
Definition: GridBuilder.h:694
const Mask< LOG2DIM > & getValueMask() const
Definition: GridBuilder.h:1191
enable_if< LEVEL==0, Node0 & >::type node(int i)
Definition: GridBuilder.h:2104
const Coord & origin() const
Definition: GridBuilder.h:745
std::vector< Node1 * > mArray1
Definition: GridBuilder.h:2144
ChildIterator & operator=(const ChildIterator &)=default
GLenum func
Definition: glcorearb.h:783
enable_if< is_floating_point< typename NodeManagerT::ValueType >::value >::type sdfToLevelSet(NodeManagerT &mgr)
Definition: GridBuilder.h:2151
ValueType mValues[SIZE]
Definition: GridBuilder.h:1112
typename AccT::RootNodeType RootNodeType
Definition: GridBuilder.h:1854
ValueIterator(const LeafNode *parent)
Definition: GridBuilder.h:1157
ChildIterator(const InternalNode *parent)
Definition: GridBuilder.h:654
typename MaskT::template Iterator< On > MaskIterT
Definition: GridBuilder.h:626
std::vector< Node0 * > mArray0
Definition: GridBuilder.h:2143
ValueOnIterator cbeginValueOn() const
Definition: GridBuilder.h:1499
TileIterator cbeginChildAll() const
Definition: GridBuilder.h:222
Coord offsetToGlobalCoord(uint32_t n) const
Definition: GridBuilder.h:1579
static BuildLeaf< T > * set(BuildLeaf< T > &leaf, uint32_t n, const typename BuildLeaf< T >::ValueType &v)
Definition: GridBuilder.h:2279
std::string lower(string_view a)
Return an all-upper case version of a (locale-independent).
Definition: strutil.h:395
void operator()(const Func &func, const CoordBBox &bbox, ValueType delta=ValueType(0))
Sets grids values in domain of the bbox to those returned by the specified func with the expected sig...
Definition: GridBuilder.h:1931
std::enable_if< std::is_floating_point< T >::value >::type signedFloodFill(T outside)
Definition: GridBuilder.h:1060
Tile * probeTile(const Coord &ijk)
Definition: GridBuilder.h:69
RootNode & operator=(const RootNode &)=delete
typename BuildToValueMap< nanovdb::ValueMask >::type ValueType
Definition: GridBuilder.h:1096
ValueAccessor(RootNodeType &root)
Definition: GridBuilder.h:1682
void setValueOnAndCache(const Coord &ijk, AccT &acc)
Definition: GridBuilder.h:406
Coord offsetToGlobalCoord(uint32_t n) const
Definition: GridBuilder.h:1402
Dummy type for a voxel whose value equals its binary active state.
Definition: NanoVDB.h:264
bool getValue(uint32_t i) const
Definition: GridBuilder.h:1411
typename NanoNode< BuildType, LEVEL >::Type NanoNodeT
Definition: GridBuilder.h:627
const TreeType & tree() const
Definition: GridBuilder.h:2135
ValueOnIterator(const LeafNode *parent)
Definition: GridBuilder.h:1125
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
void setValueAndCache(const Coord &ijk, const ValueType &value, AccT &acc)
Definition: GridBuilder.h:882
void nodeCount(std::array< size_t, 3 > &count) const
Definition: GridBuilder.h:238
Tile(const ValueType &v, bool s)
Definition: GridBuilder.h:57
static Coord OffsetToLocalCoord(uint32_t n)
Definition: GridBuilder.h:1203
Coord offsetToGlobalCoord(uint32_t n) const
Definition: GridBuilder.h:775
**If you just want to fire and args
Definition: thread.h:609
typename BuildRoot< T >::Tile BuildTile
Definition: GridBuilder.h:2032
ChildIterator cbeginChild() const
Definition: GridBuilder.h:111
static constexpr uint64_t NUM_VALUES
Definition: GridBuilder.h:623
auto getAndCache(const Coord &ijk, const AccT &acc, ArgsT &&...args) const
Definition: GridBuilder.h:810
ValueOffIterator(const LeafNode *parent)
Definition: GridBuilder.h:1141
#define SIZE
Definition: simple.C:41
typename Mask< LOG2DIM >::template Iterator< ON > MaskIterT
Definition: GridBuilder.h:1107
const MaskT & getValueMask() const
Definition: GridBuilder.h:741
static constexpr uint32_t LOG2DIM
Definition: GridBuilder.h:1098
ValueIterator cbeginValueAll() const
Definition: GridBuilder.h:1540
const Coord & origin() const
Definition: GridBuilder.h:1193
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:857
ValueOnIterator(const RootNode *parent)
Definition: GridBuilder.h:155
ValueType getValue(const Coord &ijk) const
Definition: GridBuilder.h:1732
Definition: core.h:1131
typename Node1::ChildNodeType Node0
Definition: GridBuilder.h:2068
Fp4 BuildType
Definition: NanoVDB.h:5565
Visits all tile values and child nodes of this node.
Definition: GridBuilder.h:698
Coord offsetToGlobalCoord(uint32_t n) const
Definition: GridBuilder.h:1215
enable_if< LEVEL==2, Node2 & >::type node(int i)
Definition: GridBuilder.h:2112
ValueOnIterator(const InternalNode *parent)
Definition: GridBuilder.h:688
GLboolean r
Definition: glcorearb.h:1222
void addTile(const Coord &ijk, const ValueType &value, bool state)
Add a tile containing voxel (i, j, k) at the specified tree level, creating a new branch if necessary...
Definition: GridBuilder.h:499
ValueAccessor< BuildT > getAccessor()
regular accessor for thread-safe reading and non-thread-safe writing
Definition: GridBuilder.h:1839
void prune(TreeT &tree, typename TreeT::ValueType tolerance=zeroVal< typename TreeT::ValueType >(), bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing with tiles any nodes whose values are all the same...
Definition: Prune.h:335
bool getValueAndCache(const Coord &ijk, const AccT &) const
Definition: GridBuilder.h:1601
SIM_API const UT_StringHolder distance
enable_if< LEVEL==0, const Node0 & >::type node(int i) const
Definition: GridBuilder.h:2106
ValueType getLastValue() const
Definition: GridBuilder.h:783
ValueOffIterator & operator=(const ValueOffIterator &)=default
void setName(const std::string &name)
Definition: GridBuilder.h:1913
LeafT * setValue(const Coord &ijk, const ValueType &value)
Sets value in a leaf node and returns it.
Definition: GridBuilder.h:1745
const ValueType & getValueAndCache(const Coord &ijk, const AccT &) const
Definition: GridBuilder.h:1235
auto set(const Coord &ijk, ArgsT &&...args)
Definition: GridBuilder.h:794
Mask< LOG2DIM > mValueMask
Definition: GridBuilder.h:1111
enable_if< LEVEL==2, const Node2 & >::type node(int i) const
Definition: GridBuilder.h:2114
__hostdev__ GridType mapToGridType()
Maps from a templated build type to a GridType enum.
Definition: NanoVDB.h:2031
const Coord & origin() const
Definition: GridBuilder.h:1557
typename RootNodeType::LeafNodeType LeafNodeType
Definition: GridBuilder.h:1818
const GridType & gridType() const
Definition: GridBuilder.h:1907
static uint32_t CoordToOffset(const Coord &ijk)
Return the linear offset corresponding to the given coordinate.
Definition: GridBuilder.h:1386
type
Definition: core.h:1059
bool isCached(const Coord &ijk) const
Definition: GridBuilder.h:1692
ValueIterator cbeginValueAll() const
Definition: GridBuilder.h:1172
bool ValueType
Definition: NanoVDB.h:5729
Implements Tree::getValue(Coord), i.e. return the value associated with a specific coordinate ijk...
Definition: GridBuilder.h:39
ValueType getValue(int i, int j, int k) const
Definition: GridBuilder.h:1690
void localToGlobalCoord(Coord &ijk) const
Definition: GridBuilder.h:1210
typename AccT::ValueType ValueType
Definition: GridBuilder.h:1850
void touchLeafAndCache(const Coord &ijk, AccT &acc)
Definition: GridBuilder.h:914
ValueIterator beginValue()
Definition: GridBuilder.h:1171
C++11 implementation of std::enable_if.
Definition: NanoVDB.h:469
Implements Tree::probeLeaf(Coord)
Definition: GridBuilder.h:43
const Map & map() const
Definition: GridBuilder.h:1909
const MaskT & childMask() const
Definition: GridBuilder.h:744
GLint GLsizei count
Definition: glcorearb.h:405
void addTile(const Coord &ijk, const ValueType &value, bool state)
Add a tile containing voxel (i, j, k) at the specified tree level, creating a new branch if necessary...
Definition: GridBuilder.h:991
void setValue(uint32_t n, const ValueType &value)
Definition: GridBuilder.h:1262
C++11 implementation of std::is_same.
Definition: NanoVDB.h:418
TileIterator beginTile()
Definition: GridBuilder.h:221
const Node0 & leaf(uint32_t i) const
Return the i'th leaf node with respect to breadth-first ordering.
Definition: GridBuilder.h:2117
Set the value and its state at the leaf level mapped to by ijk, and create the leaf node and branch i...
Definition: GridBuilder.h:40
auto set(const Coord &ijk, ArgsT &&...args)
Definition: GridBuilder.h:1418
Trait to map from LEVEL to node type.
Definition: NanoVDB.h:6440
typename Node2::ChildNodeType Node1
Definition: GridBuilder.h:2067
void merge(LeafNode &other)
Definition: GridBuilder.h:1269
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.
Definition: node.h:558