OpenVDB  10.0.0
ValueAccessor.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @file tree/ValueAccessor.h
5 ///
6 /// When traversing a grid in a spatially coherent pattern (e.g., iterating
7 /// over neighboring voxels), request a @c ValueAccessor from the grid
8 /// (with Grid::getAccessor()) and use the accessor's @c getValue() and
9 /// @c setValue() methods. These will typically be significantly faster
10 /// than accessing voxels directly in the grid's tree.
11 ///
12 /// @par Example:
13 ///
14 /// @code
15 /// FloatGrid grid;
16 /// FloatGrid::Accessor acc = grid.getAccessor();
17 /// // First access is slow:
18 /// acc.setValue(Coord(0, 0, 0), 100);
19 /// // Subsequent nearby accesses are fast, since the accessor now holds pointers
20 /// // to nodes that contain (0, 0, 0) along the path from the root of the grid's
21 /// // tree to the leaf:
22 /// acc.setValue(Coord(0, 0, 1), 100);
23 /// acc.getValue(Coord(0, 2, 0), 100);
24 /// // Slow, because the accessor must be repopulated:
25 /// acc.getValue(Coord(-1, -1, -1));
26 /// // Fast:
27 /// acc.getValue(Coord(-1, -1, -2));
28 /// acc.setValue(Coord(-1, -2, 0), -100);
29 /// @endcode
30 
31 #ifndef OPENVDB_TREE_VALUEACCESSOR_HAS_BEEN_INCLUDED
32 #define OPENVDB_TREE_VALUEACCESSOR_HAS_BEEN_INCLUDED
33 
34 #include <openvdb/version.h>
35 #include <openvdb/Types.h>
36 
37 #include <tbb/null_mutex.h>
38 #include <tbb/spin_mutex.h>
39 
40 #include <cassert>
41 #include <limits>
42 #include <type_traits>
43 
44 namespace openvdb {
46 namespace OPENVDB_VERSION_NAME {
47 namespace tree {
48 
49 // Forward declarations of local classes that are not intended for general use
50 // The IsSafe template parameter is explained in the warning below.
51 template<typename TreeType, bool IsSafe = true>
53 template<typename TreeType, bool IsSafe = true, Index L0 = 0>
55 template<typename TreeType, bool IsSafe = true, Index L0 = 0, Index L1 = 1>
57 template<typename TreeType, bool IsSafe = true, Index L0 = 0, Index L1 = 1, Index L2 = 2>
59 template<typename TreeCacheT, typename NodeVecT, bool AtRoot
60 #if OPENVDB_ABI_VERSION_NUMBER >= 10
61 , bool BypassLeafAPI =
64 #endif
65 > class CacheItem;
66 
67 
68 /// @brief This base class for ValueAccessors manages registration of an accessor
69 /// with a tree so that the tree can automatically clear the accessor whenever
70 /// one of its nodes is deleted.
71 ///
72 /// @internal A base class is needed because ValueAccessor is templated on both
73 /// a Tree type and a mutex type. The various instantiations of the template
74 /// are distinct, unrelated types, so they can't easily be stored in a container
75 /// such as the Tree's CacheRegistry. This base class, in contrast, is templated
76 /// only on the Tree type, so for any given Tree, only two distinct instantiations
77 /// are possible, ValueAccessorBase<Tree> and ValueAccessorBase<const Tree>.
78 ///
79 /// @warning If IsSafe = false then the ValueAccessor will not register itself
80 /// with the tree from which it is constructed. While in some rare cases this can
81 /// lead to better performance (since it avoids the small overhead of insertion
82 /// on creation and deletion on destruction) it is also unsafe if the tree is
83 /// modified. So unless you're an expert it is highly recommended to set
84 /// IsSafe = true, which is the default in all derived ValueAccessors defined
85 /// below. However if you know that the tree is no being modifed for the lifespan
86 /// of the ValueAccessor AND the work performed per ValueAccessor is small relative
87 /// to overhead of registering it you should consider setting IsSafe = false. If
88 /// this turns out to improve performance you should really rewrite your code so as
89 /// to better amortize the construction of the ValueAccessor, i.e. reuse it as much
90 /// as possible!
91 template<typename TreeType, bool IsSafe>
93 {
94 public:
95  static const bool IsConstTree = std::is_const<TreeType>::value;
96 
97  /// @brief Return true if this accessor is safe, i.e. registered
98  /// by the tree from which it is constructed. Un-registered
99  /// accessors can in rare cases be faster because it avoids the
100  /// (small) overhead of registration, but they are unsafe if the
101  /// tree is modified. So unless you're an expert it is highly
102  /// recommended to set IsSafe = true (which is the default).
103  static bool isSafe() { return IsSafe; }
104 
105  ValueAccessorBase(TreeType& tree): mTree(&tree)
106  {
107  if (IsSafe) tree.attachAccessor(*this);
108  }
109 
110  virtual ~ValueAccessorBase() { if (IsSafe && mTree) mTree->releaseAccessor(*this); }
111 
112  /// @brief Return a pointer to the tree associated with this accessor.
113  /// @details The pointer will be null only if the tree from which this accessor
114  /// was constructed was subsequently deleted (which generally leaves the
115  /// accessor in an unsafe state).
116  TreeType* getTree() const { return mTree; }
117  /// Return a reference to the tree associated with this accessor.
118  TreeType& tree() const { assert(mTree); return *mTree; }
119 
120  ValueAccessorBase(const ValueAccessorBase& other): mTree(other.mTree)
121  {
122  if (IsSafe && mTree) mTree->attachAccessor(*this);
123  }
124 
126  {
127  if (&other != this) {
128  if (IsSafe && mTree) mTree->releaseAccessor(*this);
129  mTree = other.mTree;
130  if (IsSafe && mTree) mTree->attachAccessor(*this);
131  }
132  return *this;
133  }
134 
135  virtual void clear() = 0;
136 
137 protected:
138  // Allow trees to deregister themselves.
139  template<typename> friend class Tree;
140 
141  virtual void release() { mTree = nullptr; }
142 
143  TreeType* mTree;
144 }; // class ValueAccessorBase
145 
146 
147 ////////////////////////////////////////
148 
149 
150 /// When traversing a grid in a spatially coherent pattern (e.g., iterating
151 /// over neighboring voxels), request a @c ValueAccessor from the grid
152 /// (with Grid::getAccessor()) and use the accessor's @c getValue() and
153 /// @c setValue() methods. These will typically be significantly faster
154 /// than accessing voxels directly in the grid's tree.
155 ///
156 /// A ValueAccessor caches pointers to tree nodes along the path to a voxel (x, y, z).
157 /// A subsequent access to voxel (x', y', z') starts from the cached leaf node and
158 /// moves up until a cached node that encloses (x', y', z') is found, then traverses
159 /// down the tree from that node to a leaf, updating the cache with the new path.
160 /// This leads to significant acceleration of spatially-coherent accesses.
161 ///
162 /// @param _TreeType the type of the tree to be accessed [required]
163 /// @param IsSafe if IsSafe = false then the ValueAccessor will
164 /// not register itself with the tree from which
165 /// it is constructed (see warning).
166 /// @param CacheLevels the number of nodes to be cached, starting from the leaf level
167 /// and not including the root (i.e., CacheLevels < DEPTH),
168 /// and defaulting to all non-root nodes
169 /// @param MutexType the type of mutex to use (see note)
170 ///
171 /// @warning If IsSafe = false then the ValueAccessor will not register itself
172 /// with the tree from which it is constructed. While in some rare cases this can
173 /// lead to better performance (since it avoids the small overhead of insertion
174 /// on creation and deletion on destruction) it is also unsafe if the tree is
175 /// modified. So unless you're an expert it is highly recommended to set
176 /// IsSafe = true, which is the default. However if you know that the tree is no
177 /// being modifed for the lifespan of the ValueAccessor AND the work performed
178 /// per ValueAccessor is small relative to overhead of registering it you should
179 /// consider setting IsSafe = false. If this improves performance you should
180 /// really rewrite your code so as to better amortize the construction of the
181 /// ValueAccessor, i.e. reuse it as much as possible!
182 ///
183 /// @note If @c MutexType is a TBB-compatible mutex, then multiple threads may
184 /// safely access a single, shared accessor. However, it is highly recommended
185 /// that, instead, each thread be assigned its own, non-mutex-protected accessor.
186 template<typename _TreeType,
187  bool IsSafe = true,
188  Index CacheLevels = _TreeType::DEPTH-1,
189  typename MutexType = tbb::null_mutex>
190 class ValueAccessor: public ValueAccessorBase<_TreeType, IsSafe>
191 {
192 public:
193  static_assert(CacheLevels < _TreeType::DEPTH, "cache size exceeds tree depth");
194 
195  using TreeType = _TreeType;
196  using RootNodeT = typename TreeType::RootNodeType;
197  using LeafNodeT = typename TreeType::LeafNodeType;
198  using ValueType = typename RootNodeT::ValueType;
200  using LockT = typename MutexType::scoped_lock;
201  using BaseT::IsConstTree;
202 
203 #if OPENVDB_ABI_VERSION_NUMBER >= 10
204  // If the last node being cached is a leaf node and the storage type matches
205  // the ValueType, we can cache the buffer pointer instead of using the delay
206  // load locked leaf API
207  static constexpr bool BypassLeafAPI = CacheLevels >= 1 &&
209 #endif
210 
211  ValueAccessor(TreeType& tree): BaseT(tree), mCache(*this)
212  {
213  mCache.insert(Coord(), &tree.root());
214  }
215 
216  ValueAccessor(const ValueAccessor& other) : BaseT(other), mCache(*this, other.mCache) {}
217 
219  {
220  if (&other != this) {
221  this->BaseT::operator=(other);
222  mCache.copy(*this, other.mCache);
223  }
224  return *this;
225  }
226  ~ValueAccessor() override = default;
227 
228  /// Return the number of cache levels employed by this accessor.
229  static Index numCacheLevels() { return CacheLevels; }
230 
231  /// Return @c true if nodes along the path to the given voxel have been cached.
232  bool isCached(const Coord& xyz) const { LockT lock(mMutex); return mCache.isCached(xyz); }
233 
234  /// Return the value of the voxel at the given coordinates.
235  const ValueType& getValue(const Coord& xyz) const
236  {
237  LockT lock(mMutex);
238  return mCache.getValue(xyz);
239  }
240 
241  /// Return the active state of the voxel at the given coordinates.
242  bool isValueOn(const Coord& xyz) const { LockT lock(mMutex); return mCache.isValueOn(xyz); }
243 
244  /// Return the active state of the voxel as well as its value
245  bool probeValue(const Coord& xyz, ValueType& value) const
246  {
247  LockT lock(mMutex);
248  return mCache.probeValue(xyz,value);
249  }
250 
251  /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides,
252  /// or -1 if (x, y, z) isn't explicitly represented in the tree (i.e., if it is
253  /// implicitly a background voxel).
254  int getValueDepth(const Coord& xyz) const
255  {
256  LockT lock(mMutex);
257  return mCache.getValueDepth(xyz);
258  }
259 
260  /// Return @c true if the value of voxel (x, y, z) resides at the leaf level
261  /// of the tree, i.e., if it is not a tile value.
262  bool isVoxel(const Coord& xyz) const { LockT lock(mMutex); return mCache.isVoxel(xyz); }
263 
264  //@{
265  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
266  void setValue(const Coord& xyz, const ValueType& value)
267  {
268  LockT lock(mMutex);
269  mCache.setValue(xyz, value);
270  }
271  void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); }
272  //@}
273 
274  /// Set the value of the voxel at the given coordinate but don't change its active state.
275  void setValueOnly(const Coord& xyz, const ValueType& value)
276  {
277  LockT lock(mMutex);
278  mCache.setValueOnly(xyz, value);
279  }
280 
281  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
282  void setValueOff(const Coord& xyz, const ValueType& value)
283  {
284  LockT lock(mMutex);
285  mCache.setValueOff(xyz, value);
286  }
287 
288  /// @brief Apply a functor to the value of the voxel at the given coordinates
289  /// and mark the voxel as active.
290  /// @details See Tree::modifyValue() for details.
291  template<typename ModifyOp>
292  void modifyValue(const Coord& xyz, const ModifyOp& op)
293  {
294  LockT lock(mMutex);
295  mCache.modifyValue(xyz, op);
296  }
297 
298  /// @brief Apply a functor to the voxel at the given coordinates.
299  /// @details See Tree::modifyValueAndActiveState() for details.
300  template<typename ModifyOp>
301  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
302  {
303  LockT lock(mMutex);
304  mCache.modifyValueAndActiveState(xyz, op);
305  }
306 
307  /// Set the active state of the voxel at the given coordinates but don't change its value.
308  void setActiveState(const Coord& xyz, bool on = true)
309  {
310  LockT lock(mMutex);
311  mCache.setActiveState(xyz, on);
312  }
313  /// Mark the voxel at the given coordinates as active but don't change its value.
314  void setValueOn(const Coord& xyz) { this->setActiveState(xyz, true); }
315  /// Mark the voxel at the given coordinates as inactive but don't change its value.
316  void setValueOff(const Coord& xyz) { this->setActiveState(xyz, false); }
317 
318  /// Return the cached node of type @a NodeType. [Mainly for internal use]
319  template<typename NodeType>
320  NodeType* getNode()
321  {
322  LockT lock(mMutex);
323  NodeType* node = nullptr;
324  mCache.getNode(node);
325  return node;
326  }
327 
328  /// Cache the given node, which should lie along the path from the root node to
329  /// the node containing voxel (x, y, z). [Mainly for internal use]
330  template<typename NodeType>
331  void insertNode(const Coord& xyz, NodeType& node)
332  {
333  LockT lock(mMutex);
334  mCache.insert(xyz, &node);
335  }
336 
337  /// If a node of the given type exists in the cache, remove it, so that
338  /// isCached(xyz) returns @c false for any voxel (x, y, z) contained in
339  /// that node. [Mainly for internal use]
340  template<typename NodeType>
341  void eraseNode() { LockT lock(mMutex); NodeType* node = nullptr; mCache.erase(node); }
342 
343  /// @brief Add the specified leaf to this tree, possibly creating a child branch
344  /// in the process. If the leaf node already exists, replace it.
345  void addLeaf(LeafNodeT* leaf)
346  {
347  LockT lock(mMutex);
348  mCache.addLeaf(leaf);
349  }
350 
351  /// @brief Add a tile at the specified tree level that contains voxel (x, y, z),
352  /// possibly deleting existing nodes or creating new nodes in the process.
353  void addTile(Index level, const Coord& xyz, const ValueType& value, bool state)
354  {
355  LockT lock(mMutex);
356  mCache.addTile(level, xyz, value, state);
357  }
358 
359  /// @brief Return a pointer to the leaf node that contains voxel (x, y, z).
360  /// If no such node exists, create one, but preserve the values and
361  /// active states of all voxels.
362  /// @details Use this method to preallocate a static tree topology
363  /// over which to safely perform multithreaded processing.
364  LeafNodeT* touchLeaf(const Coord& xyz)
365  {
366  LockT lock(mMutex);
367  return mCache.touchLeaf(xyz);
368  }
369 
370  //@{
371  /// @brief Return a pointer to the node of the specified type that contains
372  /// voxel (x, y, z), or @c nullptr if no such node exists.
373  template<typename NodeT>
374  NodeT* probeNode(const Coord& xyz)
375  {
376  LockT lock(mMutex);
377  return mCache.template probeNode<NodeT>(xyz);
378  }
379  template<typename NodeT>
380  const NodeT* probeConstNode(const Coord& xyz) const
381  {
382  LockT lock(mMutex);
383  return mCache.template probeConstNode<NodeT>(xyz);
384  }
385  template<typename NodeT>
386  const NodeT* probeNode(const Coord& xyz) const
387  {
388  return this->template probeConstNode<NodeT>(xyz);
389  }
390  //@}
391 
392  //@{
393  /// @brief Return a pointer to the leaf node that contains voxel (x, y, z),
394  /// or @c nullptr if no such node exists.
395  LeafNodeT* probeLeaf(const Coord& xyz)
396  {
397  LockT lock(mMutex);
398  return mCache.probeLeaf(xyz);
399  }
400  const LeafNodeT* probeConstLeaf(const Coord& xyz) const
401  {
402  LockT lock(mMutex);
403  return mCache.probeConstLeaf(xyz);
404  }
405  const LeafNodeT* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); }
406  //@}
407 
408  /// Remove all nodes from this cache, then reinsert the root node.
409  void clear() override
410  {
411  LockT lock(mMutex);
412  mCache.clear();
413  if (this->mTree) mCache.insert(Coord(), &(this->mTree->root()));
414  }
415 
416 private:
417  // Allow nodes to insert themselves into the cache.
418  template<typename> friend class RootNode;
419  template<typename, Index> friend class InternalNode;
420  template<typename, Index> friend class LeafNode;
421  // Allow trees to deregister themselves.
422  template<typename> friend class Tree;
423 
424  /// Prevent this accessor from calling Tree::releaseCache() on a tree that
425  /// no longer exists. (Called by mTree when it is destroyed.)
426  void release() override
427  {
428  LockT lock(mMutex);
429  this->BaseT::release();
430  mCache.clear();
431  }
432 
433  /// Cache the given node, which should lie along the path from the root node to
434  /// the node containing voxel (x, y, z).
435  /// @note This operation is not mutex-protected and is intended to be called
436  /// only by nodes and only in the context of a getValue() or setValue() call.
437  template<typename NodeType>
438  void insert(const Coord& xyz, NodeType* node) { mCache.insert(xyz, node); }
439 
440  // Define a list of all tree node types from LeafNode to RootNode
441  using InvTreeT = typename RootNodeT::NodeChainType;
442  // Remove all tree node types that are excluded from the cache
443  static constexpr int64_t First = CacheLevels;
444  static constexpr int64_t Last = InvTreeT::template Index<RootNodeT>;
445  using SubtreeT = typename InvTreeT::template RemoveByIndex<First, Last-1>;
447 
448  // Private member data
449  mutable CacheItemT mCache;
450  mutable MutexType mMutex;
451 
452 }; // class ValueAccessor
453 
454 
455 /// @brief Template specialization of the ValueAccessor with no mutex and no cache levels
456 /// @details This specialization is provided mainly for benchmarking.
457 /// Accessors with caching will almost always be faster.
458 template<typename TreeType, bool IsSafe>
459 class ValueAccessor<TreeType, IsSafe, 0, tbb::null_mutex>
460  : public ValueAccessor0<TreeType, IsSafe>
461 {
462 public:
463  ValueAccessor(TreeType& tree): ValueAccessor0<TreeType, IsSafe>(tree) {}
464  ValueAccessor(const ValueAccessor& other): ValueAccessor0<TreeType, IsSafe>(other) {}
465  ~ValueAccessor() override = default;
466 };
467 
468 
469 /// Template specialization of the ValueAccessor with no mutex and one cache level
470 template<typename TreeType, bool IsSafe>
471 class ValueAccessor<TreeType, IsSafe, 1, tbb::null_mutex>
472  : public ValueAccessor1<TreeType, IsSafe>
473 {
474 public:
475  ValueAccessor(TreeType& tree): ValueAccessor1<TreeType, IsSafe>(tree) {}
476  ValueAccessor(const ValueAccessor& other): ValueAccessor1<TreeType, IsSafe>(other) {}
477  ~ValueAccessor() override = default;
478 };
479 
480 
481 /// Template specialization of the ValueAccessor with no mutex and two cache levels
482 template<typename TreeType, bool IsSafe>
483 class ValueAccessor<TreeType, IsSafe, 2, tbb::null_mutex>
484  : public ValueAccessor2<TreeType, IsSafe>
485 {
486 public:
487  ValueAccessor(TreeType& tree): ValueAccessor2<TreeType, IsSafe>(tree) {}
488  ValueAccessor(const ValueAccessor& other): ValueAccessor2<TreeType, IsSafe>(other) {}
489  ~ValueAccessor() override = default;
490 };
491 
492 
493 /// Template specialization of the ValueAccessor with no mutex and three cache levels
494 template<typename TreeType, bool IsSafe>
495 class ValueAccessor<TreeType, IsSafe, 3, tbb::null_mutex>: public ValueAccessor3<TreeType, IsSafe>
496 {
497 public:
498  ValueAccessor(TreeType& tree): ValueAccessor3<TreeType, IsSafe>(tree) {}
499  ValueAccessor(const ValueAccessor&) = default;
500  ValueAccessor& operator=(const ValueAccessor&) = default;
501  ~ValueAccessor() override = default;
502 };
503 
504 
505 ////////////////////////////////////////
506 
507 
508 /// @brief This accessor is thread-safe (at the cost of speed) for both reading and
509 /// writing to a tree. That is, multiple threads may safely access a single,
510 /// shared ValueAccessorRW.
511 ///
512 /// @warning Since the mutex-locking employed by the ValueAccessorRW
513 /// can seriously impair performance of multithreaded applications, it
514 /// is recommended that, instead, each thread be assigned its own
515 /// (non-mutex protected) accessor.
516 template<typename TreeType, bool IsSafe = true>
517 class ValueAccessorRW: public ValueAccessor<TreeType, IsSafe, TreeType::DEPTH-1, tbb::spin_mutex>
518 {
519 public:
521  : ValueAccessor<TreeType, IsSafe, TreeType::DEPTH-1, tbb::spin_mutex>(tree)
522  {
523  }
524 };
525 
526 
527 ////////////////////////////////////////
528 
529 
530 //
531 // The classes below are for internal use and should rarely be used directly.
532 //
533 
534 // An element of a compile-time linked list of node pointers, ordered from LeafNode to RootNode
535 template<typename TreeCacheT, typename NodeVecT, bool AtRoot
536 #if OPENVDB_ABI_VERSION_NUMBER >= 10
537  , bool BypassLeafAPI
538 #endif
539 >
540 class CacheItem
541 {
542 public:
543  using NodeType = typename NodeVecT::Front;
544  using ValueType = typename NodeType::ValueType;
545  using LeafNodeType = typename NodeType::LeafNodeType;
546  using CoordLimits = std::numeric_limits<Int32>;
547 
548  CacheItem(TreeCacheT& parent)
549  : mParent(&parent)
550  , mHash(CoordLimits::max())
551  , mNode(nullptr)
552  , mNext(parent)
553  {
554  }
555 
556  //@{
557  /// Copy another CacheItem's node pointers and hash keys, but not its parent pointer.
558  CacheItem(TreeCacheT& parent, const CacheItem& other)
559  : mParent(&parent)
560  , mHash(other.mHash)
561  , mNode(other.mNode)
562  , mNext(parent, other.mNext)
563  {
564  }
565 
566  CacheItem& copy(TreeCacheT& parent, const CacheItem& other)
567  {
568  mParent = &parent;
569  mHash = other.mHash;
570  mNode = other.mNode;
571  mNext.copy(parent, other.mNext);
572  return *this;
573  }
574  //@}
575 
576  bool isCached(const Coord& xyz) const
577  {
578  return (this->isHashed(xyz) || mNext.isCached(xyz));
579  }
580 
581  /// Cache the given node at this level.
582  void insert(const Coord& xyz, const NodeType* node)
583  {
584  mHash = (node != nullptr) ? xyz & ~(NodeType::DIM-1) : Coord::max();
585  mNode = node;
586  }
587  /// Forward the given node to another level of the cache.
588  template<typename OtherNodeType>
589  void insert(const Coord& xyz, const OtherNodeType* node) { mNext.insert(xyz, node); }
590 
591  /// Erase the node at this level.
592  void erase(const NodeType*) { mHash = Coord::max(); mNode = nullptr; }
593  /// Erase the node at another level of the cache.
594  template<typename OtherNodeType>
595  void erase(const OtherNodeType* node) { mNext.erase(node); }
596 
597  /// Erase the nodes at this and lower levels of the cache.
598  void clear() { mHash = Coord::max(); mNode = nullptr; mNext.clear(); }
599 
600  /// Return the cached node (if any) at this level.
601  void getNode(const NodeType*& node) const { node = mNode; }
602  void getNode(const NodeType*& node) { node = mNode; }
603  void getNode(NodeType*& node)
604  {
605  // This combination of a static assertion and a const_cast might not be elegant,
606  // but it is a lot simpler than specializing TreeCache for const Trees.
607  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
608  node = const_cast<NodeType*>(mNode);
609  }
610  /// Forward the request to another level of the cache.
611  template<typename OtherNodeType>
612  void getNode(OtherNodeType*& node) { mNext.getNode(node); }
613 
614  /// Return the value of the voxel at the given coordinates.
615  const ValueType& getValue(const Coord& xyz)
616  {
617  if (this->isHashed(xyz)) {
618  assert(mNode);
619  return mNode->getValueAndCache(xyz, *mParent);
620  }
621  return mNext.getValue(xyz);
622  }
623 
624  void addLeaf(LeafNodeType* leaf)
625  {
626  static_assert(!TreeCacheT::IsConstTree, "can't add a node to a const tree");
627  if (NodeType::LEVEL == 0) {
628  mNext.addLeaf(leaf);
629  return;
630  }
631 
632  if (this->isHashed(leaf->origin())) {
633  assert(mNode);
634  return const_cast<NodeType*>(mNode)->addLeafAndCache(leaf, *mParent);
635  }
636  else {
637  mNext.addLeaf(leaf);
638  }
639  }
640 
641  void addTile(Index level, const Coord& xyz, const ValueType& value, bool state)
642  {
643  static_assert(!TreeCacheT::IsConstTree, "can't add a tile to a const tree");
644  if (NodeType::LEVEL >= level && this->isHashed(xyz)) {
645  assert(mNode);
646  const_cast<NodeType*>(mNode)->addTileAndCache(level, xyz, value, state, *mParent);
647  return;
648  }
649  mNext.addTile(level, xyz, value, state);
650  }
651 
652  LeafNodeType* touchLeaf(const Coord& xyz)
653  {
654  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
655  if (this->isHashed(xyz)) {
656  assert(mNode);
657  return const_cast<NodeType*>(mNode)->touchLeafAndCache(xyz, *mParent);
658  }
659  return mNext.touchLeaf(xyz);
660  }
661 
662  LeafNodeType* probeLeaf(const Coord& xyz)
663  {
664  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
665  if (this->isHashed(xyz)) {
666  assert(mNode);
667  return const_cast<NodeType*>(mNode)->probeLeafAndCache(xyz, *mParent);
668  }
669  return mNext.probeLeaf(xyz);
670  }
671 
672  const LeafNodeType* probeConstLeaf(const Coord& xyz)
673  {
674  if (this->isHashed(xyz)) {
675  assert(mNode);
676  return mNode->probeConstLeafAndCache(xyz, *mParent);
677  }
678  return mNext.probeConstLeaf(xyz);
679  }
680 
681  template<typename NodeT>
682  NodeT* probeNode(const Coord& xyz)
683  {
684  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
685  if constexpr ((std::is_same<NodeT, NodeType>::value)) {
686  if (this->isHashed(xyz)) {
687  assert(mNode);
688  return reinterpret_cast<NodeT*>(const_cast<NodeType*>(mNode));
689  }
690  }
691 
692  if (NodeT::LEVEL < NodeType::LEVEL && mNode) {
693  // don't need to ascend the chain, descend the tree
694  return const_cast<NodeType*>(mNode)->template probeNodeAndCache<NodeT>(xyz, *mParent);
695  }
696  else {
697  // ascend
698  return mNext.template probeNode<NodeT>(xyz);
699  }
700  }
701 
702  template<typename NodeT>
703  const NodeT* probeConstNode(const Coord& xyz)
704  {
705  if constexpr ((std::is_same<NodeT, NodeType>::value)) {
706  if (this->isHashed(xyz)) {
707  assert(mNode);
708  return reinterpret_cast<const NodeT*>(mNode);
709  }
710  }
711 
712  if (NodeT::LEVEL < NodeType::LEVEL && mNode) {
713  // don't need to ascend the chain, descend the tree
714  return mNode->template probeConstNodeAndCache<NodeT>(xyz, *mParent);
715  }
716  else {
717  // ascend
718  return mNext.template probeConstNode<NodeT>(xyz);
719  }
720  }
721 
722  /// Return the active state of the voxel at the given coordinates.
723  bool isValueOn(const Coord& xyz)
724  {
725  if (this->isHashed(xyz)) {
726  assert(mNode);
727  return mNode->isValueOnAndCache(xyz, *mParent);
728  }
729  return mNext.isValueOn(xyz);
730  }
731 
732  /// Return the active state and value of the voxel at the given coordinates.
733  bool probeValue(const Coord& xyz, ValueType& value)
734  {
735  if (this->isHashed(xyz)) {
736  assert(mNode);
737  return mNode->probeValueAndCache(xyz, value, *mParent);
738  }
739  return mNext.probeValue(xyz, value);
740  }
741 
742  int getValueDepth(const Coord& xyz)
743  {
744  if (this->isHashed(xyz)) {
745  assert(mNode);
746  return static_cast<int>(TreeCacheT::RootNodeT::LEVEL) -
747  static_cast<int>(mNode->getValueLevelAndCache(xyz, *mParent));
748  } else {
749  return mNext.getValueDepth(xyz);
750  }
751  }
752 
753  bool isVoxel(const Coord& xyz)
754  {
755  if (this->isHashed(xyz)) {
756  assert(mNode);
757  return mNode->getValueLevelAndCache(xyz, *mParent)==0;
758  } else {
759  return mNext.isVoxel(xyz);
760  }
761  }
762 
763  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
764  void setValue(const Coord& xyz, const ValueType& value)
765  {
766  if (this->isHashed(xyz)) {
767  assert(mNode);
768  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
769  const_cast<NodeType*>(mNode)->setValueAndCache(xyz, value, *mParent);
770  } else {
771  mNext.setValue(xyz, value);
772  }
773  }
774  void setValueOnly(const Coord& xyz, const ValueType& value)
775  {
776  if (this->isHashed(xyz)) {
777  assert(mNode);
778  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
779  const_cast<NodeType*>(mNode)->setValueOnlyAndCache(xyz, value, *mParent);
780  } else {
781  mNext.setValueOnly(xyz, value);
782  }
783  }
784  void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); }
785 
786  /// @brief Apply a functor to the value of the voxel at the given coordinates
787  /// and mark the voxel as active.
788  /// @details See Tree::modifyValue() for details.
789  template<typename ModifyOp>
790  void modifyValue(const Coord& xyz, const ModifyOp& op)
791  {
792  if (this->isHashed(xyz)) {
793  assert(mNode);
794  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
795  const_cast<NodeType*>(mNode)->modifyValueAndCache(xyz, op, *mParent);
796  } else {
797  mNext.modifyValue(xyz, op);
798  }
799  }
800 
801  /// @brief Apply a functor to the voxel at the given coordinates.
802  /// @details See Tree::modifyValueAndActiveState() for details.
803  template<typename ModifyOp>
804  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
805  {
806  if (this->isHashed(xyz)) {
807  assert(mNode);
808  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
809  const_cast<NodeType*>(mNode)->modifyValueAndActiveStateAndCache(xyz, op, *mParent);
810  } else {
811  mNext.modifyValueAndActiveState(xyz, op);
812  }
813  }
814 
815  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
816  void setValueOff(const Coord& xyz, const ValueType& value)
817  {
818  if (this->isHashed(xyz)) {
819  assert(mNode);
820  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
821  const_cast<NodeType*>(mNode)->setValueOffAndCache(xyz, value, *mParent);
822  } else {
823  mNext.setValueOff(xyz, value);
824  }
825  }
826 
827  /// Set the active state of the voxel at the given coordinates.
828  void setActiveState(const Coord& xyz, bool on)
829  {
830  if (this->isHashed(xyz)) {
831  assert(mNode);
832  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
833  const_cast<NodeType*>(mNode)->setActiveStateAndCache(xyz, on, *mParent);
834  } else {
835  mNext.setActiveState(xyz, on);
836  }
837  }
838 
839 private:
840  CacheItem(const CacheItem&);
841  CacheItem& operator=(const CacheItem&);
842 
843  bool isHashed(const Coord& xyz) const
844  {
845  return (xyz[0] & ~Coord::ValueType(NodeType::DIM-1)) == mHash[0]
846  && (xyz[1] & ~Coord::ValueType(NodeType::DIM-1)) == mHash[1]
847  && (xyz[2] & ~Coord::ValueType(NodeType::DIM-1)) == mHash[2];
848  }
849 
850  TreeCacheT* mParent;
851  Coord mHash;
852  const NodeType* mNode;
853  using RestT = typename NodeVecT::PopFront;
854 #if OPENVDB_ABI_VERSION_NUMBER >= 10
855  // Next item is never a leaf node as a leaf node is only ever at
856  // the front of the chain
857  CacheItem<TreeCacheT, RestT, /*AtRoot=*/RestT::Size == 1, false> mNext;
858 #else
859  CacheItem<TreeCacheT, RestT, /*AtRoot=*/RestT::Size == 1> mNext;
860 #endif
861 };// end of CacheItem
862 
863 
864 #if OPENVDB_ABI_VERSION_NUMBER >= 10
865 
866 template<typename TreeCacheT, typename NodeVecT>
867 class CacheItem<TreeCacheT, NodeVecT, /*AtRoot=*/false, true>
868 {
869 public:
870  using NodeType = typename NodeVecT::Front;
871  using ValueType = typename NodeType::ValueType;
872  using LeafNodeType = typename NodeType::LeafNodeType;
873  using CoordLimits = std::numeric_limits<Int32>;
874 
876 
877  CacheItem(TreeCacheT& parent)
878  : mParent(&parent)
879  , mHash(CoordLimits::max())
880  , mNode(nullptr)
881  , mNext(parent)
882  , mBuffer(nullptr) {}
883 
884  //@{
885  /// Copy another CacheItem's node pointers and hash keys, but not its parent pointer.
886  CacheItem(TreeCacheT& parent, const CacheItem& other)
887  : mParent(&parent)
888  , mHash(other.mHash)
889  , mNode(other.mNode)
890  , mNext(parent, other.mNext)
891  , mBuffer(other.mBuffer) {}
892 
893  CacheItem& copy(TreeCacheT& parent, const CacheItem& other)
894  {
895  mParent = &parent;
896  mHash = other.mHash;
897  mNode = other.mNode;
898  mNext.copy(parent, other.mNext);
899  mBuffer = other.mBuffer;
900  return *this;
901  }
902  //@}
903 
904  bool isCached(const Coord& xyz) const
905  {
906  return (this->isHashed(xyz) || mNext.isCached(xyz));
907  }
908 
909  /// Cache the given node at this level.
910  void insert(const Coord& xyz, const NodeType* node)
911  {
912  mHash = (node != nullptr) ? xyz & ~(NodeType::DIM-1) : Coord::max();
913  mNode = node;
914  mBuffer = node ? node->buffer().data() : nullptr;
915  }
916  /// Forward the given node to another level of the cache.
917  template<typename OtherNodeType>
918  void insert(const Coord& xyz, const OtherNodeType* node) { mNext.insert(xyz, node); }
919 
920  /// Erase the node at this level.
921  void erase(const NodeType*) { mHash = Coord::max(); mNode = nullptr; }
922  /// Erase the node at another level of the cache.
923  template<typename OtherNodeType>
924  void erase(const OtherNodeType* node) { mNext.erase(node); }
925 
926  /// Erase the nodes at this and lower levels of the cache.
927  void clear() { mHash = Coord::max(); mNode = nullptr; mNext.clear(); }
928 
929  /// Return the cached node (if any) at this level.
930  void getNode(const NodeType*& node) const { node = mNode; }
931  void getNode(const NodeType*& node) { node = mNode; }
932  void getNode(NodeType*& node)
933  {
934  // This combination of a static assertion and a const_cast might not be elegant,
935  // but it is a lot simpler than specializing TreeCache for const Trees.
936  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
937  node = const_cast<NodeType*>(mNode);
938  }
939  /// Forward the request to another level of the cache.
940  template<typename OtherNodeType>
941  void getNode(OtherNodeType*& node) { mNext.getNode(node); }
942 
943  /// Return the value of the voxel at the given coordinates.
944  const ValueType& getValue(const Coord& xyz)
945  {
946  if (this->isHashed(xyz)) {
947  assert(mNode);
948  return mBuffer[LeafNodeType::coordToOffset(xyz)];
949  }
950  return mNext.getValue(xyz);
951  }
952 
953  void addLeaf(LeafNodeType* leaf)
954  {
955  mNext.addLeaf(leaf);
956  }
957 
958  void addTile(Index level, const Coord& xyz, const ValueType& value, bool state)
959  {
960  static_assert(!TreeCacheT::IsConstTree, "can't add a tile to a const tree");
961  if (NodeType::LEVEL >= level && this->isHashed(xyz)) {
962  assert(mNode);
963  const_cast<NodeType*>(mNode)->addTileAndCache(level, xyz, value, state, *mParent);
964  return;
965  }
966  mNext.addTile(level, xyz, value, state);
967  }
968 
969  LeafNodeType* touchLeaf(const Coord& xyz)
970  {
971  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
972  if (this->isHashed(xyz)) {
973  assert(mNode);
974  return const_cast<NodeType*>(mNode)->touchLeafAndCache(xyz, *mParent);
975  }
976  return mNext.touchLeaf(xyz);
977  }
978 
979  LeafNodeType* probeLeaf(const Coord& xyz)
980  {
981  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
982  if (this->isHashed(xyz)) {
983  assert(mNode);
984  return const_cast<NodeType*>(mNode)->probeLeafAndCache(xyz, *mParent);
985  }
986  return mNext.probeLeaf(xyz);
987  }
988 
989  const LeafNodeType* probeConstLeaf(const Coord& xyz)
990  {
991  if (this->isHashed(xyz)) {
992  assert(mNode);
993  return mNode->probeConstLeafAndCache(xyz, *mParent);
994  }
995  return mNext.probeConstLeaf(xyz);
996  }
997 
998  template<typename NodeT>
999  NodeT* probeNode(const Coord& xyz)
1000  {
1001  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
1002  if constexpr ((std::is_same<NodeT, NodeType>::value)) {
1003  if (this->isHashed(xyz)) {
1004  assert(mNode);
1005  return reinterpret_cast<NodeT*>(const_cast<NodeType*>(mNode));
1006  }
1007  }
1008 
1009  if (NodeT::LEVEL < NodeType::LEVEL && mNode) {
1010  // don't need to ascend the chain, descend the tree
1011  return const_cast<NodeType*>(mNode)->template probeNodeAndCache<NodeT>(xyz, *mParent);
1012  }
1013  else {
1014  // ascend
1015  return mNext.template probeNode<NodeT>(xyz);
1016  }
1017  }
1018 
1019  template<typename NodeT>
1020  const NodeT* probeConstNode(const Coord& xyz)
1021  {
1022  if constexpr ((std::is_same<NodeT, NodeType>::value)) {
1023  if (this->isHashed(xyz)) {
1024  assert(mNode);
1025  return reinterpret_cast<const NodeT*>(mNode);
1026  }
1027  }
1028 
1029  if (NodeT::LEVEL < NodeType::LEVEL && mNode) {
1030  // don't need to ascend the chain, descend the tree
1031  return mNode->template probeConstNodeAndCache<NodeT>(xyz, *mParent);
1032  }
1033  else {
1034  // ascend
1035  return mNext.template probeConstNode<NodeT>(xyz);
1036  }
1037  }
1038 
1039  /// Return the active state of the voxel at the given coordinates.
1040  bool isValueOn(const Coord& xyz)
1041  {
1042  if (this->isHashed(xyz)) {
1043  assert(mNode);
1044  return mNode->isValueOnAndCache(xyz, *mParent);
1045  }
1046  return mNext.isValueOn(xyz);
1047  }
1048 
1049  /// Return the active state and value of the voxel at the given coordinates.
1050  bool probeValue(const Coord& xyz, ValueType& value)
1051  {
1052  if (this->isHashed(xyz)) {
1053  assert(mNode);
1054  assert(mBuffer);
1055  const auto offset = LeafNodeType::coordToOffset(xyz);
1056  value = mBuffer[offset];
1057  return mNode->isValueOn(offset);
1058  }
1059  return mNext.probeValue(xyz, value);
1060  }
1061 
1062  int getValueDepth(const Coord& xyz)
1063  {
1064  if (this->isHashed(xyz)) {
1065  assert(mNode);
1066  return static_cast<int>(TreeCacheT::RootNodeT::LEVEL) -
1067  static_cast<int>(mNode->getValueLevelAndCache(xyz, *mParent));
1068  } else {
1069  return mNext.getValueDepth(xyz);
1070  }
1071  }
1072 
1073  bool isVoxel(const Coord& xyz)
1074  {
1075  if (this->isHashed(xyz)) {
1076  assert(mNode);
1077  return mNode->getValueLevelAndCache(xyz, *mParent)==0;
1078  } else {
1079  return mNext.isVoxel(xyz);
1080  }
1081  }
1082 
1083  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
1084  void setValue(const Coord& xyz, const ValueType& value)
1085  {
1086  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
1087 
1088  if (this->isHashed(xyz)) {
1089  assert(mNode);
1090  assert(mBuffer);
1091  const auto offset = LeafNodeType::coordToOffset(xyz);
1092  const_cast<ValueType&>(mBuffer[offset]) = value;
1093  const_cast<NodeType*>(mNode)->setValueOn(offset);
1094  } else {
1095  mNext.setValue(xyz, value);
1096  }
1097  }
1098  void setValueOnly(const Coord& xyz, const ValueType& value)
1099  {
1100  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
1101  if (this->isHashed(xyz)) {
1102  assert(mNode);
1103  assert(mBuffer);
1104  const auto offset = LeafNodeType::coordToOffset(xyz);
1105  const_cast<ValueType&>(mBuffer[offset]) = value;
1106  } else {
1107  mNext.setValueOnly(xyz, value);
1108  }
1109  }
1110  void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); }
1111 
1112  /// @brief Apply a functor to the value of the voxel at the given coordinates
1113  /// and mark the voxel as active.
1114  /// @details See Tree::modifyValue() for details.
1115  template<typename ModifyOp>
1116  void modifyValue(const Coord& xyz, const ModifyOp& op)
1117  {
1118  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
1119  if (this->isHashed(xyz)) {
1120  assert(mNode);
1121  assert(mBuffer);
1122  const auto offset = LeafNodeType::coordToOffset(xyz);
1123  op(const_cast<ValueType&>(mBuffer[offset]));
1124  const_cast<NodeType*>(mNode)->setActiveState(offset, true);
1125  } else {
1126  mNext.modifyValue(xyz, op);
1127  }
1128  }
1129 
1130  /// @brief Apply a functor to the voxel at the given coordinates.
1131  /// @details See Tree::modifyValueAndActiveState() for details.
1132  template<typename ModifyOp>
1133  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
1134  {
1135  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
1136  if (this->isHashed(xyz)) {
1137  assert(mNode);
1138  assert(mBuffer);
1139  const auto offset = LeafNodeType::coordToOffset(xyz);
1140  bool state = mNode->isValueOn(offset);
1141  op(const_cast<ValueType&>(mBuffer[offset]), state);
1142  const_cast<NodeType*>(mNode)->setActiveState(offset, state);
1143  } else {
1144  mNext.modifyValueAndActiveState(xyz, op);
1145  }
1146  }
1147 
1148  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
1149  void setValueOff(const Coord& xyz, const ValueType& value)
1150  {
1151  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
1152  if (this->isHashed(xyz)) {
1153  assert(mNode);
1154  const_cast<NodeType*>(mNode)->setValueOffAndCache(xyz, value, *mParent);
1155  } else {
1156  mNext.setValueOff(xyz, value);
1157  }
1158  }
1159 
1160  /// Set the active state of the voxel at the given coordinates.
1161  void setActiveState(const Coord& xyz, bool on)
1162  {
1163  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
1164  if (this->isHashed(xyz)) {
1165  assert(mNode);
1166  const_cast<NodeType*>(mNode)->setActiveStateAndCache(xyz, on, *mParent);
1167  } else {
1168  mNext.setActiveState(xyz, on);
1169  }
1170  }
1171 
1172 private:
1173  CacheItem(const CacheItem&);
1174  CacheItem& operator=(const CacheItem&);
1175 
1176  bool isHashed(const Coord& xyz) const
1177  {
1178  return (xyz[0] & ~Coord::ValueType(NodeType::DIM-1)) == mHash[0]
1179  && (xyz[1] & ~Coord::ValueType(NodeType::DIM-1)) == mHash[1]
1180  && (xyz[2] & ~Coord::ValueType(NodeType::DIM-1)) == mHash[2];
1181  }
1182 
1183  TreeCacheT* mParent;
1184  Coord mHash;
1185  const NodeType* mNode;
1186  using RestT = typename NodeVecT::PopFront;
1187  CacheItem<TreeCacheT, RestT, /*AtRoot=*/RestT::Size == 1> mNext;
1188  const ValueType* mBuffer;
1189 };// end of CacheItem
1190 
1191 #endif
1192 
1193 /// The tail of a compile-time list of cached node pointers, ordered from LeafNode to RootNode
1194 template<typename TreeCacheT, typename NodeVecT>
1195 class CacheItem<TreeCacheT, NodeVecT, /*AtRoot=*/true
1196 #if OPENVDB_ABI_VERSION_NUMBER >= 10
1197 , /*BypassLeafAPI=*/false
1198 #endif
1199 >
1200 {
1201 public:
1202  using RootNodeType = typename NodeVecT::Front;
1203  using ValueType = typename RootNodeType::ValueType;
1204  using LeafNodeType = typename RootNodeType::LeafNodeType;
1205 
1206  CacheItem(TreeCacheT& parent): mParent(&parent), mRoot(nullptr) {}
1207  CacheItem(TreeCacheT& parent, const CacheItem& other): mParent(&parent), mRoot(other.mRoot) {}
1208 
1209  CacheItem& copy(TreeCacheT& parent, const CacheItem& other)
1210  {
1211  mParent = &parent;
1212  mRoot = other.mRoot;
1213  return *this;
1214  }
1215 
1216  bool isCached(const Coord& xyz) const { return this->isHashed(xyz); }
1217 
1218  void insert(const Coord&, const RootNodeType* root) { mRoot = root; }
1219 
1220  // Needed for node types that are not cached
1221  template<typename OtherNodeType>
1222  void insert(const Coord&, const OtherNodeType*) {}
1223 
1224  void erase(const RootNodeType*) { mRoot = nullptr; }
1225 
1226  void clear() { mRoot = nullptr; }
1227 
1228  void getNode(RootNodeType*& node)
1229  {
1230  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
1231  node = const_cast<RootNodeType*>(mRoot);
1232  }
1233  void getNode(const RootNodeType*& node) const { node = mRoot; }
1234 
1235  void addLeaf(LeafNodeType* leaf)
1236  {
1237  assert(mRoot);
1238  static_assert(!TreeCacheT::IsConstTree, "can't add a node to a const tree");
1239  const_cast<RootNodeType*>(mRoot)->addLeafAndCache(leaf, *mParent);
1240  }
1241 
1242  void addTile(Index level, const Coord& xyz, const ValueType& value, bool state)
1243  {
1244  assert(mRoot);
1245  static_assert(!TreeCacheT::IsConstTree, "can't add a tile to a const tree");
1246  const_cast<RootNodeType*>(mRoot)->addTileAndCache(level, xyz, value, state, *mParent);
1247  }
1248 
1249  LeafNodeType* touchLeaf(const Coord& xyz)
1250  {
1251  assert(mRoot);
1252  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
1253  return const_cast<RootNodeType*>(mRoot)->touchLeafAndCache(xyz, *mParent);
1254  }
1255 
1256  LeafNodeType* probeLeaf(const Coord& xyz)
1257  {
1258  assert(mRoot);
1259  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
1260  return const_cast<RootNodeType*>(mRoot)->probeLeafAndCache(xyz, *mParent);
1261  }
1262 
1263  const LeafNodeType* probeConstLeaf(const Coord& xyz)
1264  {
1265  assert(mRoot);
1266  return mRoot->probeConstLeafAndCache(xyz, *mParent);
1267  }
1268 
1269  template<typename NodeType>
1270  NodeType* probeNode(const Coord& xyz)
1271  {
1272  assert(mRoot);
1273  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
1274  return const_cast<RootNodeType*>(mRoot)->
1275  template probeNodeAndCache<NodeType>(xyz, *mParent);
1276  }
1277 
1278  template<typename NodeType>
1279  const NodeType* probeConstNode(const Coord& xyz)
1280  {
1281  assert(mRoot);
1282  return mRoot->template probeConstNodeAndCache<NodeType>(xyz, *mParent);
1283  }
1284 
1285  int getValueDepth(const Coord& xyz)
1286  {
1287  assert(mRoot);
1288  return mRoot->getValueDepthAndCache(xyz, *mParent);
1289  }
1290  bool isValueOn(const Coord& xyz)
1291  {
1292  assert(mRoot);
1293  return mRoot->isValueOnAndCache(xyz, *mParent);
1294  }
1295 
1296  bool probeValue(const Coord& xyz, ValueType& value)
1297  {
1298  assert(mRoot);
1299  return mRoot->probeValueAndCache(xyz, value, *mParent);
1300  }
1301  bool isVoxel(const Coord& xyz)
1302  {
1303  assert(mRoot);
1304  return mRoot->getValueDepthAndCache(xyz, *mParent) ==
1305  static_cast<int>(RootNodeType::LEVEL);
1306  }
1307  const ValueType& getValue(const Coord& xyz)
1308  {
1309  assert(mRoot);
1310  return mRoot->getValueAndCache(xyz, *mParent);
1311  }
1312 
1313  void setValue(const Coord& xyz, const ValueType& value)
1314  {
1315  assert(mRoot);
1316  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
1317  const_cast<RootNodeType*>(mRoot)->setValueAndCache(xyz, value, *mParent);
1318  }
1319  void setValueOnly(const Coord& xyz, const ValueType& value)
1320  {
1321  assert(mRoot);
1322  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
1323  const_cast<RootNodeType*>(mRoot)->setValueOnlyAndCache(xyz, value, *mParent);
1324  }
1325  void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); }
1326 
1327  template<typename ModifyOp>
1328  void modifyValue(const Coord& xyz, const ModifyOp& op)
1329  {
1330  assert(mRoot);
1331  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
1332  const_cast<RootNodeType*>(mRoot)->modifyValueAndCache(xyz, op, *mParent);
1333  }
1334 
1335  template<typename ModifyOp>
1336  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
1337  {
1338  assert(mRoot);
1339  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
1340  const_cast<RootNodeType*>(mRoot)->modifyValueAndActiveStateAndCache(xyz, op, *mParent);
1341  }
1342 
1343  void setValueOff(const Coord& xyz, const ValueType& value)
1344  {
1345  assert(mRoot);
1346  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
1347  const_cast<RootNodeType*>(mRoot)->setValueOffAndCache(xyz, value, *mParent);
1348  }
1349 
1350  void setActiveState(const Coord& xyz, bool on)
1351  {
1352  assert(mRoot);
1353  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
1354  const_cast<RootNodeType*>(mRoot)->setActiveStateAndCache(xyz, on, *mParent);
1355  }
1356 
1357 private:
1358  CacheItem(const CacheItem&);
1359  CacheItem& operator=(const CacheItem&);
1360 
1361  bool isHashed(const Coord&) const { return false; }
1362 
1363  TreeCacheT* mParent;
1364  const RootNodeType* mRoot;
1365 };// end of CacheItem specialized for RootNode
1366 
1367 
1368 ////////////////////////////////////////
1369 
1370 
1371 /// @brief ValueAccessor with no mutex and no node caching.
1372 /// @details This specialization is provided mainly for benchmarking.
1373 /// Accessors with caching will almost always be faster.
1374 template<typename _TreeType, bool IsSafe>
1375 class ValueAccessor0: public ValueAccessorBase<_TreeType, IsSafe>
1376 {
1377 public:
1378  using TreeType = _TreeType;
1379  using ValueType = typename TreeType::ValueType;
1380  using RootNodeT = typename TreeType::RootNodeType;
1381  using LeafNodeT = typename TreeType::LeafNodeType;
1383 
1384 #if OPENVDB_ABI_VERSION_NUMBER >= 10
1385  // No caching, nothing to do
1386  static constexpr bool BypassLeafAPI = false;
1387 #endif
1388 
1389  ValueAccessor0(TreeType& tree): BaseT(tree) {}
1390 
1391  ValueAccessor0(const ValueAccessor0& other): BaseT(other) {}
1392 
1393  /// Return the number of cache levels employed by this accessor.
1394  static Index numCacheLevels() { return 0; }
1395 
1397  {
1398  if (&other != this) this->BaseT::operator=(other);
1399  return *this;
1400  }
1401 
1402  ~ValueAccessor0() override = default;
1403 
1404  /// Return @c true if nodes along the path to the given voxel have been cached.
1405  bool isCached(const Coord&) const { return false; }
1406 
1407  /// Return the value of the voxel at the given coordinates.
1408  const ValueType& getValue(const Coord& xyz) const
1409  {
1410  assert(BaseT::mTree);
1411  return BaseT::mTree->getValue(xyz);
1412  }
1413 
1414  /// Return the active state of the voxel at the given coordinates.
1415  bool isValueOn(const Coord& xyz) const
1416  {
1417  assert(BaseT::mTree);
1418  return BaseT::mTree->isValueOn(xyz);
1419  }
1420 
1421  /// Return the active state and, in @a value, the value of the voxel at the given coordinates.
1422  bool probeValue(const Coord& xyz, ValueType& value) const
1423  {
1424  assert(BaseT::mTree);
1425  return BaseT::mTree->probeValue(xyz, value);
1426  }
1427 
1428  /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides,
1429  /// or -1 if (x, y, z) isn't explicitly represented in the tree (i.e., if it is
1430  /// implicitly a background voxel).
1431  int getValueDepth(const Coord& xyz) const
1432  {
1433  assert(BaseT::mTree);
1434  return BaseT::mTree->getValueDepth(xyz);
1435  }
1436 
1437  /// Return @c true if the value of voxel (x, y, z) resides at the leaf level
1438  /// of the tree, i.e., if it is not a tile value.
1439  bool isVoxel(const Coord& xyz) const
1440  {
1441  assert(BaseT::mTree);
1442  return BaseT::mTree->getValueDepth(xyz) == static_cast<int>(RootNodeT::LEVEL);
1443  }
1444 
1445  //@{
1446  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
1447  void setValue(const Coord& xyz, const ValueType& value)
1448  {
1449  assert(BaseT::mTree);
1450  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1451  BaseT::mTree->setValue(xyz, value);
1452  }
1453  void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); }
1454  //@}
1455 
1456  /// Set the value of the voxel at the given coordinate but don't change its active state.
1457  void setValueOnly(const Coord& xyz, const ValueType& value)
1458  {
1459  assert(BaseT::mTree);
1460  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1461  BaseT::mTree->setValueOnly(xyz, value);
1462  }
1463 
1464  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
1465  void setValueOff(const Coord& xyz, const ValueType& value)
1466  {
1467  assert(BaseT::mTree);
1468  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1469  BaseT::mTree->root().setValueOff(xyz, value);
1470  }
1471 
1472  /// @brief Apply a functor to the value of the voxel at the given coordinates
1473  /// and mark the voxel as active.
1474  /// @details See Tree::modifyValue() for details.
1475  template<typename ModifyOp>
1476  void modifyValue(const Coord& xyz, const ModifyOp& op)
1477  {
1478  assert(BaseT::mTree);
1479  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1480  BaseT::mTree->modifyValue(xyz, op);
1481  }
1482 
1483  /// @brief Apply a functor to the voxel at the given coordinates.
1484  /// @details See Tree::modifyValueAndActiveState() for details.
1485  template<typename ModifyOp>
1486  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
1487  {
1488  assert(BaseT::mTree);
1489  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1490  BaseT::mTree->modifyValueAndActiveState(xyz, op);
1491  }
1492 
1493  /// Set the active state of the voxel at the given coordinates but don't change its value.
1494  void setActiveState(const Coord& xyz, bool on = true)
1495  {
1496  assert(BaseT::mTree);
1497  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1498  BaseT::mTree->setActiveState(xyz, on);
1499  }
1500  /// Mark the voxel at the given coordinates as active but don't change its value.
1501  void setValueOn(const Coord& xyz) { this->setActiveState(xyz, true); }
1502  /// Mark the voxel at the given coordinates as inactive but don't change its value.
1503  void setValueOff(const Coord& xyz) { this->setActiveState(xyz, false); }
1504 
1505  /// Return the cached node of type @a NodeType. [Mainly for internal use]
1506  template<typename NodeT> NodeT* getNode() { return nullptr; }
1507 
1508  /// Cache the given node, which should lie along the path from the root node to
1509  /// the node containing voxel (x, y, z). [Mainly for internal use]
1510  template<typename NodeT> void insertNode(const Coord&, NodeT&) {}
1511 
1512  /// @brief Add the specified leaf to this tree, possibly creating a child branch
1513  /// in the process. If the leaf node already exists, replace it.
1514  void addLeaf(LeafNodeT* leaf)
1515  {
1516  assert(BaseT::mTree);
1517  static_assert(!BaseT::IsConstTree, "can't add a node to a const tree");
1518  BaseT::mTree->root().addLeaf(leaf);
1519  }
1520 
1521  /// @brief Add a tile at the specified tree level that contains voxel (x, y, z),
1522  /// possibly deleting existing nodes or creating new nodes in the process.
1523  void addTile(Index level, const Coord& xyz, const ValueType& value, bool state)
1524  {
1525  assert(BaseT::mTree);
1526  static_assert(!BaseT::IsConstTree, "can't add a tile to a const tree");
1527  BaseT::mTree->root().addTile(level, xyz, value, state);
1528  }
1529 
1530  /// If a node of the given type exists in the cache, remove it, so that
1531  /// isCached(xyz) returns @c false for any voxel (x, y, z) contained in
1532  /// that node. [Mainly for internal use]
1533  template<typename NodeT> void eraseNode() {}
1534 
1535  LeafNodeT* touchLeaf(const Coord& xyz)
1536  {
1537  assert(BaseT::mTree);
1538  static_assert(!BaseT::IsConstTree, "can't get a non-const node from a const tree");
1539  return BaseT::mTree->touchLeaf(xyz);
1540  }
1541 
1542  template<typename NodeT>
1543  NodeT* probeNode(const Coord& xyz)
1544  {
1545  assert(BaseT::mTree);
1546  static_assert(!BaseT::IsConstTree, "can't get a non-const node from a const tree");
1547  return BaseT::mTree->template probeNode<NodeT>(xyz);
1548  }
1549 
1550  template<typename NodeT>
1551  const NodeT* probeConstNode(const Coord& xyz) const
1552  {
1553  assert(BaseT::mTree);
1554  return BaseT::mTree->template probeConstNode<NodeT>(xyz);
1555  }
1556 
1557  LeafNodeT* probeLeaf(const Coord& xyz)
1558  {
1559  return this->template probeNode<LeafNodeT>(xyz);
1560  }
1561 
1562  const LeafNodeT* probeConstLeaf(const Coord& xyz) const
1563  {
1564  return this->template probeConstNode<LeafNodeT>(xyz);
1565  }
1566 
1567  const LeafNodeT* probeLeaf(const Coord& xyz) const
1568  {
1569  return this->probeConstLeaf(xyz);
1570  }
1571 
1572  /// Remove all nodes from this cache, then reinsert the root node.
1573  void clear() override {}
1574 
1575 private:
1576  // Allow trees to deregister themselves.
1577  template<typename> friend class Tree;
1578 
1579  /// Prevent this accessor from calling Tree::releaseCache() on a tree that
1580  /// no longer exists. (Called by mTree when it is destroyed.)
1581  void release() override { this->BaseT::release(); }
1582 
1583 }; // ValueAccessor0
1584 
1585 
1586 /// @brief Value accessor with one level of node caching.
1587 /// @details The node cache level is specified by L0 with the default value 0
1588 /// (defined in the forward declaration) corresponding to a LeafNode.
1589 ///
1590 /// @note This class is for experts only and should rarely be used
1591 /// directly. Instead use ValueAccessor with its default template arguments.
1592 template<typename _TreeType, bool IsSafe, Index L0>
1594 {
1595 public:
1596  static_assert(_TreeType::DEPTH >= 2, "cache size exceeds tree depth");
1597  static_assert(L0 < _TreeType::RootNodeType::LEVEL, "invalid cache level");
1598  using TreeType = _TreeType;
1599  using ValueType = typename TreeType::ValueType;
1600  using RootNodeT = typename TreeType::RootNodeType;
1601  using LeafNodeT = typename TreeType::LeafNodeType;
1603  using InvTreeT = typename RootNodeT::NodeChainType;
1604  using NodeT0 = typename InvTreeT::template Get<L0>;
1605 
1606 #if OPENVDB_ABI_VERSION_NUMBER >= 10
1607  // If the last node being cached is a leaf node and the storage type matches
1608  // the ValueType, we can cache the buffer pointer instead of using the delay
1609  // load locked leaf API
1610  static constexpr bool BypassLeafAPI =
1613 #endif
1614 
1615  /// Constructor from a tree
1617  : BaseT(tree)
1618  , mKey0(Coord::max()), mNode0(nullptr)
1619 #if OPENVDB_ABI_VERSION_NUMBER >= 10
1620  , mBuffer(nullptr)
1621 #endif
1622  {}
1623 
1624  /// Copy constructor
1625  ValueAccessor1(const ValueAccessor1& other) : BaseT(other) { this->copy(other); }
1626 
1627  /// Return the number of cache levels employed by this ValueAccessor
1628  static Index numCacheLevels() { return 1; }
1629 
1630  /// Assignment operator
1632  {
1633  if (&other != this) {
1634  this->BaseT::operator=(other);
1635  this->copy(other);
1636  }
1637  return *this;
1638  }
1639 
1640  /// Virtual destructor
1641  ~ValueAccessor1() override = default;
1642 
1643  /// Return @c true if any of the nodes along the path to the given
1644  /// voxel have been cached.
1645  bool isCached(const Coord& xyz) const
1646  {
1647  assert(BaseT::mTree);
1648  return this->isHashed(xyz);
1649  }
1650 
1651  /// Return the value of the voxel at the given coordinates.
1652  const ValueType& getValue(const Coord& xyz) const
1653  {
1654  assert(BaseT::mTree);
1655  if (this->isHashed(xyz)) {
1656  assert(mNode0);
1657 #if OPENVDB_ABI_VERSION_NUMBER >= 10
1658  if constexpr(BypassLeafAPI) {
1659  assert(mBuffer);
1660  return mBuffer[LeafNodeT::coordToOffset(xyz)];
1661  }
1662 #endif
1663  return mNode0->getValueAndCache(xyz, this->self());
1664  }
1665  return BaseT::mTree->root().getValueAndCache(xyz, this->self());
1666  }
1667 
1668  /// Return the active state of the voxel at the given coordinates.
1669  bool isValueOn(const Coord& xyz) const
1670  {
1671  assert(BaseT::mTree);
1672  if (this->isHashed(xyz)) {
1673  assert(mNode0);
1674  return mNode0->isValueOnAndCache(xyz, this->self());
1675  }
1676  return BaseT::mTree->root().isValueOnAndCache(xyz, this->self());
1677  }
1678 
1679  /// Return the active state of the voxel as well as its value
1680  bool probeValue(const Coord& xyz, ValueType& value) const
1681  {
1682  assert(BaseT::mTree);
1683  if (this->isHashed(xyz)) {
1684  assert(mNode0);
1685 #if OPENVDB_ABI_VERSION_NUMBER >= 10
1686  if constexpr(BypassLeafAPI) {
1687  assert(mBuffer);
1688  const auto offset = LeafNodeT::coordToOffset(xyz);
1689  value = mBuffer[offset];
1690  return mNode0->isValueOn(offset);
1691  }
1692 #endif
1693  return mNode0->probeValueAndCache(xyz, value, this->self());
1694  }
1695  return BaseT::mTree->root().probeValueAndCache(xyz, value, this->self());
1696  }
1697 
1698  /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides,
1699  /// or -1 if (x, y, z) isn't explicitly represented in the tree (i.e., if it is
1700  /// implicitly a background voxel).
1701  int getValueDepth(const Coord& xyz) const
1702  {
1703  assert(BaseT::mTree);
1704  if (this->isHashed(xyz)) {
1705  assert(mNode0);
1706  return RootNodeT::LEVEL - mNode0->getValueLevelAndCache(xyz, this->self());
1707  }
1708  return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self());
1709  }
1710 
1711  /// Return @c true if the value of voxel (x, y, z) resides at the leaf level
1712  /// of the tree, i.e., if it is not a tile value.
1713  bool isVoxel(const Coord& xyz) const
1714  {
1715  assert(BaseT::mTree);
1716  if (this->isHashed(xyz)) {
1717  assert(mNode0);
1718  return mNode0->getValueLevelAndCache(xyz, this->self()) == 0;
1719  }
1720  return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self()) ==
1721  static_cast<int>(RootNodeT::LEVEL);
1722  }
1723 
1724  //@{
1725  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
1726  void setValue(const Coord& xyz, const ValueType& value)
1727  {
1728  assert(BaseT::mTree);
1729  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1730  if (this->isHashed(xyz)) {
1731  assert(mNode0);
1732 #if OPENVDB_ABI_VERSION_NUMBER >= 10
1733  if constexpr(BypassLeafAPI) {
1734  assert(mBuffer);
1735  const auto offset = LeafNodeT::coordToOffset(xyz);
1736  const_cast<ValueType&>(mBuffer[offset]) = value;
1737  const_cast<NodeT0*>(mNode0)->setValueOn(offset);
1738  return;
1739  }
1740 #endif
1741  const_cast<NodeT0*>(mNode0)->setValueAndCache(xyz, value, *this);
1742  } else {
1743  BaseT::mTree->root().setValueAndCache(xyz, value, *this);
1744  }
1745  }
1746  void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); }
1747  //@}
1748 
1749  /// Set the value of the voxel at the given coordinate but preserves its active state.
1750  void setValueOnly(const Coord& xyz, const ValueType& value)
1751  {
1752  assert(BaseT::mTree);
1753  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1754  if (this->isHashed(xyz)) {
1755  assert(mNode0);
1756 #if OPENVDB_ABI_VERSION_NUMBER >= 10
1757  if constexpr(BypassLeafAPI) {
1758  assert(mBuffer);
1759  const auto offset = LeafNodeT::coordToOffset(xyz);
1760  const_cast<ValueType&>(mBuffer[offset]) = value;
1761  return;
1762  }
1763 #endif
1764  const_cast<NodeT0*>(mNode0)->setValueOnlyAndCache(xyz, value, *this);
1765  } else {
1766  BaseT::mTree->root().setValueOnlyAndCache(xyz, value, *this);
1767  }
1768  }
1769 
1770  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
1771  void setValueOff(const Coord& xyz, const ValueType& value)
1772  {
1773  assert(BaseT::mTree);
1774  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1775  if (this->isHashed(xyz)) {
1776  assert(mNode0);
1777  const_cast<NodeT0*>(mNode0)->setValueOffAndCache(xyz, value, *this);
1778  } else {
1779  BaseT::mTree->root().setValueOffAndCache(xyz, value, *this);
1780  }
1781  }
1782 
1783  /// @brief Apply a functor to the value of the voxel at the given coordinates
1784  /// and mark the voxel as active.
1785  /// @details See Tree::modifyValue() for details.
1786  template<typename ModifyOp>
1787  void modifyValue(const Coord& xyz, const ModifyOp& op)
1788  {
1789  assert(BaseT::mTree);
1790  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1791  if (this->isHashed(xyz)) {
1792  assert(mNode0);
1793 #if OPENVDB_ABI_VERSION_NUMBER >= 10
1794  if constexpr(BypassLeafAPI) {
1795  assert(mBuffer);
1796  const auto offset = LeafNodeT::coordToOffset(xyz);
1797  op(const_cast<ValueType&>(mBuffer[offset]));
1798  const_cast<NodeT0*>(mNode0)->setActiveState(offset, true);
1799  return;
1800  }
1801 #endif
1802  const_cast<NodeT0*>(mNode0)->modifyValueAndCache(xyz, op, *this);
1803  } else {
1804  BaseT::mTree->root().modifyValueAndCache(xyz, op, *this);
1805  }
1806  }
1807 
1808  /// @brief Apply a functor to the voxel at the given coordinates.
1809  /// @details See Tree::modifyValueAndActiveState() for details.
1810  template<typename ModifyOp>
1811  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
1812  {
1813  assert(BaseT::mTree);
1814  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1815  if (this->isHashed(xyz)) {
1816  assert(mNode0);
1817 #if OPENVDB_ABI_VERSION_NUMBER >= 10
1818  if constexpr(BypassLeafAPI) {
1819  assert(mBuffer);
1820  const auto offset = LeafNodeT::coordToOffset(xyz);
1821  bool state = mNode0->isValueOn(offset);
1822  op(const_cast<ValueType&>(mBuffer[offset]), state);
1823  const_cast<NodeT0*>(mNode0)->setActiveState(offset, state);
1824  return;
1825  }
1826 #endif
1827  const_cast<NodeT0*>(mNode0)->modifyValueAndActiveStateAndCache(xyz, op, *this);
1828  } else {
1829  BaseT::mTree->root().modifyValueAndActiveStateAndCache(xyz, op, *this);
1830  }
1831  }
1832 
1833  /// Set the active state of the voxel at the given coordinates but don't change its value.
1834  void setActiveState(const Coord& xyz, bool on = true)
1835  {
1836  assert(BaseT::mTree);
1837  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1838  if (this->isHashed(xyz)) {
1839  assert(mNode0);
1840  const_cast<NodeT0*>(mNode0)->setActiveStateAndCache(xyz, on, *this);
1841  } else {
1842  BaseT::mTree->root().setActiveStateAndCache(xyz, on, *this);
1843  }
1844  }
1845  /// Mark the voxel at the given coordinates as active but don't change its value.
1846  void setValueOn(const Coord& xyz) { this->setActiveState(xyz, true); }
1847  /// Mark the voxel at the given coordinates as inactive but don't change its value.
1848  void setValueOff(const Coord& xyz) { this->setActiveState(xyz, false); }
1849 
1850  /// Return the cached node of type @a NodeType. [Mainly for internal use]
1851  template<typename NodeT>
1852  NodeT* getNode()
1853  {
1854  const NodeT* node = nullptr;
1855  this->getNode(node);
1856  return const_cast<NodeT*>(node);
1857  }
1858 
1859  /// Cache the given node, which should lie along the path from the root node to
1860  /// the node containing voxel (x, y, z). [Mainly for internal use]
1861  template<typename NodeT>
1862  void insertNode(const Coord& xyz, NodeT& node) { this->insert(xyz, &node); }
1863 
1864  /// If a node of the given type exists in the cache, remove it, so that
1865  /// isCached(xyz) returns @c false for any voxel (x, y, z) contained in
1866  /// that node. [Mainly for internal use]
1867  template<typename NodeT>
1868  void eraseNode()
1869  {
1870  const NodeT* node = nullptr;
1871  this->eraseNode(node);
1872  }
1873 
1874  /// @brief Add the specified leaf to this tree, possibly creating a child branch
1875  /// in the process. If the leaf node already exists, replace it.
1876  void addLeaf(LeafNodeT* leaf)
1877  {
1878  assert(BaseT::mTree);
1879  static_assert(!BaseT::IsConstTree, "can't add a node to a const tree");
1880  BaseT::mTree->root().addLeaf(leaf);
1881  }
1882 
1883  /// @brief Add a tile at the specified tree level that contains voxel (x, y, z),
1884  /// possibly deleting existing nodes or creating new nodes in the process.
1885  void addTile(Index level, const Coord& xyz, const ValueType& value, bool state)
1886  {
1887  assert(BaseT::mTree);
1888  static_assert(!BaseT::IsConstTree, "can't add a tile to a const tree");
1889  BaseT::mTree->root().addTile(level, xyz, value, state);
1890  }
1891 
1892  /// @brief @return the leaf node that contains voxel (x, y, z) and
1893  /// if it doesn't exist, create it, but preserve the values and
1894  /// active states of all voxels.
1895  ///
1896  /// Use this method to preallocate a static tree topology over which to
1897  /// safely perform multithreaded processing.
1898  LeafNodeT* touchLeaf(const Coord& xyz)
1899  {
1900  assert(BaseT::mTree);
1901  static_assert(!BaseT::IsConstTree, "can't get a non-const node from a const tree");
1902  if (this->isHashed(xyz)) {
1903  assert(mNode0);
1904  return const_cast<NodeT0*>(mNode0)->touchLeafAndCache(xyz, *this);
1905  }
1906  return BaseT::mTree->root().touchLeafAndCache(xyz, *this);
1907  }
1908 
1909  /// @brief @return a pointer to the node of the specified type that contains
1910  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
1911  template<typename NodeT>
1912  NodeT* probeNode(const Coord& xyz)
1913  {
1914  assert(BaseT::mTree);
1915  static_assert(!BaseT::IsConstTree, "can't get a non-const node from a const tree");
1916  if constexpr ((std::is_same<NodeT, NodeT0>::value)) {
1917  if (this->isHashed(xyz)) {
1918  assert(mNode0);
1919  return reinterpret_cast<NodeT*>(const_cast<NodeT0*>(mNode0));
1920  }
1921  return BaseT::mTree->root().template probeNodeAndCache<NodeT>(xyz, *this);
1922  } else if constexpr (NodeT::LEVEL < NodeT0::LEVEL) {
1923  // Might still be worth caching this path if a NodeT0
1924  // is accessed in the future
1925  return BaseT::mTree->root().template probeNodeAndCache<NodeT>(xyz, *this);
1926  } else {
1927  // If we're accessing a node above our top most cache level then
1928  // there's no point trying to cache it
1929  return BaseT::mTree->root().template probeNode<NodeT>(xyz);
1930  }
1931  }
1932  LeafNodeT* probeLeaf(const Coord& xyz)
1933  {
1934  return this->template probeNode<LeafNodeT>(xyz);
1935  }
1936 
1937  /// @brief @return a const pointer to the nodeof the specified type that contains
1938  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
1939  template<typename NodeT>
1940  const NodeT* probeConstNode(const Coord& xyz) const
1941  {
1942  assert(BaseT::mTree);
1943  if constexpr ((std::is_same<NodeT, NodeT0>::value)) {
1944  if (this->isHashed(xyz)) {
1945  assert(mNode0);
1946  return reinterpret_cast<const NodeT*>(mNode0);
1947  }
1948  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
1949  } else if constexpr (NodeT::LEVEL < NodeT0::LEVEL) {
1950  // Might still be worth caching this path if a NodeT0
1951  // is accessed in the future
1952  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
1953  } else {
1954  // If we're accessing a node above our top most cache level then
1955  // there's no point trying to cache it
1956  return BaseT::mTree->root().template probeConstNode<NodeT>(xyz);
1957  }
1958  }
1959  const LeafNodeT* probeConstLeaf(const Coord& xyz) const
1960  {
1961  return this->template probeConstNode<LeafNodeT>(xyz);
1962  }
1963  const LeafNodeT* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); }
1964 
1965  /// Remove all the cached nodes and invalidate the corresponding hash-keys.
1966  void clear() override
1967  {
1968  mKey0 = Coord::max();
1969  mNode0 = nullptr;
1970 #if OPENVDB_ABI_VERSION_NUMBER >= 10
1971  mBuffer = nullptr;
1972 #endif
1973  }
1974 
1975 private:
1976  // Allow nodes to insert themselves into the cache.
1977  template<typename> friend class RootNode;
1978  template<typename, Index> friend class InternalNode;
1979  template<typename, Index> friend class LeafNode;
1980  // Allow trees to deregister themselves.
1981  template<typename> friend class Tree;
1982 
1983  // This private method is merely for convenience.
1984  inline ValueAccessor1& self() const { return const_cast<ValueAccessor1&>(*this); }
1985 
1986  void getNode(const NodeT0*& node) { node = mNode0; }
1987  void getNode(const RootNodeT*& node)
1988  {
1989  node = (BaseT::mTree ? &BaseT::mTree->root() : nullptr);
1990  }
1991 
1992  template<typename OtherNodeType> void getNode(const OtherNodeType*& node) { node = nullptr; }
1993 
1994  void eraseNode(const NodeT0*)
1995  {
1996  mKey0 = Coord::max();
1997  mNode0 = nullptr;
1998 #if OPENVDB_ABI_VERSION_NUMBER >= 10
1999  mBuffer = nullptr;
2000 #endif
2001  }
2002 
2003  template<typename OtherNodeType> void eraseNode(const OtherNodeType*) {}
2004 
2005  /// Private copy method
2006  inline void copy(const ValueAccessor1& other)
2007  {
2008  mKey0 = other.mKey0;
2009  mNode0 = other.mNode0;
2010 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2011  mBuffer = other.mBuffer;
2012 #endif
2013  }
2014 
2015  /// Prevent this accessor from calling Tree::releaseCache() on a tree that
2016  /// no longer exists. (Called by mTree when it is destroyed.)
2017  void release() override
2018  {
2019  this->BaseT::release();
2020  this->clear();
2021  }
2022  /// Cache the given node, which should lie along the path from the root node to
2023  /// the node containing voxel (x, y, z).
2024  /// @note This operation is not mutex-protected and is intended to be called
2025  /// only by nodes and only in the context of a getValue() or setValue() call.
2026  inline void insert(const Coord& xyz, const NodeT0* node)
2027  {
2028  assert(node);
2029  mKey0 = xyz & ~(NodeT0::DIM-1);
2030  mNode0 = node;
2031 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2032  if constexpr(BypassLeafAPI) {
2033  mBuffer = node->buffer().data();
2034  }
2035 #endif
2036  }
2037 
2038  /// No-op in case a tree traversal attemps to insert a node that
2039  /// is not cached by the ValueAccessor
2040  template<typename OtherNodeType> inline void insert(const Coord&, const OtherNodeType*) {}
2041 
2042  inline bool isHashed(const Coord& xyz) const
2043  {
2044  return (xyz[0] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[0]
2045  && (xyz[1] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[1]
2046  && (xyz[2] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[2];
2047  }
2048 
2049  mutable Coord mKey0;
2050  mutable const NodeT0* mNode0;
2051 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2052  mutable const ValueType* mBuffer;
2053 #endif
2054 }; // ValueAccessor1
2055 
2056 
2057 /// @brief Value accessor with two levels of node caching.
2058 /// @details The node cache levels are specified by L0 and L1
2059 /// with the default values 0 and 1 (defined in the forward declaration)
2060 /// corresponding to a LeafNode and its parent InternalNode.
2061 ///
2062 /// @note This class is for experts only and should rarely be used directly.
2063 /// Instead use ValueAccessor with its default template arguments.
2064 template<typename _TreeType, bool IsSafe, Index L0, Index L1>
2066 {
2067 public:
2068  static_assert(_TreeType::DEPTH >= 3, "cache size exceeds tree depth");
2069  static_assert(L0 < L1, "invalid cache level");
2070  static_assert(L1 < _TreeType::RootNodeType::LEVEL, "invalid cache level");
2071 
2072  using TreeType = _TreeType;
2073  using ValueType = typename TreeType::ValueType;
2074  using RootNodeT = typename TreeType::RootNodeType;
2075  using LeafNodeT = typename TreeType::LeafNodeType;
2077  using InvTreeT = typename RootNodeT::NodeChainType;
2078  using NodeT0 = typename InvTreeT::template Get<L0>;
2079  using NodeT1 = typename InvTreeT::template Get<L1>;
2080 
2081 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2082  // If the last node being cached is a leaf node and the storage type matches
2083  // the ValueType, we can cache the buffer pointer instead of using the delay
2084  // load locked leaf API
2085  static constexpr bool BypassLeafAPI =
2088 #endif
2089 
2090  /// Constructor from a tree
2092  : BaseT(tree)
2093  , mKey0(Coord::max()), mNode0(nullptr)
2094  , mKey1(Coord::max()), mNode1(nullptr)
2095 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2096  , mBuffer(nullptr)
2097 #endif
2098  {}
2099 
2100  /// Copy constructor
2101  ValueAccessor2(const ValueAccessor2& other) : BaseT(other) { this->copy(other); }
2102 
2103  /// Return the number of cache levels employed by this ValueAccessor
2104  static Index numCacheLevels() { return 2; }
2105 
2106  /// Assignment operator
2108  {
2109  if (&other != this) {
2110  this->BaseT::operator=(other);
2111  this->copy(other);
2112  }
2113  return *this;
2114  }
2115 
2116  /// Virtual destructor
2117  ~ValueAccessor2() override = default;
2118 
2119  /// Return @c true if any of the nodes along the path to the given
2120  /// voxel have been cached.
2121  bool isCached(const Coord& xyz) const
2122  {
2123  assert(BaseT::mTree);
2124  return this->isHashed1(xyz) || this->isHashed0(xyz);
2125  }
2126 
2127  /// Return the value of the voxel at the given coordinates.
2128  const ValueType& getValue(const Coord& xyz) const
2129  {
2130  assert(BaseT::mTree);
2131  if (this->isHashed0(xyz)) {
2132  assert(mNode0);
2133 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2134  if constexpr(BypassLeafAPI) {
2135  assert(mBuffer);
2136  return mBuffer[LeafNodeT::coordToOffset(xyz)];
2137  }
2138 #endif
2139  return mNode0->getValueAndCache(xyz, this->self());
2140  } else if (this->isHashed1(xyz)) {
2141  assert(mNode1);
2142  return mNode1->getValueAndCache(xyz, this->self());
2143  }
2144  return BaseT::mTree->root().getValueAndCache(xyz, this->self());
2145  }
2146 
2147  /// Return the active state of the voxel at the given coordinates.
2148  bool isValueOn(const Coord& xyz) const
2149  {
2150  assert(BaseT::mTree);
2151  if (this->isHashed0(xyz)) {
2152  assert(mNode0);
2153  return mNode0->isValueOnAndCache(xyz, this->self());
2154  } else if (this->isHashed1(xyz)) {
2155  assert(mNode1);
2156  return mNode1->isValueOnAndCache(xyz, this->self());
2157  }
2158  return BaseT::mTree->root().isValueOnAndCache(xyz, this->self());
2159  }
2160 
2161  /// Return the active state of the voxel as well as its value
2162  bool probeValue(const Coord& xyz, ValueType& value) const
2163  {
2164  assert(BaseT::mTree);
2165  if (this->isHashed0(xyz)) {
2166  assert(mNode0);
2167 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2168  if constexpr(BypassLeafAPI) {
2169  assert(mBuffer);
2170  const auto offset = LeafNodeT::coordToOffset(xyz);
2171  value = mBuffer[offset];
2172  return mNode0->isValueOn(offset);
2173  }
2174 #endif
2175  return mNode0->probeValueAndCache(xyz, value, this->self());
2176  } else if (this->isHashed1(xyz)) {
2177  assert(mNode1);
2178  return mNode1->probeValueAndCache(xyz, value, this->self());
2179  }
2180  return BaseT::mTree->root().probeValueAndCache(xyz, value, this->self());
2181  }
2182 
2183  /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides,
2184  /// or -1 if (x, y, z) isn't explicitly represented in the tree (i.e., if it is
2185  /// implicitly a background voxel).
2186  int getValueDepth(const Coord& xyz) const
2187  {
2188  assert(BaseT::mTree);
2189  if (this->isHashed0(xyz)) {
2190  assert(mNode0);
2191  return RootNodeT::LEVEL - mNode0->getValueLevelAndCache(xyz, this->self());
2192  } else if (this->isHashed1(xyz)) {
2193  assert(mNode1);
2194  return RootNodeT::LEVEL - mNode1->getValueLevelAndCache(xyz, this->self());
2195  }
2196  return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self());
2197  }
2198 
2199  /// Return @c true if the value of voxel (x, y, z) resides at the leaf level
2200  /// of the tree, i.e., if it is not a tile value.
2201  bool isVoxel(const Coord& xyz) const
2202  {
2203  assert(BaseT::mTree);
2204  if (this->isHashed0(xyz)) {
2205  assert(mNode0);
2206  return mNode0->getValueLevelAndCache(xyz, this->self())==0;
2207  } else if (this->isHashed1(xyz)) {
2208  assert(mNode1);
2209  return mNode1->getValueLevelAndCache(xyz, this->self())==0;
2210  }
2211  return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self()) ==
2212  static_cast<int>(RootNodeT::LEVEL);
2213  }
2214 
2215  //@{
2216  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
2217  void setValue(const Coord& xyz, const ValueType& value)
2218  {
2219  assert(BaseT::mTree);
2220  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2221  if (this->isHashed0(xyz)) {
2222  assert(mNode0);
2223 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2224  if constexpr(BypassLeafAPI) {
2225  assert(mBuffer);
2226  const auto offset = LeafNodeT::coordToOffset(xyz);
2227  const_cast<ValueType&>(mBuffer[offset]) = value;
2228  const_cast<NodeT0*>(mNode0)->setValueOn(offset);
2229  return;
2230  }
2231 #endif
2232  const_cast<NodeT0*>(mNode0)->setValueAndCache(xyz, value, *this);
2233  } else if (this->isHashed1(xyz)) {
2234  assert(mNode1);
2235  const_cast<NodeT1*>(mNode1)->setValueAndCache(xyz, value, *this);
2236  } else {
2237  BaseT::mTree->root().setValueAndCache(xyz, value, *this);
2238  }
2239  }
2240  void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); }
2241  //@}
2242 
2243  /// Set the value of the voxel at the given coordinate but preserves its active state.
2244  void setValueOnly(const Coord& xyz, const ValueType& value)
2245  {
2246  assert(BaseT::mTree);
2247  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2248  if (this->isHashed0(xyz)) {
2249  assert(mNode0);
2250 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2251  if constexpr(BypassLeafAPI) {
2252  assert(mBuffer);
2253  const auto offset = LeafNodeT::coordToOffset(xyz);
2254  const_cast<ValueType&>(mBuffer[offset]) = value;
2255  return;
2256  }
2257 #endif
2258  const_cast<NodeT0*>(mNode0)->setValueOnlyAndCache(xyz, value, *this);
2259  } else if (this->isHashed1(xyz)) {
2260  assert(mNode1);
2261  const_cast<NodeT1*>(mNode1)->setValueOnlyAndCache(xyz, value, *this);
2262  } else {
2263  BaseT::mTree->root().setValueOnlyAndCache(xyz, value, *this);
2264  }
2265  }
2266 
2267  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
2268  void setValueOff(const Coord& xyz, const ValueType& value)
2269  {
2270  assert(BaseT::mTree);
2271  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2272  if (this->isHashed0(xyz)) {
2273  assert(mNode0);
2274  const_cast<NodeT0*>(mNode0)->setValueOffAndCache(xyz, value, *this);
2275  } else if (this->isHashed1(xyz)) {
2276  assert(mNode1);
2277  const_cast<NodeT1*>(mNode1)->setValueOffAndCache(xyz, value, *this);
2278  } else {
2279  BaseT::mTree->root().setValueOffAndCache(xyz, value, *this);
2280  }
2281  }
2282 
2283  /// @brief Apply a functor to the value of the voxel at the given coordinates
2284  /// and mark the voxel as active.
2285  /// @details See Tree::modifyValue() for details.
2286  template<typename ModifyOp>
2287  void modifyValue(const Coord& xyz, const ModifyOp& op)
2288  {
2289  assert(BaseT::mTree);
2290  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2291  if (this->isHashed0(xyz)) {
2292  assert(mNode0);
2293 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2294  if constexpr(BypassLeafAPI) {
2295  assert(mBuffer);
2296  const auto offset = LeafNodeT::coordToOffset(xyz);
2297  op(const_cast<ValueType&>(mBuffer[offset]));
2298  const_cast<NodeT0*>(mNode0)->setActiveState(offset, true);
2299  return;
2300  }
2301 #endif
2302  const_cast<NodeT0*>(mNode0)->modifyValueAndCache(xyz, op, *this);
2303  } else if (this->isHashed1(xyz)) {
2304  assert(mNode1);
2305  const_cast<NodeT1*>(mNode1)->modifyValueAndCache(xyz, op, *this);
2306  } else {
2307  BaseT::mTree->root().modifyValueAndCache(xyz, op, *this);
2308  }
2309  }
2310 
2311  /// @brief Apply a functor to the voxel at the given coordinates.
2312  /// @details See Tree::modifyValueAndActiveState() for details.
2313  template<typename ModifyOp>
2314  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
2315  {
2316  assert(BaseT::mTree);
2317  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2318  if (this->isHashed0(xyz)) {
2319  assert(mNode0);
2320 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2321  if constexpr(BypassLeafAPI) {
2322  assert(mBuffer);
2323  const auto offset = LeafNodeT::coordToOffset(xyz);
2324  bool state = mNode0->isValueOn(offset);
2325  op(const_cast<ValueType&>(mBuffer[offset]), state);
2326  const_cast<NodeT0*>(mNode0)->setActiveState(offset, state);
2327  return;
2328  }
2329 #endif
2330  const_cast<NodeT0*>(mNode0)->modifyValueAndActiveStateAndCache(xyz, op, *this);
2331  } else if (this->isHashed1(xyz)) {
2332  assert(mNode1);
2333  const_cast<NodeT1*>(mNode1)->modifyValueAndActiveStateAndCache(xyz, op, *this);
2334  } else {
2335  BaseT::mTree->root().modifyValueAndActiveStateAndCache(xyz, op, *this);
2336  }
2337  }
2338 
2339  /// Set the active state of the voxel at the given coordinates without changing its value.
2340  void setActiveState(const Coord& xyz, bool on = true)
2341  {
2342  assert(BaseT::mTree);
2343  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2344  if (this->isHashed0(xyz)) {
2345  assert(mNode0);
2346  const_cast<NodeT0*>(mNode0)->setActiveStateAndCache(xyz, on, *this);
2347  } else if (this->isHashed1(xyz)) {
2348  assert(mNode1);
2349  const_cast<NodeT1*>(mNode1)->setActiveStateAndCache(xyz, on, *this);
2350  } else {
2351  BaseT::mTree->root().setActiveStateAndCache(xyz, on, *this);
2352  }
2353  }
2354  /// Mark the voxel at the given coordinates as active without changing its value.
2355  void setValueOn(const Coord& xyz) { this->setActiveState(xyz, true); }
2356  /// Mark the voxel at the given coordinates as inactive without changing its value.
2357  void setValueOff(const Coord& xyz) { this->setActiveState(xyz, false); }
2358 
2359  /// Return the cached node of type @a NodeType. [Mainly for internal use]
2360  template<typename NodeT>
2361  NodeT* getNode()
2362  {
2363  const NodeT* node = nullptr;
2364  this->getNode(node);
2365  return const_cast<NodeT*>(node);
2366  }
2367 
2368  /// Cache the given node, which should lie along the path from the root node to
2369  /// the node containing voxel (x, y, z). [Mainly for internal use]
2370  template<typename NodeT>
2371  void insertNode(const Coord& xyz, NodeT& node) { this->insert(xyz, &node); }
2372 
2373  /// If a node of the given type exists in the cache, remove it, so that
2374  /// isCached(xyz) returns @c false for any voxel (x, y, z) contained in
2375  /// that node. [Mainly for internal use]
2376  template<typename NodeT>
2377  void eraseNode()
2378  {
2379  const NodeT* node = nullptr;
2380  this->eraseNode(node);
2381  }
2382 
2383  /// @brief Add the specified leaf to this tree, possibly creating a child branch
2384  /// in the process. If the leaf node already exists, replace it.
2385  void addLeaf(LeafNodeT* leaf)
2386  {
2387  assert(BaseT::mTree);
2388  static_assert(!BaseT::IsConstTree, "can't add a node to a const tree");
2389  if (this->isHashed1(leaf->origin())) {
2390  assert(mNode1);
2391  return const_cast<NodeT1*>(mNode1)->addLeafAndCache(leaf, *this);
2392  }
2393  BaseT::mTree->root().addLeafAndCache(leaf, *this);
2394  }
2395 
2396  /// @brief Add a tile at the specified tree level that contains voxel (x, y, z),
2397  /// possibly deleting existing nodes or creating new nodes in the process.
2398  void addTile(Index level, const Coord& xyz, const ValueType& value, bool state)
2399  {
2400  assert(BaseT::mTree);
2401  static_assert(!BaseT::IsConstTree, "can't add a tile to a const tree");
2402  if (this->isHashed1(xyz)) {
2403  assert(mNode1);
2404  return const_cast<NodeT1*>(mNode1)->addTileAndCache(level, xyz, value, state, *this);
2405  }
2406  BaseT::mTree->root().addTileAndCache(level, xyz, value, state, *this);
2407  }
2408 
2409  /// @brief @return the leaf node that contains voxel (x, y, z) and
2410  /// if it doesn't exist, create it, but preserve the values and
2411  /// active states of all voxels.
2412  ///
2413  /// Use this method to preallocate a static tree topology over which to
2414  /// safely perform multithreaded processing.
2415  LeafNodeT* touchLeaf(const Coord& xyz)
2416  {
2417  assert(BaseT::mTree);
2418  static_assert(!BaseT::IsConstTree, "can't get a non-const node from a const tree");
2419  if (this->isHashed0(xyz)) {
2420  assert(mNode0);
2421  return const_cast<NodeT0*>(mNode0)->touchLeafAndCache(xyz, *this);
2422  } else if (this->isHashed1(xyz)) {
2423  assert(mNode1);
2424  return const_cast<NodeT1*>(mNode1)->touchLeafAndCache(xyz, *this);
2425  }
2426  return BaseT::mTree->root().touchLeafAndCache(xyz, *this);
2427  }
2428 
2429  /// @brief @return a pointer to the node of the specified type that contains
2430  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
2431  template<typename NodeT>
2432  NodeT* probeNode(const Coord& xyz)
2433  {
2434  assert(BaseT::mTree);
2435  static_assert(!BaseT::IsConstTree, "can't get a non-const node from a const tree");
2436  if constexpr ((std::is_same<NodeT, NodeT0>::value)) {
2437  if (this->isHashed0(xyz)) {
2438  assert(mNode0);
2439  return reinterpret_cast<NodeT*>(const_cast<NodeT0*>(mNode0));
2440  } else if (this->isHashed1(xyz)) {
2441  assert(mNode1);
2442  return const_cast<NodeT1*>(mNode1)->template probeNodeAndCache<NodeT>(xyz, *this);
2443  }
2444  return BaseT::mTree->root().template probeNodeAndCache<NodeT>(xyz, *this);
2445  } else if constexpr ((std::is_same<NodeT, NodeT1>::value)) {
2446  if (this->isHashed1(xyz)) {
2447  assert(mNode1);
2448  return reinterpret_cast<NodeT*>(const_cast<NodeT1*>(mNode1));
2449  }
2450  return BaseT::mTree->root().template probeNodeAndCache<NodeT>(xyz, *this);
2451  } else if constexpr (NodeT::LEVEL < NodeT1::LEVEL) {
2452  // Might still be worth caching this path if a NodeT0 or NodeT1
2453  // are accessed in the future
2454  return BaseT::mTree->root().template probeNodeAndCache<NodeT>(xyz, *this);
2455  } else {
2456  // If we're accessing a node above our top most cache level then
2457  // there's no point trying to cache it
2458  return BaseT::mTree->root().template probeNode<NodeT>(xyz);
2459  }
2460  }
2461 
2462  /// @brief @return a const pointer to the node of the specified type that contains
2463  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
2464  template<typename NodeT>
2465  const NodeT* probeConstNode(const Coord& xyz) const
2466  {
2467  assert(BaseT::mTree);
2468  if constexpr ((std::is_same<NodeT, NodeT0>::value)) {
2469  if (this->isHashed0(xyz)) {
2470  assert(mNode0);
2471  return reinterpret_cast<const NodeT*>(mNode0);
2472  } else if (this->isHashed1(xyz)) {
2473  assert(mNode1);
2474  return mNode1->template probeConstNodeAndCache<NodeT>(xyz, this->self());
2475  }
2476  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
2477  } else if constexpr ((std::is_same<NodeT, NodeT1>::value)) {
2478  if (this->isHashed1(xyz)) {
2479  assert(mNode1);
2480  return reinterpret_cast<const NodeT*>(mNode1);
2481  }
2482  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
2483  } else if constexpr (NodeT::LEVEL < NodeT1::LEVEL) {
2484  // Might still be worth caching this path if a NodeT0 or NodeT1
2485  // are accessed in the future
2486  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
2487  } else {
2488  // If we're accessing a node above our top most cache level then
2489  // there's no point trying to cache it
2490  return BaseT::mTree->root().template probeConstNode<NodeT>(xyz);
2491  }
2492  }
2493 
2494  /// @brief @return a pointer to the leaf node that contains
2495  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
2496  LeafNodeT* probeLeaf(const Coord& xyz) { return this->template probeNode<LeafNodeT>(xyz); }
2497  const LeafNodeT* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); }
2498 
2499  /// @brief @return a const pointer to the leaf node that contains
2500  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
2501  const LeafNodeT* probeConstLeaf(const Coord& xyz) const
2502  {
2503  return this->template probeConstNode<LeafNodeT>(xyz);
2504  }
2505 
2506  /// Remove all the cached nodes and invalidate the corresponding hash-keys.
2507  void clear() override
2508  {
2509  mKey0 = Coord::max();
2510  mNode0 = nullptr;
2511  mKey1 = Coord::max();
2512  mNode1 = nullptr;
2513 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2514  mBuffer = nullptr;
2515 #endif
2516  }
2517 
2518 private:
2519  // Allow nodes to insert themselves into the cache.
2520  template<typename> friend class RootNode;
2521  template<typename, Index> friend class InternalNode;
2522  template<typename, Index> friend class LeafNode;
2523  // Allow trees to deregister themselves.
2524  template<typename> friend class Tree;
2525 
2526  // This private method is merely for convenience.
2527  inline ValueAccessor2& self() const { return const_cast<ValueAccessor2&>(*this); }
2528 
2529  void getNode(const NodeT0*& node) { node = mNode0; }
2530  void getNode(const NodeT1*& node) { node = mNode1; }
2531  void getNode(const RootNodeT*& node)
2532  {
2533  node = (BaseT::mTree ? &BaseT::mTree->root() : nullptr);
2534  }
2535  template<typename OtherNodeType> void getNode(const OtherNodeType*& node) { node = nullptr; }
2536 
2537  void eraseNode(const NodeT0*)
2538  {
2539  mKey0 = Coord::max();
2540  mNode0 = nullptr;
2541 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2542  mBuffer = nullptr;
2543 #endif
2544  }
2545 
2546  void eraseNode(const NodeT1*) { mKey1 = Coord::max(); mNode1 = nullptr; }
2547  template<typename OtherNodeType> void eraseNode(const OtherNodeType*) {}
2548 
2549  /// Private copy method
2550  inline void copy(const ValueAccessor2& other)
2551  {
2552  mKey0 = other.mKey0;
2553  mNode0 = other.mNode0;
2554  mKey1 = other.mKey1;
2555  mNode1 = other.mNode1;
2556 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2557  mBuffer = other.mBuffer;
2558 #endif
2559  }
2560 
2561  /// Prevent this accessor from calling Tree::releaseCache() on a tree that
2562  /// no longer exists. (Called by mTree when it is destroyed.)
2563  void release() override
2564  {
2565  this->BaseT::release();
2566  this->clear();
2567  }
2568 
2569  /// Cache the given node, which should lie along the path from the root node to
2570  /// the node containing voxel (x, y, z).
2571  /// @note This operation is not mutex-protected and is intended to be called
2572  /// only by nodes and only in the context of a getValue() or setValue() call.
2573  inline void insert(const Coord& xyz, const NodeT0* node)
2574  {
2575  assert(node);
2576  mKey0 = xyz & ~(NodeT0::DIM-1);
2577  mNode0 = node;
2578 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2579  if constexpr(BypassLeafAPI) {
2580  mBuffer = node->buffer().data();
2581  }
2582 #endif
2583  }
2584  inline void insert(const Coord& xyz, const NodeT1* node)
2585  {
2586  assert(node);
2587  mKey1 = xyz & ~(NodeT1::DIM-1);
2588  mNode1 = node;
2589  }
2590  /// No-op in case a tree traversal attemps to insert a node that
2591  /// is not cached by the ValueAccessor
2592  template<typename NodeT> inline void insert(const Coord&, const NodeT*) {}
2593 
2594  inline bool isHashed0(const Coord& xyz) const
2595  {
2596  return (xyz[0] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[0]
2597  && (xyz[1] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[1]
2598  && (xyz[2] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[2];
2599  }
2600  inline bool isHashed1(const Coord& xyz) const
2601  {
2602  return (xyz[0] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[0]
2603  && (xyz[1] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[1]
2604  && (xyz[2] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[2];
2605  }
2606  mutable Coord mKey0;
2607  mutable const NodeT0* mNode0;
2608  mutable Coord mKey1;
2609  mutable const NodeT1* mNode1;
2610 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2611  mutable const ValueType* mBuffer;
2612 #endif
2613 }; // ValueAccessor2
2614 
2615 
2616 /// @brief Value accessor with three levels of node caching.
2617 /// @details The node cache levels are specified by L0, L1, and L2
2618 /// with the default values 0, 1 and 2 (defined in the forward declaration)
2619 /// corresponding to a LeafNode, its parent InternalNode, and its parent InternalNode.
2620 /// Since the default configuration of all typed trees and grids, e.g.,
2621 /// FloatTree or FloatGrid, has a depth of four, this value accessor is the one
2622 /// used by default.
2623 ///
2624 /// @note This class is for experts only and should rarely be used
2625 /// directly. Instead use ValueAccessor with its default template arguments
2626 template<typename _TreeType, bool IsSafe, Index L0, Index L1, Index L2>
2628 {
2629 public:
2630  static_assert(_TreeType::DEPTH >= 4, "cache size exceeds tree depth");
2631  static_assert(L0 < L1, "invalid cache level");
2632  static_assert(L1 < L2, "invalid cache level");
2633  static_assert(L2 < _TreeType::RootNodeType::LEVEL, "invalid cache level");
2634 
2635  using TreeType = _TreeType;
2636  using ValueType = typename TreeType::ValueType;
2637  using RootNodeT = typename TreeType::RootNodeType;
2638  using LeafNodeT = typename TreeType::LeafNodeType;
2640  using InvTreeT = typename RootNodeT::NodeChainType;
2641  using NodeT0 = typename InvTreeT::template Get<L0>;
2642  using NodeT1 = typename InvTreeT::template Get<L1>;
2643  using NodeT2 = typename InvTreeT::template Get<L2>;
2644 
2645 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2646  // If the last node being cached is a leaf node and the storage type matches
2647  // the ValueType, we can cache the buffer pointer instead of using the delay
2648  // load locked leaf API
2649  static constexpr bool BypassLeafAPI =
2652 #endif
2653 
2654  /// Constructor from a tree
2656  : BaseT(tree)
2657  , mKey0(Coord::max()), mNode0(nullptr)
2658  , mKey1(Coord::max()), mNode1(nullptr)
2659  , mKey2(Coord::max()), mNode2(nullptr)
2660 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2661  , mBuffer(nullptr)
2662 #endif
2663  {}
2664 
2665  /// Copy constructor
2666  ValueAccessor3(const ValueAccessor3& other) : BaseT(other) { this->copy(other); }
2667 
2668  /// Assignment operator
2670  {
2671  if (&other != this) {
2672  this->BaseT::operator=(other);
2673  this->copy(other);
2674  }
2675  return *this;
2676  }
2677 
2678  /// Return the number of cache levels employed by this ValueAccessor
2679  static Index numCacheLevels() { return 3; }
2680 
2681  /// Virtual destructor
2682  ~ValueAccessor3() override = default;
2683 
2684  /// Return @c true if any of the nodes along the path to the given
2685  /// voxel have been cached.
2686  bool isCached(const Coord& xyz) const
2687  {
2688  assert(BaseT::mTree);
2689  return this->isHashed2(xyz) || this->isHashed1(xyz) || this->isHashed0(xyz);
2690  }
2691 
2692  /// Return the value of the voxel at the given coordinates.
2693  const ValueType& getValue(const Coord& xyz) const
2694  {
2695  assert(BaseT::mTree);
2696  if (this->isHashed0(xyz)) {
2697  assert(mNode0);
2698 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2699  if constexpr(BypassLeafAPI) {
2700  assert(mBuffer);
2701  return mBuffer[LeafNodeT::coordToOffset(xyz)];
2702  }
2703 #endif
2704  return mNode0->getValueAndCache(xyz, this->self());
2705  } else if (this->isHashed1(xyz)) {
2706  assert(mNode1);
2707  return mNode1->getValueAndCache(xyz, this->self());
2708  } else if (this->isHashed2(xyz)) {
2709  assert(mNode2);
2710  return mNode2->getValueAndCache(xyz, this->self());
2711  }
2712  return BaseT::mTree->root().getValueAndCache(xyz, this->self());
2713  }
2714 
2715  /// Return the active state of the voxel at the given coordinates.
2716  bool isValueOn(const Coord& xyz) const
2717  {
2718  assert(BaseT::mTree);
2719  if (this->isHashed0(xyz)) {
2720  assert(mNode0);
2721  return mNode0->isValueOnAndCache(xyz, this->self());
2722  } else if (this->isHashed1(xyz)) {
2723  assert(mNode1);
2724  return mNode1->isValueOnAndCache(xyz, this->self());
2725  } else if (this->isHashed2(xyz)) {
2726  assert(mNode2);
2727  return mNode2->isValueOnAndCache(xyz, this->self());
2728  }
2729  return BaseT::mTree->root().isValueOnAndCache(xyz, this->self());
2730  }
2731 
2732  /// Return the active state of the voxel as well as its value
2733  bool probeValue(const Coord& xyz, ValueType& value) const
2734  {
2735  assert(BaseT::mTree);
2736  if (this->isHashed0(xyz)) {
2737  assert(mNode0);
2738 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2739  if constexpr(BypassLeafAPI) {
2740  assert(mBuffer);
2741  const auto offset = LeafNodeT::coordToOffset(xyz);
2742  value = mBuffer[offset];
2743  return mNode0->isValueOn(offset);
2744  }
2745 #endif
2746  return mNode0->probeValueAndCache(xyz, value, this->self());
2747  } else if (this->isHashed1(xyz)) {
2748  assert(mNode1);
2749  return mNode1->probeValueAndCache(xyz, value, this->self());
2750  } else if (this->isHashed2(xyz)) {
2751  assert(mNode2);
2752  return mNode2->probeValueAndCache(xyz, value, this->self());
2753  }
2754  return BaseT::mTree->root().probeValueAndCache(xyz, value, this->self());
2755  }
2756 
2757  /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides,
2758  /// or -1 if (x, y, z) isn't explicitly represented in the tree (i.e., if it is
2759  /// implicitly a background voxel).
2760  int getValueDepth(const Coord& xyz) const
2761  {
2762  assert(BaseT::mTree);
2763  if (this->isHashed0(xyz)) {
2764  assert(mNode0);
2765  return RootNodeT::LEVEL - mNode0->getValueLevelAndCache(xyz, this->self());
2766  } else if (this->isHashed1(xyz)) {
2767  assert(mNode1);
2768  return RootNodeT::LEVEL - mNode1->getValueLevelAndCache(xyz, this->self());
2769  } else if (this->isHashed2(xyz)) {
2770  assert(mNode2);
2771  return RootNodeT::LEVEL - mNode2->getValueLevelAndCache(xyz, this->self());
2772  }
2773  return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self());
2774  }
2775 
2776  /// Return @c true if the value of voxel (x, y, z) resides at the leaf level
2777  /// of the tree, i.e., if it is not a tile value.
2778  bool isVoxel(const Coord& xyz) const
2779  {
2780  assert(BaseT::mTree);
2781  if (this->isHashed0(xyz)) {
2782  assert(mNode0);
2783  return mNode0->getValueLevelAndCache(xyz, this->self())==0;
2784  } else if (this->isHashed1(xyz)) {
2785  assert(mNode1);
2786  return mNode1->getValueLevelAndCache(xyz, this->self())==0;
2787  } else if (this->isHashed2(xyz)) {
2788  assert(mNode2);
2789  return mNode2->getValueLevelAndCache(xyz, this->self())==0;
2790  }
2791  return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self()) ==
2792  static_cast<int>(RootNodeT::LEVEL);
2793  }
2794 
2795  //@{
2796  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
2797  void setValue(const Coord& xyz, const ValueType& value)
2798  {
2799  assert(BaseT::mTree);
2800  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2801  if (this->isHashed0(xyz)) {
2802  assert(mNode0);
2803 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2804  if constexpr(BypassLeafAPI) {
2805  assert(mBuffer);
2806  const auto offset = LeafNodeT::coordToOffset(xyz);
2807  const_cast<ValueType&>(mBuffer[offset]) = value;
2808  const_cast<NodeT0*>(mNode0)->setValueOn(offset);
2809  return;
2810  }
2811 #endif
2812  const_cast<NodeT0*>(mNode0)->setValueAndCache(xyz, value, *this);
2813  } else if (this->isHashed1(xyz)) {
2814  assert(mNode1);
2815  const_cast<NodeT1*>(mNode1)->setValueAndCache(xyz, value, *this);
2816  } else if (this->isHashed2(xyz)) {
2817  assert(mNode2);
2818  const_cast<NodeT2*>(mNode2)->setValueAndCache(xyz, value, *this);
2819  } else {
2820  BaseT::mTree->root().setValueAndCache(xyz, value, *this);
2821  }
2822  }
2823  void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); }
2824  //@}
2825 
2826  /// Set the value of the voxel at the given coordinate but preserves its active state.
2827  void setValueOnly(const Coord& xyz, const ValueType& value)
2828  {
2829  assert(BaseT::mTree);
2830  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2831  if (this->isHashed0(xyz)) {
2832  assert(mNode0);
2833 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2834  if constexpr(BypassLeafAPI) {
2835  assert(mBuffer);
2836  const auto offset = LeafNodeT::coordToOffset(xyz);
2837  const_cast<ValueType&>(mBuffer[offset]) = value;
2838  return;
2839  }
2840 #endif
2841  const_cast<NodeT0*>(mNode0)->setValueOnlyAndCache(xyz, value, *this);
2842  } else if (this->isHashed1(xyz)) {
2843  assert(mNode1);
2844  const_cast<NodeT1*>(mNode1)->setValueOnlyAndCache(xyz, value, *this);
2845  } else if (this->isHashed2(xyz)) {
2846  assert(mNode2);
2847  const_cast<NodeT2*>(mNode2)->setValueOnlyAndCache(xyz, value, *this);
2848  } else {
2849  BaseT::mTree->root().setValueOnlyAndCache(xyz, value, *this);
2850  }
2851  }
2852 
2853  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
2854  void setValueOff(const Coord& xyz, const ValueType& value)
2855  {
2856  assert(BaseT::mTree);
2857  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2858  if (this->isHashed0(xyz)) {
2859  assert(mNode0);
2860  const_cast<NodeT0*>(mNode0)->setValueOffAndCache(xyz, value, *this);
2861  } else if (this->isHashed1(xyz)) {
2862  assert(mNode1);
2863  const_cast<NodeT1*>(mNode1)->setValueOffAndCache(xyz, value, *this);
2864  } else if (this->isHashed2(xyz)) {
2865  assert(mNode2);
2866  const_cast<NodeT2*>(mNode2)->setValueOffAndCache(xyz, value, *this);
2867  } else {
2868  BaseT::mTree->root().setValueOffAndCache(xyz, value, *this);
2869  }
2870  }
2871 
2872  /// @brief Apply a functor to the value of the voxel at the given coordinates
2873  /// and mark the voxel as active.
2874  /// @details See Tree::modifyValue() for details.
2875  template<typename ModifyOp>
2876  void modifyValue(const Coord& xyz, const ModifyOp& op)
2877  {
2878  assert(BaseT::mTree);
2879  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2880  if (this->isHashed0(xyz)) {
2881  assert(mNode0);
2882 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2883  if constexpr(BypassLeafAPI) {
2884  assert(mBuffer);
2885  const auto offset = LeafNodeT::coordToOffset(xyz);
2886  op(const_cast<ValueType&>(mBuffer[offset]));
2887  const_cast<NodeT0*>(mNode0)->setActiveState(offset, true);
2888  return;
2889  }
2890 #endif
2891  const_cast<NodeT0*>(mNode0)->modifyValueAndCache(xyz, op, *this);
2892  } else if (this->isHashed1(xyz)) {
2893  assert(mNode1);
2894  const_cast<NodeT1*>(mNode1)->modifyValueAndCache(xyz, op, *this);
2895  } else if (this->isHashed2(xyz)) {
2896  assert(mNode2);
2897  const_cast<NodeT2*>(mNode2)->modifyValueAndCache(xyz, op, *this);
2898  } else {
2899  BaseT::mTree->root().modifyValueAndCache(xyz, op, *this);
2900  }
2901  }
2902 
2903  /// @brief Apply a functor to the voxel at the given coordinates.
2904  /// @details See Tree::modifyValueAndActiveState() for details.
2905  template<typename ModifyOp>
2906  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
2907  {
2908  assert(BaseT::mTree);
2909  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2910  if (this->isHashed0(xyz)) {
2911  assert(mNode0);
2912 #if OPENVDB_ABI_VERSION_NUMBER >= 10
2913  if constexpr(BypassLeafAPI) {
2914  assert(mBuffer);
2915  const auto offset = LeafNodeT::coordToOffset(xyz);
2916  bool state = mNode0->isValueOn(offset);
2917  op(const_cast<ValueType&>(mBuffer[offset]), state);
2918  const_cast<NodeT0*>(mNode0)->setActiveState(offset, state);
2919  return;
2920  }
2921 #endif
2922  const_cast<NodeT0*>(mNode0)->modifyValueAndActiveStateAndCache(xyz, op, *this);
2923  } else if (this->isHashed1(xyz)) {
2924  assert(mNode1);
2925  const_cast<NodeT1*>(mNode1)->modifyValueAndActiveStateAndCache(xyz, op, *this);
2926  } else if (this->isHashed2(xyz)) {
2927  assert(mNode2);
2928  const_cast<NodeT2*>(mNode2)->modifyValueAndActiveStateAndCache(xyz, op, *this);
2929  } else {
2930  BaseT::mTree->root().modifyValueAndActiveStateAndCache(xyz, op, *this);
2931  }
2932  }
2933 
2934  /// Set the active state of the voxel at the given coordinates without changing its value.
2935  void setActiveState(const Coord& xyz, bool on = true)
2936  {
2937  assert(BaseT::mTree);
2938  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2939  if (this->isHashed0(xyz)) {
2940  assert(mNode0);
2941  const_cast<NodeT0*>(mNode0)->setActiveStateAndCache(xyz, on, *this);
2942  } else if (this->isHashed1(xyz)) {
2943  assert(mNode1);
2944  const_cast<NodeT1*>(mNode1)->setActiveStateAndCache(xyz, on, *this);
2945  } else if (this->isHashed2(xyz)) {
2946  assert(mNode2);
2947  const_cast<NodeT2*>(mNode2)->setActiveStateAndCache(xyz, on, *this);
2948  } else {
2949  BaseT::mTree->root().setActiveStateAndCache(xyz, on, *this);
2950  }
2951  }
2952  /// Mark the voxel at the given coordinates as active without changing its value.
2953  void setValueOn(const Coord& xyz) { this->setActiveState(xyz, true); }
2954  /// Mark the voxel at the given coordinates as inactive without changing its value.
2955  void setValueOff(const Coord& xyz) { this->setActiveState(xyz, false); }
2956 
2957  /// Return the cached node of type @a NodeType. [Mainly for internal use]
2958  template<typename NodeT>
2959  NodeT* getNode()
2960  {
2961  const NodeT* node = nullptr;
2962  this->getNode(node);
2963  return const_cast<NodeT*>(node);
2964  }
2965 
2966  /// Cache the given node, which should lie along the path from the root node to
2967  /// the node containing voxel (x, y, z). [Mainly for internal use]
2968  template<typename NodeT>
2969  void insertNode(const Coord& xyz, NodeT& node) { this->insert(xyz, &node); }
2970 
2971  /// If a node of the given type exists in the cache, remove it, so that
2972  /// isCached(xyz) returns @c false for any voxel (x, y, z) contained in
2973  /// that node. [Mainly for internal use]
2974  template<typename NodeT>
2975  void eraseNode()
2976  {
2977  const NodeT* node = nullptr;
2978  this->eraseNode(node);
2979  }
2980 
2981  /// @brief Add the specified leaf to this tree, possibly creating a child branch
2982  /// in the process. If the leaf node already exists, replace it.
2983  void addLeaf(LeafNodeT* leaf)
2984  {
2985  assert(BaseT::mTree);
2986  static_assert(!BaseT::IsConstTree, "can't add a node to a const tree");
2987  if (this->isHashed1(leaf->origin())) {
2988  assert(mNode1);
2989  return const_cast<NodeT1*>(mNode1)->addLeafAndCache(leaf, *this);
2990  } else if (this->isHashed2(leaf->origin())) {
2991  assert(mNode2);
2992  return const_cast<NodeT2*>(mNode2)->addLeafAndCache(leaf, *this);
2993  }
2994  BaseT::mTree->root().addLeafAndCache(leaf, *this);
2995  }
2996 
2997  /// @brief Add a tile at the specified tree level that contains voxel (x, y, z),
2998  /// possibly deleting existing nodes or creating new nodes in the process.
2999  void addTile(Index level, const Coord& xyz, const ValueType& value, bool state)
3000  {
3001  assert(BaseT::mTree);
3002  static_assert(!BaseT::IsConstTree, "can't add a tile to a const tree");
3003  if (this->isHashed1(xyz)) {
3004  assert(mNode1);
3005  return const_cast<NodeT1*>(mNode1)->addTileAndCache(level, xyz, value, state, *this);
3006  } if (this->isHashed2(xyz)) {
3007  assert(mNode2);
3008  return const_cast<NodeT2*>(mNode2)->addTileAndCache(level, xyz, value, state, *this);
3009  }
3010  BaseT::mTree->root().addTileAndCache(level, xyz, value, state, *this);
3011  }
3012 
3013  /// @brief @return the leaf node that contains voxel (x, y, z) and
3014  /// if it doesn't exist, create it, but preserve the values and
3015  /// active states of all voxels.
3016  ///
3017  /// Use this method to preallocate a static tree topology over which to
3018  /// safely perform multithreaded processing.
3019  LeafNodeT* touchLeaf(const Coord& xyz)
3020  {
3021  assert(BaseT::mTree);
3022  static_assert(!BaseT::IsConstTree, "can't get a non-const node from a const tree");
3023  if (this->isHashed0(xyz)) {
3024  assert(mNode0);
3025  return const_cast<NodeT0*>(mNode0);
3026  } else if (this->isHashed1(xyz)) {
3027  assert(mNode1);
3028  return const_cast<NodeT1*>(mNode1)->touchLeafAndCache(xyz, *this);
3029  } else if (this->isHashed2(xyz)) {
3030  assert(mNode2);
3031  return const_cast<NodeT2*>(mNode2)->touchLeafAndCache(xyz, *this);
3032  }
3033  return BaseT::mTree->root().touchLeafAndCache(xyz, *this);
3034  }
3035  /// @brief @return a pointer to the node of the specified type that contains
3036  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
3037  template<typename NodeT>
3038  NodeT* probeNode(const Coord& xyz)
3039  {
3040  assert(BaseT::mTree);
3041  static_assert(!BaseT::IsConstTree, "can't get a non-const node from a const tree");
3042  if constexpr ((std::is_same<NodeT, NodeT0>::value)) {
3043  if (this->isHashed0(xyz)) {
3044  assert(mNode0);
3045  return reinterpret_cast<NodeT*>(const_cast<NodeT0*>(mNode0));
3046  } else if (this->isHashed1(xyz)) {
3047  assert(mNode1);
3048  return const_cast<NodeT1*>(mNode1)->template probeNodeAndCache<NodeT>(xyz, *this);
3049  } else if (this->isHashed2(xyz)) {
3050  assert(mNode2);
3051  return const_cast<NodeT2*>(mNode2)->template probeNodeAndCache<NodeT>(xyz, *this);
3052  }
3053  return BaseT::mTree->root().template probeNodeAndCache<NodeT>(xyz, *this);
3054  } else if constexpr ((std::is_same<NodeT, NodeT1>::value)) {
3055  if (this->isHashed1(xyz)) {
3056  assert(mNode1);
3057  return reinterpret_cast<NodeT*>(const_cast<NodeT1*>(mNode1));
3058  } else if (this->isHashed2(xyz)) {
3059  assert(mNode2);
3060  return const_cast<NodeT2*>(mNode2)->template probeNodeAndCache<NodeT>(xyz, *this);
3061  }
3062  return BaseT::mTree->root().template probeNodeAndCache<NodeT>(xyz, *this);
3063  } else if constexpr ((std::is_same<NodeT, NodeT2>::value)) {
3064  if (this->isHashed2(xyz)) {
3065  assert(mNode2);
3066  return reinterpret_cast<NodeT*>(const_cast<NodeT2*>(mNode2));
3067  }
3068  return BaseT::mTree->root().template probeNodeAndCache<NodeT>(xyz, *this);
3069  } else if constexpr (NodeT::LEVEL < NodeT2::LEVEL) {
3070  // Might still be worth caching this path if a NodeT0 or NodeT1
3071  // are accessed in the future
3072  return BaseT::mTree->root().template probeNodeAndCache<NodeT>(xyz, *this);
3073  } else {
3074  // If we're accessing a node above our top most cache level then
3075  // there's no point trying to cache it
3076  return BaseT::mTree->root().template probeNode<NodeT>(xyz);
3077  }
3078  }
3079  /// @brief @return a pointer to the leaf node that contains
3080  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
3081  LeafNodeT* probeLeaf(const Coord& xyz) { return this->template probeNode<LeafNodeT>(xyz); }
3082 
3083  /// @brief @return a const pointer to the node of the specified type that contains
3084  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
3085  template<typename NodeT>
3086  const NodeT* probeConstNode(const Coord& xyz) const
3087  {
3088  assert(BaseT::mTree);
3089  if constexpr ((std::is_same<NodeT, NodeT0>::value)) {
3090  if (this->isHashed0(xyz)) {
3091  assert(mNode0);
3092  return reinterpret_cast<const NodeT*>(mNode0);
3093  } else if (this->isHashed1(xyz)) {
3094  assert(mNode1);
3095  return mNode1->template probeConstNodeAndCache<NodeT>(xyz, this->self());
3096  } else if (this->isHashed2(xyz)) {
3097  assert(mNode2);
3098  return mNode2->template probeConstNodeAndCache<NodeT>(xyz, this->self());
3099  }
3100  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
3101  } else if constexpr ((std::is_same<NodeT, NodeT1>::value)) {
3102  if (this->isHashed1(xyz)) {
3103  assert(mNode1);
3104  return reinterpret_cast<const NodeT*>(mNode1);
3105  } else if (this->isHashed2(xyz)) {
3106  assert(mNode2);
3107  return mNode2->template probeConstNodeAndCache<NodeT>(xyz, this->self());
3108  }
3109  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
3110  } else if constexpr ((std::is_same<NodeT, NodeT2>::value)) {
3111  if (this->isHashed2(xyz)) {
3112  assert(mNode2);
3113  return reinterpret_cast<const NodeT*>(mNode2);
3114  }
3115  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
3116  } else if constexpr (NodeT::LEVEL < NodeT2::LEVEL) {
3117  // Might still be worth caching this path if a NodeT0 or NodeT1
3118  // are accessed in the future
3119  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
3120  } else {
3121  // If we're accessing a node above our top most cache level then
3122  // there's no point trying to cache it
3123  return BaseT::mTree->root().template probeConstNode<NodeT>(xyz);
3124  }
3125  }
3126  /// @brief @return a const pointer to the leaf node that contains
3127  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
3128  const LeafNodeT* probeConstLeaf(const Coord& xyz) const
3129  {
3130  return this->template probeConstNode<LeafNodeT>(xyz);
3131  }
3132  const LeafNodeT* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); }
3133 
3134  /// Remove all the cached nodes and invalidate the corresponding hash-keys.
3135  void clear() override
3136  {
3137  mKey0 = Coord::max();
3138  mNode0 = nullptr;
3139  mKey1 = Coord::max();
3140  mNode1 = nullptr;
3141  mKey2 = Coord::max();
3142  mNode2 = nullptr;
3143 #if OPENVDB_ABI_VERSION_NUMBER >= 10
3144  mBuffer = nullptr;
3145 #endif
3146  }
3147 
3148 private:
3149  // Allow nodes to insert themselves into the cache.
3150  template<typename> friend class RootNode;
3151  template<typename, Index> friend class InternalNode;
3152  template<typename, Index> friend class LeafNode;
3153  // Allow trees to deregister themselves.
3154  template<typename> friend class Tree;
3155 
3156  // This private method is merely for convenience.
3157  inline ValueAccessor3& self() const { return const_cast<ValueAccessor3&>(*this); }
3158 
3159  /// Private copy method
3160  inline void copy(const ValueAccessor3& other)
3161  {
3162  mKey0 = other.mKey0;
3163  mNode0 = other.mNode0;
3164  mKey1 = other.mKey1;
3165  mNode1 = other.mNode1;
3166  mKey2 = other.mKey2;
3167  mNode2 = other.mNode2;
3168 #if OPENVDB_ABI_VERSION_NUMBER >= 10
3169  mBuffer = other.mBuffer;
3170 #endif
3171  }
3172 
3173  /// Prevent this accessor from calling Tree::releaseCache() on a tree that
3174  /// no longer exists. (Called by mTree when it is destroyed.)
3175  void release() override
3176  {
3177  this->BaseT::release();
3178  this->clear();
3179  }
3180  void getNode(const NodeT0*& node) { node = mNode0; }
3181  void getNode(const NodeT1*& node) { node = mNode1; }
3182  void getNode(const NodeT2*& node) { node = mNode2; }
3183  void getNode(const RootNodeT*& node)
3184  {
3185  node = (BaseT::mTree ? &BaseT::mTree->root() : nullptr);
3186  }
3187  template<typename OtherNodeType> void getNode(const OtherNodeType*& node) { node = nullptr; }
3188 
3189  void eraseNode(const NodeT0*)
3190  {
3191  mKey0 = Coord::max();
3192  mNode0 = nullptr;
3193 #if OPENVDB_ABI_VERSION_NUMBER >= 10
3194  mBuffer = nullptr;
3195 #endif
3196  }
3197 
3198  void eraseNode(const NodeT1*) { mKey1 = Coord::max(); mNode1 = nullptr; }
3199  void eraseNode(const NodeT2*) { mKey2 = Coord::max(); mNode2 = nullptr; }
3200  template<typename OtherNodeType> void eraseNode(const OtherNodeType*) {}
3201 
3202  /// Cache the given node, which should lie along the path from the root node to
3203  /// the node containing voxel (x, y, z).
3204  /// @note This operation is not mutex-protected and is intended to be called
3205  /// only by nodes and only in the context of a getValue() or setValue() call.
3206  inline void insert(const Coord& xyz, const NodeT0* node)
3207  {
3208  assert(node);
3209  mKey0 = xyz & ~(NodeT0::DIM-1);
3210  mNode0 = node;
3211 #if OPENVDB_ABI_VERSION_NUMBER >= 10
3212  if constexpr(BypassLeafAPI) {
3213  mBuffer = node->buffer().data();
3214  }
3215 #endif
3216  }
3217  inline void insert(const Coord& xyz, const NodeT1* node)
3218  {
3219  assert(node);
3220  mKey1 = xyz & ~(NodeT1::DIM-1);
3221  mNode1 = node;
3222  }
3223  inline void insert(const Coord& xyz, const NodeT2* node)
3224  {
3225  assert(node);
3226  mKey2 = xyz & ~(NodeT2::DIM-1);
3227  mNode2 = node;
3228  }
3229  /// No-op in case a tree traversal attemps to insert a node that
3230  /// is not cached by the ValueAccessor
3231  template<typename OtherNodeType>
3232  inline void insert(const Coord&, const OtherNodeType*)
3233  {
3234  }
3235  inline bool isHashed0(const Coord& xyz) const
3236  {
3237  return (xyz[0] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[0]
3238  && (xyz[1] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[1]
3239  && (xyz[2] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[2];
3240  }
3241  inline bool isHashed1(const Coord& xyz) const
3242  {
3243  return (xyz[0] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[0]
3244  && (xyz[1] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[1]
3245  && (xyz[2] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[2];
3246  }
3247  inline bool isHashed2(const Coord& xyz) const
3248  {
3249  return (xyz[0] & ~Coord::ValueType(NodeT2::DIM-1)) == mKey2[0]
3250  && (xyz[1] & ~Coord::ValueType(NodeT2::DIM-1)) == mKey2[1]
3251  && (xyz[2] & ~Coord::ValueType(NodeT2::DIM-1)) == mKey2[2];
3252  }
3253  mutable Coord mKey0;
3254  mutable const NodeT0* mNode0;
3255  mutable Coord mKey1;
3256  mutable const NodeT1* mNode1;
3257  mutable Coord mKey2;
3258  mutable const NodeT2* mNode2;
3259 #if OPENVDB_ABI_VERSION_NUMBER >= 10
3260  mutable const ValueType* mBuffer;
3261 #endif
3262 }; // ValueAccessor3
3263 
3264 } // namespace tree
3265 } // namespace OPENVDB_VERSION_NAME
3266 } // namespace openvdb
3267 
3268 #endif // OPENVDB_TREE_VALUEACCESSOR_HAS_BEEN_INCLUDED
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive without changing its value.
Definition: ValueAccessor.h:2955
int getValueDepth(const Coord &xyz)
Definition: ValueAccessor.h:1062
void setValueOn(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:2823
void setActiveState(const Coord &xyz, bool on=true)
Set the active state of the voxel at the given coordinates but don&#39;t change its value.
Definition: ValueAccessor.h:1834
Index32 Index
Definition: Types.h:54
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Definition: ValueAccessor.h:1336
bool isCached(const Coord &xyz) const
Definition: ValueAccessor.h:576
typename NodeVecT::Front RootNodeType
Definition: ValueAccessor.h:1202
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:2693
void addLeaf(LeafNodeT *leaf)
Add the specified leaf to this tree, possibly creating a child branch in the process. If the leaf node already exists, replace it.
Definition: ValueAccessor.h:2385
typename NodeType::ValueType ValueType
Definition: ValueAccessor.h:871
void modifyValue(const Coord &xyz, const ModifyOp &op)
Definition: ValueAccessor.h:1328
Value accessor with one level of node caching.
Definition: ValueAccessor.h:54
TreeType * getTree() const
Return a pointer to the tree associated with this accessor.
Definition: ValueAccessor.h:116
void modifyValue(const Coord &xyz, const ModifyOp &op)
Apply a functor to the value of the voxel at the given coordinates and mark the voxel as active...
Definition: ValueAccessor.h:2876
void getNode(const NodeType *&node)
Definition: ValueAccessor.h:602
LeafNodeType * touchLeaf(const Coord &xyz)
Definition: ValueAccessor.h:1249
void eraseNode()
Definition: ValueAccessor.h:1533
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
Definition: ValueAccessor.h:2906
typename RootNodeT::NodeChainType InvTreeT
Definition: ValueAccessor.h:2640
int getValueDepth(const Coord &xyz)
Definition: ValueAccessor.h:742
const LeafNodeT * probeLeaf(const Coord &xyz) const
Definition: ValueAccessor.h:2497
ValueAccessor2(TreeType &tree)
Constructor from a tree.
Definition: ValueAccessor.h:2091
void getNode(RootNodeType *&node)
Definition: ValueAccessor.h:1228
void insert(const Coord &xyz, const NodeType *node)
Cache the given node at this level.
Definition: ValueAccessor.h:910
NodeT * probeNode(const Coord &xyz)
Definition: ValueAccessor.h:3038
const LeafNodeT * probeLeaf(const Coord &xyz) const
Return a pointer to the leaf node that contains voxel (x, y, z), or nullptr if no such node exists...
Definition: ValueAccessor.h:405
LeafNodeT * touchLeaf(const Coord &xyz)
Definition: ValueAccessor.h:3019
void setValue(const Coord &xyz, const ValueType &value)
Definition: ValueAccessor.h:1313
void eraseNode()
Definition: ValueAccessor.h:341
CacheItem(TreeCacheT &parent)
Definition: ValueAccessor.h:548
void addTile(Index level, const Coord &xyz, const ValueType &value, bool state)
Add a tile at the specified tree level that contains voxel (x, y, z), possibly deleting existing node...
Definition: ValueAccessor.h:1885
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:1669
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:266
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don&#39;t change its value.
Definition: ValueAccessor.h:314
static Index numCacheLevels()
Return the number of cache levels employed by this ValueAccessor.
Definition: ValueAccessor.h:1628
void setValueOnly(const Coord &xyz, const ValueType &value)
Definition: ValueAccessor.h:774
bool probeValue(const Coord &xyz, ValueType &value)
Definition: ValueAccessor.h:1296
typename NodeType::ValueType ValueType
Definition: ValueAccessor.h:544
ValueAccessor(TreeType &tree)
Definition: ValueAccessor.h:487
void setActiveState(const Coord &xyz, bool on=true)
Set the active state of the voxel at the given coordinates but don&#39;t change its value.
Definition: ValueAccessor.h:308
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Return a pointer to the leaf node that contains voxel (x, y, z), or nullptr if no such node exists...
Definition: ValueAccessor.h:400
friend class InternalNode
Definition: ValueAccessor.h:1978
ValueAccessor1(const ValueAccessor1 &other)
Copy constructor.
Definition: ValueAccessor.h:1625
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state and, in value, the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:1422
int getValueDepth(const Coord &xyz) const
Definition: ValueAccessor.h:1431
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active without changing its value.
Definition: ValueAccessor.h:2953
NodeT * probeNode(const Coord &xyz)
Definition: ValueAccessor.h:682
ValueAccessor(TreeType &tree)
Definition: ValueAccessor.h:475
friend class LeafNode
Definition: ValueAccessor.h:1979
void setActiveState(const Coord &xyz, bool on)
Set the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:1161
const LeafNodeType * probeConstLeaf(const Coord &xyz)
Definition: ValueAccessor.h:989
void insert(const Coord &xyz, const NodeType *node)
Cache the given node at this level.
Definition: ValueAccessor.h:582
ValueAccessorBase & operator=(const ValueAccessorBase &other)
Definition: ValueAccessor.h:125
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Definition: ValueAccessor.h:1959
const LeafNodeType * probeConstLeaf(const Coord &xyz)
Definition: ValueAccessor.h:672
ValueAccessor(const ValueAccessor &other)
Definition: ValueAccessor.h:216
ValueAccessorBase(const ValueAccessorBase &other)
Definition: ValueAccessor.h:120
CacheItem(TreeCacheT &parent, const CacheItem &other)
Copy another CacheItem&#39;s node pointers and hash keys, but not its parent pointer. ...
Definition: ValueAccessor.h:558
typename TreeType::RootNodeType RootNodeT
Definition: ValueAccessor.h:1600
void setValueOnly(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinate but don&#39;t change its active state.
Definition: ValueAccessor.h:1457
typename TreeType::LeafNodeType LeafNodeT
Definition: ValueAccessor.h:2075
void clear() override
Remove all the cached nodes and invalidate the corresponding hash-keys.
Definition: ValueAccessor.h:3135
bool probeValue(const Coord &xyz, ValueType &value)
Return the active state and value of the voxel at the given coordinates.
Definition: ValueAccessor.h:1050
bool isCached(const Coord &xyz) const
Definition: ValueAccessor.h:2686
const NodeT * probeConstNode(const Coord &xyz) const
Definition: ValueAccessor.h:1551
void setValueOn(const Coord &xyz, const ValueType &value)
Definition: ValueAccessor.h:784
void modifyValue(const Coord &xyz, const ModifyOp &op)
Apply a functor to the value of the voxel at the given coordinates and mark the voxel as active...
Definition: ValueAccessor.h:292
void setActiveState(const Coord &xyz, bool on)
Set the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:828
void setValueOnly(const Coord &xyz, const ValueType &value)
Definition: ValueAccessor.h:1098
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:110
typename NodeVecT::Front NodeType
Definition: ValueAccessor.h:870
void setValueOn(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:1746
CacheItem(TreeCacheT &parent)
Definition: ValueAccessor.h:1206
LeafNodeT * touchLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, create one, but preserve the values and active states of all voxels.
Definition: ValueAccessor.h:364
NodeType * probeNode(const Coord &xyz)
Definition: ValueAccessor.h:1270
const NodeT * probeConstNode(const Coord &xyz) const
Return a pointer to the node of the specified type that contains voxel (x, y, z), or nullptr if no su...
Definition: ValueAccessor.h:380
LeafNodeType * probeLeaf(const Coord &xyz)
Definition: ValueAccessor.h:1256
TreeType & tree() const
Return a reference to the tree associated with this accessor.
Definition: ValueAccessor.h:118
friend class Tree
Definition: ValueAccessor.h:3154
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:1447
ValueAccessor(TreeType &tree)
Definition: ValueAccessor.h:463
ValueAccessor & operator=(const ValueAccessor &other)
Definition: ValueAccessor.h:218
void addLeaf(LeafNodeT *leaf)
Add the specified leaf to this tree, possibly creating a child branch in the process. If the leaf node already exists, replace it.
Definition: ValueAccessor.h:1514
void setValueOff(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as inactive.
Definition: ValueAccessor.h:816
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don&#39;t change its value.
Definition: ValueAccessor.h:1503
void getNode(const RootNodeType *&node) const
Definition: ValueAccessor.h:1233
void clear()
Erase the nodes at this and lower levels of the cache.
Definition: ValueAccessor.h:927
void modifyValue(const Coord &xyz, const ModifyOp &op)
Apply a functor to the value of the voxel at the given coordinates and mark the voxel as active...
Definition: ValueAccessor.h:1787
void eraseNode()
Definition: ValueAccessor.h:2377
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:235
void setValueOff(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as inactive.
Definition: ValueAccessor.h:282
ValueAccessor(const ValueAccessor &other)
Definition: ValueAccessor.h:488
typename RootNodeT::NodeChainType InvTreeT
Definition: ValueAccessor.h:1603
LeafNodeT * probeLeaf(const Coord &xyz)
Definition: ValueAccessor.h:1557
This base class for ValueAccessors manages registration of an accessor with a tree so that the tree c...
Definition: ValueAccessor.h:92
typename NodeType::LeafNodeType LeafNodeType
Definition: ValueAccessor.h:545
LeafNodeT * touchLeaf(const Coord &xyz)
Definition: ValueAccessor.h:1898
NodeT * probeNode(const Coord &xyz)
Return a pointer to the node of the specified type that contains voxel (x, y, z), or nullptr if no su...
Definition: ValueAccessor.h:374
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
Definition: ValueAccessor.h:301
Value accessor with two levels of node caching.
Definition: ValueAccessor.h:56
typename InvTreeT::template Get< L0 > NodeT0
Definition: ValueAccessor.h:1604
void setValueOnly(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinate but don&#39;t change its active state.
Definition: ValueAccessor.h:275
static Index numCacheLevels()
Return the number of cache levels employed by this ValueAccessor.
Definition: ValueAccessor.h:2679
ValueAccessor3 & operator=(const ValueAccessor3 &other)
Assignment operator.
Definition: ValueAccessor.h:2669
bool isVoxel(const Coord &xyz) const
Definition: ValueAccessor.h:1439
void addTile(Index level, const Coord &xyz, const ValueType &value, bool state)
Definition: ValueAccessor.h:1242
const LeafNodeT * probeLeaf(const Coord &xyz) const
Definition: ValueAccessor.h:1963
typename NodeType::LeafNodeType LeafNodeType
Definition: ValueAccessor.h:872
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
Definition: ValueAccessor.h:2162
NodeT * probeNode(const Coord &xyz)
Definition: ValueAccessor.h:1543
void getNode(const NodeType *&node) const
Return the cached node (if any) at this level.
Definition: ValueAccessor.h:930
CacheItem & copy(TreeCacheT &parent, const CacheItem &other)
Copy another CacheItem&#39;s node pointers and hash keys, but not its parent pointer. ...
Definition: ValueAccessor.h:893
int getValueDepth(const Coord &xyz) const
Definition: ValueAccessor.h:2186
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don&#39;t change its value.
Definition: ValueAccessor.h:1846
TreeType TreeType
Definition: ValueAccessor.h:2072
void addTile(Index level, const Coord &xyz, const ValueType &value, bool state)
Add a tile at the specified tree level that contains voxel (x, y, z), possibly deleting existing node...
Definition: ValueAccessor.h:2398
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:1084
ValueAccessor0(const ValueAccessor0 &other)
Definition: ValueAccessor.h:1391
Definition: Tree.h:177
void setValueOn(const Coord &xyz, const ValueType &value)
Definition: ValueAccessor.h:1325
void insert(const Coord &xyz, const OtherNodeType *node)
Forward the given node to another level of the cache.
Definition: ValueAccessor.h:589
void insertNode(const Coord &xyz, NodeT &node)
Definition: ValueAccessor.h:2371
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
Definition: ValueAccessor.h:1133
const LeafNodeType * probeConstLeaf(const Coord &xyz)
Definition: ValueAccessor.h:1263
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Definition: ValueAccessor.h:3128
void getNode(NodeType *&node)
Definition: ValueAccessor.h:932
friend class InternalNode
Definition: ValueAccessor.h:2521
void setValueOnly(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinate but preserves its active state.
Definition: ValueAccessor.h:2244
typename TreeType::LeafNodeType LeafNodeT
Definition: ValueAccessor.h:1381
typename TreeType::ValueType ValueType
Definition: ValueAccessor.h:1379
void getNode(const NodeType *&node) const
Return the cached node (if any) at this level.
Definition: ValueAccessor.h:601
void setValueOn(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:271
void getNode(OtherNodeType *&node)
Forward the request to another level of the cache.
Definition: ValueAccessor.h:941
ValueAccessor1(TreeType &tree)
Constructor from a tree.
Definition: ValueAccessor.h:1616
NodeT * getNode()
Return the cached node of type NodeType. [Mainly for internal use].
Definition: ValueAccessor.h:2959
bool isValueOn(const Coord &xyz)
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:1040
void addTile(Index level, const Coord &xyz, const ValueType &value, bool state)
Definition: ValueAccessor.h:958
void getNode(const NodeType *&node)
Definition: ValueAccessor.h:931
friend class Tree
Definition: ValueAccessor.h:1981
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:2217
void clear() override
Remove all nodes from this cache, then reinsert the root node.
Definition: ValueAccessor.h:1573
void setValueOff(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as inactive.
Definition: ValueAccessor.h:1771
const NodeT * probeConstNode(const Coord &xyz) const
Definition: ValueAccessor.h:3086
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive without changing its value.
Definition: ValueAccessor.h:2357
void setActiveState(const Coord &xyz, bool on=true)
Set the active state of the voxel at the given coordinates without changing its value.
Definition: ValueAccessor.h:2340
TreeType * mTree
Definition: ValueAccessor.h:143
void getNode(OtherNodeType *&node)
Forward the request to another level of the cache.
Definition: ValueAccessor.h:612
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
Definition: ValueAccessor.h:245
LeafNodeType * probeLeaf(const Coord &xyz)
Definition: ValueAccessor.h:662
LeafNodeT * probeLeaf(const Coord &xyz)
Definition: ValueAccessor.h:2496
void setValueOff(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as inactive.
Definition: ValueAccessor.h:1149
const NodeT * probeNode(const Coord &xyz) const
Return a pointer to the node of the specified type that contains voxel (x, y, z), or nullptr if no su...
Definition: ValueAccessor.h:386
std::numeric_limits< Int32 > CoordLimits
Definition: ValueAccessor.h:873
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:1408
void clear()
Erase the nodes at this and lower levels of the cache.
Definition: ValueAccessor.h:598
ValueAccessor2 & operator=(const ValueAccessor2 &other)
Assignment operator.
Definition: ValueAccessor.h:2107
ValueAccessor2(const ValueAccessor2 &other)
Copy constructor.
Definition: ValueAccessor.h:2101
void addLeaf(LeafNodeType *leaf)
Definition: ValueAccessor.h:1235
typename TreeType::RootNodeType RootNodeT
Definition: ValueAccessor.h:196
const NodeT * probeConstNode(const Coord &xyz)
Definition: ValueAccessor.h:1020
ValueAccessor(TreeType &tree)
Definition: ValueAccessor.h:211
bool isVoxel(const Coord &xyz) const
Definition: ValueAccessor.h:2201
void modifyValue(const Coord &xyz, const ModifyOp &op)
Apply a functor to the value of the voxel at the given coordinates and mark the voxel as active...
Definition: ValueAccessor.h:2287
LeafNodeT * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z), or nullptr if no such node exists...
Definition: ValueAccessor.h:395
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
Definition: ValueAccessor.h:1486
const NodeType * probeConstNode(const Coord &xyz)
Definition: ValueAccessor.h:1279
typename RootNodeT::NodeChainType InvTreeT
Definition: ValueAccessor.h:2077
typename RootNodeType::LeafNodeType LeafNodeType
Definition: ValueAccessor.h:1204
Value accessor with three levels of node caching.
Definition: ValueAccessor.h:58
const LeafNodeT * probeLeaf(const Coord &xyz) const
Definition: ValueAccessor.h:3132
void erase(const OtherNodeType *node)
Erase the node at another level of the cache.
Definition: ValueAccessor.h:595
NodeT * probeNode(const Coord &xyz)
Definition: ValueAccessor.h:2432
TreeType TreeType
Definition: ValueAccessor.h:1378
void addTile(Index level, const Coord &xyz, const ValueType &value, bool state)
Add a tile at the specified tree level that contains voxel (x, y, z), possibly deleting existing node...
Definition: ValueAccessor.h:1523
void setValueOff(const Coord &xyz, const ValueType &value)
Definition: ValueAccessor.h:1343
void insert(const Coord &xyz, const OtherNodeType *node)
Forward the given node to another level of the cache.
Definition: ValueAccessor.h:918
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:2148
bool isCached(const Coord &xyz) const
Definition: ValueAccessor.h:1216
CacheItem(TreeCacheT &parent)
Definition: ValueAccessor.h:877
friend class LeafNode
Definition: ValueAccessor.h:420
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
Definition: ValueAccessor.h:1680
int getValueDepth(const Coord &xyz) const
Definition: ValueAccessor.h:1701
std::numeric_limits< Int32 > CoordLimits
Definition: ValueAccessor.h:546
friend class LeafNode
Definition: ValueAccessor.h:2522
NodeT * getNode()
Return the cached node of type NodeType. [Mainly for internal use].
Definition: ValueAccessor.h:1852
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:764
friend class Tree
Definition: ValueAccessor.h:422
void insertNode(const Coord &xyz, NodeT &node)
Definition: ValueAccessor.h:1862
void erase(const RootNodeType *)
Definition: ValueAccessor.h:1224
Definition: Exceptions.h:13
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Definition: ValueAccessor.h:1562
friend class RootNode
Definition: ValueAccessor.h:2520
typename TreeType::RootNodeType RootNodeT
Definition: ValueAccessor.h:2074
ValueAccessor0 & operator=(const ValueAccessor0 &other)
Definition: ValueAccessor.h:1396
void setValueOnly(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinate but preserves its active state.
Definition: ValueAccessor.h:1750
bool isVoxel(const Coord &xyz)
Definition: ValueAccessor.h:1301
void clear() override
Remove all the cached nodes and invalidate the corresponding hash-keys.
Definition: ValueAccessor.h:2507
typename tbb::null_mutex::scoped_lock LockT
Definition: ValueAccessor.h:200
void setValueOff(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as inactive.
Definition: ValueAccessor.h:2854
void addLeaf(LeafNodeType *leaf)
Definition: ValueAccessor.h:624
ValueT value
Definition: GridBuilder.h:1290
typename InvTreeT::template Get< L1 > NodeT1
Definition: ValueAccessor.h:2079
const NodeT * probeConstNode(const Coord &xyz) const
Definition: ValueAccessor.h:1940
LeafNodeType * probeLeaf(const Coord &xyz)
Definition: ValueAccessor.h:979
bool isVoxel(const Coord &xyz)
Definition: ValueAccessor.h:753
void setValueOn(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:2240
void setActiveState(const Coord &xyz, bool on=true)
Set the active state of the voxel at the given coordinates but don&#39;t change its value.
Definition: ValueAccessor.h:1494
void getNode(NodeType *&node)
Definition: ValueAccessor.h:603
void erase(const NodeType *)
Erase the node at this level.
Definition: ValueAccessor.h:592
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
Definition: ValueAccessor.h:804
virtual void release()
Definition: ValueAccessor.h:141
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:2128
ValueAccessor1 & operator=(const ValueAccessor1 &other)
Assignment operator.
Definition: ValueAccessor.h:1631
friend class Tree
Definition: ValueAccessor.h:2524
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:1726
void addLeaf(LeafNodeT *leaf)
Add the specified leaf to this tree, possibly creating a child branch in the process. If the leaf node already exists, replace it.
Definition: ValueAccessor.h:2983
bool probeValue(const Coord &xyz, ValueType &value)
Return the active state and value of the voxel at the given coordinates.
Definition: ValueAccessor.h:733
ValueAccessor(const ValueAccessor &other)
Definition: ValueAccessor.h:476
bool isVoxel(const Coord &xyz) const
Definition: ValueAccessor.h:262
CacheItem(TreeCacheT &parent, const CacheItem &other)
Definition: ValueAccessor.h:1207
CacheItem(TreeCacheT &parent, const CacheItem &other)
Copy another CacheItem&#39;s node pointers and hash keys, but not its parent pointer. ...
Definition: ValueAccessor.h:886
void addTile(Index level, const Coord &xyz, const ValueType &value, bool state)
Add a tile at the specified tree level that contains voxel (x, y, z), possibly deleting existing node...
Definition: ValueAccessor.h:353
void modifyValue(const Coord &xyz, const ModifyOp &op)
Apply a functor to the value of the voxel at the given coordinates and mark the voxel as active...
Definition: ValueAccessor.h:1476
void eraseNode()
Definition: ValueAccessor.h:1868
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
Definition: ValueAccessor.h:2314
bool isCached(const Coord &) const
Return true if nodes along the path to the given voxel have been cached.
Definition: ValueAccessor.h:1405
LeafNodeT * probeLeaf(const Coord &xyz)
Definition: ValueAccessor.h:1932
LeafNodeT * touchLeaf(const Coord &xyz)
Definition: ValueAccessor.h:2415
void erase(const NodeType *)
Erase the node at this level.
Definition: ValueAccessor.h:921
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:1415
static Index numCacheLevels()
Return the number of cache levels employed by this accessor.
Definition: ValueAccessor.h:1394
bool isVoxel(const Coord &xyz) const
Definition: ValueAccessor.h:1713
void insertNode(const Coord &, NodeT &)
Definition: ValueAccessor.h:1510
ValueAccessorRW(TreeType &tree)
Definition: ValueAccessor.h:520
static Index numCacheLevels()
Return the number of cache levels employed by this accessor.
Definition: ValueAccessor.h:229
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
Definition: ValueAccessor.h:2733
int getValueDepth(const Coord &xyz) const
Definition: ValueAccessor.h:254
int getValueDepth(const Coord &xyz) const
Definition: ValueAccessor.h:2760
static bool isSafe()
Return true if this accessor is safe, i.e. registered by the tree from which it is constructed...
Definition: ValueAccessor.h:103
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active without changing its value.
Definition: ValueAccessor.h:2355
TreeType TreeType
Definition: ValueAccessor.h:2635
void modifyValue(const Coord &xyz, const ModifyOp &op)
Apply a functor to the value of the voxel at the given coordinates and mark the voxel as active...
Definition: ValueAccessor.h:790
const ValueType & getValue(const Coord &xyz)
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:615
ValueAccessor3(const ValueAccessor3 &other)
Copy constructor.
Definition: ValueAccessor.h:2666
void insertNode(const Coord &xyz, NodeT &node)
Definition: ValueAccessor.h:2969
LeafNodeType * touchLeaf(const Coord &xyz)
Definition: ValueAccessor.h:652
bool isValueOn(const Coord &xyz)
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:723
typename RootNodeT::ValueType ValueType
Definition: ValueAccessor.h:198
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Definition: ValueAccessor.h:2501
void addTile(Index level, const Coord &xyz, const ValueType &value, bool state)
Definition: ValueAccessor.h:641
bool isVoxel(const Coord &xyz)
Definition: ValueAccessor.h:1073
typename TreeType::RootNodeType RootNodeT
Definition: ValueAccessor.h:1380
void setValueOnly(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinate but preserves its active state.
Definition: ValueAccessor.h:2827
typename TreeType::LeafNodeType LeafNodeT
Definition: ValueAccessor.h:2638
bool isCached(const Coord &xyz) const
Definition: ValueAccessor.h:2121
ValueAccessor(const ValueAccessor &other)
Definition: ValueAccessor.h:464
ValueAccessor0(TreeType &tree)
Definition: ValueAccessor.h:1389
friend class InternalNode
Definition: ValueAccessor.h:419
NodeT * getNode()
Return the cached node of type NodeType. [Mainly for internal use].
Definition: ValueAccessor.h:2361
void setValueOn(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:1453
void erase(const OtherNodeType *node)
Erase the node at another level of the cache.
Definition: ValueAccessor.h:924
void setValueOn(const Coord &xyz, const ValueType &value)
Definition: ValueAccessor.h:1110
bool isValueOn(const Coord &xyz)
Definition: ValueAccessor.h:1290
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don&#39;t change its value.
Definition: ValueAccessor.h:316
typename RootNodeType::ValueType ValueType
Definition: ValueAccessor.h:1203
virtual ~ValueAccessorBase()
Definition: ValueAccessor.h:110
Definition: ValueAccessor.h:190
void insertNode(const Coord &xyz, NodeType &node)
Definition: ValueAccessor.h:331
friend class RootNode
Definition: ValueAccessor.h:1977
bool isCached(const Coord &xyz) const
Definition: ValueAccessor.h:904
void insert(const Coord &, const RootNodeType *root)
Definition: ValueAccessor.h:1218
friend class Tree
Definition: ValueAccessor.h:1577
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: ValueAccessor.h:2797
void setValueOff(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as inactive.
Definition: ValueAccessor.h:1465
void addLeaf(LeafNodeT *leaf)
Add the specified leaf to this tree, possibly creating a child branch in the process. If the leaf node already exists, replace it.
Definition: ValueAccessor.h:1876
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don&#39;t change its value.
Definition: ValueAccessor.h:1848
void setActiveState(const Coord &xyz, bool on=true)
Set the active state of the voxel at the given coordinates without changing its value.
Definition: ValueAccessor.h:2935
void eraseNode()
Definition: ValueAccessor.h:2975
This accessor is thread-safe (at the cost of speed) for both reading and writing to a tree...
Definition: ValueAccessor.h:517
ValueAccessor with no mutex and no node caching.
Definition: ValueAccessor.h:52
LeafNodeT * probeLeaf(const Coord &xyz)
Definition: ValueAccessor.h:3081
CacheItem & copy(TreeCacheT &parent, const CacheItem &other)
Copy another CacheItem&#39;s node pointers and hash keys, but not its parent pointer. ...
Definition: ValueAccessor.h:566
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:1652
ValueAccessor3(TreeType &tree)
Constructor from a tree.
Definition: ValueAccessor.h:2655
bool isCached(const Coord &xyz) const
Return true if nodes along the path to the given voxel have been cached.
Definition: ValueAccessor.h:232
void setActiveState(const Coord &xyz, bool on)
Definition: ValueAccessor.h:1350
LeafNodeT * touchLeaf(const Coord &xyz)
Definition: ValueAccessor.h:1535
static Index numCacheLevels()
Return the number of cache levels employed by this ValueAccessor.
Definition: ValueAccessor.h:2104
void addLeaf(LeafNodeT *leaf)
Add the specified leaf to this tree, possibly creating a child branch in the process. If the leaf node already exists, replace it.
Definition: ValueAccessor.h:345
bool isVoxel(const Coord &xyz) const
Definition: ValueAccessor.h:2778
typename InvTreeT::template Get< L2 > NodeT2
Definition: ValueAccessor.h:2643
int getValueDepth(const Coord &xyz)
Definition: ValueAccessor.h:1285
void addLeaf(LeafNodeType *leaf)
Definition: ValueAccessor.h:953
typename TreeType::LeafNodeType LeafNodeT
Definition: ValueAccessor.h:197
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
Definition: ValueAccessor.h:1811
LeafNodeType * touchLeaf(const Coord &xyz)
Definition: ValueAccessor.h:969
void clear() override
Remove all nodes from this cache, then reinsert the root node.
Definition: ValueAccessor.h:409
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:242
const LeafNodeT * probeLeaf(const Coord &xyz) const
Definition: ValueAccessor.h:1567
ValueAccessorBase(TreeType &tree)
Definition: ValueAccessor.h:105
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
NodeT * probeNode(const Coord &xyz)
Definition: ValueAccessor.h:1912
Definition: ValueAccessor.h:65
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don&#39;t change its value.
Definition: ValueAccessor.h:1501
TreeType TreeType
Definition: ValueAccessor.h:1598
void addTile(Index level, const Coord &xyz, const ValueType &value, bool state)
Add a tile at the specified tree level that contains voxel (x, y, z), possibly deleting existing node...
Definition: ValueAccessor.h:2999
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:2716
void setValueOnly(const Coord &xyz, const ValueType &value)
Definition: ValueAccessor.h:1319
void modifyValue(const Coord &xyz, const ModifyOp &op)
Apply a functor to the value of the voxel at the given coordinates and mark the voxel as active...
Definition: ValueAccessor.h:1116
friend class InternalNode
Definition: ValueAccessor.h:3151
typename SubtreeT::Front NodeType
Definition: ValueAccessor.h:543
typename TreeType::LeafNodeType LeafNodeT
Definition: ValueAccessor.h:1601
void insert(const Coord &, const OtherNodeType *)
Definition: ValueAccessor.h:1222
friend class RootNode
Definition: ValueAccessor.h:418
ValueAccessor(TreeType &tree)
Definition: ValueAccessor.h:498
TreeType TreeType
Definition: ValueAccessor.h:195
friend class LeafNode
Definition: ValueAccessor.h:3152
NodeT * getNode()
Return the cached node of type NodeType. [Mainly for internal use].
Definition: ValueAccessor.h:1506
const ValueType & getValue(const Coord &xyz)
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:944
const NodeT * probeConstNode(const Coord &xyz)
Definition: ValueAccessor.h:703
const ValueType & getValue(const Coord &xyz)
Definition: ValueAccessor.h:1307
friend class RootNode
Definition: ValueAccessor.h:3150
typename TreeType::RootNodeType RootNodeT
Definition: ValueAccessor.h:2637
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:212
CacheItem & copy(TreeCacheT &parent, const CacheItem &other)
Definition: ValueAccessor.h:1209
void clear() override
Remove all the cached nodes and invalidate the corresponding hash-keys.
Definition: ValueAccessor.h:1966
void setValueOff(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as inactive.
Definition: ValueAccessor.h:2268
bool isCached(const Coord &xyz) const
Definition: ValueAccessor.h:1645
const NodeT * probeConstNode(const Coord &xyz) const
Definition: ValueAccessor.h:2465
NodeT * probeNode(const Coord &xyz)
Definition: ValueAccessor.h:999
NodeType * getNode()
Return the cached node of type NodeType. [Mainly for internal use].
Definition: ValueAccessor.h:320