OpenVDB  4.0.2
LeafNode.h
Go to the documentation of this file.
1 //
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 //
30 
31 #ifndef OPENVDB_TREE_LEAFNODE_HAS_BEEN_INCLUDED
32 #define OPENVDB_TREE_LEAFNODE_HAS_BEEN_INCLUDED
33 
34 #include <openvdb/Types.h>
35 #include <openvdb/util/NodeMasks.h>
36 #include <openvdb/io/Compression.h> // for io::readData(), etc.
37 #include "Iterator.h"
38 #include "LeafBuffer.h"
39 #include <iostream>
40 #include <memory>
41 #include <algorithm>// for std::nth_element
42 #include <type_traits>
43 
44 
45 class TestLeaf;
46 template<typename> class TestLeafIO;
47 
48 namespace openvdb {
50 namespace OPENVDB_VERSION_NAME {
51 namespace tree {
52 
53 template<Index, typename> struct SameLeafConfig; // forward declaration
54 
55 
60 template<typename T, Index Log2Dim>
61 class LeafNode
62 {
63 public:
64  using BuildType = T;
65  using ValueType = T;
70 
71  static const Index
72  LOG2DIM = Log2Dim, // needed by parent nodes
73  TOTAL = Log2Dim, // needed by parent nodes
74  DIM = 1 << TOTAL, // dimension along one coordinate direction
75  NUM_VALUES = 1 << 3 * Log2Dim,
76  NUM_VOXELS = NUM_VALUES, // total number of voxels represented by this node
77  SIZE = NUM_VALUES,
78  LEVEL = 0; // level 0 = leaf
79 
82  template<typename OtherValueType>
84 
87  template<typename OtherNodeType>
90  };
91 
92 
94  LeafNode();
95 
100  explicit LeafNode(const Coord& coords,
101  const ValueType& value = zeroVal<ValueType>(),
102  bool active = false);
103 
104 
105 #ifndef OPENVDB_2_ABI_COMPATIBLE
112  const Coord& coords,
113  const ValueType& value = zeroVal<ValueType>(),
114  bool active = false);
115 #endif
116 
118  LeafNode(const LeafNode&);
119 
121  LeafNode& operator=(const LeafNode&) = default;
122 
124  template<typename OtherValueType>
125  explicit LeafNode(const LeafNode<OtherValueType, Log2Dim>& other);
126 
128  template<typename OtherValueType>
130  const ValueType& offValue, const ValueType& onValue, TopologyCopy);
131 
133  template<typename OtherValueType>
135  const ValueType& background, TopologyCopy);
136 
138  ~LeafNode();
139 
140  //
141  // Statistics
142  //
144  static Index log2dim() { return Log2Dim; }
146  static Index dim() { return DIM; }
148  static Index size() { return SIZE; }
150  static Index numValues() { return SIZE; }
152  static Index getLevel() { return LEVEL; }
154  static void getNodeLog2Dims(std::vector<Index>& dims) { dims.push_back(Log2Dim); }
156  static Index getChildDim() { return 1; }
158  static Index32 leafCount() { return 1; }
160  static Index32 nonLeafCount() { return 0; }
161 
163  Index64 onVoxelCount() const { return mValueMask.countOn(); }
165  Index64 offVoxelCount() const { return mValueMask.countOff(); }
166  Index64 onLeafVoxelCount() const { return onVoxelCount(); }
167  Index64 offLeafVoxelCount() const { return offVoxelCount(); }
168  static Index64 onTileCount() { return 0; }
169  static Index64 offTileCount() { return 0; }
171  bool isEmpty() const { return mValueMask.isOff(); }
173  bool isDense() const { return mValueMask.isOn(); }
174 
175 #ifndef OPENVDB_2_ABI_COMPATIBLE
176  bool isAllocated() const { return !mBuffer.isOutOfCore() && !mBuffer.empty(); }
179  bool allocate() { return mBuffer.allocate(); }
180 #endif
181 
183  Index64 memUsage() const;
184 
188  void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const;
189 
192  CoordBBox getNodeBoundingBox() const { return CoordBBox::createCube(mOrigin, DIM); }
193 
195  void setOrigin(const Coord& origin) { mOrigin = origin; }
197  const Coord& origin() const { return mOrigin; }
199  void getOrigin(Coord& origin) const { origin = mOrigin; }
200  void getOrigin(Int32& x, Int32& y, Int32& z) const { mOrigin.asXYZ(x, y, z); }
202 
204  static Index coordToOffset(const Coord& xyz);
207  static Coord offsetToLocalCoord(Index n);
209  Coord offsetToGlobalCoord(Index n) const;
210 
212  std::string str() const;
213 
216  template<typename OtherType, Index OtherLog2Dim>
217  bool hasSameTopology(const LeafNode<OtherType, OtherLog2Dim>* other) const;
218 
220  bool operator==(const LeafNode& other) const;
221  bool operator!=(const LeafNode& other) const { return !(other == *this); }
222 
223 protected:
227 
228  // Type tags to disambiguate template instantiations
229  struct ValueOn {}; struct ValueOff {}; struct ValueAll {};
230  struct ChildOn {}; struct ChildOff {}; struct ChildAll {};
231 
232  template<typename MaskIterT, typename NodeT, typename ValueT, typename TagT>
233  struct ValueIter:
234  // Derives from SparseIteratorBase, but can also be used as a dense iterator,
235  // if MaskIterT is a dense mask iterator type.
236  public SparseIteratorBase<
237  MaskIterT, ValueIter<MaskIterT, NodeT, ValueT, TagT>, NodeT, ValueT>
238  {
240 
242  ValueIter(const MaskIterT& iter, NodeT* parent): BaseT(iter, parent) {}
243 
244  ValueT& getItem(Index pos) const { return this->parent().getValue(pos); }
245  ValueT& getValue() const { return this->parent().getValue(this->pos()); }
246 
247  // Note: setItem() can't be called on const iterators.
248  void setItem(Index pos, const ValueT& value) const
249  {
250  this->parent().setValueOnly(pos, value);
251  }
252  // Note: setValue() can't be called on const iterators.
253  void setValue(const ValueT& value) const
254  {
255  this->parent().setValueOnly(this->pos(), value);
256  }
257 
258  // Note: modifyItem() can't be called on const iterators.
259  template<typename ModifyOp>
260  void modifyItem(Index n, const ModifyOp& op) const { this->parent().modifyValue(n, op); }
261  // Note: modifyValue() can't be called on const iterators.
262  template<typename ModifyOp>
263  void modifyValue(const ModifyOp& op) const { this->parent().modifyValue(this->pos(), op); }
264  };
265 
267  template<typename MaskIterT, typename NodeT, typename TagT>
268  struct ChildIter:
269  public SparseIteratorBase<MaskIterT, ChildIter<MaskIterT, NodeT, TagT>, NodeT, ValueType>
270  {
272  ChildIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase<
273  MaskIterT, ChildIter<MaskIterT, NodeT, TagT>, NodeT, ValueType>(iter, parent) {}
274  };
275 
276  template<typename NodeT, typename ValueT, typename TagT>
277  struct DenseIter: public DenseIteratorBase<
278  MaskDenseIterator, DenseIter<NodeT, ValueT, TagT>, NodeT, /*ChildT=*/void, ValueT>
279  {
282 
284  DenseIter(const MaskDenseIterator& iter, NodeT* parent): BaseT(iter, parent) {}
285 
286  bool getItem(Index pos, void*& child, NonConstValueT& value) const
287  {
288  value = this->parent().getValue(pos);
289  child = nullptr;
290  return false; // no child
291  }
292 
293  // Note: setItem() can't be called on const iterators.
294  //void setItem(Index pos, void* child) const {}
295 
296  // Note: unsetItem() can't be called on const iterators.
297  void unsetItem(Index pos, const ValueT& value) const
298  {
299  this->parent().setValueOnly(pos, value);
300  }
301  };
302 
303 public:
316 
317  ValueOnCIter cbeginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); }
318  ValueOnCIter beginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); }
319  ValueOnIter beginValueOn() { return ValueOnIter(mValueMask.beginOn(), this); }
320  ValueOffCIter cbeginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); }
321  ValueOffCIter beginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); }
322  ValueOffIter beginValueOff() { return ValueOffIter(mValueMask.beginOff(), this); }
323  ValueAllCIter cbeginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); }
324  ValueAllCIter beginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); }
325  ValueAllIter beginValueAll() { return ValueAllIter(mValueMask.beginDense(), this); }
326 
327  ValueOnCIter cendValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); }
328  ValueOnCIter endValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); }
329  ValueOnIter endValueOn() { return ValueOnIter(mValueMask.endOn(), this); }
330  ValueOffCIter cendValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); }
331  ValueOffCIter endValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); }
332  ValueOffIter endValueOff() { return ValueOffIter(mValueMask.endOff(), this); }
333  ValueAllCIter cendValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); }
334  ValueAllCIter endValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); }
335  ValueAllIter endValueAll() { return ValueAllIter(mValueMask.endDense(), this); }
336 
337  // Note that [c]beginChildOn() and [c]beginChildOff() actually return end iterators,
338  // because leaf nodes have no children.
339  ChildOnCIter cbeginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
340  ChildOnCIter beginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
341  ChildOnIter beginChildOn() { return ChildOnIter(mValueMask.endOn(), this); }
342  ChildOffCIter cbeginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
343  ChildOffCIter beginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
344  ChildOffIter beginChildOff() { return ChildOffIter(mValueMask.endOff(), this); }
345  ChildAllCIter cbeginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); }
346  ChildAllCIter beginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); }
347  ChildAllIter beginChildAll() { return ChildAllIter(mValueMask.beginDense(), this); }
348 
349  ChildOnCIter cendChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
350  ChildOnCIter endChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
351  ChildOnIter endChildOn() { return ChildOnIter(mValueMask.endOn(), this); }
352  ChildOffCIter cendChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
353  ChildOffCIter endChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
354  ChildOffIter endChildOff() { return ChildOffIter(mValueMask.endOff(), this); }
355  ChildAllCIter cendChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); }
356  ChildAllCIter endChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); }
357  ChildAllIter endChildAll() { return ChildAllIter(mValueMask.endDense(), this); }
358 
359  //
360  // Buffer management
361  //
364  void swap(Buffer& other) { mBuffer.swap(other); }
365  const Buffer& buffer() const { return mBuffer; }
366  Buffer& buffer() { return mBuffer; }
367 
368  //
369  // I/O methods
370  //
374  void readTopology(std::istream& is, bool fromHalf = false);
378  void writeTopology(std::ostream& os, bool toHalf = false) const;
379 
383  void readBuffers(std::istream& is, bool fromHalf = false);
388  void readBuffers(std::istream& is, const CoordBBox& bbox, bool fromHalf = false);
392  void writeBuffers(std::ostream& os, bool toHalf = false) const;
393 
394  size_t streamingSize(bool toHalf = false) const;
395 
396  //
397  // Accessor methods
398  //
400  const ValueType& getValue(const Coord& xyz) const;
402  const ValueType& getValue(Index offset) const;
403 
407  bool probeValue(const Coord& xyz, ValueType& val) const;
411  bool probeValue(Index offset, ValueType& val) const;
412 
414  static Index getValueLevel(const Coord&) { return LEVEL; }
415 
417  void setActiveState(const Coord& xyz, bool on);
419  void setActiveState(Index offset, bool on) { assert(offset<SIZE); mValueMask.set(offset, on); }
420 
422  void setValueOnly(const Coord& xyz, const ValueType& val);
424  void setValueOnly(Index offset, const ValueType& val);
425 
427  void setValueOff(const Coord& xyz) { mValueMask.setOff(LeafNode::coordToOffset(xyz)); }
429  void setValueOff(Index offset) { assert(offset < SIZE); mValueMask.setOff(offset); }
430 
432  void setValueOff(const Coord& xyz, const ValueType& val);
434  void setValueOff(Index offset, const ValueType& val);
435 
437  void setValueOn(const Coord& xyz) { mValueMask.setOn(LeafNode::coordToOffset(xyz)); }
439  void setValueOn(Index offset) { assert(offset < SIZE); mValueMask.setOn(offset); }
441  void setValueOn(const Coord& xyz, const ValueType& val) {
442  this->setValueOn(LeafNode::coordToOffset(xyz), val);
443  }
445  void setValue(const Coord& xyz, const ValueType& val) { this->setValueOn(xyz, val); }
447  void setValueOn(Index offset, const ValueType& val) {
448  mBuffer.setValue(offset, val);
449  mValueMask.setOn(offset);
450  }
451 
454  template<typename ModifyOp>
455  void modifyValue(Index offset, const ModifyOp& op)
456  {
457  ValueType val = mBuffer[offset];
458  op(val);
459  mBuffer.setValue(offset, val);
460  mValueMask.setOn(offset);
461  }
464  template<typename ModifyOp>
465  void modifyValue(const Coord& xyz, const ModifyOp& op)
466  {
467  this->modifyValue(this->coordToOffset(xyz), op);
468  }
469 
471  template<typename ModifyOp>
472  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
473  {
474  const Index offset = this->coordToOffset(xyz);
475  bool state = mValueMask.isOn(offset);
476  ValueType val = mBuffer[offset];
477  op(val, state);
478  mBuffer.setValue(offset, val);
479  mValueMask.set(offset, state);
480  }
481 
483  void setValuesOn() { mValueMask.setOn(); }
485  void setValuesOff() { mValueMask.setOff(); }
486 
488  bool isValueOn(const Coord& xyz) const {return this->isValueOn(LeafNode::coordToOffset(xyz));}
490  bool isValueOn(Index offset) const { return mValueMask.isOn(offset); }
491 
493  static bool hasActiveTiles() { return false; }
494 
496  void clip(const CoordBBox&, const ValueType& background);
497 
499  void fill(const CoordBBox& bbox, const ValueType&, bool active = true);
501  void denseFill(const CoordBBox& bbox, const ValueType& value, bool active = true)
502  {
503  this->fill(bbox, value, active);
504  }
505 
507  void fill(const ValueType& value);
509  void fill(const ValueType& value, bool active);
510 
522  template<typename DenseT>
523  void copyToDense(const CoordBBox& bbox, DenseT& dense) const;
524 
541  template<typename DenseT>
542  void copyFromDense(const CoordBBox& bbox, const DenseT& dense,
543  const ValueType& background, const ValueType& tolerance);
544 
547  template<typename AccessorT>
548  const ValueType& getValueAndCache(const Coord& xyz, AccessorT&) const
549  {
550  return this->getValue(xyz);
551  }
552 
555  template<typename AccessorT>
556  bool isValueOnAndCache(const Coord& xyz, AccessorT&) const { return this->isValueOn(xyz); }
557 
560  template<typename AccessorT>
561  void setValueAndCache(const Coord& xyz, const ValueType& val, AccessorT&)
562  {
563  this->setValueOn(xyz, val);
564  }
565 
569  template<typename AccessorT>
570  void setValueOnlyAndCache(const Coord& xyz, const ValueType& val, AccessorT&)
571  {
572  this->setValueOnly(xyz, val);
573  }
574 
578  template<typename ModifyOp, typename AccessorT>
579  void modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&)
580  {
581  this->modifyValue(xyz, op);
582  }
583 
586  template<typename ModifyOp, typename AccessorT>
587  void modifyValueAndActiveStateAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&)
588  {
589  this->modifyValueAndActiveState(xyz, op);
590  }
591 
594  template<typename AccessorT>
595  void setValueOffAndCache(const Coord& xyz, const ValueType& value, AccessorT&)
596  {
597  this->setValueOff(xyz, value);
598  }
599 
603  template<typename AccessorT>
604  void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&)
605  {
606  this->setActiveState(xyz, on);
607  }
608 
612  template<typename AccessorT>
613  bool probeValueAndCache(const Coord& xyz, ValueType& val, AccessorT&) const
614  {
615  return this->probeValue(xyz, val);
616  }
617 
621  template<typename AccessorT>
622  const ValueType& getValue(const Coord& xyz, bool& state, int& level, AccessorT&) const
623  {
624  const Index offset = this->coordToOffset(xyz);
625  state = mValueMask.isOn(offset);
626  level = LEVEL;
627  return mBuffer[offset];
628  }
629 
632  template<typename AccessorT>
633  static Index getValueLevelAndCache(const Coord&, AccessorT&) { return LEVEL; }
634 
638  const ValueType& getFirstValue() const { return mBuffer[0]; }
640  const ValueType& getLastValue() const { return mBuffer[SIZE - 1]; }
641 
644  void resetBackground(const ValueType& oldBackground, const ValueType& newBackground);
645 
646  void negate();
647 
650  void voxelizeActiveTiles(bool = true) {}
651 
652  template<MergePolicy Policy> void merge(const LeafNode&);
653  template<MergePolicy Policy> void merge(const ValueType& tileValue, bool tileActive);
654  template<MergePolicy Policy>
655  void merge(const LeafNode& other, const ValueType& /*bg*/, const ValueType& /*otherBG*/);
656 
663  template<typename OtherType>
664  void topologyUnion(const LeafNode<OtherType, Log2Dim>& other);
665 
677  template<typename OtherType>
678  void topologyIntersection(const LeafNode<OtherType, Log2Dim>& other, const ValueType&);
679 
691  template<typename OtherType>
692  void topologyDifference(const LeafNode<OtherType, Log2Dim>& other, const ValueType&);
693 
694  template<typename CombineOp>
695  void combine(const LeafNode& other, CombineOp& op);
696  template<typename CombineOp>
697  void combine(const ValueType& value, bool valueIsActive, CombineOp& op);
698 
699  template<typename CombineOp, typename OtherType /*= ValueType*/>
700  void combine2(const LeafNode& other, const OtherType&, bool valueIsActive, CombineOp&);
701  template<typename CombineOp, typename OtherNodeT /*= LeafNode*/>
702  void combine2(const ValueType&, const OtherNodeT& other, bool valueIsActive, CombineOp&);
703  template<typename CombineOp, typename OtherNodeT /*= LeafNode*/>
704  void combine2(const LeafNode& b0, const OtherNodeT& b1, CombineOp&);
705 
711  template<typename BBoxOp> void visitActiveBBox(BBoxOp&) const;
712 
713  template<typename VisitorOp> void visit(VisitorOp&);
714  template<typename VisitorOp> void visit(VisitorOp&) const;
715 
716  template<typename OtherLeafNodeType, typename VisitorOp>
717  void visit2Node(OtherLeafNodeType& other, VisitorOp&);
718  template<typename OtherLeafNodeType, typename VisitorOp>
719  void visit2Node(OtherLeafNodeType& other, VisitorOp&) const;
720  template<typename IterT, typename VisitorOp>
721  void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false);
722  template<typename IterT, typename VisitorOp>
723  void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false) const;
724 
726  void prune(const ValueType& /*tolerance*/ = zeroVal<ValueType>()) {}
728  void addLeaf(LeafNode*) {}
729  template<typename AccessorT>
730  void addLeafAndCache(LeafNode*, AccessorT&) {}
731  template<typename NodeT>
732  NodeT* stealNode(const Coord&, const ValueType&, bool) { return nullptr; }
733  template<typename NodeT>
734  NodeT* probeNode(const Coord&) { return nullptr; }
735  template<typename NodeT>
736  const NodeT* probeConstNode(const Coord&) const { return nullptr; }
737  template<typename ArrayT> void getNodes(ArrayT&) const {}
738  template<typename ArrayT> void stealNodes(ArrayT&, const ValueType&, bool) {}
740 
741  void addTile(Index level, const Coord&, const ValueType&, bool);
742  void addTile(Index offset, const ValueType&, bool);
743  template<typename AccessorT>
744  void addTileAndCache(Index, const Coord&, const ValueType&, bool, AccessorT&);
745 
747  LeafNode* touchLeaf(const Coord&) { return this; }
749  template<typename AccessorT>
750  LeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; }
751  template<typename NodeT, typename AccessorT>
752  NodeT* probeNodeAndCache(const Coord&, AccessorT&)
753  {
755  if (!(std::is_same<NodeT, LeafNode>::value)) return nullptr;
756  return reinterpret_cast<NodeT*>(this);
758  }
759  LeafNode* probeLeaf(const Coord&) { return this; }
760  template<typename AccessorT>
761  LeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; }
763 
764  const LeafNode* probeConstLeaf(const Coord&) const { return this; }
766  template<typename AccessorT>
767  const LeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const { return this; }
768  template<typename AccessorT>
769  const LeafNode* probeLeafAndCache(const Coord&, AccessorT&) const { return this; }
770  const LeafNode* probeLeaf(const Coord&) const { return this; }
771  template<typename NodeT, typename AccessorT>
772  const NodeT* probeConstNodeAndCache(const Coord&, AccessorT&) const
773  {
775  if (!(std::is_same<NodeT, LeafNode>::value)) return nullptr;
776  return reinterpret_cast<const NodeT*>(this);
778  }
780 
790  bool isConstant(ValueType& firstValue, bool& state,
791  const ValueType& tolerance = zeroVal<ValueType>()) const;
792 
804  bool isConstant(ValueType& minValue, ValueType& maxValue,
805  bool& state, const ValueType& tolerance = zeroVal<ValueType>()) const;
806 
807 
822  ValueType medianAll(ValueType *tmp = nullptr) const;
823 
838  Index medianOn(ValueType &value, ValueType *tmp = nullptr) const;
839 
854  Index medianOff(ValueType &value, ValueType *tmp = nullptr) const;
855 
857  bool isInactive() const { return mValueMask.isOff(); }
858 
859 protected:
860  friend class ::TestLeaf;
861  template<typename> friend class ::TestLeafIO;
862 
863  // During topology-only construction, access is needed
864  // to protected/private members of other template instances.
865  template<typename, Index> friend class LeafNode;
866 
873 
874  // Allow iterators to call mask accessor methods (see below).
879 
880  // Mask accessors
881 public:
882  bool isValueMaskOn(Index n) const { return mValueMask.isOn(n); }
883  bool isValueMaskOn() const { return mValueMask.isOn(); }
884  bool isValueMaskOff(Index n) const { return mValueMask.isOff(n); }
885  bool isValueMaskOff() const { return mValueMask.isOff(); }
886  const NodeMaskType& getValueMask() const { return mValueMask; }
887  NodeMaskType& getValueMask() { return mValueMask; }
888  const NodeMaskType& valueMask() const { return mValueMask; }
889  void setValueMask(const NodeMaskType& mask) { mValueMask = mask; }
890  bool isChildMaskOn(Index) const { return false; } // leaf nodes have no children
891  bool isChildMaskOff(Index) const { return true; }
892  bool isChildMaskOff() const { return true; }
893 protected:
894  void setValueMask(Index n, bool on) { mValueMask.set(n, on); }
895  void setValueMaskOn(Index n) { mValueMask.setOn(n); }
896  void setValueMaskOff(Index n) { mValueMask.setOff(n); }
897 
898  inline void skipCompressedValues(bool seekable, std::istream&, bool fromHalf);
899 
901  static void evalNodeOrigin(Coord& xyz) { xyz &= ~(DIM - 1); }
902 
903  template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
904  static inline void doVisit(NodeT&, VisitorOp&);
905 
906  template<typename NodeT, typename OtherNodeT, typename VisitorOp,
907  typename ChildAllIterT, typename OtherChildAllIterT>
908  static inline void doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp&);
909 
910  template<typename NodeT, typename VisitorOp,
911  typename ChildAllIterT, typename OtherChildAllIterT>
912  static inline void doVisit2(NodeT& self, OtherChildAllIterT&, VisitorOp&, bool otherIsLHS);
913 
914 private:
916  Buffer mBuffer;
918  NodeMaskType mValueMask;
920  Coord mOrigin;
921 }; // end of LeafNode class
922 
923 
925 
926 
928 template<Index Dim1, typename NodeT2>
931 struct SameLeafConfig { static const bool value = false; };
932 
933 template<Index Dim1, typename T2>
934 struct SameLeafConfig<Dim1, LeafNode<T2, Dim1> > { static const bool value = true; };
936 
937 
939 
940 
941 template<typename T, Index Log2Dim>
942 inline
944  mValueMask(),//default is off!
945  mOrigin(0, 0, 0)
946 {
947 }
948 
949 
950 template<typename T, Index Log2Dim>
951 inline
952 LeafNode<T, Log2Dim>::LeafNode(const Coord& xyz, const ValueType& val, bool active):
953  mBuffer(val),
954  mValueMask(active),
955  mOrigin(xyz & (~(DIM - 1)))
956 {
957 }
958 
959 
960 #ifndef OPENVDB_2_ABI_COMPATIBLE
961 template<typename T, Index Log2Dim>
962 inline
963 LeafNode<T, Log2Dim>::LeafNode(PartialCreate, const Coord& xyz, const ValueType& val, bool active):
964  mBuffer(PartialCreate(), val),
965  mValueMask(active),
966  mOrigin(xyz & (~(DIM - 1)))
967 {
968 }
969 #endif
970 
971 
972 template<typename T, Index Log2Dim>
973 inline
975  mBuffer(other.mBuffer),
976  mValueMask(other.valueMask()),
977  mOrigin(other.mOrigin)
978 {
979 }
980 
981 
982 // Copy-construct from a leaf node with the same configuration but a different ValueType.
983 template<typename T, Index Log2Dim>
984 template<typename OtherValueType>
985 inline
987  mValueMask(other.valueMask()),
988  mOrigin(other.mOrigin)
989 {
990  struct Local {
992  static inline ValueType convertValue(const OtherValueType& val) { return ValueType(val); }
993  };
994 
995  for (Index i = 0; i < SIZE; ++i) {
996  mBuffer[i] = Local::convertValue(other.mBuffer[i]);
997  }
998 }
999 
1000 
1001 template<typename T, Index Log2Dim>
1002 template<typename OtherValueType>
1003 inline
1005  const ValueType& background, TopologyCopy):
1006  mBuffer(background),
1007  mValueMask(other.valueMask()),
1008  mOrigin(other.mOrigin)
1009 {
1010 }
1011 
1012 
1013 template<typename T, Index Log2Dim>
1014 template<typename OtherValueType>
1015 inline
1017  const ValueType& offValue, const ValueType& onValue, TopologyCopy):
1018  mValueMask(other.valueMask()),
1019  mOrigin(other.mOrigin)
1020 {
1021  for (Index i = 0; i < SIZE; ++i) {
1022  mBuffer[i] = (mValueMask.isOn(i) ? onValue : offValue);
1023  }
1024 }
1025 
1026 
1027 template<typename T, Index Log2Dim>
1028 inline
1030 {
1031 }
1032 
1033 
1034 template<typename T, Index Log2Dim>
1035 inline std::string
1037 {
1038  std::ostringstream ostr;
1039  ostr << "LeafNode @" << mOrigin << ": " << mBuffer;
1040  return ostr.str();
1041 }
1042 
1043 
1045 
1046 
1047 template<typename T, Index Log2Dim>
1048 inline Index
1050 {
1051  assert ((xyz[0] & (DIM-1u)) < DIM && (xyz[1] & (DIM-1u)) < DIM && (xyz[2] & (DIM-1u)) < DIM);
1052  return ((xyz[0] & (DIM-1u)) << 2*Log2Dim)
1053  + ((xyz[1] & (DIM-1u)) << Log2Dim)
1054  + (xyz[2] & (DIM-1u));
1055 }
1056 
1057 template<typename T, Index Log2Dim>
1058 inline Coord
1060 {
1061  assert(n<(1<< 3*Log2Dim));
1062  Coord xyz;
1063  xyz.setX(n >> 2*Log2Dim);
1064  n &= ((1<<2*Log2Dim)-1);
1065  xyz.setY(n >> Log2Dim);
1066  xyz.setZ(n & ((1<<Log2Dim)-1));
1067  return xyz;
1068 }
1069 
1070 
1071 template<typename T, Index Log2Dim>
1072 inline Coord
1074 {
1075  return (this->offsetToLocalCoord(n) + this->origin());
1076 }
1077 
1078 
1080 
1081 
1082 template<typename ValueT, Index Log2Dim>
1083 inline const ValueT&
1085 {
1086  return this->getValue(LeafNode::coordToOffset(xyz));
1087 }
1088 
1089 template<typename ValueT, Index Log2Dim>
1090 inline const ValueT&
1092 {
1093  assert(offset < SIZE);
1094  return mBuffer[offset];
1095 }
1096 
1097 
1098 template<typename T, Index Log2Dim>
1099 inline bool
1101 {
1102  return this->probeValue(LeafNode::coordToOffset(xyz), val);
1103 }
1104 
1105 template<typename T, Index Log2Dim>
1106 inline bool
1108 {
1109  assert(offset < SIZE);
1110  val = mBuffer[offset];
1111  return mValueMask.isOn(offset);
1112 }
1113 
1114 
1115 template<typename T, Index Log2Dim>
1116 inline void
1118 {
1119  this->setValueOff(LeafNode::coordToOffset(xyz), val);
1120 }
1121 
1122 template<typename T, Index Log2Dim>
1123 inline void
1125 {
1126  assert(offset < SIZE);
1127  mBuffer.setValue(offset, val);
1128  mValueMask.setOff(offset);
1129 }
1130 
1131 
1132 template<typename T, Index Log2Dim>
1133 inline void
1135 {
1136  mValueMask.set(this->coordToOffset(xyz), on);
1137 }
1138 
1139 
1140 template<typename T, Index Log2Dim>
1141 inline void
1143 {
1144  this->setValueOnly(LeafNode::coordToOffset(xyz), val);
1145 }
1146 
1147 template<typename T, Index Log2Dim>
1148 inline void
1150 {
1151  assert(offset<SIZE); mBuffer.setValue(offset, val);
1152 }
1153 
1154 
1156 
1157 
1158 template<typename T, Index Log2Dim>
1159 inline void
1160 LeafNode<T, Log2Dim>::clip(const CoordBBox& clipBBox, const T& background)
1161 {
1162  CoordBBox nodeBBox = this->getNodeBoundingBox();
1163  if (!clipBBox.hasOverlap(nodeBBox)) {
1164  // This node lies completely outside the clipping region. Fill it with the background.
1165  this->fill(background, /*active=*/false);
1166  } else if (clipBBox.isInside(nodeBBox)) {
1167  // This node lies completely inside the clipping region. Leave it intact.
1168  return;
1169  }
1170 
1171  // This node isn't completely contained inside the clipping region.
1172  // Set any voxels that lie outside the region to the background value.
1173 
1174  // Construct a boolean mask that is on inside the clipping region and off outside it.
1175  NodeMaskType mask;
1176  nodeBBox.intersect(clipBBox);
1177  Coord xyz;
1178  int &x = xyz.x(), &y = xyz.y(), &z = xyz.z();
1179  for (x = nodeBBox.min().x(); x <= nodeBBox.max().x(); ++x) {
1180  for (y = nodeBBox.min().y(); y <= nodeBBox.max().y(); ++y) {
1181  for (z = nodeBBox.min().z(); z <= nodeBBox.max().z(); ++z) {
1182  mask.setOn(static_cast<Index32>(this->coordToOffset(xyz)));
1183  }
1184  }
1185  }
1186 
1187  // Set voxels that lie in the inactive region of the mask (i.e., outside
1188  // the clipping region) to the background value.
1189  for (MaskOffIterator maskIter = mask.beginOff(); maskIter; ++maskIter) {
1190  this->setValueOff(maskIter.pos(), background);
1191  }
1192 }
1193 
1194 
1196 
1197 
1198 template<typename T, Index Log2Dim>
1199 inline void
1200 LeafNode<T, Log2Dim>::fill(const CoordBBox& bbox, const ValueType& value, bool active)
1201 {
1202 #ifndef OPENVDB_2_ABI_COMPATIBLE
1203  if (!this->allocate()) return;
1204 #endif
1205 
1206  auto clippedBBox = this->getNodeBoundingBox();
1207  clippedBBox.intersect(bbox);
1208  if (!clippedBBox) return;
1209 
1210  for (Int32 x = clippedBBox.min().x(); x <= clippedBBox.max().x(); ++x) {
1211  const Index offsetX = (x & (DIM-1u)) << 2*Log2Dim;
1212  for (Int32 y = clippedBBox.min().y(); y <= clippedBBox.max().y(); ++y) {
1213  const Index offsetXY = offsetX + ((y & (DIM-1u)) << Log2Dim);
1214  for (Int32 z = clippedBBox.min().z(); z <= clippedBBox.max().z(); ++z) {
1215  const Index offset = offsetXY + (z & (DIM-1u));
1216  mBuffer[offset] = value;
1217  mValueMask.set(offset, active);
1218  }
1219  }
1220  }
1221 }
1222 
1223 template<typename T, Index Log2Dim>
1224 inline void
1226 {
1227  mBuffer.fill(value);
1228 }
1229 
1230 template<typename T, Index Log2Dim>
1231 inline void
1232 LeafNode<T, Log2Dim>::fill(const ValueType& value, bool active)
1233 {
1234  mBuffer.fill(value);
1235  mValueMask.set(active);
1236 }
1237 
1238 
1240 
1241 
1242 template<typename T, Index Log2Dim>
1243 template<typename DenseT>
1244 inline void
1245 LeafNode<T, Log2Dim>::copyToDense(const CoordBBox& bbox, DenseT& dense) const
1246 {
1247 #ifndef OPENVDB_2_ABI_COMPATIBLE
1248  mBuffer.loadValues();
1249 #endif
1250 
1251  using DenseValueType = typename DenseT::ValueType;
1252 
1253  const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride();
1254  const Coord& min = dense.bbox().min();
1255  DenseValueType* t0 = dense.data() + zStride * (bbox.min()[2] - min[2]); // target array
1256  const T* s0 = &mBuffer[bbox.min()[2] & (DIM-1u)]; // source array
1257  for (Int32 x = bbox.min()[0], ex = bbox.max()[0] + 1; x < ex; ++x) {
1258  DenseValueType* t1 = t0 + xStride * (x - min[0]);
1259  const T* s1 = s0 + ((x & (DIM-1u)) << 2*Log2Dim);
1260  for (Int32 y = bbox.min()[1], ey = bbox.max()[1] + 1; y < ey; ++y) {
1261  DenseValueType* t2 = t1 + yStride * (y - min[1]);
1262  const T* s2 = s1 + ((y & (DIM-1u)) << Log2Dim);
1263  for (Int32 z = bbox.min()[2], ez = bbox.max()[2] + 1; z < ez; ++z, t2 += zStride) {
1264  *t2 = DenseValueType(*s2++);
1265  }
1266  }
1267  }
1268 }
1269 
1270 
1271 template<typename T, Index Log2Dim>
1272 template<typename DenseT>
1273 inline void
1274 LeafNode<T, Log2Dim>::copyFromDense(const CoordBBox& bbox, const DenseT& dense,
1275  const ValueType& background, const ValueType& tolerance)
1276 {
1277 #ifndef OPENVDB_2_ABI_COMPATIBLE
1278  if (!this->allocate()) return;
1279 #endif
1280 
1281  using DenseValueType = typename DenseT::ValueType;
1282 
1283  const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride();
1284  const Coord& min = dense.bbox().min();
1285 
1286  const DenseValueType* s0 = dense.data() + zStride * (bbox.min()[2] - min[2]); // source
1287  const Int32 n0 = bbox.min()[2] & (DIM-1u);
1288  for (Int32 x = bbox.min()[0], ex = bbox.max()[0]+1; x < ex; ++x) {
1289  const DenseValueType* s1 = s0 + xStride * (x - min[0]);
1290  const Int32 n1 = n0 + ((x & (DIM-1u)) << 2*LOG2DIM);
1291  for (Int32 y = bbox.min()[1], ey = bbox.max()[1]+1; y < ey; ++y) {
1292  const DenseValueType* s2 = s1 + yStride * (y - min[1]);
1293  Int32 n2 = n1 + ((y & (DIM-1u)) << LOG2DIM);
1294  for (Int32 z = bbox.min()[2], ez = bbox.max()[2]+1; z < ez; ++z, ++n2, s2 += zStride) {
1295  if (math::isApproxEqual(background, ValueType(*s2), tolerance)) {
1296  mValueMask.setOff(n2);
1297  mBuffer[n2] = background;
1298  } else {
1299  mValueMask.setOn(n2);
1300  mBuffer[n2] = ValueType(*s2);
1301  }
1302  }
1303  }
1304  }
1305 }
1306 
1307 
1309 
1310 
1311 template<typename T, Index Log2Dim>
1312 inline void
1313 LeafNode<T, Log2Dim>::readTopology(std::istream& is, bool /*fromHalf*/)
1314 {
1315  mValueMask.load(is);
1316 }
1317 
1318 
1319 template<typename T, Index Log2Dim>
1320 inline void
1321 LeafNode<T, Log2Dim>::writeTopology(std::ostream& os, bool /*toHalf*/) const
1322 {
1323  mValueMask.save(os);
1324 }
1325 
1326 
1328 
1329 
1330 
1331 template<typename T, Index Log2Dim>
1332 inline void
1333 LeafNode<T,Log2Dim>::skipCompressedValues(bool seekable, std::istream& is, bool fromHalf)
1334 {
1335  if (seekable) {
1336  // Seek over voxel values.
1337  io::readCompressedValues<ValueType, NodeMaskType>(
1338  is, nullptr, SIZE, mValueMask, fromHalf);
1339  } else {
1340  // Read and discard voxel values.
1341  Buffer temp;
1342  io::readCompressedValues(is, temp.mData, SIZE, mValueMask, fromHalf);
1343  }
1344 }
1345 
1346 
1347 template<typename T, Index Log2Dim>
1348 inline void
1349 LeafNode<T,Log2Dim>::readBuffers(std::istream& is, bool fromHalf)
1350 {
1351  this->readBuffers(is, CoordBBox::inf(), fromHalf);
1352 }
1353 
1354 
1355 template<typename T, Index Log2Dim>
1356 inline void
1357 LeafNode<T,Log2Dim>::readBuffers(std::istream& is, const CoordBBox& clipBBox, bool fromHalf)
1358 {
1360  const bool seekable = meta && meta->seekable();
1361 
1362 #ifndef OPENVDB_2_ABI_COMPATIBLE
1363  std::streamoff maskpos = is.tellg();
1364 #endif
1365 
1366  if (seekable) {
1367  // Seek over the value mask.
1368  mValueMask.seek(is);
1369  } else {
1370  // Read in the value mask.
1371  mValueMask.load(is);
1372  }
1373 
1374  int8_t numBuffers = 1;
1376  // Read in the origin.
1377  is.read(reinterpret_cast<char*>(&mOrigin), sizeof(Coord::ValueType) * 3);
1378 
1379  // Read in the number of buffers, which should now always be one.
1380  is.read(reinterpret_cast<char*>(&numBuffers), sizeof(int8_t));
1381  }
1382 
1383  CoordBBox nodeBBox = this->getNodeBoundingBox();
1384  if (!clipBBox.hasOverlap(nodeBBox)) {
1385  // This node lies completely outside the clipping region.
1386  skipCompressedValues(seekable, is, fromHalf);
1387  mValueMask.setOff();
1388  mBuffer.setOutOfCore(false);
1389  } else {
1390 #ifndef OPENVDB_2_ABI_COMPATIBLE
1391  // If this node lies completely inside the clipping region and it is being read
1392  // from a memory-mapped file, delay loading of its buffer until the buffer
1393  // is actually accessed. (If this node requires clipping, its buffer
1394  // must be accessed and therefore must be loaded.)
1395  io::MappedFile::Ptr mappedFile = io::getMappedFilePtr(is);
1396  const bool delayLoad = ((mappedFile.get() != nullptr) && clipBBox.isInside(nodeBBox));
1397 
1398  if (delayLoad) {
1399  mBuffer.setOutOfCore(true);
1400  mBuffer.mFileInfo = new typename Buffer::FileInfo;
1401  mBuffer.mFileInfo->meta = meta;
1402  mBuffer.mFileInfo->bufpos = is.tellg();
1403  mBuffer.mFileInfo->mapping = mappedFile;
1404  // Save the offset to the value mask, because the in-memory copy
1405  // might change before the value buffer gets read.
1406  mBuffer.mFileInfo->maskpos = maskpos;
1407  // Skip over voxel values.
1408  skipCompressedValues(seekable, is, fromHalf);
1409  } else {
1410 #endif
1411  mBuffer.allocate();
1412  io::readCompressedValues(is, mBuffer.mData, SIZE, mValueMask, fromHalf);
1413  mBuffer.setOutOfCore(false);
1414 
1415  // Get this tree's background value.
1416  T background = zeroVal<T>();
1417  if (const void* bgPtr = io::getGridBackgroundValuePtr(is)) {
1418  background = *static_cast<const T*>(bgPtr);
1419  }
1420  this->clip(clipBBox, background);
1421 #ifndef OPENVDB_2_ABI_COMPATIBLE
1422  }
1423 #endif
1424  }
1425 
1426  if (numBuffers > 1) {
1427  // Read in and discard auxiliary buffers that were created with earlier
1428  // versions of the library. (Auxiliary buffers are not mask compressed.)
1429  const bool zipped = io::getDataCompression(is) & io::COMPRESS_ZIP;
1430  Buffer temp;
1431  for (int i = 1; i < numBuffers; ++i) {
1432  if (fromHalf) {
1433  io::HalfReader<io::RealToHalf<T>::isReal, T>::read(is, temp.mData, SIZE, zipped);
1434  } else {
1435  io::readData<T>(is, temp.mData, SIZE, zipped);
1436  }
1437  }
1438  }
1439 }
1440 
1441 
1442 template<typename T, Index Log2Dim>
1443 inline void
1444 LeafNode<T, Log2Dim>::writeBuffers(std::ostream& os, bool toHalf) const
1445 {
1446  // Write out the value mask.
1447  mValueMask.save(os);
1448 
1449  mBuffer.loadValues();
1450 
1451  io::writeCompressedValues(os, mBuffer.mData, SIZE,
1452  mValueMask, /*childMask=*/NodeMaskType(), toHalf);
1453 }
1454 
1455 
1457 
1458 
1459 template<typename T, Index Log2Dim>
1460 inline bool
1462 {
1463  return mOrigin == other.mOrigin &&
1464  mValueMask == other.valueMask() &&
1465  mBuffer == other.mBuffer;
1466 }
1467 
1468 
1469 template<typename T, Index Log2Dim>
1470 inline Index64
1472 {
1473  // Use sizeof(*this) to capture alignment-related padding
1474  // (but note that sizeof(*this) includes sizeof(mBuffer)).
1475  return sizeof(*this) + mBuffer.memUsage() - sizeof(mBuffer);
1476 }
1477 
1478 
1479 template<typename T, Index Log2Dim>
1480 inline void
1482 {
1483  CoordBBox this_bbox = this->getNodeBoundingBox();
1484  if (bbox.isInside(this_bbox)) return;//this LeafNode is already enclosed in the bbox
1485  if (ValueOnCIter iter = this->cbeginValueOn()) {//any active values?
1486  if (visitVoxels) {//use voxel granularity?
1487  this_bbox.reset();
1488  for(; iter; ++iter) this_bbox.expand(this->offsetToLocalCoord(iter.pos()));
1489  this_bbox.translate(this->origin());
1490  }
1491  bbox.expand(this_bbox);
1492  }
1493 }
1494 
1495 
1496 template<typename T, Index Log2Dim>
1497 template<typename OtherType, Index OtherLog2Dim>
1498 inline bool
1500 {
1501  assert(other);
1502  return (Log2Dim == OtherLog2Dim && mValueMask == other->getValueMask());
1503 }
1504 
1505 template<typename T, Index Log2Dim>
1506 inline bool
1508  bool& state,
1509  const ValueType& tolerance) const
1510 {
1511  if (!mValueMask.isConstant(state)) return false;// early termination
1512  firstValue = mBuffer[0];
1513  for (Index i = 1; i < SIZE; ++i) {
1514  if ( !math::isApproxEqual(mBuffer[i], firstValue, tolerance) ) return false;// early termination
1515  }
1516  return true;
1517 }
1518 
1519 template<typename T, Index Log2Dim>
1520 inline bool
1522  ValueType& maxValue,
1523  bool& state,
1524  const ValueType& tolerance) const
1525 {
1526  if (!mValueMask.isConstant(state)) return false;// early termination
1527  minValue = maxValue = mBuffer[0];
1528  for (Index i = 1; i < SIZE; ++i) {
1529  const T& v = mBuffer[i];
1530  if (v < minValue) {
1531  if ((maxValue - v) > tolerance) return false;// early termination
1532  minValue = v;
1533  } else if (v > maxValue) {
1534  if ((v - minValue) > tolerance) return false;// early termination
1535  maxValue = v;
1536  }
1537  }
1538  return true;
1539 }
1540 
1541 template<typename T, Index Log2Dim>
1542 inline T
1544 {
1545  std::unique_ptr<T[]> data(nullptr);
1546  if (tmp == nullptr) {//allocate temporary storage
1547  data.reset(new T[NUM_VALUES]);
1548  tmp = data.get();
1549  }
1550  if (tmp != mBuffer.data()) {
1551  const T* src = mBuffer.data();
1552  for (T* dst = tmp; dst-tmp < NUM_VALUES;) *dst++ = *src++;
1553  }
1554  static const size_t midpoint = (NUM_VALUES - 1) >> 1;
1555  std::nth_element(tmp, tmp + midpoint, tmp + NUM_VALUES);
1556  return tmp[midpoint];
1557 }
1558 
1559 template<typename T, Index Log2Dim>
1560 inline Index
1561 LeafNode<T, Log2Dim>::medianOn(T &value, T *tmp) const
1562 {
1563  const Index count = mValueMask.countOn();
1564  if (count == NUM_VALUES) {//special case: all voxels are active
1565  value = this->medianAll(tmp);
1566  return NUM_VALUES;
1567  } else if (count == 0) {
1568  return 0;
1569  }
1570  std::unique_ptr<T[]> data(nullptr);
1571  if (tmp == nullptr) {//allocate temporary storage
1572  data.reset(new T[count]);// 0 < count < NUM_VALUES
1573  tmp = data.get();
1574  }
1575  for (auto iter=this->cbeginValueOn(); iter; ++iter) *tmp++ = *iter;
1576  T *begin = tmp - count;
1577  const size_t midpoint = (count - 1) >> 1;
1578  std::nth_element(begin, begin + midpoint, tmp);
1579  value = begin[midpoint];
1580  return count;
1581 }
1582 
1583 template<typename T, Index Log2Dim>
1584 inline Index
1585 LeafNode<T, Log2Dim>::medianOff(T &value, T *tmp) const
1586 {
1587  const Index count = mValueMask.countOff();
1588  if (count == NUM_VALUES) {//special case: all voxels are inactive
1589  value = this->medianAll(tmp);
1590  return NUM_VALUES;
1591  } else if (count == 0) {
1592  return 0;
1593  }
1594  std::unique_ptr<T[]> data(nullptr);
1595  if (tmp == nullptr) {//allocate temporary storage
1596  data.reset(new T[count]);// 0 < count < NUM_VALUES
1597  tmp = data.get();
1598  }
1599  for (auto iter=this->cbeginValueOff(); iter; ++iter) *tmp++ = *iter;
1600  T *begin = tmp - count;
1601  const size_t midpoint = (count - 1) >> 1;
1602  std::nth_element(begin, begin + midpoint, tmp);
1603  value = begin[midpoint];
1604  return count;
1605 }
1606 
1608 
1609 
1610 template<typename T, Index Log2Dim>
1611 inline void
1612 LeafNode<T, Log2Dim>::addTile(Index /*level*/, const Coord& xyz, const ValueType& val, bool active)
1613 {
1614  this->addTile(this->coordToOffset(xyz), val, active);
1615 }
1616 
1617 template<typename T, Index Log2Dim>
1618 inline void
1619 LeafNode<T, Log2Dim>::addTile(Index offset, const ValueType& val, bool active)
1620 {
1621  assert(offset < SIZE);
1622  setValueOnly(offset, val);
1623  setActiveState(offset, active);
1624 }
1625 
1626 template<typename T, Index Log2Dim>
1627 template<typename AccessorT>
1628 inline void
1630  const ValueType& val, bool active, AccessorT&)
1631 {
1632  this->addTile(level, xyz, val, active);
1633 }
1634 
1635 
1637 
1638 
1639 template<typename T, Index Log2Dim>
1640 inline void
1642  const ValueType& newBackground)
1643 {
1644 #ifndef OPENVDB_2_ABI_COMPATIBLE
1645  if (!this->allocate()) return;
1646 #endif
1647 
1648  typename NodeMaskType::OffIterator iter;
1649  // For all inactive values...
1650  for (iter = this->mValueMask.beginOff(); iter; ++iter) {
1651  ValueType &inactiveValue = mBuffer[iter.pos()];
1652  if (math::isApproxEqual(inactiveValue, oldBackground)) {
1653  inactiveValue = newBackground;
1654  } else if (math::isApproxEqual(inactiveValue, math::negative(oldBackground))) {
1655  inactiveValue = math::negative(newBackground);
1656  }
1657  }
1658 }
1659 
1660 
1661 template<typename T, Index Log2Dim>
1662 template<MergePolicy Policy>
1663 inline void
1665 {
1666 #ifndef OPENVDB_2_ABI_COMPATIBLE
1667  if (!this->allocate()) return;
1668 #endif
1669 
1671  if (Policy == MERGE_NODES) return;
1672  typename NodeMaskType::OnIterator iter = other.valueMask().beginOn();
1673  for (; iter; ++iter) {
1674  const Index n = iter.pos();
1675  if (mValueMask.isOff(n)) {
1676  mBuffer[n] = other.mBuffer[n];
1677  mValueMask.setOn(n);
1678  }
1679  }
1681 }
1682 
1683 template<typename T, Index Log2Dim>
1684 template<MergePolicy Policy>
1685 inline void
1687  const ValueType& /*bg*/, const ValueType& /*otherBG*/)
1688 {
1689  this->template merge<Policy>(other);
1690 }
1691 
1692 template<typename T, Index Log2Dim>
1693 template<MergePolicy Policy>
1694 inline void
1695 LeafNode<T, Log2Dim>::merge(const ValueType& tileValue, bool tileActive)
1696 {
1697 #ifndef OPENVDB_2_ABI_COMPATIBLE
1698  if (!this->allocate()) return;
1699 #endif
1700 
1702  if (Policy != MERGE_ACTIVE_STATES_AND_NODES) return;
1703  if (!tileActive) return;
1704  // Replace all inactive values with the active tile value.
1705  for (typename NodeMaskType::OffIterator iter = mValueMask.beginOff(); iter; ++iter) {
1706  const Index n = iter.pos();
1707  mBuffer[n] = tileValue;
1708  mValueMask.setOn(n);
1709  }
1711 }
1712 
1713 
1714 template<typename T, Index Log2Dim>
1715 template<typename OtherType>
1716 inline void
1718 {
1719  mValueMask |= other.valueMask();
1720 }
1721 
1722 template<typename T, Index Log2Dim>
1723 template<typename OtherType>
1724 inline void
1726  const ValueType&)
1727 {
1728  mValueMask &= other.valueMask();
1729 }
1730 
1731 template<typename T, Index Log2Dim>
1732 template<typename OtherType>
1733 inline void
1735  const ValueType&)
1736 {
1737  mValueMask &= !other.valueMask();
1738 }
1739 
1740 template<typename T, Index Log2Dim>
1741 inline void
1743 {
1744 #ifndef OPENVDB_2_ABI_COMPATIBLE
1745  if (!this->allocate()) return;
1746 #endif
1747  for (Index i = 0; i < SIZE; ++i) {
1748  mBuffer[i] = -mBuffer[i];
1749  }
1750 }
1751 
1752 
1754 
1755 
1756 template<typename T, Index Log2Dim>
1757 template<typename CombineOp>
1758 inline void
1759 LeafNode<T, Log2Dim>::combine(const LeafNode& other, CombineOp& op)
1760 {
1761 #ifndef OPENVDB_2_ABI_COMPATIBLE
1762  if (!this->allocate()) return;
1763 #endif
1764  CombineArgs<T> args;
1765  for (Index i = 0; i < SIZE; ++i) {
1766  op(args.setARef(mBuffer[i])
1767  .setAIsActive(mValueMask.isOn(i))
1768  .setBRef(other.mBuffer[i])
1769  .setBIsActive(other.valueMask().isOn(i))
1770  .setResultRef(mBuffer[i]));
1771  mValueMask.set(i, args.resultIsActive());
1772  }
1773 }
1774 
1775 
1776 template<typename T, Index Log2Dim>
1777 template<typename CombineOp>
1778 inline void
1779 LeafNode<T, Log2Dim>::combine(const ValueType& value, bool valueIsActive, CombineOp& op)
1780 {
1781 #ifndef OPENVDB_2_ABI_COMPATIBLE
1782  if (!this->allocate()) return;
1783 #endif
1784  CombineArgs<T> args;
1785  args.setBRef(value).setBIsActive(valueIsActive);
1786  for (Index i = 0; i < SIZE; ++i) {
1787  op(args.setARef(mBuffer[i])
1788  .setAIsActive(mValueMask.isOn(i))
1789  .setResultRef(mBuffer[i]));
1790  mValueMask.set(i, args.resultIsActive());
1791  }
1792 }
1793 
1794 
1796 
1797 
1798 template<typename T, Index Log2Dim>
1799 template<typename CombineOp, typename OtherType>
1800 inline void
1801 LeafNode<T, Log2Dim>::combine2(const LeafNode& other, const OtherType& value,
1802  bool valueIsActive, CombineOp& op)
1803 {
1804 #ifndef OPENVDB_2_ABI_COMPATIBLE
1805  if (!this->allocate()) return;
1806 #endif
1808  args.setBRef(value).setBIsActive(valueIsActive);
1809  for (Index i = 0; i < SIZE; ++i) {
1810  op(args.setARef(other.mBuffer[i])
1811  .setAIsActive(other.valueMask().isOn(i))
1812  .setResultRef(mBuffer[i]));
1813  mValueMask.set(i, args.resultIsActive());
1814  }
1815 }
1816 
1817 
1818 template<typename T, Index Log2Dim>
1819 template<typename CombineOp, typename OtherNodeT>
1820 inline void
1821 LeafNode<T, Log2Dim>::combine2(const ValueType& value, const OtherNodeT& other,
1822  bool valueIsActive, CombineOp& op)
1823 {
1824 #ifndef OPENVDB_2_ABI_COMPATIBLE
1825  if (!this->allocate()) return;
1826 #endif
1828  args.setARef(value).setAIsActive(valueIsActive);
1829  for (Index i = 0; i < SIZE; ++i) {
1830  op(args.setBRef(other.mBuffer[i])
1831  .setBIsActive(other.valueMask().isOn(i))
1832  .setResultRef(mBuffer[i]));
1833  mValueMask.set(i, args.resultIsActive());
1834  }
1835 }
1836 
1837 
1838 template<typename T, Index Log2Dim>
1839 template<typename CombineOp, typename OtherNodeT>
1840 inline void
1841 LeafNode<T, Log2Dim>::combine2(const LeafNode& b0, const OtherNodeT& b1, CombineOp& op)
1842 {
1843 #ifndef OPENVDB_2_ABI_COMPATIBLE
1844  if (!this->allocate()) return;
1845 #endif
1847  for (Index i = 0; i < SIZE; ++i) {
1848  mValueMask.set(i, b0.valueMask().isOn(i) || b1.valueMask().isOn(i));
1849  op(args.setARef(b0.mBuffer[i])
1850  .setAIsActive(b0.valueMask().isOn(i))
1851  .setBRef(b1.mBuffer[i])
1852  .setBIsActive(b1.valueMask().isOn(i))
1853  .setResultRef(mBuffer[i]));
1854  mValueMask.set(i, args.resultIsActive());
1855  }
1856 }
1857 
1858 
1860 
1861 
1862 template<typename T, Index Log2Dim>
1863 template<typename BBoxOp>
1864 inline void
1866 {
1867  if (op.template descent<LEVEL>()) {
1868  for (ValueOnCIter i=this->cbeginValueOn(); i; ++i) {
1869 #ifdef _MSC_VER
1870  op.operator()<LEVEL>(CoordBBox::createCube(i.getCoord(), 1));
1871 #else
1872  op.template operator()<LEVEL>(CoordBBox::createCube(i.getCoord(), 1));
1873 #endif
1874  }
1875  } else {
1876 #ifdef _MSC_VER
1877  op.operator()<LEVEL>(this->getNodeBoundingBox());
1878 #else
1879  op.template operator()<LEVEL>(this->getNodeBoundingBox());
1880 #endif
1881  }
1882 }
1883 
1884 
1885 template<typename T, Index Log2Dim>
1886 template<typename VisitorOp>
1887 inline void
1889 {
1890  doVisit<LeafNode, VisitorOp, ChildAllIter>(*this, op);
1891 }
1892 
1893 
1894 template<typename T, Index Log2Dim>
1895 template<typename VisitorOp>
1896 inline void
1897 LeafNode<T, Log2Dim>::visit(VisitorOp& op) const
1898 {
1899  doVisit<const LeafNode, VisitorOp, ChildAllCIter>(*this, op);
1900 }
1901 
1902 
1903 template<typename T, Index Log2Dim>
1904 template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
1905 inline void
1906 LeafNode<T, Log2Dim>::doVisit(NodeT& self, VisitorOp& op)
1907 {
1908  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1909  op(iter);
1910  }
1911 }
1912 
1913 
1915 
1916 
1917 template<typename T, Index Log2Dim>
1918 template<typename OtherLeafNodeType, typename VisitorOp>
1919 inline void
1920 LeafNode<T, Log2Dim>::visit2Node(OtherLeafNodeType& other, VisitorOp& op)
1921 {
1922  doVisit2Node<LeafNode, OtherLeafNodeType, VisitorOp, ChildAllIter,
1923  typename OtherLeafNodeType::ChildAllIter>(*this, other, op);
1924 }
1925 
1926 
1927 template<typename T, Index Log2Dim>
1928 template<typename OtherLeafNodeType, typename VisitorOp>
1929 inline void
1930 LeafNode<T, Log2Dim>::visit2Node(OtherLeafNodeType& other, VisitorOp& op) const
1931 {
1932  doVisit2Node<const LeafNode, OtherLeafNodeType, VisitorOp, ChildAllCIter,
1933  typename OtherLeafNodeType::ChildAllCIter>(*this, other, op);
1934 }
1935 
1936 
1937 template<typename T, Index Log2Dim>
1938 template<
1939  typename NodeT,
1940  typename OtherNodeT,
1941  typename VisitorOp,
1942  typename ChildAllIterT,
1943  typename OtherChildAllIterT>
1944 inline void
1945 LeafNode<T, Log2Dim>::doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp& op)
1946 {
1947  // Allow the two nodes to have different ValueTypes, but not different dimensions.
1948  static_assert(OtherNodeT::SIZE == NodeT::SIZE,
1949  "can't visit nodes of different sizes simultaneously");
1950  static_assert(OtherNodeT::LEVEL == NodeT::LEVEL,
1951  "can't visit nodes at different tree levels simultaneously");
1952 
1953  ChildAllIterT iter = self.beginChildAll();
1954  OtherChildAllIterT otherIter = other.beginChildAll();
1955 
1956  for ( ; iter && otherIter; ++iter, ++otherIter) {
1957  op(iter, otherIter);
1958  }
1959 }
1960 
1961 
1963 
1964 
1965 template<typename T, Index Log2Dim>
1966 template<typename IterT, typename VisitorOp>
1967 inline void
1968 LeafNode<T, Log2Dim>::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS)
1969 {
1970  doVisit2<LeafNode, VisitorOp, ChildAllIter, IterT>(
1971  *this, otherIter, op, otherIsLHS);
1972 }
1973 
1974 
1975 template<typename T, Index Log2Dim>
1976 template<typename IterT, typename VisitorOp>
1977 inline void
1978 LeafNode<T, Log2Dim>::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS) const
1979 {
1980  doVisit2<const LeafNode, VisitorOp, ChildAllCIter, IterT>(
1981  *this, otherIter, op, otherIsLHS);
1982 }
1983 
1984 
1985 template<typename T, Index Log2Dim>
1986 template<
1987  typename NodeT,
1988  typename VisitorOp,
1989  typename ChildAllIterT,
1990  typename OtherChildAllIterT>
1991 inline void
1992 LeafNode<T, Log2Dim>::doVisit2(NodeT& self, OtherChildAllIterT& otherIter,
1993  VisitorOp& op, bool otherIsLHS)
1994 {
1995  if (!otherIter) return;
1996 
1997  if (otherIsLHS) {
1998  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1999  op(otherIter, iter);
2000  }
2001  } else {
2002  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
2003  op(iter, otherIter);
2004  }
2005  }
2006 }
2007 
2008 
2010 
2011 
2012 template<typename T, Index Log2Dim>
2013 inline std::ostream&
2014 operator<<(std::ostream& os, const typename LeafNode<T, Log2Dim>::Buffer& buf)
2015 {
2016  for (Index32 i = 0, N = buf.size(); i < N; ++i) os << buf.mData[i] << ", ";
2017  return os;
2018 }
2019 
2020 } // namespace tree
2021 } // namespace OPENVDB_VERSION_NAME
2022 } // namespace openvdb
2023 
2024 
2026 
2027 
2028 // Specialization for LeafNodes of type bool
2029 #include "LeafNodeBool.h"
2030 
2031 // Specialization for LeafNodes with mask information only
2032 #include "LeafNodeMask.h"
2033 
2034 #endif // OPENVDB_TREE_LEAFNODE_HAS_BEEN_INCLUDED
2035 
2036 // Copyright (c) 2012-2017 DreamWorks Animation LLC
2037 // All rights reserved. This software is distributed under the
2038 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
void writeBuffers(std::ostream &os, bool toHalf=false) const
Write buffers to a stream.
Definition: LeafNode.h:1444
const Buffer & buffer() const
Definition: LeafNode.h:365
bool isValueMaskOn() const
Definition: LeafNode.h:883
Base class for sparse iterators over internal and leaf nodes.
Definition: Iterator.h:143
ValueOnCIter cendValueOn() const
Definition: LeafNode.h:327
NodeT * probeNodeAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: LeafNode.h:752
ValueT & getValue() const
Definition: LeafNode.h:245
static void getNodeLog2Dims(std::vector< Index > &dims)
Append the Log2Dim of this LeafNode to the specified vector.
Definition: LeafNode.h:154
void setValueOn(Index offset, const ValueType &val)
Set the value of the voxel at the given offset and mark the voxel as active.
Definition: LeafNode.h:447
bool operator!=(const LeafNode &other) const
Definition: LeafNode.h:221
NodeT * stealNode(const Coord &, const ValueType &, bool)
This function exists only to enable template instantiation.
Definition: LeafNode.h:732
typename NodeMaskType::DenseIterator MaskDenseIterator
Definition: LeafNode.h:226
GridType::Ptr clip(const GridType &grid, const BBoxd &bbox, bool keepInterior=true)
Clip the given grid against a world-space bounding box and return a new grid containing the result...
Definition: Clip.h:375
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...
OPENVDB_API uint32_t getDataCompression(std::ios_base &)
Return a bitwise OR of compression option flags (COMPRESS_ZIP, COMPRESS_ACTIVE_MASK, etc.) specifying whether and how input data is compressed or output data should be compressed.
static Index getLevel()
Return the level of this node, which by definition is zero for LeafNodes.
Definition: LeafNode.h:152
void modifyValue(const Coord &xyz, const ModifyOp &op)
Apply a functor to the value of the voxel at the given coordinates and mark the voxel as active...
Definition: LeafNode.h:465
void setActiveState(const Coord &xyz, bool on)
Set the active state of the voxel at the given coordinates but don&#39;t change its value.
Definition: LeafNode.h:1134
Index64 offLeafVoxelCount() const
Definition: LeafNode.h:167
SharedPtr< LeafNode > Ptr
Definition: LeafNode.h:69
static Index64 offTileCount()
Definition: LeafNode.h:169
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:1499
ChildOffIter endChildOff()
Definition: LeafNode.h:354
std::shared_ptr< T > SharedPtr
Definition: Types.h:130
bool isValueMaskOn(Index n) const
Definition: LeafNode.h:882
OPENVDB_API SharedPtr< StreamMetadata > getStreamMetadataPtr(std::ios_base &)
Return a shared pointer to an object that stores metadata (file format, compression scheme...
Definition: Types.h:317
Int32 z() const
Definition: Coord.h:156
Coord offsetToGlobalCoord(Index n) const
Return the global coordinates for a linear table offset.
Definition: LeafNode.h:1073
NodeMaskType & getValueMask()
Definition: LeafNode.h:887
void modifyValueAndActiveStateAndCache(const Coord &xyz, const ModifyOp &op, AccessorT &)
Definition: LeafNode.h:587
Coord & setZ(Int32 z)
Definition: Coord.h:105
Definition: LeafNode.h:46
Index64 memUsage() const
Return the memory in bytes occupied by this node.
Definition: LeafNode.h:1471
ValueOnCIter beginValueOn() const
Definition: LeafNode.h:318
std::string str() const
Return a string representation of this node.
Definition: LeafNode.h:1036
bool isOn(Index32 n) const
Return true if the nth bit is on.
Definition: NodeMasks.h:502
void visit(VisitorOp &)
Definition: LeafNode.h:1888
ChildOnCIter cendChildOn() const
Definition: LeafNode.h:349
void clip(const CoordBBox &, const ValueType &background)
Set all voxels that lie outside the given axis-aligned box to the background.
Definition: LeafNode.h:1160
bool operator==(const LeafNode &other) const
Check for buffer, state and origin equivalence.
Definition: LeafNode.h:1461
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:1200
Base class for iterators over internal and leaf nodes.
Definition: Iterator.h:58
bool probeValueAndCache(const Coord &xyz, ValueType &val, AccessorT &) const
Return true if the voxel at the given coordinates is active and return the voxel value in val...
Definition: LeafNode.h:613
static Index dim()
Return the number of voxels in each coordinate dimension.
Definition: LeafNode.h:146
void skipCompressedValues(bool seekable, std::istream &, bool fromHalf)
Definition: LeafNode.h:1333
static Index getValueLevel(const Coord &)
Return the level (i.e., 0) at which leaf node values reside.
Definition: LeafNode.h:414
LeafNode()
Default constructor.
Definition: LeafNode.h:943
static void evalNodeOrigin(Coord &xyz)
Compute the origin of the leaf node that contains the voxel with the given coordinates.
Definition: LeafNode.h:901
void setValueMaskOn(Index n)
Definition: LeafNode.h:895
bool isValueOn(Index offset) const
Return true if the voxel at the given offset is active.
Definition: LeafNode.h:490
Int32 y() const
Definition: Coord.h:155
void visitActiveBBox(BBoxOp &) const
Calls the templated functor BBoxOp with bounding box information. An additional level argument is pro...
Definition: LeafNode.h:1865
void modifyItem(Index n, const ModifyOp &op) const
Definition: LeafNode.h:260
uint32_t Index32
Definition: Types.h:55
void addTileAndCache(Index, const Coord &, const ValueType &, bool, AccessorT &)
Definition: LeafNode.h:1629
void topologyDifference(const LeafNode< OtherType, Log2Dim > &other, const ValueType &)
Difference this node&#39;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:1734
ChildOffCIter endChildOff() const
Definition: LeafNode.h:353
void modifyValue(const ModifyOp &op) const
Definition: LeafNode.h:263
tbb::atomic< Index32 > i
Definition: LeafBuffer.h:71
bool isApproxEqual(const Type &a, const Type &b)
Return true if a is equal to b to within the default floating-point comparison tolerance.
Definition: Math.h:354
bool isDense() const
Return true if this node contains only active voxels.
Definition: LeafNode.h:173
void setValueMaskOff(Index n)
Definition: LeafNode.h:896
ValueAllIter endValueAll()
Definition: LeafNode.h:335
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:1274
Index64 offVoxelCount() const
Return the number of voxels marked Off.
Definition: LeafNode.h:165
void setValueOn(const Coord &xyz, const ValueType &val)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: LeafNode.h:441
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:261
T * data
Definition: LeafBuffer.h:71
ValueIter(const MaskIterT &iter, NodeT *parent)
Definition: LeafNode.h:242
DenseIter(const MaskDenseIterator &iter, NodeT *parent)
Definition: LeafNode.h:284
Index32 pos() const
Definition: NodeMasks.h:200
void visit2(IterT &otherIter, VisitorOp &, bool otherIsLHS=false)
Definition: LeafNode.h:1968
void expand(ValueType padding)
Pad this bounding box with the specified padding.
Definition: Coord.h:419
static bool hasActiveTiles()
Return false since leaf nodes never contain tiles.
Definition: LeafNode.h:493
OffIterator beginOff() const
Definition: NodeMasks.h:354
static Index numValues()
Return the total number of voxels represented by this LeafNode.
Definition: LeafNode.h:150
typename BaseT::NonConstValueType NonConstValueT
Definition: LeafNode.h:281
ChildAllIter beginChildAll()
Definition: LeafNode.h:347
static void doVisit2(NodeT &self, OtherChildAllIterT &, VisitorOp &, bool otherIsLHS)
Definition: LeafNode.h:1992
const NodeMaskType & getValueMask() const
Definition: LeafNode.h:886
Index32 Index
Definition: Types.h:57
Definition: NodeMasks.h:270
ValueOnCIter cbeginValueOn() const
Definition: LeafNode.h:317
bool isEmpty() const
Return true if this node has no active voxels.
Definition: LeafNode.h:171
ValueOffCIter cbeginValueOff() const
Definition: LeafNode.h:320
static Index size()
Return the total number of voxels represented by this LeafNode.
Definition: LeafNode.h:148
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:505
ChildAllCIter cbeginChildAll() const
Definition: LeafNode.h:345
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: LeafNode.h:1084
void setValueOnly(const Coord &xyz, const ValueType &val)
Set the value of the voxel at the given coordinates but don&#39;t change its active state.
Definition: LeafNode.h:1142
void setValueOnlyAndCache(const Coord &xyz, const ValueType &val, AccessorT &)
Change the value of the voxel at the given coordinates but preserve its state.
Definition: LeafNode.h:570
ValueType * mData
Definition: LeafBuffer.h:220
void combine2(const LeafNode &other, const OtherType &, bool valueIsActive, CombineOp &)
Definition: LeafNode.h:1801
static Index32 nonLeafCount()
Return the non-leaf count for this node, which is zero.
Definition: LeafNode.h:160
bool isConstant(ValueType &firstValue, bool &state, const ValueType &tolerance=zeroVal< ValueType >()) const
Definition: LeafNode.h:1507
typename NodeMaskType::OffIterator MaskOffIterator
Definition: LeafNode.h:225
void writeTopology(std::ostream &os, bool toHalf=false) const
Write out just the topology.
Definition: LeafNode.h:1321
ValueOffCIter endValueOff() const
Definition: LeafNode.h:331
ValueAllCIter cbeginValueAll() const
Definition: LeafNode.h:323
LeafNode * touchLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: LeafNode.h:750
bool isChildMaskOff() const
Definition: LeafNode.h:892
void setValuesOff()
Mark all voxels as inactive but don&#39;t change their values.
Definition: LeafNode.h:485
void writeCompressedValues(std::ostream &os, ValueT *srcBuf, Index srcCount, const MaskT &valueMask, const MaskT &childMask, bool toHalf)
Definition: Compression.h:462
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don&#39;t change its value.
Definition: LeafNode.h:427
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:129
void resetBackground(const ValueType &oldBackground, const ValueType &newBackground)
Replace inactive occurrences of oldBackground with newBackground, and inactive occurrences of -oldBac...
Definition: LeafNode.h:1641
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:61
uint64_t Index64
Definition: Types.h:56
const LeafNode * probeLeafAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: LeafNode.h:769
Buffer & buffer()
Definition: LeafNode.h:366
void setValueOff(Index offset)
Mark the voxel at the given offset as inactive but don&#39;t change its value.
Definition: LeafNode.h:429
ValueConverter<T>::Type is the type of a LeafNode having the same dimensions as this node but a diffe...
Definition: LeafNode.h:83
void merge(const LeafNode &)
Definition: LeafNode.h:1664
static Index getValueLevelAndCache(const Coord &, AccessorT &)
Return the LEVEL (=0) at which leaf node values reside.
Definition: LeafNode.h:633
void setValueAndCache(const Coord &xyz, const ValueType &val, AccessorT &)
Change the value of the voxel at the given coordinates and mark it as active.
Definition: LeafNode.h:561
Index medianOn(ValueType &value, ValueType *tmp=nullptr) const
Computes the median value of all the active voxels in this node.
Definition: LeafNode.h:1561
~LeafNode()
Destructor.
Definition: LeafNode.h:1029
const NodeT * probeConstNode(const Coord &) const
This function exists only to enable template instantiation.
Definition: LeafNode.h:736
void prune(TreeT &tree, typename TreeT::ValueType tolerance=zeroVal< typename TreeT::ValueType >(), bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing with tiles any nodes whose values are all the same...
Definition: Prune.h:361
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
Definition: LeafNode.h:472
#define OPENVDB_VERSION_NAME
Definition: version.h:43
CombineArgs & setBRef(const BValueType &b)
Redirect the B value to a new external source.
Definition: Types.h:426
void unsetItem(Index pos, const ValueT &value) const
Definition: LeafNode.h:297
ValueT & getItem(Index pos) const
Definition: LeafNode.h:244
void translate(const Coord &t)
Translate this bounding box by .
Definition: Coord.h:458
DenseIter()
Definition: LeafNode.h:283
CoordBBox getNodeBoundingBox() const
Return the bounding box of this node, i.e., the full index space spanned by this leaf node...
Definition: LeafNode.h:192
static Index log2dim()
Return log2 of the dimension of this LeafNode, e.g. 3 if dimensions are 8^3.
Definition: LeafNode.h:144
const ValueType & getValue(const Coord &xyz, bool &state, int &level, AccessorT &) const
Return the value of the voxel at the given coordinates and return its active state and level (i...
Definition: LeafNode.h:622
typename NodeMaskType::OnIterator MaskOnIterator
Definition: LeafNode.h:224
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:108
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &)
Set the active state of the voxel at the given coordinates without changing its value.
Definition: LeafNode.h:604
Index64 onLeafVoxelCount() const
Definition: LeafNode.h:166
void stealNodes(ArrayT &, const ValueType &, bool)
This function exists only to enable template instantiation.
Definition: LeafNode.h:738
ChildAllIter endChildAll()
Definition: LeafNode.h:357
const ValueType & getValueAndCache(const Coord &xyz, AccessorT &) const
Return the value of the voxel at the given coordinates.
Definition: LeafNode.h:548
void setValue(const Coord &xyz, const ValueType &val)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: LeafNode.h:445
Leaf nodes have no children, so their child iterators have no get/set accessors.
Definition: LeafNode.h:268
ValueOffIter beginValueOff()
Definition: LeafNode.h:322
ChildAllCIter endChildAll() const
Definition: LeafNode.h:356
ChildAllCIter beginChildAll() const
Definition: LeafNode.h:346
static Coord offsetToLocalCoord(Index n)
Return the local coordinates for a linear table offset, where offset 0 has coordinates (0...
Definition: LeafNode.h:1059
void readCompressedValues(std::istream &is, ValueT *destBuf, Index destCount, const MaskT &valueMask, bool fromHalf)
Definition: Compression.h:339
static CoordBBox inf()
Return an "infinite" bounding box, as defined by the Coord value range.
Definition: Coord.h:332
ChildOnIter beginChildOn()
Definition: LeafNode.h:341
const ValueType & getLastValue() const
Return a const reference to the last value in the buffer.
Definition: LeafNode.h:640
void setValueMask(Index n, bool on)
Definition: LeafNode.h:894
ChildOnCIter endChildOn() const
Definition: LeafNode.h:350
bool isValueOnAndCache(const Coord &xyz, AccessorT &) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNode.h:556
bool isChildMaskOn(Index) const
Definition: LeafNode.h:890
void copyFromDense(const DenseT &dense, GridOrTreeT &sparse, const typename GridOrTreeT::ValueType &tolerance, bool serial=false)
Populate a sparse grid with the values of all of the voxels of a dense grid.
Definition: Dense.h:592
bool isInactive() const
Return true if all of this node&#39;s values are inactive.
Definition: LeafNode.h:857
ValueOffIter endValueOff()
Definition: LeafNode.h:332
bool isValueMaskOff() const
Definition: LeafNode.h:885
static Index coordToOffset(const Coord &xyz)
Return the linear table offset of the given global or local coordinates.
Definition: LeafNode.h:1049
bool isInside(const Coord &xyz) const
Return true if point (x, y, z) is inside this bounding box.
Definition: Coord.h:401
Definition: Exceptions.h:39
Coord & setX(Int32 x)
Definition: Coord.h:103
bool operator==(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Equality operator, does exact floating point comparisons.
Definition: Vec3.h:487
ChildIter(const MaskIterT &iter, NodeT *parent)
Definition: LeafNode.h:272
ValueAllCIter beginValueAll() const
Definition: LeafNode.h:324
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition: Platform.h:129
void setItem(Index pos, const ValueT &value) const
Definition: LeafNode.h:248
void combine(const LeafNode &other, CombineOp &op)
Definition: LeafNode.h:1759
void topologyUnion(const LeafNode< OtherType, Log2Dim > &other)
Union this node&#39;s set of active values with the active values of the other node, whose ValueType may ...
Definition: LeafNode.h:1717
const Coord & max() const
Definition: Coord.h:335
Definition: NodeMasks.h:239
bool resultIsActive() const
Definition: Types.h:435
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:371
bool isValueMaskOff(Index n) const
Definition: LeafNode.h:884
void swap(Buffer &other)
Exchange this node&#39;s data buffer with the given data buffer without changing the active states of the...
Definition: LeafNode.h:364
void intersect(const CoordBBox &bbox)
Intersect this bounding box with the given bounding box.
Definition: Coord.h:445
ChildOffCIter cbeginChildOff() const
Definition: LeafNode.h:342
Index64 onVoxelCount() const
Return the number of voxels marked On.
Definition: LeafNode.h:163
ChildOffCIter beginChildOff() const
Definition: LeafNode.h:343
T ValueType
Definition: LeafNode.h:65
void denseFill(const CoordBBox &bbox, const ValueType &value, bool active=true)
Set all voxels within an axis-aligned box to the specified value and active state.
Definition: LeafNode.h:501
void visit2Node(OtherLeafNodeType &other, VisitorOp &)
Definition: LeafNode.h:1920
void negate()
Definition: LeafNode.h:1742
SameConfiguration<OtherNodeType>::value is true if and only if OtherNodeType is the type of a LeafNod...
Definition: LeafNode.h:88
static Index32 leafCount()
Return the leaf count for this node, which is one.
Definition: LeafNode.h:158
OPENVDB_API uint32_t getFormatVersion(std::ios_base &)
Return the file format version number associated with the given input stream.
ChildOnIter endChildOn()
Definition: LeafNode.h:351
CombineArgs & setARef(const AValueType &a)
Redirect the A value to a new external source.
Definition: Types.h:424
void setActiveState(Index offset, bool on)
Set the active state of the voxel at the given offset but don&#39;t change its value. ...
Definition: LeafNode.h:419
ChildOffCIter cendChildOff() const
Definition: LeafNode.h:352
static const Index SIZE
Definition: LeafNode.h:77
const NodeT * probeConstNodeAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: LeafNode.h:772
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:455
void modifyValueAndCache(const Coord &xyz, const ModifyOp &op, AccessorT &)
Apply a functor to the value of the voxel at the given coordinates and mark the voxel as active...
Definition: LeafNode.h:579
static CoordBBox createCube(const Coord &min, ValueType dim)
Definition: Coord.h:326
void readBuffers(std::istream &is, bool fromHalf=false)
Read buffers from a stream.
Definition: LeafNode.h:1349
bool probeValue(const Coord &xyz, ValueType &val) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNode.h:1100
void addLeafAndCache(LeafNode *, AccessorT &)
This function exists only to enable template instantiation.
Definition: LeafNode.h:730
const NodeMaskType & valueMask() const
Definition: LeafNode.h:888
void setValueOffAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
Change the value of the voxel at the given coordinates and mark it as inactive.
Definition: LeafNode.h:595
SharedPtr< MappedFile > Ptr
Definition: io.h:152
void setValueOn(Index offset)
Mark the voxel at the given offset as active but don&#39;t change its value.
Definition: LeafNode.h:439
ChildOffIter beginChildOff()
Definition: LeafNode.h:344
ValueIter()
Definition: LeafNode.h:241
bool getItem(Index pos, void *&child, NonConstValueT &value) const
Definition: LeafNode.h:286
Int32 x() const
Definition: Coord.h:154
const LeafNode * probeConstLeafAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: LeafNode.h:767
const ValueType & getFirstValue() const
Return a const reference to the first value in the buffer.
Definition: LeafNode.h:638
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:130
void setValue(const ValueT &value) const
Definition: LeafNode.h:253
static Index getChildDim()
Return the dimension of child nodes of this LeafNode, which is one for voxels.
Definition: LeafNode.h:156
Definition: NodeMasks.h:208
void getNodes(ArrayT &) const
This function exists only to enable template instantiation.
Definition: LeafNode.h:737
T BuildType
Definition: LeafNode.h:64
const LeafNode * probeLeaf(const Coord &) const
Return a const pointer to this node.
Definition: LeafNode.h:770
ChildIter()
Definition: LeafNode.h:271
ValueOnIter beginValueOn()
Definition: LeafNode.h:319
LeafNode * probeLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: LeafNode.h:761
ValueOffCIter beginValueOff() const
Definition: LeafNode.h:321
ValueOffCIter cendValueOff() const
Definition: LeafNode.h:330
Definition: PointDataGrid.h:192
ValueOnIter endValueOn()
Definition: LeafNode.h:329
Definition: Compression.h:79
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:503
Index medianOff(ValueType &value, ValueType *tmp=nullptr) const
Computes the median value of all the inactive voxels in this node.
Definition: LeafNode.h:1585
ValueType medianAll(ValueType *tmp=nullptr) const
Computes the median value of all the active AND inactive voxels in this node.
Definition: LeafNode.h:1543
ValueOnCIter endValueOn() const
Definition: LeafNode.h:328
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:48
void getOrigin(Int32 &x, Int32 &y, Int32 &z) const
Return the grid index coordinates of this node&#39;s local origin.
Definition: LeafNode.h:200
ChildAllCIter cendChildAll() const
Definition: LeafNode.h:355
ChildOnCIter cbeginChildOn() const
Definition: LeafNode.h:339
void setOrigin(const Coord &origin)
Set the grid index coordinates of this node&#39;s local origin.
Definition: LeafNode.h:195
ChildOnCIter beginChildOn() const
Definition: LeafNode.h:340
ValueAllCIter cendValueAll() const
Definition: LeafNode.h:333
int32_t Int32
Definition: Types.h:59
void voxelizeActiveTiles(bool=true)
No-op.
Definition: LeafNode.h:650
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation. ...
Definition: NodeMasks.h:307
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don&#39;t change its value.
Definition: LeafNode.h:437
ValueAllCIter endValueAll() const
Definition: LeafNode.h:334
void topologyIntersection(const LeafNode< OtherType, Log2Dim > &other, const ValueType &)
Intersect this node&#39;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:1725
void copyToDense(const GridOrTreeT &sparse, DenseT &dense, bool serial=false)
Populate a dense grid with the values of voxels from a sparse grid, where the sparse grid intersects ...
Definition: Dense.h:445
static void doVisit(NodeT &, VisitorOp &)
Definition: LeafNode.h:1906
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
Int32 ValueType
Definition: Coord.h:56
static Index64 onTileCount()
Definition: LeafNode.h:168
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
Coord & setY(Int32 y)
Definition: Coord.h:104
const Coord & min() const
Definition: Coord.h:334
void addLeaf(LeafNode *)
This function exists only to enable template instantiation.
Definition: LeafNode.h:728
void reset()
Definition: Coord.h:340
void evalActiveBoundingBox(CoordBBox &bbox, bool visitVoxels=true) const
Definition: LeafNode.h:1481
NodeT * probeNode(const Coord &)
This function exists only to enable template instantiation.
Definition: LeafNode.h:734
LeafNode * probeLeaf(const Coord &)
Return a pointer to this node.
Definition: LeafNode.h:759
bool hasOverlap(const CoordBBox &b) const
Return true if the given bounding box overlaps with this bounding box.
Definition: Coord.h:413
ValueAllIter beginValueAll()
Definition: LeafNode.h:325
static void doVisit2Node(NodeT &self, OtherNodeT &other, VisitorOp &)
Definition: LeafNode.h:1945
void setValuesOn()
Mark all voxels as active but don&#39;t change their values.
Definition: LeafNode.h:483
bool isValueOn(const Coord &xyz) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNode.h:488
void setOn(Index32 n)
Set the nth bit on.
Definition: NodeMasks.h:452
void setValueMask(const NodeMaskType &mask)
Definition: LeafNode.h:889
boost::remove_const< UnsetItemT >::type NonConstValueType
Definition: Iterator.h:212
void getOrigin(Coord &origin) const
Return the grid index coordinates of this node&#39;s local origin.
Definition: LeafNode.h:199
Definition: Compression.h:216
void addTile(Index level, const Coord &, const ValueType &, bool)
Definition: LeafNode.h:1612
bool allocate()
Allocate memory for this node&#39;s buffer if it has not already been allocated.
Definition: LeafNode.h:179
Base class for dense iterators over internal and leaf nodes.
Definition: Iterator.h:206
OnIterator beginOn() const
Definition: NodeMasks.h:352
bool isChildMaskOff(Index) const
Definition: LeafNode.h:891
void readTopology(std::istream &is, bool fromHalf=false)
Read in just the topology.
Definition: LeafNode.h:1313
OPENVDB_API SharedPtr< MappedFile > getMappedFilePtr(std::ios_base &)
Return a shared pointer to the memory-mapped file with which the given stream is associated, or a null pointer if the stream is not associated with a memory-mapped file.