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