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