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