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