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 
145  /// Expand the given bounding box so that it includes this leaf node's active voxels.
146  /// If visitVoxels is false this LeafNode will be approximated as dense, i.e. with all
147  /// voxels active. Else the individual active voxels are visited to produce a tight bbox.
148  void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const;
149 
150  /// @brief Return the bounding box of this node, i.e., the full index space
151  /// spanned by this leaf node.
152  CoordBBox getNodeBoundingBox() const { return CoordBBox::createCube(mOrigin, DIM); }
153 
154  /// Set the grid index coordinates of this node's local origin.
155  void setOrigin(const Coord& origin) { mOrigin = origin; }
156  //@{
157  /// Return the grid index coordinates of this node's local origin.
158  const Coord& origin() const { return mOrigin; }
159  void getOrigin(Coord& origin) const { origin = mOrigin; }
160  void getOrigin(Int32& x, Int32& y, Int32& z) const { mOrigin.asXYZ(x, y, z); }
161  //@}
162 
163  /// Return the linear table offset of the given global or local coordinates.
164  static Index coordToOffset(const Coord& xyz);
165  /// @brief Return the local coordinates for a linear table offset,
166  /// where offset 0 has coordinates (0, 0, 0).
167  static Coord offsetToLocalCoord(Index n);
168  /// Return the global coordinates for a linear table offset.
169  Coord offsetToGlobalCoord(Index n) const;
170 
171 #if OPENVDB_ABI_VERSION_NUMBER >= 9
172  /// Return the transient data value.
173  Index32 transientData() const { return mTransientData; }
174  /// Set the transient data value.
175  void setTransientData(Index32 transientData) { mTransientData = transientData; }
176 #endif
177 
178  /// Return a string representation of this node.
179  std::string str() const;
180 
181  /// @brief Return @c true if the given node (which may have a different @c ValueType
182  /// than this node) has the same active value topology as this node.
183  template<typename OtherType, Index OtherLog2Dim>
184  bool hasSameTopology(const LeafNode<OtherType, OtherLog2Dim>* other) const;
185 
186  /// Check for buffer equivalence by value.
187  bool operator==(const LeafNode&) const;
188  bool operator!=(const LeafNode&) const;
189 
190  //
191  // Buffer management
192  //
193  /// @brief Exchange this node's data buffer with the given data buffer
194  /// without changing the active states of the values.
195  void swap(Buffer& other) { mBuffer.swap(other); }
196  const Buffer& buffer() const { return mBuffer; }
197  Buffer& buffer() { return mBuffer; }
198 
199  //
200  // I/O methods
201  //
202  /// Read in just the topology.
203  void readTopology(std::istream&, bool fromHalf = false);
204  /// Write out just the topology.
205  void writeTopology(std::ostream&, bool toHalf = false) const;
206 
207  /// Read in the topology and the origin.
208  void readBuffers(std::istream&, bool fromHalf = false);
209  void readBuffers(std::istream& is, const CoordBBox&, bool fromHalf = false);
210  /// Write out the topology and the origin.
211  void writeBuffers(std::ostream&, bool toHalf = false) const;
212 
213  //
214  // Accessor methods
215  //
216  /// Return the value of the voxel at the given coordinates.
217  const bool& getValue(const Coord& xyz) const;
218  /// Return the value of the voxel at the given offset.
219  const bool& getValue(Index offset) const;
220 
221  /// @brief Return @c true if the voxel at the given coordinates is active.
222  /// @param xyz the coordinates of the voxel to be probed
223  /// @param[out] val the value of the voxel at the given coordinates
224  bool probeValue(const Coord& xyz, bool& val) const;
225 
226  /// Return the level (0) at which leaf node values reside.
227  static Index getValueLevel(const Coord&) { return LEVEL; }
228 
229  /// Set the active state of the voxel at the given coordinates but don't change its value.
230  void setActiveState(const Coord& xyz, bool on);
231  /// Set the active state of the voxel at the given offset but don't change its value.
232  void setActiveState(Index offset, bool on) { assert(offset<SIZE); mBuffer.mData.set(offset, on); }
233 
234  /// Set the value of the voxel at the given coordinates but don't change its active state.
235  void setValueOnly(const Coord& xyz, bool val);
236  /// Set the value of the voxel at the given offset but don't change its active state.
237  void setValueOnly(Index offset, bool val) { assert(offset<SIZE); mBuffer.setValue(offset,val); }
238 
239  /// Mark the voxel at the given coordinates as inactive but don't change its value.
240  void setValueOff(const Coord& xyz) { mBuffer.mData.setOff(this->coordToOffset(xyz)); }
241  /// Mark the voxel at the given offset as inactive but don't change its value.
242  void setValueOff(Index offset) { assert(offset < SIZE); mBuffer.mData.setOff(offset); }
243 
244  /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
245  void setValueOff(const Coord& xyz, bool val);
246  /// Set the value of the voxel at the given offset and mark the voxel as inactive.
247  void setValueOff(Index offset, bool val);
248 
249  /// Mark the voxel at the given coordinates as active but don't change its value.
250  void setValueOn(const Coord& xyz) { mBuffer.mData.setOn(this->coordToOffset(xyz)); }
251  /// Mark the voxel at the given offset as active but don't change its value.
252  void setValueOn(Index offset) { assert(offset < SIZE); mBuffer.mData.setOn(offset); }
253 
254  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
255  void setValueOn(const Coord& xyz, bool val);
256  /// Set the value of the voxel at the given coordinates and mark the voxel as active.
257  void setValue(const Coord& xyz, bool val) { this->setValueOn(xyz, val); }
258  /// Set the value of the voxel at the given offset and mark the voxel as active.
259  void setValueOn(Index offset, bool val);
260 
261  /// @brief Apply a functor to the value of the voxel at the given offset
262  /// and mark the voxel as active.
263  template<typename ModifyOp>
264  void modifyValue(Index offset, const ModifyOp& op);
265  /// @brief Apply a functor to the value of the voxel at the given coordinates
266  /// and mark the voxel as active.
267  template<typename ModifyOp>
268  void modifyValue(const Coord& xyz, const ModifyOp& op);
269 
270  /// Apply a functor to the voxel at the given coordinates.
271  template<typename ModifyOp>
272  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op);
273 
274  /// Mark all voxels as active but don't change their values.
275  void setValuesOn() { mBuffer.mData.setOn(); }
276  /// Mark all voxels as inactive but don't change their values.
277  void setValuesOff() { mBuffer.mData.setOff(); }
278 
279  /// Return @c true if the voxel at the given coordinates is active.
280  bool isValueOn(const Coord& xyz) const { return mBuffer.mData.isOn(this->coordToOffset(xyz)); }
281  /// Return @c true if the voxel at the given offset is active.
282  bool isValueOn(Index offset) const { assert(offset < SIZE); return mBuffer.mData.isOn(offset); }
283 
284  /// Return @c false since leaf nodes never contain tiles.
285  static bool hasActiveTiles() { return false; }
286 
287  /// Set all voxels that lie outside the given axis-aligned box to the background.
288  void clip(const CoordBBox&, bool background);
289 
290  /// Set all voxels within an axis-aligned box to the specified value.
291  void fill(const CoordBBox& bbox, bool value, bool = false);
292  /// Set all voxels within an axis-aligned box to the specified value.
293  void denseFill(const CoordBBox& bbox, bool value, bool = false) { this->fill(bbox, value); }
294 
295  /// Set the state of all voxels to the specified active state.
296  void fill(const bool& value, bool dummy = false);
297 
298  /// @brief Copy into a dense grid the values of the voxels that lie within
299  /// a given bounding box.
300  ///
301  /// @param bbox inclusive bounding box of the voxels to be copied into the dense grid
302  /// @param dense dense grid with a stride in @e z of one (see tools::Dense
303  /// in tools/Dense.h for the required API)
304  ///
305  /// @note @a bbox is assumed to be identical to or contained in the coordinate domains
306  /// of both the dense grid and this node, i.e., no bounds checking is performed.
307  /// @note Consider using tools::CopyToDense in tools/Dense.h
308  /// instead of calling this method directly.
309  template<typename DenseT>
310  void copyToDense(const CoordBBox& bbox, DenseT& dense) const;
311 
312  /// @brief Copy from a dense grid into this node the values of the voxels
313  /// that lie within a given bounding box.
314  /// @details Only values that are different (by more than the given tolerance)
315  /// from the background value will be active. Other values are inactive
316  /// and truncated to the background value.
317  ///
318  /// @param bbox inclusive bounding box of the voxels to be copied into this node
319  /// @param dense dense grid with a stride in @e z of one (see tools::Dense
320  /// in tools/Dense.h for the required API)
321  /// @param background background value of the tree that this node belongs to
322  /// @param tolerance tolerance within which a value equals the background value
323  ///
324  /// @note @a bbox is assumed to be identical to or contained in the coordinate domains
325  /// of both the dense grid and this node, i.e., no bounds checking is performed.
326  /// @note Consider using tools::CopyFromDense in tools/Dense.h
327  /// instead of calling this method directly.
328  template<typename DenseT>
329  void copyFromDense(const CoordBBox& bbox, const DenseT& dense, bool background, bool tolerance);
330 
331  /// @brief Return the value of the voxel at the given coordinates.
332  /// @note Used internally by ValueAccessor.
333  template<typename AccessorT>
334  const bool& getValueAndCache(const Coord& xyz, AccessorT&) const {return this->getValue(xyz);}
335 
336  /// @brief Return @c true if the voxel at the given coordinates is active.
337  /// @note Used internally by ValueAccessor.
338  template<typename AccessorT>
339  bool isValueOnAndCache(const Coord& xyz, AccessorT&) const { return this->isValueOn(xyz); }
340 
341  /// @brief Change the value of the voxel at the given coordinates and mark it as active.
342  /// @note Used internally by ValueAccessor.
343  template<typename AccessorT>
344  void setValueAndCache(const Coord& xyz, bool val, AccessorT&) { this->setValueOn(xyz, val); }
345 
346  /// @brief Change the value of the voxel at the given coordinates
347  /// but preserve its state.
348  /// @note Used internally by ValueAccessor.
349  template<typename AccessorT>
350  void setValueOnlyAndCache(const Coord& xyz, bool val, AccessorT&) {this->setValueOnly(xyz,val);}
351 
352  /// @brief Change the value of the voxel at the given coordinates and mark it as inactive.
353  /// @note Used internally by ValueAccessor.
354  template<typename AccessorT>
355  void setValueOffAndCache(const Coord& xyz, bool value, AccessorT&)
356  {
357  this->setValueOff(xyz, value);
358  }
359 
360  /// @brief Apply a functor to the value of the voxel at the given coordinates
361  /// and mark the voxel as active.
362  /// @note Used internally by ValueAccessor.
363  template<typename ModifyOp, typename AccessorT>
364  void modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&)
365  {
366  this->modifyValue(xyz, op);
367  }
368 
369  /// Apply a functor to the voxel at the given coordinates.
370  /// @note Used internally by ValueAccessor.
371  template<typename ModifyOp, typename AccessorT>
372  void modifyValueAndActiveStateAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&)
373  {
374  this->modifyValueAndActiveState(xyz, op);
375  }
376 
377  /// @brief Set the active state of the voxel at the given coordinates
378  /// without changing its value.
379  /// @note Used internally by ValueAccessor.
380  template<typename AccessorT>
381  void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&)
382  {
383  this->setActiveState(xyz, on);
384  }
385 
386  /// @brief Return @c true if the voxel at the given coordinates is active
387  /// and return the voxel value in @a val.
388  /// @note Used internally by ValueAccessor.
389  template<typename AccessorT>
390  bool probeValueAndCache(const Coord& xyz, bool& val, AccessorT&) const
391  {
392  return this->probeValue(xyz, val);
393  }
394 
395  /// @brief Return the LEVEL (=0) at which leaf node values reside.
396  /// @note Used internally by ValueAccessor.
397  template<typename AccessorT>
398  static Index getValueLevelAndCache(const Coord&, AccessorT&) { return LEVEL; }
399 
400  /// @brief Return a const reference to the first entry in the buffer.
401  /// @note Since it's actually a reference to a static data member
402  /// it should not be converted to a non-const pointer!
403  const bool& getFirstValue() const { if (mBuffer.mData.isOn(0)) return Buffer::sOn; else return Buffer::sOff; }
404  /// @brief Return a const reference to the last entry in the buffer.
405  /// @note Since it's actually a reference to a static data member
406  /// it should not be converted to a non-const pointer!
407  const bool& getLastValue() const { if (mBuffer.mData.isOn(SIZE-1)) return Buffer::sOn; else return Buffer::sOff; }
408 
409  /// Return @c true if all of this node's voxels have the same active state
410  /// and are equal to within the given tolerance, and return the value in
411  /// @a constValue and the active state in @a state.
412  bool isConstant(bool& constValue, bool& state, bool tolerance = 0) const;
413 
414  /// @brief Computes the median value of all the active and inactive voxels in this node.
415  /// @return The median value.
416  ///
417  /// @details The median for boolean values is defined as the mode
418  /// of the values, i.e. the value that occurs most often.
419  bool medianAll() const;
420 
421  /// @brief Computes the median value of all the active voxels in this node.
422  /// @return The number of active voxels.
423  ///
424  /// @param value Updated with the median value of all the active voxels.
425  ///
426  /// @note Since the value and state are shared for this
427  /// specialization of the LeafNode the @a value will always be true!
428  Index medianOn(ValueType &value) const;
429 
430  /// @brief Computes the median value of all the inactive voxels in this node.
431  /// @return The number of inactive voxels.
432  ///
433  /// @param value Updated with the median value of all the inactive
434  /// voxels.
435  ///
436  /// @note Since the value and state are shared for this
437  /// specialization of the LeafNode the @a value will always be false!
438  Index medianOff(ValueType &value) const;
439 
440  /// Return @c true if all of this node's values are inactive.
441  bool isInactive() const { return mBuffer.mData.isOff(); }
442 
443  /// @brief no-op since for this temaplte specialization voxel
444  /// values and states are indistinguishable.
445  void resetBackground(bool, bool) {}
446 
447  /// @brief Invert the bits of the voxels, i.e. states and values
448  void negate() { mBuffer.mData.toggle(); }
449 
450  template<MergePolicy Policy>
451  void merge(const LeafNode& other, bool bg = false, bool otherBG = false);
452  template<MergePolicy Policy> void merge(bool tileValue, bool tileActive=false);
453 
454  /// @brief No-op
455  /// @details This function exists only to enable template instantiation.
456  void voxelizeActiveTiles(bool = true) {}
457 
458  /// @brief Union this node's set of active values with the active values
459  /// of the other node, whose @c ValueType may be different. So a
460  /// resulting voxel will be active if either of the original voxels
461  /// were active.
462  ///
463  /// @note This operation modifies only active states, not values.
464  template<typename OtherType>
465  void topologyUnion(const LeafNode<OtherType, Log2Dim>& other, const bool preserveTiles = false);
466 
467  /// @brief Intersect this node's set of active values with the active values
468  /// of the other node, whose @c ValueType may be different. So a
469  /// resulting voxel will be active only if both of the original voxels
470  /// were active.
471  ///
472  /// @details The last dummy argument is required to match the signature
473  /// for InternalNode::topologyIntersection.
474  ///
475  /// @note This operation modifies only active states, not
476  /// values. Also note that this operation can result in all voxels
477  /// being inactive so consider subsequnetly calling prune.
478  template<typename OtherType>
479  void topologyIntersection(const LeafNode<OtherType, Log2Dim>& other, const bool&);
480 
481  /// @brief Difference this node's set of active values with the active values
482  /// of the other node, whose @c ValueType may be different. So a
483  /// resulting voxel will be active only if the original voxel is
484  /// active in this LeafNode and inactive in the other LeafNode.
485  ///
486  /// @details The last dummy argument is required to match the signature
487  /// for InternalNode::topologyDifference.
488  ///
489  /// @note This operation modifies only active states, not values.
490  /// Also, because it can deactivate all of this node's voxels,
491  /// consider subsequently calling prune.
492  template<typename OtherType>
493  void topologyDifference(const LeafNode<OtherType, Log2Dim>& other, const bool&);
494 
495  template<typename CombineOp>
496  void combine(const LeafNode& other, CombineOp& op);
497  template<typename CombineOp>
498  void combine(bool, bool valueIsActive, CombineOp& op);
499 
500  template<typename CombineOp, typename OtherType /*= bool*/>
501  void combine2(const LeafNode& other, const OtherType&, bool valueIsActive, CombineOp&);
502  template<typename CombineOp, typename OtherNodeT /*= LeafNode*/>
503  void combine2(bool, const OtherNodeT& other, bool valueIsActive, CombineOp&);
504  template<typename CombineOp, typename OtherNodeT /*= LeafNode*/>
505  void combine2(const LeafNode& b0, const OtherNodeT& b1, CombineOp&);
506 
507  /// @brief Calls the templated functor BBoxOp with bounding box information.
508  /// An additional level argument is provided to the callback.
509  ///
510  /// @note The bounding boxes are guarenteed to be non-overlapping.
511  template<typename BBoxOp> void visitActiveBBox(BBoxOp&) const;
512 
513  template<typename VisitorOp> void visit(VisitorOp&);
514  template<typename VisitorOp> void visit(VisitorOp&) const;
515 
516  template<typename OtherLeafNodeType, typename VisitorOp>
517  void visit2Node(OtherLeafNodeType& other, VisitorOp&);
518  template<typename OtherLeafNodeType, typename VisitorOp>
519  void visit2Node(OtherLeafNodeType& other, VisitorOp&) const;
520  template<typename IterT, typename VisitorOp>
521  void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false);
522  template<typename IterT, typename VisitorOp>
523  void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false) const;
524 
525  //@{
526  /// This function exists only to enable template instantiation.
527  void prune(const ValueType& /*tolerance*/ = zeroVal<ValueType>()) {}
528  void addLeaf(LeafNode*) {}
529  template<typename AccessorT>
530  void addLeafAndCache(LeafNode*, AccessorT&) {}
531  template<typename NodeT>
532  NodeT* stealNode(const Coord&, const ValueType&, bool) { return nullptr; }
533  template<typename NodeT>
534  NodeT* probeNode(const Coord&) { return nullptr; }
535  template<typename NodeT>
536  const NodeT* probeConstNode(const Coord&) const { return nullptr; }
537  template<typename ArrayT> void getNodes(ArrayT&) const {}
538  template<typename ArrayT> void stealNodes(ArrayT&, const ValueType&, bool) {}
539  //@}
540 
541  void addTile(Index level, const Coord&, bool val, bool active);
542  void addTile(Index offset, bool val, bool active);
543  template<typename AccessorT>
544  void addTileAndCache(Index level, const Coord&, bool val, bool active, AccessorT&);
545 
546  //@{
547  /// @brief Return a pointer to this node.
548  LeafNode* touchLeaf(const Coord&) { return this; }
549  template<typename AccessorT>
550  LeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; }
551  LeafNode* probeLeaf(const Coord&) { return this; }
552  template<typename AccessorT>
553  LeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; }
554  template<typename NodeT, typename AccessorT>
555  NodeT* probeNodeAndCache(const Coord&, AccessorT&)
556  {
558  if (!(std::is_same<NodeT, LeafNode>::value)) return nullptr;
559  return reinterpret_cast<NodeT*>(this);
561  }
562  //@}
563  //@{
564  /// @brief Return a @const pointer to this node.
565  const LeafNode* probeLeaf(const Coord&) const { return this; }
566  template<typename AccessorT>
567  const LeafNode* probeLeafAndCache(const Coord&, AccessorT&) const { return this; }
568  const LeafNode* probeConstLeaf(const Coord&) const { return this; }
569  template<typename AccessorT>
570  const LeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const { return this; }
571  template<typename NodeT, typename AccessorT>
572  const NodeT* probeConstNodeAndCache(const Coord&, AccessorT&) const
573  {
575  if (!(std::is_same<NodeT, LeafNode>::value)) return nullptr;
576  return reinterpret_cast<const NodeT*>(this);
578  }
579  //@}
580 
581  //
582  // Iterators
583  //
584 protected:
588 
589  template<typename MaskIterT, typename NodeT, typename ValueT>
590  struct ValueIter:
591  // Derives from SparseIteratorBase, but can also be used as a dense iterator,
592  // if MaskIterT is a dense mask iterator type.
593  public SparseIteratorBase<MaskIterT, ValueIter<MaskIterT, NodeT, ValueT>, NodeT, ValueT>
594  {
596 
598  ValueIter(const MaskIterT& iter, NodeT* parent): BaseT(iter, parent) {}
599 
600  const bool& getItem(Index pos) const { return this->parent().getValue(pos); }
601  const bool& getValue() const { return this->getItem(this->pos()); }
602 
603  // Note: setItem() can't be called on const iterators.
604  void setItem(Index pos, bool value) const { this->parent().setValueOnly(pos, value); }
605  // Note: setValue() can't be called on const iterators.
606  void setValue(bool value) const { this->setItem(this->pos(), value); }
607 
608  // Note: modifyItem() can't be called on const iterators.
609  template<typename ModifyOp>
610  void modifyItem(Index n, const ModifyOp& op) const { this->parent().modifyValue(n, op); }
611  // Note: modifyValue() can't be called on const iterators.
612  template<typename ModifyOp>
613  void modifyValue(const ModifyOp& op) const { this->modifyItem(this->pos(), op); }
614  };
615 
616  /// Leaf nodes have no children, so their child iterators have no get/set accessors.
617  template<typename MaskIterT, typename NodeT>
618  struct ChildIter:
619  public SparseIteratorBase<MaskIterT, ChildIter<MaskIterT, NodeT>, NodeT, bool>
620  {
622  ChildIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase<
623  MaskIterT, ChildIter<MaskIterT, NodeT>, NodeT, bool>(iter, parent) {}
624  };
625 
626  template<typename NodeT, typename ValueT>
627  struct DenseIter: public DenseIteratorBase<
628  MaskDenseIter, DenseIter<NodeT, ValueT>, NodeT, /*ChildT=*/void, ValueT>
629  {
632 
634  DenseIter(const MaskDenseIter& iter, NodeT* parent): BaseT(iter, parent) {}
635 
636  bool getItem(Index pos, void*& child, NonConstValueT& value) const
637  {
638  value = this->parent().getValue(pos);
639  child = nullptr;
640  return false; // no child
641  }
642 
643  // Note: setItem() can't be called on const iterators.
644  //void setItem(Index pos, void* child) const {}
645 
646  // Note: unsetItem() can't be called on const iterators.
647  void unsetItem(Index pos, const ValueT& val) const {this->parent().setValueOnly(pos, val);}
648  };
649 
650 public:
651  using ValueOnIter = ValueIter<MaskOnIter, LeafNode, const bool>;
652  using ValueOnCIter = ValueIter<MaskOnIter, const LeafNode, const bool>;
653  using ValueOffIter = ValueIter<MaskOffIter, LeafNode, const bool>;
654  using ValueOffCIter = ValueIter<MaskOffIter, const LeafNode, const bool>;
655  using ValueAllIter = ValueIter<MaskDenseIter, LeafNode, const bool>;
656  using ValueAllCIter = ValueIter<MaskDenseIter, const LeafNode, const bool>;
657  using ChildOnIter = ChildIter<MaskOnIter, LeafNode>;
658  using ChildOnCIter = ChildIter<MaskOnIter, const LeafNode>;
659  using ChildOffIter = ChildIter<MaskOffIter, LeafNode>;
660  using ChildOffCIter = ChildIter<MaskOffIter, const LeafNode>;
661  using ChildAllIter = DenseIter<LeafNode, bool>;
662  using ChildAllCIter = DenseIter<const LeafNode, const bool>;
663 
664  ValueOnCIter cbeginValueOn() const { return ValueOnCIter(mBuffer.mData.beginOn(), this); }
665  ValueOnCIter beginValueOn() const { return ValueOnCIter(mBuffer.mData.beginOn(), this); }
666  ValueOnIter beginValueOn() { return ValueOnIter(mBuffer.mData.beginOn(), this); }
667  ValueOffCIter cbeginValueOff() const { return ValueOffCIter(mBuffer.mData.beginOff(), this); }
668  ValueOffCIter beginValueOff() const { return ValueOffCIter(mBuffer.mData.beginOff(), this); }
669  ValueOffIter beginValueOff() { return ValueOffIter(mBuffer.mData.beginOff(), this); }
670  ValueAllCIter cbeginValueAll() const { return ValueAllCIter(mBuffer.mData.beginDense(), this); }
671  ValueAllCIter beginValueAll() const { return ValueAllCIter(mBuffer.mData.beginDense(), this); }
672  ValueAllIter beginValueAll() { return ValueAllIter(mBuffer.mData.beginDense(), this); }
673 
674  ValueOnCIter cendValueOn() const { return ValueOnCIter(mBuffer.mData.endOn(), this); }
675  ValueOnCIter endValueOn() const { return ValueOnCIter(mBuffer.mData.endOn(), this); }
676  ValueOnIter endValueOn() { return ValueOnIter(mBuffer.mData.endOn(), this); }
677  ValueOffCIter cendValueOff() const { return ValueOffCIter(mBuffer.mData.endOff(), this); }
678  ValueOffCIter endValueOff() const { return ValueOffCIter(mBuffer.mData.endOff(), this); }
679  ValueOffIter endValueOff() { return ValueOffIter(mBuffer.mData.endOff(), this); }
680  ValueAllCIter cendValueAll() const { return ValueAllCIter(mBuffer.mData.endDense(), this); }
681  ValueAllCIter endValueAll() const { return ValueAllCIter(mBuffer.mData.endDense(), this); }
682  ValueAllIter endValueAll() { return ValueAllIter(mBuffer.mData.endDense(), this); }
683 
684  // Note that [c]beginChildOn() and [c]beginChildOff() actually return end iterators,
685  // because leaf nodes have no children.
686  ChildOnCIter cbeginChildOn() const { return ChildOnCIter(mBuffer.mData.endOn(), this); }
687  ChildOnCIter beginChildOn() const { return ChildOnCIter(mBuffer.mData.endOn(), this); }
688  ChildOnIter beginChildOn() { return ChildOnIter(mBuffer.mData.endOn(), this); }
689  ChildOffCIter cbeginChildOff() const { return ChildOffCIter(mBuffer.mData.endOff(), this); }
690  ChildOffCIter beginChildOff() const { return ChildOffCIter(mBuffer.mData.endOff(), this); }
691  ChildOffIter beginChildOff() { return ChildOffIter(mBuffer.mData.endOff(), this); }
692  ChildAllCIter cbeginChildAll() const { return ChildAllCIter(mBuffer.mData.beginDense(), this); }
693  ChildAllCIter beginChildAll() const { return ChildAllCIter(mBuffer.mData.beginDense(), this); }
694  ChildAllIter beginChildAll() { return ChildAllIter(mBuffer.mData.beginDense(), this); }
695 
696  ChildOnCIter cendChildOn() const { return ChildOnCIter(mBuffer.mData.endOn(), this); }
697  ChildOnCIter endChildOn() const { return ChildOnCIter(mBuffer.mData.endOn(), this); }
698  ChildOnIter endChildOn() { return ChildOnIter(mBuffer.mData.endOn(), this); }
699  ChildOffCIter cendChildOff() const { return ChildOffCIter(mBuffer.mData.endOff(), this); }
700  ChildOffCIter endChildOff() const { return ChildOffCIter(mBuffer.mData.endOff(), this); }
701  ChildOffIter endChildOff() { return ChildOffIter(mBuffer.mData.endOff(), this); }
702  ChildAllCIter cendChildAll() const { return ChildAllCIter(mBuffer.mData.endDense(), this); }
703  ChildAllCIter endChildAll() const { return ChildAllCIter(mBuffer.mData.endDense(), this); }
704  ChildAllIter endChildAll() { return ChildAllIter(mBuffer.mData.endDense(), this); }
705 
706  //
707  // Mask accessors
708  //
709  bool isValueMaskOn(Index n) const { return mBuffer.mData.isOn(n); }
710  bool isValueMaskOn() const { return mBuffer.mData.isOn(); }
711  bool isValueMaskOff(Index n) const { return mBuffer.mData.isOff(n); }
712  bool isValueMaskOff() const { return mBuffer.mData.isOff(); }
713  const NodeMaskType& getValueMask() const { return mBuffer.mData; }
714  const NodeMaskType& valueMask() const { return mBuffer.mData; }
715  NodeMaskType& getValueMask() { return mBuffer.mData; }
716  void setValueMask(const NodeMaskType& mask) { mBuffer.mData = mask; }
717  bool isChildMaskOn(Index) const { return false; } // leaf nodes have no children
718  bool isChildMaskOff(Index) const { return true; }
719  bool isChildMaskOff() const { return true; }
720 protected:
721  void setValueMask(Index n, bool on) { mBuffer.mData.set(n, on); }
722  void setValueMaskOn(Index n) { mBuffer.mData.setOn(n); }
723  void setValueMaskOff(Index n) { mBuffer.mData.setOff(n); }
724 
725  /// Compute the origin of the leaf node that contains the voxel with the given coordinates.
726  static void evalNodeOrigin(Coord& xyz) { xyz &= ~(DIM - 1); }
727 
728  template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
729  static inline void doVisit(NodeT&, VisitorOp&);
730 
731  template<typename NodeT, typename OtherNodeT, typename VisitorOp,
732  typename ChildAllIterT, typename OtherChildAllIterT>
733  static inline void doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp&);
734 
735  template<typename NodeT, typename VisitorOp,
736  typename ChildAllIterT, typename OtherChildAllIterT>
737  static inline void doVisit2(NodeT& self, OtherChildAllIterT&, VisitorOp&, bool otherIsLHS);
738 
739  /// Bitmask representing the values AND state of voxels
741  /// Global grid index coordinates (x,y,z) of the local origin of this node
742  Coord mOrigin;
743 #if OPENVDB_ABI_VERSION_NUMBER >= 9
744  /// Transient data (not serialized)
745  Index32 mTransientData = 0;
746 #endif
747 
748 private:
749  /// @brief During topology-only construction, access is needed
750  /// to protected/private members of other template instances.
751  template<typename, Index> friend class LeafNode;
752 
753  friend struct ValueIter<MaskOnIter, LeafNode, bool>;
754  friend struct ValueIter<MaskOffIter, LeafNode, bool>;
755  friend struct ValueIter<MaskDenseIter, LeafNode, bool>;
756  friend struct ValueIter<MaskOnIter, const LeafNode, bool>;
757  friend struct ValueIter<MaskOffIter, const LeafNode, bool>;
758  friend struct ValueIter<MaskDenseIter, const LeafNode, bool>;
759 
760  //@{
761  /// Allow iterators to call mask accessor methods (see below).
762  /// @todo Make mask accessors public?
766  //@}
767 
768  template<typename, Index> friend class LeafBuffer;
769 
770 }; // class LeafNode<ValueMask>
771 
772 
773 ////////////////////////////////////////
774 
775 
776 template<Index Log2Dim>
777 inline
779  : mOrigin(0, 0, 0)
780 {
781 }
782 
783 template<Index Log2Dim>
784 inline
785 LeafNode<ValueMask, Log2Dim>::LeafNode(const Coord& xyz, bool value, bool active)
786  : mBuffer(value || active)
787  , mOrigin(xyz & (~(DIM - 1)))
788 {
789 }
790 
791 
792 template<Index Log2Dim>
793 inline
794 LeafNode<ValueMask, Log2Dim>::LeafNode(PartialCreate, const Coord& xyz, bool value, bool active)
795  : mBuffer(value || active)
796  , mOrigin(xyz & (~(DIM - 1)))
797 {
798 }
799 
800 
801 template<Index Log2Dim>
802 inline
804  : mBuffer(other.mBuffer)
805  , mOrigin(other.mOrigin)
807  , mTransientData(other.mTransientData)
808 #endif
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())
821  , mTransientData(other.mTransientData)
822 #endif
823 {
824 }
825 
826 
827 template<Index Log2Dim>
828 template<typename ValueT>
829 inline
831  bool, TopologyCopy)
832  : mBuffer(other.valueMask())// value = active state
833  , mOrigin(other.origin())
835  , mTransientData(other.mTransientData)
836 #endif
837 {
838 }
839 
840 
841 template<Index Log2Dim>
842 template<typename ValueT>
843 inline
845  : mBuffer(other.valueMask())// value = active state
846  , mOrigin(other.origin())
848  , mTransientData(other.mTransientData)
849 #endif
850 {
851 }
852 
853 
854 template<Index Log2Dim>
855 template<typename ValueT>
856 inline
858  bool offValue, bool onValue, TopologyCopy)
859  : mBuffer(other.valueMask())
860  , mOrigin(other.origin())
862  , mTransientData(other.mTransientData)
863 #endif
864 {
865  if (offValue==true) {
866  if (onValue==false) {
867  mBuffer.mData.toggle();
868  } else {
869  mBuffer.mData.setOn();
870  }
871  }
872 }
873 
874 
875 template<Index Log2Dim>
876 inline
878 {
879 }
880 
881 
882 ////////////////////////////////////////
883 
884 
885 template<Index Log2Dim>
886 inline Index64
888 {
889  // Use sizeof(*this) to capture alignment-related padding
890  return sizeof(*this);
891 }
892 
893 
894 template<Index Log2Dim>
895 inline void
896 LeafNode<ValueMask, Log2Dim>::evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels) const
897 {
898  CoordBBox this_bbox = this->getNodeBoundingBox();
899  if (bbox.isInside(this_bbox)) return;//this LeafNode is already enclosed in the bbox
900  if (ValueOnCIter iter = this->cbeginValueOn()) {//any active values?
901  if (visitVoxels) {//use voxel granularity?
902  this_bbox.reset();
903  for(; iter; ++iter) this_bbox.expand(this->offsetToLocalCoord(iter.pos()));
904  this_bbox.translate(this->origin());
905  }
906  bbox.expand(this_bbox);
907  }
908 }
909 
910 
911 template<Index Log2Dim>
912 template<typename OtherType, Index OtherLog2Dim>
913 inline bool
915 {
916  assert(other);
917  return (Log2Dim == OtherLog2Dim && mBuffer.mData == other->getValueMask());
918 }
919 
920 
921 template<Index Log2Dim>
922 inline std::string
924 {
925  std::ostringstream ostr;
926  ostr << "LeafNode @" << mOrigin << ": ";
927  for (Index32 n = 0; n < SIZE; ++n) ostr << (mBuffer.mData.isOn(n) ? '#' : '.');
928  return ostr.str();
929 }
930 
931 
932 ////////////////////////////////////////
933 
934 
935 template<Index Log2Dim>
936 inline Index
938 {
939  assert ((xyz[0] & (DIM-1u)) < DIM && (xyz[1] & (DIM-1u)) < DIM && (xyz[2] & (DIM-1u)) < DIM);
940  return ((xyz[0] & (DIM-1u)) << 2*Log2Dim)
941  + ((xyz[1] & (DIM-1u)) << Log2Dim)
942  + (xyz[2] & (DIM-1u));
943 }
944 
945 
946 template<Index Log2Dim>
947 inline Coord
949 {
950  assert(n < (1 << 3*Log2Dim));
951  Coord xyz;
952  xyz.setX(n >> 2*Log2Dim);
953  n &= ((1 << 2*Log2Dim) - 1);
954  xyz.setY(n >> Log2Dim);
955  xyz.setZ(n & ((1 << Log2Dim) - 1));
956  return xyz;
957 }
958 
959 
960 template<Index Log2Dim>
961 inline Coord
963 {
964  return (this->offsetToLocalCoord(n) + this->origin());
965 }
966 
967 
968 ////////////////////////////////////////
969 
970 
971 template<Index Log2Dim>
972 inline void
973 LeafNode<ValueMask, Log2Dim>::readTopology(std::istream& is, bool /*fromHalf*/)
974 {
975  mBuffer.mData.load(is);
976 }
977 
978 
979 template<Index Log2Dim>
980 inline void
981 LeafNode<ValueMask, Log2Dim>::writeTopology(std::ostream& os, bool /*toHalf*/) const
982 {
983  mBuffer.mData.save(os);
984 }
985 
986 
987 template<Index Log2Dim>
988 inline void
989 LeafNode<ValueMask, Log2Dim>::readBuffers(std::istream& is, const CoordBBox& clipBBox, bool fromHalf)
990 {
991  // Boolean LeafNodes don't currently implement lazy loading.
992  // Instead, load the full buffer, then clip it.
993 
994  this->readBuffers(is, fromHalf);
995 
996  // Get this tree's background value.
997  bool background = false;
998  if (const void* bgPtr = io::getGridBackgroundValuePtr(is)) {
999  background = *static_cast<const bool*>(bgPtr);
1000  }
1001  this->clip(clipBBox, background);
1002 }
1003 
1004 
1005 template<Index Log2Dim>
1006 inline void
1007 LeafNode<ValueMask, Log2Dim>::readBuffers(std::istream& is, bool /*fromHalf*/)
1008 {
1009  // Read in the value mask = buffer.
1010  mBuffer.mData.load(is);
1011  // Read in the origin.
1012  is.read(reinterpret_cast<char*>(&mOrigin), sizeof(Coord::ValueType) * 3);
1013 }
1014 
1015 
1016 template<Index Log2Dim>
1017 inline void
1018 LeafNode<ValueMask, Log2Dim>::writeBuffers(std::ostream& os, bool /*toHalf*/) const
1019 {
1020  // Write out the value mask = buffer.
1021  mBuffer.mData.save(os);
1022  // Write out the origin.
1023  os.write(reinterpret_cast<const char*>(&mOrigin), sizeof(Coord::ValueType) * 3);
1024 }
1025 
1026 
1027 ////////////////////////////////////////
1028 
1029 
1030 template<Index Log2Dim>
1031 inline bool
1033 {
1034  return mOrigin == other.mOrigin && mBuffer == other.mBuffer;
1035 }
1036 
1037 
1038 template<Index Log2Dim>
1039 inline bool
1041 {
1042  return !(this->operator==(other));
1043 }
1044 
1045 
1046 ////////////////////////////////////////
1047 
1048 
1049 template<Index Log2Dim>
1050 inline bool
1051 LeafNode<ValueMask, Log2Dim>::isConstant(bool& constValue, bool& state, bool) const
1052 {
1053  if (!mBuffer.mData.isConstant(state)) return false;
1054 
1055  constValue = state;
1056  return true;
1057 }
1058 
1059 
1060 ////////////////////////////////////////
1061 
1062 template<Index Log2Dim>
1063 inline bool
1065 {
1066  const Index countTrue = mBuffer.mData.countOn();
1067  return countTrue > (NUM_VALUES >> 1);
1068 }
1069 
1070 template<Index Log2Dim>
1071 inline Index
1073 {
1074  const Index countTrueOn = mBuffer.mData.countOn();
1075  state = true;//since value and state are the same for this specialization of the leaf node
1076  return countTrueOn;
1077 }
1078 
1079 template<Index Log2Dim>
1080 inline Index
1082 {
1083  const Index countFalseOff = mBuffer.mData.countOff();
1084  state = false;//since value and state are the same for this specialization of the leaf node
1085  return countFalseOff;
1086 }
1087 
1088 
1089 ////////////////////////////////////////
1090 
1091 
1092 template<Index Log2Dim>
1093 inline void
1094 LeafNode<ValueMask, Log2Dim>::addTile(Index /*level*/, const Coord& xyz, bool val, bool active)
1095 {
1096  this->addTile(this->coordToOffset(xyz), val, active);
1097 }
1098 
1099 template<Index Log2Dim>
1100 inline void
1102 {
1103  assert(offset < SIZE);
1104  this->setValueOnly(offset, val);
1105  this->setActiveState(offset, active);
1106 }
1107 
1108 template<Index Log2Dim>
1109 template<typename AccessorT>
1110 inline void
1112  bool val, bool active, AccessorT&)
1113 {
1114  this->addTile(level, xyz, val, active);
1115 }
1116 
1117 
1118 ////////////////////////////////////////
1119 
1120 
1121 template<Index Log2Dim>
1122 inline const bool&
1124 {
1125  // This *CANNOT* use operator ? because Visual C++
1126  if (mBuffer.mData.isOn(this->coordToOffset(xyz))) return Buffer::sOn; else return Buffer::sOff;
1127 }
1128 
1129 
1130 template<Index Log2Dim>
1131 inline const bool&
1133 {
1134  assert(offset < SIZE);
1135  // This *CANNOT* use operator ? for Windows
1136  if (mBuffer.mData.isOn(offset)) return Buffer::sOn; else return Buffer::sOff;
1137 }
1138 
1139 
1140 template<Index Log2Dim>
1141 inline bool
1142 LeafNode<ValueMask, Log2Dim>::probeValue(const Coord& xyz, bool& val) const
1143 {
1144  const Index offset = this->coordToOffset(xyz);
1145  val = mBuffer.mData.isOn(offset);
1146  return val;
1147 }
1148 
1149 
1150 template<Index Log2Dim>
1151 inline void
1153 {
1154  this->setValueOn(this->coordToOffset(xyz), val);
1155 }
1156 
1157 
1158 template<Index Log2Dim>
1159 inline void
1161 {
1162  assert(offset < SIZE);
1163  mBuffer.mData.set(offset, val);
1164 }
1165 
1166 
1167 template<Index Log2Dim>
1168 inline void
1170 {
1171  this->setValueOnly(this->coordToOffset(xyz), val);
1172 }
1173 
1174 
1175 template<Index Log2Dim>
1176 inline void
1178 {
1179  mBuffer.mData.set(this->coordToOffset(xyz), on);
1180 }
1181 
1182 
1183 template<Index Log2Dim>
1184 inline void
1186 {
1187  this->setValueOff(this->coordToOffset(xyz), val);
1188 }
1189 
1190 
1191 template<Index Log2Dim>
1192 inline void
1194 {
1195  assert(offset < SIZE);
1196  mBuffer.mData.set(offset, val);
1197 }
1198 
1199 
1200 template<Index Log2Dim>
1201 template<typename ModifyOp>
1202 inline void
1204 {
1205  bool val = mBuffer.mData.isOn(offset);
1206  op(val);
1207  mBuffer.mData.set(offset, val);
1208 }
1209 
1210 
1211 template<Index Log2Dim>
1212 template<typename ModifyOp>
1213 inline void
1214 LeafNode<ValueMask, Log2Dim>::modifyValue(const Coord& xyz, const ModifyOp& op)
1215 {
1216  this->modifyValue(this->coordToOffset(xyz), op);
1217 }
1218 
1219 
1220 template<Index Log2Dim>
1221 template<typename ModifyOp>
1222 inline void
1223 LeafNode<ValueMask, Log2Dim>::modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
1224 {
1225  const Index offset = this->coordToOffset(xyz);
1226  bool val = mBuffer.mData.isOn(offset), state = val;
1227  op(val, state);
1228  mBuffer.mData.set(offset, val);
1229 }
1230 
1231 
1232 ////////////////////////////////////////
1233 
1234 
1235 template<Index Log2Dim>
1236 template<MergePolicy Policy>
1237 inline void
1238 LeafNode<ValueMask, Log2Dim>::merge(const LeafNode& other, bool /*bg*/, bool /*otherBG*/)
1239 {
1241  if (Policy == MERGE_NODES) return;
1242  mBuffer.mData |= other.mBuffer.mData;
1244 }
1245 
1246 template<Index Log2Dim>
1247 template<MergePolicy Policy>
1248 inline void
1250 {
1252  if (Policy != MERGE_ACTIVE_STATES_AND_NODES) return;
1253  if (tileValue) mBuffer.mData.setOn();
1255 }
1256 
1257 
1258 ////////////////////////////////////////
1259 
1260 
1261 template<Index Log2Dim>
1262 template<typename OtherType>
1263 inline void
1265 {
1266  mBuffer.mData |= other.valueMask();
1267 }
1268 
1269 
1270 template<Index Log2Dim>
1271 template<typename OtherType>
1272 inline void
1274  const bool&)
1275 {
1276  mBuffer.mData &= other.valueMask();
1277 }
1278 
1279 
1280 template<Index Log2Dim>
1281 template<typename OtherType>
1282 inline void
1284  const bool&)
1285 {
1286  mBuffer.mData &= !other.valueMask();
1287 }
1288 
1289 
1290 ////////////////////////////////////////
1291 
1292 
1293 template<Index Log2Dim>
1294 inline void
1295 LeafNode<ValueMask, Log2Dim>::clip(const CoordBBox& clipBBox, bool background)
1296 {
1297  CoordBBox nodeBBox = this->getNodeBoundingBox();
1298  if (!clipBBox.hasOverlap(nodeBBox)) {
1299  // This node lies completely outside the clipping region. Fill it with background tiles.
1300  this->fill(nodeBBox, background, /*active=*/false);
1301  } else if (clipBBox.isInside(nodeBBox)) {
1302  // This node lies completely inside the clipping region. Leave it intact.
1303  return;
1304  }
1305 
1306  // This node isn't completely contained inside the clipping region.
1307  // Set any voxels that lie outside the region to the background value.
1308 
1309  // Construct a boolean mask that is on inside the clipping region and off outside it.
1311  nodeBBox.intersect(clipBBox);
1312  Coord xyz;
1313  int &x = xyz.x(), &y = xyz.y(), &z = xyz.z();
1314  for (x = nodeBBox.min().x(); x <= nodeBBox.max().x(); ++x) {
1315  for (y = nodeBBox.min().y(); y <= nodeBBox.max().y(); ++y) {
1316  for (z = nodeBBox.min().z(); z <= nodeBBox.max().z(); ++z) {
1317  mask.setOn(static_cast<Index32>(this->coordToOffset(xyz)));
1318  }
1319  }
1320  }
1321 
1322  // Set voxels that lie in the inactive region of the mask (i.e., outside
1323  // the clipping region) to the background value.
1324  for (MaskOffIter maskIter = mask.beginOff(); maskIter; ++maskIter) {
1325  this->setValueOff(maskIter.pos(), background);
1326  }
1327 }
1328 
1329 
1330 ////////////////////////////////////////
1331 
1332 
1333 template<Index Log2Dim>
1334 inline void
1335 LeafNode<ValueMask, Log2Dim>::fill(const CoordBBox& bbox, bool value, bool)
1336 {
1337  auto clippedBBox = this->getNodeBoundingBox();
1338  clippedBBox.intersect(bbox);
1339  if (!clippedBBox) return;
1340 
1341  for (Int32 x = clippedBBox.min().x(); x <= clippedBBox.max().x(); ++x) {
1342  const Index offsetX = (x & (DIM-1u))<<2*Log2Dim;
1343  for (Int32 y = clippedBBox.min().y(); y <= clippedBBox.max().y(); ++y) {
1344  const Index offsetXY = offsetX + ((y & (DIM-1u))<< Log2Dim);
1345  for (Int32 z = clippedBBox.min().z(); z <= clippedBBox.max().z(); ++z) {
1346  const Index offset = offsetXY + (z & (DIM-1u));
1347  mBuffer.mData.set(offset, value);
1348  }
1349  }
1350  }
1351 }
1352 
1353 template<Index Log2Dim>
1354 inline void
1356 {
1357  mBuffer.fill(value);
1358 }
1359 
1360 
1361 ////////////////////////////////////////
1362 
1363 
1364 template<Index Log2Dim>
1365 template<typename DenseT>
1366 inline void
1367 LeafNode<ValueMask, Log2Dim>::copyToDense(const CoordBBox& bbox, DenseT& dense) const
1368 {
1369  using DenseValueType = typename DenseT::ValueType;
1370 
1371  const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride();
1372  const Coord& min = dense.bbox().min();
1373  DenseValueType* t0 = dense.data() + zStride * (bbox.min()[2] - min[2]); // target array
1374  const Int32 n0 = bbox.min()[2] & (DIM-1u);
1375  for (Int32 x = bbox.min()[0], ex = bbox.max()[0] + 1; x < ex; ++x) {
1376  DenseValueType* t1 = t0 + xStride * (x - min[0]);
1377  const Int32 n1 = n0 + ((x & (DIM-1u)) << 2*LOG2DIM);
1378  for (Int32 y = bbox.min()[1], ey = bbox.max()[1] + 1; y < ey; ++y) {
1379  DenseValueType* t2 = t1 + yStride * (y - min[1]);
1380  Int32 n2 = n1 + ((y & (DIM-1u)) << LOG2DIM);
1381  for (Int32 z = bbox.min()[2], ez = bbox.max()[2] + 1; z < ez; ++z, t2 += zStride) {
1382  *t2 = DenseValueType(mBuffer.mData.isOn(n2++));
1383  }
1384  }
1385  }
1386 }
1387 
1388 
1389 template<Index Log2Dim>
1390 template<typename DenseT>
1391 inline void
1392 LeafNode<ValueMask, Log2Dim>::copyFromDense(const CoordBBox& bbox, const DenseT& dense,
1393  bool background, bool tolerance)
1394 {
1395  using DenseValueType = typename DenseT::ValueType;
1396  struct Local {
1397  inline static bool toBool(const DenseValueType& v) { return !math::isZero(v); }
1398  };
1399 
1400  const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride();
1401  const Coord& min = dense.bbox().min();
1402  const DenseValueType* s0 = dense.data() + zStride * (bbox.min()[2] - min[2]); // source
1403  const Int32 n0 = bbox.min()[2] & (DIM-1u);
1404  for (Int32 x = bbox.min()[0], ex = bbox.max()[0] + 1; x < ex; ++x) {
1405  const DenseValueType* s1 = s0 + xStride * (x - min[0]);
1406  const Int32 n1 = n0 + ((x & (DIM-1u)) << 2*LOG2DIM);
1407  for (Int32 y = bbox.min()[1], ey = bbox.max()[1] + 1; y < ey; ++y) {
1408  const DenseValueType* s2 = s1 + yStride * (y - min[1]);
1409  Int32 n2 = n1 + ((y & (DIM-1u)) << LOG2DIM);
1410  for (Int32 z = bbox.min()[2], ez = bbox.max()[2]+1; z < ez; ++z, ++n2, s2 += zStride) {
1411  // Note: if tolerance is true (i.e., 1), then all boolean values compare equal.
1412  if (tolerance || (background == Local::toBool(*s2))) {
1413  mBuffer.mData.set(n2, background);
1414  } else {
1415  mBuffer.mData.set(n2, Local::toBool(*s2));
1416  }
1417  }
1418  }
1419  }
1420 }
1421 
1422 
1423 ////////////////////////////////////////
1424 
1425 
1426 template<Index Log2Dim>
1427 template<typename CombineOp>
1428 inline void
1430 {
1432  for (Index i = 0; i < SIZE; ++i) {
1433  bool result = false, aVal = mBuffer.mData.isOn(i), bVal = other.mBuffer.mData.isOn(i);
1434  op(args.setARef(aVal)
1435  .setAIsActive(aVal)
1436  .setBRef(bVal)
1437  .setBIsActive(bVal)
1438  .setResultRef(result));
1439  mBuffer.mData.set(i, result);
1440  }
1441 }
1442 
1443 
1444 template<Index Log2Dim>
1445 template<typename CombineOp>
1446 inline void
1447 LeafNode<ValueMask, Log2Dim>::combine(bool value, bool valueIsActive, CombineOp& op)
1448 {
1450  args.setBRef(value).setBIsActive(valueIsActive);
1451  for (Index i = 0; i < SIZE; ++i) {
1452  bool result = false, aVal = mBuffer.mData.isOn(i);
1453  op(args.setARef(aVal)
1454  .setAIsActive(aVal)
1455  .setResultRef(result));
1456  mBuffer.mData.set(i, result);
1457  }
1458 }
1459 
1460 
1461 ////////////////////////////////////////
1462 
1463 
1464 template<Index Log2Dim>
1465 template<typename CombineOp, typename OtherType>
1466 inline void
1468  bool valueIsActive, CombineOp& op)
1469 {
1471  args.setBRef(value).setBIsActive(valueIsActive);
1472  for (Index i = 0; i < SIZE; ++i) {
1473  bool result = false, aVal = other.mBuffer.mData.isOn(i);
1474  op(args.setARef(aVal)
1475  .setAIsActive(aVal)
1476  .setResultRef(result));
1477  mBuffer.mData.set(i, result);
1478  }
1479 }
1480 
1481 
1482 template<Index Log2Dim>
1483 template<typename CombineOp, typename OtherNodeT>
1484 inline void
1485 LeafNode<ValueMask, Log2Dim>::combine2(bool value, const OtherNodeT& other,
1486  bool valueIsActive, CombineOp& op)
1487 {
1489  args.setARef(value).setAIsActive(valueIsActive);
1490  for (Index i = 0; i < SIZE; ++i) {
1491  bool result = false, bVal = other.mBuffer.mData.isOn(i);
1492  op(args.setBRef(bVal)
1493  .setBIsActive(bVal)
1494  .setResultRef(result));
1495  mBuffer.mData.set(i, result);
1496  }
1497 }
1498 
1499 
1500 template<Index Log2Dim>
1501 template<typename CombineOp, typename OtherNodeT>
1502 inline void
1503 LeafNode<ValueMask, Log2Dim>::combine2(const LeafNode& b0, const OtherNodeT& b1, CombineOp& op)
1504 {
1506  for (Index i = 0; i < SIZE; ++i) {
1507  bool result = false, b0Val = b0.mBuffer.mData.isOn(i), b1Val = b1.mBuffer.mData.isOn(i);
1508  op(args.setARef(b0Val)
1509  .setAIsActive(b0Val)
1510  .setBRef(b1Val)
1511  .setBIsActive(b1Val)
1512  .setResultRef(result));
1513  mBuffer.mData.set(i, result);
1514  }
1515 }
1516 
1517 
1518 ////////////////////////////////////////
1519 
1520 template<Index Log2Dim>
1521 template<typename BBoxOp>
1522 inline void
1524 {
1525  if (op.template descent<LEVEL>()) {
1526  for (ValueOnCIter i=this->cbeginValueOn(); i; ++i) {
1527  op.template operator()<LEVEL>(CoordBBox::createCube(i.getCoord(), 1));
1528  }
1529  } else {
1530  op.template operator()<LEVEL>(this->getNodeBoundingBox());
1531  }
1532 }
1533 
1534 
1535 template<Index Log2Dim>
1536 template<typename VisitorOp>
1537 inline void
1539 {
1540  doVisit<LeafNode, VisitorOp, ChildAllIter>(*this, op);
1541 }
1542 
1543 
1544 template<Index Log2Dim>
1545 template<typename VisitorOp>
1546 inline void
1548 {
1549  doVisit<const LeafNode, VisitorOp, ChildAllCIter>(*this, op);
1550 }
1551 
1552 
1553 template<Index Log2Dim>
1554 template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
1555 inline void
1556 LeafNode<ValueMask, Log2Dim>::doVisit(NodeT& self, VisitorOp& op)
1557 {
1558  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1559  op(iter);
1560  }
1561 }
1562 
1563 
1564 ////////////////////////////////////////
1565 
1566 
1567 template<Index Log2Dim>
1568 template<typename OtherLeafNodeType, typename VisitorOp>
1569 inline void
1570 LeafNode<ValueMask, Log2Dim>::visit2Node(OtherLeafNodeType& other, VisitorOp& op)
1571 {
1572  doVisit2Node<LeafNode, OtherLeafNodeType, VisitorOp, ChildAllIter,
1573  typename OtherLeafNodeType::ChildAllIter>(*this, other, op);
1574 }
1575 
1576 
1577 template<Index Log2Dim>
1578 template<typename OtherLeafNodeType, typename VisitorOp>
1579 inline void
1580 LeafNode<ValueMask, Log2Dim>::visit2Node(OtherLeafNodeType& other, VisitorOp& op) const
1581 {
1582  doVisit2Node<const LeafNode, OtherLeafNodeType, VisitorOp, ChildAllCIter,
1583  typename OtherLeafNodeType::ChildAllCIter>(*this, other, op);
1584 }
1585 
1586 
1587 template<Index Log2Dim>
1588 template<
1589  typename NodeT,
1590  typename OtherNodeT,
1591  typename VisitorOp,
1592  typename ChildAllIterT,
1593  typename OtherChildAllIterT>
1594 inline void
1595 LeafNode<ValueMask, Log2Dim>::doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp& op)
1596 {
1597  // Allow the two nodes to have different ValueTypes, but not different dimensions.
1598  static_assert(OtherNodeT::SIZE == NodeT::SIZE,
1599  "can't visit nodes of different sizes simultaneously");
1600  static_assert(OtherNodeT::LEVEL == NodeT::LEVEL,
1601  "can't visit nodes at different tree levels simultaneously");
1602 
1603  ChildAllIterT iter = self.beginChildAll();
1604  OtherChildAllIterT otherIter = other.beginChildAll();
1605 
1606  for ( ; iter && otherIter; ++iter, ++otherIter) {
1607  op(iter, otherIter);
1608  }
1609 }
1610 
1611 
1612 ////////////////////////////////////////
1613 
1614 
1615 template<Index Log2Dim>
1616 template<typename IterT, typename VisitorOp>
1617 inline void
1618 LeafNode<ValueMask, Log2Dim>::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS)
1619 {
1620  doVisit2<LeafNode, VisitorOp, ChildAllIter, IterT>(*this, otherIter, op, otherIsLHS);
1621 }
1622 
1623 
1624 template<Index Log2Dim>
1625 template<typename IterT, typename VisitorOp>
1626 inline void
1627 LeafNode<ValueMask, Log2Dim>::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS) const
1628 {
1629  doVisit2<const LeafNode, VisitorOp, ChildAllCIter, IterT>(*this, otherIter, op, otherIsLHS);
1630 }
1631 
1632 
1633 template<Index Log2Dim>
1634 template<
1635  typename NodeT,
1636  typename VisitorOp,
1637  typename ChildAllIterT,
1638  typename OtherChildAllIterT>
1639 inline void
1640 LeafNode<ValueMask, Log2Dim>::doVisit2(NodeT& self, OtherChildAllIterT& otherIter,
1641  VisitorOp& op, bool otherIsLHS)
1642 {
1643  if (!otherIter) return;
1644 
1645  if (otherIsLHS) {
1646  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1647  op(otherIter, iter);
1648  }
1649  } else {
1650  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1651  op(iter, otherIter);
1652  }
1653  }
1654 }
1655 
1656 } // namespace tree
1657 } // namespace OPENVDB_VERSION_NAME
1658 } // namespace openvdb
1659 
1660 #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:651
bool isValueOnAndCache(const Coord &xyz, AccessorT &) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNodeMask.h:339
void stealNodes(ArrayT &, const ValueType &, bool)
This function exists only to enable template instantiation.
Definition: LeafNodeMask.h:538
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:1704
ValueIter< MaskOffIter, LeafNode, const bool > ValueOffIter
Definition: LeafNodeMask.h:653
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:446
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:876
bool getItem(Index pos, void *&child, NonConstValueT &value) const
Definition: LeafNodeMask.h:636
void readBuffers(std::istream &is, bool fromHalf=false)
Read buffers from a stream.
Definition: LeafNode.h:1345
const bool & getLastValue() const
Return a const reference to the last entry in the buffer.
Definition: LeafNodeMask.h:407
ValueIter< MaskDenseIter, const LeafNode, const bool > ValueAllCIter
Definition: LeafNodeMask.h:656
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:344
ChildIter< MaskOffIterator, LeafNode, ChildOff > ChildOffIter
Definition: LeafNode.h:293
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:1144
void readTopology(std::istream &is, bool fromHalf=false)
Read in just the topology.
Definition: LeafNode.h:1309
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:232
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: LeafNode.h:1086
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don't change its value.
Definition: LeafNode.h:418
const NodeT * probeConstNode(const Coord &) const
This function exists only to enable template instantiation.
Definition: LeafNodeMask.h:536
void getNodes(ArrayT &) const
This function exists only to enable template instantiation.
Definition: LeafNodeMask.h:537
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:568
Buffer mBuffer
Bitmask representing the values AND state of voxels.
Definition: LeafNodeMask.h:740
bool isConstant(ValueType &firstValue, bool &state, const ValueType &tolerance=zeroVal< ValueType >()) const
Definition: LeafNode.h:1500
const LeafNode * probeConstLeafAndCache(const Coord &, AccessorT &) const
Return a pointer to this node.
Definition: LeafNodeMask.h:570
static void doVisit(NodeT &, VisitorOp &)
Definition: LeafNode.h:1879
Index pos() const
Identical to offset.
Definition: Iterator.h:60
LeafNode * touchLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: LeafNodeMask.h:550
bool isAllocated() const
Return true if memory for this node's buffer has been allocated.
Definition: LeafNodeMask.h:136
GLint level
Definition: glcorearb.h:107
Coord mOrigin
Global grid index coordinates (x,y,z) of the local origin of this node.
Definition: LeafNodeMask.h:742
Index64 memUsage() const
Return the memory in bytes occupied by this node.
Definition: LeafNode.h:1464
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:178
Base class for iterators over internal and leaf nodes.
Definition: Iterator.h:29
ChildIter< MaskOnIterator, const LeafNode, ChildOn > ChildOnCIter
Definition: LeafNode.h:292
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
Definition: glew.h:12900
**But if you need a or simply need to know when the task has note that the like this
Definition: thread.h:623
ChildIter< MaskOnIterator, LeafNode, ChildOn > ChildOnIter
Definition: LeafNode.h:291
ValueIter< MaskDenseIter, LeafNode, const bool > ValueAllIter
Definition: LeafNodeMask.h:655
void clip(const CoordBBox &, const ValueType &background)
Set all voxels that lie outside the given axis-aligned box to the background.
Definition: LeafNode.h:1162
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:1712
void setValuesOn()
Mark all voxels as active but don't change their values.
Definition: LeafNodeMask.h:275
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:566
#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:240
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
Definition: glew.h:12900
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:1136
ValueIter< MaskOffIterator, const LeafNode, const ValueType, ValueOff > ValueOffCIter
Definition: LeafNode.h:288
const NodeT * probeConstNodeAndCache(const Coord &, AccessorT &) const
Return a pointer to this node.
Definition: LeafNodeMask.h:572
static Coord offsetToLocalCoord(Index n)
Return the local coordinates for a linear table offset, where offset 0 has coordinates (0...
Definition: LeafNode.h:1061
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:1437
ValueIter< MaskDenseIterator, LeafNode, const ValueType, ValueAll > ValueAllIter
Definition: LeafNode.h:289
GLint GLenum GLint x
Definition: glcorearb.h:408
void prune(const ValueType &=zeroVal< ValueType >())
This function exists only to enable template instantiation.
Definition: LeafNodeMask.h:527
static bool hasActiveTiles()
Return false since leaf nodes never contain tiles.
Definition: LeafNodeMask.h:285
bool isValueOn(Index offset) const
Return true if the voxel at the given offset is active.
Definition: LeafNodeMask.h:282
CoordBBox getNodeBoundingBox() const
Return the bounding box of this node, i.e., the full index space spanned by this leaf node...
Definition: LeafNodeMask.h:152
std::shared_ptr< T > SharedPtr
Definition: Types.h:110
LeafNode * touchLeaf(const Coord &)
Return a pointer to this node.
Definition: LeafNodeMask.h:548
bool isValueOn(const Coord &xyz) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNode.h:476
const Coord & origin() const
Return the grid index coordinates of this node's local origin.
Definition: LeafNodeMask.h:158
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:436
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s0
Definition: glew.h:12900
bool isDense() const
Return true if this node only contains active voxels.
Definition: LeafNodeMask.h:132
OffMaskIterator< NodeMask > OffIterator
Definition: NodeMasks.h:349
GLuint64EXT * result
Definition: glew.h:14311
Index64 onVoxelCount() const
Return the number of active voxels.
Definition: LeafNodeMask.h:121
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
void setOrigin(const Coord &origin)
Set the grid index coordinates of this node's local origin.
Definition: LeafNodeMask.h:155
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:253
void addTile(Index level, const Coord &, const ValueType &, bool)
Definition: LeafNode.h:1605
Index64 onVoxelCount() const
Return the number of voxels marked On.
Definition: LeafNode.h:140
GLint GLuint mask
Definition: glcorearb.h:123
const bool & getFirstValue() const
Return a const reference to the first entry in the buffer.
Definition: LeafNodeMask.h:403
NodeT * probeNodeAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: LeafNodeMask.h:555
ValueIter< MaskOnIter, const LeafNode, const bool > ValueOnCIter
Definition: LeafNodeMask.h:652
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:1721
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
const GLdouble * v
Definition: glcorearb.h:836
const LeafNode * probeLeaf(const Coord &) const
Return a pointer to this node.
Definition: LeafNodeMask.h:565
ValueIter< MaskOnIterator, LeafNode, const ValueType, ValueOn > ValueOnIter
Definition: LeafNode.h:285
GLsizei const GLchar *const * string
Definition: glcorearb.h:813
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:1245
void modifyItem(Index n, const ModifyOp &op) const
Definition: LeafNode.h:241
const bool & getValueAndCache(const Coord &xyz, AccessorT &) const
Return the value of the voxel at the given coordinates.
Definition: LeafNodeMask.h:334
static Index getValueLevel(const Coord &)
Return the level (0) at which leaf node values reside.
Definition: LeafNodeMask.h:227
const NodeMaskType & getValueMask() const
Definition: LeafNode.h:874
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:202
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:847
void getOrigin(Int32 &x, Int32 &y, Int32 &z) const
Return the grid index coordinates of this node's local origin.
Definition: LeafNodeMask.h:160
std::string str() const
Return a string representation of this node.
Definition: LeafNode.h:1038
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:1536
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:408
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:195
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:355
const Coord & origin() const
Return the grid index coordinates of this node's local origin.
Definition: LeafNode.h:172
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
Definition: LeafNode.h:457
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:293
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
SIMD Intrinsic Headers.
Definition: Platform.h:115
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:237
Coord offsetToGlobalCoord(Index n) const
Return the global coordinates for a linear table offset.
Definition: LeafNode.h:1075
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:1785
GLdouble n
Definition: glcorearb.h:2007
Index medianOn(ValueType &value, ValueType *tmp=nullptr) const
Computes the median value of all the active voxels in this node.
Definition: LeafNode.h:1554
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:364
CoordBBox getNodeBoundingBox() const
Return the bounding box of this node, i.e., the full index space spanned by this leaf node...
Definition: LeafNode.h:166
const LeafNode * probeLeafAndCache(const Coord &, AccessorT &) const
Return a pointer to this node.
Definition: LeafNodeMask.h:567
void visit2Node(OtherLeafNodeType &other, VisitorOp &)
Definition: LeafNode.h:1893
GLuint GLfloat * val
Definition: glcorearb.h:1607
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:225
bool isInactive() const
Return true if all of this node's values are inactive.
Definition: LeafNodeMask.h:441
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:448
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:390
LeafNode * probeLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: LeafNodeMask.h:553
ValueIter< MaskOnIterator, const LeafNode, const ValueType, ValueOn > ValueOnCIter
Definition: LeafNode.h:286
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don't change its value.
Definition: LeafNodeMask.h:250
void setItem(Index pos, const ValueT &value) const
Definition: LeafNode.h:229
NodeT * stealNode(const Coord &, const ValueType &, bool)
This function exists only to enable template instantiation.
Definition: LeafNodeMask.h:532
bool probeValue(const Coord &xyz, ValueType &val) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNode.h:1102
CombineArgs & setBRef(const BValueType &b)
Redirect the B value to a new external source.
Definition: Types.h:501
void combine(const LeafNode &other, CombineOp &op)
Definition: LeafNode.h:1745
void modifyValueAndActiveStateAndCache(const Coord &xyz, const ModifyOp &op, AccessorT &)
Definition: LeafNodeMask.h:372
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:1578
void addTileAndCache(Index, const Coord &, const ValueType &, bool, AccessorT &)
Definition: LeafNode.h:1622
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t0
Definition: glew.h:12900
ValueIter< MaskDenseIterator, const LeafNode, const ValueType, ValueAll > ValueAllCIter
Definition: LeafNode.h:290
OnMaskIterator< NodeMask > OnIterator
Definition: NodeMasks.h:348
GLsizei const GLfloat * value
Definition: glcorearb.h:823
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:350
**If you just want to fire and args
Definition: thread.h:615
CombineArgs & setARef(const AValueType &a)
Redirect the A value to a new external source.
Definition: Types.h:499
ValueIter< MaskOffIter, const LeafNode, const bool > ValueOffCIter
Definition: LeafNodeMask.h:654
void addLeafAndCache(LeafNode *, AccessorT &)
This function exists only to enable template instantiation.
Definition: LeafNodeMask.h:530
NodeT * probeNode(const Coord &)
This function exists only to enable template instantiation.
Definition: LeafNodeMask.h:534
#define SIZE
Definition: simple.C:40
void setValueOn(Index offset)
Mark the voxel at the given offset as active but don't change its value.
Definition: LeafNodeMask.h:252
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:1272
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:116
static Index getChildDim()
Return the dimension of child nodes of this LeafNode, which is one for voxels.
Definition: LeafNodeMask.h:112
if(rank==1) return rank
void setValuesOff()
Mark all voxels as inactive but don't change their values.
Definition: LeafNodeMask.h:277
void visit2(IterT &otherIter, VisitorOp &, bool otherIsLHS=false)
Definition: LeafNode.h:1941
GLintptr offset
Definition: glcorearb.h:664
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:560
void visitActiveBBox(BBoxOp &) const
Calls the templated functor BBoxOp with bounding box information. An additional level argument is pro...
Definition: LeafNode.h:1846
#define const
Definition: zconf.h:214
LeafNode * probeLeaf(const Coord &)
Return a pointer to this node.
Definition: LeafNodeMask.h:551
void setValue(Index i, const ValueType &)
Set the i'th value of this buffer to the specified value.
Definition: LeafBuffer.h:189
DenseIter< const LeafNode, const ValueType, ChildAll > ChildAllCIter
Definition: LeafNode.h:296
void setValueOff(Index offset)
Mark the voxel at the given offset as inactive but don't change its value.
Definition: LeafNodeMask.h:242
bool isValueOn(const Coord &xyz) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNodeMask.h:280
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:1492
bool operator==(const LeafNode &other) const
Check for buffer, state and origin equivalence.
Definition: LeafNode.h:1454
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:114
void evalActiveBoundingBox(CoordBBox &bbox, bool visitVoxels=true) const
Definition: LeafNode.h:1474
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:1051
static void evalNodeOrigin(Coord &xyz)
Compute the origin of the leaf node that contains the voxel with the given coordinates.
Definition: LeafNodeMask.h:726
static void doVisit2(NodeT &self, OtherChildAllIterT &, VisitorOp &, bool otherIsLHS)
Definition: LeafNode.h:1965
GLint y
Definition: glcorearb.h:102
ChildIter< MaskOffIterator, const LeafNode, ChildOff > ChildOffCIter
Definition: LeafNode.h:294
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:257
static Index getValueLevelAndCache(const Coord &, AccessorT &)
Return the LEVEL (=0) at which leaf node values reside.
Definition: LeafNodeMask.h:398
void addLeaf(LeafNode *)
This function exists only to enable template instantiation.
Definition: LeafNodeMask.h:528
bool isZero(const Type &x)
Return true if x is exactly equal to zero.
Definition: Math.h:338
void writeTopology(std::ostream &os, bool toHalf=false) const
Write out just the topology.
Definition: LeafNode.h:1317
DenseIter< LeafNode, ValueType, ChildAll > ChildAllIter
Definition: LeafNode.h:295
void resetBackground(bool, bool)
no-op since for this temaplte specialization voxel values and states are indistinguishable.
Definition: LeafNodeMask.h:445
void getOrigin(Coord &origin) const
Return the grid index coordinates of this node's local origin.
Definition: LeafNodeMask.h:159
ValueIter< MaskOffIterator, LeafNode, const ValueType, ValueOff > ValueOffIter
Definition: LeafNode.h:287
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:381
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:1202
static void doVisit2Node(NodeT &self, OtherNodeT &other, VisitorOp &)
Definition: LeafNode.h:1918