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