OpenVDB 13.0.1
Loading...
Searching...
No Matches
Tree.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3
4/// @file tree/Tree.h
5
6#ifndef OPENVDB_TREE_TREE_HAS_BEEN_INCLUDED
7#define OPENVDB_TREE_TREE_HAS_BEEN_INCLUDED
8
9#include <openvdb/Types.h>
10#include <openvdb/Metadata.h>
11#include <openvdb/math/Math.h>
12#include <openvdb/math/BBox.h>
13#include <openvdb/tools/Count.h> // tools::countActiveVoxels(), tools::memUsage(), tools::minMax()
16#include <openvdb/util/Assert.h>
17#include <openvdb/Platform.h>
18#include "RootNode.h"
19#include "InternalNode.h"
20#include "LeafNode.h"
21#include "TreeIterator.h"
22#include "ValueAccessor.h"
23#include <tbb/concurrent_hash_map.h>
24#include <cstdint>
25#include <iostream>
26#include <mutex>
27#include <sstream>
28#include <vector>
29
30
31namespace openvdb {
33namespace OPENVDB_VERSION_NAME {
34namespace tree {
35
36/// @brief Base class for typed trees
38{
39public:
42
43 TreeBase() = default;
44 TreeBase(const TreeBase&) = default;
45 TreeBase& operator=(const TreeBase&) = delete; // disallow assignment
46 virtual ~TreeBase() = default;
47
48 /// Return the name of this tree's type.
49 virtual const Name& type() const = 0;
50
51 /// Return the name of the type of a voxel's value (e.g., "float" or "vec3d").
52 virtual Name valueType() const = 0;
53
54 /// Return @c true if this tree is of the same type as the template parameter.
55 template<typename TreeType>
56 bool isType() const { return (this->type() == TreeType::treeType()); }
57
58 /// Return a pointer to a deep copy of this tree
59 virtual TreeBase::Ptr copy() const = 0;
60
61 //
62 // Tree methods
63 //
64 /// @brief Return this tree's background value wrapped as metadata.
65 /// @note Query the metadata object for the value's type.
66 virtual Metadata::Ptr getBackgroundValue() const { return Metadata::Ptr(); }
67
68 /// @brief Return in @a bbox the axis-aligned bounding box of all
69 /// active tiles and leaf nodes with active values.
70 /// @details This is faster than calling evalActiveVoxelBoundingBox,
71 /// which visits the individual active voxels, and hence
72 /// evalLeafBoundingBox produces a less tight, i.e. approximate, bbox.
73 /// @return @c false if the bounding box is empty (in which case
74 /// the bbox is set to its default value).
75 virtual bool evalLeafBoundingBox(CoordBBox& bbox) const = 0;
76
77 /// @brief Return in @a dim the dimensions of the axis-aligned bounding box
78 /// of all leaf nodes.
79 /// @return @c false if the bounding box is empty.
80 virtual bool evalLeafDim(Coord& dim) const = 0;
81
82 /// @brief Return in @a bbox the axis-aligned bounding box of all
83 /// active voxels and tiles.
84 /// @details This method produces a more accurate, i.e. tighter,
85 /// bounding box than evalLeafBoundingBox which is approximate but
86 /// faster.
87 /// @return @c false if the bounding box is empty (in which case
88 /// the bbox is set to its default value).
89 virtual bool evalActiveVoxelBoundingBox(CoordBBox& bbox) const = 0;
90
91 /// @brief Return in @a dim the dimensions of the axis-aligned bounding box of all
92 /// active voxels. This is a tighter bounding box than the leaf node bounding box.
93 /// @return @c false if the bounding box is empty.
94 virtual bool evalActiveVoxelDim(Coord& dim) const = 0;
95
96 virtual void getIndexRange(CoordBBox& bbox) const = 0;
97
98 /// @brief Replace with background tiles any nodes whose voxel buffers
99 /// have not yet been allocated.
100 /// @details Typically, unallocated nodes are leaf nodes whose voxel buffers
101 /// are not yet resident in memory because delayed loading is in effect.
102 /// @sa readNonresidentBuffers, io::File::open
103 virtual void clipUnallocatedNodes() = 0;
104 /// Return the total number of unallocated leaf nodes residing in this tree.
105#if OPENVDB_ABI_VERSION_NUMBER >= 12
106 virtual Index64 unallocatedLeafCount() const = 0;
107#else
108 virtual Index32 unallocatedLeafCount() const = 0;
109#endif
110
111
112 //
113 // Statistics
114 //
115 /// @brief Return the depth of this tree.
116 ///
117 /// A tree with only a root node and leaf nodes has depth 2, for example.
118 virtual Index treeDepth() const = 0;
119 /// Return the number of leaf nodes.
120#if OPENVDB_ABI_VERSION_NUMBER >= 12
121 virtual Index64 leafCount() const = 0;
122#else
123 virtual Index32 leafCount() const = 0;
124#endif
125 /// Return a vector with node counts. The number of nodes of type NodeType
126 /// is given as element NodeType::LEVEL in the return vector. Thus, the size
127 /// of this vector corresponds to the height (or depth) of this tree.
128#if OPENVDB_ABI_VERSION_NUMBER >= 12
129 virtual std::vector<Index64> nodeCount() const = 0;
130#else
131 virtual std::vector<Index32> nodeCount() const = 0;
132#endif
133 /// Return the number of non-leaf nodes.
134#if OPENVDB_ABI_VERSION_NUMBER >= 12
135 virtual Index64 nonLeafCount() const = 0;
136#else
137 virtual Index32 nonLeafCount() const = 0;
138#endif
139 /// Return the number of active voxels stored in leaf nodes.
140 virtual Index64 activeLeafVoxelCount() const = 0;
141 /// Return the number of inactive voxels stored in leaf nodes.
142 virtual Index64 inactiveLeafVoxelCount() const = 0;
143 /// Return the total number of active voxels.
144 virtual Index64 activeVoxelCount() const = 0;
145 /// Return the number of inactive voxels within the bounding box of all active voxels.
146 virtual Index64 inactiveVoxelCount() const = 0;
147 /// Return the total number of active tiles.
148 virtual Index64 activeTileCount() const = 0;
149
150 /// Return the total amount of memory in bytes occupied by this tree.
151 virtual Index64 memUsage() const { return 0; }
152
153
154 //
155 // I/O methods
156 //
157 /// @brief Read the tree topology from a stream.
158 ///
159 /// This will read the tree structure and tile values, but not voxel data.
160 virtual void readTopology(std::istream&, bool saveFloatAsHalf = false);
161 /// @brief Write the tree topology to a stream.
162 ///
163 /// This will write the tree structure and tile values, but not voxel data.
164 virtual void writeTopology(std::ostream&, bool saveFloatAsHalf = false) const;
165
166 /// Read all data buffers for this tree.
167 virtual void readBuffers(std::istream&, bool saveFloatAsHalf = false) = 0;
168 /// Read all of this tree's data buffers that intersect the given bounding box.
169 virtual void readBuffers(std::istream&, const CoordBBox&, bool saveFloatAsHalf = false) = 0;
170 /// @brief Read all of this tree's data buffers that are not yet resident in memory
171 /// (because delayed loading is in effect).
172 /// @details If this tree was read from a memory-mapped file, this operation
173 /// disconnects the tree from the file.
174 /// @sa clipUnallocatedNodes, io::File::open, io::MappedFile
175 virtual void readNonresidentBuffers() const = 0;
176 /// Write out all the data buffers for this tree.
177 virtual void writeBuffers(std::ostream&, bool saveFloatAsHalf = false) const = 0;
178
179 /// @brief Print statistics, memory usage and other information about this tree.
180 /// @param os a stream to which to write textual information
181 /// @param verboseLevel 1: print tree configuration only;
182 /// 2: include node and voxel statistics;
183 /// 3: include memory usage;
184 /// 4: include minimum and maximum voxel values
185 /// @warning @a verboseLevel 4 forces loading of any unallocated nodes.
186 virtual void print(std::ostream& os = std::cout, int verboseLevel = 1) const;
187};
188
189
190////////////////////////////////////////
191
192
193template<typename _RootNodeType>
194class Tree: public TreeBase
195{
196public:
199
200 using RootNodeType = _RootNodeType;
201 using ValueType = typename RootNodeType::ValueType;
202 using BuildType = typename RootNodeType::BuildType;
203 using LeafNodeType = typename RootNodeType::LeafNodeType;
204
205 static const Index DEPTH = RootNodeType::LEVEL + 1;
206
211
212 /// @brief ValueConverter<T>::Type is the type of a tree having the same
213 /// hierarchy as this tree but a different value type, T.
214 ///
215 /// For example, FloatTree::ValueConverter<double>::Type is equivalent to DoubleTree.
216 /// @note If the source tree type is a template argument, it might be necessary
217 /// to write "typename SourceTree::template ValueConverter<T>::Type".
218 template<typename OtherValueType>
222
223
224 Tree() {}
225
226 Tree& operator=(const Tree&) = delete; // disallow assignment
227
228 /// Deep copy constructor
229 Tree(const Tree& other): TreeBase(other), mRoot(other.mRoot)
230 {
231 }
232
233 /// @brief Value conversion deep copy constructor
234 ///
235 /// Deep copy a tree of the same configuration as this tree type but a different
236 /// ValueType, casting the other tree's values to this tree's ValueType.
237 /// @throw TypeError if the other tree's configuration doesn't match this tree's
238 /// or if this tree's ValueType is not constructible from the other tree's ValueType.
239 template<typename OtherRootType>
240 explicit Tree(const Tree<OtherRootType>& other): TreeBase(other), mRoot(other.root())
241 {
242 }
243
244 /// @brief Topology copy constructor from a tree of a different type
245 ///
246 /// Copy the structure, i.e., the active states of tiles and voxels, of another
247 /// tree of a possibly different type, but don't copy any tile or voxel values.
248 /// Instead, initialize tiles and voxels with the given active and inactive values.
249 /// @param other a tree having (possibly) a different ValueType
250 /// @param inactiveValue background value for this tree, and the value to which
251 /// all inactive tiles and voxels are initialized
252 /// @param activeValue value to which active tiles and voxels are initialized
253 /// @throw TypeError if the other tree's configuration doesn't match this tree's.
254 template<typename OtherTreeType>
255 Tree(const OtherTreeType& other,
256 const ValueType& inactiveValue,
257 const ValueType& activeValue,
259 TreeBase(other),
260 mRoot(other.root(), inactiveValue, activeValue, TopologyCopy())
261 {
262 }
263
264 /// @brief Topology copy constructor from a tree of a different type
265 ///
266 /// @note This topology copy constructor is generally faster than
267 /// the one that takes both a foreground and a background value.
268 ///
269 /// Copy the structure, i.e., the active states of tiles and voxels, of another
270 /// tree of a possibly different type, but don't copy any tile or voxel values.
271 /// Instead, initialize tiles and voxels with the given background value.
272 /// @param other a tree having (possibly) a different ValueType
273 /// @param background the value to which tiles and voxels are initialized
274 /// @throw TypeError if the other tree's configuration doesn't match this tree's.
275 template<typename OtherTreeType>
276 Tree(const OtherTreeType& other, const ValueType& background, TopologyCopy):
277 TreeBase(other),
278 mRoot(other.root(), background, TopologyCopy())
279 {
280 }
281
282 /// Empty tree constructor
284
285 ~Tree() override { this->clear(); releaseAllAccessors(); }
286
287 /// Return a pointer to a deep copy of this tree
288 TreeBase::Ptr copy() const override { return TreeBase::Ptr(new Tree(*this)); }
289
290 /// Return the name of the type of a voxel's value (e.g., "float" or "vec3d")
291 Name valueType() const override { return typeNameAsString<ValueType>(); }
292
293 /// Return the name of this type of tree.
294 static const Name& treeType();
295 /// Return the name of this type of tree.
296 const Name& type() const override { return this->treeType(); }
297
300
301 //@{
302 /// Return this tree's root node.
303 RootNodeType& root() { return mRoot; }
304 const RootNodeType& root() const { return mRoot; }
305 //@}
306
307
308 //
309 // Tree methods
310 //
311 /// @brief Return @c true if the given tree has the same node and active value
312 /// topology as this tree, whether or not it has the same @c ValueType.
313 template<typename OtherRootNodeType>
314 bool hasSameTopology(const Tree<OtherRootNodeType>& other) const;
315
316 bool evalLeafBoundingBox(CoordBBox& bbox) const override;
317 bool evalActiveVoxelBoundingBox(CoordBBox& bbox) const override;
318 bool evalActiveVoxelDim(Coord& dim) const override;
319 bool evalLeafDim(Coord& dim) const override;
320
321 /// @brief Traverse the type hierarchy of nodes, and return, in @a dims, a list
322 /// of the Log2Dims of nodes in order from RootNode to LeafNode.
323 /// @note Because RootNodes are resizable, the RootNode Log2Dim is 0 for all trees.
324 static void getNodeLog2Dims(std::vector<Index>& dims);
325
326
327 //
328 // I/O methods
329 //
330 /// @brief Read the tree topology from a stream.
331 ///
332 /// This will read the tree structure and tile values, but not voxel data.
333 void readTopology(std::istream&, bool saveFloatAsHalf = false) override;
334 /// @brief Write the tree topology to a stream.
335 ///
336 /// This will write the tree structure and tile values, but not voxel data.
337 void writeTopology(std::ostream&, bool saveFloatAsHalf = false) const override;
338 /// Read all data buffers for this tree.
339 void readBuffers(std::istream&, bool saveFloatAsHalf = false) override;
340 /// Read all of this tree's data buffers that intersect the given bounding box.
341 void readBuffers(std::istream&, const CoordBBox&, bool saveFloatAsHalf = false) override;
342 /// @brief Read all of this tree's data buffers that are not yet resident in memory
343 /// (because delayed loading is in effect).
344 /// @details If this tree was read from a memory-mapped file, this operation
345 /// disconnects the tree from the file.
346 /// @sa clipUnallocatedNodes, io::File::open, io::MappedFile
347 void readNonresidentBuffers() const override;
348 /// Write out all data buffers for this tree.
349 void writeBuffers(std::ostream&, bool saveFloatAsHalf = false) const override;
350
351 void print(std::ostream& os = std::cout, int verboseLevel = 1) const override;
352
353
354 //
355 // Statistics
356 //
357 /// @brief Return the depth of this tree.
358 ///
359 /// A tree with only a root node and leaf nodes has depth 2, for example.
360 Index treeDepth() const override { return DEPTH; }
361 /// Return the number of leaf nodes.
362#if OPENVDB_ABI_VERSION_NUMBER >= 12
363 Index64 leafCount() const override { return mRoot.leafCount(); }
364#else
365 Index32 leafCount() const override { return static_cast<Index32>(mRoot.leafCount()); }
366#endif
367 /// Return a vector with node counts. The number of nodes of type NodeType
368 /// is given as element NodeType::LEVEL in the return vector. Thus, the size
369 /// of this vector corresponds to the height (or depth) of this tree.
370#if OPENVDB_ABI_VERSION_NUMBER >= 12
371 std::vector<Index64> nodeCount() const override
372 {
373 std::vector<Index64> vec(DEPTH, 0);
374 mRoot.nodeCount( vec );
375 return vec;// Named Return Value Optimization
376 }
377#else
378 std::vector<Index32> nodeCount() const override
379 {
380 std::vector<Index32> vec(DEPTH, 0);
382 mRoot.nodeCount( vec );
384 return vec;// Named Return Value Optimization
385 }
386#endif
387 /// Return the number of non-leaf nodes.
388#if OPENVDB_ABI_VERSION_NUMBER >= 12
389 Index64 nonLeafCount() const override { return mRoot.nonLeafCount(); }
390#else
391 Index32 nonLeafCount() const override { return static_cast<Index32>(mRoot.nonLeafCount()); }
392#endif
393 /// Return the number of active voxels stored in leaf nodes.
395 /// Return the number of inactive voxels stored in leaf nodes.
397 /// Return the total number of active voxels.
398 Index64 activeVoxelCount() const override { return tools::countActiveVoxels(*this); }
399 /// Return the number of inactive voxels within the bounding box of all active voxels.
400 Index64 inactiveVoxelCount() const override { return tools::countInactiveVoxels(*this); }
401 /// Return the total number of active tiles.
402 Index64 activeTileCount() const override { return tools::countActiveTiles(*this); }
403
404 Index64 memUsage() const override { return tools::memUsage(*this); }
405
406
407 //
408 // Voxel access methods (using signed indexing)
409 //
410 /// Return the value of the voxel at the given coordinates.
411 const ValueType& getValue(const Coord& xyz) const;
412 /// @brief Return the value of the voxel at the given coordinates
413 /// and update the given accessor's node cache.
414 template<typename AccessT> const ValueType& getValue(const Coord& xyz, AccessT&) const;
415
416 /// @brief Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides.
417 /// @details If (x, y, z) isn't explicitly represented in the tree (i.e., it is
418 /// implicitly a background voxel), return -1.
419 int getValueDepth(const Coord& xyz) const;
420
421 /// Set the active state of the voxel at the given coordinates but don't change its value.
422 void setActiveState(const Coord& xyz, bool on);
423 /// Set the value of the voxel at the given coordinates but don't change its active state.
424 void setValueOnly(const Coord& xyz, const ValueType& value);
425 /// Mark the voxel at the given coordinates as active but don't change its value.
426 void setValueOn(const Coord& xyz);
427 /// Set the value of the voxel at the given coordinates and mark the voxel as active.
428 void setValueOn(const Coord& xyz, const ValueType& value);
429 /// Set the value of the voxel at the given coordinates and mark the voxel as active.
430 void setValue(const Coord& xyz, const ValueType& value);
431 /// @brief Set the value of the voxel at the given coordinates, mark the voxel as active,
432 /// and update the given accessor's node cache.
433 template<typename AccessT> void setValue(const Coord& xyz, const ValueType& value, AccessT&);
434 /// Mark the voxel at the given coordinates as inactive but don't change its value.
435 void setValueOff(const Coord& xyz);
436 /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
437 void setValueOff(const Coord& xyz, const ValueType& value);
438
439 /// @brief Apply a functor to the value of the voxel at the given coordinates
440 /// and mark the voxel as active.
441 /// @details Provided that the functor can be inlined, this is typically
442 /// significantly faster than calling getValue() followed by setValueOn().
443 /// @param xyz the coordinates of a voxel whose value is to be modified
444 /// @param op a functor of the form <tt>void op(ValueType&) const</tt> that modifies
445 /// its argument in place
446 /// @par Example:
447 /// @code
448 /// Coord xyz(1, 0, -2);
449 /// // Multiply the value of a voxel by a constant and mark the voxel as active.
450 /// floatTree.modifyValue(xyz, [](float& f) { f *= 0.25; }); // C++11
451 /// // Set the value of a voxel to the maximum of its current value and 0.25,
452 /// // and mark the voxel as active.
453 /// floatTree.modifyValue(xyz, [](float& f) { f = std::max(f, 0.25f); }); // C++11
454 /// @endcode
455 /// @note The functor is not guaranteed to be called only once.
456 /// @see tools::foreach()
457 template<typename ModifyOp>
458 void modifyValue(const Coord& xyz, const ModifyOp& op);
459
460 /// @brief Apply a functor to the voxel at the given coordinates.
461 /// @details Provided that the functor can be inlined, this is typically
462 /// significantly faster than calling getValue() followed by setValue().
463 /// @param xyz the coordinates of a voxel to be modified
464 /// @param op a functor of the form <tt>void op(ValueType&, bool&) const</tt> that
465 /// modifies its arguments, a voxel's value and active state, in place
466 /// @par Example:
467 /// @code
468 /// Coord xyz(1, 0, -2);
469 /// // Multiply the value of a voxel by a constant and mark the voxel as inactive.
470 /// floatTree.modifyValueAndActiveState(xyz,
471 /// [](float& f, bool& b) { f *= 0.25; b = false; }); // C++11
472 /// // Set the value of a voxel to the maximum of its current value and 0.25,
473 /// // but don't change the voxel's active state.
474 /// floatTree.modifyValueAndActiveState(xyz,
475 /// [](float& f, bool&) { f = std::max(f, 0.25f); }); // C++11
476 /// @endcode
477 /// @note The functor is not guaranteed to be called only once.
478 /// @see tools::foreach()
479 template<typename ModifyOp>
480 void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op);
481
482 /// @brief Get the value of the voxel at the given coordinates.
483 /// @return @c true if the value is active.
484 bool probeValue(const Coord& xyz, ValueType& value) const;
485
486 /// Return @c true if the value at the given coordinates is active.
487 bool isValueOn(const Coord& xyz) const { return mRoot.isValueOn(xyz); }
488 /// Return @c true if the value at the given coordinates is inactive.
489 bool isValueOff(const Coord& xyz) const { return !this->isValueOn(xyz); }
490 /// Return @c true if this tree has any active tiles.
491 bool hasActiveTiles() const { return mRoot.hasActiveTiles(); }
492
493 /// Set all voxels that lie outside the given axis-aligned box to the background.
494 void clip(const CoordBBox&);
495 /// @brief Replace with background tiles any nodes whose voxel buffers
496 /// have not yet been allocated.
497 /// @details Typically, unallocated nodes are leaf nodes whose voxel buffers
498 /// are not yet resident in memory because delayed loading is in effect.
499 /// @sa readNonresidentBuffers, io::File::open
500 void clipUnallocatedNodes() override;
501
502 /// Return the total number of unallocated leaf nodes residing in this tree.
503#if OPENVDB_ABI_VERSION_NUMBER >= 12
505#else
506 Index32 unallocatedLeafCount() const override;
507#endif
508
509 //@{
510 /// @brief Set all voxels within a given axis-aligned box to a constant value.
511 /// @param bbox inclusive coordinates of opposite corners of an axis-aligned box
512 /// @param value the value to which to set voxels within the box
513 /// @param active if true, mark voxels within the box as active,
514 /// otherwise mark them as inactive
515 /// @note This operation generates a sparse, but not always optimally sparse,
516 /// representation of the filled box. Follow fill operations with a prune()
517 /// operation for optimal sparseness.
518 void sparseFill(const CoordBBox& bbox, const ValueType& value, bool active = true);
519 void fill(const CoordBBox& bbox, const ValueType& value, bool active = true)
520 {
521 this->sparseFill(bbox, value, active);
522 }
523 //@}
524
525 /// @brief Set all voxels within a given axis-aligned box to a constant value
526 /// and ensure that those voxels are all represented at the leaf level.
527 /// @param bbox inclusive coordinates of opposite corners of an axis-aligned box.
528 /// @param value the value to which to set voxels within the box.
529 /// @param active if true, mark voxels within the box as active,
530 /// otherwise mark them as inactive.
531 /// @sa voxelizeActiveTiles()
532 void denseFill(const CoordBBox& bbox, const ValueType& value, bool active = true);
533
534 /// @brief Densify active tiles, i.e., replace them with leaf-level active voxels.
535 ///
536 /// @param threaded if true, this operation is multi-threaded (over the internal nodes).
537 ///
538 /// @warning This method can explode the tree's memory footprint, especially if it
539 /// contains active tiles at the upper levels (in particular the root level)!
540 ///
541 /// @sa denseFill()
542 void voxelizeActiveTiles(bool threaded = true);
543
544 /// @brief Reduce the memory footprint of this tree by replacing with tiles
545 /// any nodes whose values are all the same (optionally to within a tolerance)
546 /// and have the same active state.
547 /// @warning Will soon be deprecated!
548 void prune(const ValueType& tolerance = zeroVal<ValueType>())
549 {
550 this->clearAllAccessors();
551 mRoot.prune(tolerance);
552 }
553
554 /// @brief Add the given leaf node to this tree, creating a new branch if necessary.
555 /// If a leaf node with the same origin already exists, replace it.
556 ///
557 /// @warning Ownership of the leaf is transferred to the tree so
558 /// the client code should not attempt to delete the leaf pointer!
559 void addLeaf(LeafNodeType* leaf) { OPENVDB_ASSERT(leaf); mRoot.addLeaf(leaf); }
560
561 /// @brief Add a tile containing voxel (x, y, z) at the specified tree level,
562 /// creating a new branch if necessary. Delete any existing lower-level nodes
563 /// that contain (x, y, z).
564 /// @note @a level must be less than this tree's depth.
565 void addTile(Index level, const Coord& xyz, const ValueType& value, bool active);
566
567 /// @brief Return a pointer to the node of type @c NodeT that contains voxel (x, y, z)
568 /// and replace it with a tile of the specified value and state.
569 /// If no such node exists, leave the tree unchanged and return @c nullptr.
570 /// @note The caller takes ownership of the node and is responsible for deleting it.
571 template<typename NodeT>
572 NodeT* stealNode(const Coord& xyz, const ValueType& value, bool active);
573
574 /// @brief Return a pointer to the leaf node that contains voxel (x, y, z).
575 /// If no such node exists, create one that preserves the values and
576 /// active states of all voxels.
577 /// @details Use this method to preallocate a static tree topology over which to
578 /// safely perform multithreaded processing.
580
581 //@{
582 /// @brief Return a pointer to the node of type @c NodeType that contains
583 /// voxel (x, y, z). If no such node exists, return @c nullptr.
584 template<typename NodeType> NodeType* probeNode(const Coord& xyz);
585 template<typename NodeType> const NodeType* probeConstNode(const Coord& xyz) const;
586 template<typename NodeType> const NodeType* probeNode(const Coord& xyz) const;
587 //@}
588
589 //@{
590 /// @brief Return a pointer to the leaf node that contains voxel (x, y, z).
591 /// If no such node exists, return @c nullptr.
593 const LeafNodeType* probeConstLeaf(const Coord& xyz) const;
594 const LeafNodeType* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); }
595 //@}
596
597 //@{
598 /// @brief Adds all nodes of a certain type to a container with the following API:
599 /// @code
600 /// struct ArrayT {
601 /// using value_type = ...; // the type of node to be added to the array
602 /// void push_back(value_type nodePtr); // add a node to the array
603 /// };
604 /// @endcode
605 /// @details An example of a wrapper around a c-style array is:
606 /// @code
607 /// struct MyArray {
608 /// using value_type = LeafType*;
609 /// value_type* ptr;
610 /// MyArray(value_type* array) : ptr(array) {}
611 /// void push_back(value_type leaf) { *ptr++ = leaf; }
612 ///};
613 /// @endcode
614 /// @details An example that constructs a list of pointer to all leaf nodes is:
615 /// @code
616 /// std::vector<const LeafNodeType*> array;//most std contains have the required API
617 /// array.reserve(tree.leafCount());//this is a fast preallocation.
618 /// tree.getNodes(array);
619 /// @endcode
620 template<typename ArrayT> void getNodes(ArrayT& array);
621 template<typename ArrayT> void getNodes(ArrayT& array) const;
622 //@}
623
624 /// @brief Steals all nodes of a certain type from the tree and
625 /// adds them to a container with the following API:
626 /// @code
627 /// struct ArrayT {
628 /// using value_type = ...; // the type of node to be added to the array
629 /// void push_back(value_type nodePtr); // add a node to the array
630 /// };
631 /// @endcode
632 /// @details An example of a wrapper around a c-style array is:
633 /// @code
634 /// struct MyArray {
635 /// using value_type = LeafType*;
636 /// value_type* ptr;
637 /// MyArray(value_type* array) : ptr(array) {}
638 /// void push_back(value_type leaf) { *ptr++ = leaf; }
639 ///};
640 /// @endcode
641 /// @details An example that constructs a list of pointer to all leaf nodes is:
642 /// @code
643 /// std::vector<const LeafNodeType*> array;//most std contains have the required API
644 /// array.reserve(tree.leafCount());//this is a fast preallocation.
645 /// tree.stealNodes(array);
646 /// @endcode
647 template<typename ArrayT>
648 void stealNodes(ArrayT& array) { this->clearAllAccessors(); mRoot.stealNodes(array); }
649 template<typename ArrayT>
650 void stealNodes(ArrayT& array, const ValueType& value, bool state)
651 {
652 this->clearAllAccessors();
653 mRoot.stealNodes(array, value, state);
654 }
655
656 //
657 // Aux methods
658 //
659 /// @brief Return @c true if this tree contains no nodes other than
660 /// the root node and no tiles other than background tiles.
661 bool empty() const { return mRoot.empty(); }
662
663 /// Remove all tiles from this tree and all nodes other than the root node.
664 void clear();
665
666 /// @brief Return an accessor that provides random read and write access
667 /// to this tree's voxels.
668 /// @details The accessor is safe in the sense that it is registered with this tree.
670 /// @brief Return an unsafe accessor that provides random read and write access
671 /// to this tree's voxels.
672 /// @details The accessor is unsafe in the sense that it is not registered
673 /// with this tree's tree. In some rare cases this can give a performance advantage
674 /// over a registered accessor, but it is unsafe if the tree topology is modified.
675 /// @warning Only use this method if you're an expert and know the
676 /// risks of using an unregistered accessor (see tree/ValueAccessor.h)
678 /// Return an accessor that provides random read-only access to this tree's voxels.
680 /// Return an accessor that provides random read-only access to this tree's voxels.
682 /// @brief Return an unsafe accessor that provides random read-only access
683 /// to this tree's voxels.
684 /// @details The accessor is unsafe in the sense that it is not registered
685 /// with this tree. In some rare cases this can give a performance advantage
686 /// over a registered accessor, but it is unsafe if the tree topology is modified.
687 /// @warning Only use this method if you're an expert and know the
688 /// risks of using an unregistered accessor (see tree/ValueAccessor.h)
690
691 /// Clear all registered accessors.
693
694 //@{
695 /// @brief Register an accessor for this tree. Registered accessors are
696 /// automatically cleared whenever one of this tree's nodes is deleted.
699 //@}
700
701 //@{
702 /// Dummy implementations
705 //@}
706
707 //@{
708 /// Deregister an accessor so that it is no longer automatically cleared.
711 //@}
712
713 //@{
714 /// Dummy implementations
717 //@}
718
719 /// @brief Return this tree's background value wrapped as metadata.
720 /// @note Query the metadata object for the value's type.
722
723 /// @brief Return this tree's background value.
724 ///
725 /// @note Use tools::changeBackground to efficiently modify the
726 /// background values. Else use tree.root().setBackground, which
727 /// is serial and hence slower.
728 const ValueType& background() const { return mRoot.background(); }
729
730 /// Min and max are both inclusive.
731 void getIndexRange(CoordBBox& bbox) const override { mRoot.getIndexRange(bbox); }
732
733 /// @brief Efficiently merge another tree into this tree using one of several schemes.
734 /// @details This operation is primarily intended to combine trees that are mostly
735 /// non-overlapping (for example, intermediate trees from computations that are
736 /// parallelized across disjoint regions of space).
737 /// @note This operation is not guaranteed to produce an optimally sparse tree.
738 /// Follow merge() with prune() for optimal sparseness.
739 /// @warning This operation always empties the other tree.
741
742 /// @brief Union this tree's set of active values with the active values
743 /// of the other tree, whose @c ValueType may be different.
744 /// @details The resulting state of a value is active if the corresponding value
745 /// was already active OR if it is active in the other tree. Also, a resulting
746 /// value maps to a voxel if the corresponding value already mapped to a voxel
747 /// OR if it is a voxel in the other tree. Thus, a resulting value can only
748 /// map to a tile if the corresponding value already mapped to a tile
749 /// AND if it is a tile value in other tree.
750 ///
751 /// @note This operation modifies only active states, not values.
752 /// Specifically, active tiles and voxels in this tree are not changed, and
753 /// tiles or voxels that were inactive in this tree but active in the other tree
754 /// are marked as active in this tree but left with their original values.
755 ///
756 /// @note If preserveTiles is true, any active tile in this topology
757 /// will not be densified by overlapping child topology.
758 template<typename OtherRootNodeType>
759 void topologyUnion(const Tree<OtherRootNodeType>& other, const bool preserveTiles = false);
760
761 /// @brief Intersects this tree's set of active values with the active values
762 /// of the other tree, whose @c ValueType may be different.
763 /// @details The resulting state of a value is active only if the corresponding
764 /// value was already active AND if it is active in the other tree. Also, a
765 /// resulting value maps to a voxel if the corresponding value
766 /// already mapped to an active voxel in either of the two grids
767 /// and it maps to an active tile or voxel in the other grid.
768 ///
769 /// @note This operation can delete branches in this grid if they
770 /// overlap with inactive tiles in the other grid. Likewise active
771 /// voxels can be turned into inactive voxels resulting in leaf
772 /// nodes with no active values. Thus, it is recommended to
773 /// subsequently call tools::pruneInactive.
774 template<typename OtherRootNodeType>
776
777 /// @brief Difference this tree's set of active values with the active values
778 /// of the other tree, whose @c ValueType may be different. So a
779 /// resulting voxel will be active only if the original voxel is
780 /// active in this tree and inactive in the other tree.
781 ///
782 /// @note This operation can delete branches in this grid if they
783 /// overlap with active tiles in the other grid. Likewise active
784 /// voxels can be turned into inactive voxels resulting in leaf
785 /// nodes with no active values. Thus, it is recommended to
786 /// subsequently call tools::pruneInactive.
787 template<typename OtherRootNodeType>
789
790 /// For a given function @c f, use sparse traversal to compute <tt>f(this, other)</tt>
791 /// over all corresponding pairs of values (tile or voxel) of this tree and the other tree
792 /// and store the result in this tree.
793 /// This method is typically more space-efficient than the two-tree combine2(),
794 /// since it moves rather than copies nodes from the other tree into this tree.
795 /// @note This operation always empties the other tree.
796 /// @param other a tree of the same type as this tree
797 /// @param op a functor of the form <tt>void op(const T& a, const T& b, T& result)</tt>,
798 /// where @c T is this tree's @c ValueType, that computes
799 /// <tt>result = f(a, b)</tt>
800 /// @param prune if true, prune the resulting tree one branch at a time (this is usually
801 /// more space-efficient than pruning the entire tree in one pass)
802 ///
803 /// @par Example:
804 /// Compute the per-voxel difference between two floating-point trees,
805 /// @c aTree and @c bTree, and store the result in @c aTree (leaving @c bTree empty).
806 /// @code
807 /// {
808 /// struct Local {
809 /// static inline void diff(const float& a, const float& b, float& result) {
810 /// result = a - b;
811 /// }
812 /// };
813 /// aTree.combine(bTree, Local::diff);
814 /// }
815 /// @endcode
816 ///
817 /// @par Example:
818 /// Compute <tt>f * a + (1 - f) * b</tt> over all voxels of two floating-point trees,
819 /// @c aTree and @c bTree, and store the result in @c aTree (leaving @c bTree empty).
820 /// @code
821 /// namespace {
822 /// struct Blend {
823 /// Blend(float f): frac(f) {}
824 /// inline void operator()(const float& a, const float& b, float& result) const {
825 /// result = frac * a + (1.0 - frac) * b;
826 /// }
827 /// float frac;
828 /// };
829 /// }
830 /// {
831 /// aTree.combine(bTree, Blend(0.25)); // 0.25 * a + 0.75 * b
832 /// }
833 /// @endcode
834 template<typename CombineOp>
835 void combine(Tree& other, CombineOp& op, bool prune = false);
836 template<typename CombineOp>
837 void combine(Tree& other, const CombineOp& op, bool prune = false);
838
839 /// Like combine(), but with
840 /// @param other a tree of the same type as this tree
841 /// @param op a functor of the form <tt>void op(CombineArgs<ValueType>& args)</tt> that
842 /// computes <tt>args.setResult(f(args.a(), args.b()))</tt> and, optionally,
843 /// <tt>args.setResultIsActive(g(args.aIsActive(), args.bIsActive()))</tt>
844 /// for some functions @c f and @c g
845 /// @param prune if true, prune the resulting tree one branch at a time (this is usually
846 /// more space-efficient than pruning the entire tree in one pass)
847 ///
848 /// This variant passes not only the @em a and @em b values but also the active states
849 /// of the @em a and @em b values to the functor, which may then return, by calling
850 /// @c args.setResultIsActive(), a computed active state for the result value.
851 /// By default, the result is active if either the @em a or the @em b value is active.
852 ///
853 /// @see openvdb/Types.h for the definition of the CombineArgs struct.
854 ///
855 /// @par Example:
856 /// Replace voxel values in floating-point @c aTree with corresponding values
857 /// from floating-point @c bTree (leaving @c bTree empty) wherever the @c bTree
858 /// values are larger. Also, preserve the active states of any transferred values.
859 /// @code
860 /// {
861 /// struct Local {
862 /// static inline void max(CombineArgs<float>& args) {
863 /// if (args.b() > args.a()) {
864 /// // Transfer the B value and its active state.
865 /// args.setResult(args.b());
866 /// args.setResultIsActive(args.bIsActive());
867 /// } else {
868 /// // Preserve the A value and its active state.
869 /// args.setResult(args.a());
870 /// args.setResultIsActive(args.aIsActive());
871 /// }
872 /// }
873 /// };
874 /// aTree.combineExtended(bTree, Local::max);
875 /// }
876 /// @endcode
877 template<typename ExtendedCombineOp>
878 void combineExtended(Tree& other, ExtendedCombineOp& op, bool prune = false);
879 template<typename ExtendedCombineOp>
880 void combineExtended(Tree& other, const ExtendedCombineOp& op, bool prune = false);
881
882 /// For a given function @c f, use sparse traversal to compute <tt>f(a, b)</tt> over all
883 /// corresponding pairs of values (tile or voxel) of trees A and B and store the result
884 /// in this tree.
885 /// @param a,b two trees with the same configuration (levels and node dimensions)
886 /// as this tree but with the B tree possibly having a different value type
887 /// @param op a functor of the form <tt>void op(const T1& a, const T2& b, T1& result)</tt>,
888 /// where @c T1 is this tree's and the A tree's @c ValueType and @c T2 is the
889 /// B tree's @c ValueType, that computes <tt>result = f(a, b)</tt>
890 /// @param prune if true, prune the resulting tree one branch at a time (this is usually
891 /// more space-efficient than pruning the entire tree in one pass)
892 ///
893 /// @throw TypeError if the B tree's configuration doesn't match this tree's
894 /// or if this tree's ValueType is not constructible from the B tree's ValueType.
895 ///
896 /// @par Example:
897 /// Compute the per-voxel difference between two floating-point trees,
898 /// @c aTree and @c bTree, and store the result in a third tree.
899 /// @code
900 /// {
901 /// struct Local {
902 /// static inline void diff(const float& a, const float& b, float& result) {
903 /// result = a - b;
904 /// }
905 /// };
906 /// FloatTree resultTree;
907 /// resultTree.combine2(aTree, bTree, Local::diff);
908 /// }
909 /// @endcode
910 template<typename CombineOp, typename OtherTreeType /*= Tree*/>
911 void combine2(const Tree& a, const OtherTreeType& b, CombineOp& op, bool prune = false);
912 template<typename CombineOp, typename OtherTreeType /*= Tree*/>
913 void combine2(const Tree& a, const OtherTreeType& b, const CombineOp& op, bool prune = false);
914
915 /// Like combine2(), but with
916 /// @param a,b two trees with the same configuration (levels and node dimensions)
917 /// as this tree but with the B tree possibly having a different value type
918 /// @param op a functor of the form <tt>void op(CombineArgs<T1, T2>& args)</tt>, where
919 /// @c T1 is this tree's and the A tree's @c ValueType and @c T2 is the B tree's
920 /// @c ValueType, that computes <tt>args.setResult(f(args.a(), args.b()))</tt>
921 /// and, optionally,
922 /// <tt>args.setResultIsActive(g(args.aIsActive(), args.bIsActive()))</tt>
923 /// for some functions @c f and @c g
924 /// @param prune if true, prune the resulting tree one branch at a time (this is usually
925 /// more space-efficient than pruning the entire tree in one pass)
926 /// This variant passes not only the @em a and @em b values but also the active states
927 /// of the @em a and @em b values to the functor, which may then return, by calling
928 /// <tt>args.setResultIsActive()</tt>, a computed active state for the result value.
929 /// By default, the result is active if either the @em a or the @em b value is active.
930 ///
931 /// @throw TypeError if the B tree's configuration doesn't match this tree's
932 /// or if this tree's ValueType is not constructible from the B tree's ValueType.
933 ///
934 /// @see openvdb/Types.h for the definition of the CombineArgs struct.
935 ///
936 /// @par Example:
937 /// Compute the per-voxel maximum values of two single-precision floating-point trees,
938 /// @c aTree and @c bTree, and store the result in a third tree. Set the active state
939 /// of each output value to that of the larger of the two input values.
940 /// @code
941 /// {
942 /// struct Local {
943 /// static inline void max(CombineArgs<float>& args) {
944 /// if (args.b() > args.a()) {
945 /// // Transfer the B value and its active state.
946 /// args.setResult(args.b());
947 /// args.setResultIsActive(args.bIsActive());
948 /// } else {
949 /// // Preserve the A value and its active state.
950 /// args.setResult(args.a());
951 /// args.setResultIsActive(args.aIsActive());
952 /// }
953 /// }
954 /// };
955 /// FloatTree aTree = ...;
956 /// FloatTree bTree = ...;
957 /// FloatTree resultTree;
958 /// resultTree.combine2Extended(aTree, bTree, Local::max);
959 /// }
960 /// @endcode
961 ///
962 /// @par Example:
963 /// Compute the per-voxel maximum values of a double-precision and a single-precision
964 /// floating-point tree, @c aTree and @c bTree, and store the result in a third,
965 /// double-precision tree. Set the active state of each output value to that of
966 /// the larger of the two input values.
967 /// @code
968 /// {
969 /// struct Local {
970 /// static inline void max(CombineArgs<double, float>& args) {
971 /// if (args.b() > args.a()) {
972 /// // Transfer the B value and its active state.
973 /// args.setResult(args.b());
974 /// args.setResultIsActive(args.bIsActive());
975 /// } else {
976 /// // Preserve the A value and its active state.
977 /// args.setResult(args.a());
978 /// args.setResultIsActive(args.aIsActive());
979 /// }
980 /// }
981 /// };
982 /// DoubleTree aTree = ...;
983 /// FloatTree bTree = ...;
984 /// DoubleTree resultTree;
985 /// resultTree.combine2Extended(aTree, bTree, Local::max);
986 /// }
987 /// @endcode
988 template<typename ExtendedCombineOp, typename OtherTreeType /*= Tree*/>
989 void combine2Extended(const Tree& a, const OtherTreeType& b, ExtendedCombineOp& op,
990 bool prune = false);
991 template<typename ExtendedCombineOp, typename OtherTreeType /*= Tree*/>
992 void combine2Extended(const Tree& a, const OtherTreeType& b, const ExtendedCombineOp&,
993 bool prune = false);
994
995 //
996 // Iteration
997 //
998 //@{
999 /// Return an iterator over children of the root node.
1000 typename RootNodeType::ChildOnCIter beginRootChildren() const { return mRoot.cbeginChildOn(); }
1001 typename RootNodeType::ChildOnCIter cbeginRootChildren() const { return mRoot.cbeginChildOn(); }
1002 typename RootNodeType::ChildOnIter beginRootChildren() { return mRoot.beginChildOn(); }
1003 //@}
1004
1005 //@{
1006 /// Return an iterator over non-child entries of the root node's table.
1007 typename RootNodeType::ChildOffCIter beginRootTiles() const { return mRoot.cbeginChildOff(); }
1008 typename RootNodeType::ChildOffCIter cbeginRootTiles() const { return mRoot.cbeginChildOff(); }
1009 typename RootNodeType::ChildOffIter beginRootTiles() { return mRoot.beginChildOff(); }
1010 //@}
1011
1012 //@{
1013 /// Return an iterator over all entries of the root node's table.
1014 typename RootNodeType::ChildAllCIter beginRootDense() const { return mRoot.cbeginChildAll(); }
1015 typename RootNodeType::ChildAllCIter cbeginRootDense() const { return mRoot.cbeginChildAll(); }
1016 typename RootNodeType::ChildAllIter beginRootDense() { return mRoot.beginChildAll(); }
1017 //@}
1018
1019
1020 //@{
1021 /// Iterator over all nodes in this tree
1024 //@}
1025
1026 //@{
1027 /// Iterator over all leaf nodes in this tree
1030 //@}
1031
1032 //@{
1033 /// Return an iterator over all nodes in this tree.
1034 NodeIter beginNode() { return NodeIter(*this); }
1035 NodeCIter beginNode() const { return NodeCIter(*this); }
1036 NodeCIter cbeginNode() const { return NodeCIter(*this); }
1037 //@}
1038
1039 //@{
1040 /// Return an iterator over all leaf nodes in this tree.
1041 LeafIter beginLeaf() { return LeafIter(*this); }
1042 LeafCIter beginLeaf() const { return LeafCIter(*this); }
1043 LeafCIter cbeginLeaf() const { return LeafCIter(*this); }
1044 //@}
1045
1052
1053 //@{
1054 /// Return an iterator over all values (tile and voxel) across all nodes.
1056 ValueAllCIter beginValueAll() const { return ValueAllCIter(*this); }
1057 ValueAllCIter cbeginValueAll() const { return ValueAllCIter(*this); }
1058 //@}
1059 //@{
1060 /// Return an iterator over active values (tile and voxel) across all nodes.
1062 ValueOnCIter beginValueOn() const { return ValueOnCIter(*this); }
1063 ValueOnCIter cbeginValueOn() const { return ValueOnCIter(*this); }
1064 //@}
1065 //@{
1066 /// Return an iterator over inactive values (tile and voxel) across all nodes.
1068 ValueOffCIter beginValueOff() const { return ValueOffCIter(*this); }
1069 ValueOffCIter cbeginValueOff() const { return ValueOffCIter(*this); }
1070 //@}
1071
1072 /// @brief Return an iterator of type @c IterT (for example, begin<ValueOnIter>() is
1073 /// equivalent to beginValueOn()).
1074 template<typename IterT> IterT begin();
1075 /// @brief Return a const iterator of type CIterT (for example, cbegin<ValueOnCIter>()
1076 /// is equivalent to cbeginValueOn()).
1077 template<typename CIterT> CIterT cbegin() const;
1078
1079
1080protected:
1081 using AccessorRegistry = tbb::concurrent_hash_map<ValueAccessorBase<Tree, true>*, bool>;
1082 using ConstAccessorRegistry = tbb::concurrent_hash_map<ValueAccessorBase<const Tree, true>*, bool>;
1083
1084 /// @brief Notify all registered accessors, by calling ValueAccessor::release(),
1085 /// that this tree is about to be deleted.
1087
1088 // TBB body object used to deallocates nodes in parallel.
1089 template<typename NodeType>
1091 DeallocateNodes(std::vector<NodeType*>& nodes)
1092 : mNodes(nodes.empty() ? nullptr : &nodes.front()) { }
1093 void operator()(const tbb::blocked_range<size_t>& range) const {
1094 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1095 delete mNodes[n]; mNodes[n] = nullptr;
1096 }
1097 }
1098 NodeType ** const mNodes;
1099 };
1100
1101 //
1102 // Data members
1103 //
1104 RootNodeType mRoot; // root node of the tree
1107}; // end of Tree class
1108
1109
1110/// @brief Tree3<T, N1, N2>::Type is the type of a three-level tree
1111/// (Root, Internal, Leaf) with value type T and
1112/// internal and leaf node log dimensions N1 and N2, respectively.
1113/// @note This is NOT the standard tree configuration (Tree4 is).
1114template<typename T, Index N1=4, Index N2=3>
1118
1119
1120/// @brief Tree4<T, N1, N2, N3>::Type is the type of a four-level tree
1121/// (Root, Internal, Internal, Leaf) with value type T and
1122/// internal and leaf node log dimensions N1, N2 and N3, respectively.
1123/// @note This is the standard tree configuration.
1124template<typename T, Index N1=5, Index N2=4, Index N3=3>
1128
1129/// @brief Tree5<T, N1, N2, N3, N4>::Type is the type of a five-level tree
1130/// (Root, Internal, Internal, Internal, Leaf) with value type T and
1131/// internal and leaf node log dimensions N1, N2, N3 and N4, respectively.
1132/// @note This is NOT the standard tree configuration (Tree4 is).
1133template<typename T, Index N1=6, Index N2=5, Index N3=4, Index N4=3>
1138
1139
1140////////////////////////////////////////
1141
1142
1143inline void
1144TreeBase::readTopology(std::istream& is, bool /*saveFloatAsHalf*/)
1145{
1146 int32_t bufferCount;
1147 is.read(reinterpret_cast<char*>(&bufferCount), sizeof(int32_t));
1148 if (bufferCount != 1) OPENVDB_LOG_WARN("multi-buffer trees are no longer supported");
1149}
1150
1151
1152inline void
1153TreeBase::writeTopology(std::ostream& os, bool /*saveFloatAsHalf*/) const
1154{
1155 int32_t bufferCount = 1;
1156 os.write(reinterpret_cast<char*>(&bufferCount), sizeof(int32_t));
1157}
1158
1159
1160inline void
1161TreeBase::print(std::ostream& os, int /*verboseLevel*/) const
1162{
1163 os << " Tree Type: " << type()
1164 << " Active Voxel Count: " << activeVoxelCount() << std::endl
1165 << " Active tile Count: " << activeTileCount() << std::endl
1166 << " Inactive Voxel Count: " << inactiveVoxelCount() << std::endl
1167 << " Leaf Node Count: " << leafCount() << std::endl
1168 << " Non-leaf Node Count: " << nonLeafCount() << std::endl;
1169}
1170
1171
1172////////////////////////////////////////
1173
1174
1175//
1176// Type traits for tree iterators
1177//
1178
1179/// @brief TreeIterTraits provides, for all tree iterators, a begin(tree) function
1180/// that returns an iterator over a tree of arbitrary type.
1181template<typename TreeT, typename IterT> struct TreeIterTraits;
1182
1183template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::RootNodeType::ChildOnIter> {
1184 static typename TreeT::RootNodeType::ChildOnIter begin(TreeT& tree) {
1185 return tree.beginRootChildren();
1186 }
1187};
1188
1189template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::RootNodeType::ChildOnCIter> {
1190 static typename TreeT::RootNodeType::ChildOnCIter begin(const TreeT& tree) {
1191 return tree.cbeginRootChildren();
1192 }
1193};
1194
1195template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::RootNodeType::ChildOffIter> {
1196 static typename TreeT::RootNodeType::ChildOffIter begin(TreeT& tree) {
1197 return tree.beginRootTiles();
1198 }
1199};
1200
1201template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::RootNodeType::ChildOffCIter> {
1202 static typename TreeT::RootNodeType::ChildOffCIter begin(const TreeT& tree) {
1203 return tree.cbeginRootTiles();
1204 }
1205};
1206
1207template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::RootNodeType::ChildAllIter> {
1208 static typename TreeT::RootNodeType::ChildAllIter begin(TreeT& tree) {
1209 return tree.beginRootDense();
1210 }
1211};
1212
1213template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::RootNodeType::ChildAllCIter> {
1214 static typename TreeT::RootNodeType::ChildAllCIter begin(const TreeT& tree) {
1215 return tree.cbeginRootDense();
1216 }
1217};
1218
1219template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::NodeIter> {
1220 static typename TreeT::NodeIter begin(TreeT& tree) { return tree.beginNode(); }
1221};
1222
1223template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::NodeCIter> {
1224 static typename TreeT::NodeCIter begin(const TreeT& tree) { return tree.cbeginNode(); }
1225};
1226
1227template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::LeafIter> {
1228 static typename TreeT::LeafIter begin(TreeT& tree) { return tree.beginLeaf(); }
1229};
1230
1231template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::LeafCIter> {
1232 static typename TreeT::LeafCIter begin(const TreeT& tree) { return tree.cbeginLeaf(); }
1233};
1234
1235template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::ValueOnIter> {
1236 static typename TreeT::ValueOnIter begin(TreeT& tree) { return tree.beginValueOn(); }
1237};
1238
1239template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::ValueOnCIter> {
1240 static typename TreeT::ValueOnCIter begin(const TreeT& tree) { return tree.cbeginValueOn(); }
1241};
1242
1243template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::ValueOffIter> {
1244 static typename TreeT::ValueOffIter begin(TreeT& tree) { return tree.beginValueOff(); }
1245};
1246
1247template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::ValueOffCIter> {
1248 static typename TreeT::ValueOffCIter begin(const TreeT& tree) { return tree.cbeginValueOff(); }
1249};
1250
1251template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::ValueAllIter> {
1252 static typename TreeT::ValueAllIter begin(TreeT& tree) { return tree.beginValueAll(); }
1253};
1254
1255template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::ValueAllCIter> {
1256 static typename TreeT::ValueAllCIter begin(const TreeT& tree) { return tree.cbeginValueAll(); }
1257};
1258
1259
1260template<typename RootNodeType>
1261template<typename IterT>
1262inline IterT
1267
1268
1269template<typename RootNodeType>
1270template<typename IterT>
1271inline IterT
1276
1277
1278////////////////////////////////////////
1279
1280
1281template<typename RootNodeType>
1282void
1283Tree<RootNodeType>::readTopology(std::istream& is, bool saveFloatAsHalf)
1284{
1285 this->clearAllAccessors();
1286 TreeBase::readTopology(is, saveFloatAsHalf);
1287 mRoot.readTopology(is, saveFloatAsHalf);
1288}
1289
1290
1291template<typename RootNodeType>
1292void
1293Tree<RootNodeType>::writeTopology(std::ostream& os, bool saveFloatAsHalf) const
1294{
1295 TreeBase::writeTopology(os, saveFloatAsHalf);
1296 mRoot.writeTopology(os, saveFloatAsHalf);
1297}
1298
1299
1300template<typename RootNodeType>
1301inline void
1302Tree<RootNodeType>::readBuffers(std::istream &is, bool saveFloatAsHalf)
1303{
1304 this->clearAllAccessors();
1305 mRoot.readBuffers(is, saveFloatAsHalf);
1306}
1307
1308
1309template<typename RootNodeType>
1310inline void
1311Tree<RootNodeType>::readBuffers(std::istream &is, const CoordBBox& bbox, bool saveFloatAsHalf)
1312{
1313 this->clearAllAccessors();
1314 mRoot.readBuffers(is, bbox, saveFloatAsHalf);
1315}
1316
1317
1318template<typename RootNodeType>
1319inline void
1321{
1322 for (LeafCIter it = this->cbeginLeaf(); it; ++it) {
1323 // Retrieving the value of a leaf voxel forces loading of the leaf node's voxel buffer.
1324 it->getValue(Index(0));
1325 }
1326}
1327
1328
1329template<typename RootNodeType>
1330inline void
1331Tree<RootNodeType>::writeBuffers(std::ostream &os, bool saveFloatAsHalf) const
1332{
1333 mRoot.writeBuffers(os, saveFloatAsHalf);
1334}
1335
1336
1337template<typename RootNodeType>
1338template<typename ArrayT>
1339inline void
1341{
1342 using NodeT = typename std::remove_pointer<typename ArrayT::value_type>::type;
1343 static_assert(!std::is_same<NodeT, RootNodeType>::value,
1344 "getNodes() does not work for the RootNode. Use Tree::root()");
1345 mRoot.getNodes(array);
1346}
1347
1348
1349template<typename RootNodeType>
1350template<typename ArrayT>
1351inline void
1353{
1354 using NodeT = typename std::remove_pointer<typename ArrayT::value_type>::type;
1355 static_assert(!std::is_same<NodeT, const RootNodeType>::value,
1356 "getNodes() does not work for the RootNode. Use Tree::root()");
1357 mRoot.getNodes(array);
1358}
1359
1360
1361template<typename RootNodeType>
1362inline void
1364{
1365 std::vector<LeafNodeType*> leafnodes;
1366 this->stealNodes(leafnodes);
1367
1368 tbb::parallel_for(tbb::blocked_range<size_t>(0, leafnodes.size()),
1370
1371 std::vector<typename RootNodeType::ChildNodeType*> internalNodes;
1372 this->stealNodes(internalNodes);
1373
1374 tbb::parallel_for(tbb::blocked_range<size_t>(0, internalNodes.size()),
1376
1377 mRoot.clear();
1378
1379 this->clearAllAccessors();
1380}
1381
1382
1383////////////////////////////////////////
1384
1385
1386template<typename RootNodeType>
1389{
1390 return Accessor(*this);
1391}
1392
1393template<typename RootNodeType>
1399
1400template<typename RootNodeType>
1403{
1404 return ConstAccessor(*this);
1405}
1406
1407template<typename RootNodeType>
1410{
1411 return ConstAccessor(*this);
1412}
1413
1414template<typename RootNodeType>
1420
1421template<typename RootNodeType>
1422inline void
1424{
1425 typename AccessorRegistry::accessor a;
1426 mAccessorRegistry.insert(a, &accessor);
1427}
1428
1429
1430template<typename RootNodeType>
1431inline void
1433{
1434 typename ConstAccessorRegistry::accessor a;
1435 mConstAccessorRegistry.insert(a, &accessor);
1436}
1437
1438
1439template<typename RootNodeType>
1440inline void
1445
1446
1447template<typename RootNodeType>
1448inline void
1453
1454
1455template<typename RootNodeType>
1456inline void
1458{
1459 for (typename AccessorRegistry::iterator it = mAccessorRegistry.begin();
1460 it != mAccessorRegistry.end(); ++it)
1461 {
1462 if (it->first) it->first->clear();
1463 }
1464
1465 for (typename ConstAccessorRegistry::iterator it = mConstAccessorRegistry.begin();
1466 it != mConstAccessorRegistry.end(); ++it)
1467 {
1468 if (it->first) it->first->clear();
1469 }
1470}
1471
1472
1473template<typename RootNodeType>
1474inline void
1476{
1477 mAccessorRegistry.erase(nullptr);
1478 for (typename AccessorRegistry::iterator it = mAccessorRegistry.begin();
1479 it != mAccessorRegistry.end(); ++it)
1480 {
1481 it->first->release();
1482 }
1483 mAccessorRegistry.clear();
1484
1485 mAccessorRegistry.erase(nullptr);
1486 for (typename ConstAccessorRegistry::iterator it = mConstAccessorRegistry.begin();
1487 it != mConstAccessorRegistry.end(); ++it)
1488 {
1489 it->first->release();
1490 }
1491 mConstAccessorRegistry.clear();
1492}
1493
1494
1495////////////////////////////////////////
1496
1497
1498template<typename RootNodeType>
1499inline const typename RootNodeType::ValueType&
1501{
1502 return mRoot.getValue(xyz);
1503}
1504
1505
1506template<typename RootNodeType>
1507template<typename AccessT>
1508inline const typename RootNodeType::ValueType&
1509Tree<RootNodeType>::getValue(const Coord& xyz, AccessT& accessor) const
1510{
1511 return accessor.getValue(xyz);
1512}
1513
1514
1515template<typename RootNodeType>
1516inline int
1518{
1519 return mRoot.getValueDepth(xyz);
1520}
1521
1522
1523template<typename RootNodeType>
1524inline void
1526{
1527 mRoot.setValueOff(xyz);
1528}
1529
1530
1531template<typename RootNodeType>
1532inline void
1534{
1535 mRoot.setValueOff(xyz, value);
1536}
1537
1538
1539template<typename RootNodeType>
1540inline void
1542{
1543 mRoot.setActiveState(xyz, on);
1544}
1545
1546
1547template<typename RootNodeType>
1548inline void
1550{
1551 mRoot.setValueOn(xyz, value);
1552}
1553
1554template<typename RootNodeType>
1555inline void
1557{
1558 mRoot.setValueOnly(xyz, value);
1559}
1560
1561template<typename RootNodeType>
1562template<typename AccessT>
1563inline void
1564Tree<RootNodeType>::setValue(const Coord& xyz, const ValueType& value, AccessT& accessor)
1565{
1566 accessor.setValue(xyz, value);
1567}
1568
1569
1570template<typename RootNodeType>
1571inline void
1573{
1574 mRoot.setActiveState(xyz, true);
1575}
1576
1577
1578template<typename RootNodeType>
1579inline void
1581{
1582 mRoot.setValueOn(xyz, value);
1583}
1584
1585
1586template<typename RootNodeType>
1587template<typename ModifyOp>
1588inline void
1589Tree<RootNodeType>::modifyValue(const Coord& xyz, const ModifyOp& op)
1590{
1591 mRoot.modifyValue(xyz, op);
1592}
1593
1594
1595template<typename RootNodeType>
1596template<typename ModifyOp>
1597inline void
1599{
1600 mRoot.modifyValueAndActiveState(xyz, op);
1601}
1602
1603
1604template<typename RootNodeType>
1605inline bool
1607{
1608 return mRoot.probeValue(xyz, value);
1609}
1610
1611
1612////////////////////////////////////////
1613
1614
1615template<typename RootNodeType>
1616inline void
1618 const ValueType& value, bool active)
1619{
1620 mRoot.addTile(level, xyz, value, active);
1621}
1622
1623
1624template<typename RootNodeType>
1625template<typename NodeT>
1626inline NodeT*
1627Tree<RootNodeType>::stealNode(const Coord& xyz, const ValueType& value, bool active)
1628{
1629 this->clearAllAccessors();
1630 return mRoot.template stealNode<NodeT>(xyz, value, active);
1631}
1632
1633
1634template<typename RootNodeType>
1635inline typename RootNodeType::LeafNodeType*
1637{
1638 return mRoot.touchLeaf(xyz);
1639}
1640
1641
1642template<typename RootNodeType>
1643inline typename RootNodeType::LeafNodeType*
1645{
1646 return mRoot.probeLeaf(xyz);
1647}
1648
1649
1650template<typename RootNodeType>
1651inline const typename RootNodeType::LeafNodeType*
1653{
1654 return mRoot.probeConstLeaf(xyz);
1655}
1656
1657
1658template<typename RootNodeType>
1659template<typename NodeType>
1660inline NodeType*
1662{
1663 return mRoot.template probeNode<NodeType>(xyz);
1664}
1665
1666
1667template<typename RootNodeType>
1668template<typename NodeType>
1669inline const NodeType*
1671{
1672 return this->template probeConstNode<NodeType>(xyz);
1673}
1674
1675
1676template<typename RootNodeType>
1677template<typename NodeType>
1678inline const NodeType*
1680{
1681 return mRoot.template probeConstNode<NodeType>(xyz);
1682}
1683
1684
1685////////////////////////////////////////
1686
1687
1688template<typename RootNodeType>
1689inline void
1691{
1692 this->clearAllAccessors();
1693 return mRoot.clip(bbox);
1694}
1695
1696
1697template<typename RootNodeType>
1698inline void
1700{
1701 this->clearAllAccessors();
1702 for (LeafIter it = this->beginLeaf(); it; ) {
1703 const LeafNodeType* leaf = it.getLeaf();
1704 ++it; // advance the iterator before deleting the leaf node
1705 if (!leaf->isAllocated()) {
1706 this->addTile(/*level=*/0, leaf->origin(), this->background(), /*active=*/false);
1707 }
1708 }
1709}
1710
1711#if OPENVDB_ABI_VERSION_NUMBER >= 12
1712template<typename RootNodeType>
1713inline Index64
1715{
1716 Index64 sum = 0;
1717 for (auto it = this->cbeginLeaf(); it; ++it) if (!it->isAllocated()) ++sum;
1718 return sum;
1719}
1720#else
1721template<typename RootNodeType>
1722inline Index32
1724{
1725 Index32 sum = 0;
1726 for (auto it = this->cbeginLeaf(); it; ++it) if (!it->isAllocated()) ++sum;
1727 return sum;
1728}
1729#endif
1730
1731
1732template<typename RootNodeType>
1733inline void
1734Tree<RootNodeType>::sparseFill(const CoordBBox& bbox, const ValueType& value, bool active)
1735{
1736 this->clearAllAccessors();
1737 return mRoot.sparseFill(bbox, value, active);
1738}
1739
1740
1741template<typename RootNodeType>
1742inline void
1743Tree<RootNodeType>::denseFill(const CoordBBox& bbox, const ValueType& value, bool active)
1744{
1745 this->clearAllAccessors();
1746 return mRoot.denseFill(bbox, value, active);
1747}
1748
1749
1750template<typename RootNodeType>
1751inline void
1753{
1754 this->clearAllAccessors();
1755 mRoot.voxelizeActiveTiles(threaded);
1756}
1757
1758
1759template<typename RootNodeType>
1762{
1763 Metadata::Ptr result;
1765 using MetadataT = TypedMetadata<ValueType>;
1767 if (result->typeName() == MetadataT::staticTypeName()) {
1768 MetadataT* m = static_cast<MetadataT*>(result.get());
1769 m->value() = mRoot.background();
1770 }
1771 }
1772 return result;
1773}
1774
1775
1776////////////////////////////////////////
1777
1778
1779template<typename RootNodeType>
1780inline void
1782{
1783 this->clearAllAccessors();
1784 other.clearAllAccessors();
1785 switch (policy) {
1787 mRoot.template merge<MERGE_ACTIVE_STATES>(other.mRoot); break;
1788 case MERGE_NODES:
1789 mRoot.template merge<MERGE_NODES>(other.mRoot); break;
1791 mRoot.template merge<MERGE_ACTIVE_STATES_AND_NODES>(other.mRoot); break;
1792 }
1793}
1794
1795
1796template<typename RootNodeType>
1797template<typename OtherRootNodeType>
1798inline void
1799Tree<RootNodeType>::topologyUnion(const Tree<OtherRootNodeType>& other, const bool preserveTiles)
1800{
1801 this->clearAllAccessors();
1802 mRoot.topologyUnion(other.root(), preserveTiles);
1803}
1804
1805template<typename RootNodeType>
1806template<typename OtherRootNodeType>
1807inline void
1809{
1810 this->clearAllAccessors();
1811 mRoot.topologyIntersection(other.root());
1812}
1813
1814template<typename RootNodeType>
1815template<typename OtherRootNodeType>
1816inline void
1818{
1819 this->clearAllAccessors();
1820 mRoot.topologyDifference(other.root());
1821}
1822
1823////////////////////////////////////////
1824
1825
1826/// @brief Helper class to adapt a three-argument (a, b, result) CombineOp functor
1827/// into a single-argument functor that accepts a CombineArgs struct
1828template<typename AValueT, typename CombineOp, typename BValueT = AValueT>
1830{
1831 CombineOpAdapter(CombineOp& _op): op(_op) {}
1832
1834 op(args.a(), args.b(), args.result());
1835 }
1836
1837 CombineOp& op;
1838};
1839
1840
1841template<typename RootNodeType>
1842template<typename CombineOp>
1843inline void
1844Tree<RootNodeType>::combine(Tree& other, CombineOp& op, bool prune)
1845{
1847 this->combineExtended(other, extendedOp, prune);
1848}
1849
1850
1851/// @internal This overload is needed (for ICC and GCC, but not for VC) to disambiguate
1852/// code like this: <tt>aTree.combine(bTree, MyCombineOp(...))</tt>.
1853template<typename RootNodeType>
1854template<typename CombineOp>
1855inline void
1856Tree<RootNodeType>::combine(Tree& other, const CombineOp& op, bool prune)
1857{
1859 this->combineExtended(other, extendedOp, prune);
1860}
1861
1862
1863template<typename RootNodeType>
1864template<typename ExtendedCombineOp>
1865inline void
1866Tree<RootNodeType>::combineExtended(Tree& other, ExtendedCombineOp& op, bool prune)
1867{
1868 this->clearAllAccessors();
1869 mRoot.combine(other.root(), op, prune);
1870}
1871
1872
1873/// @internal This overload is needed (for ICC and GCC, but not for VC) to disambiguate
1874/// code like this: <tt>aTree.combineExtended(bTree, MyCombineOp(...))</tt>.
1875template<typename RootNodeType>
1876template<typename ExtendedCombineOp>
1877inline void
1878Tree<RootNodeType>::combineExtended(Tree& other, const ExtendedCombineOp& op, bool prune)
1879{
1880 this->clearAllAccessors();
1882}
1883
1884
1885template<typename RootNodeType>
1886template<typename CombineOp, typename OtherTreeType>
1887inline void
1888Tree<RootNodeType>::combine2(const Tree& a, const OtherTreeType& b, CombineOp& op, bool prune)
1889{
1891 this->combine2Extended(a, b, extendedOp, prune);
1892}
1893
1894
1895/// @internal This overload is needed (for ICC and GCC, but not for VC) to disambiguate
1896/// code like this: <tt>tree.combine2(aTree, bTree, MyCombineOp(...))</tt>.
1897template<typename RootNodeType>
1898template<typename CombineOp, typename OtherTreeType>
1899inline void
1900Tree<RootNodeType>::combine2(const Tree& a, const OtherTreeType& b, const CombineOp& op, bool prune)
1901{
1903 this->combine2Extended(a, b, extendedOp, prune);
1904}
1905
1906
1907template<typename RootNodeType>
1908template<typename ExtendedCombineOp, typename OtherTreeType>
1909inline void
1910Tree<RootNodeType>::combine2Extended(const Tree& a, const OtherTreeType& b,
1911 ExtendedCombineOp& op, bool prune)
1912{
1913 this->clearAllAccessors();
1914 mRoot.combine2(a.root(), b.root(), op, prune);
1915}
1916
1917
1918/// @internal This overload is needed (for ICC and GCC, but not for VC) to disambiguate
1919/// code like the following, where the functor argument is a temporary:
1920/// <tt>tree.combine2Extended(aTree, bTree, MyCombineOp(...))</tt>.
1921template<typename RootNodeType>
1922template<typename ExtendedCombineOp, typename OtherTreeType>
1923inline void
1924Tree<RootNodeType>::combine2Extended(const Tree& a, const OtherTreeType& b,
1925 const ExtendedCombineOp& op, bool prune)
1926{
1927 this->clearAllAccessors();
1928 mRoot.template combine2<const ExtendedCombineOp>(a.root(), b.root(), op, prune);
1929}
1930
1931
1932////////////////////////////////////////
1933
1934
1935template<typename RootNodeType>
1936inline const Name&
1938{
1939 static std::string sTreeTypeName = []()
1940 {
1941 // @todo use RootNode::NodeChain::foreach() instead
1942 std::vector<Index> dims;
1944 std::ostringstream ostr;
1945 ostr << "Tree_" << typeNameAsString<BuildType>();
1946 for (size_t i = 1, N = dims.size(); i < N; ++i) { // start from 1 to skip the RootNode
1947 ostr << "_" << dims[i];
1948 }
1949 return ostr.str();
1950 }();
1951 return sTreeTypeName;
1952}
1953
1954
1955template<typename RootNodeType>
1956template<typename OtherRootNodeType>
1957inline bool
1959{
1960 return mRoot.hasSameTopology(other.root());
1961}
1962
1963
1964template<typename RootNodeType>
1965inline bool
1967{
1968 bbox.reset(); // default invalid bbox
1969
1970 if (this->empty()) return false; // empty
1971
1972 mRoot.evalActiveBoundingBox(bbox, false);
1973
1974 return !bbox.empty();
1975}
1976
1977template<typename RootNodeType>
1978inline bool
1980{
1981 bbox.reset(); // default invalid bbox
1982
1983 if (this->empty()) return false; // empty
1984
1985 mRoot.evalActiveBoundingBox(bbox, true);
1986
1987 return !bbox.empty();
1988}
1989
1990
1991template<typename RootNodeType>
1992inline bool
1994{
1995 CoordBBox bbox;
1996 bool notEmpty = this->evalActiveVoxelBoundingBox(bbox);
1997 dim = bbox.extents();
1998 return notEmpty;
1999}
2000
2001
2002template<typename RootNodeType>
2003inline bool
2005{
2006 CoordBBox bbox;
2007 bool notEmpty = this->evalLeafBoundingBox(bbox);
2008 dim = bbox.extents();
2009 return notEmpty;
2010}
2011
2012
2013template<typename RootNodeType>
2014inline void
2016{
2017 dims.clear();
2018 RootNodeType::getNodeLog2Dims(dims);
2019}
2020
2021
2022template<typename RootNodeType>
2023inline void
2024Tree<RootNodeType>::print(std::ostream& os, int verboseLevel) const
2025{
2026 if (verboseLevel <= 0) return;
2027
2028 /// @todo Consider using boost::io::ios_precision_saver instead.
2029 struct OnExit {
2030 std::ostream& os;
2031 std::streamsize savedPrecision;
2032 OnExit(std::ostream& _os): os(_os), savedPrecision(os.precision()) {}
2033 ~OnExit() { os.precision(savedPrecision); }
2034 };
2035 OnExit restorePrecision(os);
2036
2037 std::vector<Index> dims;
2038 Tree::getNodeLog2Dims(dims);// leaf is the last element
2039
2040 os << "Information about Tree:\n"
2041 << " Type: " << this->type() << "\n";
2042
2043 os << " Configuration:\n";
2044
2045 if (verboseLevel <= 1) {
2046 // Print node types and sizes.
2047 os << " Root(" << mRoot.getTableSize() << ")";
2048 if (dims.size() > 1) {
2049 for (size_t i = 1, N = dims.size() - 1; i < N; ++i) {
2050 os << ", Internal(" << (1 << dims[i]) << "^3)";
2051 }
2052 os << ", Leaf(" << (1 << dims.back()) << "^3)\n";
2053 }
2054 os << " Background value: " << mRoot.background() << "\n";
2055 return;
2056 }
2057
2058 // The following is tree information that is expensive to extract.
2059
2060 ValueType minVal = zeroVal<ValueType>(), maxVal = zeroVal<ValueType>();
2061 if (verboseLevel > 3) {
2062 // This forces loading of all non-resident nodes.
2063 const math::MinMax<ValueType> extrema = tools::minMax(*this);
2064 minVal = extrema.min();
2065 maxVal = extrema.max();
2066 }
2067
2068 const auto nodeCount = this->nodeCount();//fast
2069 const Index64 leafCount = nodeCount.front();// leaf is the first element
2070 OPENVDB_ASSERT(dims.size() == nodeCount.size());
2071
2072 Index64 totalNodeCount = 0;
2073 for (size_t i = 0; i < nodeCount.size(); ++i) totalNodeCount += nodeCount[i];
2074
2075 // Print node types, counts and sizes.
2076 os << " Root(1 x " << mRoot.getTableSize() << ")";
2077 if (dims.size() >= 2) {
2078 for (size_t i = 1, N = dims.size() - 1; i < N; ++i) {
2079 os << ", Internal(" << util::formattedInt(nodeCount[N - i]);
2080 os << " x " << (1 << dims[i]) << "^3)";
2081 }
2082 os << ", Leaf(" << util::formattedInt(leafCount);
2083 os << " x " << (1 << dims.back()) << "^3)\n";
2084 }
2085 os << " Background value: " << mRoot.background() << "\n";
2086
2087 // Statistics of topology and values
2088
2089 if (verboseLevel > 3) {
2090 os << " Min value: " << minVal << "\n";
2091 os << " Max value: " << maxVal << "\n";
2092 }
2093
2094 const Index64
2095 numActiveVoxels = this->activeVoxelCount(),
2096 numActiveLeafVoxels = this->activeLeafVoxelCount(),
2097 numActiveTiles = this->activeTileCount();
2098
2099 os << " Number of active voxels: " << util::formattedInt(numActiveVoxels) << "\n";
2100 os << " Number of active tiles: " << util::formattedInt(numActiveTiles) << "\n";
2101
2102 Coord dim(0, 0, 0);
2103 Index64 totalVoxels = 0;
2104 if (numActiveVoxels) { // nonempty
2105 CoordBBox bbox;
2106 this->evalActiveVoxelBoundingBox(bbox);
2107 dim = bbox.extents();
2108 totalVoxels = dim.x() * uint64_t(dim.y()) * dim.z();
2109
2110 os << " Bounding box of active voxels: " << bbox << "\n";
2111 os << " Dimensions of active voxels: "
2112 << dim[0] << " x " << dim[1] << " x " << dim[2] << "\n";
2113
2114 const double activeRatio = (100.0 * double(numActiveVoxels)) / double(totalVoxels);
2115 os << " Percentage of active voxels: " << std::setprecision(3) << activeRatio << "%\n";
2116
2117 if (leafCount > 0) {
2118 const double fillRatio = (100.0 * double(numActiveLeafVoxels))
2119 / (double(leafCount) * double(LeafNodeType::NUM_VOXELS));
2120 os << " Average leaf node fill ratio: " << fillRatio << "%\n";
2121 }
2122
2123 if (verboseLevel > 2) {
2124 Index64 sum = 0;// count the number of unallocated leaf nodes
2125 for (auto it = this->cbeginLeaf(); it; ++it) if (!it->isAllocated()) ++sum;
2126 os << " Number of unallocated nodes: "
2127 << util::formattedInt(sum) << " ("
2128 << (100.0 * double(sum) / double(totalNodeCount)) << "%)\n";
2129 }
2130 } else {
2131 os << " Tree is empty!\n";
2132 }
2133 os << std::flush;
2134
2135 if (verboseLevel == 2) return;
2136
2137 // Memory footprint in bytes
2138 const Index64
2139 actualMem = this->memUsage(),
2140 denseMem = sizeof(ValueType) * totalVoxels,
2141 voxelsMem = sizeof(ValueType) * numActiveLeafVoxels;
2142 ///< @todo not accurate for BoolTree (and probably should count tile values)
2143
2144 os << "Memory footprint:\n";
2145 util::printBytes(os, actualMem, " Actual: ");
2146 util::printBytes(os, voxelsMem, " Active leaf voxels: ");
2147
2148 if (numActiveVoxels) {
2149 util::printBytes(os, denseMem, " Dense equivalent: ");
2150 os << " Actual footprint is " << (100.0 * double(actualMem) / double(denseMem))
2151 << "% of an equivalent dense volume\n";
2152 os << " Leaf voxel footprint is " << (100.0 * double(voxelsMem) / double(actualMem))
2153 << "% of actual footprint\n";
2154 }
2155}
2156
2157} // namespace tree
2158} // namespace OPENVDB_VERSION_NAME
2159} // namespace openvdb
2160
2161#endif // OPENVDB_TREE_TREE_HAS_BEEN_INCLUDED
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
Functions to count tiles, nodes or voxels in a grid.
Utility routines to output nicely-formatted numeric values.
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
#define OPENVDB_NO_DEPRECATION_WARNING_END
Definition Platform.h:218
#define OPENVDB_NO_DEPRECATION_WARNING_BEGIN
Bracket code with OPENVDB_NO_DEPRECATION_WARNING_BEGIN/_END, to inhibit warnings about deprecated cod...
Definition Platform.h:217
#define OPENVDB_API
Definition Platform.h:291
The root node of an OpenVDB tree.
ValueAccessors are designed to help accelerate accesses into the OpenVDB Tree structures by storing c...
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition Types.h:640
const AValueType & result() const
Get the output value.
Definition Types.h:684
const BValueType & b() const
Get the B input value.
Definition Types.h:681
const AValueType & a() const
Get the A input value.
Definition Types.h:679
static Metadata::Ptr createMetadata(const Name &typeName)
Create new metadata of the given type.
static bool isRegisteredType(const Name &typeName)
Return true if the given type is known by the metadata type registry.
SharedPtr< Metadata > Ptr
Definition Metadata.h:27
Definition Exceptions.h:61
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition Types.h:754
Templated metadata class to hold specific types.
Definition Metadata.h:123
Axis-aligned bounding box of signed integer coordinates.
Definition Coord.h:252
Coord extents() const
Definition Coord.h:385
bool empty() const
Return true if this bounding box is empty (i.e., encloses no coordinates).
Definition Coord.h:359
void reset()
Definition Coord.h:330
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
Int32 y() const
Definition Coord.h:132
Int32 x() const
Definition Coord.h:131
Int32 z() const
Definition Coord.h:133
double min() const
Return the minimum value.
Definition Stats.h:122
double max() const
Return the maximum value.
Definition Stats.h:125
Templated class to compute the minimum and maximum values.
Definition Stats.h:32
Base class for tree-traversal iterators over all leaf nodes (but not leaf voxels)
Definition TreeIterator.h:1188
Base class for tree-traversal iterators over all nodes.
Definition TreeIterator.h:937
virtual Name valueType() const =0
Return the name of the type of a voxel's value (e.g., "float" or "vec3d").
virtual const Name & type() const =0
Return the name of this tree's type.
virtual void writeTopology(std::ostream &, bool saveFloatAsHalf=false) const
Write the tree topology to a stream.
Definition Tree.h:1153
virtual Index64 unallocatedLeafCount() const =0
Return the total number of unallocated leaf nodes residing in this tree.
virtual Index64 activeLeafVoxelCount() const =0
Return the number of active voxels stored in leaf nodes.
virtual std::vector< Index64 > nodeCount() const =0
virtual void readBuffers(std::istream &, bool saveFloatAsHalf=false)=0
Read all data buffers for this tree.
bool isType() const
Return true if this tree is of the same type as the template parameter.
Definition Tree.h:56
virtual void writeBuffers(std::ostream &, bool saveFloatAsHalf=false) const =0
Write out all the data buffers for this tree.
virtual Index64 leafCount() const =0
Return the number of leaf nodes.
virtual Metadata::Ptr getBackgroundValue() const
Return this tree's background value wrapped as metadata.
Definition Tree.h:66
virtual Index64 nonLeafCount() const =0
Return the number of non-leaf nodes.
virtual void print(std::ostream &os=std::cout, int verboseLevel=1) const
Print statistics, memory usage and other information about this tree.
Definition Tree.h:1161
virtual void readBuffers(std::istream &, const CoordBBox &, bool saveFloatAsHalf=false)=0
Read all of this tree's data buffers that intersect the given bounding box.
virtual void getIndexRange(CoordBBox &bbox) const =0
virtual Index64 activeVoxelCount() const =0
Return the total number of active voxels.
virtual Index64 inactiveVoxelCount() const =0
Return the number of inactive voxels within the bounding box of all active voxels.
virtual void clipUnallocatedNodes()=0
Replace with background tiles any nodes whose voxel buffers have not yet been allocated.
virtual void readNonresidentBuffers() const =0
Read all of this tree's data buffers that are not yet resident in memory (because delayed loading is ...
virtual Index64 inactiveLeafVoxelCount() const =0
Return the number of inactive voxels stored in leaf nodes.
virtual Index64 memUsage() const
Return the total amount of memory in bytes occupied by this tree.
Definition Tree.h:151
virtual TreeBase::Ptr copy() const =0
Return a pointer to a deep copy of this tree.
SharedPtr< TreeBase > Ptr
Definition Tree.h:40
virtual bool evalLeafDim(Coord &dim) const =0
Return in dim the dimensions of the axis-aligned bounding box of all leaf nodes.
virtual bool evalActiveVoxelBoundingBox(CoordBBox &bbox) const =0
Return in bbox the axis-aligned bounding box of all active voxels and tiles.
virtual Index treeDepth() const =0
Return the depth of this tree.
virtual Index64 activeTileCount() const =0
Return the total number of active tiles.
SharedPtr< const TreeBase > ConstPtr
Definition Tree.h:41
virtual bool evalActiveVoxelDim(Coord &dim) const =0
Return in dim the dimensions of the axis-aligned bounding box of all active voxels....
virtual bool evalLeafBoundingBox(CoordBBox &bbox) const =0
Return in bbox the axis-aligned bounding box of all active tiles and leaf nodes with active values.
TreeBase & operator=(const TreeBase &)=delete
TreeBase(const TreeBase &)=default
virtual void readTopology(std::istream &, bool saveFloatAsHalf=false)
Read the tree topology from a stream.
Definition Tree.h:1144
Base class for tree-traversal iterators over tile and voxel values.
Definition TreeIterator.h:618
Definition Tree.h:195
void readTopology(std::istream &, bool saveFloatAsHalf=false) override
Read the tree topology from a stream.
Definition Tree.h:1283
RootNodeType::ChildAllCIter beginRootDense() const
Return an iterator over all entries of the root node's table.
Definition Tree.h:1014
Metadata::Ptr getBackgroundValue() const override
Return this tree's background value wrapped as metadata.
Definition Tree.h:1761
int getValueDepth(const Coord &xyz) const
Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides.
Definition Tree.h:1517
bool hasSameTopology(const Tree< OtherRootNodeType > &other) const
Return true if the given tree has the same node and active value topology as this tree,...
Definition Tree.h:1958
Index64 unallocatedLeafCount() const override
Return the total number of unallocated leaf nodes residing in this tree.
Definition Tree.h:1714
CIterT cbegin() const
Return a const iterator of type CIterT (for example, cbegin<ValueOnCIter>() is equivalent to cbeginVa...
bool evalActiveVoxelBoundingBox(CoordBBox &bbox) const override
Return in bbox the axis-aligned bounding box of all active voxels and tiles.
Definition Tree.h:1979
NodeT * stealNode(const Coord &xyz, const ValueType &value, bool active)
Return a pointer to the node of type NodeT that contains voxel (x, y, z) and replace it with a tile o...
Definition Tree.h:1627
void releaseAccessor(ValueAccessorBase< Tree, false > &) const
Dummy implementations.
Definition Tree.h:715
NodeType * probeNode(const Coord &xyz)
Return a pointer to the node of type NodeType that contains voxel (x, y, z). If no such node exists,...
Definition Tree.h:1661
const NodeType * probeNode(const Coord &xyz) const
Definition Tree.h:1670
void combine(Tree &other, CombineOp &op, bool prune=false)
Definition Tree.h:1844
const ValueType & getValue(const Coord &xyz, AccessT &) const
Return the value of the voxel at the given coordinates and update the given accessor's node cache.
void releaseAccessor(ValueAccessorBase< const Tree, false > &) const
Definition Tree.h:716
ConstAccessorRegistry mConstAccessorRegistry
Definition Tree.h:1106
bool isValueOn(const Coord &xyz) const
Return true if the value at the given coordinates is active.
Definition Tree.h:487
RootNodeType & root()
Definition Tree.h:303
TreeValueIteratorBase< Tree, typename RootNodeType::ValueOffIter > ValueOffIter
Definition Tree.h:1050
Tree(const Tree &other)
Deep copy constructor.
Definition Tree.h:229
RootNodeType::ChildOffCIter cbeginRootTiles() const
Definition Tree.h:1008
TreeValueIteratorBase< const Tree, typename RootNodeType::ValueOffCIter > ValueOffCIter
Definition Tree.h:1051
LeafCIter beginLeaf() const
Definition Tree.h:1042
ValueAccessor< Tree, true > Accessor
Definition Tree.h:207
void writeBuffers(std::ostream &, bool saveFloatAsHalf=false) const override
Write out all data buffers for this tree.
Definition Tree.h:1331
void writeTopology(std::ostream &, bool saveFloatAsHalf=false) const override
Write the tree topology to a stream.
Definition Tree.h:1293
ValueOffCIter cbeginValueOff() const
Definition Tree.h:1069
Tree(const Tree< OtherRootType > &other)
Value conversion deep copy constructor.
Definition Tree.h:240
const LeafNodeType * probeConstLeaf(const Coord &xyz) const
Definition Tree.h:1652
IterT begin()
Return an iterator of type IterT (for example, begin<ValueOnIter>() is equivalent to beginValueOn()).
Definition Tree.h:1263
Index64 memUsage() const override
Return the total amount of memory in bytes occupied by this tree.
Definition Tree.h:404
void merge(Tree &other, MergePolicy=MERGE_ACTIVE_STATES)
Efficiently merge another tree into this tree using one of several schemes.
Definition Tree.h:1781
TreeValueIteratorBase< const Tree, typename RootNodeType::ValueAllCIter > ValueAllCIter
Definition Tree.h:1047
typename NodeChainT::Back RootNodeType
Definition Tree.h:200
RootNodeType::ChildAllIter beginRootDense()
Definition Tree.h:1016
Accessor getAccessor()
Return an accessor that provides random read and write access to this tree's voxels.
Definition Tree.h:1388
ValueAccessor< Tree, false > UnsafeAccessor
Definition Tree.h:209
LeafCIter cbeginLeaf() const
Definition Tree.h:1043
LeafIteratorBase< const Tree, typename RootNodeType::ChildOnCIter > LeafCIter
Definition Tree.h:1029
const Name & type() const override
Return the name of this type of tree.
Definition Tree.h:296
static const Index DEPTH
Definition Tree.h:205
RootNodeType::ChildOffIter beginRootTiles()
Definition Tree.h:1009
void getNodes(ArrayT &array)
Adds all nodes of a certain type to a container with the following API:
Definition Tree.h:1340
void readBuffers(std::istream &, const CoordBBox &, bool saveFloatAsHalf=false) override
Read all of this tree's data buffers that intersect the given bounding box.
Definition Tree.h:1311
static const Name & treeType()
Return the name of this type of tree.
Definition Tree.h:1937
void voxelizeActiveTiles(bool threaded=true)
Densify active tiles, i.e., replace them with leaf-level active voxels.
Definition Tree.h:1752
RootNodeType::ChildOnCIter beginRootChildren() const
Return an iterator over children of the root node.
Definition Tree.h:1000
void combine(Tree &other, const CombineOp &op, bool prune=false)
Definition Tree.h:1856
bool operator!=(const Tree &) const
Definition Tree.h:299
Tree()
Definition Tree.h:224
AccessorRegistry mAccessorRegistry
Definition Tree.h:1105
void clip(const CoordBBox &)
Set all voxels that lie outside the given axis-aligned box to the background.
Definition Tree.h:1690
ValueAccessor< const Tree, true > ConstAccessor
Definition Tree.h:208
ValueAllCIter cbeginValueAll() const
Definition Tree.h:1057
void prune(const ValueType &tolerance=zeroVal< ValueType >())
Reduce the memory footprint of this tree by replacing with tiles any nodes whose values are all the s...
Definition Tree.h:548
LeafNodeType * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists,...
Definition Tree.h:1644
void topologyIntersection(const Tree< OtherRootNodeType > &other)
Intersects this tree's set of active values with the active values of the other tree,...
Definition Tree.h:1808
void releaseAccessor(ValueAccessorBase< Tree, true > &) const
Deregister an accessor so that it is no longer automatically cleared.
Definition Tree.h:1441
LeafNodeType * touchLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists,...
Definition Tree.h:1636
RootNodeType::ChildOnIter beginRootChildren()
Definition Tree.h:1002
Index64 leafCount() const override
Return the number of leaf nodes.
Definition Tree.h:363
ValueOnCIter beginValueOn() const
Definition Tree.h:1062
bool operator==(const Tree &) const
Definition Tree.h:298
SharedPtr< Tree > Ptr
Definition Tree.h:197
void attachAccessor(ValueAccessorBase< Tree, true > &) const
Register an accessor for this tree. Registered accessors are automatically cleared whenever one of th...
Definition Tree.h:1423
NodeIteratorBase< Tree, typename RootNodeType::ChildOnIter > NodeIter
Definition Tree.h:1022
Index64 activeLeafVoxelCount() const override
Return the number of active voxels stored in leaf nodes.
Definition Tree.h:394
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
Definition Tree.h:1598
ConstUnsafeAccessor getConstUnsafeAccessor()
Return an unsafe accessor that provides random read-only access to this tree's voxels.
Definition Tree.h:1416
void combine2Extended(const Tree &a, const OtherTreeType &b, const ExtendedCombineOp &, bool prune=false)
Definition Tree.h:1924
Index64 inactiveVoxelCount() const override
Return the number of inactive voxels within the bounding box of all active voxels.
Definition Tree.h:400
void setValueOnly(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates but don't change its active state.
Definition Tree.h:1556
bool empty() const
Return true if this tree contains no nodes other than the root node and no tiles other than backgroun...
Definition Tree.h:661
Index64 activeVoxelCount() const override
Return the total number of active voxels.
Definition Tree.h:398
Index64 inactiveLeafVoxelCount() const override
Return the number of inactive voxels stored in leaf nodes.
Definition Tree.h:396
void fill(const CoordBBox &bbox, const ValueType &value, bool active=true)
Definition Tree.h:519
ValueOffCIter beginValueOff() const
Definition Tree.h:1068
void addLeaf(LeafNodeType *leaf)
Add the given leaf node to this tree, creating a new branch if necessary. If a leaf node with the sam...
Definition Tree.h:559
TreeValueIteratorBase< Tree, typename RootNodeType::ValueAllIter > ValueAllIter
Definition Tree.h:1046
RootNodeType::ChildOffCIter beginRootTiles() const
Return an iterator over non-child entries of the root node's table.
Definition Tree.h:1007
void combineExtended(Tree &other, ExtendedCombineOp &op, bool prune=false)
Definition Tree.h:1866
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 Tree.h:1533
void addTile(Index level, const Coord &xyz, const ValueType &value, bool active)
Add a tile containing voxel (x, y, z) at the specified tree level, creating a new branch if necessary...
Definition Tree.h:1617
void releaseAccessor(ValueAccessorBase< const Tree, true > &) const
Definition Tree.h:1449
bool probeValue(const Coord &xyz, ValueType &value) const
Get the value of the voxel at the given coordinates.
Definition Tree.h:1606
TreeValueIteratorBase< const Tree, typename RootNodeType::ValueOnCIter > ValueOnCIter
Definition Tree.h:1049
void setActiveState(const Coord &xyz, bool on)
Set the active state of the voxel at the given coordinates but don't change its value.
Definition Tree.h:1541
ValueOnIter beginValueOn()
Return an iterator over active values (tile and voxel) across all nodes.
Definition Tree.h:1061
void topologyDifference(const Tree< OtherRootNodeType > &other)
Difference this tree's set of active values with the active values of the other tree,...
Definition Tree.h:1817
typename RootNodeType::BuildType BuildType
Definition Tree.h:202
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 Tree.h:1549
void combine2Extended(const Tree &a, const OtherTreeType &b, ExtendedCombineOp &op, bool prune=false)
Definition Tree.h:1910
Index64 activeTileCount() const override
Return the total number of active tiles.
Definition Tree.h:402
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don't change its value.
Definition Tree.h:1525
tbb::concurrent_hash_map< ValueAccessorBase< const Tree, true > *, bool > ConstAccessorRegistry
Definition Tree.h:1082
ValueOnCIter cbeginValueOn() const
Definition Tree.h:1063
TreeBase::Ptr copy() const override
Return a pointer to a deep copy of this tree.
Definition Tree.h:288
typename RootNodeType::ValueType ValueType
Definition Tree.h:201
void attachAccessor(ValueAccessorBase< Tree, false > &) const
Dummy implementations.
Definition Tree.h:703
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition Tree.h:1500
const LeafNodeType * probeLeaf(const Coord &xyz) const
Definition Tree.h:594
void print(std::ostream &os=std::cout, int verboseLevel=1) const override
Print statistics, memory usage and other information about this tree.
Definition Tree.h:2024
void combineExtended(Tree &other, const ExtendedCombineOp &op, bool prune=false)
Definition Tree.h:1878
void attachAccessor(ValueAccessorBase< const Tree, false > &) const
Definition Tree.h:704
UnsafeAccessor getUnsafeAccessor()
Return an unsafe accessor that provides random read and write access to this tree's voxels.
Definition Tree.h:1395
void combine2(const Tree &a, const OtherTreeType &b, const CombineOp &op, bool prune=false)
Definition Tree.h:1900
NodeCIter beginNode() const
Definition Tree.h:1035
ValueAccessor< const Tree, false > ConstUnsafeAccessor
Definition Tree.h:210
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 Tree.h:1589
LeafIteratorBase< Tree, typename RootNodeType::ChildOnIter > LeafIter
Definition Tree.h:1028
SharedPtr< const Tree > ConstPtr
Definition Tree.h:198
void readNonresidentBuffers() const override
Read all of this tree's data buffers that are not yet resident in memory (because delayed loading is ...
Definition Tree.h:1320
Tree(const OtherTreeType &other, const ValueType &background, TopologyCopy)
Topology copy constructor from a tree of a different type.
Definition Tree.h:276
RootNodeType::ChildAllCIter cbeginRootDense() const
Definition Tree.h:1015
void getNodes(ArrayT &array) const
Definition Tree.h:1352
void denseFill(const CoordBBox &bbox, const ValueType &value, bool active=true)
Set all voxels within a given axis-aligned box to a constant value and ensure that those voxels are a...
Definition Tree.h:1743
bool evalLeafBoundingBox(CoordBBox &bbox) const override
Return in bbox the axis-aligned bounding box of all active tiles and leaf nodes with active values.
Definition Tree.h:1966
void stealNodes(ArrayT &array, const ValueType &value, bool state)
Definition Tree.h:650
bool evalLeafDim(Coord &dim) const override
Return in dim the dimensions of the axis-aligned bounding box of all leaf nodes.
Definition Tree.h:2004
RootNodeType::ChildOnCIter cbeginRootChildren() const
Definition Tree.h:1001
void setValue(const Coord &xyz, const ValueType &value, AccessT &)
Set the value of the voxel at the given coordinates, mark the voxel as active, and update the given a...
Definition Tree.h:1564
std::vector< Index64 > nodeCount() const override
Definition Tree.h:371
NodeCIter cbeginNode() const
Definition Tree.h:1036
const ValueType & background() const
Definition Tree.h:728
NodeIteratorBase< const Tree, typename RootNodeType::ChildOnCIter > NodeCIter
Definition Tree.h:1023
Tree & operator=(const Tree &)=delete
static void getNodeLog2Dims(std::vector< Index > &dims)
Traverse the type hierarchy of nodes, and return, in dims, a list of the Log2Dims of nodes in order f...
Definition Tree.h:2015
ValueOffIter beginValueOff()
Return an iterator over inactive values (tile and voxel) across all nodes.
Definition Tree.h:1067
void getIndexRange(CoordBBox &bbox) const override
Min and max are both inclusive.
Definition Tree.h:731
void attachAccessor(ValueAccessorBase< const Tree, true > &) const
Definition Tree.h:1432
void readBuffers(std::istream &, bool saveFloatAsHalf=false) override
Read all data buffers for this tree.
Definition Tree.h:1302
typename RootNodeType::LeafNodeType LeafNodeType
Definition Tree.h:203
ConstAccessor getConstAccessor() const
Return an accessor that provides random read-only access to this tree's voxels.
Definition Tree.h:1409
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don't change its value.
Definition Tree.h:1572
LeafIter beginLeaf()
Return an iterator over all leaf nodes in this tree.
Definition Tree.h:1041
void sparseFill(const CoordBBox &bbox, const ValueType &value, bool active=true)
Set all voxels within a given axis-aligned box to a constant value.
Definition Tree.h:1734
Tree(const OtherTreeType &other, const ValueType &inactiveValue, const ValueType &activeValue, TopologyCopy)
Topology copy constructor from a tree of a different type.
Definition Tree.h:255
bool evalActiveVoxelDim(Coord &dim) const override
Return in dim the dimensions of the axis-aligned bounding box of all active voxels....
Definition Tree.h:1993
~Tree() override
Definition Tree.h:285
const NodeType * probeConstNode(const Coord &xyz) const
Definition Tree.h:1679
bool hasActiveTiles() const
Return true if this tree has any active tiles.
Definition Tree.h:491
Tree(const ValueType &background)
Empty tree constructor.
Definition Tree.h:283
void clipUnallocatedNodes() override
Replace with background tiles any nodes whose voxel buffers have not yet been allocated.
Definition Tree.h:1699
void setValueOn(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active.
Definition Tree.h:1580
bool isValueOff(const Coord &xyz) const
Return true if the value at the given coordinates is inactive.
Definition Tree.h:489
void stealNodes(ArrayT &array)
Steals all nodes of a certain type from the tree and adds them to a container with the following API:
Definition Tree.h:648
void topologyUnion(const Tree< OtherRootNodeType > &other, const bool preserveTiles=false)
Union this tree's set of active values with the active values of the other tree, whose ValueType may ...
Definition Tree.h:1799
Name valueType() const override
Return the name of the type of a voxel's value (e.g., "float" or "vec3d")
Definition Tree.h:291
void combine2(const Tree &a, const OtherTreeType &b, CombineOp &op, bool prune=false)
Definition Tree.h:1888
Index treeDepth() const override
Return the depth of this tree.
Definition Tree.h:360
const RootNodeType & root() const
Definition Tree.h:304
ValueAllCIter beginValueAll() const
Definition Tree.h:1056
NodeIter beginNode()
Return an iterator over all nodes in this tree.
Definition Tree.h:1034
ConstAccessor getAccessor() const
Return an accessor that provides random read-only access to this tree's voxels.
Definition Tree.h:1402
Index64 nonLeafCount() const override
Return the number of non-leaf nodes.
Definition Tree.h:389
tbb::concurrent_hash_map< ValueAccessorBase< Tree, true > *, bool > AccessorRegistry
Definition Tree.h:1081
ValueAllIter beginValueAll()
Return an iterator over all values (tile and voxel) across all nodes.
Definition Tree.h:1055
TreeValueIteratorBase< Tree, typename RootNodeType::ValueOnIter > ValueOnIter
Definition Tree.h:1048
This base class for ValueAccessors manages registration of an accessor with a tree so that the tree c...
Definition ValueAccessor.h:152
#define OPENVDB_LOG_WARN(message)
Log a warning message of the form 'someVar << "some text" << ...'.
Definition logging.h:256
Index64 countActiveLeafVoxels(const TreeT &tree, bool threaded=true)
Return the total number of active voxels stored in leaf nodes.
Definition Count.h:436
math::MinMax< typename TreeT::ValueType > minMax(const TreeT &tree, bool threaded=true)
Return the minimum and maximum active values in this tree.
Definition Count.h:516
Index64 countInactiveVoxels(const TreeT &tree, bool threaded=true)
Return the total number of inactive voxels in the tree.
Definition Count.h:461
Index64 countActiveVoxels(const TreeT &tree, bool threaded=true)
Return the total number of active voxels in the tree.
Definition Count.h:413
Index64 memUsage(const TreeT &tree, bool threaded=true)
Return the total amount of memory in bytes occupied by this tree.
Definition Count.h:493
Index64 countInactiveLeafVoxels(const TreeT &tree, bool threaded=true)
Return the total number of inactive voxels stored in leaf nodes.
Definition Count.h:471
Index64 countActiveTiles(const TreeT &tree, bool threaded=true)
Return the total number of active tiles in the tree.
Definition Count.h:482
Definition PointDataGrid.h:170
ValueAccessorImpl< TreeType, IsSafe, MutexType, openvdb::make_index_sequence< CacheLevels > > ValueAccessor
Default alias for a ValueAccessor. This is simply a helper alias for the generic definition but takes...
Definition ValueAccessor.h:86
FormattedInt< IntT > formattedInt(IntT n)
Definition Formats.h:118
OPENVDB_API int printBytes(std::ostream &os, uint64_t bytes, const std::string &head="", const std::string &tail="\n", bool exact=false, int width=8, int precision=3)
std::string Name
Definition Name.h:19
Index32 Index
Definition Types.h:34
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:71
uint32_t Index32
Definition Types.h:32
uint64_t Index64
Definition Types.h:33
std::shared_ptr< T > SharedPtr
Definition Types.h:95
MergePolicy
Definition Types.h:577
@ MERGE_ACTIVE_STATES
Definition Types.h:578
@ MERGE_NODES
Definition Types.h:579
@ MERGE_ACTIVE_STATES_AND_NODES
Definition Types.h:580
const char * typeNameAsString()
Definition Types.h:587
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
Helper class to adapt a three-argument (a, b, result) CombineOp functor into a single-argument functo...
Definition Tree.h:1830
void operator()(CombineArgs< AValueT, BValueT > &args) const
Definition Tree.h:1833
CombineOpAdapter(CombineOp &_op)
Definition Tree.h:1831
CombineOp & op
Definition Tree.h:1837
Tree3<T, N1, N2>::Type is the type of a three-level tree (Root, Internal, Leaf) with value type T and...
Definition Tree.h:1115
Tree< RootNode< InternalNode< LeafNode< T, N2 >, N1 > > > Type
Definition Tree.h:1116
Tree4<T, N1, N2, N3>::Type is the type of a four-level tree (Root, Internal, Internal,...
Definition Tree.h:1125
Tree< RootNode< InternalNode< InternalNode< LeafNode< bool, N3 >, N2 >, N1 > > > Type
Definition Tree.h:1126
Tree5<T, N1, N2, N3, N4>::Type is the type of a five-level tree (Root, Internal, Internal,...
Definition Tree.h:1134
Tree< RootNode< InternalNode< InternalNode< InternalNode< LeafNode< T, N4 >, N3 >, N2 >, N1 > > > Type
Definition Tree.h:1135
static TreeT::LeafCIter begin(const TreeT &tree)
Definition Tree.h:1232
static TreeT::LeafIter begin(TreeT &tree)
Definition Tree.h:1228
static TreeT::NodeCIter begin(const TreeT &tree)
Definition Tree.h:1224
static TreeT::NodeIter begin(TreeT &tree)
Definition Tree.h:1220
static TreeT::RootNodeType::ChildAllCIter begin(const TreeT &tree)
Definition Tree.h:1214
static TreeT::RootNodeType::ChildAllIter begin(TreeT &tree)
Definition Tree.h:1208
static TreeT::RootNodeType::ChildOffCIter begin(const TreeT &tree)
Definition Tree.h:1202
static TreeT::RootNodeType::ChildOffIter begin(TreeT &tree)
Definition Tree.h:1196
static TreeT::RootNodeType::ChildOnCIter begin(const TreeT &tree)
Definition Tree.h:1190
static TreeT::RootNodeType::ChildOnIter begin(TreeT &tree)
Definition Tree.h:1184
static TreeT::ValueAllCIter begin(const TreeT &tree)
Definition Tree.h:1256
static TreeT::ValueAllIter begin(TreeT &tree)
Definition Tree.h:1252
static TreeT::ValueOffCIter begin(const TreeT &tree)
Definition Tree.h:1248
static TreeT::ValueOffIter begin(TreeT &tree)
Definition Tree.h:1244
static TreeT::ValueOnCIter begin(const TreeT &tree)
Definition Tree.h:1240
static TreeT::ValueOnIter begin(TreeT &tree)
Definition Tree.h:1236
TreeIterTraits provides, for all tree iterators, a begin(tree) function that returns an iterator over...
Definition Tree.h:1181
DeallocateNodes(std::vector< NodeType * > &nodes)
Definition Tree.h:1091
NodeType **const mNodes
Definition Tree.h:1098
void operator()(const tbb::blocked_range< size_t > &range) const
Definition Tree.h:1093
ValueConverter<T>::Type is the type of a tree having the same hierarchy as this tree but a different ...
Definition Tree.h:219
Tree< typename RootNodeType::template ValueConverter< OtherValueType >::Type > Type
Definition Tree.h:220
#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:218