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