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