HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 <tbb/null_mutex.h>
35 #include <tbb/spin_mutex.h>
36 #include <openvdb/version.h>
37 #include <openvdb/Types.h>
38 #include <cassert>
39 #include <limits>
40 #include <type_traits>
41 
42 namespace openvdb {
44 namespace OPENVDB_VERSION_NAME {
45 namespace tree {
46 
47 // Forward declarations of local classes that are not intended for general use
48 // The IsSafe template parameter is explained in the warning below.
49 template<typename TreeType, bool IsSafe = true>
51 template<typename TreeType, bool IsSafe = true, Index L0 = 0>
53 template<typename TreeType, bool IsSafe = true, Index L0 = 0, Index L1 = 1>
55 template<typename TreeType, bool IsSafe = true, Index L0 = 0, Index L1 = 1, Index L2 = 2>
57 template<typename TreeCacheT, typename NodeVecT, bool AtRoot> class CacheItem;
58 
59 
60 /// @brief This base class for ValueAccessors manages registration of an accessor
61 /// with a tree so that the tree can automatically clear the accessor whenever
62 /// one of its nodes is deleted.
63 ///
64 /// @internal A base class is needed because ValueAccessor is templated on both
65 /// a Tree type and a mutex type. The various instantiations of the template
66 /// are distinct, unrelated types, so they can't easily be stored in a container
67 /// such as the Tree's CacheRegistry. This base class, in contrast, is templated
68 /// only on the Tree type, so for any given Tree, only two distinct instantiations
69 /// are possible, ValueAccessorBase<Tree> and ValueAccessorBase<const Tree>.
70 ///
71 /// @warning If IsSafe = false then the ValueAccessor will not register itself
72 /// with the tree from which it is constructed. While in some rare cases this can
73 /// lead to better performance (since it avoids the small overhead of insertion
74 /// on creation and deletion on destruction) it is also unsafe if the tree is
75 /// modified. So unless you're an expert it is highly recommended to set
76 /// IsSafe = true, which is the default in all derived ValueAccessors defined
77 /// below. However if you know that the tree is no being modifed for the lifespan
78 /// of the ValueAccessor AND the work performed per ValueAccessor is small relative
79 /// to overhead of registering it you should consider setting IsSafe = false. If
80 /// this turns out to improve performance you should really rewrite your code so as
81 /// to better amortize the construction of the ValueAccessor, i.e. reuse it as much
82 /// as possible!
83 template<typename TreeType, bool IsSafe>
85 {
86 public:
88 
89  /// @brief Return true if this accessor is safe, i.e. registered
90  /// by the tree from which it is constructed. Un-registered
91  /// accessors can in rare cases be faster because it avoids the
92  /// (small) overhead of registration, but they are unsafe if the
93  /// tree is modified. So unless you're an expert it is highly
94  /// recommended to set IsSafe = true (which is the default).
95  static bool isSafe() { return IsSafe; }
96 
97  ValueAccessorBase(TreeType& tree): mTree(&tree)
98  {
99  if (IsSafe) tree.attachAccessor(*this);
100  }
101 
102  virtual ~ValueAccessorBase() { if (IsSafe && mTree) mTree->releaseAccessor(*this); }
103 
104  /// @brief Return a pointer to the tree associated with this accessor.
105  /// @details The pointer will be null only if the tree from which this accessor
106  /// was constructed was subsequently deleted (which generally leaves the
107  /// accessor in an unsafe state).
108  TreeType* getTree() const { return mTree; }
109  /// Return a reference to the tree associated with this accessor.
110  TreeType& tree() const { assert(mTree); return *mTree; }
111 
113  {
114  if (IsSafe && mTree) mTree->attachAccessor(*this);
115  }
116 
118  {
119  if (&other != this) {
120  if (IsSafe && mTree) mTree->releaseAccessor(*this);
121  mTree = other.mTree;
122  if (IsSafe && mTree) mTree->attachAccessor(*this);
123  }
124  return *this;
125  }
126 
127  virtual void clear() = 0;
128 
129 protected:
130  // Allow trees to deregister themselves.
131  template<typename> friend class Tree;
132 
133  virtual void release() { mTree = nullptr; }
134 
135  TreeType* mTree;
136 }; // class ValueAccessorBase
137 
138 
139 ////////////////////////////////////////
140 
141 
142 /// When traversing a grid in a spatially coherent pattern (e.g., iterating
143 /// over neighboring voxels), request a @c ValueAccessor from the grid
144 /// (with Grid::getAccessor()) and use the accessor's @c getValue() and
145 /// @c setValue() methods. These will typically be significantly faster
146 /// than accessing voxels directly in the grid's tree.
147 ///
148 /// A ValueAccessor caches pointers to tree nodes along the path to a voxel (x, y, z).
149 /// A subsequent access to voxel (x', y', z') starts from the cached leaf node and
150 /// moves up until a cached node that encloses (x', y', z') is found, then traverses
151 /// down the tree from that node to a leaf, updating the cache with the new path.
152 /// This leads to significant acceleration of spatially-coherent accesses.
153 ///
154 /// @param _TreeType the type of the tree to be accessed [required]
155 /// @param IsSafe if IsSafe = false then the ValueAccessor will
156 /// not register itself with the tree from which
157 /// it is constructed (see warning).
158 /// @param CacheLevels the number of nodes to be cached, starting from the leaf level
159 /// and not including the root (i.e., CacheLevels < DEPTH),
160 /// and defaulting to all non-root nodes
161 /// @param MutexType the type of mutex to use (see note)
162 ///
163 /// @warning If IsSafe = false then the ValueAccessor will not register itself
164 /// with the tree from which it is constructed. While in some rare cases this can
165 /// lead to better performance (since it avoids the small overhead of insertion
166 /// on creation and deletion on destruction) it is also unsafe if the tree is
167 /// modified. So unless you're an expert it is highly recommended to set
168 /// IsSafe = true, which is the default. However if you know that the tree is no
169 /// being modifed for the lifespan of the ValueAccessor AND the work performed
170 /// per ValueAccessor is small relative to overhead of registering it you should
171 /// consider setting IsSafe = false. If this improves performance you should
172 /// really rewrite your code so as to better amortize the construction of the
173 /// ValueAccessor, i.e. reuse it as much as possible!
174 ///
175 /// @note If @c MutexType is a TBB-compatible mutex, then multiple threads may
176 /// safely access a single, shared accessor. However, it is highly recommended
177 /// that, instead, each thread be assigned its own, non-mutex-protected accessor.
178 template<typename _TreeType,
179  bool IsSafe = true,
180  Index CacheLevels = _TreeType::DEPTH-1,
181  typename MutexType = tbb::null_mutex>
182 class ValueAccessor: public ValueAccessorBase<_TreeType, IsSafe>
183 {
184 public:
185  static_assert(CacheLevels < _TreeType::DEPTH, "cache size exceeds tree depth");
186 
187  using TreeType = _TreeType;
188  using RootNodeT = typename TreeType::RootNodeType;
189  using LeafNodeT = typename TreeType::LeafNodeType;
190  using ValueType = typename RootNodeT::ValueType;
192  using LockT = typename MutexType::scoped_lock;
193  using BaseT::IsConstTree;
194 
195  ValueAccessor(TreeType& tree): BaseT(tree), mCache(*this)
196  {
197  mCache.insert(Coord(), &tree.root());
198  }
199 
200  ValueAccessor(const ValueAccessor& other): BaseT(other), mCache(*this, other.mCache) {}
201 
203  {
204  if (&other != this) {
205  this->BaseT::operator=(other);
206  mCache.copy(*this, other.mCache);
207  }
208  return *this;
209  }
210  ~ValueAccessor() override = default;
211 
212  /// Return the number of cache levels employed by this accessor.
213  static Index numCacheLevels() { return CacheLevels; }
214 
215  /// Return @c true if nodes along the path to the given voxel have been cached.
216  bool isCached(const Coord& xyz) const { LockT lock(mMutex); return mCache.isCached(xyz); }
217 
218  /// Return the value of the voxel at the given coordinates.
219  const ValueType& getValue(const Coord& xyz) const
220  {
221  LockT lock(mMutex);
222  return mCache.getValue(xyz);
223  }
224 
225  /// Return the active state of the voxel at the given coordinates.
226  bool isValueOn(const Coord& xyz) const { LockT lock(mMutex); return mCache.isValueOn(xyz); }
227 
228  /// Return the active state of the voxel as well as its value
229  bool probeValue(const Coord& xyz, ValueType& value) const
230  {
231  LockT lock(mMutex);
232  return mCache.probeValue(xyz,value);
233  }
234 
235  /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides,
236  /// or -1 if (x, y, z) isn't explicitly represented in the tree (i.e., if it is
237  /// implicitly a background voxel).
238  int getValueDepth(const Coord& xyz) const
239  {
240  LockT lock(mMutex);
241  return mCache.getValueDepth(xyz);
242  }
243 
244  /// Return @c true if the value of voxel (x, y, z) resides at the leaf level
245  /// of the tree, i.e., if it is not a tile value.
246  bool isVoxel(const Coord& xyz) const { LockT lock(mMutex); return mCache.isVoxel(xyz); }
247 
248  //@{
249  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
250  void setValue(const Coord& xyz, const ValueType& value)
251  {
252  LockT lock(mMutex);
253  mCache.setValue(xyz, value);
254  }
255  void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); }
256  //@}
257 
258  /// Set the value of the voxel at the given coordinate but don't change its active state.
259  void setValueOnly(const Coord& xyz, const ValueType& value)
260  {
261  LockT lock(mMutex);
262  mCache.setValueOnly(xyz, value);
263  }
264 
265  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
266  void setValueOff(const Coord& xyz, const ValueType& value)
267  {
268  LockT lock(mMutex);
269  mCache.setValueOff(xyz, value);
270  }
271 
272  /// @brief Apply a functor to the value of the voxel at the given coordinates
273  /// and mark the voxel as active.
274  /// @details See Tree::modifyValue() for details.
275  template<typename ModifyOp>
276  void modifyValue(const Coord& xyz, const ModifyOp& op)
277  {
278  LockT lock(mMutex);
279  mCache.modifyValue(xyz, op);
280  }
281 
282  /// @brief Apply a functor to the voxel at the given coordinates.
283  /// @details See Tree::modifyValueAndActiveState() for details.
284  template<typename ModifyOp>
285  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
286  {
287  LockT lock(mMutex);
288  mCache.modifyValueAndActiveState(xyz, op);
289  }
290 
291  /// Set the active state of the voxel at the given coordinates but don't change its value.
292  void setActiveState(const Coord& xyz, bool on = true)
293  {
294  LockT lock(mMutex);
295  mCache.setActiveState(xyz, on);
296  }
297  /// Mark the voxel at the given coordinates as active but don't change its value.
298  void setValueOn(const Coord& xyz) { this->setActiveState(xyz, true); }
299  /// Mark the voxel at the given coordinates as inactive but don't change its value.
300  void setValueOff(const Coord& xyz) { this->setActiveState(xyz, false); }
301 
302  /// Return the cached node of type @a NodeType. [Mainly for internal use]
303  template<typename NodeType>
304  NodeType* getNode()
305  {
306  LockT lock(mMutex);
307  NodeType* node = nullptr;
308  mCache.getNode(node);
309  return node;
310  }
311 
312  /// Cache the given node, which should lie along the path from the root node to
313  /// the node containing voxel (x, y, z). [Mainly for internal use]
314  template<typename NodeType>
315  void insertNode(const Coord& xyz, NodeType& node)
316  {
317  LockT lock(mMutex);
318  mCache.insert(xyz, &node);
319  }
320 
321  /// If a node of the given type exists in the cache, remove it, so that
322  /// isCached(xyz) returns @c false for any voxel (x, y, z) contained in
323  /// that node. [Mainly for internal use]
324  template<typename NodeType>
325  void eraseNode() { LockT lock(mMutex); NodeType* node = nullptr; mCache.erase(node); }
326 
327  /// @brief Add the specified leaf to this tree, possibly creating a child branch
328  /// in the process. If the leaf node already exists, replace it.
329  void addLeaf(LeafNodeT* leaf)
330  {
331  LockT lock(mMutex);
332  mCache.addLeaf(leaf);
333  }
334 
335  /// @brief Add a tile at the specified tree level that contains voxel (x, y, z),
336  /// possibly deleting existing nodes or creating new nodes in the process.
337  void addTile(Index level, const Coord& xyz, const ValueType& value, bool state)
338  {
339  LockT lock(mMutex);
340  mCache.addTile(level, xyz, value, state);
341  }
342 
343  /// @brief Return a pointer to the leaf node that contains voxel (x, y, z).
344  /// If no such node exists, create one, but preserve the values and
345  /// active states of all voxels.
346  /// @details Use this method to preallocate a static tree topology
347  /// over which to safely perform multithreaded processing.
348  LeafNodeT* touchLeaf(const Coord& xyz)
349  {
350  LockT lock(mMutex);
351  return mCache.touchLeaf(xyz);
352  }
353 
354  //@{
355  /// @brief Return a pointer to the node of the specified type that contains
356  /// voxel (x, y, z), or @c nullptr if no such node exists.
357  template<typename NodeT>
358  NodeT* probeNode(const Coord& xyz)
359  {
360  LockT lock(mMutex);
361  return mCache.template probeNode<NodeT>(xyz);
362  }
363  template<typename NodeT>
364  const NodeT* probeConstNode(const Coord& xyz) const
365  {
366  LockT lock(mMutex);
367  return mCache.template probeConstNode<NodeT>(xyz);
368  }
369  template<typename NodeT>
370  const NodeT* probeNode(const Coord& xyz) const
371  {
372  return this->template probeConstNode<NodeT>(xyz);
373  }
374  //@}
375 
376  //@{
377  /// @brief Return a pointer to the leaf node that contains voxel (x, y, z),
378  /// or @c nullptr if no such node exists.
379  LeafNodeT* probeLeaf(const Coord& xyz)
380  {
381  LockT lock(mMutex);
382  return mCache.probeLeaf(xyz);
383  }
384  const LeafNodeT* probeConstLeaf(const Coord& xyz) const
385  {
386  LockT lock(mMutex);
387  return mCache.probeConstLeaf(xyz);
388  }
389  const LeafNodeT* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); }
390  //@}
391 
392  /// Remove all nodes from this cache, then reinsert the root node.
393  void clear() override
394  {
395  LockT lock(mMutex);
396  mCache.clear();
397  if (this->mTree) mCache.insert(Coord(), &(this->mTree->root()));
398  }
399 
400 private:
401  // Allow nodes to insert themselves into the cache.
402  template<typename> friend class RootNode;
403  template<typename, Index> friend class InternalNode;
404  template<typename, Index> friend class LeafNode;
405  // Allow trees to deregister themselves.
406  template<typename> friend class Tree;
407 
408  /// Prevent this accessor from calling Tree::releaseCache() on a tree that
409  /// no longer exists. (Called by mTree when it is destroyed.)
410  void release() override
411  {
412  LockT lock(mMutex);
413  this->BaseT::release();
414  mCache.clear();
415  }
416 
417  /// Cache the given node, which should lie along the path from the root node to
418  /// the node containing voxel (x, y, z).
419  /// @note This operation is not mutex-protected and is intended to be called
420  /// only by nodes and only in the context of a getValue() or setValue() call.
421  template<typename NodeType>
422  void insert(const Coord& xyz, NodeType* node) { mCache.insert(xyz, node); }
423 
424  // Define a list of all tree node types from LeafNode to RootNode
425  using InvTreeT = typename RootNodeT::NodeChainType;
426  // Remove all tree node types that are excluded from the cache
427  static constexpr int64_t First = CacheLevels;
428  static constexpr int64_t Last = InvTreeT::template Index<RootNodeT>;
429  using SubtreeT = typename InvTreeT::template RemoveByIndex<First, Last-1>;
430  using CacheItemT = CacheItem<ValueAccessor, SubtreeT, SubtreeT::Size==1>;
431 
432  // Private member data
433  mutable CacheItemT mCache;
434  mutable MutexType mMutex;
435 
436 }; // class ValueAccessor
437 
438 
439 /// @brief Template specialization of the ValueAccessor with no mutex and no cache levels
440 /// @details This specialization is provided mainly for benchmarking.
441 /// Accessors with caching will almost always be faster.
442 template<typename TreeType, bool IsSafe>
443 class ValueAccessor<TreeType, IsSafe, 0, tbb::null_mutex>
444  : public ValueAccessor0<TreeType, IsSafe>
445 {
446 public:
448  ValueAccessor(const ValueAccessor& other): ValueAccessor0<TreeType, IsSafe>(other) {}
449  ~ValueAccessor() override = default;
450 };
451 
452 
453 /// Template specialization of the ValueAccessor with no mutex and one cache level
454 template<typename TreeType, bool IsSafe>
455 class ValueAccessor<TreeType, IsSafe, 1, tbb::null_mutex>
456  : public ValueAccessor1<TreeType, IsSafe>
457 {
458 public:
460  ValueAccessor(const ValueAccessor& other): ValueAccessor1<TreeType, IsSafe>(other) {}
461  ~ValueAccessor() override = default;
462 };
463 
464 
465 /// Template specialization of the ValueAccessor with no mutex and two cache levels
466 template<typename TreeType, bool IsSafe>
467 class ValueAccessor<TreeType, IsSafe, 2, tbb::null_mutex>
468  : public ValueAccessor2<TreeType, IsSafe>
469 {
470 public:
472  ValueAccessor(const ValueAccessor& other): ValueAccessor2<TreeType, IsSafe>(other) {}
473  ~ValueAccessor() override = default;
474 };
475 
476 
477 /// Template specialization of the ValueAccessor with no mutex and three cache levels
478 template<typename TreeType, bool IsSafe>
479 class ValueAccessor<TreeType, IsSafe, 3, tbb::null_mutex>: public ValueAccessor3<TreeType, IsSafe>
480 {
481 public:
483  ValueAccessor(const ValueAccessor&) = default;
484  ValueAccessor& operator=(const ValueAccessor&) = default;
485  ~ValueAccessor() override = default;
486 };
487 
488 
489 ////////////////////////////////////////
490 
491 
492 /// @brief This accessor is thread-safe (at the cost of speed) for both reading and
493 /// writing to a tree. That is, multiple threads may safely access a single,
494 /// shared ValueAccessorRW.
495 ///
496 /// @warning Since the mutex-locking employed by the ValueAccessorRW
497 /// can seriously impair performance of multithreaded applications, it
498 /// is recommended that, instead, each thread be assigned its own
499 /// (non-mutex protected) accessor.
500 template<typename TreeType, bool IsSafe = true>
501 class ValueAccessorRW: public ValueAccessor<TreeType, IsSafe, TreeType::DEPTH-1, tbb::spin_mutex>
502 {
503 public:
505  : ValueAccessor<TreeType, IsSafe, TreeType::DEPTH-1, tbb::spin_mutex>(tree)
506  {
507  }
508 };
509 
510 
511 ////////////////////////////////////////
512 
513 
514 //
515 // The classes below are for internal use and should rarely be used directly.
516 //
517 
518 // An element of a compile-time linked list of node pointers, ordered from LeafNode to RootNode
519 template<typename TreeCacheT, typename NodeVecT, bool AtRoot>
520 class CacheItem
521 {
522 public:
523  using NodeType = typename NodeVecT::Front;
524  using ValueType = typename NodeType::ValueType;
525  using LeafNodeType = typename NodeType::LeafNodeType;
526  using CoordLimits = std::numeric_limits<Int32>;
527 
528  CacheItem(TreeCacheT& parent):
529  mParent(&parent),
530  mHash(CoordLimits::max()),
531  mNode(nullptr),
532  mNext(parent)
533  {
534  }
535 
536  //@{
537  /// Copy another CacheItem's node pointers and hash keys, but not its parent pointer.
538  CacheItem(TreeCacheT& parent, const CacheItem& other):
539  mParent(&parent),
540  mHash(other.mHash),
541  mNode(other.mNode),
542  mNext(parent, other.mNext)
543  {
544  }
545 
546  CacheItem& copy(TreeCacheT& parent, const CacheItem& other)
547  {
548  mParent = &parent;
549  mHash = other.mHash;
550  mNode = other.mNode;
551  mNext.copy(parent, other.mNext);
552  return *this;
553  }
554  //@}
555 
556  bool isCached(const Coord& xyz) const
557  {
558  return (this->isHashed(xyz) || mNext.isCached(xyz));
559  }
560 
561  /// Cache the given node at this level.
562  void insert(const Coord& xyz, const NodeType* node)
563  {
564  mHash = (node != nullptr) ? xyz & ~(NodeType::DIM-1) : Coord::max();
565  mNode = node;
566  }
567  /// Forward the given node to another level of the cache.
568  template<typename OtherNodeType>
569  void insert(const Coord& xyz, const OtherNodeType* node) { mNext.insert(xyz, node); }
570 
571  /// Erase the node at this level.
572  void erase(const NodeType*) { mHash = Coord::max(); mNode = nullptr; }
573  /// Erase the node at another level of the cache.
574  template<typename OtherNodeType>
575  void erase(const OtherNodeType* node) { mNext.erase(node); }
576 
577  /// Erase the nodes at this and lower levels of the cache.
578  void clear() { mHash = Coord::max(); mNode = nullptr; mNext.clear(); }
579 
580  /// Return the cached node (if any) at this level.
581  void getNode(const NodeType*& node) const { node = mNode; }
582  void getNode(const NodeType*& node) { node = mNode; }
583  void getNode(NodeType*& node)
584  {
585  // This combination of a static assertion and a const_cast might not be elegant,
586  // but it is a lot simpler than specializing TreeCache for const Trees.
587  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
588  node = const_cast<NodeType*>(mNode);
589  }
590  /// Forward the request to another level of the cache.
591  template<typename OtherNodeType>
592  void getNode(OtherNodeType*& node) { mNext.getNode(node); }
593 
594  /// Return the value of the voxel at the given coordinates.
595  const ValueType& getValue(const Coord& xyz)
596  {
597  if (this->isHashed(xyz)) {
598  assert(mNode);
599  return mNode->getValueAndCache(xyz, *mParent);
600  }
601  return mNext.getValue(xyz);
602  }
603 
604  void addLeaf(LeafNodeType* leaf)
605  {
606  static_assert(!TreeCacheT::IsConstTree, "can't add a node to a const tree");
607  if (NodeType::LEVEL == 0) return;
608  if (this->isHashed(leaf->origin())) {
609  assert(mNode);
610  return const_cast<NodeType*>(mNode)->addLeafAndCache(leaf, *mParent);
611  }
612  mNext.addLeaf(leaf);
613  }
614 
615  void addTile(Index level, const Coord& xyz, const ValueType& value, bool state)
616  {
617  static_assert(!TreeCacheT::IsConstTree, "can't add a tile to a const tree");
618  if (NodeType::LEVEL < level) return;
619  if (this->isHashed(xyz)) {
620  assert(mNode);
621  return const_cast<NodeType*>(mNode)->addTileAndCache(
622  level, xyz, value, state, *mParent);
623  }
624  mNext.addTile(level, xyz, value, state);
625  }
626 
627  LeafNodeType* touchLeaf(const Coord& xyz)
628  {
629  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
630  if (this->isHashed(xyz)) {
631  assert(mNode);
632  return const_cast<NodeType*>(mNode)->touchLeafAndCache(xyz, *mParent);
633  }
634  return mNext.touchLeaf(xyz);
635  }
636 
637  LeafNodeType* probeLeaf(const Coord& xyz)
638  {
639  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
640  if (this->isHashed(xyz)) {
641  assert(mNode);
642  return const_cast<NodeType*>(mNode)->probeLeafAndCache(xyz, *mParent);
643  }
644  return mNext.probeLeaf(xyz);
645  }
646 
647  const LeafNodeType* probeConstLeaf(const Coord& xyz)
648  {
649  if (this->isHashed(xyz)) {
650  assert(mNode);
651  return mNode->probeConstLeafAndCache(xyz, *mParent);
652  }
653  return mNext.probeConstLeaf(xyz);
654  }
655 
656  template<typename NodeT>
657  NodeT* probeNode(const Coord& xyz)
658  {
659  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
661  if (this->isHashed(xyz)) {
663  assert(mNode);
664  return reinterpret_cast<NodeT*>(const_cast<NodeType*>(mNode));
665  }
666  return const_cast<NodeType*>(mNode)->template probeNodeAndCache<NodeT>(xyz, *mParent);
667  }
668  return mNext.template probeNode<NodeT>(xyz);
670  }
671 
672  template<typename NodeT>
673  const NodeT* probeConstNode(const Coord& xyz)
674  {
676  if (this->isHashed(xyz)) {
678  assert(mNode);
679  return reinterpret_cast<const NodeT*>(mNode);
680  }
681  return mNode->template probeConstNodeAndCache<NodeT>(xyz, *mParent);
682  }
683  return mNext.template probeConstNode<NodeT>(xyz);
685  }
686 
687  /// Return the active state of the voxel at the given coordinates.
688  bool isValueOn(const Coord& xyz)
689  {
690  if (this->isHashed(xyz)) {
691  assert(mNode);
692  return mNode->isValueOnAndCache(xyz, *mParent);
693  }
694  return mNext.isValueOn(xyz);
695  }
696 
697  /// Return the active state and value of the voxel at the given coordinates.
698  bool probeValue(const Coord& xyz, ValueType& value)
699  {
700  if (this->isHashed(xyz)) {
701  assert(mNode);
702  return mNode->probeValueAndCache(xyz, value, *mParent);
703  }
704  return mNext.probeValue(xyz, value);
705  }
706 
707  int getValueDepth(const Coord& xyz)
708  {
709  if (this->isHashed(xyz)) {
710  assert(mNode);
711  return static_cast<int>(TreeCacheT::RootNodeT::LEVEL) -
712  static_cast<int>(mNode->getValueLevelAndCache(xyz, *mParent));
713  } else {
714  return mNext.getValueDepth(xyz);
715  }
716  }
717 
718  bool isVoxel(const Coord& xyz)
719  {
720  if (this->isHashed(xyz)) {
721  assert(mNode);
722  return mNode->getValueLevelAndCache(xyz, *mParent)==0;
723  } else {
724  return mNext.isVoxel(xyz);
725  }
726  }
727 
728  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
729  void setValue(const Coord& xyz, const ValueType& value)
730  {
731  if (this->isHashed(xyz)) {
732  assert(mNode);
733  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
734  const_cast<NodeType*>(mNode)->setValueAndCache(xyz, value, *mParent);
735  } else {
736  mNext.setValue(xyz, value);
737  }
738  }
739  void setValueOnly(const Coord& xyz, const ValueType& value)
740  {
741  if (this->isHashed(xyz)) {
742  assert(mNode);
743  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
744  const_cast<NodeType*>(mNode)->setValueOnlyAndCache(xyz, value, *mParent);
745  } else {
746  mNext.setValueOnly(xyz, value);
747  }
748  }
749  void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); }
750 
751  /// @brief Apply a functor to the value of the voxel at the given coordinates
752  /// and mark the voxel as active.
753  /// @details See Tree::modifyValue() for details.
754  template<typename ModifyOp>
755  void modifyValue(const Coord& xyz, const ModifyOp& op)
756  {
757  if (this->isHashed(xyz)) {
758  assert(mNode);
759  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
760  const_cast<NodeType*>(mNode)->modifyValueAndCache(xyz, op, *mParent);
761  } else {
762  mNext.modifyValue(xyz, op);
763  }
764  }
765 
766  /// @brief Apply a functor to the voxel at the given coordinates.
767  /// @details See Tree::modifyValueAndActiveState() for details.
768  template<typename ModifyOp>
769  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
770  {
771  if (this->isHashed(xyz)) {
772  assert(mNode);
773  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
774  const_cast<NodeType*>(mNode)->modifyValueAndActiveStateAndCache(xyz, op, *mParent);
775  } else {
776  mNext.modifyValueAndActiveState(xyz, op);
777  }
778  }
779 
780  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
781  void setValueOff(const Coord& xyz, const ValueType& value)
782  {
783  if (this->isHashed(xyz)) {
784  assert(mNode);
785  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
786  const_cast<NodeType*>(mNode)->setValueOffAndCache(xyz, value, *mParent);
787  } else {
788  mNext.setValueOff(xyz, value);
789  }
790  }
791 
792  /// Set the active state of the voxel at the given coordinates.
793  void setActiveState(const Coord& xyz, bool on)
794  {
795  if (this->isHashed(xyz)) {
796  assert(mNode);
797  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
798  const_cast<NodeType*>(mNode)->setActiveStateAndCache(xyz, on, *mParent);
799  } else {
800  mNext.setActiveState(xyz, on);
801  }
802  }
803 
804 private:
805  CacheItem(const CacheItem&);
806  CacheItem& operator=(const CacheItem&);
807 
808  bool isHashed(const Coord& xyz) const
809  {
810  return (xyz[0] & ~Coord::ValueType(NodeType::DIM-1)) == mHash[0]
811  && (xyz[1] & ~Coord::ValueType(NodeType::DIM-1)) == mHash[1]
812  && (xyz[2] & ~Coord::ValueType(NodeType::DIM-1)) == mHash[2];
813  }
814 
815  TreeCacheT* mParent;
816  Coord mHash;
817  const NodeType* mNode;
818  using RestT = typename NodeVecT::PopFront;
819  CacheItem<TreeCacheT, RestT, /*AtRoot=*/RestT::Size == 1> mNext;
820 };// end of CacheItem
821 
822 
823 /// The tail of a compile-time list of cached node pointers, ordered from LeafNode to RootNode
824 template<typename TreeCacheT, typename NodeVecT>
825 class CacheItem<TreeCacheT, NodeVecT, /*AtRoot=*/true>
826 {
827 public:
828  using RootNodeType = typename NodeVecT::Front;
829  using ValueType = typename RootNodeType::ValueType;
830  using LeafNodeType = typename RootNodeType::LeafNodeType;
831 
832  CacheItem(TreeCacheT& parent): mParent(&parent), mRoot(nullptr) {}
833  CacheItem(TreeCacheT& parent, const CacheItem& other): mParent(&parent), mRoot(other.mRoot) {}
834 
835  CacheItem& copy(TreeCacheT& parent, const CacheItem& other)
836  {
837  mParent = &parent;
838  mRoot = other.mRoot;
839  return *this;
840  }
841 
842  bool isCached(const Coord& xyz) const { return this->isHashed(xyz); }
843 
844  void insert(const Coord&, const RootNodeType* root) { mRoot = root; }
845 
846  // Needed for node types that are not cached
847  template<typename OtherNodeType>
848  void insert(const Coord&, const OtherNodeType*) {}
849 
850  void erase(const RootNodeType*) { mRoot = nullptr; }
851 
852  void clear() { mRoot = nullptr; }
853 
854  void getNode(RootNodeType*& node)
855  {
856  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
857  node = const_cast<RootNodeType*>(mRoot);
858  }
859  void getNode(const RootNodeType*& node) const { node = mRoot; }
860 
861  void addLeaf(LeafNodeType* leaf)
862  {
863  assert(mRoot);
864  static_assert(!TreeCacheT::IsConstTree, "can't add a node to a const tree");
865  const_cast<RootNodeType*>(mRoot)->addLeafAndCache(leaf, *mParent);
866  }
867 
868  void addTile(Index level, const Coord& xyz, const ValueType& value, bool state)
869  {
870  assert(mRoot);
871  static_assert(!TreeCacheT::IsConstTree, "can't add a tile to a const tree");
872  const_cast<RootNodeType*>(mRoot)->addTileAndCache(level, xyz, value, state, *mParent);
873  }
874 
875  LeafNodeType* touchLeaf(const Coord& xyz)
876  {
877  assert(mRoot);
878  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
879  return const_cast<RootNodeType*>(mRoot)->touchLeafAndCache(xyz, *mParent);
880  }
881 
882  LeafNodeType* probeLeaf(const Coord& xyz)
883  {
884  assert(mRoot);
885  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
886  return const_cast<RootNodeType*>(mRoot)->probeLeafAndCache(xyz, *mParent);
887  }
888 
889  const LeafNodeType* probeConstLeaf(const Coord& xyz)
890  {
891  assert(mRoot);
892  return mRoot->probeConstLeafAndCache(xyz, *mParent);
893  }
894 
895  template<typename NodeType>
896  NodeType* probeNode(const Coord& xyz)
897  {
898  assert(mRoot);
899  static_assert(!TreeCacheT::IsConstTree, "can't get a non-const node from a const tree");
900  return const_cast<RootNodeType*>(mRoot)->
901  template probeNodeAndCache<NodeType>(xyz, *mParent);
902  }
903 
904  template<typename NodeType>
905  const NodeType* probeConstNode(const Coord& xyz)
906  {
907  assert(mRoot);
908  return mRoot->template probeConstNodeAndCache<NodeType>(xyz, *mParent);
909  }
910 
911  int getValueDepth(const Coord& xyz)
912  {
913  assert(mRoot);
914  return mRoot->getValueDepthAndCache(xyz, *mParent);
915  }
916  bool isValueOn(const Coord& xyz)
917  {
918  assert(mRoot);
919  return mRoot->isValueOnAndCache(xyz, *mParent);
920  }
921 
922  bool probeValue(const Coord& xyz, ValueType& value)
923  {
924  assert(mRoot);
925  return mRoot->probeValueAndCache(xyz, value, *mParent);
926  }
927  bool isVoxel(const Coord& xyz)
928  {
929  assert(mRoot);
930  return mRoot->getValueDepthAndCache(xyz, *mParent) ==
931  static_cast<int>(RootNodeType::LEVEL);
932  }
933  const ValueType& getValue(const Coord& xyz)
934  {
935  assert(mRoot);
936  return mRoot->getValueAndCache(xyz, *mParent);
937  }
938 
939  void setValue(const Coord& xyz, const ValueType& value)
940  {
941  assert(mRoot);
942  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
943  const_cast<RootNodeType*>(mRoot)->setValueAndCache(xyz, value, *mParent);
944  }
945  void setValueOnly(const Coord& xyz, const ValueType& value)
946  {
947  assert(mRoot);
948  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
949  const_cast<RootNodeType*>(mRoot)->setValueOnlyAndCache(xyz, value, *mParent);
950  }
951  void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); }
952 
953  template<typename ModifyOp>
954  void modifyValue(const Coord& xyz, const ModifyOp& op)
955  {
956  assert(mRoot);
957  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
958  const_cast<RootNodeType*>(mRoot)->modifyValueAndCache(xyz, op, *mParent);
959  }
960 
961  template<typename ModifyOp>
962  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
963  {
964  assert(mRoot);
965  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
966  const_cast<RootNodeType*>(mRoot)->modifyValueAndActiveStateAndCache(xyz, op, *mParent);
967  }
968 
969  void setValueOff(const Coord& xyz, const ValueType& value)
970  {
971  assert(mRoot);
972  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
973  const_cast<RootNodeType*>(mRoot)->setValueOffAndCache(xyz, value, *mParent);
974  }
975 
976  void setActiveState(const Coord& xyz, bool on)
977  {
978  assert(mRoot);
979  static_assert(!TreeCacheT::IsConstTree, "can't modify a const tree's values");
980  const_cast<RootNodeType*>(mRoot)->setActiveStateAndCache(xyz, on, *mParent);
981  }
982 
983 private:
984  CacheItem(const CacheItem&);
985  CacheItem& operator=(const CacheItem&);
986 
987  bool isHashed(const Coord&) const { return false; }
988 
989  TreeCacheT* mParent;
990  const RootNodeType* mRoot;
991 };// end of CacheItem specialized for RootNode
992 
993 
994 ////////////////////////////////////////
995 
996 
997 /// @brief ValueAccessor with no mutex and no node caching.
998 /// @details This specialization is provided mainly for benchmarking.
999 /// Accessors with caching will almost always be faster.
1000 template<typename _TreeType, bool IsSafe>
1001 class ValueAccessor0: public ValueAccessorBase<_TreeType, IsSafe>
1002 {
1003 public:
1004  using TreeType = _TreeType;
1005  using ValueType = typename TreeType::ValueType;
1006  using RootNodeT = typename TreeType::RootNodeType;
1007  using LeafNodeT = typename TreeType::LeafNodeType;
1009 
1011 
1012  ValueAccessor0(const ValueAccessor0& other): BaseT(other) {}
1013 
1014  /// Return the number of cache levels employed by this accessor.
1015  static Index numCacheLevels() { return 0; }
1016 
1018  {
1019  if (&other != this) this->BaseT::operator=(other);
1020  return *this;
1021  }
1022 
1023  ~ValueAccessor0() override = default;
1024 
1025  /// Return @c true if nodes along the path to the given voxel have been cached.
1026  bool isCached(const Coord&) const { return false; }
1027 
1028  /// Return the value of the voxel at the given coordinates.
1029  const ValueType& getValue(const Coord& xyz) const
1030  {
1031  assert(BaseT::mTree);
1032  return BaseT::mTree->getValue(xyz);
1033  }
1034 
1035  /// Return the active state of the voxel at the given coordinates.
1036  bool isValueOn(const Coord& xyz) const
1037  {
1038  assert(BaseT::mTree);
1039  return BaseT::mTree->isValueOn(xyz);
1040  }
1041 
1042  /// Return the active state and, in @a value, the value of the voxel at the given coordinates.
1043  bool probeValue(const Coord& xyz, ValueType& value) const
1044  {
1045  assert(BaseT::mTree);
1046  return BaseT::mTree->probeValue(xyz, value);
1047  }
1048 
1049  /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides,
1050  /// or -1 if (x, y, z) isn't explicitly represented in the tree (i.e., if it is
1051  /// implicitly a background voxel).
1052  int getValueDepth(const Coord& xyz) const
1053  {
1054  assert(BaseT::mTree);
1055  return BaseT::mTree->getValueDepth(xyz);
1056  }
1057 
1058  /// Return @c true if the value of voxel (x, y, z) resides at the leaf level
1059  /// of the tree, i.e., if it is not a tile value.
1060  bool isVoxel(const Coord& xyz) const
1061  {
1062  assert(BaseT::mTree);
1063  return BaseT::mTree->getValueDepth(xyz) == static_cast<int>(RootNodeT::LEVEL);
1064  }
1065 
1066  //@{
1067  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
1068  void setValue(const Coord& xyz, const ValueType& value)
1069  {
1070  assert(BaseT::mTree);
1071  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1072  BaseT::mTree->setValue(xyz, value);
1073  }
1074  void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); }
1075  //@}
1076 
1077  /// Set the value of the voxel at the given coordinate but don't change its active state.
1078  void setValueOnly(const Coord& xyz, const ValueType& value)
1079  {
1080  assert(BaseT::mTree);
1081  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1082  BaseT::mTree->setValueOnly(xyz, value);
1083  }
1084 
1085  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
1086  void setValueOff(const Coord& xyz, const ValueType& value)
1087  {
1088  assert(BaseT::mTree);
1089  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1090  BaseT::mTree->root().setValueOff(xyz, value);
1091  }
1092 
1093  /// @brief Apply a functor to the value of the voxel at the given coordinates
1094  /// and mark the voxel as active.
1095  /// @details See Tree::modifyValue() for details.
1096  template<typename ModifyOp>
1097  void modifyValue(const Coord& xyz, const ModifyOp& op)
1098  {
1099  assert(BaseT::mTree);
1100  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1101  BaseT::mTree->modifyValue(xyz, op);
1102  }
1103 
1104  /// @brief Apply a functor to the voxel at the given coordinates.
1105  /// @details See Tree::modifyValueAndActiveState() for details.
1106  template<typename ModifyOp>
1107  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
1108  {
1109  assert(BaseT::mTree);
1110  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1111  BaseT::mTree->modifyValueAndActiveState(xyz, op);
1112  }
1113 
1114  /// Set the active state of the voxel at the given coordinates but don't change its value.
1115  void setActiveState(const Coord& xyz, bool on = true)
1116  {
1117  assert(BaseT::mTree);
1118  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1119  BaseT::mTree->setActiveState(xyz, on);
1120  }
1121  /// Mark the voxel at the given coordinates as active but don't change its value.
1122  void setValueOn(const Coord& xyz) { this->setActiveState(xyz, true); }
1123  /// Mark the voxel at the given coordinates as inactive but don't change its value.
1124  void setValueOff(const Coord& xyz) { this->setActiveState(xyz, false); }
1125 
1126  /// Return the cached node of type @a NodeType. [Mainly for internal use]
1127  template<typename NodeT> NodeT* getNode() { return nullptr; }
1128 
1129  /// Cache the given node, which should lie along the path from the root node to
1130  /// the node containing voxel (x, y, z). [Mainly for internal use]
1131  template<typename NodeT> void insertNode(const Coord&, NodeT&) {}
1132 
1133  /// @brief Add the specified leaf to this tree, possibly creating a child branch
1134  /// in the process. If the leaf node already exists, replace it.
1135  void addLeaf(LeafNodeT* leaf)
1136  {
1137  assert(BaseT::mTree);
1138  static_assert(!BaseT::IsConstTree, "can't add a node to a const tree");
1139  BaseT::mTree->root().addLeaf(leaf);
1140  }
1141 
1142  /// @brief Add a tile at the specified tree level that contains voxel (x, y, z),
1143  /// possibly deleting existing nodes or creating new nodes in the process.
1144  void addTile(Index level, const Coord& xyz, const ValueType& value, bool state)
1145  {
1146  assert(BaseT::mTree);
1147  static_assert(!BaseT::IsConstTree, "can't add a tile to a const tree");
1148  BaseT::mTree->root().addTile(level, xyz, value, state);
1149  }
1150 
1151  /// If a node of the given type exists in the cache, remove it, so that
1152  /// isCached(xyz) returns @c false for any voxel (x, y, z) contained in
1153  /// that node. [Mainly for internal use]
1154  template<typename NodeT> void eraseNode() {}
1155 
1156  LeafNodeT* touchLeaf(const Coord& xyz)
1157  {
1158  assert(BaseT::mTree);
1159  static_assert(!BaseT::IsConstTree, "can't get a non-const node from a const tree");
1160  return BaseT::mTree->touchLeaf(xyz);
1161  }
1162 
1163  template<typename NodeT>
1164  NodeT* probeNode(const Coord& xyz)
1165  {
1166  assert(BaseT::mTree);
1167  static_assert(!BaseT::IsConstTree, "can't get a non-const node from a const tree");
1168  return BaseT::mTree->template probeNode<NodeT>(xyz);
1169  }
1170 
1171  template<typename NodeT>
1172  const NodeT* probeConstNode(const Coord& xyz) const
1173  {
1174  assert(BaseT::mTree);
1175  return BaseT::mTree->template probeConstNode<NodeT>(xyz);
1176  }
1177 
1178  LeafNodeT* probeLeaf(const Coord& xyz)
1179  {
1180  return this->template probeNode<LeafNodeT>(xyz);
1181  }
1182 
1183  const LeafNodeT* probeConstLeaf(const Coord& xyz) const
1184  {
1185  return this->template probeConstNode<LeafNodeT>(xyz);
1186  }
1187 
1188  const LeafNodeT* probeLeaf(const Coord& xyz) const
1189  {
1190  return this->probeConstLeaf(xyz);
1191  }
1192 
1193  /// Remove all nodes from this cache, then reinsert the root node.
1194  void clear() override {}
1195 
1196 private:
1197  // Allow trees to deregister themselves.
1198  template<typename> friend class Tree;
1199 
1200  /// Prevent this accessor from calling Tree::releaseCache() on a tree that
1201  /// no longer exists. (Called by mTree when it is destroyed.)
1202  void release() override { this->BaseT::release(); }
1203 
1204 }; // ValueAccessor0
1205 
1206 
1207 /// @brief Value accessor with one level of node caching.
1208 /// @details The node cache level is specified by L0 with the default value 0
1209 /// (defined in the forward declaration) corresponding to a LeafNode.
1210 ///
1211 /// @note This class is for experts only and should rarely be used
1212 /// directly. Instead use ValueAccessor with its default template arguments.
1213 template<typename _TreeType, bool IsSafe, Index L0>
1214 class ValueAccessor1 : public ValueAccessorBase<_TreeType, IsSafe>
1215 {
1216 public:
1217  static_assert(_TreeType::DEPTH >= 2, "cache size exceeds tree depth");
1218  static_assert(L0 < _TreeType::RootNodeType::LEVEL, "invalid cache level");
1219  using TreeType = _TreeType;
1220  using ValueType = typename TreeType::ValueType;
1221  using RootNodeT = typename TreeType::RootNodeType;
1222  using LeafNodeT = typename TreeType::LeafNodeType;
1224  using InvTreeT = typename RootNodeT::NodeChainType;
1225  using NodeT0 = typename InvTreeT::template Get<L0>;
1226 
1227  /// Constructor from a tree
1228  ValueAccessor1(TreeType& tree) : BaseT(tree), mKey0(Coord::max()), mNode0(nullptr)
1229  {
1230  }
1231 
1232  /// Copy constructor
1233  ValueAccessor1(const ValueAccessor1& other) : BaseT(other) { this->copy(other); }
1234 
1235  /// Return the number of cache levels employed by this ValueAccessor
1236  static Index numCacheLevels() { return 1; }
1237 
1238  /// Assignment operator
1240  {
1241  if (&other != this) {
1242  this->BaseT::operator=(other);
1243  this->copy(other);
1244  }
1245  return *this;
1246  }
1247 
1248  /// Virtual destructor
1249  ~ValueAccessor1() override = default;
1250 
1251  /// Return @c true if any of the nodes along the path to the given
1252  /// voxel have been cached.
1253  bool isCached(const Coord& xyz) const
1254  {
1255  assert(BaseT::mTree);
1256  return this->isHashed(xyz);
1257  }
1258 
1259  /// Return the value of the voxel at the given coordinates.
1260  const ValueType& getValue(const Coord& xyz) const
1261  {
1262  assert(BaseT::mTree);
1263  if (this->isHashed(xyz)) {
1264  assert(mNode0);
1265  return mNode0->getValueAndCache(xyz, this->self());
1266  }
1267  return BaseT::mTree->root().getValueAndCache(xyz, this->self());
1268  }
1269 
1270  /// Return the active state of the voxel at the given coordinates.
1271  bool isValueOn(const Coord& xyz) const
1272  {
1273  assert(BaseT::mTree);
1274  if (this->isHashed(xyz)) {
1275  assert(mNode0);
1276  return mNode0->isValueOnAndCache(xyz, this->self());
1277  }
1278  return BaseT::mTree->root().isValueOnAndCache(xyz, this->self());
1279  }
1280 
1281  /// Return the active state of the voxel as well as its value
1282  bool probeValue(const Coord& xyz, ValueType& value) const
1283  {
1284  assert(BaseT::mTree);
1285  if (this->isHashed(xyz)) {
1286  assert(mNode0);
1287  return mNode0->probeValueAndCache(xyz, value, this->self());
1288  }
1289  return BaseT::mTree->root().probeValueAndCache(xyz, value, this->self());
1290  }
1291 
1292  /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides,
1293  /// or -1 if (x, y, z) isn't explicitly represented in the tree (i.e., if it is
1294  /// implicitly a background voxel).
1295  int getValueDepth(const Coord& xyz) const
1296  {
1297  assert(BaseT::mTree);
1298  if (this->isHashed(xyz)) {
1299  assert(mNode0);
1300  return RootNodeT::LEVEL - mNode0->getValueLevelAndCache(xyz, this->self());
1301  }
1302  return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self());
1303  }
1304 
1305  /// Return @c true if the value of voxel (x, y, z) resides at the leaf level
1306  /// of the tree, i.e., if it is not a tile value.
1307  bool isVoxel(const Coord& xyz) const
1308  {
1309  assert(BaseT::mTree);
1310  if (this->isHashed(xyz)) {
1311  assert(mNode0);
1312  return mNode0->getValueLevelAndCache(xyz, this->self()) == 0;
1313  }
1314  return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self()) ==
1315  static_cast<int>(RootNodeT::LEVEL);
1316  }
1317 
1318  //@{
1319  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
1320  void setValue(const Coord& xyz, const ValueType& value)
1321  {
1322  assert(BaseT::mTree);
1323  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1324  if (this->isHashed(xyz)) {
1325  assert(mNode0);
1326  const_cast<NodeT0*>(mNode0)->setValueAndCache(xyz, value, *this);
1327  } else {
1328  BaseT::mTree->root().setValueAndCache(xyz, value, *this);
1329  }
1330  }
1331  void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); }
1332  //@}
1333 
1334  /// Set the value of the voxel at the given coordinate but preserves its active state.
1335  void setValueOnly(const Coord& xyz, const ValueType& value)
1336  {
1337  assert(BaseT::mTree);
1338  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1339  if (this->isHashed(xyz)) {
1340  assert(mNode0);
1341  const_cast<NodeT0*>(mNode0)->setValueOnlyAndCache(xyz, value, *this);
1342  } else {
1343  BaseT::mTree->root().setValueOnlyAndCache(xyz, value, *this);
1344  }
1345  }
1346 
1347  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
1348  void setValueOff(const Coord& xyz, const ValueType& value)
1349  {
1350  assert(BaseT::mTree);
1351  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1352  if (this->isHashed(xyz)) {
1353  assert(mNode0);
1354  const_cast<NodeT0*>(mNode0)->setValueOffAndCache(xyz, value, *this);
1355  } else {
1356  BaseT::mTree->root().setValueOffAndCache(xyz, value, *this);
1357  }
1358  }
1359 
1360  /// @brief Apply a functor to the value of the voxel at the given coordinates
1361  /// and mark the voxel as active.
1362  /// @details See Tree::modifyValue() for details.
1363  template<typename ModifyOp>
1364  void modifyValue(const Coord& xyz, const ModifyOp& op)
1365  {
1366  assert(BaseT::mTree);
1367  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1368  if (this->isHashed(xyz)) {
1369  assert(mNode0);
1370  const_cast<NodeT0*>(mNode0)->modifyValueAndCache(xyz, op, *this);
1371  } else {
1372  BaseT::mTree->root().modifyValueAndCache(xyz, op, *this);
1373  }
1374  }
1375 
1376  /// @brief Apply a functor to the voxel at the given coordinates.
1377  /// @details See Tree::modifyValueAndActiveState() for details.
1378  template<typename ModifyOp>
1379  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
1380  {
1381  assert(BaseT::mTree);
1382  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1383  if (this->isHashed(xyz)) {
1384  assert(mNode0);
1385  const_cast<NodeT0*>(mNode0)->modifyValueAndActiveStateAndCache(xyz, op, *this);
1386  } else {
1387  BaseT::mTree->root().modifyValueAndActiveStateAndCache(xyz, op, *this);
1388  }
1389  }
1390 
1391  /// Set the active state of the voxel at the given coordinates but don't change its value.
1392  void setActiveState(const Coord& xyz, bool on = true)
1393  {
1394  assert(BaseT::mTree);
1395  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1396  if (this->isHashed(xyz)) {
1397  assert(mNode0);
1398  const_cast<NodeT0*>(mNode0)->setActiveStateAndCache(xyz, on, *this);
1399  } else {
1400  BaseT::mTree->root().setActiveStateAndCache(xyz, on, *this);
1401  }
1402  }
1403  /// Mark the voxel at the given coordinates as active but don't change its value.
1404  void setValueOn(const Coord& xyz) { this->setActiveState(xyz, true); }
1405  /// Mark the voxel at the given coordinates as inactive but don't change its value.
1406  void setValueOff(const Coord& xyz) { this->setActiveState(xyz, false); }
1407 
1408  /// Return the cached node of type @a NodeType. [Mainly for internal use]
1409  template<typename NodeT>
1410  NodeT* getNode()
1411  {
1412  const NodeT* node = nullptr;
1413  this->getNode(node);
1414  return const_cast<NodeT*>(node);
1415  }
1416 
1417  /// Cache the given node, which should lie along the path from the root node to
1418  /// the node containing voxel (x, y, z). [Mainly for internal use]
1419  template<typename NodeT>
1420  void insertNode(const Coord& xyz, NodeT& node) { this->insert(xyz, &node); }
1421 
1422  /// If a node of the given type exists in the cache, remove it, so that
1423  /// isCached(xyz) returns @c false for any voxel (x, y, z) contained in
1424  /// that node. [Mainly for internal use]
1425  template<typename NodeT>
1426  void eraseNode()
1427  {
1428  const NodeT* node = nullptr;
1429  this->eraseNode(node);
1430  }
1431 
1432  /// @brief Add the specified leaf to this tree, possibly creating a child branch
1433  /// in the process. If the leaf node already exists, replace it.
1434  void addLeaf(LeafNodeT* leaf)
1435  {
1436  assert(BaseT::mTree);
1437  static_assert(!BaseT::IsConstTree, "can't add a node to a const tree");
1438  BaseT::mTree->root().addLeaf(leaf);
1439  }
1440 
1441  /// @brief Add a tile at the specified tree level that contains voxel (x, y, z),
1442  /// possibly deleting existing nodes or creating new nodes in the process.
1443  void addTile(Index level, const Coord& xyz, const ValueType& value, bool state)
1444  {
1445  assert(BaseT::mTree);
1446  static_assert(!BaseT::IsConstTree, "can't add a tile to a const tree");
1447  BaseT::mTree->root().addTile(level, xyz, value, state);
1448  }
1449 
1450  /// @brief @return the leaf node that contains voxel (x, y, z) and
1451  /// if it doesn't exist, create it, but preserve the values and
1452  /// active states of all voxels.
1453  ///
1454  /// Use this method to preallocate a static tree topology over which to
1455  /// safely perform multithreaded processing.
1456  LeafNodeT* touchLeaf(const Coord& xyz)
1457  {
1458  assert(BaseT::mTree);
1459  static_assert(!BaseT::IsConstTree, "can't get a non-const node from a const tree");
1460  if (this->isHashed(xyz)) {
1461  assert(mNode0);
1462  return const_cast<NodeT0*>(mNode0)->touchLeafAndCache(xyz, *this);
1463  }
1464  return BaseT::mTree->root().touchLeafAndCache(xyz, *this);
1465  }
1466 
1467  /// @brief @return a pointer to the node of the specified type that contains
1468  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
1469  template<typename NodeT>
1470  NodeT* probeNode(const Coord& xyz)
1471  {
1472  assert(BaseT::mTree);
1473  static_assert(!BaseT::IsConstTree, "can't get a non-const node from a const tree");
1476  if (this->isHashed(xyz)) {
1477  assert(mNode0);
1478  return reinterpret_cast<NodeT*>(const_cast<NodeT0*>(mNode0));
1479  }
1480  return BaseT::mTree->root().template probeNodeAndCache<NodeT>(xyz, *this);
1481  }
1482  return nullptr;
1484  }
1485  LeafNodeT* probeLeaf(const Coord& xyz)
1486  {
1487  return this->template probeNode<LeafNodeT>(xyz);
1488  }
1489 
1490  /// @brief @return a const pointer to the nodeof the specified type that contains
1491  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
1492  template<typename NodeT>
1493  const NodeT* probeConstNode(const Coord& xyz) const
1494  {
1495  assert(BaseT::mTree);
1498  if (this->isHashed(xyz)) {
1499  assert(mNode0);
1500  return reinterpret_cast<const NodeT*>(mNode0);
1501  }
1502  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
1503  }
1504  return nullptr;
1506  }
1507  const LeafNodeT* probeConstLeaf(const Coord& xyz) const
1508  {
1509  return this->template probeConstNode<LeafNodeT>(xyz);
1510  }
1511  const LeafNodeT* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); }
1512 
1513  /// Remove all the cached nodes and invalidate the corresponding hash-keys.
1514  void clear() override
1515  {
1516  mKey0 = Coord::max();
1517  mNode0 = nullptr;
1518  }
1519 
1520 private:
1521  // Allow nodes to insert themselves into the cache.
1522  template<typename> friend class RootNode;
1523  template<typename, Index> friend class InternalNode;
1524  template<typename, Index> friend class LeafNode;
1525  // Allow trees to deregister themselves.
1526  template<typename> friend class Tree;
1527 
1528  // This private method is merely for convenience.
1529  inline ValueAccessor1& self() const { return const_cast<ValueAccessor1&>(*this); }
1530 
1531  void getNode(const NodeT0*& node) { node = mNode0; }
1532  void getNode(const RootNodeT*& node)
1533  {
1534  node = (BaseT::mTree ? &BaseT::mTree->root() : nullptr);
1535  }
1536  template<typename OtherNodeType> void getNode(const OtherNodeType*& node) { node = nullptr; }
1537  void eraseNode(const NodeT0*) { mKey0 = Coord::max(); mNode0 = nullptr; }
1538  template<typename OtherNodeType> void eraseNode(const OtherNodeType*) {}
1539 
1540  /// Private copy method
1541  inline void copy(const ValueAccessor1& other)
1542  {
1543  mKey0 = other.mKey0;
1544  mNode0 = other.mNode0;
1545  }
1546 
1547  /// Prevent this accessor from calling Tree::releaseCache() on a tree that
1548  /// no longer exists. (Called by mTree when it is destroyed.)
1549  void release() override
1550  {
1551  this->BaseT::release();
1552  this->clear();
1553  }
1554  /// Cache the given node, which should lie along the path from the root node to
1555  /// the node containing voxel (x, y, z).
1556  /// @note This operation is not mutex-protected and is intended to be called
1557  /// only by nodes and only in the context of a getValue() or setValue() call.
1558  inline void insert(const Coord& xyz, const NodeT0* node)
1559  {
1560  assert(node);
1561  mKey0 = xyz & ~(NodeT0::DIM-1);
1562  mNode0 = node;
1563  }
1564 
1565  /// No-op in case a tree traversal attemps to insert a node that
1566  /// is not cached by the ValueAccessor
1567  template<typename OtherNodeType> inline void insert(const Coord&, const OtherNodeType*) {}
1568 
1569  inline bool isHashed(const Coord& xyz) const
1570  {
1571  return (xyz[0] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[0]
1572  && (xyz[1] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[1]
1573  && (xyz[2] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[2];
1574  }
1575  mutable Coord mKey0;
1576  mutable const NodeT0* mNode0;
1577 }; // ValueAccessor1
1578 
1579 
1580 /// @brief Value accessor with two levels of node caching.
1581 /// @details The node cache levels are specified by L0 and L1
1582 /// with the default values 0 and 1 (defined in the forward declaration)
1583 /// corresponding to a LeafNode and its parent InternalNode.
1584 ///
1585 /// @note This class is for experts only and should rarely be used directly.
1586 /// Instead use ValueAccessor with its default template arguments.
1587 template<typename _TreeType, bool IsSafe, Index L0, Index L1>
1588 class ValueAccessor2 : public ValueAccessorBase<_TreeType, IsSafe>
1589 {
1590 public:
1591  static_assert(_TreeType::DEPTH >= 3, "cache size exceeds tree depth");
1592  static_assert(L0 < L1, "invalid cache level");
1593  static_assert(L1 < _TreeType::RootNodeType::LEVEL, "invalid cache level");
1594 
1595  using TreeType = _TreeType;
1596  using ValueType = typename TreeType::ValueType;
1597  using RootNodeT = typename TreeType::RootNodeType;
1598  using LeafNodeT = typename TreeType::LeafNodeType;
1600  using InvTreeT = typename RootNodeT::NodeChainType;
1601  using NodeT0 = typename InvTreeT::template Get<L0>;
1602  using NodeT1 = typename InvTreeT::template Get<L1>;
1603 
1604  /// Constructor from a tree
1606  mKey0(Coord::max()), mNode0(nullptr),
1607  mKey1(Coord::max()), mNode1(nullptr) {}
1608 
1609  /// Copy constructor
1610  ValueAccessor2(const ValueAccessor2& other) : BaseT(other) { this->copy(other); }
1611 
1612  /// Return the number of cache levels employed by this ValueAccessor
1613  static Index numCacheLevels() { return 2; }
1614 
1615  /// Assignment operator
1617  {
1618  if (&other != this) {
1619  this->BaseT::operator=(other);
1620  this->copy(other);
1621  }
1622  return *this;
1623  }
1624 
1625  /// Virtual destructor
1626  ~ValueAccessor2() override = default;
1627 
1628  /// Return @c true if any of the nodes along the path to the given
1629  /// voxel have been cached.
1630  bool isCached(const Coord& xyz) const
1631  {
1632  assert(BaseT::mTree);
1633  return this->isHashed1(xyz) || this->isHashed0(xyz);
1634  }
1635 
1636  /// Return the value of the voxel at the given coordinates.
1637  const ValueType& getValue(const Coord& xyz) const
1638  {
1639  assert(BaseT::mTree);
1640  if (this->isHashed0(xyz)) {
1641  assert(mNode0);
1642  return mNode0->getValueAndCache(xyz, this->self());
1643  } else if (this->isHashed1(xyz)) {
1644  assert(mNode1);
1645  return mNode1->getValueAndCache(xyz, this->self());
1646  }
1647  return BaseT::mTree->root().getValueAndCache(xyz, this->self());
1648  }
1649 
1650  /// Return the active state of the voxel at the given coordinates.
1651  bool isValueOn(const Coord& xyz) const
1652  {
1653  assert(BaseT::mTree);
1654  if (this->isHashed0(xyz)) {
1655  assert(mNode0);
1656  return mNode0->isValueOnAndCache(xyz, this->self());
1657  } else if (this->isHashed1(xyz)) {
1658  assert(mNode1);
1659  return mNode1->isValueOnAndCache(xyz, this->self());
1660  }
1661  return BaseT::mTree->root().isValueOnAndCache(xyz, this->self());
1662  }
1663 
1664  /// Return the active state of the voxel as well as its value
1665  bool probeValue(const Coord& xyz, ValueType& value) const
1666  {
1667  assert(BaseT::mTree);
1668  if (this->isHashed0(xyz)) {
1669  assert(mNode0);
1670  return mNode0->probeValueAndCache(xyz, value, this->self());
1671  } else if (this->isHashed1(xyz)) {
1672  assert(mNode1);
1673  return mNode1->probeValueAndCache(xyz, value, this->self());
1674  }
1675  return BaseT::mTree->root().probeValueAndCache(xyz, value, this->self());
1676  }
1677 
1678  /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides,
1679  /// or -1 if (x, y, z) isn't explicitly represented in the tree (i.e., if it is
1680  /// implicitly a background voxel).
1681  int getValueDepth(const Coord& xyz) const
1682  {
1683  assert(BaseT::mTree);
1684  if (this->isHashed0(xyz)) {
1685  assert(mNode0);
1686  return RootNodeT::LEVEL - mNode0->getValueLevelAndCache(xyz, this->self());
1687  } else if (this->isHashed1(xyz)) {
1688  assert(mNode1);
1689  return RootNodeT::LEVEL - mNode1->getValueLevelAndCache(xyz, this->self());
1690  }
1691  return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self());
1692  }
1693 
1694  /// Return @c true if the value of voxel (x, y, z) resides at the leaf level
1695  /// of the tree, i.e., if it is not a tile value.
1696  bool isVoxel(const Coord& xyz) const
1697  {
1698  assert(BaseT::mTree);
1699  if (this->isHashed0(xyz)) {
1700  assert(mNode0);
1701  return mNode0->getValueLevelAndCache(xyz, this->self())==0;
1702  } else if (this->isHashed1(xyz)) {
1703  assert(mNode1);
1704  return mNode1->getValueLevelAndCache(xyz, this->self())==0;
1705  }
1706  return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self()) ==
1707  static_cast<int>(RootNodeT::LEVEL);
1708  }
1709 
1710  //@{
1711  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
1712  void setValue(const Coord& xyz, const ValueType& value)
1713  {
1714  assert(BaseT::mTree);
1715  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1716  if (this->isHashed0(xyz)) {
1717  assert(mNode0);
1718  const_cast<NodeT0*>(mNode0)->setValueAndCache(xyz, value, *this);
1719  } else if (this->isHashed1(xyz)) {
1720  assert(mNode1);
1721  const_cast<NodeT1*>(mNode1)->setValueAndCache(xyz, value, *this);
1722  } else {
1723  BaseT::mTree->root().setValueAndCache(xyz, value, *this);
1724  }
1725  }
1726  void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); }
1727  //@}
1728 
1729  /// Set the value of the voxel at the given coordinate but preserves its active state.
1730  void setValueOnly(const Coord& xyz, const ValueType& value)
1731  {
1732  assert(BaseT::mTree);
1733  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1734  if (this->isHashed0(xyz)) {
1735  assert(mNode0);
1736  const_cast<NodeT0*>(mNode0)->setValueOnlyAndCache(xyz, value, *this);
1737  } else if (this->isHashed1(xyz)) {
1738  assert(mNode1);
1739  const_cast<NodeT1*>(mNode1)->setValueOnlyAndCache(xyz, value, *this);
1740  } else {
1741  BaseT::mTree->root().setValueOnlyAndCache(xyz, value, *this);
1742  }
1743  }
1744 
1745  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
1746  void setValueOff(const Coord& xyz, const ValueType& value)
1747  {
1748  assert(BaseT::mTree);
1749  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1750  if (this->isHashed0(xyz)) {
1751  assert(mNode0);
1752  const_cast<NodeT0*>(mNode0)->setValueOffAndCache(xyz, value, *this);
1753  } else if (this->isHashed1(xyz)) {
1754  assert(mNode1);
1755  const_cast<NodeT1*>(mNode1)->setValueOffAndCache(xyz, value, *this);
1756  } else {
1757  BaseT::mTree->root().setValueOffAndCache(xyz, value, *this);
1758  }
1759  }
1760 
1761  /// @brief Apply a functor to the value of the voxel at the given coordinates
1762  /// and mark the voxel as active.
1763  /// @details See Tree::modifyValue() for details.
1764  template<typename ModifyOp>
1765  void modifyValue(const Coord& xyz, const ModifyOp& op)
1766  {
1767  assert(BaseT::mTree);
1768  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1769  if (this->isHashed0(xyz)) {
1770  assert(mNode0);
1771  const_cast<NodeT0*>(mNode0)->modifyValueAndCache(xyz, op, *this);
1772  } else if (this->isHashed1(xyz)) {
1773  assert(mNode1);
1774  const_cast<NodeT1*>(mNode1)->modifyValueAndCache(xyz, op, *this);
1775  } else {
1776  BaseT::mTree->root().modifyValueAndCache(xyz, op, *this);
1777  }
1778  }
1779 
1780  /// @brief Apply a functor to the voxel at the given coordinates.
1781  /// @details See Tree::modifyValueAndActiveState() for details.
1782  template<typename ModifyOp>
1783  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
1784  {
1785  assert(BaseT::mTree);
1786  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1787  if (this->isHashed0(xyz)) {
1788  assert(mNode0);
1789  const_cast<NodeT0*>(mNode0)->modifyValueAndActiveStateAndCache(xyz, op, *this);
1790  } else if (this->isHashed1(xyz)) {
1791  assert(mNode1);
1792  const_cast<NodeT1*>(mNode1)->modifyValueAndActiveStateAndCache(xyz, op, *this);
1793  } else {
1794  BaseT::mTree->root().modifyValueAndActiveStateAndCache(xyz, op, *this);
1795  }
1796  }
1797 
1798  /// Set the active state of the voxel at the given coordinates without changing its value.
1799  void setActiveState(const Coord& xyz, bool on = true)
1800  {
1801  assert(BaseT::mTree);
1802  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
1803  if (this->isHashed0(xyz)) {
1804  assert(mNode0);
1805  const_cast<NodeT0*>(mNode0)->setActiveStateAndCache(xyz, on, *this);
1806  } else if (this->isHashed1(xyz)) {
1807  assert(mNode1);
1808  const_cast<NodeT1*>(mNode1)->setActiveStateAndCache(xyz, on, *this);
1809  } else {
1810  BaseT::mTree->root().setActiveStateAndCache(xyz, on, *this);
1811  }
1812  }
1813  /// Mark the voxel at the given coordinates as active without changing its value.
1814  void setValueOn(const Coord& xyz) { this->setActiveState(xyz, true); }
1815  /// Mark the voxel at the given coordinates as inactive without changing its value.
1816  void setValueOff(const Coord& xyz) { this->setActiveState(xyz, false); }
1817 
1818  /// Return the cached node of type @a NodeType. [Mainly for internal use]
1819  template<typename NodeT>
1820  NodeT* getNode()
1821  {
1822  const NodeT* node = nullptr;
1823  this->getNode(node);
1824  return const_cast<NodeT*>(node);
1825  }
1826 
1827  /// Cache the given node, which should lie along the path from the root node to
1828  /// the node containing voxel (x, y, z). [Mainly for internal use]
1829  template<typename NodeT>
1830  void insertNode(const Coord& xyz, NodeT& node) { this->insert(xyz, &node); }
1831 
1832  /// If a node of the given type exists in the cache, remove it, so that
1833  /// isCached(xyz) returns @c false for any voxel (x, y, z) contained in
1834  /// that node. [Mainly for internal use]
1835  template<typename NodeT>
1836  void eraseNode()
1837  {
1838  const NodeT* node = nullptr;
1839  this->eraseNode(node);
1840  }
1841 
1842  /// @brief Add the specified leaf to this tree, possibly creating a child branch
1843  /// in the process. If the leaf node already exists, replace it.
1844  void addLeaf(LeafNodeT* leaf)
1845  {
1846  assert(BaseT::mTree);
1847  static_assert(!BaseT::IsConstTree, "can't add a node to a const tree");
1848  if (this->isHashed1(leaf->origin())) {
1849  assert(mNode1);
1850  return const_cast<NodeT1*>(mNode1)->addLeafAndCache(leaf, *this);
1851  }
1852  BaseT::mTree->root().addLeafAndCache(leaf, *this);
1853  }
1854 
1855  /// @brief Add a tile at the specified tree level that contains voxel (x, y, z),
1856  /// possibly deleting existing nodes or creating new nodes in the process.
1857  void addTile(Index level, const Coord& xyz, const ValueType& value, bool state)
1858  {
1859  assert(BaseT::mTree);
1860  static_assert(!BaseT::IsConstTree, "can't add a tile to a const tree");
1861  if (this->isHashed1(xyz)) {
1862  assert(mNode1);
1863  return const_cast<NodeT1*>(mNode1)->addTileAndCache(level, xyz, value, state, *this);
1864  }
1865  BaseT::mTree->root().addTileAndCache(level, xyz, value, state, *this);
1866  }
1867 
1868  /// @brief @return the leaf node that contains voxel (x, y, z) and
1869  /// if it doesn't exist, create it, but preserve the values and
1870  /// active states of all voxels.
1871  ///
1872  /// Use this method to preallocate a static tree topology over which to
1873  /// safely perform multithreaded processing.
1874  LeafNodeT* touchLeaf(const Coord& xyz)
1875  {
1876  assert(BaseT::mTree);
1877  static_assert(!BaseT::IsConstTree, "can't get a non-const node from a const tree");
1878  if (this->isHashed0(xyz)) {
1879  assert(mNode0);
1880  return const_cast<NodeT0*>(mNode0)->touchLeafAndCache(xyz, *this);
1881  } else if (this->isHashed1(xyz)) {
1882  assert(mNode1);
1883  return const_cast<NodeT1*>(mNode1)->touchLeafAndCache(xyz, *this);
1884  }
1885  return BaseT::mTree->root().touchLeafAndCache(xyz, *this);
1886  }
1887  /// @brief @return a pointer to the node of the specified type that contains
1888  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
1889  template<typename NodeT>
1890  NodeT* probeNode(const Coord& xyz)
1891  {
1892  assert(BaseT::mTree);
1893  static_assert(!BaseT::IsConstTree, "can't get a non-const node from a const tree");
1896  if (this->isHashed0(xyz)) {
1897  assert(mNode0);
1898  return reinterpret_cast<NodeT*>(const_cast<NodeT0*>(mNode0));
1899  } else if (this->isHashed1(xyz)) {
1900  assert(mNode1);
1901  return const_cast<NodeT1*>(mNode1)->template probeNodeAndCache<NodeT>(xyz, *this);
1902  }
1903  return BaseT::mTree->root().template probeNodeAndCache<NodeT>(xyz, *this);
1904  } else if ((std::is_same<NodeT, NodeT1>::value)) {
1905  if (this->isHashed1(xyz)) {
1906  assert(mNode1);
1907  return reinterpret_cast<NodeT*>(const_cast<NodeT1*>(mNode1));
1908  }
1909  return BaseT::mTree->root().template probeNodeAndCache<NodeT>(xyz, *this);
1910  }
1911  return nullptr;
1913  }
1914  /// @brief @return a pointer to the leaf node that contains
1915  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
1916  LeafNodeT* probeLeaf(const Coord& xyz) { return this->template probeNode<LeafNodeT>(xyz); }
1917 
1918  /// @brief @return a const pointer to the node of the specified type that contains
1919  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
1920  template<typename NodeT>
1921  const NodeT* probeConstLeaf(const Coord& xyz) const
1922  {
1925  if (this->isHashed0(xyz)) {
1926  assert(mNode0);
1927  return reinterpret_cast<const NodeT*>(mNode0);
1928  } else if (this->isHashed1(xyz)) {
1929  assert(mNode1);
1930  return mNode1->template probeConstNodeAndCache<NodeT>(xyz, this->self());
1931  }
1932  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
1933  } else if ((std::is_same<NodeT, NodeT1>::value)) {
1934  if (this->isHashed1(xyz)) {
1935  assert(mNode1);
1936  return reinterpret_cast<const NodeT*>(mNode1);
1937  }
1938  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
1939  }
1940  return nullptr;
1942  }
1943  /// @brief @return a const pointer to the leaf node that contains
1944  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
1945  const LeafNodeT* probeConstLeaf(const Coord& xyz) const
1946  {
1947  return this->template probeConstNode<LeafNodeT>(xyz);
1948  }
1949  const LeafNodeT* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); }
1950 
1951  /// @brief @return a const pointer to the node of the specified type that contains
1952  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
1953  template<typename NodeT>
1954  const NodeT* probeConstNode(const Coord& xyz) const
1955  {
1956  assert(BaseT::mTree);
1959  if (this->isHashed0(xyz)) {
1960  assert(mNode0);
1961  return reinterpret_cast<const NodeT*>(mNode0);
1962  } else if (this->isHashed1(xyz)) {
1963  assert(mNode1);
1964  return mNode1->template probeConstNodeAndCache<NodeT>(xyz, this->self());
1965  }
1966  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
1967  } else if ((std::is_same<NodeT, NodeT1>::value)) {
1968  if (this->isHashed1(xyz)) {
1969  assert(mNode1);
1970  return reinterpret_cast<const NodeT*>(mNode1);
1971  }
1972  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
1973  }
1974  return nullptr;
1976  }
1977 
1978  /// Remove all the cached nodes and invalidate the corresponding hash-keys.
1979  void clear() override
1980  {
1981  mKey0 = Coord::max();
1982  mNode0 = nullptr;
1983  mKey1 = Coord::max();
1984  mNode1 = nullptr;
1985  }
1986 
1987 private:
1988  // Allow nodes to insert themselves into the cache.
1989  template<typename> friend class RootNode;
1990  template<typename, Index> friend class InternalNode;
1991  template<typename, Index> friend class LeafNode;
1992  // Allow trees to deregister themselves.
1993  template<typename> friend class Tree;
1994 
1995  // This private method is merely for convenience.
1996  inline ValueAccessor2& self() const { return const_cast<ValueAccessor2&>(*this); }
1997 
1998  void getNode(const NodeT0*& node) { node = mNode0; }
1999  void getNode(const NodeT1*& node) { node = mNode1; }
2000  void getNode(const RootNodeT*& node)
2001  {
2002  node = (BaseT::mTree ? &BaseT::mTree->root() : nullptr);
2003  }
2004  template<typename OtherNodeType> void getNode(const OtherNodeType*& node) { node = nullptr; }
2005 
2006  void eraseNode(const NodeT0*) { mKey0 = Coord::max(); mNode0 = nullptr; }
2007  void eraseNode(const NodeT1*) { mKey1 = Coord::max(); mNode1 = nullptr; }
2008  template<typename OtherNodeType> void eraseNode(const OtherNodeType*) {}
2009 
2010  /// Private copy method
2011  inline void copy(const ValueAccessor2& other)
2012  {
2013  mKey0 = other.mKey0;
2014  mNode0 = other.mNode0;
2015  mKey1 = other.mKey1;
2016  mNode1 = other.mNode1;
2017  }
2018 
2019  /// Prevent this accessor from calling Tree::releaseCache() on a tree that
2020  /// no longer exists. (Called by mTree when it is destroyed.)
2021  void release() override
2022  {
2023  this->BaseT::release();
2024  this->clear();
2025  }
2026 
2027  /// Cache the given node, which should lie along the path from the root node to
2028  /// the node containing voxel (x, y, z).
2029  /// @note This operation is not mutex-protected and is intended to be called
2030  /// only by nodes and only in the context of a getValue() or setValue() call.
2031  inline void insert(const Coord& xyz, const NodeT0* node)
2032  {
2033  assert(node);
2034  mKey0 = xyz & ~(NodeT0::DIM-1);
2035  mNode0 = node;
2036  }
2037  inline void insert(const Coord& xyz, const NodeT1* node)
2038  {
2039  assert(node);
2040  mKey1 = xyz & ~(NodeT1::DIM-1);
2041  mNode1 = node;
2042  }
2043  /// No-op in case a tree traversal attemps to insert a node that
2044  /// is not cached by the ValueAccessor
2045  template<typename NodeT> inline void insert(const Coord&, const NodeT*) {}
2046 
2047  inline bool isHashed0(const Coord& xyz) const
2048  {
2049  return (xyz[0] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[0]
2050  && (xyz[1] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[1]
2051  && (xyz[2] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[2];
2052  }
2053  inline bool isHashed1(const Coord& xyz) const
2054  {
2055  return (xyz[0] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[0]
2056  && (xyz[1] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[1]
2057  && (xyz[2] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[2];
2058  }
2059  mutable Coord mKey0;
2060  mutable const NodeT0* mNode0;
2061  mutable Coord mKey1;
2062  mutable const NodeT1* mNode1;
2063 }; // ValueAccessor2
2064 
2065 
2066 /// @brief Value accessor with three levels of node caching.
2067 /// @details The node cache levels are specified by L0, L1, and L2
2068 /// with the default values 0, 1 and 2 (defined in the forward declaration)
2069 /// corresponding to a LeafNode, its parent InternalNode, and its parent InternalNode.
2070 /// Since the default configuration of all typed trees and grids, e.g.,
2071 /// FloatTree or FloatGrid, has a depth of four, this value accessor is the one
2072 /// used by default.
2073 ///
2074 /// @note This class is for experts only and should rarely be used
2075 /// directly. Instead use ValueAccessor with its default template arguments
2076 template<typename _TreeType, bool IsSafe, Index L0, Index L1, Index L2>
2077 class ValueAccessor3 : public ValueAccessorBase<_TreeType, IsSafe>
2078 {
2079 public:
2080  static_assert(_TreeType::DEPTH >= 4, "cache size exceeds tree depth");
2081  static_assert(L0 < L1, "invalid cache level");
2082  static_assert(L1 < L2, "invalid cache level");
2083  static_assert(L2 < _TreeType::RootNodeType::LEVEL, "invalid cache level");
2084 
2085  using TreeType = _TreeType;
2086  using ValueType = typename TreeType::ValueType;
2087  using RootNodeT = typename TreeType::RootNodeType;
2088  using LeafNodeT = typename TreeType::LeafNodeType;
2090  using InvTreeT = typename RootNodeT::NodeChainType;
2091  using NodeT0 = typename InvTreeT::template Get<L0>;
2092  using NodeT1 = typename InvTreeT::template Get<L1>;
2093  using NodeT2 = typename InvTreeT::template Get<L2>;
2094 
2095  /// Constructor from a tree
2097  mKey0(Coord::max()), mNode0(nullptr),
2098  mKey1(Coord::max()), mNode1(nullptr),
2099  mKey2(Coord::max()), mNode2(nullptr) {}
2100 
2101  /// Copy constructor
2102  ValueAccessor3(const ValueAccessor3& other) : BaseT(other) { this->copy(other); }
2103 
2104  /// Assignment operator
2106  {
2107  if (&other != this) {
2108  this->BaseT::operator=(other);
2109  this->copy(other);
2110  }
2111  return *this;
2112  }
2113 
2114  /// Return the number of cache levels employed by this ValueAccessor
2115  static Index numCacheLevels() { return 3; }
2116 
2117  /// Virtual destructor
2118  ~ValueAccessor3() override = default;
2119 
2120  /// Return @c true if any of the nodes along the path to the given
2121  /// voxel have been cached.
2122  bool isCached(const Coord& xyz) const
2123  {
2124  assert(BaseT::mTree);
2125  return this->isHashed2(xyz) || this->isHashed1(xyz) || this->isHashed0(xyz);
2126  }
2127 
2128  /// Return the value of the voxel at the given coordinates.
2129  const ValueType& getValue(const Coord& xyz) const
2130  {
2131  assert(BaseT::mTree);
2132  if (this->isHashed0(xyz)) {
2133  assert(mNode0);
2134  return mNode0->getValueAndCache(xyz, this->self());
2135  } else if (this->isHashed1(xyz)) {
2136  assert(mNode1);
2137  return mNode1->getValueAndCache(xyz, this->self());
2138  } else if (this->isHashed2(xyz)) {
2139  assert(mNode2);
2140  return mNode2->getValueAndCache(xyz, this->self());
2141  }
2142  return BaseT::mTree->root().getValueAndCache(xyz, this->self());
2143  }
2144 
2145  /// Return the active state of the voxel at the given coordinates.
2146  bool isValueOn(const Coord& xyz) const
2147  {
2148  assert(BaseT::mTree);
2149  if (this->isHashed0(xyz)) {
2150  assert(mNode0);
2151  return mNode0->isValueOnAndCache(xyz, this->self());
2152  } else if (this->isHashed1(xyz)) {
2153  assert(mNode1);
2154  return mNode1->isValueOnAndCache(xyz, this->self());
2155  } else if (this->isHashed2(xyz)) {
2156  assert(mNode2);
2157  return mNode2->isValueOnAndCache(xyz, this->self());
2158  }
2159  return BaseT::mTree->root().isValueOnAndCache(xyz, this->self());
2160  }
2161 
2162  /// Return the active state of the voxel as well as its value
2163  bool probeValue(const Coord& xyz, ValueType& value) const
2164  {
2165  assert(BaseT::mTree);
2166  if (this->isHashed0(xyz)) {
2167  assert(mNode0);
2168  return mNode0->probeValueAndCache(xyz, value, this->self());
2169  } else if (this->isHashed1(xyz)) {
2170  assert(mNode1);
2171  return mNode1->probeValueAndCache(xyz, value, this->self());
2172  } else if (this->isHashed2(xyz)) {
2173  assert(mNode2);
2174  return mNode2->probeValueAndCache(xyz, value, this->self());
2175  }
2176  return BaseT::mTree->root().probeValueAndCache(xyz, value, this->self());
2177  }
2178 
2179  /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides,
2180  /// or -1 if (x, y, z) isn't explicitly represented in the tree (i.e., if it is
2181  /// implicitly a background voxel).
2182  int getValueDepth(const Coord& xyz) const
2183  {
2184  assert(BaseT::mTree);
2185  if (this->isHashed0(xyz)) {
2186  assert(mNode0);
2187  return RootNodeT::LEVEL - mNode0->getValueLevelAndCache(xyz, this->self());
2188  } else if (this->isHashed1(xyz)) {
2189  assert(mNode1);
2190  return RootNodeT::LEVEL - mNode1->getValueLevelAndCache(xyz, this->self());
2191  } else if (this->isHashed2(xyz)) {
2192  assert(mNode2);
2193  return RootNodeT::LEVEL - mNode2->getValueLevelAndCache(xyz, this->self());
2194  }
2195  return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self());
2196  }
2197 
2198  /// Return @c true if the value of voxel (x, y, z) resides at the leaf level
2199  /// of the tree, i.e., if it is not a tile value.
2200  bool isVoxel(const Coord& xyz) const
2201  {
2202  assert(BaseT::mTree);
2203  if (this->isHashed0(xyz)) {
2204  assert(mNode0);
2205  return mNode0->getValueLevelAndCache(xyz, this->self())==0;
2206  } else if (this->isHashed1(xyz)) {
2207  assert(mNode1);
2208  return mNode1->getValueLevelAndCache(xyz, this->self())==0;
2209  } else if (this->isHashed2(xyz)) {
2210  assert(mNode2);
2211  return mNode2->getValueLevelAndCache(xyz, this->self())==0;
2212  }
2213  return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self()) ==
2214  static_cast<int>(RootNodeT::LEVEL);
2215  }
2216 
2217  //@{
2218  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
2219  void setValue(const Coord& xyz, const ValueType& value)
2220  {
2221  assert(BaseT::mTree);
2222  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2223  if (this->isHashed0(xyz)) {
2224  assert(mNode0);
2225  const_cast<NodeT0*>(mNode0)->setValueAndCache(xyz, value, *this);
2226  } else if (this->isHashed1(xyz)) {
2227  assert(mNode1);
2228  const_cast<NodeT1*>(mNode1)->setValueAndCache(xyz, value, *this);
2229  } else if (this->isHashed2(xyz)) {
2230  assert(mNode2);
2231  const_cast<NodeT2*>(mNode2)->setValueAndCache(xyz, value, *this);
2232  } else {
2233  BaseT::mTree->root().setValueAndCache(xyz, value, *this);
2234  }
2235  }
2236  void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); }
2237  //@}
2238 
2239  /// Set the value of the voxel at the given coordinate but preserves its active state.
2240  void setValueOnly(const Coord& xyz, const ValueType& value)
2241  {
2242  assert(BaseT::mTree);
2243  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2244  if (this->isHashed0(xyz)) {
2245  assert(mNode0);
2246  const_cast<NodeT0*>(mNode0)->setValueOnlyAndCache(xyz, value, *this);
2247  } else if (this->isHashed1(xyz)) {
2248  assert(mNode1);
2249  const_cast<NodeT1*>(mNode1)->setValueOnlyAndCache(xyz, value, *this);
2250  } else if (this->isHashed2(xyz)) {
2251  assert(mNode2);
2252  const_cast<NodeT2*>(mNode2)->setValueOnlyAndCache(xyz, value, *this);
2253  } else {
2254  BaseT::mTree->root().setValueOnlyAndCache(xyz, value, *this);
2255  }
2256  }
2257 
2258  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
2259  void setValueOff(const Coord& xyz, const ValueType& value)
2260  {
2261  assert(BaseT::mTree);
2262  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2263  if (this->isHashed0(xyz)) {
2264  assert(mNode0);
2265  const_cast<NodeT0*>(mNode0)->setValueOffAndCache(xyz, value, *this);
2266  } else if (this->isHashed1(xyz)) {
2267  assert(mNode1);
2268  const_cast<NodeT1*>(mNode1)->setValueOffAndCache(xyz, value, *this);
2269  } else if (this->isHashed2(xyz)) {
2270  assert(mNode2);
2271  const_cast<NodeT2*>(mNode2)->setValueOffAndCache(xyz, value, *this);
2272  } else {
2273  BaseT::mTree->root().setValueOffAndCache(xyz, value, *this);
2274  }
2275  }
2276 
2277  /// @brief Apply a functor to the value of the voxel at the given coordinates
2278  /// and mark the voxel as active.
2279  /// @details See Tree::modifyValue() for details.
2280  template<typename ModifyOp>
2281  void modifyValue(const Coord& xyz, const ModifyOp& op)
2282  {
2283  assert(BaseT::mTree);
2284  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2285  if (this->isHashed0(xyz)) {
2286  assert(mNode0);
2287  const_cast<NodeT0*>(mNode0)->modifyValueAndCache(xyz, op, *this);
2288  } else if (this->isHashed1(xyz)) {
2289  assert(mNode1);
2290  const_cast<NodeT1*>(mNode1)->modifyValueAndCache(xyz, op, *this);
2291  } else if (this->isHashed2(xyz)) {
2292  assert(mNode2);
2293  const_cast<NodeT2*>(mNode2)->modifyValueAndCache(xyz, op, *this);
2294  } else {
2295  BaseT::mTree->root().modifyValueAndCache(xyz, op, *this);
2296  }
2297  }
2298 
2299  /// @brief Apply a functor to the voxel at the given coordinates.
2300  /// @details See Tree::modifyValueAndActiveState() for details.
2301  template<typename ModifyOp>
2302  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
2303  {
2304  assert(BaseT::mTree);
2305  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2306  if (this->isHashed0(xyz)) {
2307  assert(mNode0);
2308  const_cast<NodeT0*>(mNode0)->modifyValueAndActiveStateAndCache(xyz, op, *this);
2309  } else if (this->isHashed1(xyz)) {
2310  assert(mNode1);
2311  const_cast<NodeT1*>(mNode1)->modifyValueAndActiveStateAndCache(xyz, op, *this);
2312  } else if (this->isHashed2(xyz)) {
2313  assert(mNode2);
2314  const_cast<NodeT2*>(mNode2)->modifyValueAndActiveStateAndCache(xyz, op, *this);
2315  } else {
2316  BaseT::mTree->root().modifyValueAndActiveStateAndCache(xyz, op, *this);
2317  }
2318  }
2319 
2320  /// Set the active state of the voxel at the given coordinates without changing its value.
2321  void setActiveState(const Coord& xyz, bool on = true)
2322  {
2323  assert(BaseT::mTree);
2324  static_assert(!BaseT::IsConstTree, "can't modify a const tree's values");
2325  if (this->isHashed0(xyz)) {
2326  assert(mNode0);
2327  const_cast<NodeT0*>(mNode0)->setActiveStateAndCache(xyz, on, *this);
2328  } else if (this->isHashed1(xyz)) {
2329  assert(mNode1);
2330  const_cast<NodeT1*>(mNode1)->setActiveStateAndCache(xyz, on, *this);
2331  } else if (this->isHashed2(xyz)) {
2332  assert(mNode2);
2333  const_cast<NodeT2*>(mNode2)->setActiveStateAndCache(xyz, on, *this);
2334  } else {
2335  BaseT::mTree->root().setActiveStateAndCache(xyz, on, *this);
2336  }
2337  }
2338  /// Mark the voxel at the given coordinates as active without changing its value.
2339  void setValueOn(const Coord& xyz) { this->setActiveState(xyz, true); }
2340  /// Mark the voxel at the given coordinates as inactive without changing its value.
2341  void setValueOff(const Coord& xyz) { this->setActiveState(xyz, false); }
2342 
2343  /// Return the cached node of type @a NodeType. [Mainly for internal use]
2344  template<typename NodeT>
2345  NodeT* getNode()
2346  {
2347  const NodeT* node = nullptr;
2348  this->getNode(node);
2349  return const_cast<NodeT*>(node);
2350  }
2351 
2352  /// Cache the given node, which should lie along the path from the root node to
2353  /// the node containing voxel (x, y, z). [Mainly for internal use]
2354  template<typename NodeT>
2355  void insertNode(const Coord& xyz, NodeT& node) { this->insert(xyz, &node); }
2356 
2357  /// If a node of the given type exists in the cache, remove it, so that
2358  /// isCached(xyz) returns @c false for any voxel (x, y, z) contained in
2359  /// that node. [Mainly for internal use]
2360  template<typename NodeT>
2361  void eraseNode()
2362  {
2363  const NodeT* node = nullptr;
2364  this->eraseNode(node);
2365  }
2366 
2367  /// @brief Add the specified leaf to this tree, possibly creating a child branch
2368  /// in the process. If the leaf node already exists, replace it.
2369  void addLeaf(LeafNodeT* leaf)
2370  {
2371  assert(BaseT::mTree);
2372  static_assert(!BaseT::IsConstTree, "can't add a node to a const tree");
2373  if (this->isHashed1(leaf->origin())) {
2374  assert(mNode1);
2375  return const_cast<NodeT1*>(mNode1)->addLeafAndCache(leaf, *this);
2376  } else if (this->isHashed2(leaf->origin())) {
2377  assert(mNode2);
2378  return const_cast<NodeT2*>(mNode2)->addLeafAndCache(leaf, *this);
2379  }
2380  BaseT::mTree->root().addLeafAndCache(leaf, *this);
2381  }
2382 
2383  /// @brief Add a tile at the specified tree level that contains voxel (x, y, z),
2384  /// possibly deleting existing nodes or creating new nodes in the process.
2385  void addTile(Index level, const Coord& xyz, const ValueType& value, bool state)
2386  {
2387  assert(BaseT::mTree);
2388  static_assert(!BaseT::IsConstTree, "can't add a tile to a const tree");
2389  if (this->isHashed1(xyz)) {
2390  assert(mNode1);
2391  return const_cast<NodeT1*>(mNode1)->addTileAndCache(level, xyz, value, state, *this);
2392  } if (this->isHashed2(xyz)) {
2393  assert(mNode2);
2394  return const_cast<NodeT2*>(mNode2)->addTileAndCache(level, xyz, value, state, *this);
2395  }
2396  BaseT::mTree->root().addTileAndCache(level, xyz, value, state, *this);
2397  }
2398 
2399  /// @brief @return the leaf node that contains voxel (x, y, z) and
2400  /// if it doesn't exist, create it, but preserve the values and
2401  /// active states of all voxels.
2402  ///
2403  /// Use this method to preallocate a static tree topology over which to
2404  /// safely perform multithreaded processing.
2405  LeafNodeT* touchLeaf(const Coord& xyz)
2406  {
2407  assert(BaseT::mTree);
2408  static_assert(!BaseT::IsConstTree, "can't get a non-const node from a const tree");
2409  if (this->isHashed0(xyz)) {
2410  assert(mNode0);
2411  return const_cast<NodeT0*>(mNode0);
2412  } else if (this->isHashed1(xyz)) {
2413  assert(mNode1);
2414  return const_cast<NodeT1*>(mNode1)->touchLeafAndCache(xyz, *this);
2415  } else if (this->isHashed2(xyz)) {
2416  assert(mNode2);
2417  return const_cast<NodeT2*>(mNode2)->touchLeafAndCache(xyz, *this);
2418  }
2419  return BaseT::mTree->root().touchLeafAndCache(xyz, *this);
2420  }
2421  /// @brief @return a pointer to the node of the specified type that contains
2422  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
2423  template<typename NodeT>
2424  NodeT* probeNode(const Coord& xyz)
2425  {
2426  assert(BaseT::mTree);
2427  static_assert(!BaseT::IsConstTree, "can't get a non-const node from a const tree");
2430  if (this->isHashed0(xyz)) {
2431  assert(mNode0);
2432  return reinterpret_cast<NodeT*>(const_cast<NodeT0*>(mNode0));
2433  } else if (this->isHashed1(xyz)) {
2434  assert(mNode1);
2435  return const_cast<NodeT1*>(mNode1)->template probeNodeAndCache<NodeT>(xyz, *this);
2436  } else if (this->isHashed2(xyz)) {
2437  assert(mNode2);
2438  return const_cast<NodeT2*>(mNode2)->template probeNodeAndCache<NodeT>(xyz, *this);
2439  }
2440  return BaseT::mTree->root().template probeNodeAndCache<NodeT>(xyz, *this);
2441  } else if ((std::is_same<NodeT, NodeT1>::value)) {
2442  if (this->isHashed1(xyz)) {
2443  assert(mNode1);
2444  return reinterpret_cast<NodeT*>(const_cast<NodeT1*>(mNode1));
2445  } else if (this->isHashed2(xyz)) {
2446  assert(mNode2);
2447  return const_cast<NodeT2*>(mNode2)->template probeNodeAndCache<NodeT>(xyz, *this);
2448  }
2449  return BaseT::mTree->root().template probeNodeAndCache<NodeT>(xyz, *this);
2450  } else if ((std::is_same<NodeT, NodeT2>::value)) {
2451  if (this->isHashed2(xyz)) {
2452  assert(mNode2);
2453  return reinterpret_cast<NodeT*>(const_cast<NodeT2*>(mNode2));
2454  }
2455  return BaseT::mTree->root().template probeNodeAndCache<NodeT>(xyz, *this);
2456  }
2457  return nullptr;
2459  }
2460  /// @brief @return a pointer to the leaf node that contains
2461  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
2462  LeafNodeT* probeLeaf(const Coord& xyz) { return this->template probeNode<LeafNodeT>(xyz); }
2463 
2464  /// @brief @return a const pointer to the node of the specified type that contains
2465  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
2466  template<typename NodeT>
2467  const NodeT* probeConstNode(const Coord& xyz) const
2468  {
2469  assert(BaseT::mTree);
2472  if (this->isHashed0(xyz)) {
2473  assert(mNode0);
2474  return reinterpret_cast<const NodeT*>(mNode0);
2475  } else if (this->isHashed1(xyz)) {
2476  assert(mNode1);
2477  return mNode1->template probeConstNodeAndCache<NodeT>(xyz, this->self());
2478  } else if (this->isHashed2(xyz)) {
2479  assert(mNode2);
2480  return mNode2->template probeConstNodeAndCache<NodeT>(xyz, this->self());
2481  }
2482  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
2483  } else if ((std::is_same<NodeT, NodeT1>::value)) {
2484  if (this->isHashed1(xyz)) {
2485  assert(mNode1);
2486  return reinterpret_cast<const NodeT*>(mNode1);
2487  } else if (this->isHashed2(xyz)) {
2488  assert(mNode2);
2489  return mNode2->template probeConstNodeAndCache<NodeT>(xyz, this->self());
2490  }
2491  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
2492  } else if ((std::is_same<NodeT, NodeT2>::value)) {
2493  if (this->isHashed2(xyz)) {
2494  assert(mNode2);
2495  return reinterpret_cast<const NodeT*>(mNode2);
2496  }
2497  return BaseT::mTree->root().template probeConstNodeAndCache<NodeT>(xyz, this->self());
2498  }
2499  return nullptr;
2501  }
2502  /// @brief @return a const pointer to the leaf node that contains
2503  /// voxel (x, y, z) and if it doesn't exist, return @c nullptr.
2504  const LeafNodeT* probeConstLeaf(const Coord& xyz) const
2505  {
2506  return this->template probeConstNode<LeafNodeT>(xyz);
2507  }
2508  const LeafNodeT* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); }
2509 
2510  /// Remove all the cached nodes and invalidate the corresponding hash-keys.
2511  void clear() override
2512  {
2513  mKey0 = Coord::max();
2514  mNode0 = nullptr;
2515  mKey1 = Coord::max();
2516  mNode1 = nullptr;
2517  mKey2 = Coord::max();
2518  mNode2 = nullptr;
2519  }
2520 
2521 private:
2522  // Allow nodes to insert themselves into the cache.
2523  template<typename> friend class RootNode;
2524  template<typename, Index> friend class InternalNode;
2525  template<typename, Index> friend class LeafNode;
2526  // Allow trees to deregister themselves.
2527  template<typename> friend class Tree;
2528 
2529  // This private method is merely for convenience.
2530  inline ValueAccessor3& self() const { return const_cast<ValueAccessor3&>(*this); }
2531 
2532  /// Private copy method
2533  inline void copy(const ValueAccessor3& other)
2534  {
2535  mKey0 = other.mKey0;
2536  mNode0 = other.mNode0;
2537  mKey1 = other.mKey1;
2538  mNode1 = other.mNode1;
2539  mKey2 = other.mKey2;
2540  mNode2 = other.mNode2;
2541  }
2542 
2543  /// Prevent this accessor from calling Tree::releaseCache() on a tree that
2544  /// no longer exists. (Called by mTree when it is destroyed.)
2545  void release() override
2546  {
2547  this->BaseT::release();
2548  this->clear();
2549  }
2550  void getNode(const NodeT0*& node) { node = mNode0; }
2551  void getNode(const NodeT1*& node) { node = mNode1; }
2552  void getNode(const NodeT2*& node) { node = mNode2; }
2553  void getNode(const RootNodeT*& node)
2554  {
2555  node = (BaseT::mTree ? &BaseT::mTree->root() : nullptr);
2556  }
2557  template<typename OtherNodeType> void getNode(const OtherNodeType*& node) { node = nullptr; }
2558 
2559  void eraseNode(const NodeT0*) { mKey0 = Coord::max(); mNode0 = nullptr; }
2560  void eraseNode(const NodeT1*) { mKey1 = Coord::max(); mNode1 = nullptr; }
2561  void eraseNode(const NodeT2*) { mKey2 = Coord::max(); mNode2 = nullptr; }
2562  template<typename OtherNodeType> void eraseNode(const OtherNodeType*) {}
2563 
2564  /// Cache the given node, which should lie along the path from the root node to
2565  /// the node containing voxel (x, y, z).
2566  /// @note This operation is not mutex-protected and is intended to be called
2567  /// only by nodes and only in the context of a getValue() or setValue() call.
2568  inline void insert(const Coord& xyz, const NodeT0* node)
2569  {
2570  assert(node);
2571  mKey0 = xyz & ~(NodeT0::DIM-1);
2572  mNode0 = node;
2573  }
2574  inline void insert(const Coord& xyz, const NodeT1* node)
2575  {
2576  assert(node);
2577  mKey1 = xyz & ~(NodeT1::DIM-1);
2578  mNode1 = node;
2579  }
2580  inline void insert(const Coord& xyz, const NodeT2* node)
2581  {
2582  assert(node);
2583  mKey2 = xyz & ~(NodeT2::DIM-1);
2584  mNode2 = node;
2585  }
2586  /// No-op in case a tree traversal attemps to insert a node that
2587  /// is not cached by the ValueAccessor
2588  template<typename OtherNodeType>
2589  inline void insert(const Coord&, const OtherNodeType*)
2590  {
2591  }
2592  inline bool isHashed0(const Coord& xyz) const
2593  {
2594  return (xyz[0] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[0]
2595  && (xyz[1] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[1]
2596  && (xyz[2] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[2];
2597  }
2598  inline bool isHashed1(const Coord& xyz) const
2599  {
2600  return (xyz[0] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[0]
2601  && (xyz[1] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[1]
2602  && (xyz[2] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[2];
2603  }
2604  inline bool isHashed2(const Coord& xyz) const
2605  {
2606  return (xyz[0] & ~Coord::ValueType(NodeT2::DIM-1)) == mKey2[0]
2607  && (xyz[1] & ~Coord::ValueType(NodeT2::DIM-1)) == mKey2[1]
2608  && (xyz[2] & ~Coord::ValueType(NodeT2::DIM-1)) == mKey2[2];
2609  }
2610  mutable Coord mKey0;
2611  mutable const NodeT0* mNode0;
2612  mutable Coord mKey1;
2613  mutable const NodeT1* mNode1;
2614  mutable Coord mKey2;
2615  mutable const NodeT2* mNode2;
2616 }; // ValueAccessor3
2617 
2618 } // namespace tree
2619 } // namespace OPENVDB_VERSION_NAME
2620 } // namespace openvdb
2621 
2622 #endif // OPENVDB_TREE_VALUEACCESSOR_HAS_BEEN_INCLUDED
NodeT * getNode()
Return the cached node of type NodeType. [Mainly for internal use].
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
void insertNode(const Coord &xyz, NodeT &node)
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active without changing its value.
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
void insert(const Coord &xyz, const OtherNodeType *node)
Forward the given node to another level of the cache.
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
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...
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
static Index numCacheLevels()
Return the number of cache levels employed by this ValueAccessor.
const LeafNodeT * probeLeaf(const Coord &xyz) const
const LeafNodeT * probeLeaf(const Coord &xyz) const
void insertNode(const Coord &xyz, NodeT &node)
void clear() override
Remove all nodes from this cache, then reinsert the root node.
void setValueOff(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as inactive.
Value accessor with two levels of node caching.
Definition: ValueAccessor.h:54
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
void clear() override
Remove all nodes from this cache, then reinsert the root node.
void setValueOn(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
const NodeT * probeConstNode(const Coord &xyz) const
ValueAccessor1(const ValueAccessor1 &other)
Copy constructor.
void erase(const OtherNodeType *node)
Erase the node at another level of the cache.
NodeType * getNode()
Return the cached node of type NodeType. [Mainly for internal use].
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
OIIO_UTIL_API bool copy(string_view from, string_view to, std::string &err)
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.
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...
Value accessor with three levels of node caching.
Definition: ValueAccessor.h:56
const NodeT * probeConstNode(const Coord &xyz) const
ValueAccessor0 & operator=(const ValueAccessor0 &other)
static Index numCacheLevels()
Return the number of cache levels employed by this accessor.
ValueAccessor3(const ValueAccessor3 &other)
Copy constructor.
void insert(const Coord &xyz, const NodeType *node)
Cache the given node at this level.
bool isCached(const Coord &xyz) const
void setActiveState(const Coord &xyz, bool on=true)
Set the active state of the voxel at the given coordinates without changing its value.
NodeT * getNode()
Return the cached node of type NodeType. [Mainly for internal use].
GLint level
Definition: glcorearb.h:108
ValueAccessorBase & operator=(const ValueAccessorBase &other)
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
const ValueType & getValue(const Coord &xyz)
Return the value of the voxel at the given coordinates.
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...
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
const LeafNodeT * probeLeaf(const Coord &xyz) const
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:207
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...
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
void setActiveState(const Coord &xyz, bool on=true)
Set the active state of the voxel at the given coordinates without changing its value.
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive without changing its value.
void clear() override
Remove all the cached nodes and invalidate the corresponding hash-keys.
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
**But if you need a or simply need to know when the task has note that the like this
Definition: thread.h:617
void setActiveState(const Coord &xyz, bool on=true)
Set the active state of the voxel at the given coordinates but don't change its value.
CacheItem & copy(TreeCacheT &parent, const CacheItem &other)
void setValueOff(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as inactive.
void setValueOn(const Coord &xyz, const ValueType &value)
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
void setValueOff(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as inactive.
void setValueOn(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
OIIO_FORCEINLINE vbool4 insert(const vbool4 &a, bool val)
Helper: substitute val for a[i].
Definition: simd.h:3436
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
bool isValueOn(const Coord &xyz)
Return the active state of the voxel at the given coordinates.
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...
Value accessor with one level of node caching.
Definition: ValueAccessor.h:52
void setValueOn(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
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.
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...
NodeT * getNode()
Return the cached node of type NodeType. [Mainly for internal use].
void setValueOnly(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinate but don't change its active state.
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...
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don't change its value.
const LeafNodeType * probeConstLeaf(const Coord &xyz)
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.
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
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...
void erase(const NodeType *)
Erase the node at this level.
void setActiveState(const Coord &xyz, bool on=true)
Set the active state of the voxel at the given coordinates but don't change its value.
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
void clear() override
Remove all the cached nodes and invalidate the corresponding hash-keys.
void insertNode(const Coord &xyz, NodeT &node)
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
LeafNodeType * probeLeaf(const Coord &xyz)
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
bool probeValue(const Coord &xyz, ValueType &value)
Return the active state and value of the voxel at the given coordinates.
void setValueOnly(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinate but don't change its active state.
ValueAccessor with no mutex and no node caching.
Definition: ValueAccessor.h:50
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.
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
void clear() override
Remove all the cached nodes and invalidate the corresponding hash-keys.
ValueAccessor2(TreeType &tree)
Constructor from a tree.
ValueAccessor & operator=(const ValueAccessor &other)
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active without changing its value.
void setValueOnly(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinate but preserves its active state.
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.
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...
ValueAccessor3 & operator=(const ValueAccessor3 &other)
Assignment operator.
void insertNode(const Coord &xyz, NodeType &node)
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
void setActiveState(const Coord &xyz, bool on=true)
Set the active state of the voxel at the given coordinates but don't change its value.
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
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...
bool isCached(const Coord &xyz) const
Return true if nodes along the path to the given voxel have been cached.
This base class for ValueAccessors manages registration of an accessor with a tree so that the tree c...
Definition: ValueAccessor.h:84
TreeType * getTree() const
Return a pointer to the tree associated with this accessor.
void setValueOnly(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinate but preserves its active state.
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
ValueAccessor1 & operator=(const ValueAccessor1 &other)
Assignment operator.
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
SIMD Intrinsic Headers.
Definition: Platform.h:115
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...
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...
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
void addTile(Index level, const Coord &xyz, const ValueType &value, bool state)
void setValueOnly(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinate but preserves its active state.
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
ValueAccessor3(TreeType &tree)
Constructor from a tree.
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...
const LeafNodeT * probeLeaf(const Coord &xyz) const
Library and file format version numbers.
void setValueOff(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as inactive.
static Index numCacheLevels()
Return the number of cache levels employed by this ValueAccessor.
const NodeT * probeConstNode(const Coord &xyz)
static Index numCacheLevels()
Return the number of cache levels employed by this ValueAccessor.
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...
static Index numCacheLevels()
Return the number of cache levels employed by this accessor.
NodeT * getNode()
Return the cached node of type NodeType. [Mainly for internal use].
void setValueOff(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as inactive.
ValueAccessor2(const ValueAccessor2 &other)
Copy constructor.
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
void setValueOnly(const Coord &xyz, const ValueType &value)
const NodeT * probeConstNode(const Coord &xyz) const
CacheItem & copy(TreeCacheT &parent, const CacheItem &other)
Copy another CacheItem's node pointers and hash keys, but not its parent pointer. ...
void setValueOn(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
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.
ValueAccessor2 & operator=(const ValueAccessor2 &other)
Assignment operator.
const NodeT * probeConstLeaf(const Coord &xyz) const
GLsizei const GLfloat * value
Definition: glcorearb.h:824
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...
bool isCached(const Coord &) const
Return true if nodes along the path to the given voxel have been cached.
ValueAccessor1(TreeType &tree)
Constructor from a tree.
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:116
Definition: core.h:1131
CacheItem(TreeCacheT &parent, const CacheItem &other)
Copy another CacheItem's node pointers and hash keys, but not its parent pointer. ...
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state and, in value, the value of the voxel at the given coordinates.
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
LeafNodeType * touchLeaf(const Coord &xyz)
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...
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive without changing its value.
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don't change its value.
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don't change its value.
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don't change its value.
This accessor is thread-safe (at the cost of speed) for both reading and writing to a tree...
static bool isSafe()
Return true if this accessor is safe, i.e. registered by the tree from which it is constructed...
Definition: ValueAccessor.h:95
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:119
void addTile(Index level, const Coord &xyz, const ValueType &value, bool state)
void setValueOff(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as inactive.
void getNode(const NodeType *&node) const
Return the cached node (if any) at this level.
void setValueOn(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
void getNode(OtherNodeType *&node)
Forward the request to another level of the cache.
const NodeT * probeConstNode(const Coord &xyz) const
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
void clear()
Erase the nodes at this and lower levels of the cache.
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
void setActiveState(const Coord &xyz, bool on)
Set the active state of the voxel at the given coordinates.
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don't change its value.
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...
TreeType & tree() const
Return a reference to the tree associated with this accessor.
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don't change its value.