HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
LeafNodeMask.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #ifndef OPENVDB_TREE_LEAF_NODE_MASK_HAS_BEEN_INCLUDED
5 #define OPENVDB_TREE_LEAF_NODE_MASK_HAS_BEEN_INCLUDED
6 
7 #include <openvdb/version.h>
8 #include <openvdb/Types.h>
9 #include <openvdb/io/Compression.h> // for io::readData(), etc.
10 #include <openvdb/math/Math.h> // for math::isZero()
11 #include <openvdb/util/NodeMasks.h>
12 #include <openvdb/util/Assert.h>
13 #include "LeafNode.h"
14 #include "Iterator.h"
15 #include <iostream>
16 #include <sstream>
17 #include <string>
18 #include <type_traits>
19 #include <vector>
20 
21 
22 namespace openvdb {
24 namespace OPENVDB_VERSION_NAME {
25 namespace tree {
26 
27 /// @brief LeafNode specialization for values of type ValueMask that encodes both
28 /// the active states and the boolean values of (2^Log2Dim)^3 voxels
29 /// in a single bit mask, i.e. voxel values and states are indistinguishable!
30 template<Index Log2Dim>
31 class LeafNode<ValueMask, Log2Dim>
32 {
33 public:
35  using BuildType = ValueMask;// this is a rare case where
36  using ValueType = bool;// value type != build type
37  using Buffer = LeafBuffer<ValueType, Log2Dim>;// buffer uses the bool specialization
40 
41  // These static declarations must be on separate lines to avoid VC9 compiler errors.
42  static const Index LOG2DIM = Log2Dim; // needed by parent nodes
43  static const Index TOTAL = Log2Dim; // needed by parent nodes
44  static const Index DIM = 1 << TOTAL; // dimension along one coordinate direction
45  static const Index NUM_VALUES = 1 << 3 * Log2Dim;
46  static const Index NUM_VOXELS = NUM_VALUES; // total number of voxels represented by this node
47  static const Index SIZE = NUM_VALUES;
48  static const Index LEVEL = 0; // level 0 = leaf
49 
50  /// @brief ValueConverter<T>::Type is the type of a LeafNode having the same
51  /// dimensions as this node but a different value type, T.
52  template<typename OtherValueType>
53  struct ValueConverter { using Type = LeafNode<OtherValueType, Log2Dim>; };
54 
55  /// @brief SameConfiguration<OtherNodeType>::value is @c true if and only if
56  /// OtherNodeType is the type of a LeafNode with the same dimensions as this node.
57  template<typename OtherNodeType>
58  struct SameConfiguration {
60  };
61 
62  /// Default constructor
63  LeafNode();
64 
65  /// Constructor
66  /// @param xyz the coordinates of a voxel that lies within the node
67  /// @param value the initial value = state for all of this node's voxels
68  /// @param dummy dummy value
69  explicit LeafNode(const Coord& xyz, bool value = false, bool dummy = false);
70 
71  /// "Partial creation" constructor used during file input
72  LeafNode(PartialCreate, const Coord& xyz, bool value = false, bool dummy = false);
73 
74  /// Deep copy constructor
75  LeafNode(const LeafNode&);
76 
77  /// Value conversion copy constructor
78  template<typename OtherValueType>
79  explicit LeafNode(const LeafNode<OtherValueType, Log2Dim>& other);
80 
81  /// Topology copy constructor
82  template<typename ValueType>
84 
85  //@{
86  /// @brief Topology copy constructor
87  /// @note This variant exists mainly to enable template instantiation.
88  template<typename ValueType>
89  LeafNode(const LeafNode<ValueType, Log2Dim>& other, bool offValue, bool onValue, TopologyCopy);
90  template<typename ValueType>
91  LeafNode(const LeafNode<ValueType, Log2Dim>& other, bool background, TopologyCopy);
92  //@}
93 
94  /// Destructor
95  ~LeafNode();
96 
97  //
98  // Statistics
99  //
100  /// Return log2 of the size of the buffer storage.
101  static Index log2dim() { return Log2Dim; }
102  /// Return the number of voxels in each dimension.
103  static Index dim() { return DIM; }
104  /// Return the total number of voxels represented by this LeafNode
105  static Index size() { return SIZE; }
106  /// Return the total number of voxels represented by this LeafNode
107  static Index numValues() { return SIZE; }
108  /// Return the level of this node, which by definition is zero for LeafNodes
109  static Index getLevel() { return LEVEL; }
110  /// Append the Log2Dim of this LeafNode to the specified vector
111  static void getNodeLog2Dims(std::vector<Index>& dims) { dims.push_back(Log2Dim); }
112  /// Return the dimension of child nodes of this LeafNode, which is one for voxels.
113  static Index getChildDim() { return 1; }
114  /// Return the leaf count for this node, which is one.
115  static Index64 leafCount() { return 1; }
116  /// no-op
117  void nodeCount(std::vector<Index64> &) const {}
118  OPENVDB_DEPRECATED_MESSAGE("Use input type std::vector<Index64> for nodeCount.")
119  void nodeCount(std::vector<Index32> &) const {}
120  /// Return the non-leaf count for this node, which is zero.
121  static Index64 nonLeafCount() { return 0; }
122 
123  /// Return the number of active voxels.
124  Index64 onVoxelCount() const { return mBuffer.mData.countOn(); }
125  /// Return the number of inactive voxels.
126  Index64 offVoxelCount() const { return mBuffer.mData.countOff(); }
127  Index64 onLeafVoxelCount() const { return this->onVoxelCount(); }
128  Index64 offLeafVoxelCount() const { return this->offVoxelCount(); }
129  static Index64 onTileCount() { return 0; }
130  static Index64 offTileCount() { return 0; }
131 
132  /// Return @c true if this node has no active voxels.
133  bool isEmpty() const { return mBuffer.mData.isOff(); }
134  /// Return @c true if this node only contains active voxels.
135  bool isDense() const { return mBuffer.mData.isOn(); }
136  /// @brief Return @c true if memory for this node's buffer has been allocated.
137  /// @details Currently, boolean leaf nodes don't support partial creation,
138  /// so this always returns @c true.
139  bool isAllocated() const { return true; }
140  /// @brief Allocate memory for this node's buffer if it has not already been allocated.
141  /// @details Currently, boolean leaf nodes don't support partial creation,
142  /// so this has no effect.
143  bool allocate() { return true; }
144 
145  /// Return the memory in bytes occupied by this node.
146  Index64 memUsage() const;
147  Index64 memUsageIfLoaded() const;
148 
149  /// Expand the given bounding box so that it includes this leaf node's active voxels.
150  /// If visitVoxels is false this LeafNode will be approximated as dense, i.e. with all
151  /// voxels active. Else the individual active voxels are visited to produce a tight bbox.
152  void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const;
153 
154  /// @brief Return the bounding box of this node, i.e., the full index space
155  /// spanned by this leaf node.
156  CoordBBox getNodeBoundingBox() const { return CoordBBox::createCube(mOrigin, DIM); }
157 
158  /// Set the grid index coordinates of this node's local origin.
159  void setOrigin(const Coord& origin) { mOrigin = origin; }
160  //@{
161  /// Return the grid index coordinates of this node's local origin.
162  const Coord& origin() const { return mOrigin; }
163  void getOrigin(Coord& origin) const { origin = mOrigin; }
164  void getOrigin(Int32& x, Int32& y, Int32& z) const { mOrigin.asXYZ(x, y, z); }
165  //@}
166 
167  /// Return the linear table offset of the given global or local coordinates.
168  static Index coordToOffset(const Coord& xyz);
169  /// @brief Return the local coordinates for a linear table offset,
170  /// where offset 0 has coordinates (0, 0, 0).
171  static Coord offsetToLocalCoord(Index n);
172  /// Return the global coordinates for a linear table offset.
173  Coord offsetToGlobalCoord(Index n) const;
174 
175  /// Return the transient data value.
176  Index32 transientData() const { return mTransientData; }
177  /// Set the transient data value.
179 
180  /// Return a string representation of this node.
181  std::string str() const;
182 
183  /// @brief Return @c true if the given node (which may have a different @c ValueType
184  /// than this node) has the same active value topology as this node.
185  template<typename OtherType, Index OtherLog2Dim>
186  bool hasSameTopology(const LeafNode<OtherType, OtherLog2Dim>* other) const;
187 
188  /// Check for buffer equivalence by value.
189  bool operator==(const LeafNode&) const;
190  bool operator!=(const LeafNode&) const;
191 
192  //
193  // Buffer management
194  //
195  /// @brief Exchange this node's data buffer with the given data buffer
196  /// without changing the active states of the values.
197  void swap(Buffer& other) { mBuffer.swap(other); }
198  const Buffer& buffer() const { return mBuffer; }
199  Buffer& buffer() { return mBuffer; }
200 
201  //
202  // I/O methods
203  //
204  /// Read in just the topology.
205  void readTopology(std::istream&, bool fromHalf = false);
206  /// Write out just the topology.
207  void writeTopology(std::ostream&, bool toHalf = false) const;
208 
209  /// Read in the topology and the origin.
210  void readBuffers(std::istream&, bool fromHalf = false);
211  void readBuffers(std::istream& is, const CoordBBox&, bool fromHalf = false);
212  /// Write out the topology and the origin.
213  void writeBuffers(std::ostream&, bool toHalf = false) const;
214 
215  //
216  // Accessor methods
217  //
218  /// Return the value of the voxel at the given coordinates.
219  const bool& getValue(const Coord& xyz) const;
220  /// Return the value of the voxel at the given offset.
221  const bool& getValue(Index offset) const;
222 
223  /// @brief Return @c true if the voxel at the given coordinates is active.
224  /// @param xyz the coordinates of the voxel to be probed
225  /// @param[out] val the value of the voxel at the given coordinates
226  bool probeValue(const Coord& xyz, bool& val) const;
227  /// @brief Return @c true if the voxel at the given offset is active.
228  /// @param offset the linear offset of the voxel to be probed
229  /// @param[out] val the value of the voxel at the given coordinates
230  bool probeValue(Index offset, bool& val) const;
231 
232  /// Return the level (0) at which leaf node values reside.
233  static Index getValueLevel(const Coord&) { return LEVEL; }
234 
235  /// Set the active state of the voxel at the given coordinates but don't change its value.
236  void setActiveState(const Coord& xyz, bool on);
237  /// Set the active state of the voxel at the given offset but don't change its value.
238  void setActiveState(Index offset, bool on) { OPENVDB_ASSERT(offset<SIZE); mBuffer.mData.set(offset, on); }
239 
240  /// Set the value of the voxel at the given coordinates but don't change its active state.
241  void setValueOnly(const Coord& xyz, bool val);
242  /// Set the value of the voxel at the given offset but don't change its active state.
243  void setValueOnly(Index offset, bool val) { OPENVDB_ASSERT(offset<SIZE); mBuffer.setValue(offset,val); }
244 
245  /// Mark the voxel at the given coordinates as inactive but don't change its value.
246  void setValueOff(const Coord& xyz) { mBuffer.mData.setOff(this->coordToOffset(xyz)); }
247  /// Mark the voxel at the given offset as inactive but don't change its value.
248  void setValueOff(Index offset) { OPENVDB_ASSERT(offset < SIZE); mBuffer.mData.setOff(offset); }
249 
250  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
251  void setValueOff(const Coord& xyz, bool val);
252  /// Set the value of the voxel at the given offset and mark the voxel as inactive.
253  void setValueOff(Index offset, bool val);
254 
255  /// Mark the voxel at the given coordinates as active but don't change its value.
256  void setValueOn(const Coord& xyz) { mBuffer.mData.setOn(this->coordToOffset(xyz)); }
257  /// Mark the voxel at the given offset as active but don't change its value.
258  void setValueOn(Index offset) { OPENVDB_ASSERT(offset < SIZE); mBuffer.mData.setOn(offset); }
259 
260  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
261  void setValueOn(const Coord& xyz, bool val);
262  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
263  void setValue(const Coord& xyz, bool val) { this->setValueOn(xyz, val); }
264  /// Set the value of the voxel at the given offset and mark the voxel as active.
265  void setValueOn(Index offset, bool val);
266 
267  /// @brief Apply a functor to the value of the voxel at the given offset
268  /// and mark the voxel as active.
269  template<typename ModifyOp>
270  void modifyValue(Index offset, const ModifyOp& op);
271  /// @brief Apply a functor to the value of the voxel at the given coordinates
272  /// and mark the voxel as active.
273  template<typename ModifyOp>
274  void modifyValue(const Coord& xyz, const ModifyOp& op);
275 
276  /// Apply a functor to the voxel at the given coordinates.
277  template<typename ModifyOp>
278  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op);
279 
280  /// Mark all voxels as active but don't change their values.
281  void setValuesOn() { mBuffer.mData.setOn(); }
282  /// Mark all voxels as inactive but don't change their values.
283  void setValuesOff() { mBuffer.mData.setOff(); }
284 
285  /// Return @c true if the voxel at the given coordinates is active.
286  bool isValueOn(const Coord& xyz) const { return this->isValueOn(this->coordToOffset(xyz)); }
287  /// Return @c true if the voxel at the given offset is active.
288  bool isValueOn(Index offset) const { OPENVDB_ASSERT(offset < SIZE); return mBuffer.mData.isOn(offset); }
289  /// Return @c true if the voxel at the given coordinates is inactive.
290  bool isValueOff(const Coord& xyz) const { return this->isValueOff(this->coordToOffset(xyz)); }
291  /// Return @c true if the voxel at the given offset is inactive.
292  bool isValueOff(Index offset) const { OPENVDB_ASSERT(offset < SIZE); return mBuffer.mData.isOff(offset); }
293 
294  /// Return @c false since leaf nodes never contain tiles.
295  static bool hasActiveTiles() { return false; }
296 
297  /// Set all voxels that lie outside the given axis-aligned box to the background.
298  void clip(const CoordBBox&, bool background);
299 
300  /// Set all voxels within an axis-aligned box to the specified value.
301  void fill(const CoordBBox& bbox, bool value, bool = false);
302  /// Set all voxels within an axis-aligned box to the specified value.
303  void denseFill(const CoordBBox& bbox, bool value, bool = false) { this->fill(bbox, value); }
304 
305  /// Set the state of all voxels to the specified active state.
306  void fill(const bool& value, bool dummy = false);
307 
308  /// @brief Copy into a dense grid the values of the voxels that lie within
309  /// a given bounding box.
310  ///
311  /// @param bbox inclusive bounding box of the voxels to be copied into the dense grid
312  /// @param dense dense grid with a stride in @e z of one (see tools::Dense
313  /// in tools/Dense.h for the required API)
314  ///
315  /// @note @a bbox is assumed to be identical to or contained in the coordinate domains
316  /// of both the dense grid and this node, i.e., no bounds checking is performed.
317  /// @note Consider using tools::CopyToDense in tools/Dense.h
318  /// instead of calling this method directly.
319  template<typename DenseT>
320  void copyToDense(const CoordBBox& bbox, DenseT& dense) const;
321 
322  /// @brief Copy from a dense grid into this node the values of the voxels
323  /// that lie within a given bounding box.
324  /// @details Only values that are different (by more than the given tolerance)
325  /// from the background value will be active. Other values are inactive
326  /// and truncated to the background value.
327  ///
328  /// @param bbox inclusive bounding box of the voxels to be copied into this node
329  /// @param dense dense grid with a stride in @e z of one (see tools::Dense
330  /// in tools/Dense.h for the required API)
331  /// @param background background value of the tree that this node belongs to
332  /// @param tolerance tolerance within which a value equals the background value
333  ///
334  /// @note @a bbox is assumed to be identical to or contained in the coordinate domains
335  /// of both the dense grid and this node, i.e., no bounds checking is performed.
336  /// @note Consider using tools::CopyFromDense in tools/Dense.h
337  /// instead of calling this method directly.
338  template<typename DenseT>
339  void copyFromDense(const CoordBBox& bbox, const DenseT& dense, bool background, bool tolerance);
340 
341  /// @brief Return the value of the voxel at the given coordinates.
342  /// @note Used internally by ValueAccessor.
343  template<typename AccessorT>
344  const bool& getValueAndCache(const Coord& xyz, AccessorT&) const {return this->getValue(xyz);}
345 
346  /// @brief Return @c true if the voxel at the given coordinates is active.
347  /// @note Used internally by ValueAccessor.
348  template<typename AccessorT>
349  bool isValueOnAndCache(const Coord& xyz, AccessorT&) const { return this->isValueOn(xyz); }
350 
351  /// @brief Change the value of the voxel at the given coordinates and mark it as active.
352  /// @note Used internally by ValueAccessor.
353  template<typename AccessorT>
354  void setValueAndCache(const Coord& xyz, bool val, AccessorT&) { this->setValueOn(xyz, val); }
355 
356  /// @brief Change the value of the voxel at the given coordinates
357  /// but preserve its state.
358  /// @note Used internally by ValueAccessor.
359  template<typename AccessorT>
360  void setValueOnlyAndCache(const Coord& xyz, bool val, AccessorT&) {this->setValueOnly(xyz,val);}
361 
362  /// @brief Change the value of the voxel at the given coordinates and mark it as inactive.
363  /// @note Used internally by ValueAccessor.
364  template<typename AccessorT>
365  void setValueOffAndCache(const Coord& xyz, bool value, AccessorT&)
366  {
367  this->setValueOff(xyz, value);
368  }
369 
370  /// @brief Apply a functor to the value of the voxel at the given coordinates
371  /// and mark the voxel as active.
372  /// @note Used internally by ValueAccessor.
373  template<typename ModifyOp, typename AccessorT>
374  void modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&)
375  {
376  this->modifyValue(xyz, op);
377  }
378 
379  /// Apply a functor to the voxel at the given coordinates.
380  /// @note Used internally by ValueAccessor.
381  template<typename ModifyOp, typename AccessorT>
382  void modifyValueAndActiveStateAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&)
383  {
384  this->modifyValueAndActiveState(xyz, op);
385  }
386 
387  /// @brief Set the active state of the voxel at the given coordinates
388  /// without changing its value.
389  /// @note Used internally by ValueAccessor.
390  template<typename AccessorT>
391  void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&)
392  {
393  this->setActiveState(xyz, on);
394  }
395 
396  /// @brief Return @c true if the voxel at the given coordinates is active
397  /// and return the voxel value in @a val.
398  /// @note Used internally by ValueAccessor.
399  template<typename AccessorT>
400  bool probeValueAndCache(const Coord& xyz, bool& val, AccessorT&) const
401  {
402  return this->probeValue(xyz, val);
403  }
404 
405  /// @brief Return the LEVEL (=0) at which leaf node values reside.
406  /// @note Used internally by ValueAccessor.
407  template<typename AccessorT>
408  static Index getValueLevelAndCache(const Coord&, AccessorT&) { return LEVEL; }
409 
410  /// @brief Return a const reference to the first entry in the buffer.
411  /// @note Since it's actually a reference to a static data member
412  /// it should not be converted to a non-const pointer!
413  const bool& getFirstValue() const { if (mBuffer.mData.isOn(0)) return Buffer::sOn; else return Buffer::sOff; }
414  /// @brief Return a const reference to the last entry in the buffer.
415  /// @note Since it's actually a reference to a static data member
416  /// it should not be converted to a non-const pointer!
417  const bool& getLastValue() const { if (mBuffer.mData.isOn(SIZE-1)) return Buffer::sOn; else return Buffer::sOff; }
418 
419  /// Return @c true if all of this node's voxels have the same active state
420  /// and are equal to within the given tolerance, and return the value in
421  /// @a constValue and the active state in @a state.
422  bool isConstant(bool& constValue, bool& state, bool tolerance = 0) const;
423 
424  /// @brief Computes the median value of all the active and inactive voxels in this node.
425  /// @return The median value.
426  ///
427  /// @details The median for boolean values is defined as the mode
428  /// of the values, i.e. the value that occurs most often.
429  bool medianAll() const;
430 
431  /// @brief Computes the median value of all the active voxels in this node.
432  /// @return The number of active voxels.
433  ///
434  /// @param value Updated with the median value of all the active voxels.
435  ///
436  /// @note Since the value and state are shared for this
437  /// specialization of the LeafNode the @a value will always be true!
438  Index medianOn(ValueType &value) const;
439 
440  /// @brief Computes the median value of all the inactive voxels in this node.
441  /// @return The number of inactive voxels.
442  ///
443  /// @param value Updated with the median value of all the inactive
444  /// voxels.
445  ///
446  /// @note Since the value and state are shared for this
447  /// specialization of the LeafNode the @a value will always be false!
448  Index medianOff(ValueType &value) const;
449 
450  /// Return @c true if all of this node's values are inactive.
451  bool isInactive() const { return mBuffer.mData.isOff(); }
452 
453  //
454  // Unsafe methods
455  //
456  // These methods are not in fact unsafe, but are only offered so that
457  // the same methods can be called on both internal nodes and leaf nodes.
458 
459  /// Return the value of the voxel at the given offset.
460  const bool& getValueUnsafe(Index offset) const { return this->getValue(offset); }
461  /// Return true if the voxel at the given offset is active and set value.
462  bool getValueUnsafe(Index offset, bool& value) const { return this->probeValue(offset, value); }
463  /// Set the active state of the voxel at the given offset but don't change its value.
464  void setActiveStateUnsafe(Index offset, bool on) { this->setActiveState(offset, on); }
465  /// Set the value of the voxel at the given coordinates but don't change its active state.
466  void setValueOnlyUnsafe(Index offset, const bool& value) { return this->setValueOnly(offset, value); }
467  /// Mark the voxel at the given offset as active but don't change its value.
468  void setValueOnUnsafe(Index offset) { this->setValueOn(offset); }
469  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
470  void setValueOnUnsafe(Index offset, const bool& value) { this->setValueOn(offset, value); }
471  /// Mark the voxel at the given offset as inactive but don't change its value.
472  void setValueOffUnsafe(Index offset) { this->setValueOff(offset); }
473  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
474  void setValueOffUnsafe(Index offset, const bool& value) { this->setValueOff(offset, value); }
475 
476  /// @brief no-op since for this template specialization voxel
477  /// values and states are indistinguishable.
478  void resetBackground(bool, bool) {}
479 
480  /// @brief Invert the bits of the voxels, i.e. states and values
481  void negate() { mBuffer.mData.toggle(); }
482 
483  template<MergePolicy Policy>
484  void merge(const LeafNode& other, bool bg = false, bool otherBG = false);
485  template<MergePolicy Policy> void merge(bool tileValue, bool tileActive=false);
486 
487  /// @brief No-op
488  /// @details This function exists only to enable template instantiation.
489  void voxelizeActiveTiles(bool = true) {}
490 
491  /// @brief Union this node's set of active values with the active values
492  /// of the other node, whose @c ValueType may be different. So a
493  /// resulting voxel will be active if either of the original voxels
494  /// were active.
495  ///
496  /// @note This operation modifies only active states, not values.
497  template<typename OtherType>
498  void topologyUnion(const LeafNode<OtherType, Log2Dim>& other, const bool preserveTiles = false);
499 
500  /// @brief Intersect this node's set of active values with the active values
501  /// of the other node, whose @c ValueType may be different. So a
502  /// resulting voxel will be active only if both of the original voxels
503  /// were active.
504  ///
505  /// @details The last dummy argument is required to match the signature
506  /// for InternalNode::topologyIntersection.
507  ///
508  /// @note This operation modifies only active states, not
509  /// values. Also note that this operation can result in all voxels
510  /// being inactive so consider subsequently calling prune.
511  template<typename OtherType>
512  void topologyIntersection(const LeafNode<OtherType, Log2Dim>& other, const bool&);
513 
514  /// @brief Difference this node's set of active values with the active values
515  /// of the other node, whose @c ValueType may be different. So a
516  /// resulting voxel will be active only if the original voxel is
517  /// active in this LeafNode and inactive in the other LeafNode.
518  ///
519  /// @details The last dummy argument is required to match the signature
520  /// for InternalNode::topologyDifference.
521  ///
522  /// @note This operation modifies only active states, not values.
523  /// Also, because it can deactivate all of this node's voxels,
524  /// consider subsequently calling prune.
525  template<typename OtherType>
526  void topologyDifference(const LeafNode<OtherType, Log2Dim>& other, const bool&);
527 
528  template<typename CombineOp>
529  void combine(const LeafNode& other, CombineOp& op);
530  template<typename CombineOp>
531  void combine(bool, bool valueIsActive, CombineOp& op);
532 
533  template<typename CombineOp, typename OtherType /*= bool*/>
534  void combine2(const LeafNode& other, const OtherType&, bool valueIsActive, CombineOp&);
535  template<typename CombineOp, typename OtherNodeT /*= LeafNode*/>
536  void combine2(bool, const OtherNodeT& other, bool valueIsActive, CombineOp&);
537  template<typename CombineOp, typename OtherNodeT /*= LeafNode*/>
538  void combine2(const LeafNode& b0, const OtherNodeT& b1, CombineOp&);
539 
540  //@{
541  /// This function exists only to enable template instantiation.
542  void prune(const ValueType& /*tolerance*/ = zeroVal<ValueType>()) {}
543  void addLeaf(LeafNode*) {}
544  template<typename AccessorT>
545  void addLeafAndCache(LeafNode*, AccessorT&) {}
546  template<typename NodeT>
547  NodeT* stealNode(const Coord&, const ValueType&, bool) { return nullptr; }
548  template<typename NodeT>
549  NodeT* probeNode(const Coord&) { return nullptr; }
550  template<typename NodeT>
551  const NodeT* probeConstNode(const Coord&) const { return nullptr; }
552  template<typename ArrayT> void getNodes(ArrayT&) const {}
553  template<typename ArrayT> void stealNodes(ArrayT&, const ValueType&, bool) {}
554  //@}
555 
556  void addTile(Index level, const Coord&, bool val, bool active);
557  void addTile(Index offset, bool val, bool active);
558  template<typename AccessorT>
559  void addTileAndCache(Index level, const Coord&, bool val, bool active, AccessorT&);
560 
561  //@{
562  /// @brief Return a pointer to this node.
563  LeafNode* touchLeaf(const Coord&) { return this; }
564  template<typename AccessorT>
565  LeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; }
566  LeafNode* probeLeaf(const Coord&) { return this; }
567  template<typename AccessorT>
568  LeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; }
569  template<typename NodeT, typename AccessorT>
570  NodeT* probeNodeAndCache(const Coord&, AccessorT&)
571  {
573  if (!(std::is_same<NodeT, LeafNode>::value)) return nullptr;
574  return reinterpret_cast<NodeT*>(this);
576  }
577  //@}
578  //@{
579  /// @brief Return a @const pointer to this node.
580  const LeafNode* probeLeaf(const Coord&) const { return this; }
581  template<typename AccessorT>
582  const LeafNode* probeLeafAndCache(const Coord&, AccessorT&) const { return this; }
583  const LeafNode* probeConstLeaf(const Coord&) const { return this; }
584  template<typename AccessorT>
585  const LeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const { return this; }
586  template<typename NodeT, typename AccessorT>
587  const NodeT* probeConstNodeAndCache(const Coord&, AccessorT&) const
588  {
590  if (!(std::is_same<NodeT, LeafNode>::value)) return nullptr;
591  return reinterpret_cast<const NodeT*>(this);
593  }
594  //@}
595 
596  //
597  // Iterators
598  //
599 protected:
603 
604  template<typename MaskIterT, typename NodeT, typename ValueT>
605  struct ValueIter:
606  // Derives from SparseIteratorBase, but can also be used as a dense iterator,
607  // if MaskIterT is a dense mask iterator type.
608  public SparseIteratorBase<MaskIterT, ValueIter<MaskIterT, NodeT, ValueT>, NodeT, ValueT>
609  {
611 
613  ValueIter(const MaskIterT& iter, NodeT* parent): BaseT(iter, parent) {}
614 
615  const bool& getItem(Index pos) const { return this->parent().getValue(pos); }
616  const bool& getValue() const { return this->getItem(this->pos()); }
617 
618  // Note: setItem() can't be called on const iterators.
619  void setItem(Index pos, bool value) const { this->parent().setValueOnly(pos, value); }
620  // Note: setValue() can't be called on const iterators.
621  void setValue(bool value) const { this->setItem(this->pos(), value); }
622 
623  // Note: modifyItem() can't be called on const iterators.
624  template<typename ModifyOp>
625  void modifyItem(Index n, const ModifyOp& op) const { this->parent().modifyValue(n, op); }
626  // Note: modifyValue() can't be called on const iterators.
627  template<typename ModifyOp>
628  void modifyValue(const ModifyOp& op) const { this->modifyItem(this->pos(), op); }
629  };
630 
631  /// Leaf nodes have no children, so their child iterators have no get/set accessors.
632  template<typename MaskIterT, typename NodeT>
633  struct ChildIter:
634  public SparseIteratorBase<MaskIterT, ChildIter<MaskIterT, NodeT>, NodeT, bool>
635  {
637  ChildIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase<
638  MaskIterT, ChildIter<MaskIterT, NodeT>, NodeT, bool>(iter, parent) {}
639  };
640 
641  template<typename NodeT, typename ValueT>
642  struct DenseIter: public DenseIteratorBase<
643  MaskDenseIter, DenseIter<NodeT, ValueT>, NodeT, /*ChildT=*/void, ValueT>
644  {
647 
649  DenseIter(const MaskDenseIter& iter, NodeT* parent): BaseT(iter, parent) {}
650 
651  bool getItem(Index pos, void*& child, NonConstValueT& value) const
652  {
653  value = this->parent().getValue(pos);
654  child = nullptr;
655  return false; // no child
656  }
657 
658  // Note: setItem() can't be called on const iterators.
659  //void setItem(Index pos, void* child) const {}
660 
661  // Note: unsetItem() can't be called on const iterators.
662  void unsetItem(Index pos, const ValueT& val) const {this->parent().setValueOnly(pos, val);}
663  };
664 
665 public:
666  using ValueOnIter = ValueIter<MaskOnIter, LeafNode, const bool>;
667  using ValueOnCIter = ValueIter<MaskOnIter, const LeafNode, const bool>;
668  using ValueOffIter = ValueIter<MaskOffIter, LeafNode, const bool>;
669  using ValueOffCIter = ValueIter<MaskOffIter, const LeafNode, const bool>;
670  using ValueAllIter = ValueIter<MaskDenseIter, LeafNode, const bool>;
671  using ValueAllCIter = ValueIter<MaskDenseIter, const LeafNode, const bool>;
672  using ChildOnIter = ChildIter<MaskOnIter, LeafNode>;
673  using ChildOnCIter = ChildIter<MaskOnIter, const LeafNode>;
674  using ChildOffIter = ChildIter<MaskOffIter, LeafNode>;
675  using ChildOffCIter = ChildIter<MaskOffIter, const LeafNode>;
676  using ChildAllIter = DenseIter<LeafNode, bool>;
677  using ChildAllCIter = DenseIter<const LeafNode, const bool>;
678 
679  ValueOnCIter cbeginValueOn() const { return ValueOnCIter(mBuffer.mData.beginOn(), this); }
680  ValueOnCIter beginValueOn() const { return ValueOnCIter(mBuffer.mData.beginOn(), this); }
681  ValueOnIter beginValueOn() { return ValueOnIter(mBuffer.mData.beginOn(), this); }
682  ValueOffCIter cbeginValueOff() const { return ValueOffCIter(mBuffer.mData.beginOff(), this); }
683  ValueOffCIter beginValueOff() const { return ValueOffCIter(mBuffer.mData.beginOff(), this); }
684  ValueOffIter beginValueOff() { return ValueOffIter(mBuffer.mData.beginOff(), this); }
685  ValueAllCIter cbeginValueAll() const { return ValueAllCIter(mBuffer.mData.beginDense(), this); }
686  ValueAllCIter beginValueAll() const { return ValueAllCIter(mBuffer.mData.beginDense(), this); }
687  ValueAllIter beginValueAll() { return ValueAllIter(mBuffer.mData.beginDense(), this); }
688 
689  ValueOnCIter cendValueOn() const { return ValueOnCIter(mBuffer.mData.endOn(), this); }
690  ValueOnCIter endValueOn() const { return ValueOnCIter(mBuffer.mData.endOn(), this); }
691  ValueOnIter endValueOn() { return ValueOnIter(mBuffer.mData.endOn(), this); }
692  ValueOffCIter cendValueOff() const { return ValueOffCIter(mBuffer.mData.endOff(), this); }
693  ValueOffCIter endValueOff() const { return ValueOffCIter(mBuffer.mData.endOff(), this); }
694  ValueOffIter endValueOff() { return ValueOffIter(mBuffer.mData.endOff(), this); }
695  ValueAllCIter cendValueAll() const { return ValueAllCIter(mBuffer.mData.endDense(), this); }
696  ValueAllCIter endValueAll() const { return ValueAllCIter(mBuffer.mData.endDense(), this); }
697  ValueAllIter endValueAll() { return ValueAllIter(mBuffer.mData.endDense(), this); }
698 
699  // Note that [c]beginChildOn() and [c]beginChildOff() actually return end iterators,
700  // because leaf nodes have no children.
701  ChildOnCIter cbeginChildOn() const { return ChildOnCIter(mBuffer.mData.endOn(), this); }
702  ChildOnCIter beginChildOn() const { return ChildOnCIter(mBuffer.mData.endOn(), this); }
703  ChildOnIter beginChildOn() { return ChildOnIter(mBuffer.mData.endOn(), this); }
704  ChildOffCIter cbeginChildOff() const { return ChildOffCIter(mBuffer.mData.endOff(), this); }
705  ChildOffCIter beginChildOff() const { return ChildOffCIter(mBuffer.mData.endOff(), this); }
706  ChildOffIter beginChildOff() { return ChildOffIter(mBuffer.mData.endOff(), this); }
707  ChildAllCIter cbeginChildAll() const { return ChildAllCIter(mBuffer.mData.beginDense(), this); }
708  ChildAllCIter beginChildAll() const { return ChildAllCIter(mBuffer.mData.beginDense(), this); }
709  ChildAllIter beginChildAll() { return ChildAllIter(mBuffer.mData.beginDense(), this); }
710 
711  ChildOnCIter cendChildOn() const { return ChildOnCIter(mBuffer.mData.endOn(), this); }
712  ChildOnCIter endChildOn() const { return ChildOnCIter(mBuffer.mData.endOn(), this); }
713  ChildOnIter endChildOn() { return ChildOnIter(mBuffer.mData.endOn(), this); }
714  ChildOffCIter cendChildOff() const { return ChildOffCIter(mBuffer.mData.endOff(), this); }
715  ChildOffCIter endChildOff() const { return ChildOffCIter(mBuffer.mData.endOff(), this); }
716  ChildOffIter endChildOff() { return ChildOffIter(mBuffer.mData.endOff(), this); }
717  ChildAllCIter cendChildAll() const { return ChildAllCIter(mBuffer.mData.endDense(), this); }
718  ChildAllCIter endChildAll() const { return ChildAllCIter(mBuffer.mData.endDense(), this); }
719  ChildAllIter endChildAll() { return ChildAllIter(mBuffer.mData.endDense(), this); }
720 
721  //
722  // Mask accessors
723  //
724  bool isValueMaskOn(Index n) const { return mBuffer.mData.isOn(n); }
725  bool isValueMaskOn() const { return mBuffer.mData.isOn(); }
726  bool isValueMaskOff(Index n) const { return mBuffer.mData.isOff(n); }
727  bool isValueMaskOff() const { return mBuffer.mData.isOff(); }
728  const NodeMaskType& getValueMask() const { return mBuffer.mData; }
729  const NodeMaskType& valueMask() const { return mBuffer.mData; }
730  NodeMaskType& getValueMask() { return mBuffer.mData; }
731  void setValueMask(const NodeMaskType& mask) { mBuffer.mData = mask; }
732  bool isChildMaskOn(Index) const { return false; } // leaf nodes have no children
733  bool isChildMaskOff(Index) const { return true; }
734  bool isChildMaskOff() const { return true; }
735 protected:
736  void setValueMask(Index n, bool on) { mBuffer.mData.set(n, on); }
737  void setValueMaskOn(Index n) { mBuffer.mData.setOn(n); }
738  void setValueMaskOff(Index n) { mBuffer.mData.setOff(n); }
739 
740  /// Compute the origin of the leaf node that contains the voxel with the given coordinates.
741  static void evalNodeOrigin(Coord& xyz) { xyz &= ~(DIM - 1); }
742 
743  /// Bitmask representing the values AND state of voxels
745  /// Global grid index coordinates (x,y,z) of the local origin of this node
746  Coord mOrigin;
747  /// Transient data (not serialized)
748  Index32 mTransientData = 0;
749 
750 private:
751  /// @brief During topology-only construction, access is needed
752  /// to protected/private members of other template instances.
753  template<typename, Index> friend class LeafNode;
754 
755  friend struct ValueIter<MaskOnIter, LeafNode, bool>;
756  friend struct ValueIter<MaskOffIter, LeafNode, bool>;
757  friend struct ValueIter<MaskDenseIter, LeafNode, bool>;
758  friend struct ValueIter<MaskOnIter, const LeafNode, bool>;
759  friend struct ValueIter<MaskOffIter, const LeafNode, bool>;
760  friend struct ValueIter<MaskDenseIter, const LeafNode, bool>;
761 
762  //@{
763  /// Allow iterators to call mask accessor methods (see below).
764  /// @todo Make mask accessors public?
768  //@}
769 
770  template<typename, Index> friend class LeafBuffer;
771 
772 }; // class LeafNode<ValueMask>
773 
774 
775 ////////////////////////////////////////
776 
777 
778 template<Index Log2Dim>
779 inline
781  : mOrigin(0, 0, 0)
782 {
783 }
784 
785 template<Index Log2Dim>
786 inline
788  : mBuffer(value || active)
789  , mOrigin(xyz & (~(DIM - 1)))
790 {
791 }
792 
793 
794 template<Index Log2Dim>
795 inline
797  : mBuffer(value || active)
798  , mOrigin(xyz & (~(DIM - 1)))
799 {
800 }
801 
802 
803 template<Index Log2Dim>
804 inline
806  : mBuffer(other.mBuffer)
807  , mOrigin(other.mOrigin)
808  , mTransientData(other.mTransientData)
809 {
810 }
811 
812 
813 // Copy-construct from a leaf node with the same configuration but a different ValueType.
814 template<Index Log2Dim>
815 template<typename ValueT>
816 inline
818  : mBuffer(other.valueMask())
819  , mOrigin(other.origin())
820  , mTransientData(other.mTransientData)
821 {
822 }
823 
824 
825 template<Index Log2Dim>
826 template<typename ValueT>
827 inline
829  bool, TopologyCopy)
830  : mBuffer(other.valueMask())// value = active state
831  , mOrigin(other.origin())
832  , mTransientData(other.mTransientData)
833 {
834 }
835 
836 
837 template<Index Log2Dim>
838 template<typename ValueT>
839 inline
841  : mBuffer(other.valueMask())// value = active state
842  , mOrigin(other.origin())
843  , mTransientData(other.mTransientData)
844 {
845 }
846 
847 
848 template<Index Log2Dim>
849 template<typename ValueT>
850 inline
852  bool offValue, bool onValue, TopologyCopy)
853  : mBuffer(other.valueMask())
854  , mOrigin(other.origin())
855  , mTransientData(other.mTransientData)
856 {
857  if (offValue==true) {
858  if (onValue==false) {
859  mBuffer.mData.toggle();
860  } else {
861  mBuffer.mData.setOn();
862  }
863  }
864 }
865 
866 
867 template<Index Log2Dim>
868 inline
870 {
871 }
872 
873 
874 ////////////////////////////////////////
875 
876 
877 template<Index Log2Dim>
878 inline Index64
880 {
881  // Use sizeof(*this) to capture alignment-related padding
882  return sizeof(*this);
883 }
884 
885 
886 template<Index Log2Dim>
887 inline Index64
889 {
890  // Use sizeof(*this) to capture alignment-related padding
891  return sizeof(*this);
892 }
893 
894 
895 template<Index Log2Dim>
896 inline void
898 {
899  CoordBBox this_bbox = this->getNodeBoundingBox();
900  if (bbox.isInside(this_bbox)) return;//this LeafNode is already enclosed in the bbox
901  if (ValueOnCIter iter = this->cbeginValueOn()) {//any active values?
902  if (visitVoxels) {//use voxel granularity?
903  this_bbox.reset();
904  for(; iter; ++iter) this_bbox.expand(this->offsetToLocalCoord(iter.pos()));
905  this_bbox.translate(this->origin());
906  }
907  bbox.expand(this_bbox);
908  }
909 }
910 
911 
912 template<Index Log2Dim>
913 template<typename OtherType, Index OtherLog2Dim>
914 inline bool
916 {
917  OPENVDB_ASSERT(other);
918  return (Log2Dim == OtherLog2Dim && mBuffer.mData == other->getValueMask());
919 }
920 
921 
922 template<Index Log2Dim>
923 inline std::string
925 {
926  std::ostringstream ostr;
927  ostr << "LeafNode @" << mOrigin << ": ";
928  for (Index32 n = 0; n < SIZE; ++n) ostr << (mBuffer.mData.isOn(n) ? '#' : '.');
929  return ostr.str();
930 }
931 
932 
933 ////////////////////////////////////////
934 
935 
936 template<Index Log2Dim>
937 inline Index
939 {
940  OPENVDB_ASSERT((xyz[0] & (DIM-1u)) < DIM && (xyz[1] & (DIM-1u)) < DIM && (xyz[2] & (DIM-1u)) < DIM);
941  return ((xyz[0] & (DIM-1u)) << 2*Log2Dim)
942  + ((xyz[1] & (DIM-1u)) << Log2Dim)
943  + (xyz[2] & (DIM-1u));
944 }
945 
946 
947 template<Index Log2Dim>
948 inline Coord
950 {
951  OPENVDB_ASSERT(n < (1 << 3*Log2Dim));
952  Coord xyz;
953  xyz.setX(n >> 2*Log2Dim);
954  n &= ((1 << 2*Log2Dim) - 1);
955  xyz.setY(n >> Log2Dim);
956  xyz.setZ(n & ((1 << Log2Dim) - 1));
957  return xyz;
958 }
959 
960 
961 template<Index Log2Dim>
962 inline Coord
964 {
965  return (this->offsetToLocalCoord(n) + this->origin());
966 }
967 
968 
969 ////////////////////////////////////////
970 
971 
972 template<Index Log2Dim>
973 inline void
974 LeafNode<ValueMask, Log2Dim>::readTopology(std::istream& is, bool /*fromHalf*/)
975 {
976  mBuffer.mData.load(is);
977 }
978 
979 
980 template<Index Log2Dim>
981 inline void
982 LeafNode<ValueMask, Log2Dim>::writeTopology(std::ostream& os, bool /*toHalf*/) const
983 {
984  mBuffer.mData.save(os);
985 }
986 
987 
988 template<Index Log2Dim>
989 inline void
990 LeafNode<ValueMask, Log2Dim>::readBuffers(std::istream& is, const CoordBBox& clipBBox, bool fromHalf)
991 {
992  // Boolean LeafNodes don't currently implement lazy loading.
993  // Instead, load the full buffer, then clip it.
994 
995  this->readBuffers(is, fromHalf);
996 
997  // Get this tree's background value.
998  bool background = false;
999  if (const void* bgPtr = io::getGridBackgroundValuePtr(is)) {
1000  background = *static_cast<const bool*>(bgPtr);
1001  }
1002  this->clip(clipBBox, background);
1003 }
1004 
1005 
1006 template<Index Log2Dim>
1007 inline void
1008 LeafNode<ValueMask, Log2Dim>::readBuffers(std::istream& is, bool /*fromHalf*/)
1009 {
1010  // Read in the value mask = buffer.
1011  mBuffer.mData.load(is);
1012  // Read in the origin.
1013  is.read(reinterpret_cast<char*>(&mOrigin), sizeof(Coord::ValueType) * 3);
1014 }
1015 
1016 
1017 template<Index Log2Dim>
1018 inline void
1019 LeafNode<ValueMask, Log2Dim>::writeBuffers(std::ostream& os, bool /*toHalf*/) const
1020 {
1021  // Write out the value mask = buffer.
1022  mBuffer.mData.save(os);
1023  // Write out the origin.
1024  os.write(reinterpret_cast<const char*>(&mOrigin), sizeof(Coord::ValueType) * 3);
1025 }
1026 
1027 
1028 ////////////////////////////////////////
1029 
1030 
1031 template<Index Log2Dim>
1032 inline bool
1034 {
1035  return mOrigin == other.mOrigin && mBuffer == other.mBuffer;
1036 }
1037 
1038 
1039 template<Index Log2Dim>
1040 inline bool
1042 {
1043  return !(this->operator==(other));
1044 }
1045 
1046 
1047 ////////////////////////////////////////
1048 
1049 
1050 template<Index Log2Dim>
1051 inline bool
1052 LeafNode<ValueMask, Log2Dim>::isConstant(bool& constValue, bool& state, bool) const
1053 {
1054  if (!mBuffer.mData.isConstant(state)) return false;
1055 
1056  constValue = state;
1057  return true;
1058 }
1059 
1060 
1061 ////////////////////////////////////////
1062 
1063 template<Index Log2Dim>
1064 inline bool
1066 {
1067  const Index countTrue = mBuffer.mData.countOn();
1068  return countTrue > (NUM_VALUES >> 1);
1069 }
1070 
1071 template<Index Log2Dim>
1072 inline Index
1074 {
1075  const Index countTrueOn = mBuffer.mData.countOn();
1076  state = true;//since value and state are the same for this specialization of the leaf node
1077  return countTrueOn;
1078 }
1079 
1080 template<Index Log2Dim>
1081 inline Index
1083 {
1084  const Index countFalseOff = mBuffer.mData.countOff();
1085  state = false;//since value and state are the same for this specialization of the leaf node
1086  return countFalseOff;
1087 }
1088 
1089 
1090 ////////////////////////////////////////
1091 
1092 
1093 template<Index Log2Dim>
1094 inline void
1095 LeafNode<ValueMask, Log2Dim>::addTile(Index /*level*/, const Coord& xyz, bool val, bool active)
1096 {
1097  this->addTile(this->coordToOffset(xyz), val, active);
1098 }
1099 
1100 template<Index Log2Dim>
1101 inline void
1103 {
1104  OPENVDB_ASSERT(offset < SIZE);
1105  this->setValueOnly(offset, val);
1106  this->setActiveState(offset, active);
1107 }
1108 
1109 template<Index Log2Dim>
1110 template<typename AccessorT>
1111 inline void
1113  bool val, bool active, AccessorT&)
1114 {
1115  this->addTile(level, xyz, val, active);
1116 }
1117 
1118 
1119 ////////////////////////////////////////
1120 
1121 
1122 template<Index Log2Dim>
1123 inline const bool&
1125 {
1126  // This *CANNOT* use operator ? because Visual C++
1127  if (mBuffer.mData.isOn(this->coordToOffset(xyz))) return Buffer::sOn; else return Buffer::sOff;
1128 }
1129 
1130 
1131 template<Index Log2Dim>
1132 inline const bool&
1134 {
1135  OPENVDB_ASSERT(offset < SIZE);
1136  // This *CANNOT* use operator ? for Windows
1137  if (mBuffer.mData.isOn(offset)) return Buffer::sOn; else return Buffer::sOff;
1138 }
1139 
1140 
1141 template<Index Log2Dim>
1142 inline bool
1143 LeafNode<ValueMask, Log2Dim>::probeValue(const Coord& xyz, bool& val) const
1144 {
1145  return this->probeValue(this->coordToOffset(xyz), val);
1146 }
1147 
1148 
1149 template<Index Log2Dim>
1150 inline bool
1152 {
1153  val = mBuffer.mData.isOn(offset);
1154  return val;
1155 }
1156 
1157 
1158 template<Index Log2Dim>
1159 inline void
1161 {
1162  this->setValueOn(this->coordToOffset(xyz), val);
1163 }
1164 
1165 
1166 template<Index Log2Dim>
1167 inline void
1169 {
1170  OPENVDB_ASSERT(offset < SIZE);
1171  mBuffer.mData.set(offset, val);
1172 }
1173 
1174 
1175 template<Index Log2Dim>
1176 inline void
1178 {
1179  this->setValueOnly(this->coordToOffset(xyz), val);
1180 }
1181 
1182 
1183 template<Index Log2Dim>
1184 inline void
1186 {
1187  mBuffer.mData.set(this->coordToOffset(xyz), on);
1188 }
1189 
1190 
1191 template<Index Log2Dim>
1192 inline void
1194 {
1195  this->setValueOff(this->coordToOffset(xyz), val);
1196 }
1197 
1198 
1199 template<Index Log2Dim>
1200 inline void
1202 {
1203  OPENVDB_ASSERT(offset < SIZE);
1204  mBuffer.mData.set(offset, val);
1205 }
1206 
1207 
1208 template<Index Log2Dim>
1209 template<typename ModifyOp>
1210 inline void
1212 {
1213  bool val = mBuffer.mData.isOn(offset);
1214  op(val);
1215  mBuffer.mData.set(offset, val);
1216 }
1217 
1218 
1219 template<Index Log2Dim>
1220 template<typename ModifyOp>
1221 inline void
1222 LeafNode<ValueMask, Log2Dim>::modifyValue(const Coord& xyz, const ModifyOp& op)
1223 {
1224  this->modifyValue(this->coordToOffset(xyz), op);
1225 }
1226 
1227 
1228 template<Index Log2Dim>
1229 template<typename ModifyOp>
1230 inline void
1232 {
1233  const Index offset = this->coordToOffset(xyz);
1234  bool val = mBuffer.mData.isOn(offset), state = val;
1235  op(val, state);
1236  mBuffer.mData.set(offset, val);
1237 }
1238 
1239 
1240 ////////////////////////////////////////
1241 
1242 
1243 template<Index Log2Dim>
1244 template<MergePolicy Policy>
1245 inline void
1246 LeafNode<ValueMask, Log2Dim>::merge(const LeafNode& other, bool /*bg*/, bool /*otherBG*/)
1247 {
1249  if (Policy == MERGE_NODES) return;
1250  mBuffer.mData |= other.mBuffer.mData;
1252 }
1253 
1254 template<Index Log2Dim>
1255 template<MergePolicy Policy>
1256 inline void
1258 {
1260  if (Policy != MERGE_ACTIVE_STATES_AND_NODES) return;
1261  if (tileValue) mBuffer.mData.setOn();
1263 }
1264 
1265 
1266 ////////////////////////////////////////
1267 
1268 
1269 template<Index Log2Dim>
1270 template<typename OtherType>
1271 inline void
1273 {
1274  mBuffer.mData |= other.valueMask();
1275 }
1276 
1277 
1278 template<Index Log2Dim>
1279 template<typename OtherType>
1280 inline void
1282  const bool&)
1283 {
1284  mBuffer.mData &= other.valueMask();
1285 }
1286 
1287 
1288 template<Index Log2Dim>
1289 template<typename OtherType>
1290 inline void
1292  const bool&)
1293 {
1294  mBuffer.mData &= !other.valueMask();
1295 }
1296 
1297 
1298 ////////////////////////////////////////
1299 
1300 
1301 template<Index Log2Dim>
1302 inline void
1303 LeafNode<ValueMask, Log2Dim>::clip(const CoordBBox& clipBBox, bool background)
1304 {
1305  CoordBBox nodeBBox = this->getNodeBoundingBox();
1306  if (!clipBBox.hasOverlap(nodeBBox)) {
1307  // This node lies completely outside the clipping region. Fill it with background tiles.
1308  this->fill(nodeBBox, background, /*active=*/false);
1309  } else if (clipBBox.isInside(nodeBBox)) {
1310  // This node lies completely inside the clipping region. Leave it intact.
1311  return;
1312  }
1313 
1314  // This node isn't completely contained inside the clipping region.
1315  // Set any voxels that lie outside the region to the background value.
1316 
1317  // Construct a boolean mask that is on inside the clipping region and off outside it.
1319  nodeBBox.intersect(clipBBox);
1320  Coord xyz;
1321  int &x = xyz.x(), &y = xyz.y(), &z = xyz.z();
1322  for (x = nodeBBox.min().x(); x <= nodeBBox.max().x(); ++x) {
1323  for (y = nodeBBox.min().y(); y <= nodeBBox.max().y(); ++y) {
1324  for (z = nodeBBox.min().z(); z <= nodeBBox.max().z(); ++z) {
1325  mask.setOn(static_cast<Index32>(this->coordToOffset(xyz)));
1326  }
1327  }
1328  }
1329 
1330  // Set voxels that lie in the inactive region of the mask (i.e., outside
1331  // the clipping region) to the background value.
1332  for (MaskOffIter maskIter = mask.beginOff(); maskIter; ++maskIter) {
1333  this->setValueOff(maskIter.pos(), background);
1334  }
1335 }
1336 
1337 
1338 ////////////////////////////////////////
1339 
1340 
1341 template<Index Log2Dim>
1342 inline void
1344 {
1345  auto clippedBBox = this->getNodeBoundingBox();
1346  clippedBBox.intersect(bbox);
1347  if (!clippedBBox) return;
1348 
1349  for (Int32 x = clippedBBox.min().x(); x <= clippedBBox.max().x(); ++x) {
1350  const Index offsetX = (x & (DIM-1u))<<2*Log2Dim;
1351  for (Int32 y = clippedBBox.min().y(); y <= clippedBBox.max().y(); ++y) {
1352  const Index offsetXY = offsetX + ((y & (DIM-1u))<< Log2Dim);
1353  for (Int32 z = clippedBBox.min().z(); z <= clippedBBox.max().z(); ++z) {
1354  const Index offset = offsetXY + (z & (DIM-1u));
1355  mBuffer.mData.set(offset, value);
1356  }
1357  }
1358  }
1359 }
1360 
1361 template<Index Log2Dim>
1362 inline void
1364 {
1365  mBuffer.fill(value);
1366 }
1367 
1368 
1369 ////////////////////////////////////////
1370 
1371 
1372 template<Index Log2Dim>
1373 template<typename DenseT>
1374 inline void
1375 LeafNode<ValueMask, Log2Dim>::copyToDense(const CoordBBox& bbox, DenseT& dense) const
1376 {
1377  using DenseValueType = typename DenseT::ValueType;
1378 
1379  const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride();
1380  const Coord& min = dense.bbox().min();
1381  DenseValueType* t0 = dense.data() + zStride * (bbox.min()[2] - min[2]); // target array
1382  const Int32 n0 = bbox.min()[2] & (DIM-1u);
1383  for (Int32 x = bbox.min()[0], ex = bbox.max()[0] + 1; x < ex; ++x) {
1384  DenseValueType* t1 = t0 + xStride * (x - min[0]);
1385  const Int32 n1 = n0 + ((x & (DIM-1u)) << 2*LOG2DIM);
1386  for (Int32 y = bbox.min()[1], ey = bbox.max()[1] + 1; y < ey; ++y) {
1387  DenseValueType* t2 = t1 + yStride * (y - min[1]);
1388  Int32 n2 = n1 + ((y & (DIM-1u)) << LOG2DIM);
1389  for (Int32 z = bbox.min()[2], ez = bbox.max()[2] + 1; z < ez; ++z, t2 += zStride) {
1390  *t2 = DenseValueType(mBuffer.mData.isOn(n2++));
1391  }
1392  }
1393  }
1394 }
1395 
1396 
1397 template<Index Log2Dim>
1398 template<typename DenseT>
1399 inline void
1401  bool background, bool tolerance)
1402 {
1403  using DenseValueType = typename DenseT::ValueType;
1404  struct Local {
1405  inline static bool toBool(const DenseValueType& v) { return !math::isZero(v); }
1406  };
1407 
1408  const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride();
1409  const Coord& min = dense.bbox().min();
1410  const DenseValueType* s0 = dense.data() + zStride * (bbox.min()[2] - min[2]); // source
1411  const Int32 n0 = bbox.min()[2] & (DIM-1u);
1412  for (Int32 x = bbox.min()[0], ex = bbox.max()[0] + 1; x < ex; ++x) {
1413  const DenseValueType* s1 = s0 + xStride * (x - min[0]);
1414  const Int32 n1 = n0 + ((x & (DIM-1u)) << 2*LOG2DIM);
1415  for (Int32 y = bbox.min()[1], ey = bbox.max()[1] + 1; y < ey; ++y) {
1416  const DenseValueType* s2 = s1 + yStride * (y - min[1]);
1417  Int32 n2 = n1 + ((y & (DIM-1u)) << LOG2DIM);
1418  for (Int32 z = bbox.min()[2], ez = bbox.max()[2]+1; z < ez; ++z, ++n2, s2 += zStride) {
1419  // Note: if tolerance is true (i.e., 1), then all boolean values compare equal.
1420  if (tolerance || (background == Local::toBool(*s2))) {
1421  mBuffer.mData.set(n2, background);
1422  } else {
1423  mBuffer.mData.set(n2, Local::toBool(*s2));
1424  }
1425  }
1426  }
1427  }
1428 }
1429 
1430 
1431 ////////////////////////////////////////
1432 
1433 
1434 template<Index Log2Dim>
1435 template<typename CombineOp>
1436 inline void
1438 {
1440  for (Index i = 0; i < SIZE; ++i) {
1441  bool result = false, aVal = mBuffer.mData.isOn(i), bVal = other.mBuffer.mData.isOn(i);
1442  op(args.setARef(aVal)
1443  .setAIsActive(aVal)
1444  .setBRef(bVal)
1445  .setBIsActive(bVal)
1446  .setResultRef(result));
1447  mBuffer.mData.set(i, result);
1448  }
1449 }
1450 
1451 
1452 template<Index Log2Dim>
1453 template<typename CombineOp>
1454 inline void
1455 LeafNode<ValueMask, Log2Dim>::combine(bool value, bool valueIsActive, CombineOp& op)
1456 {
1458  args.setBRef(value).setBIsActive(valueIsActive);
1459  for (Index i = 0; i < SIZE; ++i) {
1460  bool result = false, aVal = mBuffer.mData.isOn(i);
1461  op(args.setARef(aVal)
1462  .setAIsActive(aVal)
1463  .setResultRef(result));
1464  mBuffer.mData.set(i, result);
1465  }
1466 }
1467 
1468 
1469 ////////////////////////////////////////
1470 
1471 
1472 template<Index Log2Dim>
1473 template<typename CombineOp, typename OtherType>
1474 inline void
1476  bool valueIsActive, CombineOp& op)
1477 {
1479  args.setBRef(value).setBIsActive(valueIsActive);
1480  for (Index i = 0; i < SIZE; ++i) {
1481  bool result = false, aVal = other.mBuffer.mData.isOn(i);
1482  op(args.setARef(aVal)
1483  .setAIsActive(aVal)
1484  .setResultRef(result));
1485  mBuffer.mData.set(i, result);
1486  }
1487 }
1488 
1489 
1490 template<Index Log2Dim>
1491 template<typename CombineOp, typename OtherNodeT>
1492 inline void
1493 LeafNode<ValueMask, Log2Dim>::combine2(bool value, const OtherNodeT& other,
1494  bool valueIsActive, CombineOp& op)
1495 {
1497  args.setARef(value).setAIsActive(valueIsActive);
1498  for (Index i = 0; i < SIZE; ++i) {
1499  bool result = false, bVal = other.mBuffer.mData.isOn(i);
1500  op(args.setBRef(bVal)
1501  .setBIsActive(bVal)
1502  .setResultRef(result));
1503  mBuffer.mData.set(i, result);
1504  }
1505 }
1506 
1507 
1508 template<Index Log2Dim>
1509 template<typename CombineOp, typename OtherNodeT>
1510 inline void
1511 LeafNode<ValueMask, Log2Dim>::combine2(const LeafNode& b0, const OtherNodeT& b1, CombineOp& op)
1512 {
1514  for (Index i = 0; i < SIZE; ++i) {
1515  bool result = false, b0Val = b0.mBuffer.mData.isOn(i), b1Val = b1.mBuffer.mData.isOn(i);
1516  op(args.setARef(b0Val)
1517  .setAIsActive(b0Val)
1518  .setBRef(b1Val)
1519  .setBIsActive(b1Val)
1520  .setResultRef(result));
1521  mBuffer.mData.set(i, result);
1522  }
1523 }
1524 
1525 
1526 } // namespace tree
1527 } // namespace OPENVDB_VERSION_NAME
1528 } // namespace openvdb
1529 
1530 #endif // OPENVDB_TREE_LEAF_NODE_MASK_HAS_BEEN_INCLUDED
static Index64 leafCount()
Return the leaf count for this node, which is one.
Definition: LeafNodeMask.h:115
void setTransientData(Index32 transientData)
Set the transient data value.
Definition: LeafNodeMask.h:178
static Index dim()
Return the number of voxels in each dimension.
Definition: LeafNodeMask.h:103
LeafNode specialization for values of type ValueMask that encodes both the active states and the bool...
Definition: LeafNodeMask.h:31
ValueIter< MaskOnIter, LeafNode, const bool > ValueOnIter
Definition: LeafNodeMask.h:666
bool isValueOnAndCache(const Coord &xyz, AccessorT &) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNodeMask.h:349
void stealNodes(ArrayT &, const ValueType &, bool)
This function exists only to enable template instantiation.
Definition: LeafNodeMask.h:553
void topologyUnion(const LeafNode< OtherType, Log2Dim > &other, const bool preserveTiles=false)
Union this node's set of active values with the active values of the other node, whose ValueType may ...
Definition: LeafNode.h:1735
ValueIter< MaskOffIter, LeafNode, const bool > ValueOffIter
Definition: LeafNodeMask.h:668
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:568
OPENVDB_API const void * getGridBackgroundValuePtr(std::ios_base &)
Return a pointer to the background value of the grid currently being read from or written to the give...
bool allocate()
Allocate memory for this node's buffer if it has not already been allocated.
Definition: LeafNodeMask.h:143
const NodeMaskType & valueMask() const
Definition: LeafNode.h:911
const bool & getValueUnsafe(Index offset) const
Return the value of the voxel at the given offset.
Definition: LeafNodeMask.h:460
bool getItem(Index pos, void *&child, NonConstValueT &value) const
Definition: LeafNodeMask.h:651
void readBuffers(std::istream &is, bool fromHalf=false)
Read buffers from a stream.
Definition: LeafNode.h:1359
const bool & getLastValue() const
Return a const reference to the last entry in the buffer.
Definition: LeafNodeMask.h:417
ValueIter< MaskDenseIter, const LeafNode, const bool > ValueAllCIter
Definition: LeafNodeMask.h:671
void setValueAndCache(const Coord &xyz, bool val, AccessorT &)
Change the value of the voxel at the given coordinates and mark it as active.
Definition: LeafNodeMask.h:354
ChildIter< MaskOffIterator, LeafNode, ChildOff > ChildOffIter
Definition: LeafNode.h:320
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:1158
void readTopology(std::istream &is, bool fromHalf=false)
Read in just the topology.
Definition: LeafNode.h:1323
void setActiveState(Index offset, bool on)
Set the active state of the voxel at the given offset but don't change its value. ...
Definition: LeafNodeMask.h:238
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: LeafNode.h:1100
void
Definition: png.h:1083
static Index64 nonLeafCount()
Return the non-leaf count for this node, which is zero.
Definition: LeafNodeMask.h:121
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don't change its value.
Definition: LeafNode.h:445
const NodeT * probeConstNode(const Coord &) const
This function exists only to enable template instantiation.
Definition: LeafNodeMask.h:551
void getNodes(ArrayT &) const
This function exists only to enable template instantiation.
Definition: LeafNodeMask.h:552
const GLdouble * v
Definition: glcorearb.h:837
static Index size()
Return the total number of voxels represented by this LeafNode.
Definition: LeafNodeMask.h:105
const LeafNode * probeConstLeaf(const Coord &) const
Return a pointer to this node.
Definition: LeafNodeMask.h:583
Buffer mBuffer
Bitmask representing the values AND state of voxels.
Definition: LeafNodeMask.h:744
bool isConstant(ValueType &firstValue, bool &state, const ValueType &tolerance=zeroVal< ValueType >()) const
Definition: LeafNode.h:1530
GLsizei const GLfloat * value
Definition: glcorearb.h:824
const LeafNode * probeConstLeafAndCache(const Coord &, AccessorT &) const
Return a pointer to this node.
Definition: LeafNodeMask.h:585
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:848
Index pos() const
Identical to offset.
Definition: Iterator.h:60
LeafNode * touchLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: LeafNodeMask.h:565
bool isAllocated() const
Return true if memory for this node's buffer has been allocated.
Definition: LeafNodeMask.h:139
GLint level
Definition: glcorearb.h:108
Coord mOrigin
Global grid index coordinates (x,y,z) of the local origin of this node.
Definition: LeafNodeMask.h:746
Index64 memUsage() const
Return the memory in bytes occupied by this node.
Definition: LeafNode.h:1484
#define OPENVDB_DEPRECATED_MESSAGE(msg)
Definition: Platform.h:148
void setValueOnUnsafe(Index offset)
Mark the voxel at the given offset as active but don't change its value.
Definition: LeafNodeMask.h:468
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:245
Base class for iterators over internal and leaf nodes.
Definition: Iterator.h:29
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
ChildIter< MaskOnIterator, const LeafNode, ChildOn > ChildOnCIter
Definition: LeafNode.h:319
**But if you need a or simply need to know when the task has note that the like this
Definition: thread.h:626
GLint y
Definition: glcorearb.h:103
ChildIter< MaskOnIterator, LeafNode, ChildOn > ChildOnIter
Definition: LeafNode.h:318
ValueIter< MaskDenseIter, LeafNode, const bool > ValueAllIter
Definition: LeafNodeMask.h:670
void clip(const CoordBBox &, const ValueType &background)
Set all voxels that lie outside the given axis-aligned box to the background.
Definition: LeafNode.h:1176
**But if you need a result
Definition: thread.h:622
static Index log2dim()
Return log2 of the size of the buffer storage.
Definition: LeafNodeMask.h:101
NodeT & parent() const
Return a reference to the node over which this iterator is iterating.
Definition: Iterator.h:50
void topologyIntersection(const LeafNode< OtherType, Log2Dim > &other, const ValueType &)
Intersect this node's set of active values with the active values of the other node, whose ValueType may be different. So a resulting voxel will be active only if both of the original voxels were active.
Definition: LeafNode.h:1743
void setValuesOn()
Mark all voxels as active but don't change their values.
Definition: LeafNodeMask.h:281
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:689
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don't change its value.
Definition: LeafNodeMask.h:246
OutGridT const XformOp bool bool
void setActiveStateUnsafe(Index offset, bool on)
Set the active state of the voxel at the given offset but don't change its value. ...
Definition: LeafNodeMask.h:464
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:1150
ValueIter< MaskOffIterator, const LeafNode, const ValueType, ValueOff > ValueOffCIter
Definition: LeafNode.h:315
bool getValueUnsafe(Index offset, bool &value) const
Return true if the voxel at the given offset is active and set value.
Definition: LeafNodeMask.h:462
const NodeT * probeConstNodeAndCache(const Coord &, AccessorT &) const
Return a pointer to this node.
Definition: LeafNodeMask.h:587
static Coord offsetToLocalCoord(Index n)
Return the local coordinates for a linear table offset, where offset 0 has coordinates (0...
Definition: LeafNode.h:1075
void writeBuffers(std::ostream &os, bool toHalf=false) const
Write buffers to a stream.
Definition: LeafNode.h:1457
ValueIter< MaskDenseIterator, LeafNode, const ValueType, ValueAll > ValueAllIter
Definition: LeafNode.h:316
void prune(const ValueType &=zeroVal< ValueType >())
This function exists only to enable template instantiation.
Definition: LeafNodeMask.h:542
static bool hasActiveTiles()
Return false since leaf nodes never contain tiles.
Definition: LeafNodeMask.h:295
#define OPENVDB_ASSERT(X)
Definition: Assert.h:41
bool isValueOn(Index offset) const
Return true if the voxel at the given offset is active.
Definition: LeafNodeMask.h:288
CoordBBox getNodeBoundingBox() const
Return the bounding box of this node, i.e., the full index space spanned by this leaf node...
Definition: LeafNodeMask.h:156
std::shared_ptr< T > SharedPtr
Definition: Types.h:114
LeafNode * touchLeaf(const Coord &)
Return a pointer to this node.
Definition: LeafNodeMask.h:563
bool isValueOn(const Coord &xyz) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNode.h:503
void setValueOnUnsafe(Index offset, const bool &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: LeafNodeMask.h:470
const Coord & origin() const
Return the grid index coordinates of this node's local origin.
Definition: LeafNodeMask.h:162
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:463
bool isDense() const
Return true if this node only contains active voxels.
Definition: LeafNodeMask.h:135
GLdouble n
Definition: glcorearb.h:2008
bool isValueOff(Index offset) const
Return true if the voxel at the given offset is inactive.
Definition: LeafNodeMask.h:292
OffMaskIterator< NodeMask > OffIterator
Definition: NodeMasks.h:349
Index64 onVoxelCount() const
Return the number of active voxels.
Definition: LeafNodeMask.h:124
GLintptr offset
Definition: glcorearb.h:665
void setOrigin(const Coord &origin)
Set the grid index coordinates of this node's local origin.
Definition: LeafNodeMask.h:159
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation. ...
Definition: NodeMasks.h:307
void swap(LeafBuffer &)
Exchange this buffer's values with the other buffer's values.
Definition: LeafBuffer.h:303
void addTile(Index level, const Coord &, const ValueType &, bool)
Definition: LeafNode.h:1635
BBox< Coord > CoordBBox
Definition: NanoVDB.h:2516
Index64 onVoxelCount() const
Return the number of voxels marked On.
Definition: LeafNode.h:143
const bool & getFirstValue() const
Return a const reference to the first entry in the buffer.
Definition: LeafNodeMask.h:413
NodeT * probeNodeAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: LeafNodeMask.h:570
ValueIter< MaskOnIter, const LeafNode, const bool > ValueOnCIter
Definition: LeafNodeMask.h:667
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:38
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:1752
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
const LeafNode * probeLeaf(const Coord &) const
Return a pointer to this node.
Definition: LeafNodeMask.h:580
ValueIter< MaskOnIterator, LeafNode, const ValueType, ValueOn > ValueOnIter
Definition: LeafNode.h:312
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:1259
void modifyItem(Index n, const ModifyOp &op) const
Definition: LeafNode.h:253
const bool & getValueAndCache(const Coord &xyz, AccessorT &) const
Return the value of the voxel at the given coordinates.
Definition: LeafNodeMask.h:344
static Index getValueLevel(const Coord &)
Return the level (0) at which leaf node values reside.
Definition: LeafNodeMask.h:233
GLint GLuint mask
Definition: glcorearb.h:124
const NodeMaskType & getValueMask() const
Definition: LeafNode.h:909
static Index getLevel()
Return the level of this node, which by definition is zero for LeafNodes.
Definition: LeafNodeMask.h:109
bool operator!=(const LeafNode &other) const
Definition: LeafNode.h:204
constexpr enabler dummy
An instance to use in EnableIf.
Definition: CLI11.h:985
void getOrigin(Int32 &x, Int32 &y, Int32 &z) const
Return the grid index coordinates of this node's local origin.
Definition: LeafNodeMask.h:164
std::string str() const
Return a string representation of this node.
Definition: LeafNode.h:1052
typename std::remove_const< UnsetItemT >::type NonConstValueType
Definition: Iterator.h:184
bool isEmpty() const
Return true if this node has no active voxels.
Definition: LeafNodeMask.h:133
ValueType medianAll(ValueType *tmp=nullptr) const
Computes the median value of all the active AND inactive voxels in this node.
Definition: LeafNode.h:1566
void setOn(Index32 n)
Set the nth bit on.
Definition: NodeMasks.h:452
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don't change its value.
Definition: LeafNode.h:435
Index64 offVoxelCount() const
Return the number of voxels marked Off.
Definition: LeafNode.h:145
void swap(Buffer &other)
Exchange this node's data buffer with the given data buffer without changing the active states of the...
Definition: LeafNodeMask.h:197
GLint GLenum GLint x
Definition: glcorearb.h:409
void setValueOffAndCache(const Coord &xyz, bool value, AccessorT &)
Change the value of the voxel at the given coordinates and mark it as inactive.
Definition: LeafNodeMask.h:365
const Coord & origin() const
Return the grid index coordinates of this node's local origin.
Definition: LeafNode.h:176
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
Definition: LeafNode.h:484
void setValueOnlyUnsafe(Index offset, const bool &value)
Set the value of the voxel at the given coordinates but don't change its active state.
Definition: LeafNodeMask.h:466
void denseFill(const CoordBBox &bbox, bool value, bool=false)
Set all voxels within an axis-aligned box to the specified value.
Definition: LeafNodeMask.h:303
that also have some descendant prim *whose name begins with which in turn has a child named baz where *the predicate active
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition: Platform.h:140
void setValueOnly(Index offset, bool val)
Set the value of the voxel at the given offset but don't change its active state. ...
Definition: LeafNodeMask.h:243
Coord offsetToGlobalCoord(Index n) const
Return the global coordinates for a linear table offset.
Definition: LeafNode.h:1089
Base class for sparse iterators over internal and leaf nodes.
Definition: Iterator.h:114
void combine2(const LeafNode &other, const OtherType &, bool valueIsActive, CombineOp &)
Definition: LeafNode.h:1816
Index32 transientData() const
Return the transient data value.
Definition: LeafNodeMask.h:176
Index medianOn(ValueType &value, ValueType *tmp=nullptr) const
Computes the median value of all the active voxels in this node.
Definition: LeafNode.h:1584
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: LeafNodeMask.h:374
CoordBBox getNodeBoundingBox() const
Return the bounding box of this node, i.e., the full index space spanned by this leaf node...
Definition: LeafNode.h:170
const LeafNode * probeLeafAndCache(const Coord &, AccessorT &) const
Return a pointer to this node.
Definition: LeafNodeMask.h:582
Base class for dense iterators over internal and leaf nodes.
Definition: Iterator.h:178
void fill(const ValueType &)
Populate this buffer with a constant value.
Definition: LeafBuffer.h:275
bool isInactive() const
Return true if all of this node's values are inactive.
Definition: LeafNodeMask.h:451
DenseMaskIterator< NodeMask > DenseIterator
Definition: NodeMasks.h:350
Library and file format version numbers.
void negate()
Invert the bits of the voxels, i.e. states and values.
Definition: LeafNodeMask.h:481
bool probeValueAndCache(const Coord &xyz, bool &val, AccessorT &) const
Return true if the voxel at the given coordinates is active and return the voxel value in val...
Definition: LeafNodeMask.h:400
LeafNode * probeLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: LeafNodeMask.h:568
ValueIter< MaskOnIterator, const LeafNode, const ValueType, ValueOn > ValueOnCIter
Definition: LeafNode.h:313
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don't change its value.
Definition: LeafNodeMask.h:256
void setItem(Index pos, const ValueT &value) const
Definition: LeafNode.h:238
NodeT * stealNode(const Coord &, const ValueType &, bool)
This function exists only to enable template instantiation.
Definition: LeafNodeMask.h:547
void nodeCount(std::vector< Index64 > &) const
no-op
Definition: LeafNodeMask.h:117
bool probeValue(const Coord &xyz, ValueType &val) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNode.h:1116
CombineArgs & setBRef(const BValueType &b)
Redirect the B value to a new external source.
Definition: Types.h:623
void combine(const LeafNode &other, CombineOp &op)
Definition: LeafNode.h:1776
void modifyValueAndActiveStateAndCache(const Coord &xyz, const ModifyOp &op, AccessorT &)
Definition: LeafNodeMask.h:382
Index64 offVoxelCount() const
Return the number of inactive voxels.
Definition: LeafNodeMask.h:126
static void getNodeLog2Dims(std::vector< Index > &dims)
Append the Log2Dim of this LeafNode to the specified vector.
Definition: LeafNodeMask.h:111
Index medianOff(ValueType &value, ValueType *tmp=nullptr) const
Computes the median value of all the inactive voxels in this node.
Definition: LeafNode.h:1608
void addTileAndCache(Index, const Coord &, const ValueType &, bool, AccessorT &)
Definition: LeafNode.h:1652
ValueIter< MaskDenseIterator, const LeafNode, const ValueType, ValueAll > ValueAllCIter
Definition: LeafNode.h:317
OnMaskIterator< NodeMask > OnIterator
Definition: NodeMasks.h:348
void setValueOffUnsafe(Index offset, const bool &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: LeafNodeMask.h:474
GLuint GLfloat * val
Definition: glcorearb.h:1608
void setValueOnlyAndCache(const Coord &xyz, bool val, AccessorT &)
Change the value of the voxel at the given coordinates but preserve its state.
Definition: LeafNodeMask.h:360
**If you just want to fire and args
Definition: thread.h:618
CombineArgs & setARef(const AValueType &a)
Redirect the A value to a new external source.
Definition: Types.h:621
ValueIter< MaskOffIter, const LeafNode, const bool > ValueOffCIter
Definition: LeafNodeMask.h:669
void addLeafAndCache(LeafNode *, AccessorT &)
This function exists only to enable template instantiation.
Definition: LeafNodeMask.h:545
NodeT * probeNode(const Coord &)
This function exists only to enable template instantiation.
Definition: LeafNodeMask.h:549
void setValueOffUnsafe(Index offset)
Mark the voxel at the given offset as inactive but don't change its value.
Definition: LeafNodeMask.h:472
void setValueOn(Index offset)
Mark the voxel at the given offset as active but don't change its value.
Definition: LeafNodeMask.h:258
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:1286
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:141
static Index getChildDim()
Return the dimension of child nodes of this LeafNode, which is one for voxels.
Definition: LeafNodeMask.h:113
void setValuesOff()
Mark all voxels as inactive but don't change their values.
Definition: LeafNodeMask.h:283
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:683
bool isValueOff(const Coord &xyz) const
Return true if the voxel at the given coordinates is inactive.
Definition: LeafNodeMask.h:290
LeafNode * probeLeaf(const Coord &)
Return a pointer to this node.
Definition: LeafNodeMask.h:566
void setValue(Index i, const ValueType &)
Set the i'th value of this buffer to the specified value.
Definition: LeafBuffer.h:233
DenseIter< const LeafNode, const ValueType, ChildAll > ChildAllCIter
Definition: LeafNode.h:323
void setValueOff(Index offset)
Mark the voxel at the given offset as inactive but don't change its value.
Definition: LeafNodeMask.h:248
bool isValueOn(const Coord &xyz) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNodeMask.h:286
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:1522
bool operator==(const LeafNode &other) const
Check for buffer, state and origin equivalence.
Definition: LeafNode.h:1474
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:119
void evalActiveBoundingBox(CoordBBox &bbox, bool visitVoxels=true) const
Definition: LeafNode.h:1504
static Index numValues()
Return the total number of voxels represented by this LeafNode.
Definition: LeafNodeMask.h:107
static Index coordToOffset(const Coord &xyz)
Return the linear table offset of the given global or local coordinates.
Definition: LeafNode.h:1065
bool ValueType
Definition: NanoVDB.h:5729
state
Definition: core.h:2289
static void evalNodeOrigin(Coord &xyz)
Compute the origin of the leaf node that contains the voxel with the given coordinates.
Definition: LeafNodeMask.h:741
ChildIter< MaskOffIterator, const LeafNode, ChildOff > ChildOffCIter
Definition: LeafNode.h:321
void setValue(const Coord &xyz, bool val)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: LeafNodeMask.h:263
static Index getValueLevelAndCache(const Coord &, AccessorT &)
Return the LEVEL (=0) at which leaf node values reside.
Definition: LeafNodeMask.h:408
void addLeaf(LeafNode *)
This function exists only to enable template instantiation.
Definition: LeafNodeMask.h:543
bool isZero(const Type &x)
Return true if x is exactly equal to zero.
Definition: Math.h:337
void writeTopology(std::ostream &os, bool toHalf=false) const
Write out just the topology.
Definition: LeafNode.h:1331
void nodeCount(std::vector< Index64 > &) const
no-op
Definition: LeafNode.h:134
DenseIter< LeafNode, ValueType, ChildAll > ChildAllIter
Definition: LeafNode.h:322
void resetBackground(bool, bool)
no-op since for this template specialization voxel values and states are indistinguishable.
Definition: LeafNodeMask.h:478
void getOrigin(Coord &origin) const
Return the grid index coordinates of this node's local origin.
Definition: LeafNodeMask.h:163
ValueIter< MaskOffIterator, LeafNode, const ValueType, ValueOff > ValueOffIter
Definition: LeafNode.h:314
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &)
Set the active state of the voxel at the given coordinates without changing its value.
Definition: LeafNodeMask.h:391
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:1216
Index32 transientData() const
Return the transient data value.
Definition: LeafNode.h:190