OpenVDB  12.0.0
LeafNode.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #ifndef OPENVDB_TREE_LEAFNODE_HAS_BEEN_INCLUDED
5 #define OPENVDB_TREE_LEAFNODE_HAS_BEEN_INCLUDED
6 
7 #include <openvdb/Types.h>
9 #include <openvdb/util/Assert.h>
10 #include <openvdb/io/Compression.h> // for io::readData(), etc.
11 #include "Iterator.h"
12 #include "LeafBuffer.h"
13 #include <algorithm> // for std::nth_element()
14 #include <iostream>
15 #include <memory>
16 #include <sstream>
17 #include <string>
18 #include <type_traits>
19 #include <vector>
20 
21 
22 class TestLeaf;
23 template<typename> class TestLeafIO;
24 
25 namespace openvdb {
27 namespace OPENVDB_VERSION_NAME {
28 namespace tree {
29 
30 template<Index, typename> struct SameLeafConfig; // forward declaration
31 
32 
33 /// @brief Templated block class to hold specific data types and a fixed
34 /// number of values determined by Log2Dim. The actual coordinate
35 /// dimension of the block is 2^Log2Dim, i.e. Log2Dim=3 corresponds to
36 /// a LeafNode that spans a 8^3 block.
37 template<typename T, Index Log2Dim>
38 class LeafNode
39 {
40 public:
41  using BuildType = T;
42  using ValueType = T;
47 
48  static const Index
49  LOG2DIM = Log2Dim, // needed by parent nodes
50  TOTAL = Log2Dim, // needed by parent nodes
51  DIM = 1 << TOTAL, // dimension along one coordinate direction
52  NUM_VALUES = 1 << 3 * Log2Dim,
53  NUM_VOXELS = NUM_VALUES, // total number of voxels represented by this node
54  SIZE = NUM_VALUES,
55  LEVEL = 0; // level 0 = leaf
56 
57  /// @brief ValueConverter<T>::Type is the type of a LeafNode having the same
58  /// dimensions as this node but a different value type, T.
59  template<typename OtherValueType>
61 
62  /// @brief SameConfiguration<OtherNodeType>::value is @c true if and only if
63  /// OtherNodeType is the type of a LeafNode with the same dimensions as this node.
64  template<typename OtherNodeType>
67  };
68 
69 
70  /// Default constructor
71  LeafNode();
72 
73  /// @brief Constructor
74  /// @param coords the grid index coordinates of a voxel
75  /// @param value a value with which to fill the buffer
76  /// @param active the active state to which to initialize all voxels
77  explicit LeafNode(const Coord& coords,
78  const ValueType& value = zeroVal<ValueType>(),
79  bool active = false);
80 
81  /// @brief "Partial creation" constructor used during file input
82  /// @param coords the grid index coordinates of a voxel
83  /// @param value a value with which to fill the buffer
84  /// @param active the active state to which to initialize all voxels
85  /// @details This constructor does not allocate memory for voxel values.
87  const Coord& coords,
88  const ValueType& value = zeroVal<ValueType>(),
89  bool active = false);
90 
91  /// Deep copy constructor
92  LeafNode(const LeafNode&);
93 
94  /// Deep assignment operator
95  LeafNode& operator=(const LeafNode&) = default;
96 
97  /// Value conversion copy constructor
98  template<typename OtherValueType>
99  explicit LeafNode(const LeafNode<OtherValueType, Log2Dim>& other);
100 
101  /// Topology copy constructor
102  template<typename OtherValueType>
104  const ValueType& offValue, const ValueType& onValue, TopologyCopy);
105 
106  /// Topology copy constructor
107  template<typename OtherValueType>
109  const ValueType& background, TopologyCopy);
110 
111  /// Destructor.
112  ~LeafNode();
113 
114  //
115  // Statistics
116  //
117  /// Return log2 of the dimension of this LeafNode, e.g. 3 if dimensions are 8^3
118  static Index log2dim() { return Log2Dim; }
119  /// Return the number of voxels in each coordinate dimension.
120  static Index dim() { return DIM; }
121  /// Return the total number of voxels represented by this LeafNode
122  static Index size() { return SIZE; }
123  /// Return the total number of voxels represented by this LeafNode
124  static Index numValues() { return SIZE; }
125  /// Return the level of this node, which by definition is zero for LeafNodes
126  static Index getLevel() { return LEVEL; }
127  /// Append the Log2Dim of this LeafNode to the specified vector
128  static void getNodeLog2Dims(std::vector<Index>& dims) { dims.push_back(Log2Dim); }
129  /// Return the dimension of child nodes of this LeafNode, which is one for voxels.
130  static Index getChildDim() { return 1; }
131  /// Return the leaf count for this node, which is one.
132  static Index64 leafCount() { return 1; }
133  /// no-op
134  void nodeCount(std::vector<Index64> &) const {}
135  OPENVDB_DEPRECATED_MESSAGE("Use input type std::vector<Index64> for nodeCount.")
136  void nodeCount(std::vector<Index32> &) const {}
137  /// Return the non-leaf count for this node, which is zero.
138  static Index64 nonLeafCount() { return 0; }
139  /// Return the child count for this node, which is zero.
140  static Index32 childCount() { return 0; }
141 
142  /// Return the number of voxels marked On.
143  Index64 onVoxelCount() const { return mValueMask.countOn(); }
144  /// Return the number of voxels marked Off.
145  Index64 offVoxelCount() const { return mValueMask.countOff(); }
146  Index64 onLeafVoxelCount() const { return onVoxelCount(); }
147  Index64 offLeafVoxelCount() const { return offVoxelCount(); }
148  static Index64 onTileCount() { return 0; }
149  static Index64 offTileCount() { return 0; }
150  /// Return @c true if this node has no active voxels.
151  bool isEmpty() const { return mValueMask.isOff(); }
152  /// Return @c true if this node contains only active voxels.
153  bool isDense() const { return mValueMask.isOn(); }
154  /// Return @c true if memory for this node's buffer has been allocated.
155  bool isAllocated() const { return !mBuffer.isOutOfCore() && !mBuffer.empty(); }
156  /// Allocate memory for this node's buffer if it has not already been allocated.
157  bool allocate() { return mBuffer.allocate(); }
158 
159  /// Return the memory in bytes occupied by this node.
160  Index64 memUsage() const;
161  Index64 memUsageIfLoaded() const;
162 
163  /// Expand the given bounding box so that it includes this leaf node's active voxels.
164  /// If visitVoxels is false this LeafNode will be approximated as dense, i.e. with all
165  /// voxels active. Else the individual active voxels are visited to produce a tight bbox.
166  void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const;
167 
168  /// @brief Return the bounding box of this node, i.e., the full index space
169  /// spanned by this leaf node.
170  CoordBBox getNodeBoundingBox() const { return CoordBBox::createCube(mOrigin, DIM); }
171 
172  /// Set the grid index coordinates of this node's local origin.
173  void setOrigin(const Coord& origin) { mOrigin = origin; }
174  //@{
175  /// Return the grid index coordinates of this node's local origin.
176  const Coord& origin() const { return mOrigin; }
177  void getOrigin(Coord& origin) const { origin = mOrigin; }
178  void getOrigin(Int32& x, Int32& y, Int32& z) const { mOrigin.asXYZ(x, y, z); }
179  //@}
180 
181  /// Return the linear table offset of the given global or local coordinates.
182  static Index coordToOffset(const Coord& xyz);
183  /// @brief Return the local coordinates for a linear table offset,
184  /// where offset 0 has coordinates (0, 0, 0).
185  static Coord offsetToLocalCoord(Index n);
186  /// Return the global coordinates for a linear table offset.
187  Coord offsetToGlobalCoord(Index n) const;
188 
189  /// Return the transient data value.
190  Index32 transientData() const { return mTransientData; }
191  /// Set the transient data value.
192  void setTransientData(Index32 transientData) { mTransientData = transientData; }
193 
194  /// Return a string representation of this node.
195  std::string str() const;
196 
197  /// @brief Return @c true if the given node (which may have a different @c ValueType
198  /// than this node) has the same active value topology as this node.
199  template<typename OtherType, Index OtherLog2Dim>
200  bool hasSameTopology(const LeafNode<OtherType, OtherLog2Dim>* other) const;
201 
202  /// Check for buffer, state and origin equivalence.
203  bool operator==(const LeafNode& other) const;
204  bool operator!=(const LeafNode& other) const { return !(other == *this); }
205 
206 protected:
210 
211  // Type tags to disambiguate template instantiations
212  struct ValueOn {}; struct ValueOff {}; struct ValueAll {};
213  struct ChildOn {}; struct ChildOff {}; struct ChildAll {};
214 
215  template<typename MaskIterT, typename NodeT, typename ValueT, typename TagT>
216  struct ValueIter:
217  // Derives from SparseIteratorBase, but can also be used as a dense iterator,
218  // if MaskIterT is a dense mask iterator type.
219  public SparseIteratorBase<
220  MaskIterT, ValueIter<MaskIterT, NodeT, ValueT, TagT>, NodeT, ValueT>
221  {
223 
225  ValueIter(const MaskIterT& iter, NodeT* parent): BaseT(iter, parent) {}
226 
227  ValueT& getItem(Index pos) const { return this->parent().getValue(pos); }
228  ValueT& getValue() const { return this->parent().getValue(this->pos()); }
229 
230  // Note: setItem() can't be called on const iterators.
231  void setItem(Index pos, const ValueT& value) const
232  {
233  this->parent().setValueOnly(pos, value);
234  }
235  // Note: setValue() can't be called on const iterators.
236  void setValue(const ValueT& value) const
237  {
238  this->parent().setValueOnly(this->pos(), value);
239  }
240 
241  // Note: modifyItem() can't be called on const iterators.
242  template<typename ModifyOp>
243  void modifyItem(Index n, const ModifyOp& op) const { this->parent().modifyValue(n, op); }
244  // Note: modifyValue() can't be called on const iterators.
245  template<typename ModifyOp>
246  void modifyValue(const ModifyOp& op) const { this->parent().modifyValue(this->pos(), op); }
247  };
248 
249  /// Leaf nodes have no children, so their child iterators have no get/set accessors.
250  template<typename MaskIterT, typename NodeT, typename TagT>
251  struct ChildIter:
252  public SparseIteratorBase<MaskIterT, ChildIter<MaskIterT, NodeT, TagT>, NodeT, ValueType>
253  {
255  ChildIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase<
256  MaskIterT, ChildIter<MaskIterT, NodeT, TagT>, NodeT, ValueType>(iter, parent) {}
257  };
258 
259  template<typename NodeT, typename ValueT, typename TagT>
260  struct DenseIter: public DenseIteratorBase<
261  MaskDenseIterator, DenseIter<NodeT, ValueT, TagT>, NodeT, /*ChildT=*/void, ValueT>
262  {
265 
267  DenseIter(const MaskDenseIterator& iter, NodeT* parent): BaseT(iter, parent) {}
268 
269  bool getItem(Index pos, void*& child, NonConstValueT& value) const
270  {
271  value = this->parent().getValue(pos);
272  child = nullptr;
273  return false; // no child
274  }
275 
276  // Note: setItem() can't be called on const iterators.
277  //void setItem(Index pos, void* child) const {}
278 
279  // Note: unsetItem() can't be called on const iterators.
280  void unsetItem(Index pos, const ValueT& value) const
281  {
282  this->parent().setValueOnly(pos, value);
283  }
284  };
285 
286 public:
299 
300  ValueOnCIter cbeginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); }
301  ValueOnCIter beginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); }
302  ValueOnIter beginValueOn() { return ValueOnIter(mValueMask.beginOn(), this); }
303  ValueOffCIter cbeginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); }
304  ValueOffCIter beginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); }
305  ValueOffIter beginValueOff() { return ValueOffIter(mValueMask.beginOff(), this); }
306  ValueAllCIter cbeginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); }
307  ValueAllCIter beginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); }
308  ValueAllIter beginValueAll() { return ValueAllIter(mValueMask.beginDense(), this); }
309 
310  ValueOnCIter cendValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); }
311  ValueOnCIter endValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); }
312  ValueOnIter endValueOn() { return ValueOnIter(mValueMask.endOn(), this); }
313  ValueOffCIter cendValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); }
314  ValueOffCIter endValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); }
315  ValueOffIter endValueOff() { return ValueOffIter(mValueMask.endOff(), this); }
316  ValueAllCIter cendValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); }
317  ValueAllCIter endValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); }
318  ValueAllIter endValueAll() { return ValueAllIter(mValueMask.endDense(), this); }
319 
320  // Note that [c]beginChildOn() and [c]beginChildOff() actually return end iterators,
321  // because leaf nodes have no children.
322  ChildOnCIter cbeginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
323  ChildOnCIter beginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
324  ChildOnIter beginChildOn() { return ChildOnIter(mValueMask.endOn(), this); }
325  ChildOffCIter cbeginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
326  ChildOffCIter beginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
327  ChildOffIter beginChildOff() { return ChildOffIter(mValueMask.endOff(), this); }
328  ChildAllCIter cbeginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); }
329  ChildAllCIter beginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); }
330  ChildAllIter beginChildAll() { return ChildAllIter(mValueMask.beginDense(), this); }
331 
332  ChildOnCIter cendChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
333  ChildOnCIter endChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
334  ChildOnIter endChildOn() { return ChildOnIter(mValueMask.endOn(), this); }
335  ChildOffCIter cendChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
336  ChildOffCIter endChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
337  ChildOffIter endChildOff() { return ChildOffIter(mValueMask.endOff(), this); }
338  ChildAllCIter cendChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); }
339  ChildAllCIter endChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); }
340  ChildAllIter endChildAll() { return ChildAllIter(mValueMask.endDense(), this); }
341 
342  //
343  // Buffer management
344  //
345  /// @brief Exchange this node's data buffer with the given data buffer
346  /// without changing the active states of the values.
347  void swap(Buffer& other) { mBuffer.swap(other); }
348  const Buffer& buffer() const { return mBuffer; }
349  Buffer& buffer() { return mBuffer; }
350 
351  //
352  // I/O methods
353  //
354  /// @brief Read in just the topology.
355  /// @param is the stream from which to read
356  /// @param fromHalf if true, floating-point input values are assumed to be 16-bit
357  void readTopology(std::istream& is, bool fromHalf = false);
358  /// @brief Write out just the topology.
359  /// @param os the stream to which to write
360  /// @param toHalf if true, output floating-point values as 16-bit half floats
361  void writeTopology(std::ostream& os, bool toHalf = false) const;
362 
363  /// @brief Read buffers from a stream.
364  /// @param is the stream from which to read
365  /// @param fromHalf if true, floating-point input values are assumed to be 16-bit
366  void readBuffers(std::istream& is, bool fromHalf = false);
367  /// @brief Read buffers that intersect the given bounding box.
368  /// @param is the stream from which to read
369  /// @param bbox an index-space bounding box
370  /// @param fromHalf if true, floating-point input values are assumed to be 16-bit
371  void readBuffers(std::istream& is, const CoordBBox& bbox, bool fromHalf = false);
372  /// @brief Write buffers to a stream.
373  /// @param os the stream to which to write
374  /// @param toHalf if true, output floating-point values as 16-bit half floats
375  void writeBuffers(std::ostream& os, bool toHalf = false) const;
376 
377  size_t streamingSize(bool toHalf = false) const;
378 
379  //
380  // Accessor methods
381  //
382  /// Return the value of the voxel at the given coordinates.
383  const ValueType& getValue(const Coord& xyz) const;
384  /// Return the value of the voxel at the given linear offset.
385  const ValueType& getValue(Index offset) const;
386 
387  /// @brief Return @c true if the voxel at the given coordinates is active.
388  /// @param xyz the coordinates of the voxel to be probed
389  /// @param[out] val the value of the voxel at the given coordinates
390  bool probeValue(const Coord& xyz, ValueType& val) const;
391  /// @brief Return @c true if the voxel at the given offset is active.
392  /// @param offset the linear offset of the voxel to be probed
393  /// @param[out] val the value of the voxel at the given coordinates
394  bool probeValue(Index offset, ValueType& val) const;
395 
396  /// Return the level (i.e., 0) at which leaf node values reside.
397  static Index getValueLevel(const Coord&) { return LEVEL; }
398 
399  /// Set the active state of the voxel at the given coordinates but don't change its value.
400  void setActiveState(const Coord& xyz, bool on);
401  /// Set the active state of the voxel at the given offset but don't change its value.
402  void setActiveState(Index offset, bool on) { OPENVDB_ASSERT(offset<SIZE); mValueMask.set(offset, on); }
403 
404  /// Set the value of the voxel at the given coordinates but don't change its active state.
405  void setValueOnly(const Coord& xyz, const ValueType& val);
406  /// Set the value of the voxel at the given offset but don't change its active state.
407  void setValueOnly(Index offset, const ValueType& val);
408 
409  /// Mark the voxel at the given coordinates as inactive but don't change its value.
410  void setValueOff(const Coord& xyz) { mValueMask.setOff(LeafNode::coordToOffset(xyz)); }
411  /// Mark the voxel at the given offset as inactive but don't change its value.
412  void setValueOff(Index offset) { OPENVDB_ASSERT(offset < SIZE); mValueMask.setOff(offset); }
413 
414  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
415  void setValueOff(const Coord& xyz, const ValueType& val);
416  /// Set the value of the voxel at the given offset and mark the voxel as inactive.
417  void setValueOff(Index offset, const ValueType& val);
418 
419  /// Mark the voxel at the given coordinates as active but don't change its value.
420  void setValueOn(const Coord& xyz) { mValueMask.setOn(LeafNode::coordToOffset(xyz)); }
421  /// Mark the voxel at the given offset as active but don't change its value.
422  void setValueOn(Index offset) { OPENVDB_ASSERT(offset < SIZE); mValueMask.setOn(offset); }
423  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
424  void setValueOn(const Coord& xyz, const ValueType& val) {
425  this->setValueOn(LeafNode::coordToOffset(xyz), val);
426  }
427  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
428  void setValue(const Coord& xyz, const ValueType& val) { this->setValueOn(xyz, val); }
429  /// Set the value of the voxel at the given offset and mark the voxel as active.
430  void setValueOn(Index offset, const ValueType& val) {
431  mBuffer.setValue(offset, val);
432  mValueMask.setOn(offset);
433  }
434 
435  /// @brief Apply a functor to the value of the voxel at the given offset
436  /// and mark the voxel as active.
437  template<typename ModifyOp>
438  void modifyValue(Index offset, const ModifyOp& op)
439  {
440  mBuffer.loadValues();
441  if (!mBuffer.empty()) {
442  // in-place modify value
443  ValueType& val = const_cast<ValueType&>(mBuffer[offset]);
444  op(val);
445  mValueMask.setOn(offset);
446  }
447  }
448 
449  /// @brief Apply a functor to the value of the voxel at the given coordinates
450  /// and mark the voxel as active.
451  template<typename ModifyOp>
452  void modifyValue(const Coord& xyz, const ModifyOp& op)
453  {
454  this->modifyValue(this->coordToOffset(xyz), op);
455  }
456 
457  /// Apply a functor to the voxel at the given coordinates.
458  template<typename ModifyOp>
459  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
460  {
461  mBuffer.loadValues();
462  if (!mBuffer.empty()) {
463  const Index offset = this->coordToOffset(xyz);
464  bool state = mValueMask.isOn(offset);
465  // in-place modify value
466  ValueType& val = const_cast<ValueType&>(mBuffer[offset]);
467  op(val, state);
468  mValueMask.set(offset, state);
469  }
470  }
471 
472  /// Mark all voxels as active but don't change their values.
473  void setValuesOn() { mValueMask.setOn(); }
474  /// Mark all voxels as inactive but don't change their values.
475  void setValuesOff() { mValueMask.setOff(); }
476 
477  /// Return @c true if the voxel at the given coordinates is active.
478  bool isValueOn(const Coord& xyz) const { return this->isValueOn(LeafNode::coordToOffset(xyz)); }
479  /// Return @c true if the voxel at the given offset is active.
480  bool isValueOn(Index offset) const { OPENVDB_ASSERT(offset < SIZE); return mValueMask.isOn(offset); }
481  /// Return @c true if the voxel at the given coordinates is inactive.
482  bool isValueOff(const Coord& xyz) const { return this->isValueOff(LeafNode::coordToOffset(xyz)); }
483  /// Return @c true if the voxel at the given offset is inactive.
484  bool isValueOff(Index offset) const { OPENVDB_ASSERT(offset < SIZE); return mValueMask.isOff(offset); }
485 
486  /// Return @c false since leaf nodes never contain tiles.
487  static bool hasActiveTiles() { return false; }
488 
489  /// Set all voxels that lie outside the given axis-aligned box to the background.
490  void clip(const CoordBBox&, const ValueType& background);
491 
492  /// Set all voxels within an axis-aligned box to the specified value and active state.
493  void fill(const CoordBBox& bbox, const ValueType&, bool active = true);
494  /// Set all voxels within an axis-aligned box to the specified value and active state.
495  void denseFill(const CoordBBox& bbox, const ValueType& value, bool active = true)
496  {
497  this->fill(bbox, value, active);
498  }
499 
500  /// Set all voxels to the specified value but don't change their active states.
501  void fill(const ValueType& value);
502  /// Set all voxels to the specified value and active state.
503  void fill(const ValueType& value, bool active);
504 
505  /// @brief Copy into a dense grid the values of the voxels that lie within
506  /// a given bounding box.
507  ///
508  /// @param bbox inclusive bounding box of the voxels to be copied into the dense grid
509  /// @param dense dense grid with a stride in @e z of one (see tools::Dense
510  /// in tools/Dense.h for the required API)
511  ///
512  /// @note @a bbox is assumed to be identical to or contained in the coordinate domains
513  /// of both the dense grid and this node, i.e., no bounds checking is performed.
514  /// @note Consider using tools::CopyToDense in tools/Dense.h
515  /// instead of calling this method directly.
516  template<typename DenseT>
517  void copyToDense(const CoordBBox& bbox, DenseT& dense) const;
518 
519  /// @brief Copy from a dense grid into this node the values of the voxels
520  /// that lie within a given bounding box.
521  /// @details Only values that are different (by more than the given tolerance)
522  /// from the background value will be active. Other values are inactive
523  /// and truncated to the background value.
524  ///
525  /// @param bbox inclusive bounding box of the voxels to be copied into this node
526  /// @param dense dense grid with a stride in @e z of one (see tools::Dense
527  /// in tools/Dense.h for the required API)
528  /// @param background background value of the tree that this node belongs to
529  /// @param tolerance tolerance within which a value equals the background value
530  ///
531  /// @note @a bbox is assumed to be identical to or contained in the coordinate domains
532  /// of both the dense grid and this node, i.e., no bounds checking is performed.
533  /// @note Consider using tools::CopyFromDense in tools/Dense.h
534  /// instead of calling this method directly.
535  template<typename DenseT>
536  void copyFromDense(const CoordBBox& bbox, const DenseT& dense,
537  const ValueType& background, const ValueType& tolerance);
538 
539  /// @brief Return the value of the voxel at the given coordinates.
540  /// @note Used internally by ValueAccessor.
541  template<typename AccessorT>
542  const ValueType& getValueAndCache(const Coord& xyz, AccessorT&) const
543  {
544  return this->getValue(xyz);
545  }
546 
547  /// @brief Return @c true if the voxel at the given coordinates is active.
548  /// @note Used internally by ValueAccessor.
549  template<typename AccessorT>
550  bool isValueOnAndCache(const Coord& xyz, AccessorT&) const { return this->isValueOn(xyz); }
551 
552  /// @brief Change the value of the voxel at the given coordinates and mark it as active.
553  /// @note Used internally by ValueAccessor.
554  template<typename AccessorT>
555  void setValueAndCache(const Coord& xyz, const ValueType& val, AccessorT&)
556  {
557  this->setValueOn(xyz, val);
558  }
559 
560  /// @brief Change the value of the voxel at the given coordinates
561  /// but preserve its state.
562  /// @note Used internally by ValueAccessor.
563  template<typename AccessorT>
564  void setValueOnlyAndCache(const Coord& xyz, const ValueType& val, AccessorT&)
565  {
566  this->setValueOnly(xyz, val);
567  }
568 
569  /// @brief Apply a functor to the value of the voxel at the given coordinates
570  /// and mark the voxel as active.
571  /// @note Used internally by ValueAccessor.
572  template<typename ModifyOp, typename AccessorT>
573  void modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&)
574  {
575  this->modifyValue(xyz, op);
576  }
577 
578  /// Apply a functor to the voxel at the given coordinates.
579  /// @note Used internally by ValueAccessor.
580  template<typename ModifyOp, typename AccessorT>
581  void modifyValueAndActiveStateAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&)
582  {
583  this->modifyValueAndActiveState(xyz, op);
584  }
585 
586  /// @brief Change the value of the voxel at the given coordinates and mark it as inactive.
587  /// @note Used internally by ValueAccessor.
588  template<typename AccessorT>
589  void setValueOffAndCache(const Coord& xyz, const ValueType& value, AccessorT&)
590  {
591  this->setValueOff(xyz, value);
592  }
593 
594  /// @brief Set the active state of the voxel at the given coordinates
595  /// without changing its value.
596  /// @note Used internally by ValueAccessor.
597  template<typename AccessorT>
598  void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&)
599  {
600  this->setActiveState(xyz, on);
601  }
602 
603  /// @brief Return @c true if the voxel at the given coordinates is active
604  /// and return the voxel value in @a val.
605  /// @note Used internally by ValueAccessor.
606  template<typename AccessorT>
607  bool probeValueAndCache(const Coord& xyz, ValueType& val, AccessorT&) const
608  {
609  return this->probeValue(xyz, val);
610  }
611 
612  /// @brief Return the value of the voxel at the given coordinates and return
613  /// its active state and level (i.e., 0) in @a state and @a level.
614  /// @note Used internally by ValueAccessor.
615  template<typename AccessorT>
616  const ValueType& getValue(const Coord& xyz, bool& state, int& level, AccessorT&) const
617  {
618  const Index offset = this->coordToOffset(xyz);
619  state = mValueMask.isOn(offset);
620  level = LEVEL;
621  return mBuffer[offset];
622  }
623 
624  /// @brief Return the LEVEL (=0) at which leaf node values reside.
625  /// @note Used internally by ValueAccessor (note last argument is a dummy).
626  template<typename AccessorT>
627  static Index getValueLevelAndCache(const Coord&, AccessorT&) { return LEVEL; }
628 
629  /// @brief Return a const reference to the first value in the buffer.
630  /// @note Though it is potentially risky you can convert this
631  /// to a non-const pointer by means of const_case<ValueType*>&.
632  const ValueType& getFirstValue() const { return mBuffer[0]; }
633  /// Return a const reference to the last value in the buffer.
634  const ValueType& getLastValue() const { return mBuffer[SIZE - 1]; }
635 
636  /// @brief Replace inactive occurrences of @a oldBackground with @a newBackground,
637  /// and inactive occurrences of @a -oldBackground with @a -newBackground.
638  void resetBackground(const ValueType& oldBackground, const ValueType& newBackground);
639 
640  void negate();
641 
642  /// @brief No-op
643  /// @details This function exists only to enable template instantiation.
644  void voxelizeActiveTiles(bool = true) {}
645 
646  template<MergePolicy Policy> void merge(const LeafNode&);
647  template<MergePolicy Policy> void merge(const ValueType& tileValue, bool tileActive);
648  template<MergePolicy Policy>
649  void merge(const LeafNode& other, const ValueType& /*bg*/, const ValueType& /*otherBG*/);
650 
651  /// @brief Union this node's set of active values with the active values
652  /// of the other node, whose @c ValueType may be different. So a
653  /// resulting voxel will be active if either of the original voxels
654  /// were active.
655  ///
656  /// @note This operation modifies only active states, not values.
657  template<typename OtherType>
658  void topologyUnion(const LeafNode<OtherType, Log2Dim>& other, const bool preserveTiles = false);
659 
660  /// @brief Intersect this node's set of active values with the active values
661  /// of the other node, whose @c ValueType may be different. So a
662  /// resulting voxel will be active only if both of the original voxels
663  /// were active.
664  ///
665  /// @details The last dummy argument is required to match the signature
666  /// for InternalNode::topologyIntersection.
667  ///
668  /// @note This operation modifies only active states, not
669  /// values. Also note that this operation can result in all voxels
670  /// being inactive so consider subsequently calling prune.
671  template<typename OtherType>
672  void topologyIntersection(const LeafNode<OtherType, Log2Dim>& other, const ValueType&);
673 
674  /// @brief Difference this node's set of active values with the active values
675  /// of the other node, whose @c ValueType may be different. So a
676  /// resulting voxel will be active only if the original voxel is
677  /// active in this LeafNode and inactive in the other LeafNode.
678  ///
679  /// @details The last dummy argument is required to match the signature
680  /// for InternalNode::topologyDifference.
681  ///
682  /// @note This operation modifies only active states, not values.
683  /// Also, because it can deactivate all of this node's voxels,
684  /// consider subsequently calling prune.
685  template<typename OtherType>
686  void topologyDifference(const LeafNode<OtherType, Log2Dim>& other, const ValueType&);
687 
688  template<typename CombineOp>
689  void combine(const LeafNode& other, CombineOp& op);
690  template<typename CombineOp>
691  void combine(const ValueType& value, bool valueIsActive, CombineOp& op);
692 
693  template<typename CombineOp, typename OtherType /*= ValueType*/>
694  void combine2(const LeafNode& other, const OtherType&, bool valueIsActive, CombineOp&);
695  template<typename CombineOp, typename OtherNodeT /*= LeafNode*/>
696  void combine2(const ValueType&, const OtherNodeT& other, bool valueIsActive, CombineOp&);
697  template<typename CombineOp, typename OtherNodeT /*= LeafNode*/>
698  void combine2(const LeafNode& b0, const OtherNodeT& b1, CombineOp&);
699 
700  //@{
701  /// This function exists only to enable template instantiation.
702  void prune(const ValueType& /*tolerance*/ = zeroVal<ValueType>()) {}
703  void addLeaf(LeafNode*) {}
704  template<typename AccessorT>
705  void addLeafAndCache(LeafNode*, AccessorT&) {}
706  template<typename NodeT>
707  NodeT* stealNode(const Coord&, const ValueType&, bool) { return nullptr; }
708  template<typename NodeT>
709  NodeT* probeNode(const Coord&) { return nullptr; }
710  template<typename NodeT>
711  const NodeT* probeConstNode(const Coord&) const { return nullptr; }
712  template<typename ArrayT> void getNodes(ArrayT&) const {}
713  template<typename ArrayT> void stealNodes(ArrayT&, const ValueType&, bool) {}
714  //@}
715 
716  void addTile(Index level, const Coord&, const ValueType&, bool);
717  void addTile(Index offset, const ValueType&, bool);
718  template<typename AccessorT>
719  void addTileAndCache(Index, const Coord&, const ValueType&, bool, AccessorT&);
720 
721  //@{
722  /// @brief Return a pointer to this node.
723  LeafNode* touchLeaf(const Coord&) { return this; }
724  template<typename AccessorT>
725  LeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; }
726  template<typename NodeT, typename AccessorT>
727  NodeT* probeNodeAndCache(const Coord&, AccessorT&)
728  {
730  if (!(std::is_same<NodeT, LeafNode>::value)) return nullptr;
731  return reinterpret_cast<NodeT*>(this);
733  }
734  LeafNode* probeLeaf(const Coord&) { return this; }
735  template<typename AccessorT>
736  LeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; }
737  //@}
738  //@{
739  /// @brief Return a @const pointer to this node.
740  const LeafNode* probeConstLeaf(const Coord&) const { return this; }
741  template<typename AccessorT>
742  const LeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const { return this; }
743  template<typename AccessorT>
744  const LeafNode* probeLeafAndCache(const Coord&, AccessorT&) const { return this; }
745  const LeafNode* probeLeaf(const Coord&) const { return this; }
746  template<typename NodeT, typename AccessorT>
747  const NodeT* probeConstNodeAndCache(const Coord&, AccessorT&) const
748  {
750  if (!(std::is_same<NodeT, LeafNode>::value)) return nullptr;
751  return reinterpret_cast<const NodeT*>(this);
753  }
754  //@}
755 
756  /// Return @c true if all of this node's values have the same active state
757  /// and are in the range this->getFirstValue() +/- @a tolerance.
758  ///
759  ///
760  /// @param firstValue Is updated with the first value of this leaf node.
761  /// @param state Is updated with the state of all values IF method
762  /// returns @c true. Else the value is undefined!
763  /// @param tolerance The tolerance used to determine if values are
764  /// approximately equal to the for value.
765  bool isConstant(ValueType& firstValue, bool& state,
766  const ValueType& tolerance = zeroVal<ValueType>()) const;
767 
768  /// Return @c true if all of this node's values have the same active state
769  /// and the range (@a maxValue - @a minValue) < @a tolerance.
770  ///
771  /// @param minValue Is updated with the minimum of all values IF method
772  /// returns @c true. Else the value is undefined!
773  /// @param maxValue Is updated with the maximum of all values IF method
774  /// returns @c true. Else the value is undefined!
775  /// @param state Is updated with the state of all values IF method
776  /// returns @c true. Else the value is undefined!
777  /// @param tolerance The tolerance used to determine if values are
778  /// approximately constant.
779  bool isConstant(ValueType& minValue, ValueType& maxValue,
780  bool& state, const ValueType& tolerance = zeroVal<ValueType>()) const;
781 
782 
783  /// @brief Computes the median value of all the active AND inactive voxels in this node.
784  /// @return The median value of all values in this node.
785  ///
786  /// @param tmp Optional temporary storage that can hold at least NUM_VALUES values
787  /// Use of this temporary storage can improve performance
788  /// when this method is called multiple times.
789  ///
790  /// @note If tmp = this->buffer().data() then the median
791  /// value is computed very efficiently (in place) but
792  /// the voxel values in this node are re-shuffled!
793  ///
794  /// @warning If tmp != nullptr then it is the responsibility of
795  /// the client code that it points to enough memory to
796  /// hold NUM_VALUES elements of type ValueType.
797  ValueType medianAll(ValueType *tmp = nullptr) const;
798 
799  /// @brief Computes the median value of all the active voxels in this node.
800  /// @return The number of active voxels.
801  ///
802  /// @param value If the return value is non zero @a value is updated
803  /// with the median value.
804  ///
805  /// @param tmp Optional temporary storage that can hold at least
806  /// as many values as there are active voxels in this node.
807  /// Use of this temporary storage can improve performance
808  /// when this method is called multiple times.
809  ///
810  /// @warning If tmp != nullptr then it is the responsibility of
811  /// the client code that it points to enough memory to
812  /// hold the number of active voxels of type ValueType.
813  Index medianOn(ValueType &value, ValueType *tmp = nullptr) const;
814 
815  /// @brief Computes the median value of all the inactive voxels in this node.
816  /// @return The number of inactive voxels.
817  ///
818  /// @param value If the return value is non zero @a value is updated
819  /// with the median value.
820  ///
821  /// @param tmp Optional temporary storage that can hold at least
822  /// as many values as there are inactive voxels in this node.
823  /// Use of this temporary storage can improve performance
824  /// when this method is called multiple times.
825  ///
826  /// @warning If tmp != nullptr then it is the responsibility of
827  /// the client code that it points to enough memory to
828  /// hold the number of inactive voxels of type ValueType.
829  Index medianOff(ValueType &value, ValueType *tmp = nullptr) const;
830 
831  /// Return @c true if all of this node's values are inactive.
832  bool isInactive() const { return mValueMask.isOff(); }
833 
834  //
835  // Unsafe methods
836  //
837  // These methods are not in fact unsafe, but are only offered so that
838  // the same methods can be called on both internal nodes and leaf nodes.
839 
840  /// Return the value of the voxel at the given offset.
841  const ValueType& getValueUnsafe(Index offset) const { return this->getValue(offset); }
842  /// Return true if the voxel at the given offset is active and set value.
843  bool getValueUnsafe(Index offset, ValueType& value) const { return this->probeValue(offset, value); }
844  /// Set the active state of the voxel at the given offset but don't change its value.
845  void setActiveStateUnsafe(Index offset, bool on) { this->setActiveState(offset, on); }
846  /// Set the value of the voxel at the given coordinates but don't change its active state.
847  void setValueOnlyUnsafe(Index offset, const ValueType& value) { return this->setValueOnly(offset, value); }
848  /// Mark the voxel at the given offset as active but don't change its value.
849  void setValueOnUnsafe(Index offset) { this->setValueOn(offset); }
850  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
851  void setValueOnUnsafe(Index offset, const ValueType& value) { this->setValueOn(offset, value); }
852  /// Mark the voxel at the given offset as inactive but don't change its value.
853  void setValueOffUnsafe(Index offset) { this->setValueOff(offset); }
854  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
855  void setValueOffUnsafe(Index offset, const ValueType& value) { this->setValueOff(offset, value); }
856 
857 protected:
858  friend class ::TestLeaf;
859  template<typename> friend class ::TestLeafIO;
860 
861  // During topology-only construction, access is needed
862  // to protected/private members of other template instances.
863  template<typename, Index> friend class LeafNode;
864 
871 
872  // Allow iterators to call mask accessor methods (see below).
873  /// @todo Make mask accessors public?
877 
878  // Mask accessors
879 public:
880  bool isValueMaskOn(Index n) const { return mValueMask.isOn(n); }
881  bool isValueMaskOn() const { return mValueMask.isOn(); }
882  bool isValueMaskOff(Index n) const { return mValueMask.isOff(n); }
883  bool isValueMaskOff() const { return mValueMask.isOff(); }
884  const NodeMaskType& getValueMask() const { return mValueMask; }
885  NodeMaskType& getValueMask() { return mValueMask; }
886  const NodeMaskType& valueMask() const { return mValueMask; }
887  void setValueMask(const NodeMaskType& mask) { mValueMask = mask; }
888  bool isChildMaskOn(Index) const { return false; } // leaf nodes have no children
889  bool isChildMaskOff(Index) const { return true; }
890  bool isChildMaskOff() const { return true; }
891 protected:
892  void setValueMask(Index n, bool on) { mValueMask.set(n, on); }
893  void setValueMaskOn(Index n) { mValueMask.setOn(n); }
894  void setValueMaskOff(Index n) { mValueMask.setOff(n); }
895 
896  inline void skipCompressedValues(bool seekable, std::istream&, bool fromHalf);
897 
898  /// Compute the origin of the leaf node that contains the voxel with the given coordinates.
899  static void evalNodeOrigin(Coord& xyz) { xyz &= ~(DIM - 1); }
900 
901 private:
902  /// Buffer containing the actual data values
903  Buffer mBuffer;
904  /// Bitmask that determines which voxels are active
905  NodeMaskType mValueMask;
906  /// Global grid index coordinates (x,y,z) of the local origin of this node
907  Coord mOrigin;
908  /// Transient data (not serialized)
909  Index32 mTransientData = 0;
910 }; // end of LeafNode class
911 
912 
913 ////////////////////////////////////////
914 
915 
916 //@{
917 /// Helper metafunction used to implement LeafNode::SameConfiguration
918 /// (which, as an inner class, can't be independently specialized)
919 template<Index Dim1, typename NodeT2>
920 struct SameLeafConfig { static const bool value = false; };
921 
922 template<Index Dim1, typename T2>
923 struct SameLeafConfig<Dim1, LeafNode<T2, Dim1> > { static const bool value = true; };
924 //@}
925 
926 
927 ////////////////////////////////////////
928 
929 
930 template<typename T, Index Log2Dim>
931 inline
933  mValueMask(),//default is off!
934  mOrigin(0, 0, 0)
935 {
936 }
937 
938 
939 template<typename T, Index Log2Dim>
940 inline
941 LeafNode<T, Log2Dim>::LeafNode(const Coord& xyz, const ValueType& val, bool active):
942  mBuffer(val),
943  mValueMask(active),
944  mOrigin(xyz & (~(DIM - 1)))
945 {
946 }
947 
948 
949 template<typename T, Index Log2Dim>
950 inline
951 LeafNode<T, Log2Dim>::LeafNode(PartialCreate, const Coord& xyz, const ValueType& val, bool active):
952  mBuffer(PartialCreate(), val),
953  mValueMask(active),
954  mOrigin(xyz & (~(DIM - 1)))
955 {
956 }
957 
958 
959 template<typename T, Index Log2Dim>
960 inline
962  : mBuffer(other.mBuffer)
963  , mValueMask(other.valueMask())
964  , mOrigin(other.mOrigin)
965  , mTransientData(other.mTransientData)
966 {
967 }
968 
969 
970 // Copy-construct from a leaf node with the same configuration but a different ValueType.
971 template<typename T, Index Log2Dim>
972 template<typename OtherValueType>
973 inline
975  : mValueMask(other.valueMask())
976  , mOrigin(other.mOrigin)
977  , mTransientData(other.mTransientData)
978 {
979  struct Local {
980  /// @todo Consider using a value conversion functor passed as an argument instead.
981  static inline ValueType convertValue(const OtherValueType& val) { return ValueType(val); }
982  };
983 
984  for (Index i = 0; i < SIZE; ++i) {
985  mBuffer[i] = Local::convertValue(other.mBuffer[i]);
986  }
987 }
988 
989 
990 template<typename T, Index Log2Dim>
991 template<typename OtherValueType>
992 inline
994  const ValueType& background, TopologyCopy)
995  : mBuffer(background)
996  , mValueMask(other.valueMask())
997  , mOrigin(other.mOrigin)
998  , mTransientData(other.mTransientData)
999 {
1000 }
1001 
1002 
1003 template<typename T, Index Log2Dim>
1004 template<typename OtherValueType>
1005 inline
1007  const ValueType& offValue, const ValueType& onValue, TopologyCopy)
1008  : mValueMask(other.valueMask())
1009  , mOrigin(other.mOrigin)
1010  , mTransientData(other.mTransientData)
1011 {
1012  for (Index i = 0; i < SIZE; ++i) {
1013  mBuffer[i] = (mValueMask.isOn(i) ? onValue : offValue);
1014  }
1015 }
1016 
1017 
1018 template<typename T, Index Log2Dim>
1019 inline
1021 {
1022 }
1023 
1024 
1025 template<typename T, Index Log2Dim>
1026 inline std::string
1028 {
1029  std::ostringstream ostr;
1030  ostr << "LeafNode @" << mOrigin << ": " << mBuffer;
1031  return ostr.str();
1032 }
1033 
1034 
1035 ////////////////////////////////////////
1036 
1037 
1038 template<typename T, Index Log2Dim>
1039 inline Index
1041 {
1042  OPENVDB_ASSERT((xyz[0] & (DIM-1u)) < DIM && (xyz[1] & (DIM-1u)) < DIM && (xyz[2] & (DIM-1u)) < DIM);
1043  return ((xyz[0] & (DIM-1u)) << 2*Log2Dim)
1044  + ((xyz[1] & (DIM-1u)) << Log2Dim)
1045  + (xyz[2] & (DIM-1u));
1046 }
1047 
1048 template<typename T, Index Log2Dim>
1049 inline Coord
1051 {
1052  OPENVDB_ASSERT(n<(1<< 3*Log2Dim));
1053  Coord xyz;
1054  xyz.setX(n >> 2*Log2Dim);
1055  n &= ((1<<2*Log2Dim)-1);
1056  xyz.setY(n >> Log2Dim);
1057  xyz.setZ(n & ((1<<Log2Dim)-1));
1058  return xyz;
1059 }
1060 
1061 
1062 template<typename T, Index Log2Dim>
1063 inline Coord
1065 {
1066  return (this->offsetToLocalCoord(n) + this->origin());
1067 }
1068 
1069 
1070 ////////////////////////////////////////
1071 
1072 
1073 template<typename ValueT, Index Log2Dim>
1074 inline const ValueT&
1076 {
1077  return this->getValue(LeafNode::coordToOffset(xyz));
1078 }
1079 
1080 template<typename ValueT, Index Log2Dim>
1081 inline const ValueT&
1083 {
1084  OPENVDB_ASSERT(offset < SIZE);
1085  return mBuffer[offset];
1086 }
1087 
1088 
1089 template<typename T, Index Log2Dim>
1090 inline bool
1091 LeafNode<T, Log2Dim>::probeValue(const Coord& xyz, ValueType& val) const
1092 {
1093  return this->probeValue(LeafNode::coordToOffset(xyz), val);
1094 }
1095 
1096 template<typename T, Index Log2Dim>
1097 inline bool
1099 {
1100  OPENVDB_ASSERT(offset < SIZE);
1101  val = mBuffer[offset];
1102  return mValueMask.isOn(offset);
1103 }
1104 
1105 
1106 template<typename T, Index Log2Dim>
1107 inline void
1108 LeafNode<T, Log2Dim>::setValueOff(const Coord& xyz, const ValueType& val)
1109 {
1110  this->setValueOff(LeafNode::coordToOffset(xyz), val);
1111 }
1112 
1113 template<typename T, Index Log2Dim>
1114 inline void
1116 {
1117  OPENVDB_ASSERT(offset < SIZE);
1118  mBuffer.setValue(offset, val);
1119  mValueMask.setOff(offset);
1120 }
1121 
1122 
1123 template<typename T, Index Log2Dim>
1124 inline void
1125 LeafNode<T, Log2Dim>::setActiveState(const Coord& xyz, bool on)
1126 {
1127  mValueMask.set(this->coordToOffset(xyz), on);
1128 }
1129 
1130 
1131 template<typename T, Index Log2Dim>
1132 inline void
1133 LeafNode<T, Log2Dim>::setValueOnly(const Coord& xyz, const ValueType& val)
1134 {
1135  this->setValueOnly(LeafNode::coordToOffset(xyz), val);
1136 }
1137 
1138 template<typename T, Index Log2Dim>
1139 inline void
1141 {
1142  OPENVDB_ASSERT(offset<SIZE); mBuffer.setValue(offset, val);
1143 }
1144 
1145 
1146 ////////////////////////////////////////
1147 
1148 
1149 template<typename T, Index Log2Dim>
1150 inline void
1151 LeafNode<T, Log2Dim>::clip(const CoordBBox& clipBBox, const T& background)
1152 {
1153  CoordBBox nodeBBox = this->getNodeBoundingBox();
1154  if (!clipBBox.hasOverlap(nodeBBox)) {
1155  // This node lies completely outside the clipping region. Fill it with the background.
1156  this->fill(background, /*active=*/false);
1157  } else if (clipBBox.isInside(nodeBBox)) {
1158  // This node lies completely inside the clipping region. Leave it intact.
1159  return;
1160  }
1161 
1162  // This node isn't completely contained inside the clipping region.
1163  // Set any voxels that lie outside the region to the background value.
1164 
1165  // Construct a boolean mask that is on inside the clipping region and off outside it.
1166  NodeMaskType mask;
1167  nodeBBox.intersect(clipBBox);
1168  Coord xyz;
1169  int &x = xyz.x(), &y = xyz.y(), &z = xyz.z();
1170  for (x = nodeBBox.min().x(); x <= nodeBBox.max().x(); ++x) {
1171  for (y = nodeBBox.min().y(); y <= nodeBBox.max().y(); ++y) {
1172  for (z = nodeBBox.min().z(); z <= nodeBBox.max().z(); ++z) {
1173  mask.setOn(static_cast<Index32>(this->coordToOffset(xyz)));
1174  }
1175  }
1176  }
1177 
1178  // Set voxels that lie in the inactive region of the mask (i.e., outside
1179  // the clipping region) to the background value.
1180  for (MaskOffIterator maskIter = mask.beginOff(); maskIter; ++maskIter) {
1181  this->setValueOff(maskIter.pos(), background);
1182  }
1183 }
1184 
1185 
1186 ////////////////////////////////////////
1187 
1188 
1189 template<typename T, Index Log2Dim>
1190 inline void
1191 LeafNode<T, Log2Dim>::fill(const CoordBBox& bbox, const ValueType& value, bool active)
1192 {
1193  if (!this->allocate()) return;
1194 
1195  auto clippedBBox = this->getNodeBoundingBox();
1196  clippedBBox.intersect(bbox);
1197  if (!clippedBBox) return;
1198 
1199  for (Int32 x = clippedBBox.min().x(); x <= clippedBBox.max().x(); ++x) {
1200  const Index offsetX = (x & (DIM-1u)) << 2*Log2Dim;
1201  for (Int32 y = clippedBBox.min().y(); y <= clippedBBox.max().y(); ++y) {
1202  const Index offsetXY = offsetX + ((y & (DIM-1u)) << Log2Dim);
1203  for (Int32 z = clippedBBox.min().z(); z <= clippedBBox.max().z(); ++z) {
1204  const Index offset = offsetXY + (z & (DIM-1u));
1205  mBuffer[offset] = value;
1206  mValueMask.set(offset, active);
1207  }
1208  }
1209  }
1210 }
1211 
1212 template<typename T, Index Log2Dim>
1213 inline void
1215 {
1216  mBuffer.fill(value);
1217 }
1218 
1219 template<typename T, Index Log2Dim>
1220 inline void
1221 LeafNode<T, Log2Dim>::fill(const ValueType& value, bool active)
1222 {
1223  mBuffer.fill(value);
1224  mValueMask.set(active);
1225 }
1226 
1227 
1228 ////////////////////////////////////////
1229 
1230 
1231 template<typename T, Index Log2Dim>
1232 template<typename DenseT>
1233 inline void
1234 LeafNode<T, Log2Dim>::copyToDense(const CoordBBox& bbox, DenseT& dense) const
1235 {
1236  mBuffer.loadValues();
1237 
1238  using DenseValueType = typename DenseT::ValueType;
1239 
1240  const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride();
1241  const Coord& min = dense.bbox().min();
1242  DenseValueType* t0 = dense.data() + zStride * (bbox.min()[2] - min[2]); // target array
1243  const T* s0 = &mBuffer[bbox.min()[2] & (DIM-1u)]; // source array
1244  for (Int32 x = bbox.min()[0], ex = bbox.max()[0] + 1; x < ex; ++x) {
1245  DenseValueType* t1 = t0 + xStride * (x - min[0]);
1246  const T* s1 = s0 + ((x & (DIM-1u)) << 2*Log2Dim);
1247  for (Int32 y = bbox.min()[1], ey = bbox.max()[1] + 1; y < ey; ++y) {
1248  DenseValueType* t2 = t1 + yStride * (y - min[1]);
1249  const T* s2 = s1 + ((y & (DIM-1u)) << Log2Dim);
1250  for (Int32 z = bbox.min()[2], ez = bbox.max()[2] + 1; z < ez; ++z, t2 += zStride) {
1251  *t2 = DenseValueType(*s2++);
1252  }
1253  }
1254  }
1255 }
1256 
1257 
1258 template<typename T, Index Log2Dim>
1259 template<typename DenseT>
1260 inline void
1261 LeafNode<T, Log2Dim>::copyFromDense(const CoordBBox& bbox, const DenseT& dense,
1262  const ValueType& background, const ValueType& tolerance)
1263 {
1264  if (!this->allocate()) return;
1265 
1266  using DenseValueType = typename DenseT::ValueType;
1267 
1268  const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride();
1269  const Coord& min = dense.bbox().min();
1270 
1271  const DenseValueType* s0 = dense.data() + zStride * (bbox.min()[2] - min[2]); // source
1272  const Int32 n0 = bbox.min()[2] & (DIM-1u);
1273  for (Int32 x = bbox.min()[0], ex = bbox.max()[0]+1; x < ex; ++x) {
1274  const DenseValueType* s1 = s0 + xStride * (x - min[0]);
1275  const Int32 n1 = n0 + ((x & (DIM-1u)) << 2*LOG2DIM);
1276  for (Int32 y = bbox.min()[1], ey = bbox.max()[1]+1; y < ey; ++y) {
1277  const DenseValueType* s2 = s1 + yStride * (y - min[1]);
1278  Int32 n2 = n1 + ((y & (DIM-1u)) << LOG2DIM);
1279  for (Int32 z = bbox.min()[2], ez = bbox.max()[2]+1; z < ez; ++z, ++n2, s2 += zStride) {
1280  if (math::isApproxEqual(background, ValueType(*s2), tolerance)) {
1281  mValueMask.setOff(n2);
1282  mBuffer[n2] = background;
1283  } else {
1284  mValueMask.setOn(n2);
1285  mBuffer[n2] = ValueType(*s2);
1286  }
1287  }
1288  }
1289  }
1290 }
1291 
1292 
1293 ////////////////////////////////////////
1294 
1295 
1296 template<typename T, Index Log2Dim>
1297 inline void
1298 LeafNode<T, Log2Dim>::readTopology(std::istream& is, bool /*fromHalf*/)
1299 {
1300  mValueMask.load(is);
1301 }
1302 
1303 
1304 template<typename T, Index Log2Dim>
1305 inline void
1306 LeafNode<T, Log2Dim>::writeTopology(std::ostream& os, bool /*toHalf*/) const
1307 {
1308  mValueMask.save(os);
1309 }
1310 
1311 
1312 ////////////////////////////////////////
1313 
1314 
1315 
1316 template<typename T, Index Log2Dim>
1317 inline void
1318 LeafNode<T,Log2Dim>::skipCompressedValues(bool seekable, std::istream& is, bool fromHalf)
1319 {
1320  if (seekable) {
1321  // Seek over voxel values.
1322  io::readCompressedValues<ValueType, NodeMaskType>(
1323  is, nullptr, SIZE, mValueMask, fromHalf);
1324  } else {
1325  // Read and discard voxel values.
1326  Buffer temp;
1327  io::readCompressedValues(is, temp.mData, SIZE, mValueMask, fromHalf);
1328  }
1329 }
1330 
1331 
1332 template<typename T, Index Log2Dim>
1333 inline void
1334 LeafNode<T,Log2Dim>::readBuffers(std::istream& is, bool fromHalf)
1335 {
1336  this->readBuffers(is, CoordBBox::inf(), fromHalf);
1337 }
1338 
1339 
1340 template<typename T, Index Log2Dim>
1341 inline void
1342 LeafNode<T,Log2Dim>::readBuffers(std::istream& is, const CoordBBox& clipBBox, bool fromHalf)
1343 {
1345  const bool seekable = meta && meta->seekable();
1346 
1347 #ifdef OPENVDB_USE_DELAYED_LOADING
1348  std::streamoff maskpos = is.tellg();
1349 #endif
1350 
1351  if (seekable) {
1352  // Seek over the value mask.
1353  mValueMask.seek(is);
1354  } else {
1355  // Read in the value mask.
1356  mValueMask.load(is);
1357  }
1358 
1359  int8_t numBuffers = 1;
1361  // Read in the origin.
1362  is.read(reinterpret_cast<char*>(&mOrigin), sizeof(Coord::ValueType) * 3);
1363 
1364  // Read in the number of buffers, which should now always be one.
1365  is.read(reinterpret_cast<char*>(&numBuffers), sizeof(int8_t));
1366  }
1367 
1368  CoordBBox nodeBBox = this->getNodeBoundingBox();
1369  if (!clipBBox.hasOverlap(nodeBBox)) {
1370  // This node lies completely outside the clipping region.
1371  skipCompressedValues(seekable, is, fromHalf);
1372  mValueMask.setOff();
1373  mBuffer.setOutOfCore(false);
1374  } else {
1375 #ifdef OPENVDB_USE_DELAYED_LOADING
1376  // If this node lies completely inside the clipping region and it is being read
1377  // from a memory-mapped file, delay loading of its buffer until the buffer
1378  // is actually accessed. (If this node requires clipping, its buffer
1379  // must be accessed and therefore must be loaded.)
1380  io::MappedFile::Ptr mappedFile = io::getMappedFilePtr(is);
1381  const bool delayLoad = ((mappedFile.get() != nullptr) && clipBBox.isInside(nodeBBox));
1382 
1383  if (delayLoad) {
1384  mBuffer.setOutOfCore(true);
1385  mBuffer.mFileInfo = new typename Buffer::FileInfo;
1386  mBuffer.mFileInfo->meta = meta;
1387  mBuffer.mFileInfo->bufpos = is.tellg();
1388  mBuffer.mFileInfo->mapping = mappedFile;
1389  // Save the offset to the value mask, because the in-memory copy
1390  // might change before the value buffer gets read.
1391  mBuffer.mFileInfo->maskpos = maskpos;
1392  // Skip over voxel values.
1393  skipCompressedValues(seekable, is, fromHalf);
1394  } else {
1395 #endif
1396  mBuffer.allocate();
1397  io::readCompressedValues(is, mBuffer.mData, SIZE, mValueMask, fromHalf);
1398  mBuffer.setOutOfCore(false);
1399 
1400  // Get this tree's background value.
1401  T background = zeroVal<T>();
1402  if (const void* bgPtr = io::getGridBackgroundValuePtr(is)) {
1403  background = *static_cast<const T*>(bgPtr);
1404  }
1405  this->clip(clipBBox, background);
1406 #ifdef OPENVDB_USE_DELAYED_LOADING
1407  }
1408 #endif
1409  }
1410 
1411  if (numBuffers > 1) {
1412  // Read in and discard auxiliary buffers that were created with earlier
1413  // versions of the library. (Auxiliary buffers are not mask compressed.)
1414  const bool zipped = io::getDataCompression(is) & io::COMPRESS_ZIP;
1415  Buffer temp;
1416  for (int i = 1; i < numBuffers; ++i) {
1417  if (fromHalf) {
1418  io::HalfReader<io::RealToHalf<T>::isReal, T>::read(is, temp.mData, SIZE, zipped);
1419  } else {
1420  io::readData<T>(is, temp.mData, SIZE, zipped);
1421  }
1422  }
1423  }
1424 
1425  // increment the leaf number
1426  if (meta) meta->setLeaf(meta->leaf() + 1);
1427 }
1428 
1429 
1430 template<typename T, Index Log2Dim>
1431 inline void
1432 LeafNode<T, Log2Dim>::writeBuffers(std::ostream& os, bool toHalf) const
1433 {
1434  // Write out the value mask.
1435  mValueMask.save(os);
1436 
1437  mBuffer.loadValues();
1438 
1439  io::writeCompressedValues(os, mBuffer.mData, SIZE,
1440  mValueMask, /*childMask=*/NodeMaskType(), toHalf);
1441 }
1442 
1443 
1444 ////////////////////////////////////////
1445 
1446 
1447 template<typename T, Index Log2Dim>
1448 inline bool
1450 {
1451  return mOrigin == other.mOrigin &&
1452  mValueMask == other.valueMask() &&
1453  mBuffer == other.mBuffer;
1454 }
1455 
1456 
1457 template<typename T, Index Log2Dim>
1458 inline Index64
1460 {
1461  // Use sizeof(*this) to capture alignment-related padding
1462  // (but note that sizeof(*this) includes sizeof(mBuffer)).
1463  return sizeof(*this) + mBuffer.memUsage() - sizeof(mBuffer);
1464 }
1465 
1466 
1467 template<typename T, Index Log2Dim>
1468 inline Index64
1470 {
1471  // Use sizeof(*this) to capture alignment-related padding
1472  // (but note that sizeof(*this) includes sizeof(mBuffer)).
1473  return sizeof(*this) + mBuffer.memUsageIfLoaded() - sizeof(mBuffer);
1474 }
1475 
1476 
1477 template<typename T, Index Log2Dim>
1478 inline void
1479 LeafNode<T, Log2Dim>::evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels) const
1480 {
1481  CoordBBox this_bbox = this->getNodeBoundingBox();
1482  if (bbox.isInside(this_bbox)) return;//this LeafNode is already enclosed in the bbox
1483  if (ValueOnCIter iter = this->cbeginValueOn()) {//any active values?
1484  if (visitVoxels) {//use voxel granularity?
1485  this_bbox.reset();
1486  for(; iter; ++iter) this_bbox.expand(this->offsetToLocalCoord(iter.pos()));
1487  this_bbox.translate(this->origin());
1488  }
1489  bbox.expand(this_bbox);
1490  }
1491 }
1492 
1493 
1494 template<typename T, Index Log2Dim>
1495 template<typename OtherType, Index OtherLog2Dim>
1496 inline bool
1498 {
1499  OPENVDB_ASSERT(other);
1500  return (Log2Dim == OtherLog2Dim && mValueMask == other->getValueMask());
1501 }
1502 
1503 template<typename T, Index Log2Dim>
1504 inline bool
1506  bool& state,
1507  const ValueType& tolerance) const
1508 {
1509  if (!mValueMask.isConstant(state)) return false;// early termination
1510  firstValue = mBuffer[0];
1511  for (Index i = 1; i < SIZE; ++i) {
1512  if ( !math::isApproxEqual(mBuffer[i], firstValue, tolerance) ) return false;// early termination
1513  }
1514  return true;
1515 }
1516 
1517 template<typename T, Index Log2Dim>
1518 inline bool
1520  ValueType& maxValue,
1521  bool& state,
1522  const ValueType& tolerance) const
1523 {
1524  if (!mValueMask.isConstant(state)) return false;// early termination
1525  minValue = maxValue = mBuffer[0];
1526  for (Index i = 1; i < SIZE; ++i) {
1527  const T& v = mBuffer[i];
1528  if (v < minValue) {
1529  if ((maxValue - v) > tolerance) return false;// early termination
1530  minValue = v;
1531  } else if (v > maxValue) {
1532  if ((v - minValue) > tolerance) return false;// early termination
1533  maxValue = v;
1534  }
1535  }
1536  return true;
1537 }
1538 
1539 template<typename T, Index Log2Dim>
1540 inline T
1542 {
1543  std::unique_ptr<T[]> data(nullptr);
1544  if (tmp == nullptr) {//allocate temporary storage
1545  data.reset(new T[NUM_VALUES]);
1546  tmp = data.get();
1547  }
1548  if (tmp != mBuffer.data()) {
1549  const T* src = mBuffer.data();
1550  for (T* dst = tmp; dst-tmp < NUM_VALUES;) *dst++ = *src++;
1551  }
1552  static const size_t midpoint = (NUM_VALUES - 1) >> 1;
1553  std::nth_element(tmp, tmp + midpoint, tmp + NUM_VALUES);
1554  return tmp[midpoint];
1555 }
1556 
1557 template<typename T, Index Log2Dim>
1558 inline Index
1559 LeafNode<T, Log2Dim>::medianOn(T &value, T *tmp) const
1560 {
1561  const Index count = mValueMask.countOn();
1562  if (count == NUM_VALUES) {//special case: all voxels are active
1563  value = this->medianAll(tmp);
1564  return NUM_VALUES;
1565  } else if (count == 0) {
1566  return 0;
1567  }
1568  std::unique_ptr<T[]> data(nullptr);
1569  if (tmp == nullptr) {//allocate temporary storage
1570  data.reset(new T[count]);// 0 < count < NUM_VALUES
1571  tmp = data.get();
1572  }
1573  for (auto iter=this->cbeginValueOn(); iter; ++iter) *tmp++ = *iter;
1574  T *begin = tmp - count;
1575  const size_t midpoint = (count - 1) >> 1;
1576  std::nth_element(begin, begin + midpoint, tmp);
1577  value = begin[midpoint];
1578  return count;
1579 }
1580 
1581 template<typename T, Index Log2Dim>
1582 inline Index
1583 LeafNode<T, Log2Dim>::medianOff(T &value, T *tmp) const
1584 {
1585  const Index count = mValueMask.countOff();
1586  if (count == NUM_VALUES) {//special case: all voxels are inactive
1587  value = this->medianAll(tmp);
1588  return NUM_VALUES;
1589  } else if (count == 0) {
1590  return 0;
1591  }
1592  std::unique_ptr<T[]> data(nullptr);
1593  if (tmp == nullptr) {//allocate temporary storage
1594  data.reset(new T[count]);// 0 < count < NUM_VALUES
1595  tmp = data.get();
1596  }
1597  for (auto iter=this->cbeginValueOff(); iter; ++iter) *tmp++ = *iter;
1598  T *begin = tmp - count;
1599  const size_t midpoint = (count - 1) >> 1;
1600  std::nth_element(begin, begin + midpoint, tmp);
1601  value = begin[midpoint];
1602  return count;
1603 }
1604 
1605 ////////////////////////////////////////
1606 
1607 
1608 template<typename T, Index Log2Dim>
1609 inline void
1610 LeafNode<T, Log2Dim>::addTile(Index /*level*/, const Coord& xyz, const ValueType& val, bool active)
1611 {
1612  this->addTile(this->coordToOffset(xyz), val, active);
1613 }
1614 
1615 template<typename T, Index Log2Dim>
1616 inline void
1617 LeafNode<T, Log2Dim>::addTile(Index offset, const ValueType& val, bool active)
1618 {
1619  OPENVDB_ASSERT(offset < SIZE);
1620  setValueOnly(offset, val);
1621  setActiveState(offset, active);
1622 }
1623 
1624 template<typename T, Index Log2Dim>
1625 template<typename AccessorT>
1626 inline void
1628  const ValueType& val, bool active, AccessorT&)
1629 {
1630  this->addTile(level, xyz, val, active);
1631 }
1632 
1633 
1634 ////////////////////////////////////////
1635 
1636 
1637 template<typename T, Index Log2Dim>
1638 inline void
1640  const ValueType& newBackground)
1641 {
1642  if (!this->allocate()) return;
1643  if (math::isExactlyEqual(oldBackground, newBackground)) return;
1644 
1645  typename NodeMaskType::OffIterator iter;
1646  // For all inactive values...
1647  for (iter = this->mValueMask.beginOff(); iter; ++iter) {
1648  ValueType &inactiveValue = mBuffer[iter.pos()];
1649  if (math::isApproxEqual(inactiveValue, oldBackground)) {
1650  inactiveValue = newBackground;
1651  } else if (math::isApproxEqual(inactiveValue, math::negative(oldBackground))) {
1652  inactiveValue = math::negative(newBackground);
1653  }
1654  }
1655 }
1656 
1657 
1658 template<typename T, Index Log2Dim>
1659 template<MergePolicy Policy>
1660 inline void
1662 {
1663  if (!this->allocate()) return;
1664 
1666  if (Policy == MERGE_NODES) return;
1667  typename NodeMaskType::OnIterator iter = other.valueMask().beginOn();
1668  for (; iter; ++iter) {
1669  const Index n = iter.pos();
1670  if (mValueMask.isOff(n)) {
1671  mBuffer[n] = other.mBuffer[n];
1672  mValueMask.setOn(n);
1673  }
1674  }
1676 }
1677 
1678 template<typename T, Index Log2Dim>
1679 template<MergePolicy Policy>
1680 inline void
1682  const ValueType& /*bg*/, const ValueType& /*otherBG*/)
1683 {
1684  this->template merge<Policy>(other);
1685 }
1686 
1687 template<typename T, Index Log2Dim>
1688 template<MergePolicy Policy>
1689 inline void
1690 LeafNode<T, Log2Dim>::merge(const ValueType& tileValue, bool tileActive)
1691 {
1692  if (!this->allocate()) return;
1693 
1695  if (Policy != MERGE_ACTIVE_STATES_AND_NODES) return;
1696  if (!tileActive) return;
1697  // Replace all inactive values with the active tile value.
1698  for (typename NodeMaskType::OffIterator iter = mValueMask.beginOff(); iter; ++iter) {
1699  const Index n = iter.pos();
1700  mBuffer[n] = tileValue;
1701  mValueMask.setOn(n);
1702  }
1704 }
1705 
1706 
1707 template<typename T, Index Log2Dim>
1708 template<typename OtherType>
1709 inline void
1711 {
1712  mValueMask |= other.valueMask();
1713 }
1714 
1715 template<typename T, Index Log2Dim>
1716 template<typename OtherType>
1717 inline void
1719  const ValueType&)
1720 {
1721  mValueMask &= other.valueMask();
1722 }
1723 
1724 template<typename T, Index Log2Dim>
1725 template<typename OtherType>
1726 inline void
1728  const ValueType&)
1729 {
1730  mValueMask &= !other.valueMask();
1731 }
1732 
1733 template<typename T, Index Log2Dim>
1734 inline void
1736 {
1737  if (!this->allocate()) return;
1738 
1739  for (Index i = 0; i < SIZE; ++i) {
1740  mBuffer[i] = -mBuffer[i];
1741  }
1742 }
1743 
1744 
1745 ////////////////////////////////////////
1746 
1747 
1748 template<typename T, Index Log2Dim>
1749 template<typename CombineOp>
1750 inline void
1751 LeafNode<T, Log2Dim>::combine(const LeafNode& other, CombineOp& op)
1752 {
1753  if (!this->allocate()) return;
1754 
1755  CombineArgs<T> args;
1756  for (Index i = 0; i < SIZE; ++i) {
1757  op(args.setARef(mBuffer[i])
1758  .setAIsActive(mValueMask.isOn(i))
1759  .setBRef(other.mBuffer[i])
1760  .setBIsActive(other.valueMask().isOn(i))
1761  .setResultRef(mBuffer[i]));
1762  mValueMask.set(i, args.resultIsActive());
1763  }
1764 }
1765 
1766 
1767 template<typename T, Index Log2Dim>
1768 template<typename CombineOp>
1769 inline void
1770 LeafNode<T, Log2Dim>::combine(const ValueType& value, bool valueIsActive, CombineOp& op)
1771 {
1772  if (!this->allocate()) return;
1773 
1774  CombineArgs<T> args;
1775  args.setBRef(value).setBIsActive(valueIsActive);
1776  for (Index i = 0; i < SIZE; ++i) {
1777  op(args.setARef(mBuffer[i])
1778  .setAIsActive(mValueMask.isOn(i))
1779  .setResultRef(mBuffer[i]));
1780  mValueMask.set(i, args.resultIsActive());
1781  }
1782 }
1783 
1784 
1785 ////////////////////////////////////////
1786 
1787 
1788 template<typename T, Index Log2Dim>
1789 template<typename CombineOp, typename OtherType>
1790 inline void
1791 LeafNode<T, Log2Dim>::combine2(const LeafNode& other, const OtherType& value,
1792  bool valueIsActive, CombineOp& op)
1793 {
1794  if (!this->allocate()) return;
1795 
1797  args.setBRef(value).setBIsActive(valueIsActive);
1798  for (Index i = 0; i < SIZE; ++i) {
1799  op(args.setARef(other.mBuffer[i])
1800  .setAIsActive(other.valueMask().isOn(i))
1801  .setResultRef(mBuffer[i]));
1802  mValueMask.set(i, args.resultIsActive());
1803  }
1804 }
1805 
1806 
1807 template<typename T, Index Log2Dim>
1808 template<typename CombineOp, typename OtherNodeT>
1809 inline void
1810 LeafNode<T, Log2Dim>::combine2(const ValueType& value, const OtherNodeT& other,
1811  bool valueIsActive, CombineOp& op)
1812 {
1813  if (!this->allocate()) return;
1814 
1816  args.setARef(value).setAIsActive(valueIsActive);
1817  for (Index i = 0; i < SIZE; ++i) {
1818  op(args.setBRef(other.mBuffer[i])
1819  .setBIsActive(other.valueMask().isOn(i))
1820  .setResultRef(mBuffer[i]));
1821  mValueMask.set(i, args.resultIsActive());
1822  }
1823 }
1824 
1825 
1826 template<typename T, Index Log2Dim>
1827 template<typename CombineOp, typename OtherNodeT>
1828 inline void
1829 LeafNode<T, Log2Dim>::combine2(const LeafNode& b0, const OtherNodeT& b1, CombineOp& op)
1830 {
1831  if (!this->allocate()) return;
1832 
1834  for (Index i = 0; i < SIZE; ++i) {
1835  mValueMask.set(i, b0.valueMask().isOn(i) || b1.valueMask().isOn(i));
1836  op(args.setARef(b0.mBuffer[i])
1837  .setAIsActive(b0.valueMask().isOn(i))
1838  .setBRef(b1.mBuffer[i])
1839  .setBIsActive(b1.valueMask().isOn(i))
1840  .setResultRef(mBuffer[i]));
1841  mValueMask.set(i, args.resultIsActive());
1842  }
1843 }
1844 
1845 
1846 ////////////////////////////////////////
1847 
1848 
1849 template<typename T, Index Log2Dim>
1850 inline std::ostream&
1851 operator<<(std::ostream& os, const typename LeafNode<T, Log2Dim>::Buffer& buf)
1852 {
1853  for (Index32 i = 0, N = buf.size(); i < N; ++i) os << buf.mData[i] << ", ";
1854  return os;
1855 }
1856 
1857 } // namespace tree
1858 } // namespace OPENVDB_VERSION_NAME
1859 } // namespace openvdb
1860 
1861 
1862 ////////////////////////////////////////
1863 
1864 
1865 // Specialization for LeafNodes of type bool
1866 #include "LeafNodeBool.h"
1867 
1868 // Specialization for LeafNodes with mask information only
1869 #include "LeafNodeMask.h"
1870 
1871 #endif // OPENVDB_TREE_LEAFNODE_HAS_BEEN_INCLUDED
void seek(std::istream &is) const
Definition: NodeMasks.h:570
ValueAllIter endValueAll()
Definition: LeafNode.h:318
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:443
void setValueOffUnsafe(Index offset, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: LeafNode.h:855
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:38
const LeafNode * probeLeaf(const Coord &) const
Return a const pointer to this node.
Definition: LeafNode.h:745
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
bool isValueOnAndCache(const Coord &xyz, AccessorT &) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNode.h:550
void setValueAndCache(const Coord &xyz, const ValueType &val, AccessorT &)
Change the value of the voxel at the given coordinates and mark it as active.
Definition: LeafNode.h:555
ValueType medianAll(ValueType *tmp=nullptr) const
Computes the median value of all the active AND inactive voxels in this node.
Definition: LeafNode.h:1541
void nodeCount(std::vector< Index64 > &) const
no-op
Definition: LeafNode.h:134
void readBuffers(std::istream &is, bool fromHalf=false)
Read buffers from a stream.
Definition: LeafNode.h:1334
LeafNode * touchLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: LeafNode.h:725
ChildAllIter endChildAll()
Definition: LeafNode.h:340
bool getItem(Index pos, void *&child, NonConstValueT &value) const
Definition: LeafNode.h:269
static Index dim()
Return the number of voxels in each coordinate dimension.
Definition: LeafNode.h:120
void getNodes(ArrayT &) const
This function exists only to enable template instantiation.
Definition: LeafNode.h:712
ValueOnCIter cbeginValueOn() const
Definition: LeafNode.h:300
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
Definition: LeafNode.h:459
bool isValueMaskOn() const
Definition: LeafNode.h:881
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:568
ValueOnCIter endValueOn() const
Definition: LeafNode.h:311
bool operator==(const LeafNode &other) const
Check for buffer, state and origin equivalence.
Definition: LeafNode.h:1449
Index32 pos() const
Definition: NodeMasks.h:200
Base class for iterators over internal and leaf nodes.
Definition: Iterator.h:29
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: LeafNode.h:1234
LeafNode()
Default constructor.
Definition: LeafNode.h:932
void setItem(Index pos, const ValueT &value) const
Definition: LeafNode.h:231
ValueOnCIter beginValueOn() const
Definition: LeafNode.h:301
void readTopology(std::istream &is, bool fromHalf=false)
Read in just the topology.
Definition: LeafNode.h:1298
void voxelizeActiveTiles(bool=true)
No-op.
Definition: LeafNode.h:644
ValueIter()
Definition: LeafNode.h:224
Index64 memUsageIfLoaded(const TreeT &tree, bool threaded=true)
Return the deserialized memory usage of this tree. This is not necessarily equal to the current memor...
Definition: Count.h:502
void addLeafAndCache(LeafNode *, AccessorT &)
This function exists only to enable template instantiation.
Definition: LeafNode.h:705
Definition: LeafNode.h:23
void modifyValue(Index offset, const ModifyOp &op)
Apply a functor to the value of the voxel at the given offset and mark the voxel as active...
Definition: LeafNode.h:438
const LeafNode * probeLeafAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: LeafNode.h:744
Buffer & buffer()
Definition: LeafNode.h:349
uint64_t Index64
Definition: Types.h:53
bool resultIsActive() const
Definition: Types.h:632
void setOn(Index32 n)
Set the nth bit on.
Definition: NodeMasks.h:452
void topologyIntersection(const LeafNode< OtherType, Log2Dim > &other, const ValueType &)
Intersect 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 both of the original voxels were active.
Definition: LeafNode.h:1718
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don&#39;t change its value.
Definition: LeafNode.h:410
CoordBBox getNodeBoundingBox() const
Return the bounding box of this node, i.e., the full index space spanned by this leaf node...
Definition: LeafNode.h:170
ValueOffCIter beginValueOff() const
Definition: LeafNode.h:304
void setValueMaskOn(Index n)
Definition: LeafNode.h:893
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: LeafNode.h:1125
ValueOffCIter cendValueOff() const
Definition: LeafNode.h:313
void modifyValueAndActiveStateAndCache(const Coord &xyz, const ModifyOp &op, AccessorT &)
Definition: LeafNode.h:581
ValueOffCIter cbeginValueOff() const
Definition: LeafNode.h:303
bool isAllocated() const
Return true if memory for this node&#39;s buffer has been allocated.
Definition: LeafNode.h:155
Index memUsageIfLoaded() const
Definition: LeafBuffer.h:337
static const Index DIM
Definition: LeafNode.h:51
void combine(const LeafNode &other, CombineOp &op)
Definition: LeafNode.h:1751
ValueT & getValue() const
Definition: LeafNode.h:228
void setValue(const Coord &xyz, const ValueType &val)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: LeafNode.h:428
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: LeafNode.h:1075
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation. ...
Definition: NodeMasks.h:307
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don&#39;t change its value.
Definition: LeafNode.h:420
Definition: NodeMasks.h:270
const LeafNode * probeConstLeafAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: LeafNode.h:742
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 setValueMask(const NodeMaskType &mask)
Definition: LeafNode.h:887
bool isChildMaskOff() const
Definition: LeafNode.h:890
void copyFromDense(const CoordBBox &bbox, const DenseT &dense, const ValueType &background, const ValueType &tolerance)
Copy from a dense grid into this node the values of the voxels that lie within a given bounding box...
Definition: LeafNode.h:1261
Definition: NodeMasks.h:239
NodeT * probeNodeAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: LeafNode.h:727
static Coord offsetToLocalCoord(Index n)
Return the local coordinates for a linear table offset, where offset 0 has coordinates (0...
Definition: LeafNode.h:1050
typename NodeMaskType::OnIterator MaskOnIterator
Definition: LeafNode.h:207
void resetBackground(const ValueType &oldBackground, const ValueType &newBackground)
Replace inactive occurrences of oldBackground with newBackground, and inactive occurrences of -oldBac...
Definition: LeafNode.h:1639
Definition: Coord.h:590
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
ValueOnCIter cendValueOn() const
Definition: LeafNode.h:310
void setValueOffUnsafe(Index offset)
Mark the voxel at the given offset as inactive but don&#39;t change its value.
Definition: LeafNode.h:853
void setValueOnlyUnsafe(Index offset, const ValueType &value)
Set the value of the voxel at the given coordinates but don&#39;t change its active state.
Definition: LeafNode.h:847
bool isValueMaskOff(Index n) const
Definition: LeafNode.h:882
static const Index SIZE
Definition: LeafNode.h:54
void modifyValue(const ModifyOp &op) const
Definition: LeafNode.h:246
Index memUsage() const
Return the memory footprint of this buffer in bytes.
Definition: LeafBuffer.h:320
LeafNode * touchLeaf(const Coord &)
Return a pointer to this node.
Definition: LeafNode.h:723
void addLeaf(LeafNode *)
This function exists only to enable template instantiation.
Definition: LeafNode.h:703
typename NodeMaskType::OffIterator MaskOffIterator
Definition: LeafNode.h:208
Definition: Compression.h:55
int32_t Int32
Definition: Types.h:56
const ValueType & getValueAndCache(const Coord &xyz, AccessorT &) const
Return the value of the voxel at the given coordinates.
Definition: LeafNode.h:542
static Index64 leafCount()
Return the leaf count for this node, which is one.
Definition: LeafNode.h:132
ValueOffIter beginValueOff()
Definition: LeafNode.h:305
Index32 Index
Definition: Types.h:54
const Coord & origin() const
Return the grid index coordinates of this node&#39;s local origin.
Definition: LeafNode.h:176
void setValueOnUnsafe(Index offset)
Mark the voxel at the given offset as active but don&#39;t change its value.
Definition: LeafNode.h:849
void setValuesOff()
Mark all voxels as inactive but don&#39;t change their values.
Definition: LeafNode.h:475
OutGridT XformOp & op
Definition: ValueTransformer.h:139
const ValueType & getValue(const Coord &xyz, bool &state, int &level, AccessorT &) const
Return the value of the voxel at the given coordinates and return its active state and level (i...
Definition: LeafNode.h:616
Index32 transientData() const
Return the transient data value.
Definition: LeafNode.h:190
typename NodeMaskType::DenseIterator MaskDenseIterator
Definition: LeafNode.h:209
void denseFill(const CoordBBox &bbox, const ValueType &value, bool active=true)
Set all voxels within an axis-aligned box to the specified value and active state.
Definition: LeafNode.h:495
ValueOffIter endValueOff()
Definition: LeafNode.h:315
ValueOffCIter endValueOff() const
Definition: LeafNode.h:314
bool getValueUnsafe(Index offset, ValueType &value) const
Return true if the voxel at the given offset is active and set value.
Definition: LeafNode.h:843
void setValuesOn()
Mark all voxels as active but don&#39;t change their values.
Definition: LeafNode.h:473
void merge(const LeafNode &)
Definition: LeafNode.h:1661
static void getNodeLog2Dims(std::vector< Index > &dims)
Append the Log2Dim of this LeafNode to the specified vector.
Definition: LeafNode.h:128
void addTile(Index level, const Coord &, const ValueType &, bool)
Definition: LeafNode.h:1610
Index64 onLeafVoxelCount() const
Definition: LeafNode.h:146
void getOrigin(Int32 &x, Int32 &y, Int32 &z) const
Return the grid index coordinates of this node&#39;s local origin.
Definition: LeafNode.h:178
void setValueOffAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
Change the value of the voxel at the given coordinates and mark it as inactive.
Definition: LeafNode.h:589
static Index coordToOffset(const Coord &xyz)
Return the linear table offset of the given global or local coordinates.
Definition: LeafNode.h:1040
Index64 memUsage() const
Return the memory in bytes occupied by this node.
Definition: LeafNode.h:1459
Definition: LeafNode.h:213
bool isChildMaskOff(Index) const
Definition: LeafNode.h:889
void set(Index32 n, bool On)
Set the nth bit to the specified state.
Definition: NodeMasks.h:462
bool operator==(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Equality operator, does exact floating point comparisons.
Definition: Vec3.h:474
void evalActiveBoundingBox(CoordBBox &bbox, bool visitVoxels=true) const
Definition: LeafNode.h:1479
ChildAllCIter cbeginChildAll() const
Definition: LeafNode.h:328
static const Index LOG2DIM
Definition: LeafNode.h:49
OutGridT XformOp bool bool MergePolicy merge
Definition: ValueTransformer.h:141
ChildOnCIter endChildOn() const
Definition: LeafNode.h:333
ChildOnIter endChildOn()
Definition: LeafNode.h:334
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:128
bool operator!=(const LeafNode &other) const
Definition: LeafNode.h:204
ChildIter()
Definition: LeafNode.h:254
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: LeafNode.h:573
void setValueMask(Index n, bool on)
Definition: LeafNode.h:892
LeafNode * probeLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: LeafNode.h:736
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: LeafNode.h:452
static Index64 offTileCount()
Definition: LeafNode.h:149
ChildOffCIter beginChildOff() const
Definition: LeafNode.h:326
CombineArgs & setBRef(const BValueType &b)
Redirect the B value to a new external source.
Definition: Types.h:623
void setValueOnly(const Coord &xyz, const ValueType &val)
Set the value of the voxel at the given coordinates but don&#39;t change its active state.
Definition: LeafNode.h:1133
Definition: Compression.h:293
void writeBuffers(std::ostream &os, bool toHalf=false) const
Write buffers to a stream.
Definition: LeafNode.h:1432
Definition: NodeMasks.h:208
Index64 memUsage(const TreeT &tree, bool threaded=true)
Return the total amount of memory in bytes occupied by this tree.
Definition: Count.h:493
Index64 onVoxelCount() const
Return the number of voxels marked On.
Definition: LeafNode.h:143
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 topologyDifference(const LeafNode< OtherType, Log2Dim > &other, const ValueType &)
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 LeafNode and inactive in the other LeafNode.
Definition: LeafNode.h:1727
ChildOffIter beginChildOff()
Definition: LeafNode.h:327
ChildOffCIter cendChildOff() const
Definition: LeafNode.h:335
std::shared_ptr< T > SharedPtr
Definition: Types.h:114
const Buffer & buffer() const
Definition: LeafNode.h:348
#define OPENVDB_ASSERT(X)
Definition: Assert.h:41
bool hasSameTopology(const LeafNode< OtherType, OtherLog2Dim > *other) const
Return true if the given node (which may have a different ValueType than this node) has the same acti...
Definition: LeafNode.h:1497
static Index getChildDim()
Return the dimension of child nodes of this LeafNode, which is one for voxels.
Definition: LeafNode.h:130
static void evalNodeOrigin(Coord &xyz)
Compute the origin of the leaf node that contains the voxel with the given coordinates.
Definition: LeafNode.h:899
ValueOnIter beginValueOn()
Definition: LeafNode.h:302
T BuildType
Definition: LeafNode.h:41
Definition: Types.h:508
Leaf nodes have no children, so their child iterators have no get/set accessors.
Definition: LeafNode.h:251
void writeTopology(std::ostream &os, bool toHalf=false) const
Write out just the topology.
Definition: LeafNode.h:1306
static const Index NUM_VALUES
Definition: LeafNode.h:52
void skipCompressedValues(bool seekable, std::istream &, bool fromHalf)
Definition: LeafNode.h:1318
ChildOffCIter endChildOff() const
Definition: LeafNode.h:336
void setTransientData(Index32 transientData)
Set the transient data value.
Definition: LeafNode.h:192
static bool hasActiveTiles()
Return false since leaf nodes never contain tiles.
Definition: LeafNode.h:487
ChildOnCIter cbeginChildOn() const
Definition: LeafNode.h:322
void swap(Buffer &other)
Exchange this node&#39;s data buffer with the given data buffer without changing the active states of the...
Definition: LeafNode.h:347
ChildOnCIter beginChildOn() const
Definition: LeafNode.h:323
void setValueOff(Index offset)
Mark the voxel at the given offset as inactive but don&#39;t change its value.
Definition: LeafNode.h:412
void negate()
Definition: LeafNode.h:1735
void setValue(Index i, const ValueType &)
Set the i&#39;th value of this buffer to the specified value.
Definition: LeafBuffer.h:233
Definition: Exceptions.h:13
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition: Platform.h:140
typename BaseT::NonConstValueType NonConstValueT
Definition: LeafNode.h:264
Index medianOn(ValueType &value, ValueType *tmp=nullptr) const
Computes the median value of all the active voxels in this node.
Definition: LeafNode.h:1559
Index32 countOn() const
Return the total number of on bits.
Definition: NodeMasks.h:443
const NodeT * probeConstNode(const Coord &) const
This function exists only to enable template instantiation.
Definition: LeafNode.h:711
static Index64 onTileCount()
Definition: LeafNode.h:148
static Index size()
Return the total number of voxels represented by this LeafNode.
Definition: LeafNode.h:122
static Index log2dim()
Return log2 of the dimension of this LeafNode, e.g. 3 if dimensions are 8^3.
Definition: LeafNode.h:118
bool isValueMaskOn(Index n) const
Definition: LeafNode.h:880
bool isValueMaskOff() const
Definition: LeafNode.h:883
void setActiveState(Index offset, bool on)
Set the active state of the voxel at the given offset but don&#39;t change its value. ...
Definition: LeafNode.h:402
std::string str() const
Return a string representation of this node.
Definition: LeafNode.h:1027
bool isOn(Index32 n) const
Return true if the nth bit is on.
Definition: NodeMasks.h:502
static Index getValueLevel(const Coord &)
Return the level (i.e., 0) at which leaf node values reside.
Definition: LeafNode.h:397
SameConfiguration<OtherNodeType>::value is true if and only if OtherNodeType is the type of a LeafNod...
Definition: LeafNode.h:65
bool isConstant(bool &isOn) const
Definition: NodeMasks.h:526
void setValueOn(const Coord &xyz, const ValueType &val)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: LeafNode.h:424
bool isValueOn(const Coord &xyz) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNode.h:478
ValueT & getItem(Index pos) const
Definition: LeafNode.h:227
void setValue(const ValueT &value) const
Definition: LeafNode.h:236
void addTileAndCache(Index, const Coord &, const ValueType &, bool, AccessorT &)
Definition: LeafNode.h:1627
bool isEmpty() const
Return true if this node has no active voxels.
Definition: LeafNode.h:151
void prune(const ValueType &=zeroVal< ValueType >())
This function exists only to enable template instantiation.
Definition: LeafNode.h:702
ValueAllCIter cbeginValueAll() const
Definition: LeafNode.h:306
bool isValueOff(Index offset) const
Return true if the voxel at the given offset is inactive.
Definition: LeafNode.h:484
ValueIter(const MaskIterT &iter, NodeT *parent)
Definition: LeafNode.h:225
Index64 memUsageIfLoaded() const
Definition: LeafNode.h:1469
ChildAllIter beginChildAll()
Definition: LeafNode.h:330
ChildAllCIter endChildAll() const
Definition: LeafNode.h:339
DenseIter(const MaskDenseIterator &iter, NodeT *parent)
Definition: LeafNode.h:267
void copyFromDense(const DenseT &dense, GridOrTreeT &sparse, const typename GridOrTreeT::ValueType &tolerance, bool serial=false)
Populate a sparse grid with the values of all of the voxels of a dense grid.
Definition: Dense.h:569
ChildAllCIter cendChildAll() const
Definition: LeafNode.h:338
bool probeValue(const Coord &xyz, ValueType &val) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNode.h:1091
OnIterator beginOn() const
Definition: NodeMasks.h:352
OffIterator beginOff() const
Definition: NodeMasks.h:354
static Index32 childCount()
Return the child count for this node, which is zero.
Definition: LeafNode.h:140
OPENVDB_API SharedPtr< StreamMetadata > getStreamMetadataPtr(std::ios_base &)
Return a shared pointer to an object that stores metadata (file format, compression scheme...
const NodeMaskType & getValueMask() const
Definition: LeafNode.h:884
ValueAllCIter beginValueAll() const
Definition: LeafNode.h:307
uint32_t Index32
Definition: Types.h:52
Index64 offVoxelCount() const
Return the number of voxels marked Off.
Definition: LeafNode.h:145
Definition: LeafNode.h:212
void setOrigin(const Coord &origin)
Set the grid index coordinates of this node&#39;s local origin.
Definition: LeafNode.h:173
Coord offsetToGlobalCoord(Index n) const
Return the global coordinates for a linear table offset.
Definition: LeafNode.h:1064
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:141
void setValueOnlyAndCache(const Coord &xyz, const ValueType &val, AccessorT &)
Change the value of the voxel at the given coordinates but preserve its state.
Definition: LeafNode.h:564
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...
bool isConstant(ValueType &firstValue, bool &state, const ValueType &tolerance=zeroVal< ValueType >()) const
Definition: LeafNode.h:1505
const NodeT * probeConstNodeAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: LeafNode.h:747
ValueAllCIter cendValueAll() const
Definition: LeafNode.h:316
Index32 countOff() const
Return the total number of on bits.
Definition: NodeMasks.h:450
static Index numValues()
Return the total number of voxels represented by this LeafNode.
Definition: LeafNode.h:124
void unsetItem(Index pos, const ValueT &value) const
Definition: LeafNode.h:280
SharedPtr< LeafNode > Ptr
Definition: LeafNode.h:46
void topologyUnion(const LeafNode< OtherType, Log2Dim > &other, const bool preserveTiles=false)
Union this node&#39;s set of active values with the active values of the other node, whose ValueType may ...
Definition: LeafNode.h:1710
ChildOffIter endChildOff()
Definition: LeafNode.h:337
void clip(const CoordBBox &, const ValueType &background)
Set all voxels that lie outside the given axis-aligned box to the background.
Definition: LeafNode.h:1151
typename std::remove_const< UnsetItemT >::type NonConstValueType
Definition: Iterator.h:184
const ValueType & getLastValue() const
Return a const reference to the last value in the buffer.
Definition: LeafNode.h:634
ChildOffCIter cbeginChildOff() const
Definition: LeafNode.h:325
static Index64 nonLeafCount()
Return the non-leaf count for this node, which is zero.
Definition: LeafNode.h:138
bool allocate()
Allocate memory for this buffer if it has not already been allocated.
Definition: LeafBuffer.h:83
bool isDense() const
Return true if this node contains only active voxels.
Definition: LeafNode.h:153
const NodeMaskType & valueMask() const
Definition: LeafNode.h:886
void setValueOn(Index offset, const ValueType &val)
Set the value of the voxel at the given offset and mark the voxel as active.
Definition: LeafNode.h:430
ValueOnIter endValueOn()
Definition: LeafNode.h:312
ValueConverter<T>::Type is the type of a LeafNode having the same dimensions as this node but a diffe...
Definition: LeafNode.h:60
ChildIter(const MaskIterT &iter, NodeT *parent)
Definition: LeafNode.h:255
NodeT * stealNode(const Coord &, const ValueType &, bool)
This function exists only to enable template instantiation.
Definition: LeafNode.h:707
void getOrigin(Coord &origin) const
Return the grid index coordinates of this node&#39;s local origin.
Definition: LeafNode.h:177
DenseIter()
Definition: LeafNode.h:266
const ValueType * data() const
Return a const pointer to the array of voxel values.
Definition: LeafBuffer.h:347
static Index getLevel()
Return the level of this node, which by definition is zero for LeafNodes.
Definition: LeafNode.h:126
const ValueType & getValueUnsafe(Index offset) const
Return the value of the voxel at the given offset.
Definition: LeafNode.h:841
OPENVDB_API uint32_t getFormatVersion(std::ios_base &)
Return the file format version number associated with the given input stream.
void setActiveStateUnsafe(Index offset, bool on)
Set the active state of the voxel at the given offset but don&#39;t change its value. ...
Definition: LeafNode.h:845
static Index getValueLevelAndCache(const Coord &, AccessorT &)
Return the LEVEL (=0) at which leaf node values reside.
Definition: LeafNode.h:627
void setValueOn(Index offset)
Mark the voxel at the given offset as active but don&#39;t change its value.
Definition: LeafNode.h:422
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
void stealNodes(ArrayT &, const ValueType &, bool)
This function exists only to enable template instantiation.
Definition: LeafNode.h:713
Index medianOff(ValueType &value, ValueType *tmp=nullptr) const
Computes the median value of all the inactive voxels in this node.
Definition: LeafNode.h:1583
ChildOnIter beginChildOn()
Definition: LeafNode.h:324
ValueAllIter beginValueAll()
Definition: LeafNode.h:308
T ValueType
Definition: LeafNode.h:42
LeafNode * probeLeaf(const Coord &)
Return a pointer to this node.
Definition: LeafNode.h:734
~LeafNode()
Destructor.
Definition: LeafNode.h:1020
void load(std::istream &is)
Definition: NodeMasks.h:569
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
bool probeValueAndCache(const Coord &xyz, ValueType &val, AccessorT &) const
Return true if the voxel at the given coordinates is active and return the voxel value in val...
Definition: LeafNode.h:607
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &)
Set the active state of the voxel at the given coordinates without changing its value.
Definition: LeafNode.h:598
const ValueType & getFirstValue() const
Return a const reference to the first value in the buffer.
Definition: LeafNode.h:632
ValueAllCIter endValueAll() const
Definition: LeafNode.h:317
void save(std::ostream &os) const
Definition: NodeMasks.h:565
void setOff(Index32 n)
Set the nth bit off.
Definition: NodeMasks.h:457
void combine2(const LeafNode &other, const OtherType &, bool valueIsActive, CombineOp &)
Definition: LeafNode.h:1791
NodeT * probeNode(const Coord &)
This function exists only to enable template instantiation.
Definition: LeafNode.h:709
ValueType combine(const ValueType &v0, const ValueType &v1, const ValueType &v2, const openvdb::Vec3d &w)
Combine different value types.
Definition: AttributeTransferUtil.h:141
bool isChildMaskOn(Index) const
Definition: LeafNode.h:888
void modifyItem(Index n, const ModifyOp &op) const
Definition: LeafNode.h:243
ChildOnCIter cendChildOn() const
Definition: LeafNode.h:332
Definition: PointDataGrid.h:171
Index64 offLeafVoxelCount() const
Definition: LeafNode.h:147
bool isInactive() const
Return true if all of this node&#39;s values are inactive.
Definition: LeafNode.h:832
bool isValueOff(const Coord &xyz) const
Return true if the voxel at the given coordinates is inactive.
Definition: LeafNode.h:482
Base class for dense iterators over internal and leaf nodes.
Definition: Iterator.h:178
void setValueOnUnsafe(Index offset, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: LeafNode.h:851
const LeafNode * probeConstLeaf(const Coord &) const
Return a const pointer to this node.
Definition: LeafNode.h:740
OPENVDB_API uint32_t getDataCompression(std::ios_base &)
Return a bitwise OR of compression option flags (COMPRESS_ZIP, COMPRESS_ACTIVE_MASK, etc.) specifying whether and how input data is compressed or output data should be compressed.
#define OPENVDB_DEPRECATED_MESSAGE(msg)
Definition: Platform.h:148
void fill(const ValueType &)
Populate this buffer with a constant value.
Definition: LeafBuffer.h:275
void fill(const CoordBBox &bbox, const ValueType &, bool active=true)
Set all voxels within an axis-aligned box to the specified value and active state.
Definition: LeafNode.h:1191
void writeCompressedValues(std::ostream &os, ValueT *srcBuf, Index srcCount, const MaskT &valueMask, const MaskT &childMask, bool toHalf)
Definition: Compression.h:646
bool isOff(Index32 n) const
Return true if the nth bit is off.
Definition: NodeMasks.h:508
bool allocate()
Allocate memory for this node&#39;s buffer if it has not already been allocated.
Definition: LeafNode.h:157
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:218
Base class for sparse iterators over internal and leaf nodes.
Definition: Iterator.h:114
ChildAllCIter beginChildAll() const
Definition: LeafNode.h:329
void setValueMaskOff(Index n)
Definition: LeafNode.h:894
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:689
NodeMaskType & getValueMask()
Definition: LeafNode.h:885
bool isValueOn(Index offset) const
Return true if the voxel at the given offset is active.
Definition: LeafNode.h:480