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