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