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