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