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