OpenVDB  1.2.0
LeafNode.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2013 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 <iostream>
35 #include <algorithm> // for std::swap
36 #include <cstring> // for std::memcpy()
37 #include <boost/shared_ptr.hpp>
38 #include <boost/static_assert.hpp>
39 #include <boost/bind.hpp>
40 #include <tbb/blocked_range.h>
41 #include <tbb/parallel_for.h>
42 #include <openvdb/Types.h>
43 #include <openvdb/util/NodeMasks.h>
44 #include <openvdb/io/Compression.h> // for io::readData(), etc.
45 #include "Iterator.h"
46 #include "Util.h"
47 
48 
49 class TestLeaf;
50 template<typename> class TestLeafIO;
51 
52 namespace openvdb {
54 namespace OPENVDB_VERSION_NAME {
55 namespace tree {
56 
61 template<typename T, Index Log2Dim>
62 class LeafNode
63 {
64 public:
65  typedef T ValueType;
67  typedef boost::shared_ptr<LeafNode> Ptr;
69 
70  static const Index
71  LOG2DIM = Log2Dim, // needed by parent nodes
72  TOTAL = Log2Dim, // needed by parent nodes
73  DIM = 1 << TOTAL, // dimension along one coordinate direction
74  NUM_VALUES = 1 << 3 * Log2Dim,
75  NUM_VOXELS = NUM_VALUES, // total number of voxels represented by this node
76  SIZE = NUM_VALUES,
77  LEVEL = 0; // level 0 = leaf
78 
81  template<typename OtherValueType>
82  struct ValueConverter {
84  };
85 
88  class Buffer
89  {
90  public:
92  Buffer(): mData(new ValueType[SIZE]) {}
94  Buffer(const ValueType& val) : mData(new ValueType[SIZE]) { this->fill(val); }
96  Buffer(const Buffer& other) : mData(new ValueType[SIZE]) { *this = other; }
98  ~Buffer() { delete [] mData; }
100  void fill(const ValueType& val)
101  {
102  ValueType* target = mData;
103  Index n = SIZE;
104  while (n--) *target++ = val;
105  }
107  const ValueType& getValue(Index i) const { assert(i < SIZE); return mData[i]; }
109  const ValueType& operator[](Index i) const { return this->getValue(i); }
111  void setValue(Index i, const ValueType& val) { assert(i < SIZE); mData[i] = val; }
113  Buffer& operator=(const Buffer& other)
114  {
115  ValueType* target = mData;
116  const ValueType* source = other.mData;
117  Index n = SIZE;
118  while (n--) *target++ = *source++;
119  return *this;
120  }
123  bool operator==(const Buffer& other) const
124  {
125  const ValueType* target = mData;
126  const ValueType* source = other.mData;
127  Index n = SIZE;
128  while (n && math::isExactlyEqual(*target++, *source++)) --n;
129  return n == 0;
130  }
133  bool operator!=(const Buffer& other) const { return !(other == *this); }
135  void swap(Buffer& other)
136  {
137  ValueType* tmp = mData;
138  mData = other.mData;
139  other.mData = tmp;
140  }
142  static Index memUsage() { return sizeof(ValueType*) + SIZE * sizeof(ValueType); }
144  static Index size() { return SIZE; }
145 
146  private:
149  ValueType& operator[](Index i) { assert(i < SIZE); return mData[i]; }
150 
151  friend class ::TestLeaf;
152  // Allow the parent LeafNode to access this Buffer's data pointer.
153  friend class LeafNode;
154 
155  ValueType* mData;
156  }; // class Buffer
157 
158 
160  LeafNode();
161 
166  explicit LeafNode(const Coord& coords,
167  const ValueType& value = zeroVal<ValueType>(),
168  bool active = false);
169 
171  LeafNode(const LeafNode&);
172 
174  template<typename OtherValueType>
176  const ValueType& offValue, const ValueType& onValue, TopologyCopy);
177 
179  template<typename OtherValueType>
181  const ValueType& background, TopologyCopy);
182 
184  ~LeafNode();
185 
186  //
187  // Statistics
188  //
190  static Index log2dim() { return Log2Dim; }
192  static Index dim() { return DIM; }
194  static Index size() { return SIZE; }
196  static Index numValues() { return SIZE; }
198  static Index getLevel() { return LEVEL; }
200  static void getNodeLog2Dims(std::vector<Index>& dims) { dims.push_back(Log2Dim); }
202  static Index getChildDim() { return 1; }
204  static Index32 leafCount() { return 1; }
206  static Index32 nonLeafCount() { return 0; }
207 
209  Index64 onVoxelCount() const { return mValueMask.countOn(); }
211  Index64 offVoxelCount() const { return mValueMask.countOff(); }
212  Index64 onLeafVoxelCount() const { return onVoxelCount(); }
213  Index64 offLeafVoxelCount() const { return offVoxelCount(); }
215  bool isEmpty() const { return mValueMask.isOff(); }
217  bool isDense() const { return mValueMask.isOn(); }
218 
220  Index64 memUsage() const;
221 
223  void evalActiveVoxelBoundingBox(CoordBBox&) const;
224 
227  CoordBBox getNodeBoundingBox() const { return CoordBBox::createCube(mOrigin, DIM); }
228 
230  void setOrigin(const Coord& origin) { mOrigin = origin; }
232  const Coord& origin() const { return mOrigin; }
233  const Coord& getOrigin() const { return mOrigin; }
234  void getOrigin(Coord& origin) const { origin = mOrigin; }
235  void getOrigin(Int32& x, Int32& y, Int32& z) const { mOrigin.asXYZ(x, y, z); }
236 
238  static Index coord2offset(const Coord& xyz);
240  static void offset2coord(Index n, Coord &xyz);
242  Coord offset2globalCoord(Index n) const;
243 
245  std::string str() const;
246 
249  template<typename OtherType, Index OtherLog2Dim>
250  bool hasSameTopology(const LeafNode<OtherType, OtherLog2Dim>* other) const;
251 
253  bool operator==(const LeafNode& other) const;
254  bool operator!=(const LeafNode& other) const { return !(other == *this); }
255 
256 protected:
260 
261  // Type tags to disambiguate template instantiations
262  struct ValueOn {}; struct ValueOff {}; struct ValueAll {};
263  struct ChildOn {}; struct ChildOff {}; struct ChildAll {};
264 
265  template<typename MaskIterT, typename NodeT, typename ValueT, typename TagT>
266  struct ValueIter:
267  // Derives from SparseIteratorBase, but can also be used as a dense iterator,
268  // if MaskIterT is a dense mask iterator type.
269  public SparseIteratorBase<
270  MaskIterT, ValueIter<MaskIterT, NodeT, ValueT, TagT>, NodeT, ValueT>
271  {
273 
275  ValueIter(const MaskIterT& iter, NodeT* parent): BaseT(iter, parent) {}
276 
277  ValueT& getItem(Index pos) const { return this->parent().getValue(pos); }
278  ValueT& getValue() const { return this->parent().getValue(this->pos()); }
279 
280  // Note: setItem() can't be called on const iterators.
281  void setItem(Index pos, const ValueT& value) const
282  {
283  this->parent().setValueOnly(pos, value);
284  }
285  // Note: setValue() can't be called on const iterators.
286  void setValue(const ValueT& value) const
287  {
288  this->parent().setValueOnly(this->pos(), value);
289  }
290  };
291 
293  template<typename MaskIterT, typename NodeT, typename TagT>
294  struct ChildIter:
295  public SparseIteratorBase<MaskIterT, ChildIter<MaskIterT, NodeT, TagT>, NodeT, ValueType>
296  {
298  ChildIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase<
299  MaskIterT, ChildIter<MaskIterT, NodeT, TagT>, NodeT, ValueType>(iter, parent) {}
300  };
301 
302  template<typename NodeT, typename ValueT, typename TagT>
303  struct DenseIter: public DenseIteratorBase<
304  MaskDenseIterator, DenseIter<NodeT, ValueT, TagT>, NodeT, /*ChildT=*/void, ValueT>
305  {
308 
310  DenseIter(const MaskDenseIterator& iter, NodeT* parent): BaseT(iter, parent) {}
311 
312  bool getItem(Index pos, void*& child, NonConstValueT& value) const
313  {
314  value = this->parent().getValue(pos);
315  child = NULL;
316  return false; // no child
317  }
318 
319  // Note: setItem() can't be called on const iterators.
320  //void setItem(Index pos, void* child) const {}
321 
322  // Note: unsetItem() can't be called on const iterators.
323  void unsetItem(Index pos, const ValueT& value) const
324  {
325  this->parent().setValueOnly(pos, value);
326  }
327  };
328 
329 public:
342 
343  ValueOnCIter cbeginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); }
344  ValueOnCIter beginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); }
345  ValueOnIter beginValueOn() { return ValueOnIter(mValueMask.beginOn(), this); }
346  ValueOffCIter cbeginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); }
347  ValueOffCIter beginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); }
348  ValueOffIter beginValueOff() { return ValueOffIter(mValueMask.beginOff(), this); }
349  ValueAllCIter cbeginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); }
350  ValueAllCIter beginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); }
351  ValueAllIter beginValueAll() { return ValueAllIter(mValueMask.beginDense(), this); }
352 
353  ValueOnCIter cendValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); }
354  ValueOnCIter endValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); }
355  ValueOnIter endValueOn() { return ValueOnIter(mValueMask.endOn(), this); }
356  ValueOffCIter cendValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); }
357  ValueOffCIter endValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); }
358  ValueOffIter endValueOff() { return ValueOffIter(mValueMask.endOff(), this); }
359  ValueAllCIter cendValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); }
360  ValueAllCIter endValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); }
361  ValueAllIter endValueAll() { return ValueAllIter(mValueMask.endDense(), this); }
362 
363  // Note that [c]beginChildOn() and [c]beginChildOff() actually return end iterators,
364  // because leaf nodes have no children.
365  ChildOnCIter cbeginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
366  ChildOnCIter beginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
367  ChildOnIter beginChildOn() { return ChildOnIter(mValueMask.endOn(), this); }
368  ChildOffCIter cbeginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
369  ChildOffCIter beginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
370  ChildOffIter beginChildOff() { return ChildOffIter(mValueMask.endOff(), this); }
371  ChildAllCIter cbeginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); }
372  ChildAllCIter beginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); }
373  ChildAllIter beginChildAll() { return ChildAllIter(mValueMask.beginDense(), this); }
374 
375  ChildOnCIter cendChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
376  ChildOnCIter endChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
377  ChildOnIter endChildOn() { return ChildOnIter(mValueMask.endOn(), this); }
378  ChildOffCIter cendChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
379  ChildOffCIter endChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
380  ChildOffIter endChildOff() { return ChildOffIter(mValueMask.endOff(), this); }
381  ChildAllCIter cendChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); }
382  ChildAllCIter endChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); }
383  ChildAllIter endChildAll() { return ChildAllIter(mValueMask.endDense(), this); }
384 
385  //
386  // Buffer management
387  //
390  void swap(Buffer& other) { mBuffer.swap(other); }
391  const Buffer& buffer() const { return mBuffer; }
392  Buffer& buffer() { return mBuffer; }
393 
394  //
395  // I/O methods
396  //
400  void readTopology(std::istream& is, bool fromHalf = false);
404  void writeTopology(std::ostream& os, bool toHalf = false) const;
405 
409  void readBuffers(std::istream& is, bool fromHalf = false);
413  void writeBuffers(std::ostream& os, bool toHalf = false) const;
414 
415  size_t streamingSize(bool toHalf = false) const;
416 
417  //
418  // Accessor methods
419  //
421  const ValueType& getValue(const Coord& xyz) const;
423  const ValueType& getValue(Index offset) const;
424 
428  bool probeValue(const Coord& xyz, ValueType& val) const;
432  bool probeValue(Index offset, ValueType& val) const;
433 
435  static Index getValueLevel(const Coord&) { return LEVEL; }
436 
438  void setActiveState(const Coord& xyz, bool on);
439 
441  void setValueOff(const Coord& xyz) { mValueMask.setOff(LeafNode::coord2offset(xyz)); }
443  void setValueOff(Index offset) { assert(offset < SIZE); mValueMask.setOff(offset); }
444 
446  void setValueOff(const Coord& xyz, const ValueType& val);
448  void setValueOff(Index offset, const ValueType& val);
449 
451  void setValueOn(const Coord& xyz) { mValueMask.setOn(LeafNode::coord2offset(xyz)); }
453  void setValueOn(Index offset) { assert(offset < SIZE); mValueMask.setOn(offset); }
455  void setValueOn(const Coord& xyz, const ValueType& val) {
456  this->setValueOn(LeafNode::coord2offset(xyz), val);
457  }
459  void setValue(const Coord& xyz, const ValueType& val) { this->setValueOn(xyz, val); };
461  void setValueOn(Index offset, const ValueType& val) {
462  mBuffer[offset] = val;
463  mValueMask.setOn(offset);
464  }
465 
468  void setValueOnMin(const Coord& xyz, const ValueType& val) {
469  this->setValueOnMin(LeafNode::coord2offset(xyz), val);
470  }
473  void setValueOnMin(Index offset, const ValueType& val) {
474  mBuffer[offset] = std::min(val, mBuffer[offset]);
475  mValueMask.setOn(offset);
476  }
477 
480  void setValueOnMax(const Coord& xyz, const ValueType& val) {
481  this->setValueOnMax(LeafNode::coord2offset(xyz), val);
482  }
485  void setValueOnMax(Index offset, const ValueType& val) {
486  mBuffer[offset] = std::max(val, mBuffer[offset]);
487  mValueMask.setOn(offset);
488  }
489 
492  void setValueOnSum(const Coord& xyz, const ValueType& val) {
493  this->setValueOnSum(LeafNode::coord2offset(xyz), val);
494  }
497  void setValueOnSum(Index offset, const ValueType& val) {
498  mBuffer[offset] += val;
499  mValueMask.setOn(offset);
500  }
501 
504  void setValueOnly(const Coord& xyz, const ValueType& val) {
505  this->setValueOnly(LeafNode::coord2offset(xyz), val);
506  }
511  void setValueOnly(Index offset, const ValueType& val) {
512  assert(offset<SIZE); mBuffer[offset] = val;
513  }
514 
516  OPENVDB_DEPRECATED void addValue(const ValueType& val);
518  OPENVDB_DEPRECATED void scaleValue(const ValueType& scale);
519 
521  void setValuesOn() { mValueMask.setOn(); }
523  void setValuesOff() { mValueMask.setOff(); }
524 
526  bool isValueOn(const Coord& xyz) const { return this->isValueOn(LeafNode::coord2offset(xyz)); }
528  bool isValueOn(Index offset) const { return mValueMask.isOn(offset); }
529 
531  static bool hasActiveTiles() { return false; }
532 
535  void fill(const CoordBBox& bbox, const ValueType&, bool active = true);
536 
538  void fill(const ValueType& value);
539 
541  void fill(const ValueType& value, bool active);
542 
554  template<typename DenseT>
555  void copyToDense(const CoordBBox& bbox, DenseT& dense) const;
556 
573  template<typename DenseT>
574  void copyFromDense(const CoordBBox& bbox, const DenseT& dense,
575  const ValueType& background, const ValueType& tolerance);
576 
579  template<typename AccessorT>
580  const ValueType& getValueAndCache(const Coord& xyz, AccessorT&) const
581  {
582  return this->getValue(xyz);
583  }
584 
587  template<typename AccessorT>
588  bool isValueOnAndCache(const Coord& xyz, AccessorT&) const { return this->isValueOn(xyz); }
589 
592  template<typename AccessorT>
593  void setValueAndCache(const Coord& xyz, const ValueType& val, AccessorT&)
594  {
595  this->setValueOn(xyz, val);
596  }
597 
601  template<typename AccessorT>
602  void setValueOnlyAndCache(const Coord& xyz, const ValueType& val, AccessorT&)
603  {
604  this->setValueOnly(xyz, val);
605  }
606 
611  template<typename AccessorT>
612  void setValueOnSumAndCache(const Coord& xyz, const ValueType& val, AccessorT&)
613  {
614  this->setValueOnSum(xyz, val);
615  }
616 
619  template<typename AccessorT>
620  void setValueOffAndCache(const Coord& xyz, const ValueType& value, AccessorT&)
621  {
622  this->setValueOff(xyz, value);
623  }
624 
628  template<typename AccessorT>
629  void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&)
630  {
631  this->setActiveState(xyz, on);
632  }
633 
637  template<typename AccessorT>
638  bool probeValueAndCache(const Coord& xyz, ValueType& val, AccessorT&) const
639  {
640  return this->probeValue(xyz, val);
641  }
642 
646  template<typename AccessorT>
647  const ValueType& getValue(const Coord& xyz, bool& state, int& level, AccessorT&) const
648  {
649  const Index offset = this->coord2offset(xyz);
650  state = mValueMask.isOn(offset);
651  level = LEVEL;
652  return mBuffer[offset];
653  }
654 
657  template<typename AccessorT>
658  static Index getValueLevelAndCache(const Coord&, AccessorT&) { return LEVEL; }
659 
663  const ValueType& getFirstValue() const { return mBuffer[0]; }
665  const ValueType& getLastValue() const { return mBuffer[SIZE - 1]; }
666 
669  void resetBackground(const ValueType& oldBackground, const ValueType& newBackground);
670 
680  void signedFloodFill(const ValueType& background);
681 
688  void signedFloodFill(const ValueType& outside, const ValueType& inside);
689 
690  void negate();
691 
692  void merge(const LeafNode&);
693  void merge(const LeafNode& other, const ValueType& /*bg*/, const ValueType& /*otherBG*/)
694  {
695  LeafNode::merge(other);
696  }
698 
705  template<typename OtherType>
706  void topologyUnion(const LeafNode<OtherType, Log2Dim>& other);
707 
719  template<typename OtherType>
720  void topologyIntersection(const LeafNode<OtherType, Log2Dim>& other, const ValueType&);
721 
733  template<typename OtherType>
734  void topologyDifference(const LeafNode<OtherType, Log2Dim>& other, const ValueType&);
735 
736  template<typename CombineOp>
737  void combine(const LeafNode& other, CombineOp& op);
738  template<typename CombineOp>
739  void combine(const ValueType& value, bool valueIsActive, CombineOp& op);
740 
741  template<typename CombineOp>
742  void combine2(const LeafNode& other, const ValueType&, bool valueIsActive, CombineOp&);
743  template<typename CombineOp>
744  void combine2(const ValueType&, const LeafNode& other, bool valueIsActive, CombineOp&);
745  template<typename CombineOp>
746  void combine2(const LeafNode& b0, const LeafNode& b1, CombineOp&);
747 
753  template<typename BBoxOp> void visitActiveBBox(BBoxOp&) const;
754 
755  template<typename VisitorOp> void visit(VisitorOp&);
756  template<typename VisitorOp> void visit(VisitorOp&) const;
757 
758  template<typename OtherLeafNodeType, typename VisitorOp>
759  void visit2Node(OtherLeafNodeType& other, VisitorOp&);
760  template<typename OtherLeafNodeType, typename VisitorOp>
761  void visit2Node(OtherLeafNodeType& other, VisitorOp&) const;
762  template<typename IterT, typename VisitorOp>
763  void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false);
764  template<typename IterT, typename VisitorOp>
765  void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false) const;
766 
768  template<typename PruneOp> void pruneOp(PruneOp&) {}
770  void prune(const ValueType& /*tolerance*/ = zeroVal<ValueType>()) {}
771  void pruneInactive(const ValueType&) {}
772  void addLeaf(LeafNode*) {}
773  template<typename AccessorT>
774  void addLeafAndCache(LeafNode*, AccessorT&) {}
775  template<typename NodeT>
776  NodeT* stealNode(const Coord&, const ValueType&, bool) { return NULL; }
777  template<typename NodeT>
778  NodeT* probeNode(const Coord&) { return NULL; }
779  template<typename NodeT>
780  const NodeT* probeConstNode(const Coord&) const { return NULL; }
781  void addTile(Index, const Coord&, const ValueType&, bool) {}
782  template<typename AccessorT>
783  void addTileAndCache(Index, const Coord&, const ValueType&, bool, AccessorT&) {}
785 
786  LeafNode* touchLeaf(const Coord&) { return this; }
788  template<typename AccessorT>
789  LeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; }
790  template<typename NodeT, typename AccessorT>
791  NodeT* probeNodeAndCache(const Coord&, AccessorT&)
792  {
794  if (!(boost::is_same<NodeT,LeafNode>::value)) return NULL;
795  return reinterpret_cast<NodeT*>(this);
797  }
798  LeafNode* probeLeaf(const Coord&) { return this; }
799  template<typename AccessorT>
800  LeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; }
802 
803  const LeafNode* probeConstLeaf(const Coord&) const { return this; }
805  template<typename AccessorT>
806  const LeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const { return this; }
807  template<typename AccessorT>
808  const LeafNode* probeLeafAndCache(const Coord&, AccessorT&) const { return this; }
809  const LeafNode* probeLeaf(const Coord&) const { return this; }
810  template<typename NodeT, typename AccessorT>
811  const NodeT* probeConstNodeAndCache(const Coord&, AccessorT&) const
812  {
814  if (!(boost::is_same<NodeT,LeafNode>::value)) return NULL;
815  return reinterpret_cast<const NodeT*>(this);
817  }
819 
821  template<typename NodeT>
822  static bool hasNodeType() { return (boost::is_same<NodeT,LeafNode>::value); }
823 
827  bool isConstant(ValueType& constValue, bool& state,
828  const ValueType& tolerance = zeroVal<ValueType>()) const;
830  bool isInactive() const { return mValueMask.isOff(); }
831 
832 protected:
833  friend class ::TestLeaf;
834  template<typename> friend class ::TestLeafIO;
835 
836  // During topology-only construction, access is needed
837  // to protected/private members of other template instances.
838  template<typename, Index> friend class LeafNode;
839 
846 
847  // Allow iterators to call mask accessor methods (see below).
852 
859 
860  // Mask accessors
861 public:
862  bool isValueMaskOn(Index n) const { return mValueMask.isOn(n); }
863  bool isValueMaskOn() const { return mValueMask.isOn(); }
864  bool isValueMaskOff(Index n) const { return mValueMask.isOff(n); }
865  bool isValueMaskOff() const { return mValueMask.isOff(); }
866  const NodeMaskType& getValueMask() const { return mValueMask; }
867  NodeMaskType& getValueMask() { 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 
878  static void evalNodeOrigin(Coord& xyz) { xyz &= ~(DIM - 1); }
879 
880  template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
881  static inline void doVisit(NodeT&, VisitorOp&);
882 
883  template<typename NodeT, typename OtherNodeT, typename VisitorOp,
884  typename ChildAllIterT, typename OtherChildAllIterT>
885  static inline void doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp&);
886 
887  template<typename NodeT, typename VisitorOp,
888  typename ChildAllIterT, typename OtherChildAllIterT>
889  static inline void doVisit2(NodeT& self, OtherChildAllIterT&, VisitorOp&, bool otherIsLHS);
890 
891 private:
892 
893  // Disallow copying.
894  LeafNode& operator=(const LeafNode&);
895 
896 }; // end of LeafNode class
897 
898 
900 
901 template<typename T, Index Log2Dim>
902 inline
904  mValueMask(),//default is off!
905  mOrigin(0, 0, 0)
906 {
907 }
908 
909 
910 template<typename T, Index Log2Dim>
911 inline
912 LeafNode<T, Log2Dim>::LeafNode(const Coord& xyz, const ValueType& val, bool active):
913  mBuffer(val),
914  mValueMask(active),
915  mOrigin(xyz & (~(DIM - 1)))
916 {
917 }
918 
919 template<typename T, Index Log2Dim>
920 template<typename OtherValueType>
921 inline
923  const ValueType& background, TopologyCopy):
924  mBuffer(background),
925  mValueMask(other.mValueMask),
926  mOrigin(other.mOrigin)
927 {
928 }
929 
930 template<typename T, Index Log2Dim>
931 template<typename OtherValueType>
932 inline
934  const ValueType& offValue, const ValueType& onValue, TopologyCopy):
935  mValueMask(other.mValueMask),
936  mOrigin(other.mOrigin)
937 {
938  for (Index i = 0; i < SIZE; ++i) {
939  mBuffer[i] = (mValueMask.isOn(i) ? onValue : offValue);
940  }
941 }
942 
943 template<typename T, Index Log2Dim>
944 inline
946  mBuffer(other.mBuffer),
947  mValueMask(other.mValueMask),
948  mOrigin(other.mOrigin)
949 {
950 }
951 
952 
953 template<typename T, Index Log2Dim>
954 inline
956 {
957 }
958 
959 
960 template<typename T, Index Log2Dim>
961 inline std::string
963 {
964  std::ostringstream ostr;
965  ostr << "LeafNode @" << mOrigin << ": " << mBuffer;
966  return ostr.str();
967 }
968 
969 
971 
972 
973 template<typename T, Index Log2Dim>
974 inline Index
976 {
977  assert ((xyz[0]&DIM-1u)<DIM && (xyz[1]&DIM-1u)<DIM && (xyz[2]&DIM-1u)<DIM);
978  return ((xyz[0]&DIM-1u)<<2*Log2Dim)
979  + ((xyz[1]&DIM-1u)<< Log2Dim)
980  + (xyz[2]&DIM-1u);
981 }
982 
983 
984 template<typename T, Index Log2Dim>
985 inline void
987 {
988  assert(n<(1<< 3*Log2Dim));
989  xyz.setX(n >> 2*Log2Dim);
990  n &= ((1<<2*Log2Dim)-1);
991  xyz.setY(n >> Log2Dim);
992  xyz.setZ(n & ((1<<Log2Dim)-1));
993 }
994 
995 
996 template<typename T, Index Log2Dim>
997 inline Coord
999 {
1000  Coord local;
1001  this->offset2coord(n, local);
1002  return Coord(local + this->getOrigin());
1003 }
1004 
1005 
1007 
1008 
1009 template<typename ValueT, Index Log2Dim>
1010 inline const ValueT&
1012 {
1013  return this->getValue(LeafNode::coord2offset(xyz));
1014 }
1015 
1016 template<typename ValueT, Index Log2Dim>
1017 inline const ValueT&
1019 {
1020  assert(offset < SIZE);
1021  return mBuffer[offset];
1022 }
1023 
1024 
1025 template<typename T, Index Log2Dim>
1026 inline bool
1028 {
1029  return this->probeValue(LeafNode::coord2offset(xyz), val);
1030 }
1031 
1032 template<typename T, Index Log2Dim>
1033 inline bool
1035 {
1036  assert(offset < SIZE);
1037  val = mBuffer[offset];
1038  return mValueMask.isOn(offset);
1039 }
1040 
1041 
1042 template<typename T, Index Log2Dim>
1043 inline void
1045 {
1046  this->setValueOff(LeafNode::coord2offset(xyz), val);
1047 }
1048 
1049 template<typename T, Index Log2Dim>
1050 inline void
1052 {
1053  assert(offset < SIZE);
1054  mBuffer[offset] = val;
1055  mValueMask.setOff(offset);
1056 }
1057 
1058 
1059 template<typename T, Index Log2Dim>
1060 inline void
1062 {
1063  mValueMask.set(this->coord2offset(xyz), on);
1064 }
1065 
1066 
1067 template<typename T, Index Log2Dim>
1068 inline void
1070 {
1071  for (typename NodeMaskType::OnIterator iter = mValueMask.beginOn(); iter; ++iter) {
1072  mBuffer[iter.pos()] += val;
1073  }
1074 }
1075 
1076 
1077 template<typename T, Index Log2Dim>
1078 inline void
1080 {
1081  for (typename NodeMaskType::OnIterator iter = mValueMask.beginOn(); iter; ++iter) {
1082  mBuffer[iter.pos()] *= scale;
1083  }
1084 }
1085 
1086 
1088 
1089 
1090 template<typename T, Index Log2Dim>
1091 inline void
1092 LeafNode<T, Log2Dim>::fill(const CoordBBox& bbox, const ValueType& value, bool active)
1093 {
1094  for (Int32 x = bbox.min().x(); x <= bbox.max().x(); ++x) {
1095  const Index offsetX = (x&DIM-1u)<<2*Log2Dim;
1096  for (Int32 y = bbox.min().y(); y <= bbox.max().y(); ++y) {
1097  const Index offsetXY = offsetX + ((y&DIM-1u)<< Log2Dim);
1098  for (Int32 z = bbox.min().z(); z <= bbox.max().z(); ++z) {
1099  const Index offset = offsetXY + (z&DIM-1u);
1100  mBuffer[offset] = value;
1101  mValueMask.set(offset, active);
1102  }
1103  }
1104  }
1105 }
1106 
1107 template<typename T, Index Log2Dim>
1108 inline void
1110 {
1111  mBuffer.fill(value);
1112 }
1113 
1114 template<typename T, Index Log2Dim>
1115 inline void
1116 LeafNode<T, Log2Dim>::fill(const ValueType& value, bool active)
1117 {
1118  mBuffer.fill(value);
1119  mValueMask.set(active);
1120 }
1121 
1123 
1124 template<typename T, Index Log2Dim>
1125 template<typename DenseT>
1126 inline void
1127 LeafNode<T, Log2Dim>::copyToDense(const CoordBBox& bbox, DenseT& dense) const
1128 {
1129  const size_t xStride = dense.xStride(), yStride = dense.yStride();// zStride=1
1130  const Coord& min = dense.bbox().min();
1131  T* t0 = dense.data() + bbox.min()[2]-min[2];//target array
1132  const T* s0 = &mBuffer[bbox.min()[2]&DIM-1u];//source array
1133  for (Int32 x = bbox.min()[0], ex=bbox.max()[0]+1; x<ex; ++x) {
1134  T* t1 = t0 + xStride*(x-min[0]);
1135  const T* s1 = s0 + ((x&DIM-1u)<<2*Log2Dim);
1136  for (Int32 y = bbox.min()[1], ey=bbox.max()[1]+1; y<ey; ++y) {
1137  T* t2 = t1 + yStride*(y-min[1]);
1138  const T* s2 = s1 + ((y&DIM-1u)<<Log2Dim);
1139  for (Int32 z = bbox.min()[2], ez=bbox.max()[2]+1; z<ez ; ++z) *t2++ = *s2++;
1140  }
1141  }
1142 }
1143 
1144 template<typename T, Index Log2Dim>
1145 template<typename DenseT>
1146 inline void
1147 LeafNode<T, Log2Dim>::copyFromDense(const CoordBBox& bbox, const DenseT& dense,
1148  const ValueType& background, const ValueType& tolerance)
1149 {
1150  const size_t xStride = dense.xStride(), yStride = dense.yStride();// zStride=1
1151  const Coord& min = dense.bbox().min();
1152 
1153  const ValueType* s0 = dense.data() + bbox.min()[2]-min[2];//source
1154  const Int32 n0 = bbox.min()[2]&DIM-1u;
1155  for (Int32 x = bbox.min()[0], ex=bbox.max()[0]+1; x<ex; ++x) {
1156  const ValueType* s1 = s0 + xStride*(x-min[0]);
1157  const Int32 n1 = n0 + ((x&DIM-1u)<<2*LOG2DIM);
1158  for (Int32 y = bbox.min()[1], ey=bbox.max()[1]+1; y<ey; ++y) {
1159  const ValueType* s2 = s1 + yStride*(y-min[1]);
1160  Int32 n2 = n1 + ((y&DIM-1u)<<LOG2DIM) ;
1161  for (Int32 z = bbox.min()[2], ez=bbox.max()[2]+1; z<ez ; ++z, ++n2, ++s2) {
1162  if (math::isApproxEqual(background, *s2, tolerance)) {
1163  mValueMask.setOff(n2);
1164  mBuffer[n2] = background;
1165  } else {
1166  mValueMask.setOn(n2);
1167  mBuffer[n2] = *s2;
1168  }
1169  }
1170  }
1171  }
1172 }
1173 
1175 
1176 
1177 template<typename T, Index Log2Dim>
1178 inline void
1179 LeafNode<T, Log2Dim>::readTopology(std::istream& is, bool /*fromHalf*/)
1180 {
1181  mValueMask.load(is);
1182 }
1183 
1184 
1185 template<typename T, Index Log2Dim>
1186 inline void
1187 LeafNode<T, Log2Dim>::writeTopology(std::ostream& os, bool /*toHalf*/) const
1188 {
1189  mValueMask.save(os);
1190 }
1191 
1192 
1194 
1195 
1196 template<typename T, Index Log2Dim>
1197 inline void
1198 LeafNode<T,Log2Dim>::readBuffers(std::istream& is, bool fromHalf)
1199 {
1200  // Read in the value mask.
1201  mValueMask.load(is);
1202 
1203  int8_t numBuffers = 1;
1205  // Read in the origin.
1206  is.read(reinterpret_cast<char*>(&mOrigin), sizeof(Coord::ValueType) * 3);
1207 
1208  // Read in the number of buffers, which should now always be one.
1209  is.read(reinterpret_cast<char*>(&numBuffers), sizeof(int8_t));
1210  }
1211 
1212  io::readCompressedValues(is, mBuffer.mData, SIZE, mValueMask, fromHalf);
1213 
1214  if (numBuffers > 1) {
1215  // Read in and discard auxiliary buffers that were created with earlier
1216  // versions of the library. (Auxiliary buffers are not mask compressed.)
1217  const bool zipped = io::getDataCompression(is) & io::COMPRESS_ZIP;
1218  Buffer temp;
1219  for (int i = 1; i < numBuffers; ++i) {
1220  if (fromHalf) {
1221  io::HalfReader<io::RealToHalf<T>::isReal, T>::read(is, temp.mData, SIZE, zipped);
1222  } else {
1223  io::readData<T>(is, temp.mData, SIZE, zipped);
1224  }
1225  }
1226  }
1227 }
1228 
1229 
1230 template<typename T, Index Log2Dim>
1231 inline void
1232 LeafNode<T, Log2Dim>::writeBuffers(std::ostream& os, bool toHalf) const
1233 {
1234  // Write out the value mask.
1235  mValueMask.save(os);
1236 
1237  io::writeCompressedValues(os, mBuffer.mData, SIZE,
1238  mValueMask, /*childMask=*/NodeMaskType(), toHalf);
1239 }
1240 
1241 
1243 
1244 
1245 template<typename T, Index Log2Dim>
1246 inline bool
1248 {
1249  return mOrigin == other.mOrigin &&
1250  mValueMask == other.mValueMask &&
1251  mBuffer == other.mBuffer;
1252 }
1253 
1254 
1255 template<typename T, Index Log2Dim>
1256 inline Index64
1258 {
1259  return mBuffer.memUsage() + sizeof(mOrigin) + mValueMask.memUsage();
1260 }
1261 
1262 
1263 template<typename T, Index Log2Dim>
1264 inline void
1266 {
1267  const CoordBBox this_bbox = this->getNodeBoundingBox();
1268  if (bbox.isInside(this_bbox)) {
1269  // nothing to do
1270  } else if (this->isDense()) {
1271  bbox.expand(this_bbox);
1272  } else {
1273  for (ValueOnCIter iter=this->cbeginValueOn(); iter; ++iter) bbox.expand(iter.getCoord());
1274  }
1275 }
1276 
1277 
1278 template<typename T, Index Log2Dim>
1279 template<typename OtherType, Index OtherLog2Dim>
1280 inline bool
1282 {
1283  assert(other);
1284  return (Log2Dim == OtherLog2Dim && mValueMask == other->getValueMask());
1285 }
1286 
1287 
1288 template<typename T, Index Log2Dim>
1289 inline bool
1291  bool& state, const ValueType& tolerance) const
1292 {
1293  if (!mValueMask.isOn() && !mValueMask.isOff()) return false;
1294 
1295  state = mValueMask.isOn();
1296 
1297  bool allEqual = true;
1298  const T value = mBuffer[0];
1299  for (Index i = 1; allEqual && i < SIZE; ++i) {
1301  allEqual = math::isApproxEqual(mBuffer[i], value, tolerance);
1302  }
1303  if (allEqual) constValue = value;
1304  return allEqual;
1305 }
1306 
1307 template<typename T, Index Log2Dim>
1308 inline void
1310 {
1311  this->signedFloodFill(background, negative(background));
1312 }
1313 
1314 template<typename T, Index Log2Dim>
1315 inline void
1317  const ValueType& insideValue)
1318 {
1319  const Index first = mValueMask.findFirstOn();
1320  if (first < SIZE) {
1321  bool xInside = math::isNegative(mBuffer[first]), yInside = xInside, zInside = xInside;
1322  for (Index x = 0; x != (1 << Log2Dim); ++x) {
1323  const Index x00 = x << (2 * Log2Dim);
1324  if (mValueMask.isOn(x00)) {
1325  xInside = math::isNegative(mBuffer[x00]); // element(x, 0, 0)
1326  }
1327  yInside = xInside;
1328  for (Index y = 0; y != (1 << Log2Dim); ++y) {
1329  const Index xy0 = x00 + (y << Log2Dim);
1330  if (mValueMask.isOn(xy0)) {
1331  yInside = math::isNegative(mBuffer[xy0]); // element(x, y, 0)
1332  }
1333  zInside = yInside;
1334  for (Index z = 0; z != (1 << Log2Dim); ++z) {
1335  const Index xyz = xy0 + z; // element(x, y, z)
1336  if (mValueMask.isOn(xyz)) {
1337  zInside = math::isNegative(mBuffer[xyz]);
1338  } else {
1339  mBuffer[xyz] = zInside ? insideValue : outsideValue;
1340  }
1341  }
1342  }
1343  }
1344  } else {// if no active voxels exist simply use the sign of the first value
1345  mBuffer.fill(math::isNegative(mBuffer[0]) ? insideValue : outsideValue);
1346  }
1347 }
1348 
1349 
1350 template<typename T, Index Log2Dim>
1351 inline void
1353  const ValueType& newBackground)
1354 {
1355  typename NodeMaskType::OffIterator iter;
1356  // For all inactive values...
1357  for (iter = this->mValueMask.beginOff(); iter; ++iter) {
1358  ValueType &inactiveValue = mBuffer[iter.pos()];
1359  if (math::isApproxEqual(inactiveValue, oldBackground)) {
1360  inactiveValue = newBackground;
1361  } else if (math::isApproxEqual(inactiveValue, negative(oldBackground))) {
1362  inactiveValue = negative(newBackground);
1363  }
1364  }
1365 }
1366 
1367 
1368 template<typename T, Index Log2Dim>
1369 inline void
1371 {
1372  typename NodeMaskType::OnIterator iter = other.mValueMask.beginOn();
1373  for (; iter; ++iter) {
1374  const Index n = iter.pos();
1375  if (mValueMask.isOn(n)) continue;
1376  mBuffer[n] = other.mBuffer[n];
1377  mValueMask.setOn(n);
1378  }
1379 }
1380 
1381 
1382 template<typename T, Index Log2Dim>
1383 template<typename OtherType>
1384 inline void
1386 {
1387  mValueMask |= other.getValueMask();
1388 }
1389 
1390 template<typename T, Index Log2Dim>
1391 template<typename OtherType>
1392 inline void
1394  const ValueType&)
1395 {
1396  mValueMask &= other.getValueMask();
1397 }
1398 
1399 template<typename T, Index Log2Dim>
1400 template<typename OtherType>
1401 inline void
1403  const ValueType&)
1404 {
1405  mValueMask &= !other.getValueMask();
1406 }
1407 
1408 template<typename T, Index Log2Dim>
1409 inline void
1411 {
1412  for (Index i = 0; i < SIZE; ++i) {
1413  mBuffer[i] = -mBuffer[i];
1414  }
1415 }
1416 
1417 
1419 
1420 
1421 template<typename T, Index Log2Dim>
1422 template<typename CombineOp>
1423 inline void
1424 LeafNode<T, Log2Dim>::combine(const LeafNode& other, CombineOp& op)
1425 {
1426  CombineArgs<T> args;
1427  for (Index i = 0; i < SIZE; ++i) {
1428  op(args.setARef(mBuffer[i])
1429  .setAIsActive(mValueMask.isOn(i))
1430  .setBRef(other.mBuffer[i])
1431  .setBIsActive(other.mValueMask.isOn(i))
1432  .setResultRef(mBuffer[i]));
1433  mValueMask.set(i, args.resultIsActive());
1434  }
1435 }
1436 
1437 
1438 template<typename T, Index Log2Dim>
1439 template<typename CombineOp>
1440 inline void
1441 LeafNode<T, Log2Dim>::combine(const ValueType& value, bool valueIsActive, CombineOp& op)
1442 {
1443  CombineArgs<T> args;
1444  args.setBRef(value).setBIsActive(valueIsActive);
1445  for (Index i = 0; i < SIZE; ++i) {
1446  op(args.setARef(mBuffer[i])
1447  .setAIsActive(mValueMask.isOn(i))
1448  .setResultRef(mBuffer[i]));
1449  mValueMask.set(i, args.resultIsActive());
1450  }
1451 }
1452 
1453 
1455 
1456 
1457 template<typename T, Index Log2Dim>
1458 template<typename CombineOp>
1459 inline void
1461  bool valueIsActive, CombineOp& op)
1462 {
1463  CombineArgs<T> args;
1464  args.setBRef(value).setBIsActive(valueIsActive);
1465  for (Index i = 0; i < SIZE; ++i) {
1466  op(args.setARef(other.mBuffer[i])
1467  .setAIsActive(other.mValueMask.isOn(i))
1468  .setResultRef(mBuffer[i]));
1469  mValueMask.set(i, args.resultIsActive());
1470  }
1471 }
1472 
1473 
1474 template<typename T, Index Log2Dim>
1475 template<typename CombineOp>
1476 inline void
1478  bool valueIsActive, CombineOp& op)
1479 {
1480  CombineArgs<T> args;
1481  args.setARef(value).setAIsActive(valueIsActive);
1482  for (Index i = 0; i < SIZE; ++i) {
1483  op(args.setBRef(other.mBuffer[i])
1484  .setBIsActive(other.mValueMask.isOn(i))
1485  .setResultRef(mBuffer[i]));
1486  mValueMask.set(i, args.resultIsActive());
1487  }
1488 }
1489 
1490 
1491 template<typename T, Index Log2Dim>
1492 template<typename CombineOp>
1493 inline void
1494 LeafNode<T, Log2Dim>::combine2(const LeafNode& b0, const LeafNode& b1, CombineOp& op)
1495 {
1496  CombineArgs<T> args;
1497  for (Index i = 0; i < SIZE; ++i) {
1498  mValueMask.set(i, b0.mValueMask.isOn(i) || b1.mValueMask.isOn(i));
1499  op(args.setARef(b0.mBuffer[i])
1500  .setAIsActive(b0.mValueMask.isOn(i))
1501  .setBRef(b1.mBuffer[i])
1502  .setBIsActive(b1.mValueMask.isOn(i))
1503  .setResultRef(mBuffer[i]));
1504  mValueMask.set(i, args.resultIsActive());
1505  }
1506 }
1507 
1508 
1510 
1511 
1512 template<typename T, Index Log2Dim>
1513 template<typename BBoxOp>
1514 inline void
1516 {
1517  if (op.template descent<LEVEL>()) {
1518  for (ValueOnCIter i=this->cbeginValueOn(); i; ++i) {
1519 #ifdef _MSC_VER
1520  op.operator()<LEVEL>(CoordBBox::createCube(i.getCoord(), 1));
1521 #else
1522  op.template operator()<LEVEL>(CoordBBox::createCube(i.getCoord(), 1));
1523 #endif
1524  }
1525  } else {
1526 #ifdef _MSC_VER
1527  op.operator()<LEVEL>(this->getNodeBoundingBox());
1528 #else
1529  op.template operator()<LEVEL>(this->getNodeBoundingBox());
1530 #endif
1531  }
1532 }
1533 
1534 
1535 template<typename T, Index Log2Dim>
1536 template<typename VisitorOp>
1537 inline void
1539 {
1540  doVisit<LeafNode, VisitorOp, ChildAllIter>(*this, op);
1541 }
1542 
1543 
1544 template<typename T, Index Log2Dim>
1545 template<typename VisitorOp>
1546 inline void
1547 LeafNode<T, Log2Dim>::visit(VisitorOp& op) const
1548 {
1549  doVisit<const LeafNode, VisitorOp, ChildAllCIter>(*this, op);
1550 }
1551 
1552 
1553 template<typename T, Index Log2Dim>
1554 template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
1555 inline void
1556 LeafNode<T, Log2Dim>::doVisit(NodeT& self, VisitorOp& op)
1557 {
1558  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1559  op(iter);
1560  }
1561 }
1562 
1563 
1565 
1566 
1567 template<typename T, Index Log2Dim>
1568 template<typename OtherLeafNodeType, typename VisitorOp>
1569 inline void
1570 LeafNode<T, Log2Dim>::visit2Node(OtherLeafNodeType& other, VisitorOp& op)
1571 {
1572  doVisit2Node<LeafNode, OtherLeafNodeType, VisitorOp, ChildAllIter,
1573  typename OtherLeafNodeType::ChildAllIter>(*this, other, op);
1574 }
1575 
1576 
1577 template<typename T, Index Log2Dim>
1578 template<typename OtherLeafNodeType, typename VisitorOp>
1579 inline void
1580 LeafNode<T, Log2Dim>::visit2Node(OtherLeafNodeType& other, VisitorOp& op) const
1581 {
1582  doVisit2Node<const LeafNode, OtherLeafNodeType, VisitorOp, ChildAllCIter,
1583  typename OtherLeafNodeType::ChildAllCIter>(*this, other, op);
1584 }
1585 
1586 
1587 template<typename T, Index Log2Dim>
1588 template<
1589  typename NodeT,
1590  typename OtherNodeT,
1591  typename VisitorOp,
1592  typename ChildAllIterT,
1593  typename OtherChildAllIterT>
1594 inline void
1595 LeafNode<T, Log2Dim>::doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp& op)
1596 {
1597  // Allow the two nodes to have different ValueTypes, but not different dimensions.
1598  BOOST_STATIC_ASSERT(OtherNodeT::SIZE == NodeT::SIZE);
1599  BOOST_STATIC_ASSERT(OtherNodeT::LEVEL == NodeT::LEVEL);
1600 
1601  ChildAllIterT iter = self.beginChildAll();
1602  OtherChildAllIterT otherIter = other.beginChildAll();
1603 
1604  for ( ; iter && otherIter; ++iter, ++otherIter) {
1605  op(iter, otherIter);
1606  }
1607 }
1608 
1609 
1611 
1612 
1613 template<typename T, Index Log2Dim>
1614 template<typename IterT, typename VisitorOp>
1615 inline void
1616 LeafNode<T, Log2Dim>::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS)
1617 {
1618  doVisit2<LeafNode, VisitorOp, ChildAllIter, IterT>(
1619  *this, otherIter, op, otherIsLHS);
1620 }
1621 
1622 
1623 template<typename T, Index Log2Dim>
1624 template<typename IterT, typename VisitorOp>
1625 inline void
1626 LeafNode<T, Log2Dim>::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS) const
1627 {
1628  doVisit2<const LeafNode, VisitorOp, ChildAllCIter, IterT>(
1629  *this, otherIter, op, otherIsLHS);
1630 }
1631 
1632 
1633 template<typename T, Index Log2Dim>
1634 template<
1635  typename NodeT,
1636  typename VisitorOp,
1637  typename ChildAllIterT,
1638  typename OtherChildAllIterT>
1639 inline void
1640 LeafNode<T, Log2Dim>::doVisit2(NodeT& self, OtherChildAllIterT& otherIter,
1641  VisitorOp& op, bool otherIsLHS)
1642 {
1643  if (!otherIter) return;
1644 
1645  if (otherIsLHS) {
1646  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1647  op(otherIter, iter);
1648  }
1649  } else {
1650  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1651  op(iter, otherIter);
1652  }
1653  }
1654 }
1655 
1656 
1658 
1659 
1660 template<typename T, Index Log2Dim>
1661 inline std::ostream&
1662 operator<<(std::ostream& os, const typename LeafNode<T, Log2Dim>::Buffer& buf)
1663 {
1664  for (Index32 i = 0, N = buf.size(); i < N; ++i) os << buf.mData[i] << ", ";
1665  return os;
1666 }
1667 
1668 } // namespace tree
1669 } // namespace OPENVDB_VERSION_NAME
1670 } // namespace openvdb
1671 
1672 
1674 
1675 
1676 // Specialization for LeafNodes of type bool
1677 #include "LeafNodeBool.h"
1678 
1679 #endif // OPENVDB_TREE_LEAFNODE_HAS_BEEN_INCLUDED
1680 
1681 // Copyright (c) 2012-2013 DreamWorks Animation LLC
1682 // All rights reserved. This software is distributed under the
1683 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )