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 
1372  const bool seekable = meta && meta->seekable();
1373 
1374 #ifdef OPENVDB_USE_DELAYED_LOADING
1375  std::streamoff maskpos = is.tellg();
1376 #endif
1377 
1378  if (seekable) {
1379  // Seek over the value mask.
1380  mValueMask.seek(is);
1381  } else {
1382  // Read in the value mask.
1383  mValueMask.load(is);
1384  }
1385 
1386  int8_t numBuffers = 1;
1388  // Read in the origin.
1389  is.read(reinterpret_cast<char*>(&mOrigin), sizeof(Coord::ValueType) * 3);
1390 
1391  // Read in the number of buffers, which should now always be one.
1392  is.read(reinterpret_cast<char*>(&numBuffers), sizeof(int8_t));
1393  }
1394 
1395  CoordBBox nodeBBox = this->getNodeBoundingBox();
1396  if (!clipBBox.hasOverlap(nodeBBox)) {
1397  // This node lies completely outside the clipping region.
1398  skipCompressedValues(seekable, is, fromHalf);
1399  mValueMask.setOff();
1400  mBuffer.setOutOfCore(false);
1401  } else {
1402 #ifdef OPENVDB_USE_DELAYED_LOADING
1403  // If this node lies completely inside the clipping region and it is being read
1404  // from a memory-mapped file, delay loading of its buffer until the buffer
1405  // is actually accessed. (If this node requires clipping, its buffer
1406  // must be accessed and therefore must be loaded.)
1407  io::MappedFile::Ptr mappedFile = io::getMappedFilePtr(is);
1408  const bool delayLoad = ((mappedFile.get() != nullptr) && clipBBox.isInside(nodeBBox));
1409 
1410  if (delayLoad) {
1411  // Save the offset to the value mask (maskpos), because the in-memory copy
1412  // might change before the value buffer gets read.
1413  mBuffer.enableOutOfCore(meta, is.tellg(), mappedFile, maskpos);
1414  // Skip over voxel values.
1415  skipCompressedValues(seekable, is, fromHalf);
1416  } else {
1417 #endif
1418  mBuffer.allocate();
1419  io::readCompressedValues(is, mBuffer.mData, SIZE, mValueMask, fromHalf);
1420  mBuffer.setOutOfCore(false);
1421 
1422  // Get this tree's background value.
1423  T background = zeroVal<T>();
1424  if (const void* bgPtr = io::getGridBackgroundValuePtr(is)) {
1425  background = *static_cast<const T*>(bgPtr);
1426  }
1427  this->clip(clipBBox, background);
1428 #ifdef OPENVDB_USE_DELAYED_LOADING
1429  }
1430 #endif
1431  }
1432 
1433  if (numBuffers > 1) {
1434  // Read in and discard auxiliary buffers that were created with earlier
1435  // versions of the library. (Auxiliary buffers are not mask compressed.)
1436  const bool zipped = io::getDataCompression(is) & io::COMPRESS_ZIP;
1437  Buffer temp;
1438  for (int i = 1; i < numBuffers; ++i) {
1439  if (fromHalf) {
1440  io::HalfReader<io::RealToHalf<T>::isReal, T>::read(is, temp.mData, SIZE, zipped);
1441  } else {
1442  io::readData<T>(is, temp.mData, SIZE, zipped);
1443  }
1444  }
1445  }
1446 
1447  // increment the leaf number
1448  if (meta) meta->setLeaf(meta->leaf() + 1);
1449 }
1450 
1451 
1452 template<typename T, Index Log2Dim>
1453 inline void
1454 LeafNode<T, Log2Dim>::writeBuffers(std::ostream& os, bool toHalf) const
1455 {
1456  // Write out the value mask.
1457  mValueMask.save(os);
1458 
1459  mBuffer.loadValues();
1460 
1461  io::writeCompressedValues(os, mBuffer.mData, SIZE,
1462  mValueMask, /*childMask=*/NodeMaskType(), toHalf);
1463 }
1464 
1465 
1466 ////////////////////////////////////////
1467 
1468 
1469 template<typename T, Index Log2Dim>
1470 inline bool
1472 {
1473  return mOrigin == other.mOrigin &&
1474  mValueMask == other.valueMask() &&
1475  mBuffer == other.mBuffer;
1476 }
1477 
1478 
1479 template<typename T, Index Log2Dim>
1480 inline Index64
1482 {
1483  // Use sizeof(*this) to capture alignment-related padding
1484  // (but note that sizeof(*this) includes sizeof(mBuffer)).
1485  return sizeof(*this) + mBuffer.memUsage() - sizeof(mBuffer);
1486 }
1487 
1488 
1489 template<typename T, Index Log2Dim>
1490 inline Index64
1492 {
1493  // Use sizeof(*this) to capture alignment-related padding
1494  // (but note that sizeof(*this) includes sizeof(mBuffer)).
1495  return sizeof(*this) + mBuffer.memUsageIfLoaded() - sizeof(mBuffer);
1496 }
1497 
1498 
1499 template<typename T, Index Log2Dim>
1500 inline void
1502 {
1503  CoordBBox this_bbox = this->getNodeBoundingBox();
1504  if (bbox.isInside(this_bbox)) return;//this LeafNode is already enclosed in the bbox
1505  if (ValueOnCIter iter = this->cbeginValueOn()) {//any active values?
1506  if (visitVoxels) {//use voxel granularity?
1507  this_bbox.reset();
1508  for(; iter; ++iter) this_bbox.expand(this->offsetToLocalCoord(iter.pos()));
1509  this_bbox.translate(this->origin());
1510  }
1511  bbox.expand(this_bbox);
1512  }
1513 }
1514 
1515 
1516 template<typename T, Index Log2Dim>
1517 template<typename OtherType, Index OtherLog2Dim>
1518 inline bool
1520 {
1521  OPENVDB_ASSERT(other);
1522  return (Log2Dim == OtherLog2Dim && mValueMask == other->getValueMask());
1523 }
1524 
1525 template<typename T, Index Log2Dim>
1526 inline bool
1528  bool& state,
1529  const ValueType& tolerance) const
1530 {
1531  if (!mValueMask.isConstant(state)) return false;// early termination
1532  firstValue = mBuffer[0];
1533  for (Index i = 1; i < SIZE; ++i) {
1534  if ( !math::isApproxEqual(mBuffer[i], firstValue, tolerance) ) return false;// early termination
1535  }
1536  return true;
1537 }
1538 
1539 template<typename T, Index Log2Dim>
1540 inline bool
1542  ValueType& maxValue,
1543  bool& state,
1544  const ValueType& tolerance) const
1545 {
1546  if (!mValueMask.isConstant(state)) return false;// early termination
1547  minValue = maxValue = mBuffer[0];
1548  for (Index i = 1; i < SIZE; ++i) {
1549  const T& v = mBuffer[i];
1550  if (v < minValue) {
1551  if ((maxValue - v) > tolerance) return false;// early termination
1552  minValue = v;
1553  } else if (v > maxValue) {
1554  if ((v - minValue) > tolerance) return false;// early termination
1555  maxValue = v;
1556  }
1557  }
1558  return true;
1559 }
1560 
1561 template<typename T, Index Log2Dim>
1562 inline T
1564 {
1565  std::unique_ptr<T[]> data(nullptr);
1566  if (tmp == nullptr) {//allocate temporary storage
1567  data.reset(new T[NUM_VALUES]);
1568  tmp = data.get();
1569  }
1570  if (tmp != mBuffer.data()) {
1571  const T* src = mBuffer.data();
1572  for (T* dst = tmp; dst-tmp < NUM_VALUES;) *dst++ = *src++;
1573  }
1574  static const size_t midpoint = (NUM_VALUES - 1) >> 1;
1575  std::nth_element(tmp, tmp + midpoint, tmp + NUM_VALUES);
1576  return tmp[midpoint];
1577 }
1578 
1579 template<typename T, Index Log2Dim>
1580 inline Index
1582 {
1583  const Index count = mValueMask.countOn();
1584  if (count == NUM_VALUES) {//special case: all voxels are active
1585  value = this->medianAll(tmp);
1586  return NUM_VALUES;
1587  } else if (count == 0) {
1588  return 0;
1589  }
1590  std::unique_ptr<T[]> data(nullptr);
1591  if (tmp == nullptr) {//allocate temporary storage
1592  data.reset(new T[count]);// 0 < count < NUM_VALUES
1593  tmp = data.get();
1594  }
1595  for (auto iter=this->cbeginValueOn(); iter; ++iter) *tmp++ = *iter;
1596  T *begin = tmp - count;
1597  const size_t midpoint = (count - 1) >> 1;
1598  std::nth_element(begin, begin + midpoint, tmp);
1599  value = begin[midpoint];
1600  return count;
1601 }
1602 
1603 template<typename T, Index Log2Dim>
1604 inline Index
1606 {
1607  const Index count = mValueMask.countOff();
1608  if (count == NUM_VALUES) {//special case: all voxels are inactive
1609  value = this->medianAll(tmp);
1610  return NUM_VALUES;
1611  } else if (count == 0) {
1612  return 0;
1613  }
1614  std::unique_ptr<T[]> data(nullptr);
1615  if (tmp == nullptr) {//allocate temporary storage
1616  data.reset(new T[count]);// 0 < count < NUM_VALUES
1617  tmp = data.get();
1618  }
1619  for (auto iter=this->cbeginValueOff(); iter; ++iter) *tmp++ = *iter;
1620  T *begin = tmp - count;
1621  const size_t midpoint = (count - 1) >> 1;
1622  std::nth_element(begin, begin + midpoint, tmp);
1623  value = begin[midpoint];
1624  return count;
1625 }
1626 
1627 ////////////////////////////////////////
1628 
1629 
1630 template<typename T, Index Log2Dim>
1631 inline void
1632 LeafNode<T, Log2Dim>::addTile(Index /*level*/, const Coord& xyz, const ValueType& val, bool active)
1633 {
1634  this->addTile(this->coordToOffset(xyz), val, active);
1635 }
1636 
1637 template<typename T, Index Log2Dim>
1638 inline void
1640 {
1641  OPENVDB_ASSERT(offset < SIZE);
1642  setValueOnly(offset, val);
1643  setActiveState(offset, active);
1644 }
1645 
1646 template<typename T, Index Log2Dim>
1647 template<typename AccessorT>
1648 inline void
1650  const ValueType& val, bool active, AccessorT&)
1651 {
1652  this->addTile(level, xyz, val, active);
1653 }
1654 
1655 
1656 ////////////////////////////////////////
1657 
1658 
1659 template<typename T, Index Log2Dim>
1660 inline void
1662  const ValueType& newBackground)
1663 {
1664  if (!this->allocate()) return;
1665  if (math::isExactlyEqual(oldBackground, newBackground)) return;
1666 
1667  typename NodeMaskType::OffIterator iter;
1668  // For all inactive values...
1669  for (iter = this->mValueMask.beginOff(); iter; ++iter) {
1670  ValueType &inactiveValue = mBuffer[iter.pos()];
1671  if (math::isApproxEqual(inactiveValue, oldBackground)) {
1672  inactiveValue = newBackground;
1673  } else if (math::isApproxEqual(inactiveValue, math::negative(oldBackground))) {
1674  inactiveValue = math::negative(newBackground);
1675  }
1676  }
1677 }
1678 
1679 
1680 template<typename T, Index Log2Dim>
1681 template<MergePolicy Policy>
1682 inline void
1684 {
1685  if (!this->allocate()) return;
1686 
1688  if (Policy == MERGE_NODES) return;
1689  typename NodeMaskType::OnIterator iter = other.valueMask().beginOn();
1690  for (; iter; ++iter) {
1691  const Index n = iter.pos();
1692  if (mValueMask.isOff(n)) {
1693  mBuffer[n] = other.mBuffer[n];
1694  mValueMask.setOn(n);
1695  }
1696  }
1698 }
1699 
1700 template<typename T, Index Log2Dim>
1701 template<MergePolicy Policy>
1702 inline void
1704  const ValueType& /*bg*/, const ValueType& /*otherBG*/)
1705 {
1706  this->template merge<Policy>(other);
1707 }
1708 
1709 template<typename T, Index Log2Dim>
1710 template<MergePolicy Policy>
1711 inline void
1712 LeafNode<T, Log2Dim>::merge(const ValueType& tileValue, bool tileActive)
1713 {
1714  if (!this->allocate()) return;
1715 
1717  if (Policy != MERGE_ACTIVE_STATES_AND_NODES) return;
1718  if (!tileActive) return;
1719  // Replace all inactive values with the active tile value.
1720  for (typename NodeMaskType::OffIterator iter = mValueMask.beginOff(); iter; ++iter) {
1721  const Index n = iter.pos();
1722  mBuffer[n] = tileValue;
1723  mValueMask.setOn(n);
1724  }
1726 }
1727 
1728 
1729 template<typename T, Index Log2Dim>
1730 template<typename OtherType>
1731 inline void
1733 {
1734  mValueMask |= other.valueMask();
1735 }
1736 
1737 template<typename T, Index Log2Dim>
1738 template<typename OtherType>
1739 inline void
1741  const ValueType&)
1742 {
1743  mValueMask &= other.valueMask();
1744 }
1745 
1746 template<typename T, Index Log2Dim>
1747 template<typename OtherType>
1748 inline void
1750  const ValueType&)
1751 {
1752  mValueMask &= !other.valueMask();
1753 }
1754 
1755 template<typename T, Index Log2Dim>
1756 inline void
1758 {
1759  if (!this->allocate()) return;
1760 
1761  for (Index i = 0; i < SIZE; ++i) {
1762  mBuffer[i] = -mBuffer[i];
1763  }
1764 }
1765 
1766 
1767 ////////////////////////////////////////
1768 
1769 
1770 template<typename T, Index Log2Dim>
1771 template<typename CombineOp>
1772 inline void
1773 LeafNode<T, Log2Dim>::combine(const LeafNode& other, CombineOp& op)
1774 {
1775  if (!this->allocate()) return;
1776 
1778  for (Index i = 0; i < SIZE; ++i) {
1779  op(args.setARef(mBuffer[i])
1780  .setAIsActive(mValueMask.isOn(i))
1781  .setBRef(other.mBuffer[i])
1782  .setBIsActive(other.valueMask().isOn(i))
1783  .setResultRef(mBuffer[i]));
1784  mValueMask.set(i, args.resultIsActive());
1785  }
1786 }
1787 
1788 
1789 template<typename T, Index Log2Dim>
1790 template<typename CombineOp>
1791 inline void
1792 LeafNode<T, Log2Dim>::combine(const ValueType& value, bool valueIsActive, CombineOp& op)
1793 {
1794  if (!this->allocate()) return;
1795 
1797  args.setBRef(value).setBIsActive(valueIsActive);
1798  for (Index i = 0; i < SIZE; ++i) {
1799  op(args.setARef(mBuffer[i])
1800  .setAIsActive(mValueMask.isOn(i))
1801  .setResultRef(mBuffer[i]));
1802  mValueMask.set(i, args.resultIsActive());
1803  }
1804 }
1805 
1806 
1807 ////////////////////////////////////////
1808 
1809 
1810 template<typename T, Index Log2Dim>
1811 template<typename CombineOp, typename OtherType>
1812 inline void
1813 LeafNode<T, Log2Dim>::combine2(const LeafNode& other, const OtherType& value,
1814  bool valueIsActive, CombineOp& op)
1815 {
1816  if (!this->allocate()) return;
1817 
1819  args.setBRef(value).setBIsActive(valueIsActive);
1820  for (Index i = 0; i < SIZE; ++i) {
1821  op(args.setARef(other.mBuffer[i])
1822  .setAIsActive(other.valueMask().isOn(i))
1823  .setResultRef(mBuffer[i]));
1824  mValueMask.set(i, args.resultIsActive());
1825  }
1826 }
1827 
1828 
1829 template<typename T, Index Log2Dim>
1830 template<typename CombineOp, typename OtherNodeT>
1831 inline void
1832 LeafNode<T, Log2Dim>::combine2(const ValueType& value, const OtherNodeT& other,
1833  bool valueIsActive, CombineOp& op)
1834 {
1835  if (!this->allocate()) return;
1836 
1838  args.setARef(value).setAIsActive(valueIsActive);
1839  for (Index i = 0; i < SIZE; ++i) {
1840  op(args.setBRef(other.mBuffer[i])
1841  .setBIsActive(other.valueMask().isOn(i))
1842  .setResultRef(mBuffer[i]));
1843  mValueMask.set(i, args.resultIsActive());
1844  }
1845 }
1846 
1847 
1848 template<typename T, Index Log2Dim>
1849 template<typename CombineOp, typename OtherNodeT>
1850 inline void
1851 LeafNode<T, Log2Dim>::combine2(const LeafNode& b0, const OtherNodeT& b1, CombineOp& op)
1852 {
1853  if (!this->allocate()) return;
1854 
1856  for (Index i = 0; i < SIZE; ++i) {
1857  mValueMask.set(i, b0.valueMask().isOn(i) || b1.valueMask().isOn(i));
1858  op(args.setARef(b0.mBuffer[i])
1859  .setAIsActive(b0.valueMask().isOn(i))
1860  .setBRef(b1.mBuffer[i])
1861  .setBIsActive(b1.valueMask().isOn(i))
1862  .setResultRef(mBuffer[i]));
1863  mValueMask.set(i, args.resultIsActive());
1864  }
1865 }
1866 
1867 
1868 ////////////////////////////////////////
1869 
1870 
1871 template<typename T, Index Log2Dim>
1872 inline std::ostream&
1873 operator<<(std::ostream& os, const typename LeafNode<T, Log2Dim>::Buffer& buf)
1874 {
1875  for (Index32 i = 0, N = buf.size(); i < N; ++i) os << buf.mData[i] << ", ";
1876  return os;
1877 }
1878 
1879 } // namespace tree
1880 } // namespace OPENVDB_VERSION_NAME
1881 } // namespace openvdb
1882 
1883 
1884 ////////////////////////////////////////
1885 
1886 
1887 // Specialization for LeafNodes of type bool
1888 #include "LeafNodeBool.h"
1889 
1890 // Specialization for LeafNodes with mask information only
1891 #include "LeafNodeMask.h"
1892 
1893 #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:1732
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:635
OPENVDB_API const void * getGridBackgroundValuePtr(std::ios_base &)
Return a pointer to the background value of the grid currently being read from or written to the give...
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:468
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:139
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:1527
LeafNode * probeLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: LeafNode.h:761
GLsizei const GLfloat * value
Definition: glcorearb.h:824
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:1481
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:171
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:246
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:1740
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:756
FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, const fill_t< Char > &fill) -> OutputIt
Definition: format.h:1860
OPENVDB_API void checkFormatVersion(std::ios_base &)
Throws an IoError if the file format version number is not supported.
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:1454
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:95
void writeCompressedValues(std::ostream &os, const ValueT *srcBuf, Index srcCount, const MaskT &valueMask, const MaskT &childMask, bool toHalf)
Definition: Compression.h:648
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:431
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:323
void addTile(Index level, const Coord &, const ValueType &, bool)
Definition: LeafNode.h:1632
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:1749
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:1661
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:1563
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:163
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:1813
Index medianOn(ValueType &value, ValueType *tmp=nullptr) const
Computes the median value of all the active voxels in this node.
Definition: LeafNode.h:1581
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
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.
Definition: node.h:587
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:690
void combine(const LeafNode &other, CombineOp &op)
Definition: LeafNode.h:1773
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:1605
void addTileAndCache(Index, const Coord &, const ValueType &, bool, AccessorT &)
Definition: LeafNode.h:1649
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:688
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:164
size_t streamingSize(bool toHalf=false) const
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:750
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:239
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:1519
bool operator==(const LeafNode &other) const
Check for buffer, state and origin equivalence.
Definition: LeafNode.h:1471
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:1501
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