HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
InternalNode.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 InternalNode.h
5 ///
6 /// @brief Internal table nodes for OpenVDB trees
7 
8 #ifndef OPENVDB_TREE_INTERNALNODE_HAS_BEEN_INCLUDED
9 #define OPENVDB_TREE_INTERNALNODE_HAS_BEEN_INCLUDED
10 
11 #include <openvdb/Platform.h>
12 #include <openvdb/util/NodeMasks.h>
13 #include <openvdb/util/Assert.h>
14 #include <openvdb/io/Compression.h> // for io::readCompressedValues(), etc.
15 #include <openvdb/math/Math.h> // for math::isExactlyEqual(), etc.
16 #include <openvdb/version.h>
17 #include <openvdb/Types.h>
18 #include "Iterator.h"
19 #include "NodeUnion.h"
20 #include <tbb/parallel_for.h>
21 #include <memory>
22 #include <type_traits>
23 
24 
25 namespace openvdb {
27 namespace OPENVDB_VERSION_NAME {
28 namespace tree {
29 
30 template<typename, Index, typename> struct SameInternalConfig; // forward declaration
31 
32 
33 template<typename _ChildNodeType, Index Log2Dim>
35 {
36 public:
37  using ChildNodeType = _ChildNodeType;
38  using LeafNodeType = typename ChildNodeType::LeafNodeType;
43 
44  static const Index
45  LOG2DIM = Log2Dim, // log2 of tile count in one dimension
46  TOTAL = Log2Dim + ChildNodeType::TOTAL, // log2 of voxel count in one dimension
47  DIM = 1 << TOTAL, // total voxel count in one dimension
48  NUM_VALUES = 1 << (3 * Log2Dim), // total voxel count represented by this node
49  LEVEL = 1 + ChildNodeType::LEVEL; // level 0 = leaf
50  static const Index64
51  NUM_VOXELS = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node
52 
53  /// @brief ValueConverter<T>::Type is the type of an InternalNode having the same
54  /// child hierarchy and dimensions as this node but a different value type, T.
55  template<typename OtherValueType>
56  struct ValueConverter {
57  using Type = InternalNode<typename ChildNodeType::template ValueConverter<
58  OtherValueType>::Type, Log2Dim>;
59  };
60 
61  /// @brief SameConfiguration<OtherNodeType>::value is @c true if and only if OtherNodeType
62  /// is the type of an InternalNode with the same dimensions as this node and whose
63  /// ChildNodeType has the same configuration as this node's ChildNodeType.
64  template<typename OtherNodeType>
66  static const bool value =
68  };
69 
70 
71  /// @brief Default constructor
72  /// @warning The resulting InternalNode is uninitialized
74 
75  /// @brief Constructor of an InternalNode with dense inactive tiles of the specified value.
76  /// @param offValue Background value used for inactive values
77  explicit InternalNode(const ValueType& offValue);
78 
79  /// @brief Constructs an InternalNode with dense tiles
80  /// @param origin The location in index space of the fist tile value
81  /// @param fillValue Value assigned to all the tiles
82  /// @param active State assigned to all the tiles
83  InternalNode(const Coord& origin, const ValueType& fillValue, bool active = false);
84 
85  InternalNode(PartialCreate, const Coord&, const ValueType& fillValue, bool active = false);
86 
87  /// @brief Deep copy constructor
88  ///
89  /// @note This method is multi-threaded!
90  InternalNode(const InternalNode&);
91 
92  /// @brief Value conversion copy constructor
93  ///
94  /// @note This method is multi-threaded!
95  template<typename OtherChildNodeType>
97 
98  /// @brief Topology copy constructor
99  ///
100  /// @note This method is multi-threaded!
101  template<typename OtherChildNodeType>
103  const ValueType& background, TopologyCopy);
104 
105  /// @brief Topology copy constructor
106  ///
107  /// @note This method is multi-threaded!
108  template<typename OtherChildNodeType>
110  const ValueType& offValue, const ValueType& onValue, TopologyCopy);
111 
112  ~InternalNode();
113 
114 protected:
118 
119  // Type tags to disambiguate template instantiations
120  struct ValueOn {}; struct ValueOff {}; struct ValueAll {};
121  struct ChildOn {}; struct ChildOff {}; struct ChildAll {};
122 
123  // The following class templates implement the iterator interfaces specified in Iterator.h
124  // by providing getItem(), setItem() and/or modifyItem() methods.
125 
126  // Sparse iterator that visits child nodes of an InternalNode
127  template<typename NodeT, typename ChildT, typename MaskIterT, typename TagT>
129  MaskIterT, ChildIter<NodeT, ChildT, MaskIterT, TagT>, NodeT, ChildT>
130  {
132  ChildIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase<
133  MaskIterT, ChildIter<NodeT, ChildT, MaskIterT, TagT>, NodeT, ChildT>(iter, parent) {}
134 
135  ChildT& getItem(Index pos) const
136  {
137  OPENVDB_ASSERT(this->parent().isChildMaskOn(pos));
138  return *(this->parent().getChildNode(pos));
139  }
140 
141  // Note: setItem() can't be called on const iterators.
142  void setItem(Index pos, const ChildT& c) const { this->parent().resetChildNode(pos, &c); }
143 
144  // Note: modifyItem() isn't implemented, since it's not useful for child node pointers.
145  };// ChildIter
146 
147  // Sparse iterator that visits tile values of an InternalNode
148  template<typename NodeT, typename ValueT, typename MaskIterT, typename TagT>
150  MaskIterT, ValueIter<NodeT, ValueT, MaskIterT, TagT>, NodeT, ValueT>
151  {
153  ValueIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase<
154  MaskIterT, ValueIter<NodeT, ValueT, MaskIterT, TagT>, NodeT, ValueT>(iter, parent) {}
155 
156  const ValueT& getItem(Index pos) const { return this->parent().mNodes[pos].getValue(); }
157 
158  // Note: setItem() can't be called on const iterators.
159  void setItem(Index pos, const ValueT& v) const { this->parent().mNodes[pos].setValue(v); }
160 
161  // Note: modifyItem() can't be called on const iterators.
162  template<typename ModifyOp>
163  void modifyItem(Index pos, const ModifyOp& op) const
164  {
165  op(this->parent().mNodes[pos].getValue());
166  }
167  };// ValueIter
168 
169  // Dense iterator that visits both tiles and child nodes of an InternalNode
170  template<typename NodeT, typename ChildT, typename ValueT, typename TagT>
171  struct DenseIter: public DenseIteratorBase<
172  MaskDenseIterator, DenseIter<NodeT, ChildT, ValueT, TagT>, NodeT, ChildT, ValueT>
173  {
176 
178  DenseIter(const MaskDenseIterator& iter, NodeT* parent):
179  DenseIteratorBase<MaskDenseIterator, DenseIter, NodeT, ChildT, ValueT>(iter, parent) {}
180 
181  bool getItem(Index pos, ChildT*& child, NonConstValueT& value) const
182  {
183  if (this->parent().isChildMaskOn(pos)) {
184  child = this->parent().getChildNode(pos);
185  return true;
186  }
187  child = nullptr;
188  value = this->parent().mNodes[pos].getValue();
189  return false;
190  }
191 
192  // Note: setItem() can't be called on const iterators.
193  void setItem(Index pos, ChildT* child) const
194  {
195  this->parent().resetChildNode(pos, child);
196  }
197 
198  // Note: unsetItem() can't be called on const iterators.
199  void unsetItem(Index pos, const ValueT& value) const
200  {
201  this->parent().unsetChildNode(pos, value);
202  }
203  };// DenseIter
204 
205 public:
206  // Iterators (see Iterator.h for usage)
213 
220 
230 
232  /// @warning This iterator will also visit child nodes so use isChildMaskOn to skip them!
236  /// @warning This iterator will also visit child nodes so use isChildMaskOn to skip them!
240  /// @warning This iterator will also visit child nodes so use isChildMaskOn to skip them!
243 
244 
245  /// @return The dimension of this InternalNode
246  /// @details The number of voxels in one coordinate direction covered by this node
247  static Index dim() { return DIM; }
248  /// @return The level of this node
249  /// @details Level 0 is by definition the level of the leaf nodes
250  static Index getLevel() { return LEVEL; }
251  /// @brief Populated an std::vector with the dimension of all the
252  /// nodes in the branch starting with this node.
253  static void getNodeLog2Dims(std::vector<Index>& dims);
254  /// @return The dimension of the child nodes of this node.
255  /// @details The number of voxels in one coordinate direction
256  /// covered by a child node of this node.
257  static Index getChildDim() { return ChildNodeType::DIM; }
258 
259  /// Return the linear table offset of the given global or local coordinates.
260  static Index coordToOffset(const Coord& xyz);
261  /// @brief Return the local coordinates for a linear table offset,
262  /// where offset 0 has coordinates (0, 0, 0).
263  static void offsetToLocalCoord(Index n, Coord& xyz);
264  /// Return the global coordinates for a linear table offset.
265  Coord offsetToGlobalCoord(Index n) const;
266 
267  /// Return the grid index coordinates of this node's local origin.
268  const Coord& origin() const { return mOrigin; }
269  /// Set the grid index coordinates of this node's local origin.
270  void setOrigin(const Coord& origin) { mOrigin = origin; }
271 
272  /// Return the transient data value.
274  /// Set the transient data value.
276 
277  Index64 leafCount() const;
278  Index64 nonLeafCount() const;
279  void nodeCount(std::vector<Index64> &vec) const;
280  OPENVDB_DEPRECATED_MESSAGE("Use input type std::vector<Index64> for nodeCount.")
281  void nodeCount(std::vector<Index32> &vec) const;
282  Index32 childCount() const;
283  Index64 onVoxelCount() const;
284  Index64 offVoxelCount() const;
285  Index64 onLeafVoxelCount() const;
286  Index64 offLeafVoxelCount() const;
287  Index64 onTileCount() const;
288 
289  /// Return the total amount of memory in bytes occupied by this node and its children.
290  Index64 memUsage() const;
291 
292  /// @brief Expand the specified bounding box so that it includes the active tiles
293  /// of this internal node as well as all the active values in its child nodes.
294  /// If visitVoxels is false LeafNodes will be approximated as dense, i.e. with all
295  /// voxels active. Else the individual active voxels are visited to produce a tight bbox.
296  void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const;
297 
298  /// @brief Return the bounding box of this node, i.e., the full index space
299  /// spanned by the node regardless of its content.
300  CoordBBox getNodeBoundingBox() const { return CoordBBox::createCube(mOrigin, DIM); }
301 
302  /// @return True if this node contains no child nodes.
303  bool isEmpty() const { return mChildMask.isOff(); }
304 
305  /// Return @c true if all of this node's table entries have the same active state
306  /// and the same constant value to within the given tolerance,
307  /// and return that value in @a firstValue and the active state in @a state.
308  ///
309  /// @note This method also returns @c false if this node contains any child nodes.
310  bool isConstant(ValueType& firstValue, bool& state,
311  const ValueType& tolerance = zeroVal<ValueType>()) const;
312 
313  /// Return @c true if all of this node's tables entries have
314  /// the same active @a state and the range of its values satisfy
315  /// (@a maxValue - @a minValue) <= @a tolerance.
316  ///
317  /// @param minValue Is updated with the minimum of all values IF method
318  /// returns @c true. Else the value is undefined!
319  /// @param maxValue Is updated with the maximum of all values IF method
320  /// returns @c true. Else the value is undefined!
321  /// @param state Is updated with the state of all values IF method
322  /// returns @c true. Else the value is undefined!
323  /// @param tolerance The tolerance used to determine if values are
324  /// approximately constant.
325  ///
326  /// @note This method also returns @c false if this node contains any child nodes.
327  bool isConstant(ValueType& minValue, ValueType& maxValue,
328  bool& state, const ValueType& tolerance = zeroVal<ValueType>()) const;
329 
330  /// Return @c true if this node has no children and only contains inactive values.
331  bool isInactive() const { return this->isChildMaskOff() && this->isValueMaskOff(); }
332 
333  /// Return @c true if the voxel at the given coordinates is active.
334  bool isValueOn(const Coord& xyz) const;
335  /// Return @c true if the voxel at the given offset is active.
336  bool isValueOn(Index offset) const { OPENVDB_ASSERT(offset < NUM_VALUES); return mValueMask.isOn(offset); }
337  /// Return @c true if the voxel at the given coordinates is inactive.
338  bool isValueOff(const Coord& xyz) const;
339  /// Return @c true if the voxel at the given offset is inactive.
340  bool isValueOff(Index offset) const { OPENVDB_ASSERT(offset < NUM_VALUES); return mValueMask.isOff(offset); }
341 
342  /// Return @c true if this node or any of its child nodes have any active tiles.
343  bool hasActiveTiles() const;
344 
345  const ValueType& getValue(const Coord& xyz) const;
346  bool probeValue(const Coord& xyz, ValueType& value) const;
347 
348  /// @brief Return the level of the tree (0 = leaf) at which the value
349  /// at the given coordinates resides.
350  Index getValueLevel(const Coord& xyz) const;
351 
352  /// @brief If the first entry in this node's table is a tile, return the tile's value.
353  /// Otherwise, return the result of calling getFirstValue() on the child.
354  const ValueType& getFirstValue() const;
355  /// @brief If the last entry in this node's table is a tile, return the tile's value.
356  /// Otherwise, return the result of calling getLastValue() on the child.
357  const ValueType& getLastValue() const;
358 
359  /// Set the active state of the voxel at the given coordinates but don't change its value.
360  void setActiveState(const Coord& xyz, bool on);
361  /// Set the value of the voxel at the given coordinates but don't change its active state.
362  void setValueOnly(const Coord& xyz, const ValueType& value);
363  /// Mark the voxel at the given coordinates as active but don't change its value.
364  void setValueOn(const Coord& xyz);
365  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
366  void setValueOn(const Coord& xyz, const ValueType& value);
367  /// Mark the voxel at the given coordinates as inactive but don't change its value.
368  void setValueOff(const Coord& xyz);
369  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
370  void setValueOff(const Coord& xyz, const ValueType& value);
371 
372  /// @brief Apply a functor to the value of the voxel at the given coordinates
373  /// and mark the voxel as active.
374  template<typename ModifyOp>
375  void modifyValue(const Coord& xyz, const ModifyOp& op);
376  /// Apply a functor to the voxel at the given coordinates.
377  template<typename ModifyOp>
378  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op);
379 
380  /// Return the value of the voxel at the given coordinates and, if necessary, update
381  /// the accessor with pointers to the nodes along the path from the root node to
382  /// the node containing the voxel.
383  /// @note Used internally by ValueAccessor.
384  template<typename AccessorT>
385  const ValueType& getValueAndCache(const Coord& xyz, AccessorT&) const;
386 
387  /// Return @c true if the voxel at the given coordinates is active and, if necessary,
388  /// update the accessor with pointers to the nodes along the path from the root node
389  /// to the node containing the voxel.
390  /// @note Used internally by ValueAccessor.
391  template<typename AccessorT>
392  bool isValueOnAndCache(const Coord& xyz, AccessorT&) const;
393 
394  /// Change the value of the voxel at the given coordinates and mark it as active.
395  /// If necessary, update the accessor with pointers to the nodes along the path
396  /// from the root node to the node containing the voxel.
397  /// @note Used internally by ValueAccessor.
398  template<typename AccessorT>
399  void setValueAndCache(const Coord& xyz, const ValueType& value, AccessorT&);
400 
401  /// Set the value of the voxel at the given coordinate but preserves its active state.
402  /// If necessary, update the accessor with pointers to the nodes along the path
403  /// from the root node to the node containing the voxel.
404  /// @note Used internally by ValueAccessor.
405  template<typename AccessorT>
406  void setValueOnlyAndCache(const Coord& xyz, const ValueType& value, AccessorT&);
407 
408  /// @brief Apply a functor to the value of the voxel at the given coordinates
409  /// and mark the voxel as active.
410  /// If necessary, update the accessor with pointers to the nodes along the path
411  /// from the root node to the node containing the voxel.
412  /// @note Used internally by ValueAccessor.
413  template<typename ModifyOp, typename AccessorT>
414  void modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&);
415 
416  /// Apply a functor to the voxel at the given coordinates.
417  /// If necessary, update the accessor with pointers to the nodes along the path
418  /// from the root node to the node containing the voxel.
419  /// @note Used internally by ValueAccessor.
420  template<typename ModifyOp, typename AccessorT>
421  void modifyValueAndActiveStateAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&);
422 
423  /// Change the value of the voxel at the given coordinates and mark it as inactive.
424  /// If necessary, update the accessor with pointers to the nodes along the path
425  /// from the root node to the node containing the voxel.
426  /// @note Used internally by ValueAccessor.
427  template<typename AccessorT>
428  void setValueOffAndCache(const Coord& xyz, const ValueType& value, AccessorT&);
429 
430  /// Set the active state of the voxel at the given coordinates without changing its value.
431  /// If necessary, update the accessor with pointers to the nodes along the path
432  /// from the root node to the node containing the voxel.
433  /// @note Used internally by ValueAccessor.
434  template<typename AccessorT>
435  void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&);
436 
437  /// Return, in @a value, the value of the voxel at the given coordinates and,
438  /// if necessary, update the accessor with pointers to the nodes along
439  /// the path from the root node to the node containing the voxel.
440  /// @return @c true if the voxel at the given coordinates is active
441  /// @note Used internally by ValueAccessor.
442  template<typename AccessorT>
443  bool probeValueAndCache(const Coord& xyz, ValueType& value, AccessorT&) const;
444 
445  /// @brief Return the level of the tree (0 = leaf) at which the value
446  /// at the given coordinates resides.
447  ///
448  /// If necessary, update the accessor with pointers to the nodes along the path
449  /// from the root node to the node containing the voxel.
450  /// @note Used internally by ValueAccessor.
451  template<typename AccessorT>
452  Index getValueLevelAndCache(const Coord& xyz, AccessorT&) const;
453 
454  /// Mark all values (both tiles and voxels) as active.
455  void setValuesOn();
456 
457  //
458  // I/O
459  //
460  void writeTopology(std::ostream&, bool toHalf = false) const;
461  void readTopology(std::istream&, bool fromHalf = false);
462  void writeBuffers(std::ostream&, bool toHalf = false) const;
463  void readBuffers(std::istream&, bool fromHalf = false);
464  void readBuffers(std::istream&, const CoordBBox&, bool fromHalf = false);
465 
466 
467  //
468  // Unsafe methods
469  //
470  // WARNING: For improved performance, these unsafe methods do not check the value or
471  // child masks. If used incorrectly, at best they will leave the InternalNode in an
472  // invalid state and at worst cause the application to crash. Always use the safer
473  // alternative method(s) unless you really know what you're doing.
474  // Enabling OpenVDB asserts will catch where assumptions are incorrectly invalidated.
475 
476  /// @brief Return the tile value at offset.
477  /// @note Use getValue(const Coord&) for a safer alternative.
478  /// @warning This method should only be used by experts seeking low-level optimizations.
479  const ValueType& getValueUnsafe(Index offset) const;
480  /// @brief Return the tile value and active state at offset.
481  /// @note Use probeValue(const Coord&, ValueType&) for a safer alternative.
482  /// @warning This method should only be used by experts seeking low-level optimizations.
483  bool getValueUnsafe(Index offset, ValueType& value) const;
484 
485  /// @brief Return the child node at offset.
486  /// @note Use probeChild(const Coord&) for a safer alternative.
487  /// @warning This method should only be used by experts seeking low-level optimizations.
489  /// @brief Return the child node at offset.
490  /// @note Use probeConstChild(const Coord&) for a safer alternative.
491  /// @warning This method should only be used by experts seeking low-level optimizations.
493  /// @brief Return the child node at offset.
494  /// @note Use probeChild(const Coord&) for a safer alternative.
495  /// @warning This method should only be used by experts seeking low-level optimizations.
497 
498  /// @brief Set the tile active state at offset but don't change its value.
499  /// @note Use setActiveState(const Coord&, bool) for a safer alternative.
500  /// @warning This method should only be used by experts seeking low-level optimizations.
501  void setActiveStateUnsafe(Index offset, bool on);
502  /// @brief Set the tile value at offset but don't change its value.
503  /// @note Use setValueOnly(const Coord&, const ValueType&) for a safer alternative.
504  /// @warning This method should only be used by experts seeking low-level optimizations.
506  /// @brief Mark the tile active at offset but don't change its value.
507  /// @note Use setValueOn(const Coord&) for a safer alternative.
508  /// @warning This method should only be used by experts seeking low-level optimizations.
510  /// @brief Set the tile value at offset and mark the voxel as active.
511  /// @note Use setValueOn(const Coord&, const ValueType&) for a safer alternative.
512  /// @warning This method should only be used by experts seeking low-level optimizations.
514  /// @brief Mark the tile inactive at offset but don't change its value.
515  /// @note Use setValueOff(const Coord&) for a safer alternative.
516  /// @warning This method should only be used by experts seeking low-level optimizations.
518  /// @brief Set the tile value at offset and mark the voxel as inactive.
519  /// @note Use setValueOff(const Coord&, const ValueType&) for a safer alternative.
520  /// @warning This method should only be used by experts seeking low-level optimizations.
522 
523  /// @brief Set the active/inactive value mask.
524  /// @note Use setValueOn(const Coord&)/setValueOff(const Coord&) for a safer alternative.
525  /// @warning This method should only be used by experts seeking low-level optimizations.
526  void setValueMaskUnsafe(const NodeMaskType& mask);
527 
528  /// @brief Replace a tile at offset with the given child node.
529  /// @note Use addChild(ChildNodeType*) for a safer alternative.
530  /// @warning This method should only be used by experts seeking low-level optimizations.
532  /// @brief Replace a child node at offset with the given child node.
533  /// @note Use addChild(ChildNodeType*) for a safer alternative.
534  /// @warning This method should only be used by experts seeking low-level optimizations.
536  /// @brief Replace a child node at offset with the given value and active state.
537  /// @note Use addChild(ChildNodeType*) for a safer alternative.
538  /// @warning This method should only be used by experts seeking low-level optimizations.
540  /// @brief Delete a child node at offset and replace with the given value and active state.
541  /// @note Use addTile(Index, const ValueType&, bool) for a safer alternative.
542  /// @warning This method should only be used by experts seeking low-level optimizations.
543  void deleteChildUnsafe(Index offset, const ValueType& value, bool active);
544 
545  //
546  // Aux methods
547  //
548 
549  /// Change the sign of all the values represented in this node and its child nodes.
550  void negate();
551 
552  /// @brief Set all voxels within a given axis-aligned box to a constant value.
553  /// @param bbox inclusive coordinates of opposite corners of an axis-aligned box
554  /// @param value the value to which to set voxels within the box
555  /// @param active if true, mark voxels within the box as active,
556  /// otherwise mark them as inactive
557  /// @note This operation generates a sparse, but not always optimally sparse,
558  /// representation of the filled box. Follow fill operations with a prune()
559  /// operation for optimal sparseness.
560  void fill(const CoordBBox& bbox, const ValueType& value, bool active = true);
561 
562  /// @brief Set all voxels within a given axis-aligned box to a constant value
563  /// and ensure that those voxels are all represented at the leaf level.
564  /// @param bbox inclusive coordinates of opposite corners of an axis-aligned box.
565  /// @param value the value to which to set voxels within the box.
566  /// @param active if true, mark voxels within the box as active,
567  /// otherwise mark them as inactive.
568  /// @sa voxelizeActiveTiles()
569  void denseFill(const CoordBBox& bbox, const ValueType& value, bool active = true);
570 
571  /// @brief Densify active tiles, i.e., replace them with leaf-level active voxels.
572  /// @param threaded if true, this operation is multi-threaded (over the internal nodes).
573  /// @sa denseFill()
574  void voxelizeActiveTiles(bool threaded = true);
575 
576  /// @brief Copy into a dense grid the values of the voxels that lie within
577  /// a given bounding box.
578  /// @param bbox inclusive bounding box of the voxels to be copied into the dense grid
579  /// @param dense dense grid with a stride in @e z of one (see tools::Dense
580  /// in tools/Dense.h for the required API)
581  /// @note @a bbox is assumed to be identical to or contained in the coordinate domains
582  /// of both the dense grid and this node, i.e., no bounds checking is performed.
583  template<typename DenseT>
584  void copyToDense(const CoordBBox& bbox, DenseT& dense) const;
585 
586  /// @brief Efficiently merge another tree into this tree using one of several schemes.
587  /// @warning This operation cannibalizes the other tree.
588  template<MergePolicy Policy>
589  void merge(InternalNode& other, const ValueType& background, const ValueType& otherBackground);
590 
591  /// @brief Merge, using one of several schemes, this node (and its descendants)
592  /// with a tile of the same dimensions and the given value and active state.
593  template<MergePolicy Policy> void merge(const ValueType& tileValue, bool tileActive);
594 
595  /// @brief Union this branch's set of active values with the other branch's
596  /// active values. The value type of the other branch can be different.
597  /// @details The resulting state of a value is active if the corresponding value
598  /// was already active OR if it is active in the other tree. Also, a resulting
599  /// value maps to a voxel if the corresponding value already mapped to a voxel
600  /// OR if it is a voxel in the other tree. Thus, a resulting value can only
601  /// map to a tile if the corresponding value already mapped to a tile
602  /// AND if it is a tile value in other tree.
603  ///
604  /// Specifically, active tiles and voxels in this branch are not changed, and
605  /// tiles or voxels that were inactive in this branch but active in the other branch
606  /// are marked as active in this branch but left with their original values.
607  template<typename OtherChildNodeType>
608  void topologyUnion(const InternalNode<OtherChildNodeType, Log2Dim>& other, const bool preserveTiles = false);
609 
610  /// @brief Intersects this tree's set of active values with the active values
611  /// of the other tree, whose @c ValueType may be different.
612  /// @details The resulting state of a value is active only if the corresponding
613  /// value was already active AND if it is active in the other tree. Also, a
614  /// resulting value maps to a voxel if the corresponding value
615  /// already mapped to an active voxel in either of the two grids
616  /// and it maps to an active tile or voxel in the other grid.
617  ///
618  /// @note This operation can delete branches in this grid if they
619  /// overlap with inactive tiles in the other grid. Likewise active
620  /// voxels can be turned into inactive voxels resulting in leaf
621  /// nodes with no active values. Thus, it is recommended to
622  /// subsequently call prune.
623  template<typename OtherChildNodeType>
625  const ValueType& background);
626 
627  /// @brief Difference this node's set of active values with the active values
628  /// of the other node, whose @c ValueType may be different. So a
629  /// resulting voxel will be active only if the original voxel is
630  /// active in this node and inactive in the other node.
631  ///
632  /// @details The last dummy argument is required to match the signature
633  /// for InternalNode::topologyDifference.
634  ///
635  /// @note This operation modifies only active states, not
636  /// values. Also note that this operation can result in all voxels
637  /// being inactive so consider subsequently calling prune.
638  template<typename OtherChildNodeType>
640  const ValueType& background);
641 
642  template<typename CombineOp>
643  void combine(InternalNode& other, CombineOp&);
644  template<typename CombineOp>
645  void combine(const ValueType& value, bool valueIsActive, CombineOp&);
646 
647  template<typename CombineOp, typename OtherNodeType /*= InternalNode*/>
648  void combine2(const InternalNode& other0, const OtherNodeType& other1, CombineOp&);
649  template<typename CombineOp, typename OtherNodeType /*= InternalNode*/>
650  void combine2(const ValueType& value, const OtherNodeType& other, bool valIsActive, CombineOp&);
651  template<typename CombineOp, typename OtherValueType>
652  void combine2(const InternalNode& other, const OtherValueType&, bool valIsActive, CombineOp&);
653 
654  /// Set all voxels that lie outside the given axis-aligned box to the background.
655  void clip(const CoordBBox&, const ValueType& background);
656 
657  /// @brief Reduce the memory footprint of this tree by replacing with tiles
658  /// any nodes whose values are all the same (optionally to within a tolerance)
659  /// and have the same active state.
660  void prune(const ValueType& tolerance = zeroVal<ValueType>());
661 
662  /// @brief Add the specified leaf to this node, possibly creating a child branch
663  /// in the process. If the leaf node already exists, replace it.
664  void addLeaf(LeafNodeType* leaf);
665 
666  /// @brief Same as addLeaf() except, if necessary, update the accessor with pointers
667  /// to the nodes along the path from the root node to the node containing the coordinate.
668  template<typename AccessorT>
669  void addLeafAndCache(LeafNodeType* leaf, AccessorT&);
670 
671  /// @brief Return a pointer to the node of type @c NodeT that contains voxel (x, y, z)
672  /// and replace it with a tile of the specified value and state.
673  /// If no such node exists, leave the tree unchanged and return @c nullptr.
674  ///
675  /// @note The caller takes ownership of the node and is responsible for deleting it.
676  ///
677  /// @warning Since this method potentially removes nodes and branches of the tree,
678  /// it is important to clear the caches of all ValueAccessors associated with this tree.
679  template<typename NodeT>
680  NodeT* stealNode(const Coord& xyz, const ValueType& value, bool state);
681 
682  /// @brief Add the given child node at this level deducing the offset from it's origin.
683  /// If a child node with this offset already exists, delete the old node and add the
684  /// new node in its place (i.e. ownership of the new child node is transferred to
685  /// this InternalNode)
686  /// @return @c true if inserting the child has been successful, otherwise the caller
687  /// retains ownership of the node and is responsible for deleting it.
688  bool addChild(ChildNodeType* child);
689 
690  /// @brief Add a tile at the specified tree level that contains voxel (x, y, z),
691  /// possibly creating a parent branch or deleting a child branch in the process.
692  void addTile(Index level, const Coord& xyz, const ValueType& value, bool state);
693 
694  /// @brief Delete any existing child branch at the specified offset and add a tile.
695  void addTile(Index offset, const ValueType& value, bool state);
696 
697  /// @brief Same as addTile() except, if necessary, update the accessor with pointers
698  /// to the nodes along the path from the root node to the node containing (x, y, z).
699  template<typename AccessorT>
700  void addTileAndCache(Index level, const Coord& xyz, const ValueType&, bool state, AccessorT&);
701 
702  //@{
703  /// @brief Return a pointer to the node that contains voxel (x, y, z).
704  /// If no such node exists, return nullptr.
705  template<typename NodeType> NodeType* probeNode(const Coord& xyz);
706  template<typename NodeType> const NodeType* probeConstNode(const Coord& xyz) const;
707  template<typename NodeType> const NodeType* probeNode(const Coord& xyz) const { return this->probeConstNode<NodeType>(xyz); }
708  //@}
709 
710  //@{
711  /// @brief Return a pointer to the child node that contains voxel (x, y, z).
712  /// If no such node exists, return nullptr.
713  ChildNodeType* probeChild(const Coord& xyz);
714  const ChildNodeType* probeConstChild(const Coord& xyz) const;
715  const ChildNodeType* probeChild(const Coord& xyz) const { return this->probeConstChild(xyz); }
716  //@}
717 
718  //@{
719  /// @brief Return a pointer to the child node that contains voxel (x, y, z).
720  /// If no such node exists, return nullptr.
721  ChildNodeType* probeChild(const Coord& xyz, ValueType& value, bool& active);
722  const ChildNodeType* probeConstChild(const Coord& xyz, ValueType& value, bool& active) const;
723  const ChildNodeType* probeChild(const Coord& xyz, ValueType& value, bool& active) const { return this->probeConstChild(xyz, value, active); }
724  //@}
725 
726  //@{
727  /// @brief Return a pointer to the child node for a specific offset.
728  /// If no such node exists, return nullptr.
729  /// @warning This method should only be used by experts seeking low-level optimizations.
730  /// @note Out-of-bounds memory access attempts will wrap around using modulo indexing.
733  const ChildNodeType* probeChildUnsafe(Index offset) const { return this->probeConstChildUnsafe(offset); }
734  //@}
735 
736  //@{
737  /// @brief Return a pointer to the child node for a specific offset.
738  /// If no such node exists, return nullptr.
739  /// @warning This method should only be used by experts seeking low-level optimizations.
740  /// @note Out-of-bounds memory access attempts will wrap around using modulo indexing.
743  const ChildNodeType* probeChildUnsafe(Index offset, ValueType& value, bool& active) const { return this->probeConstChildUnsafe(offset, value, active); }
744  //@}
745 
746  //@{
747  /// @brief Same as probeNode() except, if necessary, update the accessor with pointers
748  /// to the nodes along the path from the root node to the node containing (x, y, z).
749  template<typename NodeType, typename AccessorT>
750  NodeType* probeNodeAndCache(const Coord& xyz, AccessorT&);
751  template<typename NodeType, typename AccessorT>
752  const NodeType* probeConstNodeAndCache(const Coord& xyz, AccessorT&) const;
753  //@}
754 
755  //@{
756  /// @brief Return a pointer to the leaf node that contains voxel (x, y, z).
757  /// If no such node exists, return @c nullptr.
758  LeafNodeType* probeLeaf(const Coord& xyz);
759  const LeafNodeType* probeConstLeaf(const Coord& xyz) const;
760  const LeafNodeType* probeLeaf(const Coord& xyz) const;
761  //@}
762 
763  //@{
764  /// @brief Same as probeLeaf() except, if necessary, update the accessor with pointers
765  /// to the nodes along the path from the root node to the node containing (x, y, z).
766  template<typename AccessorT>
767  LeafNodeType* probeLeafAndCache(const Coord& xyz, AccessorT& acc);
768  template<typename AccessorT>
769  const LeafNodeType* probeConstLeafAndCache(const Coord& xyz, AccessorT& acc) const;
770  template<typename AccessorT>
771  const LeafNodeType* probeLeafAndCache(const Coord& xyz, AccessorT& acc) const;
772  //@}
773 
774  /// @brief Return the leaf node that contains voxel (x, y, z).
775  /// If no such node exists, create one, but preserve the values and
776  /// active states of all voxels.
777  ///
778  /// @details Use this method to preallocate a static tree topology
779  /// over which to safely perform multithreaded processing.
780  LeafNodeType* touchLeaf(const Coord& xyz);
781 
782  /// @brief Same as touchLeaf() except, if necessary, update the accessor with pointers
783  /// to the nodes along the path from the root node to the node containing the coordinate.
784  template<typename AccessorT>
785  LeafNodeType* touchLeafAndCache(const Coord& xyz, AccessorT&);
786 
787  //@{
788  /// @brief Adds all nodes of a certain type to a container with the following API:
789  /// @code
790  /// struct ArrayT {
791  /// using value_type = ...;// defines the type of nodes to be added to the array
792  /// void push_back(value_type nodePtr);// method that add nodes to the array
793  /// };
794  /// @endcode
795  /// @details An example of a wrapper around a c-style array is:
796  /// @code
797  /// struct MyArray {
798  /// using value_type = LeafType*;
799  /// value_type* ptr;
800  /// MyArray(value_type* array) : ptr(array) {}
801  /// void push_back(value_type leaf) { *ptr++ = leaf; }
802  ///};
803  /// @endcode
804  /// @details An example that constructs a list of pointer to all leaf nodes is:
805  /// @code
806  /// std::vector<const LeafNodeType*> array;//most std contains have the required API
807  /// array.reserve(tree.leafCount());//this is a fast preallocation.
808  /// tree.getNodes(array);
809  /// @endcode
810  template<typename ArrayT>
811  void getNodes(ArrayT& array);
812  template<typename ArrayT>
813  void getNodes(ArrayT& array) const;
814  //@}
815 
816  /// @brief Steals all nodes of a certain type from the tree and
817  /// adds them to a container with the following API:
818  /// @code
819  /// struct ArrayT {
820  /// using value_type = ...;// defines the type of nodes to be added to the array
821  /// void push_back(value_type nodePtr);// method that add nodes to the array
822  /// };
823  /// @endcode
824  /// @details An example of a wrapper around a c-style array is:
825  /// @code
826  /// struct MyArray {
827  /// using value_type = LeafType*;
828  /// value_type* ptr;
829  /// MyArray(value_type* array) : ptr(array) {}
830  /// void push_back(value_type leaf) { *ptr++ = leaf; }
831  ///};
832  /// @endcode
833  /// @details An example that constructs a list of pointer to all leaf nodes is:
834  /// @code
835  /// std::vector<const LeafNodeType*> array;//most std contains have the required API
836  /// array.reserve(tree.leafCount());//this is a fast preallocation.
837  /// tree.stealNodes(array);
838  /// @endcode
839  template<typename ArrayT>
840  void stealNodes(ArrayT& array, const ValueType& value, bool state);
841 
842  /// @brief Change inactive tiles or voxels with value oldBackground to newBackground
843  /// or -oldBackground to -newBackground. Active values are unchanged.
844  void resetBackground(const ValueType& oldBackground, const ValueType& newBackground);
845 
846  /// @brief Return @c true if the given tree branch has the same node and active value
847  /// topology as this tree branch (but possibly a different @c ValueType).
848  template<typename OtherChildNodeType, Index OtherLog2Dim>
850 
851 protected:
852  //@{
853  /// Allow iterators to call mask accessor methods (setValueMask(), setChildMask(), etc.).
854  /// @todo Make mask accessors public?
858  //@}
859 
860  /// @brief During topology-only construction, access is needed
861  /// to protected/private members of other template instances.
862  template<typename, Index> friend class InternalNode;
863 
864  // Mask accessors
865 public:
866  bool isValueMaskOn(Index n) const { return mValueMask.isOn(n); }
867  bool isValueMaskOn() const { return mValueMask.isOn(); }
868  bool isValueMaskOff(Index n) const { return mValueMask.isOff(n); }
869  bool isValueMaskOff() const { return mValueMask.isOff(); }
870  bool isChildMaskOn(Index n) const { return mChildMask.isOn(n); }
871  bool isChildMaskOff(Index n) const { return mChildMask.isOff(n); }
872  bool isChildMaskOff() const { return mChildMask.isOff(); }
873  const NodeMaskType& getValueMask() const { return mValueMask; }
874  const NodeMaskType& getChildMask() const { return mChildMask; }
876  {
878  mask |= mChildMask;
879  mask.toggle();
880  return mask;
881  }
882  const UnionType* getTable() const { return mNodes; }
883 protected:
884  //@{
885  /// Use a mask accessor to ensure consistency between the child and value masks;
886  /// i.e., the value mask should always be off wherever the child mask is on.
887  void setValueMask(Index n, bool on) { mValueMask.set(n, mChildMask.isOn(n) ? false : on); }
888  //@}
889 
890  void makeChildNodeEmpty(Index n, const ValueType& value);
891  void setChildNode( Index i, ChildNodeType* child);//assumes a tile
892  void resetChildNode(Index i, ChildNodeType* child);//checks for an existing child
894 
895  ///@{
896  /// @brief Returns a pointer to the child node at the linear offset n.
897  /// @warning This protected method assumes that a child node exists at
898  /// the specified linear offset!
900  const ChildNodeType* getChildNode(Index n) const;
901  ///@}
902 
903  ///@{
904  /// @brief Protected member classes for recursive multi-threading
905  struct VoxelizeActiveTiles;
906  template<typename OtherInternalNode> struct DeepCopy;
907  template<typename OtherInternalNode> struct TopologyCopy1;
908  template<typename OtherInternalNode> struct TopologyCopy2;
909  template<typename OtherInternalNode> struct TopologyUnion;
910  template<typename OtherInternalNode> struct TopologyDifference;
911  template<typename OtherInternalNode> struct TopologyIntersection;
912  ///@}
913 
916  /// Global grid index coordinates (x,y,z) of the local origin of this node
917  Coord mOrigin;
918  /// Transient data (not serialized)
920 }; // class InternalNode
921 
922 
923 ////////////////////////////////////////
924 
925 
926 //@{
927 /// Helper metafunction used to implement InternalNode::SameConfiguration
928 /// (which, as an inner class, can't be independently specialized)
929 template<typename ChildT1, Index Dim1, typename NodeT2>
930 struct SameInternalConfig {
931  static const bool value = false;
932 };
933 
934 template<typename ChildT1, Index Dim1, typename ChildT2>
935 struct SameInternalConfig<ChildT1, Dim1, InternalNode<ChildT2, Dim1> > {
936  static const bool value = ChildT1::template SameConfiguration<ChildT2>::value;
937 };
938 //@}
939 
940 
941 ////////////////////////////////////////
942 
943 
944 template<typename ChildT, Index Log2Dim>
945 inline
947 {
948  for (Index i = 0; i < NUM_VALUES; ++i) mNodes[i].setValue(background);
949 }
950 
951 
952 template<typename ChildT, Index Log2Dim>
953 inline
955  mOrigin(origin[0] & ~(DIM - 1), // zero out the low-order bits
956  origin[1] & ~(DIM - 1),
957  origin[2] & ~(DIM - 1))
958 {
959  if (active) mValueMask.setOn();
960  for (Index i = 0; i < NUM_VALUES; ++i) mNodes[i].setValue(val);
961 }
962 
963 
964 // For InternalNodes, the PartialCreate constructor is identical to its
965 // non-PartialCreate counterpart.
966 template<typename ChildT, Index Log2Dim>
967 inline
969  const Coord& origin, const ValueType& val, bool active)
970  : mOrigin(origin[0] & ~(DIM-1), origin[1] & ~(DIM-1), origin[2] & ~(DIM-1))
971 {
972  if (active) mValueMask.setOn();
973  for (Index i = 0; i < NUM_VALUES; ++i) mNodes[i].setValue(val);
974 }
975 
976 template<typename ChildT, Index Log2Dim>
977 template<typename OtherInternalNode>
978 struct InternalNode<ChildT, Log2Dim>::DeepCopy
979 {
980  DeepCopy(const OtherInternalNode* source, InternalNode* target) : s(source), t(target) {
981  tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
982  //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//serial
983  }
984  void operator()(const tbb::blocked_range<Index> &r) const {
985  for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
986  if (s->mChildMask.isOff(i)) {
987  t->mNodes[i].setValue(ValueType(s->mNodes[i].getValue()));
988  } else {
989  t->mNodes[i].setChild(new ChildNodeType(*(s->mNodes[i].getChild())));
990  }
991  }
992  }
993  const OtherInternalNode* s;
995 };// DeepCopy
996 
997 template<typename ChildT, Index Log2Dim>
998 inline
1000  : mChildMask(other.mChildMask)
1001  , mValueMask(other.mValueMask)
1002  , mOrigin(other.mOrigin)
1003  , mTransientData(other.mTransientData)
1004 {
1005  DeepCopy<InternalNode<ChildT, Log2Dim> > tmp(&other, this);
1006 }
1007 
1008 
1009 // Copy-construct from a node with the same configuration but a different ValueType.
1010 template<typename ChildT, Index Log2Dim>
1011 template<typename OtherChildNodeType>
1012 inline
1014  : mChildMask(other.mChildMask)
1015  , mValueMask(other.mValueMask)
1016  , mOrigin(other.mOrigin)
1017  , mTransientData(other.mTransientData)
1018 {
1020 }
1021 
1022 template<typename ChildT, Index Log2Dim>
1023 template<typename OtherInternalNode>
1024 struct InternalNode<ChildT, Log2Dim>::TopologyCopy1
1025 {
1026  TopologyCopy1(const OtherInternalNode* source, InternalNode* target,
1027  const ValueType& background) : s(source), t(target), b(background) {
1028  tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
1029  //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//serial
1030  }
1031  void operator()(const tbb::blocked_range<Index> &r) const {
1032  for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
1033  if (s->isChildMaskOn(i)) {
1034  t->mNodes[i].setChild(new ChildNodeType(*(s->mNodes[i].getChild()),
1035  b, TopologyCopy()));
1036  } else {
1037  t->mNodes[i].setValue(b);
1038  }
1039  }
1040  }
1041  const OtherInternalNode* s;
1043  const ValueType &b;
1044 };// TopologyCopy1
1045 
1046 template<typename ChildT, Index Log2Dim>
1047 template<typename OtherChildNodeType>
1048 inline
1050  const ValueType& background, TopologyCopy)
1051  : mChildMask(other.mChildMask)
1052  , mValueMask(other.mValueMask)
1053  , mOrigin(other.mOrigin)
1054  , mTransientData(other.mTransientData)
1055 {
1056  TopologyCopy1<InternalNode<OtherChildNodeType, Log2Dim> > tmp(&other, this, background);
1057 }
1058 
1059 template<typename ChildT, Index Log2Dim>
1060 template<typename OtherInternalNode>
1061 struct InternalNode<ChildT, Log2Dim>::TopologyCopy2
1062 {
1063  TopologyCopy2(const OtherInternalNode* source, InternalNode* target,
1064  const ValueType& offValue, const ValueType& onValue)
1065  : s(source), t(target), offV(offValue), onV(onValue) {
1066  tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
1067  }
1068  void operator()(const tbb::blocked_range<Index> &r) const {
1069  for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
1070  if (s->isChildMaskOn(i)) {
1071  t->mNodes[i].setChild(new ChildNodeType(*(s->mNodes[i].getChild()),
1072  offV, onV, TopologyCopy()));
1073  } else {
1074  t->mNodes[i].setValue(s->isValueMaskOn(i) ? onV : offV);
1075  }
1076  }
1077  }
1078  const OtherInternalNode* s;
1080  const ValueType &offV, &onV;
1081  };// TopologyCopy2
1082 
1083 template<typename ChildT, Index Log2Dim>
1084 template<typename OtherChildNodeType>
1085 inline
1087  const ValueType& offValue,
1088  const ValueType& onValue, TopologyCopy)
1089  : mChildMask(other.mChildMask)
1090  , mValueMask(other.mValueMask)
1091  , mOrigin(other.mOrigin)
1092  , mTransientData(other.mTransientData)
1093 {
1094  TopologyCopy2<InternalNode<OtherChildNodeType, Log2Dim> > tmp(&other, this, offValue, onValue);
1095 }
1096 
1097 
1098 template<typename ChildT, Index Log2Dim>
1099 inline
1101 {
1102  for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
1103  delete mNodes[iter.pos()].getChild();
1104  }
1105 }
1106 
1107 
1108 ////////////////////////////////////////
1109 
1110 
1111 template<typename ChildT, Index Log2Dim>
1112 inline Index64
1114 {
1115  if (ChildNodeType::getLevel() == 0) return mChildMask.countOn();
1116  Index64 sum = 0;
1117  for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1118  sum += iter->leafCount();
1119  }
1120  return sum;
1121 }
1122 
1123 template<typename ChildT, Index Log2Dim>
1124 inline void
1125 InternalNode<ChildT, Log2Dim>::nodeCount(std::vector<Index64> &vec) const
1126 {
1127  OPENVDB_ASSERT(vec.size() > ChildNodeType::LEVEL);
1128  const auto count = mChildMask.countOn();
1129  if (ChildNodeType::LEVEL > 0 && count > 0) {
1130  for (auto iter = this->cbeginChildOn(); iter; ++iter) iter->nodeCount(vec);
1131  }
1132  vec[ChildNodeType::LEVEL] += count;
1133 }
1134 
1135 template<typename ChildT, Index Log2Dim>
1136 inline void
1137 InternalNode<ChildT, Log2Dim>::nodeCount(std::vector<Index32> &vec) const
1138 {
1139  OPENVDB_ASSERT(vec.size() > ChildNodeType::LEVEL);
1140  const auto count = mChildMask.countOn();
1141  if (ChildNodeType::LEVEL > 0 && count > 0) {
1142  for (auto iter = this->cbeginChildOn(); iter; ++iter) {
1144  iter->nodeCount(vec);
1146  }
1147  }
1148  vec[ChildNodeType::LEVEL] += count;
1149 }
1150 
1151 
1152 template<typename ChildT, Index Log2Dim>
1153 inline Index64
1155 {
1156  Index64 sum = 1;
1157  if (ChildNodeType::getLevel() == 0) return sum;
1158  for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1159  sum += iter->nonLeafCount();
1160  }
1161  return sum;
1162 }
1163 
1164 
1165 template<typename ChildT, Index Log2Dim>
1166 inline Index32
1168 {
1169  return this->getChildMask().countOn();
1170 }
1171 
1172 
1173 template<typename ChildT, Index Log2Dim>
1174 inline Index64
1176 {
1177  Index64 sum = ChildT::NUM_VOXELS * mValueMask.countOn();
1178  for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1179  sum += iter->onVoxelCount();
1180  }
1181  return sum;
1182 }
1183 
1184 
1185 template<typename ChildT, Index Log2Dim>
1186 inline Index64
1188 {
1189  Index64 sum = ChildT::NUM_VOXELS * (NUM_VALUES-mValueMask.countOn()-mChildMask.countOn());
1190  for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1191  sum += iter->offVoxelCount();
1192  }
1193  return sum;
1194 }
1195 
1196 
1197 template<typename ChildT, Index Log2Dim>
1198 inline Index64
1200 {
1201  Index64 sum = 0;
1202  for (ChildOnCIter iter = this->beginChildOn(); iter; ++iter) {
1203  sum += mNodes[iter.pos()].getChild()->onLeafVoxelCount();
1204  }
1205  return sum;
1206 }
1207 
1208 
1209 template<typename ChildT, Index Log2Dim>
1210 inline Index64
1212 {
1213  Index64 sum = 0;
1214  for (ChildOnCIter iter = this->beginChildOn(); iter; ++iter) {
1215  sum += mNodes[iter.pos()].getChild()->offLeafVoxelCount();
1216  }
1217  return sum;
1218 }
1219 
1220 template<typename ChildT, Index Log2Dim>
1221 inline Index64
1223 {
1224  Index64 sum = mValueMask.countOn();
1225  for (ChildOnCIter iter = this->cbeginChildOn(); LEVEL>1 && iter; ++iter) {
1226  sum += iter->onTileCount();
1227  }
1228  return sum;
1229 }
1230 
1231 template<typename ChildT, Index Log2Dim>
1232 inline Index64
1234 {
1235  Index64 sum = NUM_VALUES * sizeof(UnionType) + mChildMask.memUsage()
1236  + mValueMask.memUsage() + sizeof(mOrigin);
1237  for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1238  sum += iter->memUsage();
1239  }
1240  return sum;
1241 }
1242 
1243 
1244 template<typename ChildT, Index Log2Dim>
1245 inline void
1247 {
1248  if (bbox.isInside(this->getNodeBoundingBox())) return;
1249 
1250  for (ValueOnCIter i = this->cbeginValueOn(); i; ++i) {
1251  bbox.expand(i.getCoord(), ChildT::DIM);
1252  }
1253  for (ChildOnCIter i = this->cbeginChildOn(); i; ++i) {
1254  i->evalActiveBoundingBox(bbox, visitVoxels);
1255  }
1256 }
1257 
1258 
1259 ////////////////////////////////////////
1260 
1261 
1262 template<typename ChildT, Index Log2Dim>
1263 inline void
1265 {
1266  bool state = false;
1267  ValueType value = zeroVal<ValueType>();
1268  for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
1269  const Index i = iter.pos();
1270  ChildT* child = mNodes[i].getChild();
1271  child->prune(tolerance);
1272  if (child->isConstant(value, state, tolerance)) {
1273  delete child;
1274  mChildMask.setOff(i);
1275  mValueMask.set(i, state);
1276  mNodes[i].setValue(value);
1277  }
1278  }
1279 }
1280 
1281 
1282 ////////////////////////////////////////
1283 
1284 
1285 template<typename ChildT, Index Log2Dim>
1286 template<typename NodeT>
1287 inline NodeT*
1288 InternalNode<ChildT, Log2Dim>::stealNode(const Coord& xyz, const ValueType& value, bool state)
1289 {
1290  if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
1291  NodeT::LEVEL > ChildT::LEVEL) return nullptr;
1293  const Index n = this->coordToOffset(xyz);
1294  if (mChildMask.isOff(n)) return nullptr;
1295  ChildT* child = mNodes[n].getChild();
1297  mChildMask.setOff(n);
1298  mValueMask.set(n, state);
1299  mNodes[n].setValue(value);
1300  }
1302  ? reinterpret_cast<NodeT*>(child)
1303  : child->template stealNode<NodeT>(xyz, value, state);
1305 }
1306 
1307 
1308 ////////////////////////////////////////
1309 
1310 
1311 template<typename ChildT, Index Log2Dim>
1312 template<typename NodeT>
1313 inline NodeT*
1315 {
1316  if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
1317  NodeT::LEVEL > ChildT::LEVEL) return nullptr;
1319  const Index n = this->coordToOffset(xyz);
1320  if (mChildMask.isOff(n)) return nullptr;
1321  ChildT* child = mNodes[n].getChild();
1323  ? reinterpret_cast<NodeT*>(child)
1324  : child->template probeNode<NodeT>(xyz);
1326 }
1327 
1328 
1329 template<typename ChildT, Index Log2Dim>
1330 template<typename NodeT, typename AccessorT>
1331 inline NodeT*
1332 InternalNode<ChildT, Log2Dim>::probeNodeAndCache(const Coord& xyz, AccessorT& acc)
1333 {
1334  if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
1335  NodeT::LEVEL > ChildT::LEVEL) return nullptr;
1337  const Index n = this->coordToOffset(xyz);
1338  if (mChildMask.isOff(n)) return nullptr;
1339  ChildT* child = mNodes[n].getChild();
1340  acc.insert(xyz, child);
1342  ? reinterpret_cast<NodeT*>(child)
1343  : child->template probeNodeAndCache<NodeT>(xyz, acc);
1345 }
1346 
1347 
1348 template<typename ChildT, Index Log2Dim>
1349 template<typename NodeT>
1350 inline const NodeT*
1352 {
1353  if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
1354  NodeT::LEVEL > ChildT::LEVEL) return nullptr;
1356  const Index n = this->coordToOffset(xyz);
1357  if (mChildMask.isOff(n)) return nullptr;
1358  const ChildT* child = mNodes[n].getChild();
1360  ? reinterpret_cast<const NodeT*>(child)
1361  : child->template probeConstNode<NodeT>(xyz);
1363 }
1364 
1365 
1366 template<typename ChildT, Index Log2Dim>
1367 template<typename NodeT, typename AccessorT>
1368 inline const NodeT*
1369 InternalNode<ChildT, Log2Dim>::probeConstNodeAndCache(const Coord& xyz, AccessorT& acc) const
1370 {
1371  if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
1372  NodeT::LEVEL > ChildT::LEVEL) return nullptr;
1374  const Index n = this->coordToOffset(xyz);
1375  if (mChildMask.isOff(n)) return nullptr;
1376  const ChildT* child = mNodes[n].getChild();
1377  acc.insert(xyz, child);
1379  ? reinterpret_cast<const NodeT*>(child)
1380  : child->template probeConstNodeAndCache<NodeT>(xyz, acc);
1382 }
1383 
1384 
1385 ////////////////////////////////////////
1386 
1387 
1388 template<typename ChildT, Index Log2Dim>
1389 inline ChildT*
1391 {
1392  const Index n = this->coordToOffset(xyz);
1393  return this->probeChildUnsafe(n);
1394 }
1395 
1396 template<typename ChildT, Index Log2Dim>
1397 inline const ChildT*
1399 {
1400  const Index n = this->coordToOffset(xyz);
1401  return this->probeConstChildUnsafe(n);
1402 }
1403 
1404 template<typename ChildT, Index Log2Dim>
1405 inline ChildT*
1407 {
1408  const Index n = this->coordToOffset(xyz);
1409  return this->probeChildUnsafe(n, value, active);
1410 }
1411 
1412 template<typename ChildT, Index Log2Dim>
1413 inline const ChildT*
1415 {
1416  const Index n = this->coordToOffset(xyz);
1417  return this->probeConstChildUnsafe(n, value, active);
1418 }
1419 
1420 template<typename ChildT, Index Log2Dim>
1421 inline ChildT*
1423 {
1424  OPENVDB_ASSERT(offset < NUM_VALUES);
1425  if (mChildMask.isOn(offset)) return mNodes[offset].getChild();
1426  return nullptr;
1427 }
1428 
1429 template<typename ChildT, Index Log2Dim>
1430 inline const ChildT*
1432 {
1433  OPENVDB_ASSERT(offset < NUM_VALUES);
1434  if (mChildMask.isOn(offset)) return mNodes[offset].getChild();
1435  return nullptr;
1436 }
1437 
1438 template<typename ChildT, Index Log2Dim>
1439 inline ChildT*
1441 {
1442  OPENVDB_ASSERT(offset < NUM_VALUES);
1443  if (mChildMask.isOn(offset)) return mNodes[offset].getChild();
1444  value = mNodes[offset].getValue();
1445  active = mValueMask.isOn(offset);
1446  return nullptr;
1447 }
1448 
1449 template<typename ChildT, Index Log2Dim>
1450 inline const ChildT*
1452 {
1453  OPENVDB_ASSERT(offset < NUM_VALUES);
1454  if (mChildMask.isOn(offset)) return mNodes[offset].getChild();
1455  value = mNodes[offset].getValue();
1456  active = mValueMask.isOn(offset);
1457  return nullptr;
1458 }
1459 
1460 
1461 ////////////////////////////////////////
1462 
1463 
1464 template<typename ChildT, Index Log2Dim>
1465 inline typename ChildT::LeafNodeType*
1467 {
1468  return this->template probeNode<LeafNodeType>(xyz);
1469 }
1470 
1471 
1472 template<typename ChildT, Index Log2Dim>
1473 template<typename AccessorT>
1474 inline typename ChildT::LeafNodeType*
1475 InternalNode<ChildT, Log2Dim>::probeLeafAndCache(const Coord& xyz, AccessorT& acc)
1476 {
1477  return this->template probeNodeAndCache<LeafNodeType>(xyz, acc);
1478 }
1479 
1480 
1481 template<typename ChildT, Index Log2Dim>
1482 template<typename AccessorT>
1483 inline const typename ChildT::LeafNodeType*
1484 InternalNode<ChildT, Log2Dim>::probeLeafAndCache(const Coord& xyz, AccessorT& acc) const
1485 {
1486  return this->probeConstLeafAndCache(xyz, acc);
1487 }
1488 
1489 
1490 template<typename ChildT, Index Log2Dim>
1491 inline const typename ChildT::LeafNodeType*
1493 {
1494  return this->template probeConstNode<LeafNodeType>(xyz);
1495 }
1496 
1497 
1498 template<typename ChildT, Index Log2Dim>
1499 template<typename AccessorT>
1500 inline const typename ChildT::LeafNodeType*
1501 InternalNode<ChildT, Log2Dim>::probeConstLeafAndCache(const Coord& xyz, AccessorT& acc) const
1502 {
1503  return this->template probeConstNodeAndCache<LeafNodeType>(xyz, acc);
1504 }
1505 
1506 
1507 ////////////////////////////////////////
1508 
1509 
1510 template<typename ChildT, Index Log2Dim>
1511 inline void
1513 {
1514  OPENVDB_ASSERT(leaf != nullptr);
1515  const Coord& xyz = leaf->origin();
1516  const Index n = this->coordToOffset(xyz);
1517  ChildT* child = nullptr;
1518  if (mChildMask.isOff(n)) {
1519  if (ChildT::LEVEL>0) {
1520  child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n));
1521  } else {
1522  child = reinterpret_cast<ChildT*>(leaf);
1523  }
1524  this->setChildNode(n, child);
1525  } else {
1526  if (ChildT::LEVEL>0) {
1527  child = mNodes[n].getChild();
1528  } else {
1529  delete mNodes[n].getChild();
1530  child = reinterpret_cast<ChildT*>(leaf);
1531  mNodes[n].setChild(child);
1532  }
1533  }
1534  child->addLeaf(leaf);
1535 }
1536 
1537 
1538 template<typename ChildT, Index Log2Dim>
1539 template<typename AccessorT>
1540 inline void
1542 {
1543  OPENVDB_ASSERT(leaf != nullptr);
1544  const Coord& xyz = leaf->origin();
1545  const Index n = this->coordToOffset(xyz);
1546  ChildT* child = nullptr;
1547  if (mChildMask.isOff(n)) {
1548  if (ChildT::LEVEL>0) {
1549  child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n));
1550  acc.insert(xyz, child);//we only cache internal nodes
1551  } else {
1552  child = reinterpret_cast<ChildT*>(leaf);
1553  }
1554  this->setChildNode(n, child);
1555  } else {
1556  if (ChildT::LEVEL>0) {
1557  child = mNodes[n].getChild();
1558  acc.insert(xyz, child);//we only cache internal nodes
1559  } else {
1560  delete mNodes[n].getChild();
1561  child = reinterpret_cast<ChildT*>(leaf);
1562  mNodes[n].setChild(child);
1563  }
1564  }
1565  child->addLeafAndCache(leaf, acc);
1566 }
1567 
1568 
1569 ////////////////////////////////////////
1570 
1571 
1572 template<typename ChildT, Index Log2Dim>
1573 inline bool
1575 {
1576  OPENVDB_ASSERT(child);
1577  const Coord& xyz = child->origin();
1578  // verify that the child belongs in this internal node
1579  if (Coord((xyz & ~(DIM-1))) != this->origin()) return false;
1580  // compute the offset and insert the child node
1581  const Index n = this->coordToOffset(xyz);
1582  // this also deletes an existing child node
1583  this->resetChildNode(n, child);
1584  return true;
1585 }
1586 
1587 
1588 template<typename ChildT, Index Log2Dim>
1589 inline void
1591 {
1592  OPENVDB_ASSERT(n < NUM_VALUES);
1593  this->makeChildNodeEmpty(n, value);
1594  mValueMask.set(n, state);
1595 }
1596 
1597 
1598 template<typename ChildT, Index Log2Dim>
1599 inline void
1601  const ValueType& value, bool state)
1602 {
1603  if (LEVEL >= level) {
1604  const Index n = this->coordToOffset(xyz);
1605  if (mChildMask.isOff(n)) {// tile case
1606  if (LEVEL > level) {
1607  ChildT* child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n));
1608  this->setChildNode(n, child);
1609  child->addTile(level, xyz, value, state);
1610  } else {
1611  mValueMask.set(n, state);
1612  mNodes[n].setValue(value);
1613  }
1614  } else {// child branch case
1615  ChildT* child = mNodes[n].getChild();
1616  if (LEVEL > level) {
1617  child->addTile(level, xyz, value, state);
1618  } else {
1619  delete child;
1620  mChildMask.setOff(n);
1621  mValueMask.set(n, state);
1622  mNodes[n].setValue(value);
1623  }
1624  }
1625  }
1626 }
1627 
1628 
1629 template<typename ChildT, Index Log2Dim>
1630 template<typename AccessorT>
1631 inline void
1633  const ValueType& value, bool state, AccessorT& acc)
1634 {
1635  if (LEVEL >= level) {
1636  const Index n = this->coordToOffset(xyz);
1637  if (mChildMask.isOff(n)) {// tile case
1638  if (LEVEL > level) {
1639  ChildT* child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n));
1640  this->setChildNode(n, child);
1641  acc.insert(xyz, child);
1642  child->addTileAndCache(level, xyz, value, state, acc);
1643  } else {
1644  mValueMask.set(n, state);
1645  mNodes[n].setValue(value);
1646  }
1647  } else {// child branch case
1648  ChildT* child = mNodes[n].getChild();
1649  if (LEVEL > level) {
1650  acc.insert(xyz, child);
1651  child->addTileAndCache(level, xyz, value, state, acc);
1652  } else {
1653  delete child;
1654  mChildMask.setOff(n);
1655  mValueMask.set(n, state);
1656  mNodes[n].setValue(value);
1657  }
1658  }
1659  }
1660 }
1661 
1662 
1663 ////////////////////////////////////////
1664 
1665 
1666 template<typename ChildT, Index Log2Dim>
1667 inline typename ChildT::LeafNodeType*
1669 {
1670  const Index n = this->coordToOffset(xyz);
1671  ChildT* child = nullptr;
1672  if (mChildMask.isOff(n)) {
1673  child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n));
1674  this->setChildNode(n, child);
1675  } else {
1676  child = mNodes[n].getChild();
1677  }
1678  return child->touchLeaf(xyz);
1679 }
1680 
1681 
1682 template<typename ChildT, Index Log2Dim>
1683 template<typename AccessorT>
1684 inline typename ChildT::LeafNodeType*
1686 {
1687  const Index n = this->coordToOffset(xyz);
1688  if (mChildMask.isOff(n)) {
1689  this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), mValueMask.isOn(n)));
1690  }
1691  acc.insert(xyz, mNodes[n].getChild());
1692  return mNodes[n].getChild()->touchLeafAndCache(xyz, acc);
1693 }
1694 
1695 
1696 ////////////////////////////////////////
1697 
1698 
1699 template<typename ChildT, Index Log2Dim>
1700 inline bool
1702  const ValueType& tolerance) const
1703 {
1704  if (!mChildMask.isOff() || !mValueMask.isConstant(state)) return false;// early termination
1705 
1706  firstValue = mNodes[0].getValue();
1707  for (Index i = 1; i < NUM_VALUES; ++i) {
1708  if (!math::isApproxEqual(mNodes[i].getValue(), firstValue, tolerance)) {
1709  return false; // early termination
1710  }
1711  }
1712  return true;
1713 }
1714 
1715 
1716 ////////////////////////////////////////
1717 
1718 
1719 template<typename ChildT, Index Log2Dim>
1720 inline bool
1722  ValueType& maxValue,
1723  bool& state,
1724  const ValueType& tolerance) const
1725 {
1726 
1727  if (!mChildMask.isOff() || !mValueMask.isConstant(state)) return false;// early termination
1728  minValue = maxValue = mNodes[0].getValue();
1729  for (Index i = 1; i < NUM_VALUES; ++i) {
1730  const ValueType& v = mNodes[i].getValue();
1731  if (v < minValue) {
1732  if ((maxValue - v) > tolerance) return false;// early termination
1733  minValue = v;
1734  } else if (v > maxValue) {
1735  if ((v - minValue) > tolerance) return false;// early termination
1736  maxValue = v;
1737  }
1738  }
1739  return true;
1740 }
1741 
1742 
1743 ////////////////////////////////////////
1744 
1745 
1746 template<typename ChildT, Index Log2Dim>
1747 inline bool
1749 {
1751  const bool anyActiveTiles = !mValueMask.isOff();
1752  if (LEVEL==1 || anyActiveTiles) return anyActiveTiles;
1753  for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1754  if (iter->hasActiveTiles()) return true;
1755  }
1756  return false;
1758 }
1759 
1760 
1761 template<typename ChildT, Index Log2Dim>
1762 inline bool
1764 {
1765  const Index n = this->coordToOffset(xyz);
1766  return this->isChildMaskOff(n) ? this->isValueMaskOn(n)
1767  : mNodes[n].getChild()->isValueOn(xyz);
1768 }
1769 
1770 template<typename ChildT, Index Log2Dim>
1771 inline bool
1773 {
1774  const Index n = this->coordToOffset(xyz);
1775  return this->isChildMaskOff(n) ? this->isValueMaskOn(n)
1776  : mNodes[n].getChild()->isValueOff(xyz);
1777 }
1778 
1779 template<typename ChildT, Index Log2Dim>
1780 template<typename AccessorT>
1781 inline bool
1782 InternalNode<ChildT, Log2Dim>::isValueOnAndCache(const Coord& xyz, AccessorT& acc) const
1783 {
1784  const Index n = this->coordToOffset(xyz);
1785  if (this->isChildMaskOff(n)) return this->isValueMaskOn(n);
1786  acc.insert(xyz, mNodes[n].getChild());
1787  return mNodes[n].getChild()->isValueOnAndCache(xyz, acc);
1788 }
1789 
1790 
1791 template<typename ChildT, Index Log2Dim>
1792 inline const typename ChildT::ValueType&
1794 {
1795  const Index n = this->coordToOffset(xyz);
1796  return this->isChildMaskOff(n) ? mNodes[n].getValue()
1797  : mNodes[n].getChild()->getValue(xyz);
1798 }
1799 
1800 template<typename ChildT, Index Log2Dim>
1801 template<typename AccessorT>
1802 inline const typename ChildT::ValueType&
1804 {
1805  const Index n = this->coordToOffset(xyz);
1806  if (this->isChildMaskOn(n)) {
1807  acc.insert(xyz, mNodes[n].getChild());
1808  return mNodes[n].getChild()->getValueAndCache(xyz, acc);
1809  }
1810  return mNodes[n].getValue();
1811 }
1812 
1813 
1814 template<typename ChildT, Index Log2Dim>
1815 inline Index
1817 {
1818  const Index n = this->coordToOffset(xyz);
1819  return this->isChildMaskOff(n) ? LEVEL : mNodes[n].getChild()->getValueLevel(xyz);
1820 }
1821 
1822 template<typename ChildT, Index Log2Dim>
1823 template<typename AccessorT>
1824 inline Index
1825 InternalNode<ChildT, Log2Dim>::getValueLevelAndCache(const Coord& xyz, AccessorT& acc) const
1826 {
1827  const Index n = this->coordToOffset(xyz);
1828  if (this->isChildMaskOn(n)) {
1829  acc.insert(xyz, mNodes[n].getChild());
1830  return mNodes[n].getChild()->getValueLevelAndCache(xyz, acc);
1831  }
1832  return LEVEL;
1833 }
1834 
1835 
1836 template<typename ChildT, Index Log2Dim>
1837 inline bool
1839 {
1840  const Index n = this->coordToOffset(xyz);
1841  if (this->isChildMaskOff(n)) {
1842  value = mNodes[n].getValue();
1843  return this->isValueMaskOn(n);
1844  }
1845  return mNodes[n].getChild()->probeValue(xyz, value);
1846 }
1847 
1848 template<typename ChildT, Index Log2Dim>
1849 template<typename AccessorT>
1850 inline bool
1852  ValueType& value, AccessorT& acc) const
1853 {
1854  const Index n = this->coordToOffset(xyz);
1855  if (this->isChildMaskOn(n)) {
1856  acc.insert(xyz, mNodes[n].getChild());
1857  return mNodes[n].getChild()->probeValueAndCache(xyz, value, acc);
1858  }
1859  value = mNodes[n].getValue();
1860  return this->isValueMaskOn(n);
1861 }
1862 
1863 
1864 template<typename ChildT, Index Log2Dim>
1865 inline void
1867 {
1868  const Index n = this->coordToOffset(xyz);
1869  bool hasChild = this->isChildMaskOn(n);
1870  if (!hasChild && this->isValueMaskOn(n)) {
1871  // If the voxel belongs to a constant tile that is active,
1872  // a child subtree must be constructed.
1873  hasChild = true;
1874  this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), /*active=*/true));
1875  }
1876  if (hasChild) mNodes[n].getChild()->setValueOff(xyz);
1877 }
1878 
1879 
1880 template<typename ChildT, Index Log2Dim>
1881 inline void
1883 {
1884  const Index n = this->coordToOffset(xyz);
1885  bool hasChild = this->isChildMaskOn(n);
1886  if (!hasChild && !this->isValueMaskOn(n)) {
1887  // If the voxel belongs to a constant tile that is inactive,
1888  // a child subtree must be constructed.
1889  hasChild = true;
1890  this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), /*active=*/false));
1891  }
1892  if (hasChild) mNodes[n].getChild()->setValueOn(xyz);
1893 }
1894 
1895 
1896 template<typename ChildT, Index Log2Dim>
1897 inline void
1899 {
1900  const Index n = InternalNode::coordToOffset(xyz);
1901  bool hasChild = this->isChildMaskOn(n);
1902  if (!hasChild) {
1903  const bool active = this->isValueMaskOn(n);
1904  if (active || !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1905  // If the voxel belongs to a tile that is either active or that
1906  // has a constant value that is different from the one provided,
1907  // a child subtree must be constructed.
1908  hasChild = true;
1909  this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1910  }
1911  }
1912  if (hasChild) mNodes[n].getChild()->setValueOff(xyz, value);
1913 }
1914 
1915 template<typename ChildT, Index Log2Dim>
1916 template<typename AccessorT>
1917 inline void
1919  const ValueType& value, AccessorT& acc)
1920 {
1921  const Index n = InternalNode::coordToOffset(xyz);
1922  bool hasChild = this->isChildMaskOn(n);
1923  if (!hasChild) {
1924  const bool active = this->isValueMaskOn(n);
1925  if (active || !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1926  // If the voxel belongs to a tile that is either active or that
1927  // has a constant value that is different from the one provided,
1928  // a child subtree must be constructed.
1929  hasChild = true;
1930  this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1931  }
1932  }
1933  if (hasChild) {
1934  ChildT* child = mNodes[n].getChild();
1935  acc.insert(xyz, child);
1936  child->setValueOffAndCache(xyz, value, acc);
1937  }
1938 }
1939 
1940 
1941 template<typename ChildT, Index Log2Dim>
1942 inline void
1944 {
1945  const Index n = this->coordToOffset(xyz);
1946  bool hasChild = this->isChildMaskOn(n);
1947  if (!hasChild) {
1948  const bool active = this->isValueMaskOn(n); // tile's active state
1949  if (!active || !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1950  // If the voxel belongs to a tile that is either inactive or that
1951  // has a constant value that is different from the one provided,
1952  // a child subtree must be constructed.
1953  hasChild = true;
1954  this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1955  }
1956  }
1957  if (hasChild) mNodes[n].getChild()->setValueOn(xyz, value);
1958 }
1959 
1960 template<typename ChildT, Index Log2Dim>
1961 template<typename AccessorT>
1962 inline void
1964  const ValueType& value, AccessorT& acc)
1965 {
1966  const Index n = this->coordToOffset(xyz);
1967  bool hasChild = this->isChildMaskOn(n);
1968  if (!hasChild) {
1969  const bool active = this->isValueMaskOn(n);
1970  if (!active || !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1971  // If the voxel belongs to a tile that is either inactive or that
1972  // has a constant value that is different from the one provided,
1973  // a child subtree must be constructed.
1974  hasChild = true;
1975  this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1976  }
1977  }
1978  if (hasChild) {
1979  acc.insert(xyz, mNodes[n].getChild());
1980  mNodes[n].getChild()->setValueAndCache(xyz, value, acc);
1981  }
1982 }
1983 
1984 
1985 template<typename ChildT, Index Log2Dim>
1986 inline void
1988 {
1989  const Index n = this->coordToOffset(xyz);
1990  bool hasChild = this->isChildMaskOn(n);
1991  if (!hasChild && !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1992  // If the voxel has a tile value that is different from the one provided,
1993  // a child subtree must be constructed.
1994  const bool active = this->isValueMaskOn(n);
1995  hasChild = true;
1996  this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1997  }
1998  if (hasChild) mNodes[n].getChild()->setValueOnly(xyz, value);
1999 }
2000 
2001 template<typename ChildT, Index Log2Dim>
2002 template<typename AccessorT>
2003 inline void
2005  const ValueType& value, AccessorT& acc)
2006 {
2007  const Index n = this->coordToOffset(xyz);
2008  bool hasChild = this->isChildMaskOn(n);
2009  if (!hasChild && !math::isExactlyEqual(mNodes[n].getValue(), value)) {
2010  // If the voxel has a tile value that is different from the one provided,
2011  // a child subtree must be constructed.
2012  const bool active = this->isValueMaskOn(n);
2013  hasChild = true;
2014  this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
2015  }
2016  if (hasChild) {
2017  acc.insert(xyz, mNodes[n].getChild());
2018  mNodes[n].getChild()->setValueOnlyAndCache(xyz, value, acc);
2019  }
2020 }
2021 
2022 
2023 template<typename ChildT, Index Log2Dim>
2024 inline void
2026 {
2027  const Index n = this->coordToOffset(xyz);
2028  bool hasChild = this->isChildMaskOn(n);
2029  if (!hasChild) {
2030  if (on != this->isValueMaskOn(n)) {
2031  // If the voxel belongs to a tile with the wrong active state,
2032  // then a child subtree must be constructed.
2033  // 'on' is the voxel's new state, therefore '!on' is the tile's current state
2034  hasChild = true;
2035  this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), !on));
2036  }
2037  }
2038  if (hasChild) mNodes[n].getChild()->setActiveState(xyz, on);
2039 }
2040 
2041 template<typename ChildT, Index Log2Dim>
2042 template<typename AccessorT>
2043 inline void
2044 InternalNode<ChildT, Log2Dim>::setActiveStateAndCache(const Coord& xyz, bool on, AccessorT& acc)
2045 {
2046  const Index n = this->coordToOffset(xyz);
2047  bool hasChild = this->isChildMaskOn(n);
2048  if (!hasChild) {
2049  if (on != this->isValueMaskOn(n)) {
2050  // If the voxel belongs to a tile with the wrong active state,
2051  // then a child subtree must be constructed.
2052  // 'on' is the voxel's new state, therefore '!on' is the tile's current state
2053  hasChild = true;
2054  this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), !on));
2055  }
2056  }
2057  if (hasChild) {
2058  ChildT* child = mNodes[n].getChild();
2059  acc.insert(xyz, child);
2060  child->setActiveStateAndCache(xyz, on, acc);
2061  }
2062 }
2063 
2064 
2065 template<typename ChildT, Index Log2Dim>
2066 inline void
2068 {
2069  mValueMask = !mChildMask;
2070  for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
2071  mNodes[iter.pos()].getChild()->setValuesOn();
2072  }
2073 }
2074 
2075 
2076 template<typename ChildT, Index Log2Dim>
2077 template<typename ModifyOp>
2078 inline void
2079 InternalNode<ChildT, Log2Dim>::modifyValue(const Coord& xyz, const ModifyOp& op)
2080 {
2081  const Index n = InternalNode::coordToOffset(xyz);
2082  bool hasChild = this->isChildMaskOn(n);
2083  if (!hasChild) {
2084  // Need to create a child if the tile is inactive,
2085  // in order to activate voxel (x, y, z).
2086  const bool active = this->isValueMaskOn(n);
2087  bool createChild = !active;
2088  if (!createChild) {
2089  // Need to create a child if applying the functor
2090  // to the tile value produces a different value.
2091  const ValueType& tileVal = mNodes[n].getValue();
2092  ValueType modifiedVal = tileVal;
2093  op(modifiedVal);
2094  createChild = !math::isExactlyEqual(tileVal, modifiedVal);
2095  }
2096  if (createChild) {
2097  hasChild = true;
2098  this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
2099  }
2100  }
2101  if (hasChild) mNodes[n].getChild()->modifyValue(xyz, op);
2102 }
2103 
2104 template<typename ChildT, Index Log2Dim>
2105 template<typename ModifyOp, typename AccessorT>
2106 inline void
2107 InternalNode<ChildT, Log2Dim>::modifyValueAndCache(const Coord& xyz, const ModifyOp& op,
2108  AccessorT& acc)
2109 {
2110  const Index n = InternalNode::coordToOffset(xyz);
2111  bool hasChild = this->isChildMaskOn(n);
2112  if (!hasChild) {
2113  // Need to create a child if the tile is inactive,
2114  // in order to activate voxel (x, y, z).
2115  const bool active = this->isValueMaskOn(n);
2116  bool createChild = !active;
2117  if (!createChild) {
2118  // Need to create a child if applying the functor
2119  // to the tile value produces a different value.
2120  const ValueType& tileVal = mNodes[n].getValue();
2121  ValueType modifiedVal = tileVal;
2122  op(modifiedVal);
2123  createChild = !math::isExactlyEqual(tileVal, modifiedVal);
2124  }
2125  if (createChild) {
2126  hasChild = true;
2127  this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
2128  }
2129  }
2130  if (hasChild) {
2131  ChildNodeType* child = mNodes[n].getChild();
2132  acc.insert(xyz, child);
2133  child->modifyValueAndCache(xyz, op, acc);
2134  }
2135 }
2136 
2137 
2138 template<typename ChildT, Index Log2Dim>
2139 template<typename ModifyOp>
2140 inline void
2142 {
2143  const Index n = InternalNode::coordToOffset(xyz);
2144  bool hasChild = this->isChildMaskOn(n);
2145  if (!hasChild) {
2146  const bool tileState = this->isValueMaskOn(n);
2147  const ValueType& tileVal = mNodes[n].getValue();
2148  bool modifiedState = !tileState;
2149  ValueType modifiedVal = tileVal;
2150  op(modifiedVal, modifiedState);
2151  // Need to create a child if applying the functor to the tile
2152  // produces a different value or active state.
2153  if (modifiedState != tileState || !math::isExactlyEqual(modifiedVal, tileVal)) {
2154  hasChild = true;
2155  this->setChildNode(n, new ChildNodeType(xyz, tileVal, tileState));
2156  }
2157  }
2158  if (hasChild) mNodes[n].getChild()->modifyValueAndActiveState(xyz, op);
2159 }
2160 
2161 template<typename ChildT, Index Log2Dim>
2162 template<typename ModifyOp, typename AccessorT>
2163 inline void
2165  const Coord& xyz, const ModifyOp& op, AccessorT& acc)
2166 {
2167  const Index n = InternalNode::coordToOffset(xyz);
2168  bool hasChild = this->isChildMaskOn(n);
2169  if (!hasChild) {
2170  const bool tileState = this->isValueMaskOn(n);
2171  const ValueType& tileVal = mNodes[n].getValue();
2172  bool modifiedState = !tileState;
2173  ValueType modifiedVal = tileVal;
2174  op(modifiedVal, modifiedState);
2175  // Need to create a child if applying the functor to the tile
2176  // produces a different value or active state.
2177  if (modifiedState != tileState || !math::isExactlyEqual(modifiedVal, tileVal)) {
2178  hasChild = true;
2179  this->setChildNode(n, new ChildNodeType(xyz, tileVal, tileState));
2180  }
2181  }
2182  if (hasChild) {
2183  ChildNodeType* child = mNodes[n].getChild();
2184  acc.insert(xyz, child);
2185  child->modifyValueAndActiveStateAndCache(xyz, op, acc);
2186  }
2187 }
2188 
2189 
2190 ////////////////////////////////////////
2191 
2192 
2193 template<typename ChildT, Index Log2Dim>
2194 inline void
2195 InternalNode<ChildT, Log2Dim>::clip(const CoordBBox& clipBBox, const ValueType& background)
2196 {
2197  CoordBBox nodeBBox = this->getNodeBoundingBox();
2198  if (!clipBBox.hasOverlap(nodeBBox)) {
2199  // This node lies completely outside the clipping region. Fill it with background tiles.
2200  this->fill(nodeBBox, background, /*active=*/false);
2201  } else if (clipBBox.isInside(nodeBBox)) {
2202  // This node lies completely inside the clipping region. Leave it intact.
2203  return;
2204  }
2205 
2206  // This node isn't completely contained inside the clipping region.
2207  // Clip tiles and children, and replace any that lie outside the region
2208  // with background tiles.
2209 
2210  for (Index pos = 0; pos < NUM_VALUES; ++pos) {
2211  const Coord xyz = this->offsetToGlobalCoord(pos); // tile or child origin
2212  CoordBBox tileBBox(xyz, xyz.offsetBy(ChildT::DIM - 1)); // tile or child bounds
2213  if (!clipBBox.hasOverlap(tileBBox)) {
2214  // This table entry lies completely outside the clipping region.
2215  // Replace it with a background tile.
2216  this->makeChildNodeEmpty(pos, background);
2217  mValueMask.setOff(pos);
2218  } else if (!clipBBox.isInside(tileBBox)) {
2219  // This table entry does not lie completely inside the clipping region
2220  // and must be clipped.
2221  if (this->isChildMaskOn(pos)) {
2222  mNodes[pos].getChild()->clip(clipBBox, background);
2223  } else {
2224  // Replace this tile with a background tile, then fill the clip region
2225  // with the tile's original value. (This might create a child branch.)
2226  tileBBox.intersect(clipBBox);
2227  const ValueType val = mNodes[pos].getValue();
2228  const bool on = this->isValueMaskOn(pos);
2229  mNodes[pos].setValue(background);
2230  mValueMask.setOff(pos);
2231  this->fill(tileBBox, val, on);
2232  }
2233  } else {
2234  // This table entry lies completely inside the clipping region. Leave it intact.
2235  }
2236  }
2237 }
2238 
2239 
2240 ////////////////////////////////////////
2241 
2242 
2243 template<typename ChildT, Index Log2Dim>
2244 inline void
2246 {
2247  auto clippedBBox = this->getNodeBoundingBox();
2248  clippedBBox.intersect(bbox);
2249  if (!clippedBBox) return;
2250 
2251  // Iterate over the fill region in axis-aligned, tile-sized chunks.
2252  // (The first and last chunks along each axis might be smaller than a tile.)
2253  Coord xyz, tileMin, tileMax;
2254  for (int x = clippedBBox.min().x(); x <= clippedBBox.max().x(); x = tileMax.x() + 1) {
2255  xyz.setX(x);
2256  for (int y = clippedBBox.min().y(); y <= clippedBBox.max().y(); y = tileMax.y() + 1) {
2257  xyz.setY(y);
2258  for (int z = clippedBBox.min().z(); z <= clippedBBox.max().z(); z = tileMax.z() + 1) {
2259  xyz.setZ(z);
2260 
2261  // Get the bounds of the tile that contains voxel (x, y, z).
2262  const Index n = this->coordToOffset(xyz);
2263  tileMin = this->offsetToGlobalCoord(n);
2264  tileMax = tileMin.offsetBy(ChildT::DIM - 1);
2265 
2266  if (xyz != tileMin || Coord::lessThan(clippedBBox.max(), tileMax)) {
2267  // If the box defined by (xyz, clippedBBox.max()) doesn't completely enclose
2268  // the tile to which xyz belongs, create a child node (or retrieve
2269  // the existing one).
2270  ChildT* child = nullptr;
2271  if (this->isChildMaskOff(n)) {
2272  // Replace the tile with a newly-created child that is initialized
2273  // with the tile's value and active state.
2274  child = new ChildT{xyz, mNodes[n].getValue(), this->isValueMaskOn(n)};
2275  this->setChildNode(n, child);
2276  } else {
2277  child = mNodes[n].getChild();
2278  }
2279 
2280  // Forward the fill request to the child.
2281  if (child) {
2282  const Coord tmp = Coord::minComponent(clippedBBox.max(), tileMax);
2283  child->fill(CoordBBox(xyz, tmp), value, active);
2284  }
2285 
2286  } else {
2287  // If the box given by (xyz, clippedBBox.max()) completely encloses
2288  // the tile to which xyz belongs, create the tile (if it
2289  // doesn't already exist) and give it the fill value.
2290  this->makeChildNodeEmpty(n, value);
2291  mValueMask.set(n, active);
2292  }
2293  }
2294  }
2295  }
2296 }
2297 
2298 
2299 template<typename ChildT, Index Log2Dim>
2300 inline void
2302 {
2303  auto clippedBBox = this->getNodeBoundingBox();
2304  clippedBBox.intersect(bbox);
2305  if (!clippedBBox) return;
2306 
2307  // Iterate over the fill region in axis-aligned, tile-sized chunks.
2308  // (The first and last chunks along each axis might be smaller than a tile.)
2309  Coord xyz, tileMin, tileMax;
2310  for (int x = clippedBBox.min().x(); x <= clippedBBox.max().x(); x = tileMax.x() + 1) {
2311  xyz.setX(x);
2312  for (int y = clippedBBox.min().y(); y <= clippedBBox.max().y(); y = tileMax.y() + 1) {
2313  xyz.setY(y);
2314  for (int z = clippedBBox.min().z(); z <= clippedBBox.max().z(); z = tileMax.z() + 1) {
2315  xyz.setZ(z);
2316 
2317  // Get the table index of the tile that contains voxel (x, y, z).
2318  const auto n = this->coordToOffset(xyz);
2319 
2320  // Retrieve the child node at index n, or replace the tile at index n with a child.
2321  ChildT* child = nullptr;
2322  if (this->isChildMaskOn(n)) {
2323  child = mNodes[n].getChild();
2324  } else {
2325  // Replace the tile with a newly-created child that is filled
2326  // with the tile's value and active state.
2327  child = new ChildT{xyz, mNodes[n].getValue(), this->isValueMaskOn(n)};
2328  this->setChildNode(n, child);
2329  }
2330 
2331  // Get the bounds of the tile that contains voxel (x, y, z).
2332  tileMin = this->offsetToGlobalCoord(n);
2333  tileMax = tileMin.offsetBy(ChildT::DIM - 1);
2334 
2335  // Forward the fill request to the child.
2336  child->denseFill(CoordBBox{xyz, clippedBBox.max()}, value, active);
2337  }
2338  }
2339  }
2340 }
2341 
2342 
2343 ////////////////////////////////////////
2344 
2345 
2346 template<typename ChildT, Index Log2Dim>
2347 template<typename DenseT>
2348 inline void
2350 {
2351  using DenseValueType = typename DenseT::ValueType;
2352 
2353  const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride();
2354  const Coord& min = dense.bbox().min();
2355  for (Coord xyz = bbox.min(), max; xyz[0] <= bbox.max()[0]; xyz[0] = max[0] + 1) {
2356  for (xyz[1] = bbox.min()[1]; xyz[1] <= bbox.max()[1]; xyz[1] = max[1] + 1) {
2357  for (xyz[2] = bbox.min()[2]; xyz[2] <= bbox.max()[2]; xyz[2] = max[2] + 1) {
2358  const Index n = this->coordToOffset(xyz);
2359  // Get max coordinates of the child node that contains voxel xyz.
2360  max = this->offsetToGlobalCoord(n).offsetBy(ChildT::DIM-1);
2361 
2362  // Get the bbox of the interection of bbox and the child node
2363  CoordBBox sub(xyz, Coord::minComponent(bbox.max(), max));
2364 
2365  if (this->isChildMaskOn(n)) {//is a child
2366  mNodes[n].getChild()->copyToDense(sub, dense);
2367  } else {//a tile value
2368  const ValueType value = mNodes[n].getValue();
2369  sub.translate(-min);
2370  DenseValueType* a0 = dense.data() + zStride*sub.min()[2];
2371  for (Int32 x=sub.min()[0], ex=sub.max()[0]+1; x<ex; ++x) {
2372  DenseValueType* a1 = a0 + x*xStride;
2373  for (Int32 y=sub.min()[1], ey=sub.max()[1]+1; y<ey; ++y) {
2374  DenseValueType* a2 = a1 + y*yStride;
2375  for (Int32 z = sub.min()[2], ez = sub.max()[2]+1;
2376  z < ez; ++z, a2 += zStride)
2377  {
2378  *a2 = DenseValueType(value);
2379  }
2380  }
2381  }
2382  }
2383  }
2384  }
2385  }
2386 }
2387 
2388 
2389 ////////////////////////////////////////
2390 
2391 
2392 template<typename ChildT, Index Log2Dim>
2393 inline void
2394 InternalNode<ChildT, Log2Dim>::writeTopology(std::ostream& os, bool toHalf) const
2395 {
2396  mChildMask.save(os);
2397  mValueMask.save(os);
2398 
2399  {
2400  // Copy all of this node's values into an array.
2401  std::unique_ptr<ValueType[]> valuePtr(new ValueType[NUM_VALUES]);
2402  ValueType* values = valuePtr.get();
2403  const ValueType zero = zeroVal<ValueType>();
2404  for (Index i = 0; i < NUM_VALUES; ++i) {
2405  values[i] = (mChildMask.isOff(i) ? mNodes[i].getValue() : zero);
2406  }
2407  // Compress (optionally) and write out the contents of the array.
2408  io::writeCompressedValues(os, values, NUM_VALUES, mValueMask, mChildMask, toHalf);
2409  }
2410  // Write out the child nodes in order.
2411  for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
2412  iter->writeTopology(os, toHalf);
2413  }
2414 }
2415 
2416 
2417 template<typename ChildT, Index Log2Dim>
2418 inline void
2419 InternalNode<ChildT, Log2Dim>::readTopology(std::istream& is, bool fromHalf)
2420 {
2422 
2423  const ValueType background = (!io::getGridBackgroundValuePtr(is) ? zeroVal<ValueType>()
2424  : *static_cast<const ValueType*>(io::getGridBackgroundValuePtr(is)));
2425 
2426  mChildMask.load(is);
2427  mValueMask.load(is);
2428 
2429  const bool oldVersion =
2431  const Index numValues = (oldVersion ? mChildMask.countOff() : NUM_VALUES);
2432  {
2433  // Read in (and uncompress, if necessary) all of this node's values
2434  // into a contiguous array.
2435  std::unique_ptr<ValueType[]> valuePtr(new ValueType[numValues]);
2436  ValueType* values = valuePtr.get();
2437  io::readCompressedValues(is, values, numValues, mValueMask, fromHalf);
2438 
2439  // Copy values from the array into this node's table.
2440  if (oldVersion) {
2441  Index n = 0;
2442  for (ValueAllIter iter = this->beginValueAll(); iter; ++iter) {
2443  mNodes[iter.pos()].setValue(values[n++]);
2444  }
2445  OPENVDB_ASSERT(n == numValues);
2446  } else {
2447  for (ValueAllIter iter = this->beginValueAll(); iter; ++iter) {
2448  mNodes[iter.pos()].setValue(values[iter.pos()]);
2449  }
2450  }
2451  }
2452 
2453  // Read in all child nodes and insert them into the table at their proper locations.
2454  for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
2455  ChildNodeType* child = new ChildNodeType(PartialCreate(), iter.getCoord(), background);
2456  mNodes[iter.pos()].setChild(child);
2457  child->readTopology(is, fromHalf);
2458  }
2459 }
2460 
2461 
2462 ////////////////////////////////////////
2463 
2464 
2465 template<typename ChildT, Index Log2Dim>
2466 inline const typename ChildT::ValueType&
2468 {
2469  return (this->isChildMaskOn(0) ? mNodes[0].getChild()->getFirstValue() : mNodes[0].getValue());
2470 }
2471 
2472 
2473 template<typename ChildT, Index Log2Dim>
2474 inline const typename ChildT::ValueType&
2476 {
2477  const Index n = NUM_VALUES - 1;
2478  return (this->isChildMaskOn(n) ? mNodes[n].getChild()->getLastValue() : mNodes[n].getValue());
2479 }
2480 
2481 
2482 ////////////////////////////////////////
2483 
2484 
2485 template<typename ChildT, Index Log2Dim>
2486 inline const typename ChildT::ValueType&
2488 {
2489  OPENVDB_ASSERT(n < NUM_VALUES);
2490  OPENVDB_ASSERT(mChildMask.isOff(n));
2491  return mNodes[n].getValue();
2492 }
2493 
2494 template<typename ChildT, Index Log2Dim>
2495 inline bool
2497 {
2498  OPENVDB_ASSERT(n < NUM_VALUES);
2499  OPENVDB_ASSERT(mChildMask.isOff(n));
2500  value = mNodes[n].getValue();
2501  return mValueMask.isOn(n);
2502 }
2503 
2504 template<typename ChildT, Index Log2Dim>
2505 inline ChildT*
2507 {
2508  OPENVDB_ASSERT(n < NUM_VALUES);
2509  OPENVDB_ASSERT(mChildMask.isOn(n));
2510  return mNodes[n].getChild();
2511 }
2512 
2513 template<typename ChildT, Index Log2Dim>
2514 inline const ChildT*
2516 {
2517  OPENVDB_ASSERT(n < NUM_VALUES);
2518  OPENVDB_ASSERT(mChildMask.isOn(n));
2519  return mNodes[n].getChild();
2520 }
2521 
2522 template<typename ChildT, Index Log2Dim>
2523 inline const ChildT*
2525 {
2526  return this->getConstChildUnsafe(n);
2527 }
2528 
2529 template<typename ChildT, Index Log2Dim>
2530 inline void
2532 {
2533  OPENVDB_ASSERT(n < NUM_VALUES);
2534  OPENVDB_ASSERT(mChildMask.isOff(n));
2535  mValueMask.set(n, on);
2536 }
2537 
2538 template<typename ChildT, Index Log2Dim>
2539 inline void
2541 {
2542  OPENVDB_ASSERT(n < NUM_VALUES);
2543  OPENVDB_ASSERT(mChildMask.isOff(n));
2544  mNodes[n].setValue(value);
2545 }
2546 
2547 template<typename ChildT, Index Log2Dim>
2548 inline void
2550 {
2551  OPENVDB_ASSERT(n < NUM_VALUES);
2552  OPENVDB_ASSERT(mChildMask.isOff(n));
2553  mValueMask.setOn(n);
2554 }
2555 
2556 template<typename ChildT, Index Log2Dim>
2557 inline void
2559 {
2560  OPENVDB_ASSERT(n < NUM_VALUES);
2561  OPENVDB_ASSERT(mChildMask.isOff(n));
2562  mNodes[n].setValue(value);
2563  mValueMask.setOn(n);
2564 }
2565 
2566 template<typename ChildT, Index Log2Dim>
2567 inline void
2569 {
2570  OPENVDB_ASSERT(n < NUM_VALUES);
2571  OPENVDB_ASSERT(mChildMask.isOff(n));
2572  mValueMask.setOff(n);
2573 }
2574 
2575 template<typename ChildT, Index Log2Dim>
2576 inline void
2578 {
2579  OPENVDB_ASSERT(n < NUM_VALUES);
2580  OPENVDB_ASSERT(mChildMask.isOff(n));
2581  mNodes[n].setValue(value);
2582  mValueMask.setOff(n);
2583 }
2584 
2585 template<typename ChildT, Index Log2Dim>
2586 inline void
2588 {
2589  OPENVDB_ASSERT(mChildMask.isOff());
2590  mValueMask = mask;
2591 }
2592 
2593 template<typename ChildT, Index Log2Dim>
2594 inline void
2596 {
2597  // replace tile with child
2598  OPENVDB_ASSERT(n < NUM_VALUES);
2599  OPENVDB_ASSERT(mChildMask.isOff(n));
2600  mNodes[n].setChild(child);
2601  mChildMask.setOn(n);
2602  mValueMask.setOff(n);
2603 }
2604 
2605 template<typename ChildT, Index Log2Dim>
2606 inline void
2608 {
2609  // replace child with child
2610  OPENVDB_ASSERT(child);
2611  OPENVDB_ASSERT(n < NUM_VALUES);
2612  OPENVDB_ASSERT(mChildMask.isOn(n));
2613  delete mNodes[n].getChild();
2614  mNodes[n].setChild(child);
2615 }
2616 
2617 template<typename ChildT, Index Log2Dim>
2618 inline ChildT*
2620 {
2621  // replace child with tile (and return child)
2622  OPENVDB_ASSERT(n < NUM_VALUES);
2623  OPENVDB_ASSERT(mChildMask.isOn(n));
2624  auto* child = mNodes[n].getChild();
2625  mChildMask.setOff(n);
2626  mValueMask.set(n, active);
2627  mNodes[n].setValue(value);
2628  return child;
2629 }
2630 
2631 template<typename ChildT, Index Log2Dim>
2632 inline void
2634 {
2635  // replace child with tile (and delete child)
2636  delete this->stealChildUnsafe(n, value, active);
2637 }
2638 
2639 
2640 ////////////////////////////////////////
2641 
2642 
2643 template<typename ChildT, Index Log2Dim>
2644 inline void
2646 {
2647  for (Index i = 0; i < NUM_VALUES; ++i) {
2648  if (this->isChildMaskOn(i)) {
2649  mNodes[i].getChild()->negate();
2650  } else {
2651  mNodes[i].setValue(math::negative(mNodes[i].getValue()));
2652  }
2653  }
2654 
2655 }
2656 
2657 
2658 ////////////////////////////////////////
2659 
2660 
2661 template<typename ChildT, Index Log2Dim>
2663 {
2664  VoxelizeActiveTiles(InternalNode &node) : mNode(&node) {
2665  //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//single thread for debugging
2666  tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
2667 
2668  node.mChildMask |= node.mValueMask;
2669  node.mValueMask.setOff();
2670  }
2671  void operator()(const tbb::blocked_range<Index> &r) const
2672  {
2673  for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
2674  if (mNode->mChildMask.isOn(i)) {// Loop over node's child nodes
2675  mNode->mNodes[i].getChild()->voxelizeActiveTiles(true);
2676  } else if (mNode->mValueMask.isOn(i)) {// Loop over node's active tiles
2677  const Coord &ijk = mNode->offsetToGlobalCoord(i);
2678  ChildNodeType *child = new ChildNodeType(ijk, mNode->mNodes[i].getValue(), true);
2679  child->voxelizeActiveTiles(true);
2680  mNode->mNodes[i].setChild(child);
2681  }
2682  }
2683  }
2685 };// VoxelizeActiveTiles
2686 
2687 template<typename ChildT, Index Log2Dim>
2688 inline void
2690 {
2691  if (threaded) {
2692  VoxelizeActiveTiles tmp(*this);
2693  } else {
2694  for (ValueOnIter iter = this->beginValueOn(); iter; ++iter) {
2695  this->setChildNode(iter.pos(),
2696  new ChildNodeType(iter.getCoord(), iter.getValue(), true));
2697  }
2698  for (ChildOnIter iter = this->beginChildOn(); iter; ++iter)
2699  iter->voxelizeActiveTiles(false);
2700  }
2701 }
2702 
2703 
2704 ////////////////////////////////////////
2705 
2706 
2707 template<typename ChildT, Index Log2Dim>
2708 template<MergePolicy Policy>
2709 inline void
2711  const ValueType& background, const ValueType& otherBackground)
2712 {
2714 
2715  switch (Policy) {
2716 
2717  case MERGE_ACTIVE_STATES:
2718  default:
2719  {
2720  for (ChildOnIter iter = other.beginChildOn(); iter; ++iter) {
2721  const Index n = iter.pos();
2722  if (mChildMask.isOn(n)) {
2723  // Merge this node's child with the other node's child.
2724  mNodes[n].getChild()->template merge<MERGE_ACTIVE_STATES>(*iter,
2725  background, otherBackground);
2726  } else if (mValueMask.isOff(n)) {
2727  // Replace this node's inactive tile with the other node's child
2728  // and replace the other node's child with a tile of undefined value
2729  // (which is okay since the other tree is assumed to be cannibalized
2730  // in the process of merging).
2731  ChildNodeType* child = other.mNodes[n].getChild();
2732  other.mChildMask.setOff(n);
2733  child->resetBackground(otherBackground, background);
2734  this->setChildNode(n, child);
2735  }
2736  }
2737 
2738  // Copy active tile values.
2739  for (ValueOnCIter iter = other.cbeginValueOn(); iter; ++iter) {
2740  const Index n = iter.pos();
2741  if (mValueMask.isOff(n)) {
2742  // Replace this node's child or inactive tile with the other node's active tile.
2743  this->makeChildNodeEmpty(n, iter.getValue());
2744  mValueMask.setOn(n);
2745  }
2746  }
2747  break;
2748  }
2749 
2750  case MERGE_NODES:
2751  {
2752  for (ChildOnIter iter = other.beginChildOn(); iter; ++iter) {
2753  const Index n = iter.pos();
2754  if (mChildMask.isOn(n)) {
2755  // Merge this node's child with the other node's child.
2756  mNodes[n].getChild()->template merge<Policy>(*iter, background, otherBackground);
2757  } else {
2758  // Replace this node's tile (regardless of its active state) with
2759  // the other node's child and replace the other node's child with
2760  // a tile of undefined value (which is okay since the other tree
2761  // is assumed to be cannibalized in the process of merging).
2762  ChildNodeType* child = other.mNodes[n].getChild();
2763  other.mChildMask.setOff(n);
2764  child->resetBackground(otherBackground, background);
2765  this->setChildNode(n, child);
2766  }
2767  }
2768  break;
2769  }
2770 
2772  {
2773  // Transfer children from the other tree to this tree.
2774  for (ChildOnIter iter = other.beginChildOn(); iter; ++iter) {
2775  const Index n = iter.pos();
2776  if (mChildMask.isOn(n)) {
2777  // Merge this node's child with the other node's child.
2778  mNodes[n].getChild()->template merge<Policy>(*iter, background, otherBackground);
2779  } else {
2780  // Replace this node's tile with the other node's child, leaving the other
2781  // node with an inactive tile of undefined value (which is okay since
2782  // the other tree is assumed to be cannibalized in the process of merging).
2783  ChildNodeType* child = other.mNodes[n].getChild();
2784  other.mChildMask.setOff(n);
2785  child->resetBackground(otherBackground, background);
2786  if (mValueMask.isOn(n)) {
2787  // Merge the child with this node's active tile.
2788  child->template merge<Policy>(mNodes[n].getValue(), /*on=*/true);
2789  mValueMask.setOff(n);
2790  }
2791  mChildMask.setOn(n);
2792  mNodes[n].setChild(child);
2793  }
2794  }
2795 
2796  // Merge active tiles into this tree.
2797  for (ValueOnCIter iter = other.cbeginValueOn(); iter; ++iter) {
2798  const Index n = iter.pos();
2799  if (mChildMask.isOn(n)) {
2800  // Merge the other node's active tile into this node's child.
2801  mNodes[n].getChild()->template merge<Policy>(iter.getValue(), /*on=*/true);
2802  } else if (mValueMask.isOff(n)) {
2803  // Replace this node's inactive tile with the other node's active tile.
2804  mNodes[n].setValue(iter.getValue());
2805  mValueMask.setOn(n);
2806  }
2807  }
2808  break;
2809  }
2810 
2811  }
2813 }
2814 
2815 
2816 template<typename ChildT, Index Log2Dim>
2817 template<MergePolicy Policy>
2818 inline void
2819 InternalNode<ChildT, Log2Dim>::merge(const ValueType& tileValue, bool tileActive)
2820 {
2822 
2823  if (Policy != MERGE_ACTIVE_STATES_AND_NODES) return;
2824 
2825  // For MERGE_ACTIVE_STATES_AND_NODES, inactive tiles in the other tree are ignored.
2826  if (!tileActive) return;
2827 
2828  // Iterate over this node's children and inactive tiles.
2829  for (ValueOffIter iter = this->beginValueOff(); iter; ++iter) {
2830  const Index n = iter.pos();
2831  if (mChildMask.isOn(n)) {
2832  // Merge the other node's active tile into this node's child.
2833  mNodes[n].getChild()->template merge<Policy>(tileValue, /*on=*/true);
2834  } else {
2835  // Replace this node's inactive tile with the other node's active tile.
2836  iter.setValue(tileValue);
2837  mValueMask.setOn(n);
2838  }
2839  }
2841 }
2842 
2843 
2844 ////////////////////////////////////////
2845 
2846 
2847 template<typename ChildT, Index Log2Dim>
2848 template<typename OtherInternalNode>
2850 {
2851  using W = typename NodeMaskType::Word;
2852  struct A { inline void operator()(W &tV, const W& sV, const W& tC) const
2853  { tV = (tV | sV) & ~tC; }
2854  };
2855  TopologyUnion(const OtherInternalNode* source, InternalNode* target, const bool preserveTiles)
2856  : s(source), t(target), mPreserveTiles(preserveTiles) {
2857  //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//single thread for debugging
2858  tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
2859 
2860  // Bit processing is done in a single thread!
2861  if (!mPreserveTiles) t->mChildMask |= s->mChildMask;//serial but very fast bitwise post-process
2862  else t->mChildMask |= (s->mChildMask & !t->mValueMask);
2863 
2864  A op;
2865  t->mValueMask.foreach(s->mValueMask, t->mChildMask, op);
2866  OPENVDB_ASSERT((t->mValueMask & t->mChildMask).isOff());//no overlapping active tiles or child nodes
2867  }
2868  void operator()(const tbb::blocked_range<Index> &r) const {
2869  for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
2870  if (s->mChildMask.isOn(i)) {// Loop over other node's child nodes
2871  const typename OtherInternalNode::ChildNodeType& other = *(s->mNodes[i].getChild());
2872  if (t->mChildMask.isOn(i)) {//this has a child node
2873  t->mNodes[i].getChild()->topologyUnion(other, mPreserveTiles);
2874  } else {// this is a tile so replace it with a child branch with identical topology
2875  if (!mPreserveTiles || t->mValueMask.isOff(i)) { // force child topology
2876  ChildT* child = new ChildT(other, t->mNodes[i].getValue(), TopologyCopy());
2877  if (t->mValueMask.isOn(i)) child->setValuesOn();//activate all values
2878  t->mNodes[i].setChild(child);
2879  }
2880  }
2881  } else if (s->mValueMask.isOn(i) && t->mChildMask.isOn(i)) {
2882  t->mNodes[i].getChild()->setValuesOn();
2883  }
2884  }
2885  }
2886  const OtherInternalNode* s;
2888  const bool mPreserveTiles;
2889 };// TopologyUnion
2890 
2891 template<typename ChildT, Index Log2Dim>
2892 template<typename OtherChildT>
2893 inline void
2895 {
2896  TopologyUnion<InternalNode<OtherChildT, Log2Dim> > tmp(&other, this, preserveTiles);
2897 }
2898 
2899 template<typename ChildT, Index Log2Dim>
2900 template<typename OtherInternalNode>
2901 struct InternalNode<ChildT, Log2Dim>::TopologyIntersection
2902 {
2903  using W = typename NodeMaskType::Word;
2904  struct A { inline void operator()(W &tC, const W& sC, const W& sV, const W& tV) const
2905  { tC = (tC & (sC | sV)) | (tV & sC); }
2906  };
2907  TopologyIntersection(const OtherInternalNode* source, InternalNode* target,
2908  const ValueType& background) : s(source), t(target), b(background) {
2909  //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//single thread for debugging
2910  tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
2911 
2912  // Bit processing is done in a single thread!
2913  A op;
2914  t->mChildMask.foreach(s->mChildMask, s->mValueMask, t->mValueMask, op);
2915 
2916  t->mValueMask &= s->mValueMask;
2917  OPENVDB_ASSERT((t->mValueMask & t->mChildMask).isOff());//no overlapping active tiles or child nodes
2918  }
2919  void operator()(const tbb::blocked_range<Index> &r) const {
2920  for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
2921  if (t->mChildMask.isOn(i)) {// Loop over this node's child nodes
2922  ChildT* child = t->mNodes[i].getChild();
2923  if (s->mChildMask.isOn(i)) {//other also has a child node
2924  child->topologyIntersection(*(s->mNodes[i].getChild()), b);
2925  } else if (s->mValueMask.isOff(i)) {//other is an inactive tile
2926  delete child;//convert child to an inactive tile
2927  t->mNodes[i].setValue(b);
2928  }
2929  } else if (t->mValueMask.isOn(i) && s->mChildMask.isOn(i)) {//active tile -> a branch
2930  t->mNodes[i].setChild(new ChildT(*(s->mNodes[i].getChild()),
2931  t->mNodes[i].getValue(), TopologyCopy()));
2932  }
2933  }
2934  }
2935  const OtherInternalNode* s;
2937  const ValueType& b;
2938 };// TopologyIntersection
2939 
2940 template<typename ChildT, Index Log2Dim>
2941 template<typename OtherChildT>
2942 inline void
2944  const InternalNode<OtherChildT, Log2Dim>& other, const ValueType& background)
2945 {
2946  TopologyIntersection<InternalNode<OtherChildT, Log2Dim> > tmp(&other, this, background);
2947 }
2948 
2949 template<typename ChildT, Index Log2Dim>
2950 template<typename OtherInternalNode>
2951 struct InternalNode<ChildT, Log2Dim>::TopologyDifference
2952 {
2953  using W = typename NodeMaskType::Word;
2954  struct A {inline void operator()(W &tC, const W& sC, const W& sV, const W& tV) const
2955  { tC = (tC & (sC | ~sV)) | (tV & sC); }
2956  };
2957  struct B {inline void operator()(W &tV, const W& sC, const W& sV, const W& tC) const
2958  { tV &= ~((tC & sV) | (sC | sV)); }
2959  };
2960  TopologyDifference(const OtherInternalNode* source, InternalNode* target,
2961  const ValueType& background) : s(source), t(target), b(background) {
2962  //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//single thread for debugging
2963  tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
2964 
2965  // Bit processing is done in a single thread!
2966  const NodeMaskType oldChildMask(t->mChildMask);//important to avoid cross pollution
2967  A op1;
2968  t->mChildMask.foreach(s->mChildMask, s->mValueMask, t->mValueMask, op1);
2969 
2970  B op2;
2971  t->mValueMask.foreach(t->mChildMask, s->mValueMask, oldChildMask, op2);
2972  OPENVDB_ASSERT((t->mValueMask & t->mChildMask).isOff());//no overlapping active tiles or child nodes
2973  }
2974  void operator()(const tbb::blocked_range<Index> &r) const {
2975  for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
2976  if (t->mChildMask.isOn(i)) {// Loop over this node's child nodes
2977  ChildT* child = t->mNodes[i].getChild();
2978  if (s->mChildMask.isOn(i)) {
2979  child->topologyDifference(*(s->mNodes[i].getChild()), b);
2980  } else if (s->mValueMask.isOn(i)) {
2981  delete child;//convert child to an inactive tile
2982  t->mNodes[i].setValue(b);
2983  }
2984  } else if (t->mValueMask.isOn(i)) {//this is an active tile
2985  if (s->mChildMask.isOn(i)) {
2986  const typename OtherInternalNode::ChildNodeType& other =
2987  *(s->mNodes[i].getChild());
2988  ChildT* child = new ChildT(other.origin(), t->mNodes[i].getValue(), true);
2989  child->topologyDifference(other, b);
2990  t->mNodes[i].setChild(child);//replace the active tile with a child branch
2991  }
2992  }
2993  }
2994  }
2995  const OtherInternalNode* s;
2997  const ValueType& b;
2998 };// TopologyDifference
2999 
3000 template<typename ChildT, Index Log2Dim>
3001 template<typename OtherChildT>
3002 inline void
3004  const ValueType& background)
3005 {
3006  TopologyDifference<InternalNode<OtherChildT, Log2Dim> > tmp(&other, this, background);
3007 }
3008 
3009 
3010 ////////////////////////////////////////
3011 
3012 
3013 template<typename ChildT, Index Log2Dim>
3014 template<typename CombineOp>
3015 inline void
3017 {
3018  const ValueType zero = zeroVal<ValueType>();
3019 
3021 
3022  for (Index i = 0; i < NUM_VALUES; ++i) {
3023  if (this->isChildMaskOff(i) && other.isChildMaskOff(i)) {
3024  // Both this node and the other node have constant values (tiles).
3025  // Combine the two values and store the result as this node's new tile value.
3026  op(args.setARef(mNodes[i].getValue())
3027  .setAIsActive(isValueMaskOn(i))
3028  .setBRef(other.mNodes[i].getValue())
3029  .setBIsActive(other.isValueMaskOn(i)));
3030  mNodes[i].setValue(args.result());
3031  mValueMask.set(i, args.resultIsActive());
3032  } else if (this->isChildMaskOn(i) && other.isChildMaskOff(i)) {
3033  // Combine this node's child with the other node's constant value.
3034  ChildNodeType* child = mNodes[i].getChild();
3035  OPENVDB_ASSERT(child);
3036  if (child) {
3037  child->combine(other.mNodes[i].getValue(), other.isValueMaskOn(i), op);
3038  }
3039  } else if (this->isChildMaskOff(i) && other.isChildMaskOn(i)) {
3040  // Combine this node's constant value with the other node's child.
3041  ChildNodeType* child = other.mNodes[i].getChild();
3042  OPENVDB_ASSERT(child);
3043  if (child) {
3044  // Combine this node's constant value with the other node's child,
3045  // but use a new functor in which the A and B values are swapped,
3046  // since the constant value is the A value, not the B value.
3048  child->combine(mNodes[i].getValue(), isValueMaskOn(i), swappedOp);
3049 
3050  // Steal the other node's child.
3051  other.mChildMask.setOff(i);
3052  other.mNodes[i].setValue(zero);
3053  this->setChildNode(i, child);
3054  }
3055 
3056  } else /*if (isChildMaskOn(i) && other.isChildMaskOn(i))*/ {
3057  // Combine this node's child with the other node's child.
3059  *child = mNodes[i].getChild(),
3060  *otherChild = other.mNodes[i].getChild();
3061  OPENVDB_ASSERT(child);
3062  OPENVDB_ASSERT(otherChild);
3063  if (child && otherChild) {
3064  child->combine(*otherChild, op);
3065  }
3066  }
3067  }
3068 }
3069 
3070 
3071 template<typename ChildT, Index Log2Dim>
3072 template<typename CombineOp>
3073 inline void
3074 InternalNode<ChildT, Log2Dim>::combine(const ValueType& value, bool valueIsActive, CombineOp& op)
3075 {
3077 
3078  for (Index i = 0; i < NUM_VALUES; ++i) {
3079  if (this->isChildMaskOff(i)) {
3080  // Combine this node's constant value with the given constant value.
3081  op(args.setARef(mNodes[i].getValue())
3082  .setAIsActive(isValueMaskOn(i))
3083  .setBRef(value)
3084  .setBIsActive(valueIsActive));
3085  mNodes[i].setValue(args.result());
3086  mValueMask.set(i, args.resultIsActive());
3087  } else /*if (isChildMaskOn(i))*/ {
3088  // Combine this node's child with the given constant value.
3089  ChildNodeType* child = mNodes[i].getChild();
3090  OPENVDB_ASSERT(child);
3091  if (child) child->combine(value, valueIsActive, op);
3092  }
3093  }
3094 }
3095 
3096 
3097 ////////////////////////////////////////
3098 
3099 
3100 template<typename ChildT, Index Log2Dim>
3101 template<typename CombineOp, typename OtherNodeType>
3102 inline void
3103 InternalNode<ChildT, Log2Dim>::combine2(const InternalNode& other0, const OtherNodeType& other1,
3104  CombineOp& op)
3105 {
3107 
3108  for (Index i = 0; i < NUM_VALUES; ++i) {
3109  if (other0.isChildMaskOff(i) && other1.isChildMaskOff(i)) {
3110  op(args.setARef(other0.mNodes[i].getValue())
3111  .setAIsActive(other0.isValueMaskOn(i))
3112  .setBRef(other1.mNodes[i].getValue())
3113  .setBIsActive(other1.isValueMaskOn(i)));
3114  // Replace child i with a constant value.
3115  this->makeChildNodeEmpty(i, args.result());
3116  mValueMask.set(i, args.resultIsActive());
3117  } else {
3118  if (this->isChildMaskOff(i)) {
3119  // Add a new child with the same coordinates, etc. as the other node's child.
3120  const Coord& childOrigin = other0.isChildMaskOn(i)
3121  ? other0.mNodes[i].getChild()->origin()
3122  : other1.mNodes[i].getChild()->origin();
3123  this->setChildNode(i, new ChildNodeType(childOrigin, mNodes[i].getValue()));
3124  }
3125 
3126  if (other0.isChildMaskOff(i)) {
3127  // Combine node1's child with node0's constant value
3128  // and write the result into child i.
3129  mNodes[i].getChild()->combine2(other0.mNodes[i].getValue(),
3130  *other1.mNodes[i].getChild(), other0.isValueMaskOn(i), op);
3131  } else if (other1.isChildMaskOff(i)) {
3132  // Combine node0's child with node1's constant value
3133  // and write the result into child i.
3134  mNodes[i].getChild()->combine2(*other0.mNodes[i].getChild(),
3135  other1.mNodes[i].getValue(), other1.isValueMaskOn(i), op);
3136  } else {
3137  // Combine node0's child with node1's child
3138  // and write the result into child i.
3139  mNodes[i].getChild()->combine2(*other0.mNodes[i].getChild(),
3140  *other1.mNodes[i].getChild(), op);
3141  }
3142  }
3143  }
3144 }
3145 
3146 
3147 template<typename ChildT, Index Log2Dim>
3148 template<typename CombineOp, typename OtherNodeType>
3149 inline void
3150 InternalNode<ChildT, Log2Dim>::combine2(const ValueType& value, const OtherNodeType& other,
3151  bool valueIsActive, CombineOp& op)
3152 {
3154 
3155  for (Index i = 0; i < NUM_VALUES; ++i) {
3156  if (other.isChildMaskOff(i)) {
3157  op(args.setARef(value)
3158  .setAIsActive(valueIsActive)
3159  .setBRef(other.mNodes[i].getValue())
3160  .setBIsActive(other.isValueMaskOn(i)));
3161  // Replace child i with a constant value.
3162  this->makeChildNodeEmpty(i, args.result());
3163  mValueMask.set(i, args.resultIsActive());
3164  } else {
3165  typename OtherNodeType::ChildNodeType* otherChild = other.mNodes[i].getChild();
3166  OPENVDB_ASSERT(otherChild);
3167  if (this->isChildMaskOff(i)) {
3168  // Add a new child with the same coordinates, etc.
3169  // as the other node's child.
3170  this->setChildNode(i, new ChildNodeType(*otherChild));
3171  }
3172  // Combine the other node's child with a constant value
3173  // and write the result into child i.
3174  mNodes[i].getChild()->combine2(value, *otherChild, valueIsActive, op);
3175  }
3176  }
3177 }
3178 
3179 
3180 template<typename ChildT, Index Log2Dim>
3181 template<typename CombineOp, typename OtherValueType>
3182 inline void
3183 InternalNode<ChildT, Log2Dim>::combine2(const InternalNode& other, const OtherValueType& value,
3184  bool valueIsActive, CombineOp& op)
3185 {
3187 
3188  for (Index i = 0; i < NUM_VALUES; ++i) {
3189  if (other.isChildMaskOff(i)) {
3190  op(args.setARef(other.mNodes[i].getValue())
3191  .setAIsActive(other.isValueMaskOn(i))
3192  .setBRef(value)
3193  .setBIsActive(valueIsActive));
3194  // Replace child i with a constant value.
3195  this->makeChildNodeEmpty(i, args.result());
3196  mValueMask.set(i, args.resultIsActive());
3197  } else {
3198  ChildNodeType* otherChild = other.mNodes[i].getChild();
3199  OPENVDB_ASSERT(otherChild);
3200  if (this->isChildMaskOff(i)) {
3201  // Add a new child with the same coordinates, etc. as the other node's child.
3202  this->setChildNode(i,
3203  new ChildNodeType(otherChild->origin(), mNodes[i].getValue()));
3204  }
3205  // Combine the other node's child with a constant value
3206  // and write the result into child i.
3207  mNodes[i].getChild()->combine2(*otherChild, value, valueIsActive, op);
3208  }
3209  }
3210 }
3211 
3212 
3213 ////////////////////////////////////////
3214 
3215 
3216 template<typename ChildT, Index Log2Dim>
3217 inline void
3218 InternalNode<ChildT, Log2Dim>::writeBuffers(std::ostream& os, bool toHalf) const
3219 {
3220  for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
3221  iter->writeBuffers(os, toHalf);
3222  }
3223 }
3224 
3225 
3226 template<typename ChildT, Index Log2Dim>
3227 inline void
3228 InternalNode<ChildT, Log2Dim>::readBuffers(std::istream& is, bool fromHalf)
3229 {
3230  for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
3231  iter->readBuffers(is, fromHalf);
3232  }
3233 }
3234 
3235 
3236 template<typename ChildT, Index Log2Dim>
3237 inline void
3239  const CoordBBox& clipBBox, bool fromHalf)
3240 {
3241  for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
3242  // Stream in the branch rooted at this child.
3243  // (We can't skip over children that lie outside the clipping region,
3244  // because buffers are serialized in depth-first order and need to be
3245  // unserialized in the same order.)
3246  iter->readBuffers(is, clipBBox, fromHalf);
3247  }
3248 
3249  // Get this tree's background value.
3250  ValueType background = zeroVal<ValueType>();
3251  if (const void* bgPtr = io::getGridBackgroundValuePtr(is)) {
3252  background = *static_cast<const ValueType*>(bgPtr);
3253  }
3254  this->clip(clipBBox, background);
3255 }
3256 
3257 
3258 ////////////////////////////////////////
3259 
3260 
3261 template<typename ChildT, Index Log2Dim>
3262 void
3264 {
3265  dims.push_back(Log2Dim);
3266  ChildNodeType::getNodeLog2Dims(dims);
3267 }
3268 
3269 
3270 template<typename ChildT, Index Log2Dim>
3271 inline void
3273 {
3274  OPENVDB_ASSERT(n<(1<<3*Log2Dim));
3275  xyz.setX(n >> 2*Log2Dim);
3276  n &= ((1<<2*Log2Dim)-1);
3277  xyz.setY(n >> Log2Dim);
3278  xyz.setZ(n & ((1<<Log2Dim)-1));
3279 }
3280 
3281 
3282 template<typename ChildT, Index Log2Dim>
3283 inline Index
3285 {
3286  return (((xyz[0] & (DIM-1u)) >> ChildNodeType::TOTAL) << 2*Log2Dim)
3287  + (((xyz[1] & (DIM-1u)) >> ChildNodeType::TOTAL) << Log2Dim)
3288  + ((xyz[2] & (DIM-1u)) >> ChildNodeType::TOTAL);
3289 }
3290 
3291 
3292 template<typename ChildT, Index Log2Dim>
3293 inline Coord
3295 {
3296  Coord local;
3297  this->offsetToLocalCoord(n, local);
3298  local <<= ChildT::TOTAL;
3299  return local + this->origin();
3300 }
3301 
3302 
3303 ////////////////////////////////////////
3304 
3305 
3306 template<typename ChildT, Index Log2Dim>
3307 template<typename ArrayT>
3308 inline void
3310 {
3311  using T = typename ArrayT::value_type;
3312  static_assert(std::is_pointer<T>::value, "argument to getNodes() must be a pointer array");
3313  using ArrayChildT = typename std::conditional<
3315  for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
3318  array.push_back(reinterpret_cast<T>(mNodes[iter.pos()].getChild()));
3319  } else {
3320  iter->getNodes(array);//descent
3321  }
3323  }
3324 }
3325 
3326 template<typename ChildT, Index Log2Dim>
3327 template<typename ArrayT>
3328 inline void
3330 {
3331  using T = typename ArrayT::value_type;
3332  static_assert(std::is_pointer<T>::value, "argument to getNodes() must be a pointer array");
3333  static_assert(std::is_const<typename std::remove_pointer<T>::type>::value,
3334  "argument to getNodes() must be an array of const node pointers");
3335  for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
3338  array.push_back(reinterpret_cast<T>(mNodes[iter.pos()].getChild()));
3339  } else {
3340  iter->getNodes(array);//descent
3341  }
3343  }
3344 }
3345 
3346 
3347 ////////////////////////////////////////
3348 
3349 
3350 template<typename ChildT, Index Log2Dim>
3351 template<typename ArrayT>
3352 inline void
3354 {
3355  using T = typename ArrayT::value_type;
3356  static_assert(std::is_pointer<T>::value, "argument to stealNodes() must be a pointer array");
3357  using ArrayChildT = typename std::conditional<
3360  for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
3361  const Index n = iter.pos();
3363  array.push_back(reinterpret_cast<T>(mNodes[n].getChild()));
3364  mValueMask.set(n, state);
3365  mNodes[n].setValue(value);
3366  } else {
3367  iter->stealNodes(array, value, state);//descent
3368  }
3369  }
3370  if (std::is_same<T, ArrayChildT*>::value) mChildMask.setOff();
3372 }
3373 
3374 
3375 ////////////////////////////////////////
3376 
3377 
3378 template<typename ChildT, Index Log2Dim>
3379 inline void
3381  const ValueType& newBackground)
3382 {
3383  if (math::isExactlyEqual(oldBackground, newBackground)) return;
3384  for (Index i = 0; i < NUM_VALUES; ++i) {
3385  if (this->isChildMaskOn(i)) {
3386  mNodes[i].getChild()->resetBackground(oldBackground, newBackground);
3387  } else if (this->isValueMaskOff(i)) {
3388  if (math::isApproxEqual(mNodes[i].getValue(), oldBackground)) {
3389  mNodes[i].setValue(newBackground);
3390  } else if (math::isApproxEqual(mNodes[i].getValue(), math::negative(oldBackground))) {
3391  mNodes[i].setValue(math::negative(newBackground));
3392  }
3393  }
3394  }
3395 }
3396 
3397 template<typename ChildT, Index Log2Dim>
3398 template<typename OtherChildNodeType, Index OtherLog2Dim>
3399 inline bool
3402 {
3403  if (Log2Dim != OtherLog2Dim || mChildMask != other->mChildMask ||
3404  mValueMask != other->mValueMask) return false;
3405  for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
3406  if (!iter->hasSameTopology(other->mNodes[iter.pos()].getChild())) return false;
3407  }
3408  return true;
3409 }
3410 
3411 
3412 template<typename ChildT, Index Log2Dim>
3413 inline void
3415 {
3416  OPENVDB_ASSERT(child);
3417  if (this->isChildMaskOn(i)) {
3418  delete mNodes[i].getChild();
3419  } else {
3420  mChildMask.setOn(i);
3421  mValueMask.setOff(i);
3422  }
3423  mNodes[i].setChild(child);
3424 }
3425 
3426 template<typename ChildT, Index Log2Dim>
3427 inline void
3429 {
3430  OPENVDB_ASSERT(child);
3431  OPENVDB_ASSERT(mChildMask.isOff(i));
3432  mChildMask.setOn(i);
3433  mValueMask.setOff(i);
3434  mNodes[i].setChild(child);
3435 }
3436 
3437 
3438 template<typename ChildT, Index Log2Dim>
3439 inline ChildT*
3441 {
3442  if (this->isChildMaskOff(i)) {
3443  mNodes[i].setValue(value);
3444  return nullptr;
3445  }
3446  ChildNodeType* child = mNodes[i].getChild();
3447  mChildMask.setOff(i);
3448  mNodes[i].setValue(value);
3449  return child;
3450 }
3451 
3452 
3453 template<typename ChildT, Index Log2Dim>
3454 inline void
3456 {
3457  delete this->unsetChildNode(n, value);
3458 }
3459 
3460 template<typename ChildT, Index Log2Dim>
3461 inline ChildT*
3463 {
3464  OPENVDB_ASSERT(this->isChildMaskOn(n));
3465  return mNodes[n].getChild();
3466 }
3467 
3468 
3469 template<typename ChildT, Index Log2Dim>
3470 inline const ChildT*
3472 {
3473  OPENVDB_ASSERT(this->isChildMaskOn(n));
3474  return mNodes[n].getChild();
3475 }
3476 
3477 } // namespace tree
3478 } // namespace OPENVDB_VERSION_NAME
3479 } // namespace openvdb
3480 
3481 #endif // OPENVDB_TREE_INTERNALNODE_HAS_BEEN_INCLUDED
bool probeValue(const Coord &xyz, ValueType &value) const
const AValueType & result() const
Get the output value.
Definition: Types.h:680
Vec2< T > minComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise minimum of the two vectors.
Definition: Vec2.h:504
type
Definition: core.h:556
void negate()
Change the sign of all the values represented in this node and its child nodes.
bool probeValueAndCache(const Coord &xyz, ValueType &value, AccessorT &) const
void combine(InternalNode &other, CombineOp &)
void setOrigin(const Coord &origin)
Set the grid index coordinates of this node's local origin.
Definition: InternalNode.h:270
ValueIter< InternalNode, const ValueType, MaskOffIterator, ValueAll > ValueAllIter
Definition: InternalNode.h:218
void operator()(const tbb::blocked_range< Index > &r) const
void stealNodes(ArrayT &array, const ValueType &value, bool state)
Steals all nodes of a certain type from the tree and adds them to a container with the following API:...
void setItem(Index pos, const ValueT &v) const
Definition: InternalNode.h:159
const Coord & origin() const
Return the grid index coordinates of this node's local origin.
Definition: InternalNode.h:268
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:635
OPENVDB_API const void * getGridBackgroundValuePtr(std::ios_base &)
Return a pointer to the background value of the grid currently being read from or written to the give...
NodeType * probeNodeAndCache(const Coord &xyz, AccessorT &)
Same as probeNode() except, if necessary, update the accessor with pointers to the nodes along the pa...
void getNodes(ArrayT &array)
Adds all nodes of a certain type to a container with the following API:
ChildIter< InternalNode, ChildNodeType, MaskOnIterator, ChildOn > ChildOnIter
Definition: InternalNode.h:207
Signed (i, j, k) 32-bit integer coordinate class, similar to openvdb::math::Coord.
Definition: NanoVDB.h:1282
TopologyDifference(const OtherInternalNode *source, InternalNode *target, const ValueType &background)
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:468
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don't change its value.
void
Definition: png.h:1083
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:139
const GLdouble * v
Definition: glcorearb.h:837
const ChildNodeType * probeChild(const Coord &xyz, ValueType &value, bool &active) const
Return a pointer to the child node that contains voxel (x, y, z). If no such node exists...
Definition: InternalNode.h:723
const ChildNodeType * probeChild(const Coord &xyz) const
Return a pointer to the child node that contains voxel (x, y, z). If no such node exists...
Definition: InternalNode.h:715
void clip(const CoordBBox &, const ValueType &background)
Set all voxels that lie outside the given axis-aligned box to the background.
bool anyActiveTiles(const TreeT &tree, const CoordBBox &bbox)
Returns true if the bounding box intersects any of the active tiles in a tree, i.e. ignores active leaf values.
ValueIter< InternalNode, const ValueType, MaskOffIterator, ValueOff > ValueOffIter
Definition: InternalNode.h:216
GLsizei const GLfloat * value
Definition: glcorearb.h:824
const NodeMaskType & getChildMask() const
Definition: InternalNode.h:874
void addTileAndCache(Index level, const Coord &xyz, const ValueType &, bool state, AccessorT &)
Same as addTile() except, if necessary, update the accessor with pointers to the nodes along the path...
void setOff(Index32 n)
Set the nth bit off.
Definition: NodeMasks.h:457
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:848
Index pos() const
Identical to offset.
Definition: Iterator.h:60
void nodeCount(std::vector< Index64 > &vec) const
GLint level
Definition: glcorearb.h:108
const ChildNodeType * probeConstChild(const Coord &xyz) const
Return a pointer to the child node that contains voxel (x, y, z). If no such node exists...
const NodeType * probeConstNode(const Coord &xyz) const
Return a pointer to the node that contains voxel (x, y, z). If no such node exists, return nullptr.
TopologyUnion(const OtherInternalNode *source, InternalNode *target, const bool preserveTiles)
void setChildNode(Index i, ChildNodeType *child)
void setValueOffUnsafe(Index offset)
Mark the tile inactive at offset but don't change its value.
#define OPENVDB_DEPRECATED_MESSAGE(msg)
Definition: Platform.h:171
GLdouble s
Definition: glad.h:3009
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:246
bool isValueOn(Index offset) const
Return true if the voxel at the given offset is active.
Definition: InternalNode.h:336
typename NodeMaskType::OnIterator MaskOnIterator
Definition: InternalNode.h:115
void toggle(Index32 n)
Toggle the state of the nth bit.
Definition: NodeMasks.h:483
Base class for iterators over internal and leaf nodes.
Definition: Iterator.h:29
const ChildNodeType * getConstChildUnsafe(Index offset) const
Return the child node at offset.
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...
NodeT * stealNode(const Coord &xyz, const ValueType &value, bool state)
Return a pointer to the node of type NodeT that contains voxel (x, y, z) and replace it with a tile o...
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
ValueConverter<T>::Type is the type of an InternalNode having the same child hierarchy and dimensions...
Definition: InternalNode.h:56
**But if you need a or simply need to know when the task has note that the like this
Definition: thread.h:626
void writeTopology(std::ostream &, bool toHalf=false) const
GLint y
Definition: glcorearb.h:103
bool hasActiveTiles() const
Return true if this node or any of its child nodes have any active tiles.
void operator()(W &tV, const W &sC, const W &sV, const W &tC) const
typename ChildNodeType::LeafNodeType LeafNodeType
Definition: InternalNode.h:38
const ChildNodeType * probeConstChildUnsafe(Index offset) const
Return a pointer to the child node for a specific offset. If no such node exists, return nullptr...
void addTile(Index level, const Coord &xyz, const ValueType &value, bool state)
Add a tile at the specified tree level that contains voxel (x, y, z), possibly creating a parent bran...
bool isValueOff(Index offset) const
Return true if the voxel at the given offset is inactive.
Definition: InternalNode.h:340
NodeT & parent() const
Return a reference to the node over which this iterator is iterating.
Definition: Iterator.h:50
static Index coordToOffset(const Coord &xyz)
Return the linear table offset of the given global or local coordinates.
typename ChildNodeType::BuildType BuildType
Definition: InternalNode.h:40
bool isConstant(ValueType &firstValue, bool &state, const ValueType &tolerance=zeroVal< ValueType >()) const
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.
bool getItem(Index pos, ChildT *&child, NonConstValueT &value) const
Definition: InternalNode.h:181
DenseIter(const MaskDenseIterator &iter, NodeT *parent)
Definition: InternalNode.h:178
void setValueOnlyAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
void operator()(const tbb::blocked_range< Index > &r) const
uint64 value_type
Definition: GA_PrimCompat.h:29
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:756
typename NodeMaskType::DenseIterator MaskDenseIterator
Definition: InternalNode.h:117
LeafNodeType * probeLeafAndCache(const Coord &xyz, AccessorT &acc)
Same as probeLeaf() except, if necessary, update the accessor with pointers to the nodes along the pa...
const ValueType & getFirstValue() const
If the first entry in this node's table is a tile, return the tile's value. Otherwise, return the result of calling getFirstValue() on the child.
FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, const fill_t< Char > &fill) -> OutputIt
Definition: format.h:1860
OPENVDB_API void checkFormatVersion(std::ios_base &)
Throws an IoError if the file format version number is not supported.
const ValueType & getValueUnsafe(Index offset) const
Return the tile value at offset.
ChildNodeType * probeChildUnsafe(Index offset)
Return a pointer to the child node for a specific offset. If no such node exists, return nullptr...
void modifyValueAndActiveStateAndCache(const Coord &xyz, const ModifyOp &op, AccessorT &)
typename NodeMaskType::OffIterator MaskOffIterator
Definition: InternalNode.h:116
__hostdev__ float getValue(uint32_t i) const
Definition: NanoVDB.h:5578
ChildNodeType * getChildNode(Index n)
Returns a pointer to the child node at the linear offset n.
ChildIter< const InternalNode, const ChildNodeType, MaskOnIterator, ChildOn > ChildOnCIter
Definition: InternalNode.h:208
DeepCopy(const OtherInternalNode *source, InternalNode *target)
Definition: InternalNode.h:980
bool isInactive() const
Return true if this node has no children and only contains inactive values.
Definition: InternalNode.h:331
void operator()(const tbb::blocked_range< Index > &r) const
#define OPENVDB_ASSERT(X)
Definition: Assert.h:41
void readCompressedValues(std::istream &is, ValueT *destBuf, Index destCount, const MaskT &valueMask, bool fromHalf)
Definition: Compression.h:466
void writeCompressedValues(std::ostream &os, const ValueT *srcBuf, Index srcCount, const MaskT &valueMask, const MaskT &childMask, bool toHalf)
Definition: Compression.h:648
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
void setValuesOn()
Mark all values (both tiles and voxels) as active.
void topologyUnion(const InternalNode< OtherChildNodeType, Log2Dim > &other, const bool preserveTiles=false)
Union this branch's set of active values with the other branch's active values. The value type of the...
Index64 memUsage() const
Return the total amount of memory in bytes occupied by this node and its children.
typename ChildNodeType::ValueType ValueType
Definition: InternalNode.h:39
GLdouble n
Definition: glcorearb.h:2008
OffMaskIterator< NodeMask > OffIterator
Definition: NodeMasks.h:349
void setValueOnlyUnsafe(Index offset, const ValueType &value)
Set the tile value at offset but don't change its value.
const ChildNodeType * probeChildUnsafe(Index offset) const
Return a pointer to the child node for a specific offset. If no such node exists, return nullptr...
Definition: InternalNode.h:733
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...
Index32 mTransientData
Transient data (not serialized)
Definition: InternalNode.h:919
GLintptr offset
Definition: glcorearb.h:665
ImageBuf OIIO_API sub(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
bool isApproxEqual(const Type &a, const Type &b, const Type &tolerance)
Return true if a is equal to b to within the given tolerance.
Definition: Math.h:431
bool isValueOn(const Coord &xyz) const
Return true if the voxel at the given coordinates is active.
void setValueMaskUnsafe(const NodeMaskType &mask)
Set the active/inactive value mask.
void operator()(const tbb::blocked_range< Index > &r) const
LeafNodeType * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, return nullptr.
const LeafNodeType * probeConstLeafAndCache(const Coord &xyz, AccessorT &acc) const
Same as probeLeaf() except, if necessary, update the accessor with pointers to the nodes along the pa...
void topologyIntersection(const InternalNode< OtherChildNodeType, Log2Dim > &other, const ValueType &background)
Intersects this tree's set of active values with the active values of the other tree, whose ValueType may be different.
bool isOn(Index32 n) const
Return true if the nth bit is on.
Definition: NodeMasks.h:502
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation. ...
Definition: NodeMasks.h:307
void makeChildNodeEmpty(Index n, const ValueType &value)
BBox< Coord > CoordBBox
Definition: NanoVDB.h:2516
ChildNodeType * probeChild(const Coord &xyz)
Return a pointer to the child node that contains voxel (x, y, z). If no such node exists...
const NodeType * probeNode(const Coord &xyz) const
Return a pointer to the node that contains voxel (x, y, z). If no such node exists, return nullptr.
Definition: InternalNode.h:707
void fill(const CoordBBox &bbox, const ValueType &value, bool active=true)
Set all voxels within a given axis-aligned box to a constant value.
const NodeMaskType & getValueMask() const
Definition: InternalNode.h:873
void operator()(W &tC, const W &sC, const W &sV, const W &tV) const
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
ValueIter< const InternalNode, const ValueType, MaskOffIterator, ValueAll > ValueAllCIter
Definition: InternalNode.h:219
GLuint GLuint end
Definition: glcorearb.h:475
GLsizei GLsizei GLchar * source
Definition: glcorearb.h:803
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don't change its value.
void deleteChildUnsafe(Index offset, const ValueType &value, bool active)
Delete a child node at offset and replace with the given value and active state.
OIIO_UTIL_API void parallel_for(int32_t begin, int32_t end, function_view< void(int32_t)> task, paropt opt=0)
void setTransientData(Index32 transientData)
Set the transient data value.
Definition: InternalNode.h:275
GLint GLuint mask
Definition: glcorearb.h:124
void resetChildNode(Index i, ChildNodeType *child)
void unsetItem(Index pos, const ValueT &value) const
Definition: InternalNode.h:199
void operator()(const tbb::blocked_range< Index > &r) const
Definition: InternalNode.h:984
ChildNodeType * unsetChildNode(Index i, const ValueType &value)
void operator()(const tbb::blocked_range< Index > &r) const
LeafNodeType * touchLeaf(const Coord &xyz)
Return the leaf node that contains voxel (x, y, z). If no such node exists, create one...
Coord offsetToGlobalCoord(Index n) const
Return the global coordinates for a linear table offset.
bool hasSameTopology(const InternalNode< OtherChildNodeType, OtherLog2Dim > *other) const
Return true if the given tree branch has the same node and active value topology as this tree branch ...
void set(Index32 n, bool On)
Set the nth bit to the specified state.
Definition: NodeMasks.h:462
typename std::remove_const< UnsetItemT >::type NonConstValueType
Definition: Iterator.h:184
GLenum target
Definition: glcorearb.h:1667
void setValueAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &)
#define OPENVDB_NO_DEPRECATION_WARNING_BEGIN
Bracket code with OPENVDB_NO_DEPRECATION_WARNING_BEGIN/_END, to inhibit warnings about deprecated cod...
Definition: Platform.h:217
void setOn(Index32 n)
Set the nth bit on.
Definition: NodeMasks.h:452
Index getValueLevelAndCache(const Coord &xyz, AccessorT &) const
Return the level of the tree (0 = leaf) at which the value at the given coordinates resides...
ValueIter< const InternalNode, const ValueType, MaskOnIterator, ValueOn > ValueOnCIter
Definition: InternalNode.h:215
void writeBuffers(std::ostream &, bool toHalf=false) const
const ChildNodeType * probeChildUnsafe(Index offset, ValueType &value, bool &active) const
Return a pointer to the child node for a specific offset. If no such node exists, return nullptr...
Definition: InternalNode.h:743
void operator()(W &tC, const W &sC, const W &sV, const W &tV) const
void modifyItem(Index pos, const ModifyOp &op) const
Definition: InternalNode.h:163
bool addChild(ChildNodeType *child)
Add the given child node at this level deducing the offset from it's origin. If a child node with thi...
void setActiveStateUnsafe(Index offset, bool on)
Set the tile active state at offset but don't change its value.
static void getNodeLog2Dims(std::vector< Index > &dims)
Populated an std::vector with the dimension of all the nodes in the branch starting with this node...
void resetChildUnsafe(Index offset, ChildNodeType *child)
Replace a child node at offset with the given child node.
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
ChildNodeType * stealChildUnsafe(Index offset, const ValueType &value, bool active)
Replace a child node at offset with the given value and active state.
ValueIter< const InternalNode, const ValueType, MaskOffIterator, ChildOff > ChildOffCIter
Definition: InternalNode.h:210
GLint GLenum GLint x
Definition: glcorearb.h:409
CoordBBox getNodeBoundingBox() const
Return the bounding box of this node, i.e., the full index space spanned by the node regardless of it...
Definition: InternalNode.h:300
that also have some descendant prim *whose name begins with which in turn has a child named baz where *the predicate active
MaskT< LOG2DIM > mValueMask
Definition: NanoVDB.h:5738
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition: Platform.h:163
GLdouble t
Definition: glad.h:2397
TopologyCopy1(const OtherInternalNode *source, InternalNode *target, const ValueType &background)
DenseIter< InternalNode, ChildNodeType, ValueType, ChildAll > ChildAllIter
Definition: InternalNode.h:211
Index32 transientData() const
Return the transient data value.
Definition: InternalNode.h:273
Base class for sparse iterators over internal and leaf nodes.
Definition: Iterator.h:114
void merge(InternalNode &other, const ValueType &background, const ValueType &otherBackground)
Efficiently merge another tree into this tree using one of several schemes.
const NodeType * probeConstNodeAndCache(const Coord &xyz, AccessorT &) const
Same as probeNode() except, if necessary, update the accessor with pointers to the nodes along the pa...
ChildNodeType * getChildUnsafe(Index offset)
Return the child node at offset.
const ValueType & getLastValue() const
If the last entry in this node's table is a tile, return the tile's value. Otherwise, return the result of calling getLastValue() on the child.
Base class for dense iterators over internal and leaf nodes.
Definition: Iterator.h:178
bool isValueOff(const Coord &xyz) const
Return true if the voxel at the given coordinates is inactive.
InternalNode< typename ChildNodeType::template ValueConverter< OtherValueType >::Type, Log2Dim > Type
Definition: InternalNode.h:58
void operator()(W &tV, const W &sV, const W &tC) const
DenseMaskIterator< NodeMask > DenseIterator
Definition: NodeMasks.h:350
Library and file format version numbers.
void setValueOnUnsafe(Index offset)
Mark the tile active at offset but don't change its value.
GLenum GLsizei GLsizei GLint * values
Definition: glcorearb.h:1602
void voxelizeActiveTiles(bool threaded=true)
Densify active tiles, i.e., replace them with leaf-level active voxels.
void setActiveState(const Coord &xyz, bool on)
Set the active state of the voxel at the given coordinates but don't change its value.
ValueIter< InternalNode, const ValueType, MaskOffIterator, ChildOff > ChildOffIter
Definition: InternalNode.h:209
void readTopology(std::istream &, bool fromHalf=false)
void addLeaf(LeafNodeType *leaf)
Add the specified leaf to this node, possibly creating a child branch in the process. If the leaf node already exists, replace it.
void resetBackground(const ValueType &oldBackground, const ValueType &newBackground)
Change inactive tiles or voxels with value oldBackground to newBackground or -oldBackground to -newBa...
void setValueOffAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
bool isValueOnAndCache(const Coord &xyz, AccessorT &) const
void setItem(Index pos, const ChildT &c) const
Definition: InternalNode.h:142
OnMaskIterator< NodeMask > OnIterator
Definition: NodeMasks.h:348
#define OPENVDB_NO_DEPRECATION_WARNING_END
Definition: Platform.h:218
void operator()(const tbb::blocked_range< Index > &r) const
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
GLuint GLfloat * val
Definition: glcorearb.h:1608
const ValueType & getValue(const Coord &xyz) const
**If you just want to fire and args
Definition: thread.h:618
CombineArgs & setARef(const AValueType &a)
Redirect the A value to a new external source.
Definition: Types.h:688
void setChildUnsafe(Index offset, ChildNodeType *child)
Replace a tile at offset with the given child node.
static void offsetToLocalCoord(Index n, Coord &xyz)
Return the local coordinates for a linear table offset, where offset 0 has coordinates (0...
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:164
TopologyCopy2(const OtherInternalNode *source, InternalNode *target, const ValueType &offValue, const ValueType &onValue)
Fp4 BuildType
Definition: NanoVDB.h:5565
void combine2(const InternalNode &other0, const OtherNodeType &other1, CombineOp &)
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:750
SameConfiguration<OtherNodeType>::value is true if and only if OtherNodeType is the type of an Internal...
Definition: InternalNode.h:65
Index getValueLevel(const Coord &xyz) const
Return the level of the tree (0 = leaf) at which the value at the given coordinates resides...
GLboolean r
Definition: glcorearb.h:1222
Tag dispatch class that distinguishes constructors that deep copy.
Definition: Types.h:752
NodeType * probeNode(const Coord &xyz)
Return a pointer to the node that contains voxel (x, y, z). If no such node exists, return nullptr.
void addLeafAndCache(LeafNodeType *leaf, AccessorT &)
Same as addLeaf() except, if necessary, update the accessor with pointers to the nodes along the path...
ValueIter< InternalNode, const ValueType, MaskOnIterator, ValueOn > ValueOnIter
Definition: InternalNode.h:214
void copyToDense(const CoordBBox &bbox, DenseT &dense) const
Copy into a dense grid the values of the voxels that lie within a given bounding box.
const LeafNodeType * probeConstLeaf(const Coord &xyz) const
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, return nullptr.
IMATH_INTERNAL_NAMESPACE_HEADER_ENTER IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T clip(const T &p, const Box< T > &box) IMATH_NOEXCEPT
Definition: ImathBoxAlgo.h:29
DenseIter< const InternalNode, const ChildNodeType, ValueType, ChildAll > ChildAllCIter
Definition: InternalNode.h:212
Coord mOrigin
Global grid index coordinates (x,y,z) of the local origin of this node.
Definition: InternalNode.h:917
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:119
bool ValueType
Definition: NanoVDB.h:5729
OPENVDB_API uint32_t getFormatVersion(std::ios_base &)
Return the file format version number associated with the given input stream.
TopologyIntersection(const OtherInternalNode *source, InternalNode *target, const ValueType &background)
state
Definition: core.h:2289
const ValueType & getValueAndCache(const Coord &xyz, AccessorT &) const
void readBuffers(std::istream &, bool fromHalf=false)
void modifyValueAndCache(const Coord &xyz, const ModifyOp &op, AccessorT &)
Apply a functor to the value of the voxel at the given coordinates and mark the voxel as active...
LeafNodeType * touchLeafAndCache(const Coord &xyz, AccessorT &)
Same as touchLeaf() except, if necessary, update the accessor with pointers to the nodes along the pa...
ValueIter< const InternalNode, const ValueType, MaskOffIterator, ValueOff > ValueOffCIter
Definition: InternalNode.h:217
GLint GLsizei count
Definition: glcorearb.h:405
void topologyDifference(const InternalNode< OtherChildNodeType, Log2Dim > &other, const ValueType &background)
Difference this node's set of active values with the active values of the other node, whose ValueType may be different. So a resulting voxel will be active only if the original voxel is active in this node and inactive in the other node.
void modifyValue(const Coord &xyz, const ModifyOp &op)
Apply a functor to the value of the voxel at the given coordinates and mark the voxel as active...
void evalActiveBoundingBox(CoordBBox &bbox, bool visitVoxels=true) const
Expand the specified bounding box so that it includes the active tiles of this internal node as well ...
bool isOff(Index32 n) const
Return true if the nth bit is off.
Definition: NodeMasks.h:508