OpenVDB 12.0.0
 
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;
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 /// Return the minimum and maximum active values in this tree.
405 OPENVDB_DEPRECATED_MESSAGE("Switch to tools::minMax. Use threaded = false for serial execution")
406 void evalMinMax(ValueType &min, ValueType &max) const;
407
408 Index64 memUsage() const override { return tools::memUsage(*this); }
409
410
411 //
412 // Voxel access methods (using signed indexing)
413 //
414 /// Return the value of the voxel at the given coordinates.
415 const ValueType& getValue(const Coord& xyz) const;
416 /// @brief Return the value of the voxel at the given coordinates
417 /// and update the given accessor's node cache.
418 template<typename AccessT> const ValueType& getValue(const Coord& xyz, AccessT&) const;
419
420 /// @brief Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides.
421 /// @details If (x, y, z) isn't explicitly represented in the tree (i.e., it is
422 /// implicitly a background voxel), return -1.
423 int getValueDepth(const Coord& xyz) const;
424
425 /// Set the active state of the voxel at the given coordinates but don't change its value.
426 void setActiveState(const Coord& xyz, bool on);
427 /// Set the value of the voxel at the given coordinates but don't change its active state.
428 void setValueOnly(const Coord& xyz, const ValueType& value);
429 /// Mark the voxel at the given coordinates as active but don't change its value.
430 void setValueOn(const Coord& xyz);
431 /// Set the value of the voxel at the given coordinates and mark the voxel as active.
432 void setValueOn(const Coord& xyz, const ValueType& value);
433 /// Set the value of the voxel at the given coordinates and mark the voxel as active.
434 void setValue(const Coord& xyz, const ValueType& value);
435 /// @brief Set the value of the voxel at the given coordinates, mark the voxel as active,
436 /// and update the given accessor's node cache.
437 template<typename AccessT> void setValue(const Coord& xyz, const ValueType& value, AccessT&);
438 /// Mark the voxel at the given coordinates as inactive but don't change its value.
439 void setValueOff(const Coord& xyz);
440 /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
441 void setValueOff(const Coord& xyz, const ValueType& value);
442
443 /// @brief Apply a functor to the value of the voxel at the given coordinates
444 /// and mark the voxel as active.
445 /// @details Provided that the functor can be inlined, this is typically
446 /// significantly faster than calling getValue() followed by setValueOn().
447 /// @param xyz the coordinates of a voxel whose value is to be modified
448 /// @param op a functor of the form <tt>void op(ValueType&) const</tt> that modifies
449 /// its argument in place
450 /// @par Example:
451 /// @code
452 /// Coord xyz(1, 0, -2);
453 /// // Multiply the value of a voxel by a constant and mark the voxel as active.
454 /// floatTree.modifyValue(xyz, [](float& f) { f *= 0.25; }); // C++11
455 /// // Set the value of a voxel to the maximum of its current value and 0.25,
456 /// // and mark the voxel as active.
457 /// floatTree.modifyValue(xyz, [](float& f) { f = std::max(f, 0.25f); }); // C++11
458 /// @endcode
459 /// @note The functor is not guaranteed to be called only once.
460 /// @see tools::foreach()
461 template<typename ModifyOp>
462 void modifyValue(const Coord& xyz, const ModifyOp& op);
463
464 /// @brief Apply a functor to the voxel at the given coordinates.
465 /// @details Provided that the functor can be inlined, this is typically
466 /// significantly faster than calling getValue() followed by setValue().
467 /// @param xyz the coordinates of a voxel to be modified
468 /// @param op a functor of the form <tt>void op(ValueType&, bool&) const</tt> that
469 /// modifies its arguments, a voxel's value and active state, in place
470 /// @par Example:
471 /// @code
472 /// Coord xyz(1, 0, -2);
473 /// // Multiply the value of a voxel by a constant and mark the voxel as inactive.
474 /// floatTree.modifyValueAndActiveState(xyz,
475 /// [](float& f, bool& b) { f *= 0.25; b = false; }); // C++11
476 /// // Set the value of a voxel to the maximum of its current value and 0.25,
477 /// // but don't change the voxel's active state.
478 /// floatTree.modifyValueAndActiveState(xyz,
479 /// [](float& f, bool&) { f = std::max(f, 0.25f); }); // C++11
480 /// @endcode
481 /// @note The functor is not guaranteed to be called only once.
482 /// @see tools::foreach()
483 template<typename ModifyOp>
484 void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op);
485
486 /// @brief Get the value of the voxel at the given coordinates.
487 /// @return @c true if the value is active.
488 bool probeValue(const Coord& xyz, ValueType& value) const;
489
490 /// Return @c true if the value at the given coordinates is active.
491 bool isValueOn(const Coord& xyz) const { return mRoot.isValueOn(xyz); }
492 /// Return @c true if the value at the given coordinates is inactive.
493 bool isValueOff(const Coord& xyz) const { return !this->isValueOn(xyz); }
494 /// Return @c true if this tree has any active tiles.
495 bool hasActiveTiles() const { return mRoot.hasActiveTiles(); }
496
497 /// Set all voxels that lie outside the given axis-aligned box to the background.
498 void clip(const CoordBBox&);
499 /// @brief Replace with background tiles any nodes whose voxel buffers
500 /// have not yet been allocated.
501 /// @details Typically, unallocated nodes are leaf nodes whose voxel buffers
502 /// are not yet resident in memory because delayed loading is in effect.
503 /// @sa readNonresidentBuffers, io::File::open
504 void clipUnallocatedNodes() override;
505
506 /// Return the total number of unallocated leaf nodes residing in this tree.
507#if OPENVDB_ABI_VERSION_NUMBER >= 12
509#else
510 Index32 unallocatedLeafCount() const override;
511#endif
512
513 //@{
514 /// @brief Set all voxels within a given axis-aligned box to a constant value.
515 /// @param bbox inclusive coordinates of opposite corners of an axis-aligned box
516 /// @param value the value to which to set voxels within the box
517 /// @param active if true, mark voxels within the box as active,
518 /// otherwise mark them as inactive
519 /// @note This operation generates a sparse, but not always optimally sparse,
520 /// representation of the filled box. Follow fill operations with a prune()
521 /// operation for optimal sparseness.
522 void sparseFill(const CoordBBox& bbox, const ValueType& value, bool active = true);
523 void fill(const CoordBBox& bbox, const ValueType& value, bool active = true)
524 {
525 this->sparseFill(bbox, value, active);
526 }
527 //@}
528
529 /// @brief Set all voxels within a given axis-aligned box to a constant value
530 /// and ensure that those voxels are all represented at the leaf level.
531 /// @param bbox inclusive coordinates of opposite corners of an axis-aligned box.
532 /// @param value the value to which to set voxels within the box.
533 /// @param active if true, mark voxels within the box as active,
534 /// otherwise mark them as inactive.
535 /// @sa voxelizeActiveTiles()
536 void denseFill(const CoordBBox& bbox, const ValueType& value, bool active = true);
537
538 /// @brief Densify active tiles, i.e., replace them with leaf-level active voxels.
539 ///
540 /// @param threaded if true, this operation is multi-threaded (over the internal nodes).
541 ///
542 /// @warning This method can explode the tree's memory footprint, especially if it
543 /// contains active tiles at the upper levels (in particular the root level)!
544 ///
545 /// @sa denseFill()
546 void voxelizeActiveTiles(bool threaded = true);
547
548 /// @brief Reduce the memory footprint of this tree by replacing with tiles
549 /// any nodes whose values are all the same (optionally to within a tolerance)
550 /// and have the same active state.
551 /// @warning Will soon be deprecated!
552 void prune(const ValueType& tolerance = zeroVal<ValueType>())
553 {
554 this->clearAllAccessors();
555 mRoot.prune(tolerance);
556 }
557
558 /// @brief Add the given leaf node to this tree, creating a new branch if necessary.
559 /// If a leaf node with the same origin already exists, replace it.
560 ///
561 /// @warning Ownership of the leaf is transferred to the tree so
562 /// the client code should not attempt to delete the leaf pointer!
563 void addLeaf(LeafNodeType* leaf) { OPENVDB_ASSERT(leaf); mRoot.addLeaf(leaf); }
564
565 /// @brief Add a tile containing voxel (x, y, z) at the specified tree level,
566 /// creating a new branch if necessary. Delete any existing lower-level nodes
567 /// that contain (x, y, z).
568 /// @note @a level must be less than this tree's depth.
569 void addTile(Index level, const Coord& xyz, const ValueType& value, bool active);
570
571 /// @brief Return a pointer to the node of type @c NodeT that contains voxel (x, y, z)
572 /// and replace it with a tile of the specified value and state.
573 /// If no such node exists, leave the tree unchanged and return @c nullptr.
574 /// @note The caller takes ownership of the node and is responsible for deleting it.
575 template<typename NodeT>
576 NodeT* stealNode(const Coord& xyz, const ValueType& value, bool active);
577
578 /// @brief Return a pointer to the leaf node that contains voxel (x, y, z).
579 /// If no such node exists, create one that preserves the values and
580 /// active states of all voxels.
581 /// @details Use this method to preallocate a static tree topology over which to
582 /// safely perform multithreaded processing.
584
585 //@{
586 /// @brief Return a pointer to the node of type @c NodeType that contains
587 /// voxel (x, y, z). If no such node exists, return @c nullptr.
588 template<typename NodeType> NodeType* probeNode(const Coord& xyz);
589 template<typename NodeType> const NodeType* probeConstNode(const Coord& xyz) const;
590 template<typename NodeType> const NodeType* probeNode(const Coord& xyz) const;
591 //@}
592
593 //@{
594 /// @brief Return a pointer to the leaf node that contains voxel (x, y, z).
595 /// If no such node exists, return @c nullptr.
597 const LeafNodeType* probeConstLeaf(const Coord& xyz) const;
598 const LeafNodeType* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); }
599 //@}
600
601 //@{
602 /// @brief Adds all nodes of a certain type to a container with the following API:
603 /// @code
604 /// struct ArrayT {
605 /// using value_type = ...; // the type of node to be added to the array
606 /// void push_back(value_type nodePtr); // add a node to the array
607 /// };
608 /// @endcode
609 /// @details An example of a wrapper around a c-style array is:
610 /// @code
611 /// struct MyArray {
612 /// using value_type = LeafType*;
613 /// value_type* ptr;
614 /// MyArray(value_type* array) : ptr(array) {}
615 /// void push_back(value_type leaf) { *ptr++ = leaf; }
616 ///};
617 /// @endcode
618 /// @details An example that constructs a list of pointer to all leaf nodes is:
619 /// @code
620 /// std::vector<const LeafNodeType*> array;//most std contains have the required API
621 /// array.reserve(tree.leafCount());//this is a fast preallocation.
622 /// tree.getNodes(array);
623 /// @endcode
624 template<typename ArrayT> void getNodes(ArrayT& array);
625 template<typename ArrayT> void getNodes(ArrayT& array) const;
626 //@}
627
628 /// @brief Steals all nodes of a certain type from the tree and
629 /// adds them to a container with the following API:
630 /// @code
631 /// struct ArrayT {
632 /// using value_type = ...; // the type of node to be added to the array
633 /// void push_back(value_type nodePtr); // add a node to the array
634 /// };
635 /// @endcode
636 /// @details An example of a wrapper around a c-style array is:
637 /// @code
638 /// struct MyArray {
639 /// using value_type = LeafType*;
640 /// value_type* ptr;
641 /// MyArray(value_type* array) : ptr(array) {}
642 /// void push_back(value_type leaf) { *ptr++ = leaf; }
643 ///};
644 /// @endcode
645 /// @details An example that constructs a list of pointer to all leaf nodes is:
646 /// @code
647 /// std::vector<const LeafNodeType*> array;//most std contains have the required API
648 /// array.reserve(tree.leafCount());//this is a fast preallocation.
649 /// tree.stealNodes(array);
650 /// @endcode
651 template<typename ArrayT>
652 void stealNodes(ArrayT& array) { this->clearAllAccessors(); mRoot.stealNodes(array); }
653 template<typename ArrayT>
654 void stealNodes(ArrayT& array, const ValueType& value, bool state)
655 {
656 this->clearAllAccessors();
657 mRoot.stealNodes(array, value, state);
658 }
659
660 //
661 // Aux methods
662 //
663 /// @brief Return @c true if this tree contains no nodes other than
664 /// the root node and no tiles other than background tiles.
665 bool empty() const { return mRoot.empty(); }
666
667 /// Remove all tiles from this tree and all nodes other than the root node.
668 void clear();
669
670 /// @brief Return an accessor that provides random read and write access
671 /// to this tree's voxels.
672 /// @details The accessor is safe in the sense that it is registered with this tree.
674 /// @brief Return an unsafe accessor that provides random read and write access
675 /// to this tree's voxels.
676 /// @details The accessor is unsafe in the sense that it is not registered
677 /// with this tree's tree. In some rare cases this can give a performance advantage
678 /// over a registered accessor, but it is unsafe if the tree topology is modified.
679 /// @warning Only use this method if you're an expert and know the
680 /// risks of using an unregistered accessor (see tree/ValueAccessor.h)
682 /// Return an accessor that provides random read-only access to this tree's voxels.
684 /// Return an accessor that provides random read-only access to this tree's voxels.
686 /// @brief Return an unsafe accessor that provides random read-only access
687 /// to this tree's voxels.
688 /// @details The accessor is unsafe in the sense that it is not registered
689 /// with this tree. In some rare cases this can give a performance advantage
690 /// over a registered accessor, but it is unsafe if the tree topology is modified.
691 /// @warning Only use this method if you're an expert and know the
692 /// risks of using an unregistered accessor (see tree/ValueAccessor.h)
694
695 /// Clear all registered accessors.
697
698 //@{
699 /// @brief Register an accessor for this tree. Registered accessors are
700 /// automatically cleared whenever one of this tree's nodes is deleted.
703 //@}
704
705 //@{
706 /// Dummy implementations
709 //@}
710
711 //@{
712 /// Deregister an accessor so that it is no longer automatically cleared.
715 //@}
716
717 //@{
718 /// Dummy implementations
721 //@}
722
723 /// @brief Return this tree's background value wrapped as metadata.
724 /// @note Query the metadata object for the value's type.
726
727 /// @brief Return this tree's background value.
728 ///
729 /// @note Use tools::changeBackground to efficiently modify the
730 /// background values. Else use tree.root().setBackground, which
731 /// is serial and hence slower.
732 const ValueType& background() const { return mRoot.background(); }
733
734 /// Min and max are both inclusive.
735 void getIndexRange(CoordBBox& bbox) const override { mRoot.getIndexRange(bbox); }
736
737 /// @brief Efficiently merge another tree into this tree using one of several schemes.
738 /// @details This operation is primarily intended to combine trees that are mostly
739 /// non-overlapping (for example, intermediate trees from computations that are
740 /// parallelized across disjoint regions of space).
741 /// @note This operation is not guaranteed to produce an optimally sparse tree.
742 /// Follow merge() with prune() for optimal sparseness.
743 /// @warning This operation always empties the other tree.
745
746 /// @brief Union this tree's set of active values with the active values
747 /// of the other tree, whose @c ValueType may be different.
748 /// @details The resulting state of a value is active if the corresponding value
749 /// was already active OR if it is active in the other tree. Also, a resulting
750 /// value maps to a voxel if the corresponding value already mapped to a voxel
751 /// OR if it is a voxel in the other tree. Thus, a resulting value can only
752 /// map to a tile if the corresponding value already mapped to a tile
753 /// AND if it is a tile value in other tree.
754 ///
755 /// @note This operation modifies only active states, not values.
756 /// Specifically, active tiles and voxels in this tree are not changed, and
757 /// tiles or voxels that were inactive in this tree but active in the other tree
758 /// are marked as active in this tree but left with their original values.
759 ///
760 /// @note If preserveTiles is true, any active tile in this topology
761 /// will not be densified by overlapping child topology.
762 template<typename OtherRootNodeType>
763 void topologyUnion(const Tree<OtherRootNodeType>& other, const bool preserveTiles = false);
764
765 /// @brief Intersects this tree's set of active values with the active values
766 /// of the other tree, whose @c ValueType may be different.
767 /// @details The resulting state of a value is active only if the corresponding
768 /// value was already active AND if it is active in the other tree. Also, a
769 /// resulting value maps to a voxel if the corresponding value
770 /// already mapped to an active voxel in either of the two grids
771 /// and it maps to an active tile or voxel in the other grid.
772 ///
773 /// @note This operation can delete branches in this grid if they
774 /// overlap with inactive tiles in the other grid. Likewise active
775 /// voxels can be turned into inactive voxels resulting in leaf
776 /// nodes with no active values. Thus, it is recommended to
777 /// subsequently call tools::pruneInactive.
778 template<typename OtherRootNodeType>
780
781 /// @brief Difference this tree's set of active values with the active values
782 /// of the other tree, whose @c ValueType may be different. So a
783 /// resulting voxel will be active only if the original voxel is
784 /// active in this tree and inactive in the other tree.
785 ///
786 /// @note This operation can delete branches in this grid if they
787 /// overlap with active tiles in the other grid. Likewise active
788 /// voxels can be turned into inactive voxels resulting in leaf
789 /// nodes with no active values. Thus, it is recommended to
790 /// subsequently call tools::pruneInactive.
791 template<typename OtherRootNodeType>
793
794 /// For a given function @c f, use sparse traversal to compute <tt>f(this, other)</tt>
795 /// over all corresponding pairs of values (tile or voxel) of this tree and the other tree
796 /// and store the result in this tree.
797 /// This method is typically more space-efficient than the two-tree combine2(),
798 /// since it moves rather than copies nodes from the other tree into this tree.
799 /// @note This operation always empties the other tree.
800 /// @param other a tree of the same type as this tree
801 /// @param op a functor of the form <tt>void op(const T& a, const T& b, T& result)</tt>,
802 /// where @c T is this tree's @c ValueType, that computes
803 /// <tt>result = f(a, b)</tt>
804 /// @param prune if true, prune the resulting tree one branch at a time (this is usually
805 /// more space-efficient than pruning the entire tree in one pass)
806 ///
807 /// @par Example:
808 /// Compute the per-voxel difference between two floating-point trees,
809 /// @c aTree and @c bTree, and store the result in @c aTree (leaving @c bTree empty).
810 /// @code
811 /// {
812 /// struct Local {
813 /// static inline void diff(const float& a, const float& b, float& result) {
814 /// result = a - b;
815 /// }
816 /// };
817 /// aTree.combine(bTree, Local::diff);
818 /// }
819 /// @endcode
820 ///
821 /// @par Example:
822 /// Compute <tt>f * a + (1 - f) * b</tt> over all voxels of two floating-point trees,
823 /// @c aTree and @c bTree, and store the result in @c aTree (leaving @c bTree empty).
824 /// @code
825 /// namespace {
826 /// struct Blend {
827 /// Blend(float f): frac(f) {}
828 /// inline void operator()(const float& a, const float& b, float& result) const {
829 /// result = frac * a + (1.0 - frac) * b;
830 /// }
831 /// float frac;
832 /// };
833 /// }
834 /// {
835 /// aTree.combine(bTree, Blend(0.25)); // 0.25 * a + 0.75 * b
836 /// }
837 /// @endcode
838 template<typename CombineOp>
839 void combine(Tree& other, CombineOp& op, bool prune = false);
840 template<typename CombineOp>
841 void combine(Tree& other, const CombineOp& op, bool prune = false);
842
843 /// Like combine(), but with
844 /// @param other a tree of the same type as this tree
845 /// @param op a functor of the form <tt>void op(CombineArgs<ValueType>& args)</tt> that
846 /// computes <tt>args.setResult(f(args.a(), args.b()))</tt> and, optionally,
847 /// <tt>args.setResultIsActive(g(args.aIsActive(), args.bIsActive()))</tt>
848 /// for some functions @c f and @c g
849 /// @param prune if true, prune the resulting tree one branch at a time (this is usually
850 /// more space-efficient than pruning the entire tree in one pass)
851 ///
852 /// This variant passes not only the @em a and @em b values but also the active states
853 /// of the @em a and @em b values to the functor, which may then return, by calling
854 /// @c args.setResultIsActive(), a computed active state for the result value.
855 /// By default, the result is active if either the @em a or the @em b value is active.
856 ///
857 /// @see openvdb/Types.h for the definition of the CombineArgs struct.
858 ///
859 /// @par Example:
860 /// Replace voxel values in floating-point @c aTree with corresponding values
861 /// from floating-point @c bTree (leaving @c bTree empty) wherever the @c bTree
862 /// values are larger. Also, preserve the active states of any transferred values.
863 /// @code
864 /// {
865 /// struct Local {
866 /// static inline void max(CombineArgs<float>& args) {
867 /// if (args.b() > args.a()) {
868 /// // Transfer the B value and its active state.
869 /// args.setResult(args.b());
870 /// args.setResultIsActive(args.bIsActive());
871 /// } else {
872 /// // Preserve the A value and its active state.
873 /// args.setResult(args.a());
874 /// args.setResultIsActive(args.aIsActive());
875 /// }
876 /// }
877 /// };
878 /// aTree.combineExtended(bTree, Local::max);
879 /// }
880 /// @endcode
881 template<typename ExtendedCombineOp>
882 void combineExtended(Tree& other, ExtendedCombineOp& op, bool prune = false);
883 template<typename ExtendedCombineOp>
884 void combineExtended(Tree& other, const ExtendedCombineOp& op, bool prune = false);
885
886 /// For a given function @c f, use sparse traversal to compute <tt>f(a, b)</tt> over all
887 /// corresponding pairs of values (tile or voxel) of trees A and B and store the result
888 /// in this tree.
889 /// @param a,b two trees with the same configuration (levels and node dimensions)
890 /// as this tree but with the B tree possibly having a different value type
891 /// @param op a functor of the form <tt>void op(const T1& a, const T2& b, T1& result)</tt>,
892 /// where @c T1 is this tree's and the A tree's @c ValueType and @c T2 is the
893 /// B tree's @c ValueType, that computes <tt>result = f(a, b)</tt>
894 /// @param prune if true, prune the resulting tree one branch at a time (this is usually
895 /// more space-efficient than pruning the entire tree in one pass)
896 ///
897 /// @throw TypeError if the B tree's configuration doesn't match this tree's
898 /// or if this tree's ValueType is not constructible from the B tree's ValueType.
899 ///
900 /// @par Example:
901 /// Compute the per-voxel difference between two floating-point trees,
902 /// @c aTree and @c bTree, and store the result in a third tree.
903 /// @code
904 /// {
905 /// struct Local {
906 /// static inline void diff(const float& a, const float& b, float& result) {
907 /// result = a - b;
908 /// }
909 /// };
910 /// FloatTree resultTree;
911 /// resultTree.combine2(aTree, bTree, Local::diff);
912 /// }
913 /// @endcode
914 template<typename CombineOp, typename OtherTreeType /*= Tree*/>
915 void combine2(const Tree& a, const OtherTreeType& b, CombineOp& op, bool prune = false);
916 template<typename CombineOp, typename OtherTreeType /*= Tree*/>
917 void combine2(const Tree& a, const OtherTreeType& b, const CombineOp& op, bool prune = false);
918
919 /// Like combine2(), but with
920 /// @param a,b two trees with the same configuration (levels and node dimensions)
921 /// as this tree but with the B tree possibly having a different value type
922 /// @param op a functor of the form <tt>void op(CombineArgs<T1, T2>& args)</tt>, where
923 /// @c T1 is this tree's and the A tree's @c ValueType and @c T2 is the B tree's
924 /// @c ValueType, that computes <tt>args.setResult(f(args.a(), args.b()))</tt>
925 /// and, optionally,
926 /// <tt>args.setResultIsActive(g(args.aIsActive(), args.bIsActive()))</tt>
927 /// for some functions @c f and @c g
928 /// @param prune if true, prune the resulting tree one branch at a time (this is usually
929 /// more space-efficient than pruning the entire tree in one pass)
930 /// This variant passes not only the @em a and @em b values but also the active states
931 /// of the @em a and @em b values to the functor, which may then return, by calling
932 /// <tt>args.setResultIsActive()</tt>, a computed active state for the result value.
933 /// By default, the result is active if either the @em a or the @em b value is active.
934 ///
935 /// @throw TypeError if the B tree's configuration doesn't match this tree's
936 /// or if this tree's ValueType is not constructible from the B tree's ValueType.
937 ///
938 /// @see openvdb/Types.h for the definition of the CombineArgs struct.
939 ///
940 /// @par Example:
941 /// Compute the per-voxel maximum values of two single-precision floating-point trees,
942 /// @c aTree and @c bTree, and store the result in a third tree. Set the active state
943 /// of each output value to that of the larger of the two input values.
944 /// @code
945 /// {
946 /// struct Local {
947 /// static inline void max(CombineArgs<float>& args) {
948 /// if (args.b() > args.a()) {
949 /// // Transfer the B value and its active state.
950 /// args.setResult(args.b());
951 /// args.setResultIsActive(args.bIsActive());
952 /// } else {
953 /// // Preserve the A value and its active state.
954 /// args.setResult(args.a());
955 /// args.setResultIsActive(args.aIsActive());
956 /// }
957 /// }
958 /// };
959 /// FloatTree aTree = ...;
960 /// FloatTree bTree = ...;
961 /// FloatTree resultTree;
962 /// resultTree.combine2Extended(aTree, bTree, Local::max);
963 /// }
964 /// @endcode
965 ///
966 /// @par Example:
967 /// Compute the per-voxel maximum values of a double-precision and a single-precision
968 /// floating-point tree, @c aTree and @c bTree, and store the result in a third,
969 /// double-precision tree. Set the active state of each output value to that of
970 /// the larger of the two input values.
971 /// @code
972 /// {
973 /// struct Local {
974 /// static inline void max(CombineArgs<double, float>& args) {
975 /// if (args.b() > args.a()) {
976 /// // Transfer the B value and its active state.
977 /// args.setResult(args.b());
978 /// args.setResultIsActive(args.bIsActive());
979 /// } else {
980 /// // Preserve the A value and its active state.
981 /// args.setResult(args.a());
982 /// args.setResultIsActive(args.aIsActive());
983 /// }
984 /// }
985 /// };
986 /// DoubleTree aTree = ...;
987 /// FloatTree bTree = ...;
988 /// DoubleTree resultTree;
989 /// resultTree.combine2Extended(aTree, bTree, Local::max);
990 /// }
991 /// @endcode
992 template<typename ExtendedCombineOp, typename OtherTreeType /*= Tree*/>
993 void combine2Extended(const Tree& a, const OtherTreeType& b, ExtendedCombineOp& op,
994 bool prune = false);
995 template<typename ExtendedCombineOp, typename OtherTreeType /*= Tree*/>
996 void combine2Extended(const Tree& a, const OtherTreeType& b, const ExtendedCombineOp&,
997 bool prune = false);
998
999 //
1000 // Iteration
1001 //
1002 //@{
1003 /// Return an iterator over children of the root node.
1004 typename RootNodeType::ChildOnCIter beginRootChildren() const { return mRoot.cbeginChildOn(); }
1005 typename RootNodeType::ChildOnCIter cbeginRootChildren() const { return mRoot.cbeginChildOn(); }
1006 typename RootNodeType::ChildOnIter beginRootChildren() { return mRoot.beginChildOn(); }
1007 //@}
1008
1009 //@{
1010 /// Return an iterator over non-child entries of the root node's table.
1011 typename RootNodeType::ChildOffCIter beginRootTiles() const { return mRoot.cbeginChildOff(); }
1012 typename RootNodeType::ChildOffCIter cbeginRootTiles() const { return mRoot.cbeginChildOff(); }
1013 typename RootNodeType::ChildOffIter beginRootTiles() { return mRoot.beginChildOff(); }
1014 //@}
1015
1016 //@{
1017 /// Return an iterator over all entries of the root node's table.
1018 typename RootNodeType::ChildAllCIter beginRootDense() const { return mRoot.cbeginChildAll(); }
1019 typename RootNodeType::ChildAllCIter cbeginRootDense() const { return mRoot.cbeginChildAll(); }
1020 typename RootNodeType::ChildAllIter beginRootDense() { return mRoot.beginChildAll(); }
1021 //@}
1022
1023
1024 //@{
1025 /// Iterator over all nodes in this tree
1028 //@}
1029
1030 //@{
1031 /// Iterator over all leaf nodes in this tree
1034 //@}
1035
1036 //@{
1037 /// Return an iterator over all nodes in this tree.
1038 NodeIter beginNode() { return NodeIter(*this); }
1039 NodeCIter beginNode() const { return NodeCIter(*this); }
1040 NodeCIter cbeginNode() const { return NodeCIter(*this); }
1041 //@}
1042
1043 //@{
1044 /// Return an iterator over all leaf nodes in this tree.
1045 LeafIter beginLeaf() { return LeafIter(*this); }
1046 LeafCIter beginLeaf() const { return LeafCIter(*this); }
1047 LeafCIter cbeginLeaf() const { return LeafCIter(*this); }
1048 //@}
1049
1056
1057 //@{
1058 /// Return an iterator over all values (tile and voxel) across all nodes.
1060 ValueAllCIter beginValueAll() const { return ValueAllCIter(*this); }
1061 ValueAllCIter cbeginValueAll() const { return ValueAllCIter(*this); }
1062 //@}
1063 //@{
1064 /// Return an iterator over active values (tile and voxel) across all nodes.
1066 ValueOnCIter beginValueOn() const { return ValueOnCIter(*this); }
1067 ValueOnCIter cbeginValueOn() const { return ValueOnCIter(*this); }
1068 //@}
1069 //@{
1070 /// Return an iterator over inactive values (tile and voxel) across all nodes.
1072 ValueOffCIter beginValueOff() const { return ValueOffCIter(*this); }
1073 ValueOffCIter cbeginValueOff() const { return ValueOffCIter(*this); }
1074 //@}
1075
1076 /// @brief Return an iterator of type @c IterT (for example, begin<ValueOnIter>() is
1077 /// equivalent to beginValueOn()).
1078 template<typename IterT> IterT begin();
1079 /// @brief Return a const iterator of type CIterT (for example, cbegin<ValueOnCIter>()
1080 /// is equivalent to cbeginValueOn()).
1081 template<typename CIterT> CIterT cbegin() const;
1082
1083
1084protected:
1085 using AccessorRegistry = tbb::concurrent_hash_map<ValueAccessorBase<Tree, true>*, bool>;
1086 using ConstAccessorRegistry = tbb::concurrent_hash_map<ValueAccessorBase<const Tree, true>*, bool>;
1087
1088 /// @brief Notify all registered accessors, by calling ValueAccessor::release(),
1089 /// that this tree is about to be deleted.
1091
1092 // TBB body object used to deallocates nodes in parallel.
1093 template<typename NodeType>
1095 DeallocateNodes(std::vector<NodeType*>& nodes)
1096 : mNodes(nodes.empty() ? nullptr : &nodes.front()) { }
1097 void operator()(const tbb::blocked_range<size_t>& range) const {
1098 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1099 delete mNodes[n]; mNodes[n] = nullptr;
1100 }
1101 }
1102 NodeType ** const mNodes;
1103 };
1104
1105 //
1106 // Data members
1107 //
1108 RootNodeType mRoot; // root node of the tree
1111}; // end of Tree class
1112
1113
1114/// @brief Tree3<T, N1, N2>::Type is the type of a three-level tree
1115/// (Root, Internal, Leaf) with value type T and
1116/// internal and leaf node log dimensions N1 and N2, respectively.
1117/// @note This is NOT the standard tree configuration (Tree4 is).
1118template<typename T, Index N1=4, Index N2=3>
1122
1123
1124/// @brief Tree4<T, N1, N2, N3>::Type is the type of a four-level tree
1125/// (Root, Internal, Internal, Leaf) with value type T and
1126/// internal and leaf node log dimensions N1, N2 and N3, respectively.
1127/// @note This is the standard tree configuration.
1128template<typename T, Index N1=5, Index N2=4, Index N3=3>
1132
1133/// @brief Tree5<T, N1, N2, N3, N4>::Type is the type of a five-level tree
1134/// (Root, Internal, Internal, Internal, Leaf) with value type T and
1135/// internal and leaf node log dimensions N1, N2, N3 and N4, respectively.
1136/// @note This is NOT the standard tree configuration (Tree4 is).
1137template<typename T, Index N1=6, Index N2=5, Index N3=4, Index N4=3>
1142
1143
1144////////////////////////////////////////
1145
1146
1147inline void
1148TreeBase::readTopology(std::istream& is, bool /*saveFloatAsHalf*/)
1149{
1150 int32_t bufferCount;
1151 is.read(reinterpret_cast<char*>(&bufferCount), sizeof(int32_t));
1152 if (bufferCount != 1) OPENVDB_LOG_WARN("multi-buffer trees are no longer supported");
1153}
1154
1155
1156inline void
1157TreeBase::writeTopology(std::ostream& os, bool /*saveFloatAsHalf*/) const
1158{
1159 int32_t bufferCount = 1;
1160 os.write(reinterpret_cast<char*>(&bufferCount), sizeof(int32_t));
1161}
1162
1163
1164inline void
1165TreeBase::print(std::ostream& os, int /*verboseLevel*/) const
1166{
1167 os << " Tree Type: " << type()
1168 << " Active Voxel Count: " << activeVoxelCount() << std::endl
1169 << " Active tile Count: " << activeTileCount() << std::endl
1170 << " Inactive Voxel Count: " << inactiveVoxelCount() << std::endl
1171 << " Leaf Node Count: " << leafCount() << std::endl
1172 << " Non-leaf Node Count: " << nonLeafCount() << std::endl;
1173}
1174
1175
1176////////////////////////////////////////
1177
1178
1179//
1180// Type traits for tree iterators
1181//
1182
1183/// @brief TreeIterTraits provides, for all tree iterators, a begin(tree) function
1184/// that returns an iterator over a tree of arbitrary type.
1185template<typename TreeT, typename IterT> struct TreeIterTraits;
1186
1187template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::RootNodeType::ChildOnIter> {
1188 static typename TreeT::RootNodeType::ChildOnIter begin(TreeT& tree) {
1189 return tree.beginRootChildren();
1190 }
1191};
1192
1193template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::RootNodeType::ChildOnCIter> {
1194 static typename TreeT::RootNodeType::ChildOnCIter begin(const TreeT& tree) {
1195 return tree.cbeginRootChildren();
1196 }
1197};
1198
1199template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::RootNodeType::ChildOffIter> {
1200 static typename TreeT::RootNodeType::ChildOffIter begin(TreeT& tree) {
1201 return tree.beginRootTiles();
1202 }
1203};
1204
1205template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::RootNodeType::ChildOffCIter> {
1206 static typename TreeT::RootNodeType::ChildOffCIter begin(const TreeT& tree) {
1207 return tree.cbeginRootTiles();
1208 }
1209};
1210
1211template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::RootNodeType::ChildAllIter> {
1212 static typename TreeT::RootNodeType::ChildAllIter begin(TreeT& tree) {
1213 return tree.beginRootDense();
1214 }
1215};
1216
1217template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::RootNodeType::ChildAllCIter> {
1218 static typename TreeT::RootNodeType::ChildAllCIter begin(const TreeT& tree) {
1219 return tree.cbeginRootDense();
1220 }
1221};
1222
1223template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::NodeIter> {
1224 static typename TreeT::NodeIter begin(TreeT& tree) { return tree.beginNode(); }
1225};
1226
1227template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::NodeCIter> {
1228 static typename TreeT::NodeCIter begin(const TreeT& tree) { return tree.cbeginNode(); }
1229};
1230
1231template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::LeafIter> {
1232 static typename TreeT::LeafIter begin(TreeT& tree) { return tree.beginLeaf(); }
1233};
1234
1235template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::LeafCIter> {
1236 static typename TreeT::LeafCIter begin(const TreeT& tree) { return tree.cbeginLeaf(); }
1237};
1238
1239template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::ValueOnIter> {
1240 static typename TreeT::ValueOnIter begin(TreeT& tree) { return tree.beginValueOn(); }
1241};
1242
1243template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::ValueOnCIter> {
1244 static typename TreeT::ValueOnCIter begin(const TreeT& tree) { return tree.cbeginValueOn(); }
1245};
1246
1247template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::ValueOffIter> {
1248 static typename TreeT::ValueOffIter begin(TreeT& tree) { return tree.beginValueOff(); }
1249};
1250
1251template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::ValueOffCIter> {
1252 static typename TreeT::ValueOffCIter begin(const TreeT& tree) { return tree.cbeginValueOff(); }
1253};
1254
1255template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::ValueAllIter> {
1256 static typename TreeT::ValueAllIter begin(TreeT& tree) { return tree.beginValueAll(); }
1257};
1258
1259template<typename TreeT> struct TreeIterTraits<TreeT, typename TreeT::ValueAllCIter> {
1260 static typename TreeT::ValueAllCIter begin(const TreeT& tree) { return tree.cbeginValueAll(); }
1261};
1262
1263
1264template<typename RootNodeType>
1265template<typename IterT>
1266inline IterT
1271
1272
1273template<typename RootNodeType>
1274template<typename IterT>
1275inline IterT
1280
1281
1282////////////////////////////////////////
1283
1284
1285template<typename RootNodeType>
1286void
1287Tree<RootNodeType>::readTopology(std::istream& is, bool saveFloatAsHalf)
1288{
1289 this->clearAllAccessors();
1290 TreeBase::readTopology(is, saveFloatAsHalf);
1291 mRoot.readTopology(is, saveFloatAsHalf);
1292}
1293
1294
1295template<typename RootNodeType>
1296void
1297Tree<RootNodeType>::writeTopology(std::ostream& os, bool saveFloatAsHalf) const
1298{
1299 TreeBase::writeTopology(os, saveFloatAsHalf);
1300 mRoot.writeTopology(os, saveFloatAsHalf);
1301}
1302
1303
1304template<typename RootNodeType>
1305inline void
1306Tree<RootNodeType>::readBuffers(std::istream &is, bool saveFloatAsHalf)
1307{
1308 this->clearAllAccessors();
1309 mRoot.readBuffers(is, saveFloatAsHalf);
1310}
1311
1312
1313template<typename RootNodeType>
1314inline void
1315Tree<RootNodeType>::readBuffers(std::istream &is, const CoordBBox& bbox, bool saveFloatAsHalf)
1316{
1317 this->clearAllAccessors();
1318 mRoot.readBuffers(is, bbox, saveFloatAsHalf);
1319}
1320
1321
1322template<typename RootNodeType>
1323inline void
1325{
1326 for (LeafCIter it = this->cbeginLeaf(); it; ++it) {
1327 // Retrieving the value of a leaf voxel forces loading of the leaf node's voxel buffer.
1328 it->getValue(Index(0));
1329 }
1330}
1331
1332
1333template<typename RootNodeType>
1334inline void
1335Tree<RootNodeType>::writeBuffers(std::ostream &os, bool saveFloatAsHalf) const
1336{
1337 mRoot.writeBuffers(os, saveFloatAsHalf);
1338}
1339
1340
1341template<typename RootNodeType>
1342template<typename ArrayT>
1343inline void
1345{
1346 using NodeT = typename std::remove_pointer<typename ArrayT::value_type>::type;
1347 static_assert(!std::is_same<NodeT, RootNodeType>::value,
1348 "getNodes() does not work for the RootNode. Use Tree::root()");
1349 mRoot.getNodes(array);
1350}
1351
1352
1353template<typename RootNodeType>
1354template<typename ArrayT>
1355inline void
1357{
1358 using NodeT = typename std::remove_pointer<typename ArrayT::value_type>::type;
1359 static_assert(!std::is_same<NodeT, const RootNodeType>::value,
1360 "getNodes() does not work for the RootNode. Use Tree::root()");
1361 mRoot.getNodes(array);
1362}
1363
1364
1365template<typename RootNodeType>
1366inline void
1368{
1369 std::vector<LeafNodeType*> leafnodes;
1370 this->stealNodes(leafnodes);
1371
1372 tbb::parallel_for(tbb::blocked_range<size_t>(0, leafnodes.size()),
1374
1375 std::vector<typename RootNodeType::ChildNodeType*> internalNodes;
1376 this->stealNodes(internalNodes);
1377
1378 tbb::parallel_for(tbb::blocked_range<size_t>(0, internalNodes.size()),
1380
1381 mRoot.clear();
1382
1383 this->clearAllAccessors();
1384}
1385
1386
1387////////////////////////////////////////
1388
1389
1390template<typename RootNodeType>
1393{
1394 return Accessor(*this);
1395}
1396
1397template<typename RootNodeType>
1403
1404template<typename RootNodeType>
1407{
1408 return ConstAccessor(*this);
1409}
1410
1411template<typename RootNodeType>
1414{
1415 return ConstAccessor(*this);
1416}
1417
1418template<typename RootNodeType>
1424
1425template<typename RootNodeType>
1426inline void
1428{
1429 typename AccessorRegistry::accessor a;
1430 mAccessorRegistry.insert(a, &accessor);
1431}
1432
1433
1434template<typename RootNodeType>
1435inline void
1437{
1438 typename ConstAccessorRegistry::accessor a;
1439 mConstAccessorRegistry.insert(a, &accessor);
1440}
1441
1442
1443template<typename RootNodeType>
1444inline void
1449
1450
1451template<typename RootNodeType>
1452inline void
1457
1458
1459template<typename RootNodeType>
1460inline void
1462{
1463 for (typename AccessorRegistry::iterator it = mAccessorRegistry.begin();
1464 it != mAccessorRegistry.end(); ++it)
1465 {
1466 if (it->first) it->first->clear();
1467 }
1468
1469 for (typename ConstAccessorRegistry::iterator it = mConstAccessorRegistry.begin();
1470 it != mConstAccessorRegistry.end(); ++it)
1471 {
1472 if (it->first) it->first->clear();
1473 }
1474}
1475
1476
1477template<typename RootNodeType>
1478inline void
1480{
1481 mAccessorRegistry.erase(nullptr);
1482 for (typename AccessorRegistry::iterator it = mAccessorRegistry.begin();
1483 it != mAccessorRegistry.end(); ++it)
1484 {
1485 it->first->release();
1486 }
1487 mAccessorRegistry.clear();
1488
1489 mAccessorRegistry.erase(nullptr);
1490 for (typename ConstAccessorRegistry::iterator it = mConstAccessorRegistry.begin();
1491 it != mConstAccessorRegistry.end(); ++it)
1492 {
1493 it->first->release();
1494 }
1495 mConstAccessorRegistry.clear();
1496}
1497
1498
1499////////////////////////////////////////
1500
1501
1502template<typename RootNodeType>
1503inline const typename RootNodeType::ValueType&
1505{
1506 return mRoot.getValue(xyz);
1507}
1508
1509
1510template<typename RootNodeType>
1511template<typename AccessT>
1512inline const typename RootNodeType::ValueType&
1513Tree<RootNodeType>::getValue(const Coord& xyz, AccessT& accessor) const
1514{
1515 return accessor.getValue(xyz);
1516}
1517
1518
1519template<typename RootNodeType>
1520inline int
1522{
1523 return mRoot.getValueDepth(xyz);
1524}
1525
1526
1527template<typename RootNodeType>
1528inline void
1530{
1531 mRoot.setValueOff(xyz);
1532}
1533
1534
1535template<typename RootNodeType>
1536inline void
1538{
1539 mRoot.setValueOff(xyz, value);
1540}
1541
1542
1543template<typename RootNodeType>
1544inline void
1546{
1547 mRoot.setActiveState(xyz, on);
1548}
1549
1550
1551template<typename RootNodeType>
1552inline void
1554{
1555 mRoot.setValueOn(xyz, value);
1556}
1557
1558template<typename RootNodeType>
1559inline void
1561{
1562 mRoot.setValueOnly(xyz, value);
1563}
1564
1565template<typename RootNodeType>
1566template<typename AccessT>
1567inline void
1568Tree<RootNodeType>::setValue(const Coord& xyz, const ValueType& value, AccessT& accessor)
1569{
1570 accessor.setValue(xyz, value);
1571}
1572
1573
1574template<typename RootNodeType>
1575inline void
1577{
1578 mRoot.setActiveState(xyz, true);
1579}
1580
1581
1582template<typename RootNodeType>
1583inline void
1585{
1586 mRoot.setValueOn(xyz, value);
1587}
1588
1589
1590template<typename RootNodeType>
1591template<typename ModifyOp>
1592inline void
1593Tree<RootNodeType>::modifyValue(const Coord& xyz, const ModifyOp& op)
1594{
1595 mRoot.modifyValue(xyz, op);
1596}
1597
1598
1599template<typename RootNodeType>
1600template<typename ModifyOp>
1601inline void
1603{
1604 mRoot.modifyValueAndActiveState(xyz, op);
1605}
1606
1607
1608template<typename RootNodeType>
1609inline bool
1611{
1612 return mRoot.probeValue(xyz, value);
1613}
1614
1615
1616////////////////////////////////////////
1617
1618
1619template<typename RootNodeType>
1620inline void
1622 const ValueType& value, bool active)
1623{
1624 mRoot.addTile(level, xyz, value, active);
1625}
1626
1627
1628template<typename RootNodeType>
1629template<typename NodeT>
1630inline NodeT*
1631Tree<RootNodeType>::stealNode(const Coord& xyz, const ValueType& value, bool active)
1632{
1633 this->clearAllAccessors();
1634 return mRoot.template stealNode<NodeT>(xyz, value, active);
1635}
1636
1637
1638template<typename RootNodeType>
1639inline typename RootNodeType::LeafNodeType*
1641{
1642 return mRoot.touchLeaf(xyz);
1643}
1644
1645
1646template<typename RootNodeType>
1647inline typename RootNodeType::LeafNodeType*
1649{
1650 return mRoot.probeLeaf(xyz);
1651}
1652
1653
1654template<typename RootNodeType>
1655inline const typename RootNodeType::LeafNodeType*
1657{
1658 return mRoot.probeConstLeaf(xyz);
1659}
1660
1661
1662template<typename RootNodeType>
1663template<typename NodeType>
1664inline NodeType*
1666{
1667 return mRoot.template probeNode<NodeType>(xyz);
1668}
1669
1670
1671template<typename RootNodeType>
1672template<typename NodeType>
1673inline const NodeType*
1675{
1676 return this->template probeConstNode<NodeType>(xyz);
1677}
1678
1679
1680template<typename RootNodeType>
1681template<typename NodeType>
1682inline const NodeType*
1684{
1685 return mRoot.template probeConstNode<NodeType>(xyz);
1686}
1687
1688
1689////////////////////////////////////////
1690
1691
1692template<typename RootNodeType>
1693inline void
1695{
1696 this->clearAllAccessors();
1697 return mRoot.clip(bbox);
1698}
1699
1700
1701template<typename RootNodeType>
1702inline void
1704{
1705 this->clearAllAccessors();
1706 for (LeafIter it = this->beginLeaf(); it; ) {
1707 const LeafNodeType* leaf = it.getLeaf();
1708 ++it; // advance the iterator before deleting the leaf node
1709 if (!leaf->isAllocated()) {
1710 this->addTile(/*level=*/0, leaf->origin(), this->background(), /*active=*/false);
1711 }
1712 }
1713}
1714
1715#if OPENVDB_ABI_VERSION_NUMBER >= 12
1716template<typename RootNodeType>
1717inline Index64
1719{
1720 Index64 sum = 0;
1721 for (auto it = this->cbeginLeaf(); it; ++it) if (!it->isAllocated()) ++sum;
1722 return sum;
1723}
1724#else
1725template<typename RootNodeType>
1726inline Index32
1728{
1729 Index32 sum = 0;
1730 for (auto it = this->cbeginLeaf(); it; ++it) if (!it->isAllocated()) ++sum;
1731 return sum;
1732}
1733#endif
1734
1735
1736template<typename RootNodeType>
1737inline void
1738Tree<RootNodeType>::sparseFill(const CoordBBox& bbox, const ValueType& value, bool active)
1739{
1740 this->clearAllAccessors();
1741 return mRoot.sparseFill(bbox, value, active);
1742}
1743
1744
1745template<typename RootNodeType>
1746inline void
1747Tree<RootNodeType>::denseFill(const CoordBBox& bbox, const ValueType& value, bool active)
1748{
1749 this->clearAllAccessors();
1750 return mRoot.denseFill(bbox, value, active);
1751}
1752
1753
1754template<typename RootNodeType>
1755inline void
1757{
1758 this->clearAllAccessors();
1759 mRoot.voxelizeActiveTiles(threaded);
1760}
1761
1762
1763template<typename RootNodeType>
1766{
1767 Metadata::Ptr result;
1769 using MetadataT = TypedMetadata<ValueType>;
1771 if (result->typeName() == MetadataT::staticTypeName()) {
1772 MetadataT* m = static_cast<MetadataT*>(result.get());
1773 m->value() = mRoot.background();
1774 }
1775 }
1776 return result;
1777}
1778
1779
1780////////////////////////////////////////
1781
1782
1783template<typename RootNodeType>
1784inline void
1786{
1787 this->clearAllAccessors();
1788 other.clearAllAccessors();
1789 switch (policy) {
1791 mRoot.template merge<MERGE_ACTIVE_STATES>(other.mRoot); break;
1792 case MERGE_NODES:
1793 mRoot.template merge<MERGE_NODES>(other.mRoot); break;
1795 mRoot.template merge<MERGE_ACTIVE_STATES_AND_NODES>(other.mRoot); break;
1796 }
1797}
1798
1799
1800template<typename RootNodeType>
1801template<typename OtherRootNodeType>
1802inline void
1803Tree<RootNodeType>::topologyUnion(const Tree<OtherRootNodeType>& other, const bool preserveTiles)
1804{
1805 this->clearAllAccessors();
1806 mRoot.topologyUnion(other.root(), preserveTiles);
1807}
1808
1809template<typename RootNodeType>
1810template<typename OtherRootNodeType>
1811inline void
1813{
1814 this->clearAllAccessors();
1815 mRoot.topologyIntersection(other.root());
1816}
1817
1818template<typename RootNodeType>
1819template<typename OtherRootNodeType>
1820inline void
1822{
1823 this->clearAllAccessors();
1824 mRoot.topologyDifference(other.root());
1825}
1826
1827////////////////////////////////////////
1828
1829
1830/// @brief Helper class to adapt a three-argument (a, b, result) CombineOp functor
1831/// into a single-argument functor that accepts a CombineArgs struct
1832template<typename AValueT, typename CombineOp, typename BValueT = AValueT>
1834{
1835 CombineOpAdapter(CombineOp& _op): op(_op) {}
1836
1838 op(args.a(), args.b(), args.result());
1839 }
1840
1841 CombineOp& op;
1842};
1843
1844
1845template<typename RootNodeType>
1846template<typename CombineOp>
1847inline void
1848Tree<RootNodeType>::combine(Tree& other, CombineOp& op, bool prune)
1849{
1851 this->combineExtended(other, extendedOp, prune);
1852}
1853
1854
1855/// @internal This overload is needed (for ICC and GCC, but not for VC) to disambiguate
1856/// code like this: <tt>aTree.combine(bTree, MyCombineOp(...))</tt>.
1857template<typename RootNodeType>
1858template<typename CombineOp>
1859inline void
1860Tree<RootNodeType>::combine(Tree& other, const CombineOp& op, bool prune)
1861{
1863 this->combineExtended(other, extendedOp, prune);
1864}
1865
1866
1867template<typename RootNodeType>
1868template<typename ExtendedCombineOp>
1869inline void
1870Tree<RootNodeType>::combineExtended(Tree& other, ExtendedCombineOp& op, bool prune)
1871{
1872 this->clearAllAccessors();
1873 mRoot.combine(other.root(), op, prune);
1874}
1875
1876
1877/// @internal This overload is needed (for ICC and GCC, but not for VC) to disambiguate
1878/// code like this: <tt>aTree.combineExtended(bTree, MyCombineOp(...))</tt>.
1879template<typename RootNodeType>
1880template<typename ExtendedCombineOp>
1881inline void
1882Tree<RootNodeType>::combineExtended(Tree& other, const ExtendedCombineOp& op, bool prune)
1883{
1884 this->clearAllAccessors();
1886}
1887
1888
1889template<typename RootNodeType>
1890template<typename CombineOp, typename OtherTreeType>
1891inline void
1892Tree<RootNodeType>::combine2(const Tree& a, const OtherTreeType& b, CombineOp& op, bool prune)
1893{
1895 this->combine2Extended(a, b, extendedOp, prune);
1896}
1897
1898
1899/// @internal This overload is needed (for ICC and GCC, but not for VC) to disambiguate
1900/// code like this: <tt>tree.combine2(aTree, bTree, MyCombineOp(...))</tt>.
1901template<typename RootNodeType>
1902template<typename CombineOp, typename OtherTreeType>
1903inline void
1904Tree<RootNodeType>::combine2(const Tree& a, const OtherTreeType& b, const CombineOp& op, bool prune)
1905{
1907 this->combine2Extended(a, b, extendedOp, prune);
1908}
1909
1910
1911template<typename RootNodeType>
1912template<typename ExtendedCombineOp, typename OtherTreeType>
1913inline void
1914Tree<RootNodeType>::combine2Extended(const Tree& a, const OtherTreeType& b,
1915 ExtendedCombineOp& op, bool prune)
1916{
1917 this->clearAllAccessors();
1918 mRoot.combine2(a.root(), b.root(), op, prune);
1919}
1920
1921
1922/// @internal This overload is needed (for ICC and GCC, but not for VC) to disambiguate
1923/// code like the following, where the functor argument is a temporary:
1924/// <tt>tree.combine2Extended(aTree, bTree, MyCombineOp(...))</tt>.
1925template<typename RootNodeType>
1926template<typename ExtendedCombineOp, typename OtherTreeType>
1927inline void
1928Tree<RootNodeType>::combine2Extended(const Tree& a, const OtherTreeType& b,
1929 const ExtendedCombineOp& op, bool prune)
1930{
1931 this->clearAllAccessors();
1932 mRoot.template combine2<const ExtendedCombineOp>(a.root(), b.root(), op, prune);
1933}
1934
1935
1936////////////////////////////////////////
1937
1938
1939template<typename RootNodeType>
1940inline const Name&
1942{
1943 static std::string sTreeTypeName = []()
1944 {
1945 // @todo use RootNode::NodeChain::foreach() instead
1946 std::vector<Index> dims;
1948 std::ostringstream ostr;
1949 ostr << "Tree_" << typeNameAsString<BuildType>();
1950 for (size_t i = 1, N = dims.size(); i < N; ++i) { // start from 1 to skip the RootNode
1951 ostr << "_" << dims[i];
1952 }
1953 return ostr.str();
1954 }();
1955 return sTreeTypeName;
1956}
1957
1958
1959template<typename RootNodeType>
1960template<typename OtherRootNodeType>
1961inline bool
1963{
1964 return mRoot.hasSameTopology(other.root());
1965}
1966
1967
1968template<typename RootNodeType>
1969inline bool
1971{
1972 bbox.reset(); // default invalid bbox
1973
1974 if (this->empty()) return false; // empty
1975
1976 mRoot.evalActiveBoundingBox(bbox, false);
1977
1978 return !bbox.empty();
1979}
1980
1981template<typename RootNodeType>
1982inline bool
1984{
1985 bbox.reset(); // default invalid bbox
1986
1987 if (this->empty()) return false; // empty
1988
1989 mRoot.evalActiveBoundingBox(bbox, true);
1990
1991 return !bbox.empty();
1992}
1993
1994
1995template<typename RootNodeType>
1996inline bool
1998{
1999 CoordBBox bbox;
2000 bool notEmpty = this->evalActiveVoxelBoundingBox(bbox);
2001 dim = bbox.extents();
2002 return notEmpty;
2003}
2004
2005
2006template<typename RootNodeType>
2007inline bool
2009{
2010 CoordBBox bbox;
2011 bool notEmpty = this->evalLeafBoundingBox(bbox);
2012 dim = bbox.extents();
2013 return notEmpty;
2014}
2015
2016
2017template<typename RootNodeType>
2018inline void
2020{
2021 minVal = maxVal = zeroVal<ValueType>();
2022 if (ValueOnCIter iter = this->cbeginValueOn()) {
2023 minVal = maxVal = *iter;
2024 for (++iter; iter; ++iter) {
2025 const ValueType& val = *iter;
2026 if (math::cwiseLessThan(val, minVal)) minVal = val;
2027 if (math::cwiseGreaterThan(val, maxVal)) maxVal = val;
2028 }
2029 }
2030}
2031
2032
2033template<typename RootNodeType>
2034inline void
2036{
2037 dims.clear();
2038 RootNodeType::getNodeLog2Dims(dims);
2039}
2040
2041
2042template<typename RootNodeType>
2043inline void
2044Tree<RootNodeType>::print(std::ostream& os, int verboseLevel) const
2045{
2046 if (verboseLevel <= 0) return;
2047
2048 /// @todo Consider using boost::io::ios_precision_saver instead.
2049 struct OnExit {
2050 std::ostream& os;
2051 std::streamsize savedPrecision;
2052 OnExit(std::ostream& _os): os(_os), savedPrecision(os.precision()) {}
2053 ~OnExit() { os.precision(savedPrecision); }
2054 };
2055 OnExit restorePrecision(os);
2056
2057 std::vector<Index> dims;
2058 Tree::getNodeLog2Dims(dims);// leaf is the last element
2059
2060 os << "Information about Tree:\n"
2061 << " Type: " << this->type() << "\n";
2062
2063 os << " Configuration:\n";
2064
2065 if (verboseLevel <= 1) {
2066 // Print node types and sizes.
2067 os << " Root(" << mRoot.getTableSize() << ")";
2068 if (dims.size() > 1) {
2069 for (size_t i = 1, N = dims.size() - 1; i < N; ++i) {
2070 os << ", Internal(" << (1 << dims[i]) << "^3)";
2071 }
2072 os << ", Leaf(" << (1 << dims.back()) << "^3)\n";
2073 }
2074 os << " Background value: " << mRoot.background() << "\n";
2075 return;
2076 }
2077
2078 // The following is tree information that is expensive to extract.
2079
2080 ValueType minVal = zeroVal<ValueType>(), maxVal = zeroVal<ValueType>();
2081 if (verboseLevel > 3) {
2082 // This forces loading of all non-resident nodes.
2083 const math::MinMax<ValueType> extrema = tools::minMax(*this);
2084 minVal = extrema.min();
2085 maxVal = extrema.max();
2086 }
2087
2088 const auto nodeCount = this->nodeCount();//fast
2089 const Index64 leafCount = nodeCount.front();// leaf is the first element
2090 OPENVDB_ASSERT(dims.size() == nodeCount.size());
2091
2092 Index64 totalNodeCount = 0;
2093 for (size_t i = 0; i < nodeCount.size(); ++i) totalNodeCount += nodeCount[i];
2094
2095 // Print node types, counts and sizes.
2096 os << " Root(1 x " << mRoot.getTableSize() << ")";
2097 if (dims.size() >= 2) {
2098 for (size_t i = 1, N = dims.size() - 1; i < N; ++i) {
2099 os << ", Internal(" << util::formattedInt(nodeCount[N - i]);
2100 os << " x " << (1 << dims[i]) << "^3)";
2101 }
2102 os << ", Leaf(" << util::formattedInt(leafCount);
2103 os << " x " << (1 << dims.back()) << "^3)\n";
2104 }
2105 os << " Background value: " << mRoot.background() << "\n";
2106
2107 // Statistics of topology and values
2108
2109 if (verboseLevel > 3) {
2110 os << " Min value: " << minVal << "\n";
2111 os << " Max value: " << maxVal << "\n";
2112 }
2113
2114 const Index64
2115 numActiveVoxels = this->activeVoxelCount(),
2116 numActiveLeafVoxels = this->activeLeafVoxelCount(),
2117 numActiveTiles = this->activeTileCount();
2118
2119 os << " Number of active voxels: " << util::formattedInt(numActiveVoxels) << "\n";
2120 os << " Number of active tiles: " << util::formattedInt(numActiveTiles) << "\n";
2121
2122 Coord dim(0, 0, 0);
2123 Index64 totalVoxels = 0;
2124 if (numActiveVoxels) { // nonempty
2125 CoordBBox bbox;
2126 this->evalActiveVoxelBoundingBox(bbox);
2127 dim = bbox.extents();
2128 totalVoxels = dim.x() * uint64_t(dim.y()) * dim.z();
2129
2130 os << " Bounding box of active voxels: " << bbox << "\n";
2131 os << " Dimensions of active voxels: "
2132 << dim[0] << " x " << dim[1] << " x " << dim[2] << "\n";
2133
2134 const double activeRatio = (100.0 * double(numActiveVoxels)) / double(totalVoxels);
2135 os << " Percentage of active voxels: " << std::setprecision(3) << activeRatio << "%\n";
2136
2137 if (leafCount > 0) {
2138 const double fillRatio = (100.0 * double(numActiveLeafVoxels))
2139 / (double(leafCount) * double(LeafNodeType::NUM_VOXELS));
2140 os << " Average leaf node fill ratio: " << fillRatio << "%\n";
2141 }
2142
2143 if (verboseLevel > 2) {
2144 Index64 sum = 0;// count the number of unallocated leaf nodes
2145 for (auto it = this->cbeginLeaf(); it; ++it) if (!it->isAllocated()) ++sum;
2146 os << " Number of unallocated nodes: "
2147 << util::formattedInt(sum) << " ("
2148 << (100.0 * double(sum) / double(totalNodeCount)) << "%)\n";
2149 }
2150 } else {
2151 os << " Tree is empty!\n";
2152 }
2153 os << std::flush;
2154
2155 if (verboseLevel == 2) return;
2156
2157 // Memory footprint in bytes
2158 const Index64
2159 actualMem = this->memUsage(),
2160 denseMem = sizeof(ValueType) * totalVoxels,
2161 voxelsMem = sizeof(ValueType) * numActiveLeafVoxels;
2162 ///< @todo not accurate for BoolTree (and probably should count tile values)
2163
2164 os << "Memory footprint:\n";
2165 util::printBytes(os, actualMem, " Actual: ");
2166 util::printBytes(os, voxelsMem, " Active leaf voxels: ");
2167
2168 if (numActiveVoxels) {
2169 util::printBytes(os, denseMem, " Dense equivalent: ");
2170 os << " Actual footprint is " << (100.0 * double(actualMem) / double(denseMem))
2171 << "% of an equivalent dense volume\n";
2172 os << " Leaf voxel footprint is " << (100.0 * double(voxelsMem) / double(actualMem))
2173 << "% of actual footprint\n";
2174 }
2175}
2176
2177} // namespace tree
2178} // namespace OPENVDB_VERSION_NAME
2179} // namespace openvdb
2180
2181#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.
Internal table nodes for OpenVDB trees.
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
#define OPENVDB_NO_DEPRECATION_WARNING_END
Definition Platform.h:195
#define OPENVDB_NO_DEPRECATION_WARNING_BEGIN
Bracket code with OPENVDB_NO_DEPRECATION_WARNING_BEGIN/_END, to inhibit warnings about deprecated cod...
Definition Platform.h:194
#define OPENVDB_API
Definition Platform.h:268
#define OPENVDB_DEPRECATED_MESSAGE(msg)
Definition Platform.h:148
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:569
const AValueType & result() const
Get the output value.
Definition Types.h:613
const BValueType & b() const
Get the B input value.
Definition Types.h:610
const AValueType & a() const
Get the A input value.
Definition Types.h:608
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:683
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
DenseIter< RootNode, MapIter, ChildType, ValueType > ChildAllIter
Definition RootNode.h:366
typename ChildType::LeafNodeType LeafNodeType
Definition RootNode.h:43
ChildIter< RootNode, MapIter, ChildOnPred, ChildType > ChildOnIter
Definition RootNode.h:362
ValueIter< const RootNode, MapCIter, ChildOffPred, ValueType > ChildOffCIter
Definition RootNode.h:365
static const Index LEVEL
Definition RootNode.h:47
typename ChildType::ValueType ValueType
Definition RootNode.h:44
typename ChildType::BuildType BuildType
Definition RootNode.h:45
DenseIter< const RootNode, MapCIter, const ChildType, const ValueType > ChildAllCIter
Definition RootNode.h:367
ValueIter< RootNode, MapIter, ChildOffPred, const ValueType > ChildOffIter
Definition RootNode.h:364
ChildIter< const RootNode, MapCIter, ChildOnPred, const ChildType > ChildOnCIter
Definition RootNode.h:363
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:1157
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:1165
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:1148
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:1287
RootNodeType::ChildAllCIter beginRootDense() const
Return an iterator over all entries of the root node's table.
Definition Tree.h:1018
Metadata::Ptr getBackgroundValue() const override
Return this tree's background value wrapped as metadata.
Definition Tree.h:1765
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:1521
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:1962
Index64 unallocatedLeafCount() const override
Return the total number of unallocated leaf nodes residing in this tree.
Definition Tree.h:1718
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:1983
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:1631
void releaseAccessor(ValueAccessorBase< Tree, false > &) const
Dummy implementations.
Definition Tree.h:719
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:1665
const NodeType * probeNode(const Coord &xyz) const
Definition Tree.h:1674
void combine(Tree &other, CombineOp &op, bool prune=false)
Definition Tree.h:1848
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:720
bool isValueOn(const Coord &xyz) const
Return true if the value at the given coordinates is active.
Definition Tree.h:491
Tree(const Tree &other)
Deep copy constructor.
Definition Tree.h:229
RootNodeType::ChildOffCIter cbeginRootTiles() const
Definition Tree.h:1012
TreeValueIteratorBase< const Tree, typename RootNodeType::ValueOffCIter > ValueOffCIter
Definition Tree.h:1055
LeafCIter beginLeaf() const
Definition Tree.h:1046
void writeBuffers(std::ostream &, bool saveFloatAsHalf=false) const override
Write out all data buffers for this tree.
Definition Tree.h:1335
void writeTopology(std::ostream &, bool saveFloatAsHalf=false) const override
Write the tree topology to a stream.
Definition Tree.h:1297
ValueOffCIter cbeginValueOff() const
Definition Tree.h:1073
Tree(const Tree< OtherRootType > &other)
Value conversion deep copy constructor.
Definition Tree.h:240
const LeafNodeType * probeConstLeaf(const Coord &xyz) const
Definition Tree.h:1656
IterT begin()
Return an iterator of type IterT (for example, begin<ValueOnIter>() is equivalent to beginValueOn()).
Definition Tree.h:1267
void merge(Tree &other, MergePolicy=MERGE_ACTIVE_STATES)
Efficiently merge another tree into this tree using one of several schemes.
Definition Tree.h:1785
TreeValueIteratorBase< const Tree, typename RootNodeType::ValueAllCIter > ValueAllCIter
Definition Tree.h:1051
tree::RootNode< tree::InternalNode< tree::InternalNode< PointDataLeafNode< PointDataIndex32, 3 >, 4 >, 5 > > RootNodeType
Definition Tree.h:200
RootNodeType::ChildAllIter beginRootDense()
Definition Tree.h:1020
Accessor getAccessor()
Return an accessor that provides random read and write access to this tree's voxels.
Definition Tree.h:1392
LeafCIter cbeginLeaf() const
Definition Tree.h:1047
const Name & type() const override
Return the name of this type of tree.
Definition Tree.h:296
RootNodeType::ChildOffIter beginRootTiles()
Definition Tree.h:1013
void getNodes(ArrayT &array)
Adds all nodes of a certain type to a container with the following API:
Definition Tree.h:1344
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:1315
static const Name & treeType()
Return the name of this type of tree.
Definition Tree.h:1941
void voxelizeActiveTiles(bool threaded=true)
Densify active tiles, i.e., replace them with leaf-level active voxels.
Definition Tree.h:1756
RootNodeType::ChildOnCIter beginRootChildren() const
Return an iterator over children of the root node.
Definition Tree.h:1004
void combine(Tree &other, const CombineOp &op, bool prune=false)
Definition Tree.h:1860
bool operator!=(const Tree &) const
Definition Tree.h:299
Tree()
Definition Tree.h:224
void clip(const CoordBBox &)
Set all voxels that lie outside the given axis-aligned box to the background.
Definition Tree.h:1694
ValueAllCIter cbeginValueAll() const
Definition Tree.h:1061
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:552
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:1648
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:1812
void releaseAccessor(ValueAccessorBase< Tree, true > &) const
Deregister an accessor so that it is no longer automatically cleared.
Definition Tree.h:1445
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:1640
RootNodeType::ChildOnIter beginRootChildren()
Definition Tree.h:1006
Index64 leafCount() const override
Return the number of leaf nodes.
Definition Tree.h:363
ValueOnCIter beginValueOn() const
Definition Tree.h:1066
bool operator==(const Tree &) const
Definition Tree.h:298
void attachAccessor(ValueAccessorBase< Tree, true > &) const
Register an accessor for this tree. Registered accessors are automatically cleared whenever one of th...
Definition Tree.h:1427
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:1602
ConstUnsafeAccessor getConstUnsafeAccessor()
Return an unsafe accessor that provides random read-only access to this tree's voxels.
Definition Tree.h:1420
void combine2Extended(const Tree &a, const OtherTreeType &b, const ExtendedCombineOp &, bool prune=false)
Definition Tree.h:1928
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:1560
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:665
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:523
ValueOffCIter beginValueOff() const
Definition Tree.h:1072
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:563
RootNodeType::ChildOffCIter beginRootTiles() const
Return an iterator over non-child entries of the root node's table.
Definition Tree.h:1011
void combineExtended(Tree &other, ExtendedCombineOp &op, bool prune=false)
Definition Tree.h:1870
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:1537
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:1621
void releaseAccessor(ValueAccessorBase< const Tree, true > &) const
Definition Tree.h:1453
bool probeValue(const Coord &xyz, ValueType &value) const
Get the value of the voxel at the given coordinates.
Definition Tree.h:1610
TreeValueIteratorBase< const Tree, typename RootNodeType::ValueOnCIter > ValueOnCIter
Definition Tree.h:1053
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:1545
ValueOnIter beginValueOn()
Return an iterator over active values (tile and voxel) across all nodes.
Definition Tree.h:1065
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:1821
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:1553
void combine2Extended(const Tree &a, const OtherTreeType &b, ExtendedCombineOp &op, bool prune=false)
Definition Tree.h:1914
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:1529
tbb::concurrent_hash_map< ValueAccessorBase< const Tree, true > *, bool > ConstAccessorRegistry
Definition Tree.h:1086
ValueOnCIter cbeginValueOn() const
Definition Tree.h:1067
TreeBase::Ptr copy() const override
Return a pointer to a deep copy of this tree.
Definition Tree.h:288
void attachAccessor(ValueAccessorBase< Tree, false > &) const
Dummy implementations.
Definition Tree.h:707
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition Tree.h:1504
const LeafNodeType * probeLeaf(const Coord &xyz) const
Definition Tree.h:598
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:2044
void combineExtended(Tree &other, const ExtendedCombineOp &op, bool prune=false)
Definition Tree.h:1882
void attachAccessor(ValueAccessorBase< const Tree, false > &) const
Definition Tree.h:708
UnsafeAccessor getUnsafeAccessor()
Return an unsafe accessor that provides random read and write access to this tree's voxels.
Definition Tree.h:1399
void combine2(const Tree &a, const OtherTreeType &b, const CombineOp &op, bool prune=false)
Definition Tree.h:1904
NodeCIter beginNode() const
Definition Tree.h:1039
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:1593
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:1324
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:1019
void getNodes(ArrayT &array) const
Definition Tree.h:1356
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:1747
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:1970
void stealNodes(ArrayT &array, const ValueType &value, bool state)
Definition Tree.h:654
bool evalLeafDim(Coord &dim) const override
Return in dim the dimensions of the axis-aligned bounding box of all leaf nodes.
Definition Tree.h:2008
RootNodeType::ChildOnCIter cbeginRootChildren() const
Definition Tree.h:1005
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:1568
std::vector< Index64 > nodeCount() const override
Definition Tree.h:371
NodeCIter cbeginNode() const
Definition Tree.h:1040
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:2035
ValueOffIter beginValueOff()
Return an iterator over inactive values (tile and voxel) across all nodes.
Definition Tree.h:1071
void getIndexRange(CoordBBox &bbox) const override
Min and max are both inclusive.
Definition Tree.h:735
void attachAccessor(ValueAccessorBase< const Tree, true > &) const
Definition Tree.h:1436
void readBuffers(std::istream &, bool saveFloatAsHalf=false) override
Read all data buffers for this tree.
Definition Tree.h:1306
ConstAccessor getConstAccessor() const
Return an accessor that provides random read-only access to this tree's voxels.
Definition Tree.h:1413
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don't change its value.
Definition Tree.h:1576
LeafIter beginLeaf()
Return an iterator over all leaf nodes in this tree.
Definition Tree.h:1045
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:1738
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:1997
~Tree() override
Definition Tree.h:285
const NodeType * probeConstNode(const Coord &xyz) const
Definition Tree.h:1683
bool hasActiveTiles() const
Return true if this tree has any active tiles.
Definition Tree.h:495
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:1703
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:1584
bool isValueOff(const Coord &xyz) const
Return true if the value at the given coordinates is inactive.
Definition Tree.h:493
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:652
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:1803
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:1892
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:1060
NodeIter beginNode()
Return an iterator over all nodes in this tree.
Definition Tree.h:1038
ConstAccessor getAccessor() const
Return an accessor that provides random read-only access to this tree's voxels.
Definition Tree.h:1406
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:1085
ValueAllIter beginValueAll()
Return an iterator over all values (tile and voxel) across all nodes.
Definition Tree.h:1059
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
bool cwiseLessThan(const Mat< SIZE, T > &m0, const Mat< SIZE, T > &m1)
Definition Mat.h:1015
bool cwiseGreaterThan(const Mat< SIZE, T > &m0, const Mat< SIZE, T > &m1)
Definition Mat.h:1029
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 TreeIterator.h:30
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:54
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:70
uint32_t Index32
Definition Types.h:52
uint64_t Index64
Definition Types.h:53
std::shared_ptr< T > SharedPtr
Definition Types.h:114
MergePolicy
Definition Types.h:506
@ MERGE_ACTIVE_STATES
Definition Types.h:507
@ MERGE_NODES
Definition Types.h:508
@ MERGE_ACTIVE_STATES_AND_NODES
Definition Types.h:509
const char * typeNameAsString()
Definition Types.h:516
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:1834
void operator()(CombineArgs< AValueT, BValueT > &args) const
Definition Tree.h:1837
CombineOpAdapter(CombineOp &_op)
Definition Tree.h:1835
CombineOp & op
Definition Tree.h:1841
Tree3<T, N1, N2>::Type is the type of a three-level tree (Root, Internal, Leaf) with value type T and...
Definition Tree.h:1119
Tree< RootNode< InternalNode< LeafNode< T, N2 >, N1 > > > Type
Definition Tree.h:1120
Tree4<T, N1, N2, N3>::Type is the type of a four-level tree (Root, Internal, Internal,...
Definition Tree.h:1129
Tree< RootNode< InternalNode< InternalNode< LeafNode< bool, N3 >, N2 >, N1 > > > Type
Definition Tree.h:1130
Tree5<T, N1, N2, N3, N4>::Type is the type of a five-level tree (Root, Internal, Internal,...
Definition Tree.h:1138
Tree< RootNode< InternalNode< InternalNode< InternalNode< LeafNode< T, N4 >, N3 >, N2 >, N1 > > > Type
Definition Tree.h:1139
static TreeT::LeafCIter begin(const TreeT &tree)
Definition Tree.h:1236
static TreeT::LeafIter begin(TreeT &tree)
Definition Tree.h:1232
static TreeT::NodeCIter begin(const TreeT &tree)
Definition Tree.h:1228
static TreeT::NodeIter begin(TreeT &tree)
Definition Tree.h:1224
static TreeT::RootNodeType::ChildAllCIter begin(const TreeT &tree)
Definition Tree.h:1218
static TreeT::RootNodeType::ChildAllIter begin(TreeT &tree)
Definition Tree.h:1212
static TreeT::RootNodeType::ChildOffCIter begin(const TreeT &tree)
Definition Tree.h:1206
static TreeT::RootNodeType::ChildOffIter begin(TreeT &tree)
Definition Tree.h:1200
static TreeT::RootNodeType::ChildOnCIter begin(const TreeT &tree)
Definition Tree.h:1194
static TreeT::RootNodeType::ChildOnIter begin(TreeT &tree)
Definition Tree.h:1188
static TreeT::ValueAllCIter begin(const TreeT &tree)
Definition Tree.h:1260
static TreeT::ValueAllIter begin(TreeT &tree)
Definition Tree.h:1256
static TreeT::ValueOffCIter begin(const TreeT &tree)
Definition Tree.h:1252
static TreeT::ValueOffIter begin(TreeT &tree)
Definition Tree.h:1248
static TreeT::ValueOnCIter begin(const TreeT &tree)
Definition Tree.h:1244
static TreeT::ValueOnIter begin(TreeT &tree)
Definition Tree.h:1240
TreeIterTraits provides, for all tree iterators, a begin(tree) function that returns an iterator over...
Definition Tree.h:1185
DeallocateNodes(std::vector< NodeType * > &nodes)
Definition Tree.h:1095
NodeType **const mNodes
Definition Tree.h:1102
void operator()(const tbb::blocked_range< size_t > &range) const
Definition Tree.h:1097
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