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