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