OpenVDB  7.0.0
LeafNode.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 #ifndef OPENVDB_TREE_LEAFNODE_HAS_BEEN_INCLUDED
5 #define OPENVDB_TREE_LEAFNODE_HAS_BEEN_INCLUDED
6 
7 #include <openvdb/Types.h>
9 #include <openvdb/io/Compression.h> // for io::readData(), etc.
10 #include "Iterator.h"
11 #include "LeafBuffer.h"
12 #include <algorithm> // for std::nth_element()
13 #include <iostream>
14 #include <memory>
15 #include <sstream>
16 #include <string>
17 #include <type_traits>
18 #include <vector>
19 
20 
21 class TestLeaf;
22 template<typename> class TestLeafIO;
23 
24 namespace openvdb {
26 namespace OPENVDB_VERSION_NAME {
27 namespace tree {
28 
29 template<Index, typename> struct SameLeafConfig; // forward declaration
30 
31 
36 template<typename T, Index Log2Dim>
37 class LeafNode
38 {
39 public:
40  using BuildType = T;
41  using ValueType = T;
46 
47  static const Index
48  LOG2DIM = Log2Dim, // needed by parent nodes
49  TOTAL = Log2Dim, // needed by parent nodes
50  DIM = 1 << TOTAL, // dimension along one coordinate direction
51  NUM_VALUES = 1 << 3 * Log2Dim,
52  NUM_VOXELS = NUM_VALUES, // total number of voxels represented by this node
53  SIZE = NUM_VALUES,
54  LEVEL = 0; // level 0 = leaf
55 
58  template<typename OtherValueType>
60 
63  template<typename OtherNodeType>
66  };
67 
68 
70  LeafNode();
71 
76  explicit LeafNode(const Coord& coords,
77  const ValueType& value = zeroVal<ValueType>(),
78  bool active = false);
79 
86  const Coord& coords,
87  const ValueType& value = zeroVal<ValueType>(),
88  bool active = false);
89 
91  LeafNode(const LeafNode&);
92 
94  LeafNode& operator=(const LeafNode&) = default;
95 
97  template<typename OtherValueType>
98  explicit LeafNode(const LeafNode<OtherValueType, Log2Dim>& other);
99 
101  template<typename OtherValueType>
103  const ValueType& offValue, const ValueType& onValue, TopologyCopy);
104 
106  template<typename OtherValueType>
108  const ValueType& background, TopologyCopy);
109 
111  ~LeafNode();
112 
113  //
114  // Statistics
115  //
117  static Index log2dim() { return Log2Dim; }
119  static Index dim() { return DIM; }
121  static Index size() { return SIZE; }
123  static Index numValues() { return SIZE; }
125  static Index getLevel() { return LEVEL; }
127  static void getNodeLog2Dims(std::vector<Index>& dims) { dims.push_back(Log2Dim); }
129  static Index getChildDim() { return 1; }
131  static Index32 leafCount() { return 1; }
133  void nodeCount(std::vector<Index32> &) const {}
135  static Index32 nonLeafCount() { return 0; }
136 
138  Index64 onVoxelCount() const { return mValueMask.countOn(); }
140  Index64 offVoxelCount() const { return mValueMask.countOff(); }
141  Index64 onLeafVoxelCount() const { return onVoxelCount(); }
142  Index64 offLeafVoxelCount() const { return offVoxelCount(); }
143  static Index64 onTileCount() { return 0; }
144  static Index64 offTileCount() { return 0; }
146  bool isEmpty() const { return mValueMask.isOff(); }
148  bool isDense() const { return mValueMask.isOn(); }
150  bool isAllocated() const { return !mBuffer.isOutOfCore() && !mBuffer.empty(); }
152  bool allocate() { return mBuffer.allocate(); }
153 
155  Index64 memUsage() const;
156 
160  void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const;
161 
164  CoordBBox getNodeBoundingBox() const { return CoordBBox::createCube(mOrigin, DIM); }
165 
167  void setOrigin(const Coord& origin) { mOrigin = origin; }
169  const Coord& origin() const { return mOrigin; }
171  void getOrigin(Coord& origin) const { origin = mOrigin; }
172  void getOrigin(Int32& x, Int32& y, Int32& z) const { mOrigin.asXYZ(x, y, z); }
174 
176  static Index coordToOffset(const Coord& xyz);
179  static Coord offsetToLocalCoord(Index n);
181  Coord offsetToGlobalCoord(Index n) const;
182 
184  std::string str() const;
185 
188  template<typename OtherType, Index OtherLog2Dim>
189  bool hasSameTopology(const LeafNode<OtherType, OtherLog2Dim>* other) const;
190 
192  bool operator==(const LeafNode& other) const;
193  bool operator!=(const LeafNode& other) const { return !(other == *this); }
194 
195 protected:
199 
200  // Type tags to disambiguate template instantiations
201  struct ValueOn {}; struct ValueOff {}; struct ValueAll {};
202  struct ChildOn {}; struct ChildOff {}; struct ChildAll {};
203 
204  template<typename MaskIterT, typename NodeT, typename ValueT, typename TagT>
205  struct ValueIter:
206  // Derives from SparseIteratorBase, but can also be used as a dense iterator,
207  // if MaskIterT is a dense mask iterator type.
208  public SparseIteratorBase<
209  MaskIterT, ValueIter<MaskIterT, NodeT, ValueT, TagT>, NodeT, ValueT>
210  {
212 
214  ValueIter(const MaskIterT& iter, NodeT* parent): BaseT(iter, parent) {}
215 
216  ValueT& getItem(Index pos) const { return this->parent().getValue(pos); }
217  ValueT& getValue() const { return this->parent().getValue(this->pos()); }
218 
219  // Note: setItem() can't be called on const iterators.
220  void setItem(Index pos, const ValueT& value) const
221  {
222  this->parent().setValueOnly(pos, value);
223  }
224  // Note: setValue() can't be called on const iterators.
225  void setValue(const ValueT& value) const
226  {
227  this->parent().setValueOnly(this->pos(), value);
228  }
229 
230  // Note: modifyItem() can't be called on const iterators.
231  template<typename ModifyOp>
232  void modifyItem(Index n, const ModifyOp& op) const { this->parent().modifyValue(n, op); }
233  // Note: modifyValue() can't be called on const iterators.
234  template<typename ModifyOp>
235  void modifyValue(const ModifyOp& op) const { this->parent().modifyValue(this->pos(), op); }
236  };
237 
239  template<typename MaskIterT, typename NodeT, typename TagT>
240  struct ChildIter:
241  public SparseIteratorBase<MaskIterT, ChildIter<MaskIterT, NodeT, TagT>, NodeT, ValueType>
242  {
244  ChildIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase<
245  MaskIterT, ChildIter<MaskIterT, NodeT, TagT>, NodeT, ValueType>(iter, parent) {}
246  };
247 
248  template<typename NodeT, typename ValueT, typename TagT>
249  struct DenseIter: public DenseIteratorBase<
250  MaskDenseIterator, DenseIter<NodeT, ValueT, TagT>, NodeT, /*ChildT=*/void, ValueT>
251  {
254 
256  DenseIter(const MaskDenseIterator& iter, NodeT* parent): BaseT(iter, parent) {}
257 
258  bool getItem(Index pos, void*& child, NonConstValueT& value) const
259  {
260  value = this->parent().getValue(pos);
261  child = nullptr;
262  return false; // no child
263  }
264 
265  // Note: setItem() can't be called on const iterators.
266  //void setItem(Index pos, void* child) const {}
267 
268  // Note: unsetItem() can't be called on const iterators.
269  void unsetItem(Index pos, const ValueT& value) const
270  {
271  this->parent().setValueOnly(pos, value);
272  }
273  };
274 
275 public:
288 
289  ValueOnCIter cbeginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); }
290  ValueOnCIter beginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); }
291  ValueOnIter beginValueOn() { return ValueOnIter(mValueMask.beginOn(), this); }
292  ValueOffCIter cbeginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); }
293  ValueOffCIter beginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); }
294  ValueOffIter beginValueOff() { return ValueOffIter(mValueMask.beginOff(), this); }
295  ValueAllCIter cbeginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); }
296  ValueAllCIter beginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); }
297  ValueAllIter beginValueAll() { return ValueAllIter(mValueMask.beginDense(), this); }
298 
299  ValueOnCIter cendValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); }
300  ValueOnCIter endValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); }
301  ValueOnIter endValueOn() { return ValueOnIter(mValueMask.endOn(), this); }
302  ValueOffCIter cendValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); }
303  ValueOffCIter endValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); }
304  ValueOffIter endValueOff() { return ValueOffIter(mValueMask.endOff(), this); }
305  ValueAllCIter cendValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); }
306  ValueAllCIter endValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); }
307  ValueAllIter endValueAll() { return ValueAllIter(mValueMask.endDense(), this); }
308 
309  // Note that [c]beginChildOn() and [c]beginChildOff() actually return end iterators,
310  // because leaf nodes have no children.
311  ChildOnCIter cbeginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
312  ChildOnCIter beginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
313  ChildOnIter beginChildOn() { return ChildOnIter(mValueMask.endOn(), this); }
314  ChildOffCIter cbeginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
315  ChildOffCIter beginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
316  ChildOffIter beginChildOff() { return ChildOffIter(mValueMask.endOff(), this); }
317  ChildAllCIter cbeginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); }
318  ChildAllCIter beginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); }
319  ChildAllIter beginChildAll() { return ChildAllIter(mValueMask.beginDense(), this); }
320 
321  ChildOnCIter cendChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
322  ChildOnCIter endChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
323  ChildOnIter endChildOn() { return ChildOnIter(mValueMask.endOn(), this); }
324  ChildOffCIter cendChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
325  ChildOffCIter endChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
326  ChildOffIter endChildOff() { return ChildOffIter(mValueMask.endOff(), this); }
327  ChildAllCIter cendChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); }
328  ChildAllCIter endChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); }
329  ChildAllIter endChildAll() { return ChildAllIter(mValueMask.endDense(), this); }
330 
331  //
332  // Buffer management
333  //
336  void swap(Buffer& other) { mBuffer.swap(other); }
337  const Buffer& buffer() const { return mBuffer; }
338  Buffer& buffer() { return mBuffer; }
339 
340  //
341  // I/O methods
342  //
346  void readTopology(std::istream& is, bool fromHalf = false);
350  void writeTopology(std::ostream& os, bool toHalf = false) const;
351 
355  void readBuffers(std::istream& is, bool fromHalf = false);
360  void readBuffers(std::istream& is, const CoordBBox& bbox, bool fromHalf = false);
364  void writeBuffers(std::ostream& os, bool toHalf = false) const;
365 
366  size_t streamingSize(bool toHalf = false) const;
367 
368  //
369  // Accessor methods
370  //
372  const ValueType& getValue(const Coord& xyz) const;
374  const ValueType& getValue(Index offset) const;
375 
379  bool probeValue(const Coord& xyz, ValueType& val) const;
383  bool probeValue(Index offset, ValueType& val) const;
384 
386  static Index getValueLevel(const Coord&) { return LEVEL; }
387 
389  void setActiveState(const Coord& xyz, bool on);
391  void setActiveState(Index offset, bool on) { assert(offset<SIZE); mValueMask.set(offset, on); }
392 
394  void setValueOnly(const Coord& xyz, const ValueType& val);
396  void setValueOnly(Index offset, const ValueType& val);
397 
399  void setValueOff(const Coord& xyz) { mValueMask.setOff(LeafNode::coordToOffset(xyz)); }
401  void setValueOff(Index offset) { assert(offset < SIZE); mValueMask.setOff(offset); }
402 
404  void setValueOff(const Coord& xyz, const ValueType& val);
406  void setValueOff(Index offset, const ValueType& val);
407 
409  void setValueOn(const Coord& xyz) { mValueMask.setOn(LeafNode::coordToOffset(xyz)); }
411  void setValueOn(Index offset) { assert(offset < SIZE); mValueMask.setOn(offset); }
413  void setValueOn(const Coord& xyz, const ValueType& val) {
414  this->setValueOn(LeafNode::coordToOffset(xyz), val);
415  }
417  void setValue(const Coord& xyz, const ValueType& val) { this->setValueOn(xyz, val); }
419  void setValueOn(Index offset, const ValueType& val) {
420  mBuffer.setValue(offset, val);
421  mValueMask.setOn(offset);
422  }
423 
426  template<typename ModifyOp>
427  void modifyValue(Index offset, const ModifyOp& op)
428  {
429  mBuffer.loadValues();
430  if (!mBuffer.empty()) {
431  // in-place modify value
432  ValueType& val = const_cast<ValueType&>(mBuffer[offset]);
433  op(val);
434  mValueMask.setOn(offset);
435  }
436  }
437 
440  template<typename ModifyOp>
441  void modifyValue(const Coord& xyz, const ModifyOp& op)
442  {
443  this->modifyValue(this->coordToOffset(xyz), op);
444  }
445 
447  template<typename ModifyOp>
448  void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
449  {
450  mBuffer.loadValues();
451  if (!mBuffer.empty()) {
452  const Index offset = this->coordToOffset(xyz);
453  bool state = mValueMask.isOn(offset);
454  // in-place modify value
455  ValueType& val = const_cast<ValueType&>(mBuffer[offset]);
456  op(val, state);
457  mValueMask.set(offset, state);
458  }
459  }
460 
462  void setValuesOn() { mValueMask.setOn(); }
464  void setValuesOff() { mValueMask.setOff(); }
465 
467  bool isValueOn(const Coord& xyz) const {return this->isValueOn(LeafNode::coordToOffset(xyz));}
469  bool isValueOn(Index offset) const { return mValueMask.isOn(offset); }
470 
472  static bool hasActiveTiles() { return false; }
473 
475  void clip(const CoordBBox&, const ValueType& background);
476 
478  void fill(const CoordBBox& bbox, const ValueType&, bool active = true);
480  void denseFill(const CoordBBox& bbox, const ValueType& value, bool active = true)
481  {
482  this->fill(bbox, value, active);
483  }
484 
486  void fill(const ValueType& value);
488  void fill(const ValueType& value, bool active);
489 
501  template<typename DenseT>
502  void copyToDense(const CoordBBox& bbox, DenseT& dense) const;
503 
520  template<typename DenseT>
521  void copyFromDense(const CoordBBox& bbox, const DenseT& dense,
522  const ValueType& background, const ValueType& tolerance);
523 
526  template<typename AccessorT>
527  const ValueType& getValueAndCache(const Coord& xyz, AccessorT&) const
528  {
529  return this->getValue(xyz);
530  }
531 
534  template<typename AccessorT>
535  bool isValueOnAndCache(const Coord& xyz, AccessorT&) const { return this->isValueOn(xyz); }
536 
539  template<typename AccessorT>
540  void setValueAndCache(const Coord& xyz, const ValueType& val, AccessorT&)
541  {
542  this->setValueOn(xyz, val);
543  }
544 
548  template<typename AccessorT>
549  void setValueOnlyAndCache(const Coord& xyz, const ValueType& val, AccessorT&)
550  {
551  this->setValueOnly(xyz, val);
552  }
553 
557  template<typename ModifyOp, typename AccessorT>
558  void modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&)
559  {
560  this->modifyValue(xyz, op);
561  }
562 
565  template<typename ModifyOp, typename AccessorT>
566  void modifyValueAndActiveStateAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&)
567  {
568  this->modifyValueAndActiveState(xyz, op);
569  }
570 
573  template<typename AccessorT>
574  void setValueOffAndCache(const Coord& xyz, const ValueType& value, AccessorT&)
575  {
576  this->setValueOff(xyz, value);
577  }
578 
582  template<typename AccessorT>
583  void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&)
584  {
585  this->setActiveState(xyz, on);
586  }
587 
591  template<typename AccessorT>
592  bool probeValueAndCache(const Coord& xyz, ValueType& val, AccessorT&) const
593  {
594  return this->probeValue(xyz, val);
595  }
596 
600  template<typename AccessorT>
601  const ValueType& getValue(const Coord& xyz, bool& state, int& level, AccessorT&) const
602  {
603  const Index offset = this->coordToOffset(xyz);
604  state = mValueMask.isOn(offset);
605  level = LEVEL;
606  return mBuffer[offset];
607  }
608 
611  template<typename AccessorT>
612  static Index getValueLevelAndCache(const Coord&, AccessorT&) { return LEVEL; }
613 
617  const ValueType& getFirstValue() const { return mBuffer[0]; }
619  const ValueType& getLastValue() const { return mBuffer[SIZE - 1]; }
620 
623  void resetBackground(const ValueType& oldBackground, const ValueType& newBackground);
624 
625  void negate();
626 
629  void voxelizeActiveTiles(bool = true) {}
630 
631  template<MergePolicy Policy> void merge(const LeafNode&);
632  template<MergePolicy Policy> void merge(const ValueType& tileValue, bool tileActive);
633  template<MergePolicy Policy>
634  void merge(const LeafNode& other, const ValueType& /*bg*/, const ValueType& /*otherBG*/);
635 
642  template<typename OtherType>
643  void topologyUnion(const LeafNode<OtherType, Log2Dim>& other);
644 
656  template<typename OtherType>
657  void topologyIntersection(const LeafNode<OtherType, Log2Dim>& other, const ValueType&);
658 
670  template<typename OtherType>
671  void topologyDifference(const LeafNode<OtherType, Log2Dim>& other, const ValueType&);
672 
673  template<typename CombineOp>
674  void combine(const LeafNode& other, CombineOp& op);
675  template<typename CombineOp>
676  void combine(const ValueType& value, bool valueIsActive, CombineOp& op);
677 
678  template<typename CombineOp, typename OtherType /*= ValueType*/>
679  void combine2(const LeafNode& other, const OtherType&, bool valueIsActive, CombineOp&);
680  template<typename CombineOp, typename OtherNodeT /*= LeafNode*/>
681  void combine2(const ValueType&, const OtherNodeT& other, bool valueIsActive, CombineOp&);
682  template<typename CombineOp, typename OtherNodeT /*= LeafNode*/>
683  void combine2(const LeafNode& b0, const OtherNodeT& b1, CombineOp&);
684 
690  template<typename BBoxOp> void visitActiveBBox(BBoxOp&) const;
691 
692  template<typename VisitorOp> void visit(VisitorOp&);
693  template<typename VisitorOp> void visit(VisitorOp&) const;
694 
695  template<typename OtherLeafNodeType, typename VisitorOp>
696  void visit2Node(OtherLeafNodeType& other, VisitorOp&);
697  template<typename OtherLeafNodeType, typename VisitorOp>
698  void visit2Node(OtherLeafNodeType& other, VisitorOp&) const;
699  template<typename IterT, typename VisitorOp>
700  void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false);
701  template<typename IterT, typename VisitorOp>
702  void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false) const;
703 
705  void prune(const ValueType& /*tolerance*/ = zeroVal<ValueType>()) {}
707  void addLeaf(LeafNode*) {}
708  template<typename AccessorT>
709  void addLeafAndCache(LeafNode*, AccessorT&) {}
710  template<typename NodeT>
711  NodeT* stealNode(const Coord&, const ValueType&, bool) { return nullptr; }
712  template<typename NodeT>
713  NodeT* probeNode(const Coord&) { return nullptr; }
714  template<typename NodeT>
715  const NodeT* probeConstNode(const Coord&) const { return nullptr; }
716  template<typename ArrayT> void getNodes(ArrayT&) const {}
717  template<typename ArrayT> void stealNodes(ArrayT&, const ValueType&, bool) {}
719 
720  void addTile(Index level, const Coord&, const ValueType&, bool);
721  void addTile(Index offset, const ValueType&, bool);
722  template<typename AccessorT>
723  void addTileAndCache(Index, const Coord&, const ValueType&, bool, AccessorT&);
724 
726  LeafNode* touchLeaf(const Coord&) { return this; }
728  template<typename AccessorT>
729  LeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; }
730  template<typename NodeT, typename AccessorT>
731  NodeT* probeNodeAndCache(const Coord&, AccessorT&)
732  {
734  if (!(std::is_same<NodeT, LeafNode>::value)) return nullptr;
735  return reinterpret_cast<NodeT*>(this);
737  }
738  LeafNode* probeLeaf(const Coord&) { return this; }
739  template<typename AccessorT>
740  LeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; }
742 
743  const LeafNode* probeConstLeaf(const Coord&) const { return this; }
745  template<typename AccessorT>
746  const LeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const { return this; }
747  template<typename AccessorT>
748  const LeafNode* probeLeafAndCache(const Coord&, AccessorT&) const { return this; }
749  const LeafNode* probeLeaf(const Coord&) const { return this; }
750  template<typename NodeT, typename AccessorT>
751  const NodeT* probeConstNodeAndCache(const Coord&, AccessorT&) const
752  {
754  if (!(std::is_same<NodeT, LeafNode>::value)) return nullptr;
755  return reinterpret_cast<const NodeT*>(this);
757  }
759 
769  bool isConstant(ValueType& firstValue, bool& state,
770  const ValueType& tolerance = zeroVal<ValueType>()) const;
771 
783  bool isConstant(ValueType& minValue, ValueType& maxValue,
784  bool& state, const ValueType& tolerance = zeroVal<ValueType>()) const;
785 
786 
801  ValueType medianAll(ValueType *tmp = nullptr) const;
802 
817  Index medianOn(ValueType &value, ValueType *tmp = nullptr) const;
818 
833  Index medianOff(ValueType &value, ValueType *tmp = nullptr) const;
834 
836  bool isInactive() const { return mValueMask.isOff(); }
837 
838 protected:
839  friend class ::TestLeaf;
840  template<typename> friend class ::TestLeafIO;
841 
842  // During topology-only construction, access is needed
843  // to protected/private members of other template instances.
844  template<typename, Index> friend class LeafNode;
845 
852 
853  // Allow iterators to call mask accessor methods (see below).
858 
859  // Mask accessors
860 public:
861  bool isValueMaskOn(Index n) const { return mValueMask.isOn(n); }
862  bool isValueMaskOn() const { return mValueMask.isOn(); }
863  bool isValueMaskOff(Index n) const { return mValueMask.isOff(n); }
864  bool isValueMaskOff() const { return mValueMask.isOff(); }
865  const NodeMaskType& getValueMask() const { return mValueMask; }
866  NodeMaskType& getValueMask() { return mValueMask; }
867  const NodeMaskType& valueMask() const { return mValueMask; }
868  void setValueMask(const NodeMaskType& mask) { mValueMask = mask; }
869  bool isChildMaskOn(Index) const { return false; } // leaf nodes have no children
870  bool isChildMaskOff(Index) const { return true; }
871  bool isChildMaskOff() const { return true; }
872 protected:
873  void setValueMask(Index n, bool on) { mValueMask.set(n, on); }
874  void setValueMaskOn(Index n) { mValueMask.setOn(n); }
875  void setValueMaskOff(Index n) { mValueMask.setOff(n); }
876 
877  inline void skipCompressedValues(bool seekable, std::istream&, bool fromHalf);
878 
880  static void evalNodeOrigin(Coord& xyz) { xyz &= ~(DIM - 1); }
881 
882  template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
883  static inline void doVisit(NodeT&, VisitorOp&);
884 
885  template<typename NodeT, typename OtherNodeT, typename VisitorOp,
886  typename ChildAllIterT, typename OtherChildAllIterT>
887  static inline void doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp&);
888 
889  template<typename NodeT, typename VisitorOp,
890  typename ChildAllIterT, typename OtherChildAllIterT>
891  static inline void doVisit2(NodeT& self, OtherChildAllIterT&, VisitorOp&, bool otherIsLHS);
892 
893 private:
895  Buffer mBuffer;
897  NodeMaskType mValueMask;
899  Coord mOrigin;
900 }; // end of LeafNode class
901 
902 
904 
905 
907 template<Index Dim1, typename NodeT2>
910 struct SameLeafConfig { static const bool value = false; };
911 
912 template<Index Dim1, typename T2>
913 struct SameLeafConfig<Dim1, LeafNode<T2, Dim1> > { static const bool value = true; };
915 
916 
918 
919 
920 template<typename T, Index Log2Dim>
921 inline
923  mValueMask(),//default is off!
924  mOrigin(0, 0, 0)
925 {
926 }
927 
928 
929 template<typename T, Index Log2Dim>
930 inline
931 LeafNode<T, Log2Dim>::LeafNode(const Coord& xyz, const ValueType& val, bool active):
932  mBuffer(val),
933  mValueMask(active),
934  mOrigin(xyz & (~(DIM - 1)))
935 {
936 }
937 
938 
939 template<typename T, Index Log2Dim>
940 inline
941 LeafNode<T, Log2Dim>::LeafNode(PartialCreate, const Coord& xyz, const ValueType& val, bool active):
942  mBuffer(PartialCreate(), val),
943  mValueMask(active),
944  mOrigin(xyz & (~(DIM - 1)))
945 {
946 }
947 
948 
949 template<typename T, Index Log2Dim>
950 inline
952  mBuffer(other.mBuffer),
953  mValueMask(other.valueMask()),
954  mOrigin(other.mOrigin)
955 {
956 }
957 
958 
959 // Copy-construct from a leaf node with the same configuration but a different ValueType.
960 template<typename T, Index Log2Dim>
961 template<typename OtherValueType>
962 inline
964  mValueMask(other.valueMask()),
965  mOrigin(other.mOrigin)
966 {
967  struct Local {
969  static inline ValueType convertValue(const OtherValueType& val) { return ValueType(val); }
970  };
971 
972  for (Index i = 0; i < SIZE; ++i) {
973  mBuffer[i] = Local::convertValue(other.mBuffer[i]);
974  }
975 }
976 
977 
978 template<typename T, Index Log2Dim>
979 template<typename OtherValueType>
980 inline
982  const ValueType& background, TopologyCopy):
983  mBuffer(background),
984  mValueMask(other.valueMask()),
985  mOrigin(other.mOrigin)
986 {
987 }
988 
989 
990 template<typename T, Index Log2Dim>
991 template<typename OtherValueType>
992 inline
994  const ValueType& offValue, const ValueType& onValue, TopologyCopy):
995  mValueMask(other.valueMask()),
996  mOrigin(other.mOrigin)
997 {
998  for (Index i = 0; i < SIZE; ++i) {
999  mBuffer[i] = (mValueMask.isOn(i) ? onValue : offValue);
1000  }
1001 }
1002 
1003 
1004 template<typename T, Index Log2Dim>
1005 inline
1007 {
1008 }
1009 
1010 
1011 template<typename T, Index Log2Dim>
1012 inline std::string
1014 {
1015  std::ostringstream ostr;
1016  ostr << "LeafNode @" << mOrigin << ": " << mBuffer;
1017  return ostr.str();
1018 }
1019 
1020 
1022 
1023 
1024 template<typename T, Index Log2Dim>
1025 inline Index
1027 {
1028  assert ((xyz[0] & (DIM-1u)) < DIM && (xyz[1] & (DIM-1u)) < DIM && (xyz[2] & (DIM-1u)) < DIM);
1029  return ((xyz[0] & (DIM-1u)) << 2*Log2Dim)
1030  + ((xyz[1] & (DIM-1u)) << Log2Dim)
1031  + (xyz[2] & (DIM-1u));
1032 }
1033 
1034 template<typename T, Index Log2Dim>
1035 inline Coord
1037 {
1038  assert(n<(1<< 3*Log2Dim));
1039  Coord xyz;
1040  xyz.setX(n >> 2*Log2Dim);
1041  n &= ((1<<2*Log2Dim)-1);
1042  xyz.setY(n >> Log2Dim);
1043  xyz.setZ(n & ((1<<Log2Dim)-1));
1044  return xyz;
1045 }
1046 
1047 
1048 template<typename T, Index Log2Dim>
1049 inline Coord
1051 {
1052  return (this->offsetToLocalCoord(n) + this->origin());
1053 }
1054 
1055 
1057 
1058 
1059 template<typename ValueT, Index Log2Dim>
1060 inline const ValueT&
1062 {
1063  return this->getValue(LeafNode::coordToOffset(xyz));
1064 }
1065 
1066 template<typename ValueT, Index Log2Dim>
1067 inline const ValueT&
1069 {
1070  assert(offset < SIZE);
1071  return mBuffer[offset];
1072 }
1073 
1074 
1075 template<typename T, Index Log2Dim>
1076 inline bool
1077 LeafNode<T, Log2Dim>::probeValue(const Coord& xyz, ValueType& val) const
1078 {
1079  return this->probeValue(LeafNode::coordToOffset(xyz), val);
1080 }
1081 
1082 template<typename T, Index Log2Dim>
1083 inline bool
1085 {
1086  assert(offset < SIZE);
1087  val = mBuffer[offset];
1088  return mValueMask.isOn(offset);
1089 }
1090 
1091 
1092 template<typename T, Index Log2Dim>
1093 inline void
1094 LeafNode<T, Log2Dim>::setValueOff(const Coord& xyz, const ValueType& val)
1095 {
1096  this->setValueOff(LeafNode::coordToOffset(xyz), val);
1097 }
1098 
1099 template<typename T, Index Log2Dim>
1100 inline void
1102 {
1103  assert(offset < SIZE);
1104  mBuffer.setValue(offset, val);
1105  mValueMask.setOff(offset);
1106 }
1107 
1108 
1109 template<typename T, Index Log2Dim>
1110 inline void
1111 LeafNode<T, Log2Dim>::setActiveState(const Coord& xyz, bool on)
1112 {
1113  mValueMask.set(this->coordToOffset(xyz), on);
1114 }
1115 
1116 
1117 template<typename T, Index Log2Dim>
1118 inline void
1119 LeafNode<T, Log2Dim>::setValueOnly(const Coord& xyz, const ValueType& val)
1120 {
1121  this->setValueOnly(LeafNode::coordToOffset(xyz), val);
1122 }
1123 
1124 template<typename T, Index Log2Dim>
1125 inline void
1127 {
1128  assert(offset<SIZE); mBuffer.setValue(offset, val);
1129 }
1130 
1131 
1133 
1134 
1135 template<typename T, Index Log2Dim>
1136 inline void
1137 LeafNode<T, Log2Dim>::clip(const CoordBBox& clipBBox, const T& background)
1138 {
1139  CoordBBox nodeBBox = this->getNodeBoundingBox();
1140  if (!clipBBox.hasOverlap(nodeBBox)) {
1141  // This node lies completely outside the clipping region. Fill it with the background.
1142  this->fill(background, /*active=*/false);
1143  } else if (clipBBox.isInside(nodeBBox)) {
1144  // This node lies completely inside the clipping region. Leave it intact.
1145  return;
1146  }
1147 
1148  // This node isn't completely contained inside the clipping region.
1149  // Set any voxels that lie outside the region to the background value.
1150 
1151  // Construct a boolean mask that is on inside the clipping region and off outside it.
1152  NodeMaskType mask;
1153  nodeBBox.intersect(clipBBox);
1154  Coord xyz;
1155  int &x = xyz.x(), &y = xyz.y(), &z = xyz.z();
1156  for (x = nodeBBox.min().x(); x <= nodeBBox.max().x(); ++x) {
1157  for (y = nodeBBox.min().y(); y <= nodeBBox.max().y(); ++y) {
1158  for (z = nodeBBox.min().z(); z <= nodeBBox.max().z(); ++z) {
1159  mask.setOn(static_cast<Index32>(this->coordToOffset(xyz)));
1160  }
1161  }
1162  }
1163 
1164  // Set voxels that lie in the inactive region of the mask (i.e., outside
1165  // the clipping region) to the background value.
1166  for (MaskOffIterator maskIter = mask.beginOff(); maskIter; ++maskIter) {
1167  this->setValueOff(maskIter.pos(), background);
1168  }
1169 }
1170 
1171 
1173 
1174 
1175 template<typename T, Index Log2Dim>
1176 inline void
1177 LeafNode<T, Log2Dim>::fill(const CoordBBox& bbox, const ValueType& value, bool active)
1178 {
1179  if (!this->allocate()) return;
1180 
1181  auto clippedBBox = this->getNodeBoundingBox();
1182  clippedBBox.intersect(bbox);
1183  if (!clippedBBox) return;
1184 
1185  for (Int32 x = clippedBBox.min().x(); x <= clippedBBox.max().x(); ++x) {
1186  const Index offsetX = (x & (DIM-1u)) << 2*Log2Dim;
1187  for (Int32 y = clippedBBox.min().y(); y <= clippedBBox.max().y(); ++y) {
1188  const Index offsetXY = offsetX + ((y & (DIM-1u)) << Log2Dim);
1189  for (Int32 z = clippedBBox.min().z(); z <= clippedBBox.max().z(); ++z) {
1190  const Index offset = offsetXY + (z & (DIM-1u));
1191  mBuffer[offset] = value;
1192  mValueMask.set(offset, active);
1193  }
1194  }
1195  }
1196 }
1197 
1198 template<typename T, Index Log2Dim>
1199 inline void
1201 {
1202  mBuffer.fill(value);
1203 }
1204 
1205 template<typename T, Index Log2Dim>
1206 inline void
1207 LeafNode<T, Log2Dim>::fill(const ValueType& value, bool active)
1208 {
1209  mBuffer.fill(value);
1210  mValueMask.set(active);
1211 }
1212 
1213 
1215 
1216 
1217 template<typename T, Index Log2Dim>
1218 template<typename DenseT>
1219 inline void
1220 LeafNode<T, Log2Dim>::copyToDense(const CoordBBox& bbox, DenseT& dense) const
1221 {
1222  mBuffer.loadValues();
1223 
1224  using DenseValueType = typename DenseT::ValueType;
1225 
1226  const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride();
1227  const Coord& min = dense.bbox().min();
1228  DenseValueType* t0 = dense.data() + zStride * (bbox.min()[2] - min[2]); // target array
1229  const T* s0 = &mBuffer[bbox.min()[2] & (DIM-1u)]; // source array
1230  for (Int32 x = bbox.min()[0], ex = bbox.max()[0] + 1; x < ex; ++x) {
1231  DenseValueType* t1 = t0 + xStride * (x - min[0]);
1232  const T* s1 = s0 + ((x & (DIM-1u)) << 2*Log2Dim);
1233  for (Int32 y = bbox.min()[1], ey = bbox.max()[1] + 1; y < ey; ++y) {
1234  DenseValueType* t2 = t1 + yStride * (y - min[1]);
1235  const T* s2 = s1 + ((y & (DIM-1u)) << Log2Dim);
1236  for (Int32 z = bbox.min()[2], ez = bbox.max()[2] + 1; z < ez; ++z, t2 += zStride) {
1237  *t2 = DenseValueType(*s2++);
1238  }
1239  }
1240  }
1241 }
1242 
1243 
1244 template<typename T, Index Log2Dim>
1245 template<typename DenseT>
1246 inline void
1247 LeafNode<T, Log2Dim>::copyFromDense(const CoordBBox& bbox, const DenseT& dense,
1248  const ValueType& background, const ValueType& tolerance)
1249 {
1250  if (!this->allocate()) return;
1251 
1252  using DenseValueType = typename DenseT::ValueType;
1253 
1254  const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride();
1255  const Coord& min = dense.bbox().min();
1256 
1257  const DenseValueType* s0 = dense.data() + zStride * (bbox.min()[2] - min[2]); // source
1258  const Int32 n0 = bbox.min()[2] & (DIM-1u);
1259  for (Int32 x = bbox.min()[0], ex = bbox.max()[0]+1; x < ex; ++x) {
1260  const DenseValueType* s1 = s0 + xStride * (x - min[0]);
1261  const Int32 n1 = n0 + ((x & (DIM-1u)) << 2*LOG2DIM);
1262  for (Int32 y = bbox.min()[1], ey = bbox.max()[1]+1; y < ey; ++y) {
1263  const DenseValueType* s2 = s1 + yStride * (y - min[1]);
1264  Int32 n2 = n1 + ((y & (DIM-1u)) << LOG2DIM);
1265  for (Int32 z = bbox.min()[2], ez = bbox.max()[2]+1; z < ez; ++z, ++n2, s2 += zStride) {
1266  if (math::isApproxEqual(background, ValueType(*s2), tolerance)) {
1267  mValueMask.setOff(n2);
1268  mBuffer[n2] = background;
1269  } else {
1270  mValueMask.setOn(n2);
1271  mBuffer[n2] = ValueType(*s2);
1272  }
1273  }
1274  }
1275  }
1276 }
1277 
1278 
1280 
1281 
1282 template<typename T, Index Log2Dim>
1283 inline void
1284 LeafNode<T, Log2Dim>::readTopology(std::istream& is, bool /*fromHalf*/)
1285 {
1286  mValueMask.load(is);
1287 }
1288 
1289 
1290 template<typename T, Index Log2Dim>
1291 inline void
1292 LeafNode<T, Log2Dim>::writeTopology(std::ostream& os, bool /*toHalf*/) const
1293 {
1294  mValueMask.save(os);
1295 }
1296 
1297 
1299 
1300 
1301 
1302 template<typename T, Index Log2Dim>
1303 inline void
1304 LeafNode<T,Log2Dim>::skipCompressedValues(bool seekable, std::istream& is, bool fromHalf)
1305 {
1306  if (seekable) {
1307  // Seek over voxel values.
1308  io::readCompressedValues<ValueType, NodeMaskType>(
1309  is, nullptr, SIZE, mValueMask, fromHalf);
1310  } else {
1311  // Read and discard voxel values.
1312  Buffer temp;
1313  io::readCompressedValues(is, temp.mData, SIZE, mValueMask, fromHalf);
1314  }
1315 }
1316 
1317 
1318 template<typename T, Index Log2Dim>
1319 inline void
1320 LeafNode<T,Log2Dim>::readBuffers(std::istream& is, bool fromHalf)
1321 {
1322  this->readBuffers(is, CoordBBox::inf(), fromHalf);
1323 }
1324 
1325 
1326 template<typename T, Index Log2Dim>
1327 inline void
1328 LeafNode<T,Log2Dim>::readBuffers(std::istream& is, const CoordBBox& clipBBox, bool fromHalf)
1329 {
1331  const bool seekable = meta && meta->seekable();
1332 
1333  std::streamoff maskpos = is.tellg();
1334 
1335  if (seekable) {
1336  // Seek over the value mask.
1337  mValueMask.seek(is);
1338  } else {
1339  // Read in the value mask.
1340  mValueMask.load(is);
1341  }
1342 
1343  int8_t numBuffers = 1;
1345  // Read in the origin.
1346  is.read(reinterpret_cast<char*>(&mOrigin), sizeof(Coord::ValueType) * 3);
1347 
1348  // Read in the number of buffers, which should now always be one.
1349  is.read(reinterpret_cast<char*>(&numBuffers), sizeof(int8_t));
1350  }
1351 
1352  CoordBBox nodeBBox = this->getNodeBoundingBox();
1353  if (!clipBBox.hasOverlap(nodeBBox)) {
1354  // This node lies completely outside the clipping region.
1355  skipCompressedValues(seekable, is, fromHalf);
1356  mValueMask.setOff();
1357  mBuffer.setOutOfCore(false);
1358  } else {
1359  // If this node lies completely inside the clipping region and it is being read
1360  // from a memory-mapped file, delay loading of its buffer until the buffer
1361  // is actually accessed. (If this node requires clipping, its buffer
1362  // must be accessed and therefore must be loaded.)
1363  io::MappedFile::Ptr mappedFile = io::getMappedFilePtr(is);
1364  const bool delayLoad = ((mappedFile.get() != nullptr) && clipBBox.isInside(nodeBBox));
1365 
1366  if (delayLoad) {
1367  mBuffer.setOutOfCore(true);
1368  mBuffer.mFileInfo = new typename Buffer::FileInfo;
1369  mBuffer.mFileInfo->meta = meta;
1370  mBuffer.mFileInfo->bufpos = is.tellg();
1371  mBuffer.mFileInfo->mapping = mappedFile;
1372  // Save the offset to the value mask, because the in-memory copy
1373  // might change before the value buffer gets read.
1374  mBuffer.mFileInfo->maskpos = maskpos;
1375  // Skip over voxel values.
1376  skipCompressedValues(seekable, is, fromHalf);
1377  } else {
1378  mBuffer.allocate();
1379  io::readCompressedValues(is, mBuffer.mData, SIZE, mValueMask, fromHalf);
1380  mBuffer.setOutOfCore(false);
1381 
1382  // Get this tree's background value.
1383  T background = zeroVal<T>();
1384  if (const void* bgPtr = io::getGridBackgroundValuePtr(is)) {
1385  background = *static_cast<const T*>(bgPtr);
1386  }
1387  this->clip(clipBBox, background);
1388  }
1389  }
1390 
1391  if (numBuffers > 1) {
1392  // Read in and discard auxiliary buffers that were created with earlier
1393  // versions of the library. (Auxiliary buffers are not mask compressed.)
1394  const bool zipped = io::getDataCompression(is) & io::COMPRESS_ZIP;
1395  Buffer temp;
1396  for (int i = 1; i < numBuffers; ++i) {
1397  if (fromHalf) {
1398  io::HalfReader<io::RealToHalf<T>::isReal, T>::read(is, temp.mData, SIZE, zipped);
1399  } else {
1400  io::readData<T>(is, temp.mData, SIZE, zipped);
1401  }
1402  }
1403  }
1404 
1405  // increment the leaf number
1406  if (meta) meta->setLeaf(meta->leaf() + 1);
1407 }
1408 
1409 
1410 template<typename T, Index Log2Dim>
1411 inline void
1412 LeafNode<T, Log2Dim>::writeBuffers(std::ostream& os, bool toHalf) const
1413 {
1414  // Write out the value mask.
1415  mValueMask.save(os);
1416 
1417  mBuffer.loadValues();
1418 
1419  io::writeCompressedValues(os, mBuffer.mData, SIZE,
1420  mValueMask, /*childMask=*/NodeMaskType(), toHalf);
1421 }
1422 
1423 
1425 
1426 
1427 template<typename T, Index Log2Dim>
1428 inline bool
1430 {
1431  return mOrigin == other.mOrigin &&
1432  mValueMask == other.valueMask() &&
1433  mBuffer == other.mBuffer;
1434 }
1435 
1436 
1437 template<typename T, Index Log2Dim>
1438 inline Index64
1440 {
1441  // Use sizeof(*this) to capture alignment-related padding
1442  // (but note that sizeof(*this) includes sizeof(mBuffer)).
1443  return sizeof(*this) + mBuffer.memUsage() - sizeof(mBuffer);
1444 }
1445 
1446 
1447 template<typename T, Index Log2Dim>
1448 inline void
1449 LeafNode<T, Log2Dim>::evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels) const
1450 {
1451  CoordBBox this_bbox = this->getNodeBoundingBox();
1452  if (bbox.isInside(this_bbox)) return;//this LeafNode is already enclosed in the bbox
1453  if (ValueOnCIter iter = this->cbeginValueOn()) {//any active values?
1454  if (visitVoxels) {//use voxel granularity?
1455  this_bbox.reset();
1456  for(; iter; ++iter) this_bbox.expand(this->offsetToLocalCoord(iter.pos()));
1457  this_bbox.translate(this->origin());
1458  }
1459  bbox.expand(this_bbox);
1460  }
1461 }
1462 
1463 
1464 template<typename T, Index Log2Dim>
1465 template<typename OtherType, Index OtherLog2Dim>
1466 inline bool
1468 {
1469  assert(other);
1470  return (Log2Dim == OtherLog2Dim && mValueMask == other->getValueMask());
1471 }
1472 
1473 template<typename T, Index Log2Dim>
1474 inline bool
1476  bool& state,
1477  const ValueType& tolerance) const
1478 {
1479  if (!mValueMask.isConstant(state)) return false;// early termination
1480  firstValue = mBuffer[0];
1481  for (Index i = 1; i < SIZE; ++i) {
1482  if ( !math::isApproxEqual(mBuffer[i], firstValue, tolerance) ) return false;// early termination
1483  }
1484  return true;
1485 }
1486 
1487 template<typename T, Index Log2Dim>
1488 inline bool
1490  ValueType& maxValue,
1491  bool& state,
1492  const ValueType& tolerance) const
1493 {
1494  if (!mValueMask.isConstant(state)) return false;// early termination
1495  minValue = maxValue = mBuffer[0];
1496  for (Index i = 1; i < SIZE; ++i) {
1497  const T& v = mBuffer[i];
1498  if (v < minValue) {
1499  if ((maxValue - v) > tolerance) return false;// early termination
1500  minValue = v;
1501  } else if (v > maxValue) {
1502  if ((v - minValue) > tolerance) return false;// early termination
1503  maxValue = v;
1504  }
1505  }
1506  return true;
1507 }
1508 
1509 template<typename T, Index Log2Dim>
1510 inline T
1512 {
1513  std::unique_ptr<T[]> data(nullptr);
1514  if (tmp == nullptr) {//allocate temporary storage
1515  data.reset(new T[NUM_VALUES]);
1516  tmp = data.get();
1517  }
1518  if (tmp != mBuffer.data()) {
1519  const T* src = mBuffer.data();
1520  for (T* dst = tmp; dst-tmp < NUM_VALUES;) *dst++ = *src++;
1521  }
1522  static const size_t midpoint = (NUM_VALUES - 1) >> 1;
1523  std::nth_element(tmp, tmp + midpoint, tmp + NUM_VALUES);
1524  return tmp[midpoint];
1525 }
1526 
1527 template<typename T, Index Log2Dim>
1528 inline Index
1529 LeafNode<T, Log2Dim>::medianOn(T &value, T *tmp) const
1530 {
1531  const Index count = mValueMask.countOn();
1532  if (count == NUM_VALUES) {//special case: all voxels are active
1533  value = this->medianAll(tmp);
1534  return NUM_VALUES;
1535  } else if (count == 0) {
1536  return 0;
1537  }
1538  std::unique_ptr<T[]> data(nullptr);
1539  if (tmp == nullptr) {//allocate temporary storage
1540  data.reset(new T[count]);// 0 < count < NUM_VALUES
1541  tmp = data.get();
1542  }
1543  for (auto iter=this->cbeginValueOn(); iter; ++iter) *tmp++ = *iter;
1544  T *begin = tmp - count;
1545  const size_t midpoint = (count - 1) >> 1;
1546  std::nth_element(begin, begin + midpoint, tmp);
1547  value = begin[midpoint];
1548  return count;
1549 }
1550 
1551 template<typename T, Index Log2Dim>
1552 inline Index
1553 LeafNode<T, Log2Dim>::medianOff(T &value, T *tmp) const
1554 {
1555  const Index count = mValueMask.countOff();
1556  if (count == NUM_VALUES) {//special case: all voxels are inactive
1557  value = this->medianAll(tmp);
1558  return NUM_VALUES;
1559  } else if (count == 0) {
1560  return 0;
1561  }
1562  std::unique_ptr<T[]> data(nullptr);
1563  if (tmp == nullptr) {//allocate temporary storage
1564  data.reset(new T[count]);// 0 < count < NUM_VALUES
1565  tmp = data.get();
1566  }
1567  for (auto iter=this->cbeginValueOff(); iter; ++iter) *tmp++ = *iter;
1568  T *begin = tmp - count;
1569  const size_t midpoint = (count - 1) >> 1;
1570  std::nth_element(begin, begin + midpoint, tmp);
1571  value = begin[midpoint];
1572  return count;
1573 }
1574 
1576 
1577 
1578 template<typename T, Index Log2Dim>
1579 inline void
1580 LeafNode<T, Log2Dim>::addTile(Index /*level*/, const Coord& xyz, const ValueType& val, bool active)
1581 {
1582  this->addTile(this->coordToOffset(xyz), val, active);
1583 }
1584 
1585 template<typename T, Index Log2Dim>
1586 inline void
1587 LeafNode<T, Log2Dim>::addTile(Index offset, const ValueType& val, bool active)
1588 {
1589  assert(offset < SIZE);
1590  setValueOnly(offset, val);
1591  setActiveState(offset, active);
1592 }
1593 
1594 template<typename T, Index Log2Dim>
1595 template<typename AccessorT>
1596 inline void
1598  const ValueType& val, bool active, AccessorT&)
1599 {
1600  this->addTile(level, xyz, val, active);
1601 }
1602 
1603 
1605 
1606 
1607 template<typename T, Index Log2Dim>
1608 inline void
1610  const ValueType& newBackground)
1611 {
1612  if (!this->allocate()) return;
1613 
1614  typename NodeMaskType::OffIterator iter;
1615  // For all inactive values...
1616  for (iter = this->mValueMask.beginOff(); iter; ++iter) {
1617  ValueType &inactiveValue = mBuffer[iter.pos()];
1618  if (math::isApproxEqual(inactiveValue, oldBackground)) {
1619  inactiveValue = newBackground;
1620  } else if (math::isApproxEqual(inactiveValue, math::negative(oldBackground))) {
1621  inactiveValue = math::negative(newBackground);
1622  }
1623  }
1624 }
1625 
1626 
1627 template<typename T, Index Log2Dim>
1628 template<MergePolicy Policy>
1629 inline void
1631 {
1632  if (!this->allocate()) return;
1633 
1635  if (Policy == MERGE_NODES) return;
1636  typename NodeMaskType::OnIterator iter = other.valueMask().beginOn();
1637  for (; iter; ++iter) {
1638  const Index n = iter.pos();
1639  if (mValueMask.isOff(n)) {
1640  mBuffer[n] = other.mBuffer[n];
1641  mValueMask.setOn(n);
1642  }
1643  }
1645 }
1646 
1647 template<typename T, Index Log2Dim>
1648 template<MergePolicy Policy>
1649 inline void
1651  const ValueType& /*bg*/, const ValueType& /*otherBG*/)
1652 {
1653  this->template merge<Policy>(other);
1654 }
1655 
1656 template<typename T, Index Log2Dim>
1657 template<MergePolicy Policy>
1658 inline void
1659 LeafNode<T, Log2Dim>::merge(const ValueType& tileValue, bool tileActive)
1660 {
1661  if (!this->allocate()) return;
1662 
1664  if (Policy != MERGE_ACTIVE_STATES_AND_NODES) return;
1665  if (!tileActive) return;
1666  // Replace all inactive values with the active tile value.
1667  for (typename NodeMaskType::OffIterator iter = mValueMask.beginOff(); iter; ++iter) {
1668  const Index n = iter.pos();
1669  mBuffer[n] = tileValue;
1670  mValueMask.setOn(n);
1671  }
1673 }
1674 
1675 
1676 template<typename T, Index Log2Dim>
1677 template<typename OtherType>
1678 inline void
1680 {
1681  mValueMask |= other.valueMask();
1682 }
1683 
1684 template<typename T, Index Log2Dim>
1685 template<typename OtherType>
1686 inline void
1688  const ValueType&)
1689 {
1690  mValueMask &= other.valueMask();
1691 }
1692 
1693 template<typename T, Index Log2Dim>
1694 template<typename OtherType>
1695 inline void
1697  const ValueType&)
1698 {
1699  mValueMask &= !other.valueMask();
1700 }
1701 
1702 template<typename T, Index Log2Dim>
1703 inline void
1705 {
1706  if (!this->allocate()) return;
1707 
1708  for (Index i = 0; i < SIZE; ++i) {
1709  mBuffer[i] = -mBuffer[i];
1710  }
1711 }
1712 
1713 
1715 
1716 
1717 template<typename T, Index Log2Dim>
1718 template<typename CombineOp>
1719 inline void
1720 LeafNode<T, Log2Dim>::combine(const LeafNode& other, CombineOp& op)
1721 {
1722  if (!this->allocate()) return;
1723 
1724  CombineArgs<T> args;
1725  for (Index i = 0; i < SIZE; ++i) {
1726  op(args.setARef(mBuffer[i])
1727  .setAIsActive(mValueMask.isOn(i))
1728  .setBRef(other.mBuffer[i])
1729  .setBIsActive(other.valueMask().isOn(i))
1730  .setResultRef(mBuffer[i]));
1731  mValueMask.set(i, args.resultIsActive());
1732  }
1733 }
1734 
1735 
1736 template<typename T, Index Log2Dim>
1737 template<typename CombineOp>
1738 inline void
1739 LeafNode<T, Log2Dim>::combine(const ValueType& value, bool valueIsActive, CombineOp& op)
1740 {
1741  if (!this->allocate()) return;
1742 
1743  CombineArgs<T> args;
1744  args.setBRef(value).setBIsActive(valueIsActive);
1745  for (Index i = 0; i < SIZE; ++i) {
1746  op(args.setARef(mBuffer[i])
1747  .setAIsActive(mValueMask.isOn(i))
1748  .setResultRef(mBuffer[i]));
1749  mValueMask.set(i, args.resultIsActive());
1750  }
1751 }
1752 
1753 
1755 
1756 
1757 template<typename T, Index Log2Dim>
1758 template<typename CombineOp, typename OtherType>
1759 inline void
1760 LeafNode<T, Log2Dim>::combine2(const LeafNode& other, const OtherType& value,
1761  bool valueIsActive, CombineOp& op)
1762 {
1763  if (!this->allocate()) return;
1764 
1766  args.setBRef(value).setBIsActive(valueIsActive);
1767  for (Index i = 0; i < SIZE; ++i) {
1768  op(args.setARef(other.mBuffer[i])
1769  .setAIsActive(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, typename OtherNodeT>
1778 inline void
1779 LeafNode<T, Log2Dim>::combine2(const ValueType& value, const OtherNodeT& other,
1780  bool valueIsActive, CombineOp& op)
1781 {
1782  if (!this->allocate()) return;
1783 
1785  args.setARef(value).setAIsActive(valueIsActive);
1786  for (Index i = 0; i < SIZE; ++i) {
1787  op(args.setBRef(other.mBuffer[i])
1788  .setBIsActive(other.valueMask().isOn(i))
1789  .setResultRef(mBuffer[i]));
1790  mValueMask.set(i, args.resultIsActive());
1791  }
1792 }
1793 
1794 
1795 template<typename T, Index Log2Dim>
1796 template<typename CombineOp, typename OtherNodeT>
1797 inline void
1798 LeafNode<T, Log2Dim>::combine2(const LeafNode& b0, const OtherNodeT& b1, CombineOp& op)
1799 {
1800  if (!this->allocate()) return;
1801 
1803  for (Index i = 0; i < SIZE; ++i) {
1804  mValueMask.set(i, b0.valueMask().isOn(i) || b1.valueMask().isOn(i));
1805  op(args.setARef(b0.mBuffer[i])
1806  .setAIsActive(b0.valueMask().isOn(i))
1807  .setBRef(b1.mBuffer[i])
1808  .setBIsActive(b1.valueMask().isOn(i))
1809  .setResultRef(mBuffer[i]));
1810  mValueMask.set(i, args.resultIsActive());
1811  }
1812 }
1813 
1814 
1816 
1817 
1818 template<typename T, Index Log2Dim>
1819 template<typename BBoxOp>
1820 inline void
1822 {
1823  if (op.template descent<LEVEL>()) {
1824  for (ValueOnCIter i=this->cbeginValueOn(); i; ++i) {
1825 #ifdef _MSC_VER
1826  op.operator()<LEVEL>(CoordBBox::createCube(i.getCoord(), 1));
1827 #else
1828  op.template operator()<LEVEL>(CoordBBox::createCube(i.getCoord(), 1));
1829 #endif
1830  }
1831  } else {
1832 #ifdef _MSC_VER
1833  op.operator()<LEVEL>(this->getNodeBoundingBox());
1834 #else
1835  op.template operator()<LEVEL>(this->getNodeBoundingBox());
1836 #endif
1837  }
1838 }
1839 
1840 
1841 template<typename T, Index Log2Dim>
1842 template<typename VisitorOp>
1843 inline void
1845 {
1846  doVisit<LeafNode, VisitorOp, ChildAllIter>(*this, op);
1847 }
1848 
1849 
1850 template<typename T, Index Log2Dim>
1851 template<typename VisitorOp>
1852 inline void
1853 LeafNode<T, Log2Dim>::visit(VisitorOp& op) const
1854 {
1855  doVisit<const LeafNode, VisitorOp, ChildAllCIter>(*this, op);
1856 }
1857 
1858 
1859 template<typename T, Index Log2Dim>
1860 template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
1861 inline void
1862 LeafNode<T, Log2Dim>::doVisit(NodeT& self, VisitorOp& op)
1863 {
1864  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1865  op(iter);
1866  }
1867 }
1868 
1869 
1871 
1872 
1873 template<typename T, Index Log2Dim>
1874 template<typename OtherLeafNodeType, typename VisitorOp>
1875 inline void
1876 LeafNode<T, Log2Dim>::visit2Node(OtherLeafNodeType& other, VisitorOp& op)
1877 {
1878  doVisit2Node<LeafNode, OtherLeafNodeType, VisitorOp, ChildAllIter,
1879  typename OtherLeafNodeType::ChildAllIter>(*this, other, op);
1880 }
1881 
1882 
1883 template<typename T, Index Log2Dim>
1884 template<typename OtherLeafNodeType, typename VisitorOp>
1885 inline void
1886 LeafNode<T, Log2Dim>::visit2Node(OtherLeafNodeType& other, VisitorOp& op) const
1887 {
1888  doVisit2Node<const LeafNode, OtherLeafNodeType, VisitorOp, ChildAllCIter,
1889  typename OtherLeafNodeType::ChildAllCIter>(*this, other, op);
1890 }
1891 
1892 
1893 template<typename T, Index Log2Dim>
1894 template<
1895  typename NodeT,
1896  typename OtherNodeT,
1897  typename VisitorOp,
1898  typename ChildAllIterT,
1899  typename OtherChildAllIterT>
1900 inline void
1901 LeafNode<T, Log2Dim>::doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp& op)
1902 {
1903  // Allow the two nodes to have different ValueTypes, but not different dimensions.
1904  static_assert(OtherNodeT::SIZE == NodeT::SIZE,
1905  "can't visit nodes of different sizes simultaneously");
1906  static_assert(OtherNodeT::LEVEL == NodeT::LEVEL,
1907  "can't visit nodes at different tree levels simultaneously");
1908 
1909  ChildAllIterT iter = self.beginChildAll();
1910  OtherChildAllIterT otherIter = other.beginChildAll();
1911 
1912  for ( ; iter && otherIter; ++iter, ++otherIter) {
1913  op(iter, otherIter);
1914  }
1915 }
1916 
1917 
1919 
1920 
1921 template<typename T, Index Log2Dim>
1922 template<typename IterT, typename VisitorOp>
1923 inline void
1924 LeafNode<T, Log2Dim>::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS)
1925 {
1926  doVisit2<LeafNode, VisitorOp, ChildAllIter, IterT>(
1927  *this, otherIter, op, otherIsLHS);
1928 }
1929 
1930 
1931 template<typename T, Index Log2Dim>
1932 template<typename IterT, typename VisitorOp>
1933 inline void
1934 LeafNode<T, Log2Dim>::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS) const
1935 {
1936  doVisit2<const LeafNode, VisitorOp, ChildAllCIter, IterT>(
1937  *this, otherIter, op, otherIsLHS);
1938 }
1939 
1940 
1941 template<typename T, Index Log2Dim>
1942 template<
1943  typename NodeT,
1944  typename VisitorOp,
1945  typename ChildAllIterT,
1946  typename OtherChildAllIterT>
1947 inline void
1948 LeafNode<T, Log2Dim>::doVisit2(NodeT& self, OtherChildAllIterT& otherIter,
1949  VisitorOp& op, bool otherIsLHS)
1950 {
1951  if (!otherIter) return;
1952 
1953  if (otherIsLHS) {
1954  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1955  op(otherIter, iter);
1956  }
1957  } else {
1958  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1959  op(iter, otherIter);
1960  }
1961  }
1962 }
1963 
1964 
1966 
1967 
1968 template<typename T, Index Log2Dim>
1969 inline std::ostream&
1970 operator<<(std::ostream& os, const typename LeafNode<T, Log2Dim>::Buffer& buf)
1971 {
1972  for (Index32 i = 0, N = buf.size(); i < N; ++i) os << buf.mData[i] << ", ";
1973  return os;
1974 }
1975 
1976 } // namespace tree
1977 } // namespace OPENVDB_VERSION_NAME
1978 } // namespace openvdb
1979 
1980 
1982 
1983 
1984 // Specialization for LeafNodes of type bool
1985 #include "LeafNodeBool.h"
1986 
1987 // Specialization for LeafNodes with mask information only
1988 #include "LeafNodeMask.h"
1989 
1990 #endif // OPENVDB_TREE_LEAFNODE_HAS_BEEN_INCLUDED
bool isOff(Index32 n) const
Return true if the nth bit is off.
Definition: NodeMasks.h:489
ValueAllCIter beginValueAll() const
Definition: LeafNode.h:296
Base class for sparse iterators over internal and leaf nodes.
Definition: Iterator.h:114
const Coord & origin() const
Return the grid index coordinates of this node&#39;s local origin.
Definition: LeafNode.h:170
static const Index LOG2DIM
Definition: LeafNode.h:48
ChildAllIter beginChildAll()
Definition: LeafNode.h:319
ChildOffCIter beginChildOff() const
Definition: LeafNode.h:315
void modifyValue(const ModifyOp &op) const
Definition: LeafNode.h:235
ValueIter(const MaskIterT &iter, NodeT *parent)
Definition: LeafNode.h:214
ChildOnCIter cendChildOn() const
Definition: LeafNode.h:321
LeafNode * touchLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: LeafNode.h:729
ChildOnIter beginChildOn()
Definition: LeafNode.h:313
~LeafNode()
Destructor.
Definition: LeafNode.h:1006
void writeBuffers(std::ostream &os, bool toHalf=false) const
Write buffers to a stream.
Definition: LeafNode.h:1412
Definition: LeafNode.h:202
ValueT & getValue() const
Definition: LeafNode.h:217
void addLeafAndCache(LeafNode *, AccessorT &)
This function exists only to enable template instantiation.
Definition: LeafNode.h:709
void setValueOff(Index offset)
Mark the voxel at the given offset as inactive but don&#39;t change its value.
Definition: LeafNode.h:401
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:1111
ChildOnCIter endChildOn() const
Definition: LeafNode.h:322
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:1220
const NodeT * probeConstNodeAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: LeafNode.h:751
ChildOffCIter cbeginChildOff() const
Definition: LeafNode.h:314
static Index getValueLevel(const Coord &)
Return the level (i.e., 0) at which leaf node values reside.
Definition: LeafNode.h:386
ValueOffCIter cendValueOff() const
Definition: LeafNode.h:302
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:351
static void getNodeLog2Dims(std::vector< Index > &dims)
Append the Log2Dim of this LeafNode to the specified vector.
Definition: LeafNode.h:127
Index32 countOn() const
Return the total number of on bits.
Definition: NodeMasks.h:424
NodeT * probeNodeAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: LeafNode.h:731
Definition: Types.h:507
Base class for iterators over internal and leaf nodes.
Definition: Iterator.h:29
void addLeaf(LeafNode *)
This function exists only to enable template instantiation.
Definition: LeafNode.h:707
DenseIter(const MaskDenseIterator &iter, NodeT *parent)
Definition: LeafNode.h:256
static Index size()
Return the total number of voxels represented by this LeafNode.
Definition: LeafNode.h:121
bool getItem(Index pos, void *&child, NonConstValueT &value) const
Definition: LeafNode.h:258
static Index dim()
Return the number of voxels in each coordinate dimension.
Definition: LeafNode.h:119
Definition: LeafNode.h:202
Definition: LeafNode.h:22
ValueAllIter endValueAll()
Definition: LeafNode.h:307
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:558
void setValue(Index i, const ValueType &)
Set the i&#39;th value of this buffer to the specified value.
Definition: LeafBuffer.h:233
SharedPtr< MappedFile > Ptr
Definition: io.h:136
ChildOffIter endChildOff()
Definition: LeafNode.h:326
OnIterator beginOn() const
Definition: NodeMasks.h:333
bool resultIsActive() const
Definition: Types.h:631
uint32_t Index32
Definition: Types.h:29
bool isEmpty() const
Return true if this node has no active voxels.
Definition: LeafNode.h:146
Base class for dense iterators over internal and leaf nodes.
Definition: Iterator.h:178
LeafNode * probeLeaf(const Coord &)
Return a pointer to this node.
Definition: LeafNode.h:738
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:568
static const Index SIZE
Definition: LeafNode.h:53
bool isValueMaskOff() const
Definition: LeafNode.h:864
bool isValueMaskOn(Index n) const
Definition: LeafNode.h:861
static void doVisit2(NodeT &self, OtherChildAllIterT &, VisitorOp &, bool otherIsLHS)
Definition: LeafNode.h:1948
typename BaseT::NonConstValueType NonConstValueT
Definition: LeafNode.h:253
ValueAllCIter cbeginValueAll() const
Definition: LeafNode.h:295
std::shared_ptr< T > SharedPtr
Definition: Types.h:91
Definition: NodeMasks.h:251
bool allocate()
Allocate memory for this node&#39;s buffer if it has not already been allocated.
Definition: LeafNode.h:152
void visit2(IterT &otherIter, VisitorOp &, bool otherIsLHS=false)
Definition: LeafNode.h:1924
Index medianOff(ValueType &value, ValueType *tmp=nullptr) const
Computes the median value of all the inactive voxels in this node.
Definition: LeafNode.h:1553
Index64 onLeafVoxelCount() const
Definition: LeafNode.h:141
ValueType medianAll(ValueType *tmp=nullptr) const
Computes the median value of all the active AND inactive voxels in this node.
Definition: LeafNode.h:1511
Index64 offVoxelCount() const
Return the number of voxels marked Off.
Definition: LeafNode.h:140
static Index32 nonLeafCount()
Return the non-leaf count for this node, which is zero.
Definition: LeafNode.h:135
ChildOnCIter cbeginChildOn() const
Definition: LeafNode.h:311
T BuildType
Definition: LeafNode.h:40
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don&#39;t change its value.
Definition: LeafNode.h:399
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:37
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:592
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:574
const LeafNode * probeConstLeafAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: LeafNode.h:746
void readTopology(std::istream &is, bool fromHalf=false)
Read in just the topology.
Definition: LeafNode.h:1284
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:1247
void setValueOn(Index offset)
Mark the voxel at the given offset as active but don&#39;t change its value.
Definition: LeafNode.h:411
void getOrigin(Coord &origin) const
Return the grid index coordinates of this node&#39;s local origin.
Definition: LeafNode.h:171
bool isChildMaskOff() const
Definition: LeafNode.h:871
CombineArgs & setARef(const AValueType &a)
Redirect the A value to a new external source.
Definition: Types.h:620
ChildOffCIter endChildOff() const
Definition: LeafNode.h:325
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:583
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: LeafNode.h:1061
ValueAllCIter endValueAll() const
Definition: LeafNode.h:306
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:1687
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
Definition: LeafNode.h:448
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:419
Index64 offLeafVoxelCount() const
Definition: LeafNode.h:142
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:1696
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:427
CoordBBox getNodeBoundingBox() const
Return the bounding box of this node, i.e., the full index space spanned by this leaf node...
Definition: LeafNode.h:164
bool allocate()
Allocate memory for this buffer if it has not already been allocated.
Definition: LeafBuffer.h:107
static void doVisit(NodeT &, VisitorOp &)
Definition: LeafNode.h:1862
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation. ...
Definition: NodeMasks.h:288
void setValueMask(const NodeMaskType &mask)
Definition: LeafNode.h:868
bool operator==(const LeafNode &other) const
Check for buffer, state and origin equivalence.
Definition: LeafNode.h:1429
static void evalNodeOrigin(Coord &xyz)
Compute the origin of the leaf node that contains the voxel with the given coordinates.
Definition: LeafNode.h:880
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 Index32 leafCount()
Return the leaf count for this node, which is one.
Definition: LeafNode.h:131
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:81
ValueOnCIter beginValueOn() const
Definition: LeafNode.h:290
void readCompressedValues(std::istream &is, ValueT *destBuf, Index destCount, const MaskT &valueMask, bool fromHalf)
Definition: Compression.h:465
ValueOnIter beginValueOn()
Definition: LeafNode.h:291
void setOn(Index32 n)
Set the nth bit on.
Definition: NodeMasks.h:433
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:421
Definition: LeafNode.h:202
void save(std::ostream &os) const
Definition: NodeMasks.h:546
ChildAllCIter cbeginChildAll() const
Definition: LeafNode.h:317
bool isChildMaskOn(Index) const
Definition: LeafNode.h:869
ChildOffIter beginChildOff()
Definition: LeafNode.h:316
void setValue(const ValueT &value) const
Definition: LeafNode.h:225
void setOff(Index32 n)
Set the nth bit off.
Definition: NodeMasks.h:438
Definition: Compression.h:292
ValueOnCIter cendValueOn() const
Definition: LeafNode.h:299
static Index numValues()
Return the total number of voxels represented by this LeafNode.
Definition: LeafNode.h:123
LeafNode()
Default constructor.
Definition: LeafNode.h:922
Index32 countOff() const
Return the total number of on bits.
Definition: NodeMasks.h:431
ValueIter()
Definition: LeafNode.h:213
void nodeCount(std::vector< Index32 > &) const
no-op
Definition: LeafNode.h:133
ValueOnIter endValueOn()
Definition: LeafNode.h:301
void stealNodes(ArrayT &, const ValueType &, bool)
This function exists only to enable template instantiation.
Definition: LeafNode.h:717
NodeMaskType & getValueMask()
Definition: LeafNode.h:866
Index64 onVoxelCount() const
Return the number of voxels marked On.
Definition: LeafNode.h:138
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:1177
std::string str() const
Return a string representation of this node.
Definition: LeafNode.h:1013
ValueAllCIter cendValueAll() const
Definition: LeafNode.h:305
ChildOnCIter beginChildOn() const
Definition: LeafNode.h:312
void combine2(const LeafNode &other, const OtherType &, bool valueIsActive, CombineOp &)
Definition: LeafNode.h:1760
void seek(std::istream &is) const
Definition: NodeMasks.h:551
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:102
const ValueType & getValueAndCache(const Coord &xyz, AccessorT &) const
Return the value of the voxel at the given coordinates.
Definition: LeafNode.h:527
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:336
void setValuesOff()
Mark all voxels as inactive but don&#39;t change their values.
Definition: LeafNode.h:464
void visit2Node(OtherLeafNodeType &other, VisitorOp &)
Definition: LeafNode.h:1876
int32_t Int32
Definition: Types.h:33
Leaf nodes have no children, so their child iterators have no get/set accessors.
Definition: LeafNode.h:240
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:549
bool isInactive() const
Return true if all of this node&#39;s values are inactive.
Definition: LeafNode.h:836
void set(Index32 n, bool On)
Set the nth bit to the specified state.
Definition: NodeMasks.h:443
SameConfiguration<OtherNodeType>::value is true if and only if OtherNodeType is the type of a LeafNod...
Definition: LeafNode.h:64
const NodeMaskType & valueMask() const
Definition: LeafNode.h:867
static Index getChildDim()
Return the dimension of child nodes of this LeafNode, which is one for voxels.
Definition: LeafNode.h:129
void addTile(Index level, const Coord &, const ValueType &, bool)
Definition: LeafNode.h:1580
Index medianOn(ValueType &value, ValueType *tmp=nullptr) const
Computes the median value of all the active voxels in this node.
Definition: LeafNode.h:1529
void visitActiveBBox(BBoxOp &) const
Calls the templated functor BBoxOp with bounding box information. An additional level argument is pro...
Definition: LeafNode.h:1821
Buffer & buffer()
Definition: LeafNode.h:338
void unsetItem(Index pos, const ValueT &value) const
Definition: LeafNode.h:269
void visit(VisitorOp &)
Definition: LeafNode.h:1844
void clip(const CoordBBox &, const ValueType &background)
Set all voxels that lie outside the given axis-aligned box to the background.
Definition: LeafNode.h:1137
typename std::remove_const< UnsetItemT >::type NonConstValueType
Definition: Iterator.h:184
static Index64 offTileCount()
Definition: LeafNode.h:144
Definition: PointDataGrid.h:174
bool isValueMaskOn() const
Definition: LeafNode.h:862
Definition: Exceptions.h:13
bool probeValue(const Coord &xyz, ValueType &val) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNode.h:1077
static const Index NUM_VALUES
Definition: LeafNode.h:51
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
SIMD Intrinsic Headers.
Definition: Platform.h:114
CombineArgs & setBRef(const BValueType &b)
Redirect the B value to a new external source.
Definition: Types.h:622
static Index log2dim()
Return log2 of the dimension of this LeafNode, e.g. 3 if dimensions are 8^3.
Definition: LeafNode.h:117
void setValueMask(Index n, bool on)
Definition: LeafNode.h:873
bool isValueMaskOff(Index n) const
Definition: LeafNode.h:863
ChildOnIter endChildOn()
Definition: LeafNode.h:323
DenseIter< const LeafNode, const ValueType, ChildAll > ChildAllCIter
Definition: LeafNode.h:287
bool isOn(Index32 n) const
Return true if the nth bit is on.
Definition: NodeMasks.h:483
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:441
void voxelizeActiveTiles(bool=true)
No-op.
Definition: LeafNode.h:629
bool isValueOn(Index offset) const
Return true if the voxel at the given offset is active.
Definition: LeafNode.h:469
static Index getValueLevelAndCache(const Coord &, AccessorT &)
Return the LEVEL (=0) at which leaf node values reside.
Definition: LeafNode.h:612
void setValueMaskOff(Index n)
Definition: LeafNode.h:875
static void doVisit2Node(NodeT &self, OtherNodeT &other, VisitorOp &)
Definition: LeafNode.h:1901
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:1679
Definition: NodeMasks.h:220
bool operator!=(const LeafNode &other) const
Definition: LeafNode.h:193
static bool hasActiveTiles()
Return false since leaf nodes never contain tiles.
Definition: LeafNode.h:472
ValueOffIter endValueOff()
Definition: LeafNode.h:304
Definition: Compression.h:54
void getOrigin(Int32 &x, Int32 &y, Int32 &z) const
Return the grid index coordinates of this node&#39;s local origin.
Definition: LeafNode.h:172
bool isConstant(ValueType &firstValue, bool &state, const ValueType &tolerance=zeroVal< ValueType >()) const
Definition: LeafNode.h:1475
typename NodeMaskType::DenseIterator MaskDenseIterator
Definition: LeafNode.h:198
ValueType * mData
Definition: LeafBuffer.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:1467
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:681
const ValueType & getFirstValue() const
Return a const reference to the first value in the buffer.
Definition: LeafNode.h:617
void addTileAndCache(Index, const Coord &, const ValueType &, bool, AccessorT &)
Definition: LeafNode.h:1597
ValueAllIter beginValueAll()
Definition: LeafNode.h:297
ValueOffCIter beginValueOff() const
Definition: LeafNode.h:293
static Index getLevel()
Return the level of this node, which by definition is zero for LeafNodes.
Definition: LeafNode.h:125
void resetBackground(const ValueType &oldBackground, const ValueType &newBackground)
Replace inactive occurrences of oldBackground with newBackground, and inactive occurrences of -oldBac...
Definition: LeafNode.h:1609
static Index coordToOffset(const Coord &xyz)
Return the linear table offset of the given global or local coordinates.
Definition: LeafNode.h:1026
void writeCompressedValues(std::ostream &os, ValueT *srcBuf, Index srcCount, const MaskT &valueMask, const MaskT &childMask, bool toHalf)
Definition: Compression.h:645
void writeTopology(std::ostream &os, bool toHalf=false) const
Write out just the topology.
Definition: LeafNode.h:1292
void skipCompressedValues(bool seekable, std::istream &, bool fromHalf)
Definition: LeafNode.h:1304
bool isAllocated() const
Return true if memory for this node&#39;s buffer has been allocated.
Definition: LeafNode.h:150
static const Index LEVEL
Definition: LeafNode.h:54
bool operator==(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Equality operator, does exact floating point comparisons.
Definition: Vec3.h:471
SharedPtr< LeafNode > Ptr
Definition: LeafNode.h:45
typename NodeMaskType::OnIterator MaskOnIterator
Definition: LeafNode.h:196
const ValueType & getLastValue() const
Return a const reference to the last value in the buffer.
Definition: LeafNode.h:619
static Coord offsetToLocalCoord(Index n)
Return the local coordinates for a linear table offset, where offset 0 has coordinates (0...
Definition: LeafNode.h:1036
Index memUsage() const
Return the memory footprint of this buffer in bytes.
Definition: LeafBuffer.h:305
void negate()
Definition: LeafNode.h:1704
Index32 Index
Definition: Types.h:31
void setItem(Index pos, const ValueT &value) const
Definition: LeafNode.h:220
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:115
Coord offsetToGlobalCoord(Index n) const
Return the global coordinates for a linear table offset.
Definition: LeafNode.h:1050
OPENVDB_API uint32_t getFormatVersion(std::ios_base &)
Return the file format version number associated with the given input stream.
bool isValueOn(const Coord &xyz) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNode.h:467
static const Index DIM
Definition: LeafNode.h:50
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:540
LeafNode * probeLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Definition: LeafNode.h:740
void merge(const LeafNode &)
Definition: LeafNode.h:1630
DenseIter()
Definition: LeafNode.h:255
void setValuesOn()
Mark all voxels as active but don&#39;t change their values.
Definition: LeafNode.h:462
ChildAllCIter endChildAll() const
Definition: LeafNode.h:328
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:391
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:601
const LeafNode * probeLeafAndCache(const Coord &, AccessorT &) const
Return a const pointer to this node.
Definition: LeafNode.h:748
NodeT * stealNode(const Coord &, const ValueType &, bool)
This function exists only to enable template instantiation.
Definition: LeafNode.h:711
bool isDense() const
Return true if this node contains only active voxels.
Definition: LeafNode.h:148
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:102
ValueOffCIter endValueOff() const
Definition: LeafNode.h:303
Index32 pos() const
Definition: NodeMasks.h:181
void readBuffers(std::istream &is, bool fromHalf=false)
Read buffers from a stream.
Definition: LeafNode.h:1320
ChildAllCIter cendChildAll() const
Definition: LeafNode.h:327
DenseIter< LeafNode, ValueType, ChildAll > ChildAllIter
Definition: LeafNode.h:286
OPENVDB_API SharedPtr< StreamMetadata > getStreamMetadataPtr(std::ios_base &)
Return a shared pointer to an object that stores metadata (file format, compression scheme...
OffIterator beginOff() const
Definition: NodeMasks.h:335
Definition: LeafNode.h:201
ChildIter(const MaskIterT &iter, NodeT *parent)
Definition: LeafNode.h:244
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:683
ValueOnCIter endValueOn() const
Definition: LeafNode.h:300
ValueOffCIter cbeginValueOff() const
Definition: LeafNode.h:292
ChildAllIter endChildAll()
Definition: LeafNode.h:329
const NodeMaskType & getValueMask() const
Definition: LeafNode.h:865
uint64_t Index64
Definition: Types.h:30
void evalActiveBoundingBox(CoordBBox &bbox, bool visitVoxels=true) const
Definition: LeafNode.h:1449
ChildAllCIter beginChildAll() const
Definition: LeafNode.h:318
bool isValueOnAndCache(const Coord &xyz, AccessorT &) const
Return true if the voxel at the given coordinates is active.
Definition: LeafNode.h:535
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:417
typename NodeMaskType::OffIterator MaskOffIterator
Definition: LeafNode.h:197
void modifyItem(Index n, const ModifyOp &op) const
Definition: LeafNode.h:232
void fill(const ValueType &)
Populate this buffer with a constant value.
Definition: LeafBuffer.h:268
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:154
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:567
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don&#39;t change its value.
Definition: LeafNode.h:409
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:334
ValueOffIter beginValueOff()
Definition: LeafNode.h:294
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:348
Definition: LeafNode.h:201
void getNodes(ArrayT &) const
This function exists only to enable template instantiation.
Definition: LeafNode.h:716
NodeT * probeNode(const Coord &)
This function exists only to enable template instantiation.
Definition: LeafNode.h:713
Index64 memUsage() const
Return the memory in bytes occupied by this node.
Definition: LeafNode.h:1439
void setValueMaskOn(Index n)
Definition: LeafNode.h:874
ValueT & getItem(Index pos) const
Definition: LeafNode.h:216
FileInfo * mFileInfo
Definition: LeafBuffer.h:170
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:413
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.
ChildOffCIter cendChildOff() const
Definition: LeafNode.h:324
void load(std::istream &is)
Definition: NodeMasks.h:550
ValueType combine(const ValueType &v0, const ValueType &v1, const ValueType &v2, const openvdb::Vec3d &w)
Combine different value types.
Definition: AttributeTransferUtil.h:141
ValueOnCIter cbeginValueOn() const
Definition: LeafNode.h:289
bool isConstant(bool &isOn) const
Definition: NodeMasks.h:507
bool isChildMaskOff(Index) const
Definition: LeafNode.h:870
void modifyValueAndActiveStateAndCache(const Coord &xyz, const ModifyOp &op, AccessorT &)
Definition: LeafNode.h:566
static Index64 onTileCount()
Definition: LeafNode.h:143
Definition: NodeMasks.h:189
const NodeT * probeConstNode(const Coord &) const
This function exists only to enable template instantiation.
Definition: LeafNode.h:715
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:1119
const ValueType * data() const
Return a const pointer to the array of voxel values.
Definition: LeafBuffer.h:316
void combine(const LeafNode &other, CombineOp &op)
Definition: LeafNode.h:1720
const Buffer & buffer() const
Definition: LeafNode.h:337
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:480
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...
ValueConverter<T>::Type is the type of a LeafNode having the same dimensions as this node but a diffe...
Definition: LeafNode.h:59
T ValueType
Definition: LeafNode.h:41
Definition: LeafNode.h:201
void setOrigin(const Coord &origin)
Set the grid index coordinates of this node&#39;s local origin.
Definition: LeafNode.h:167
const LeafNode * probeLeaf(const Coord &) const
Return a const pointer to this node.
Definition: LeafNode.h:749
ChildIter()
Definition: LeafNode.h:243