OpenVDB  1.2.0
LeafNodeBool.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_LEAFNODEBOOL_HAS_BEEN_INCLUDED
32 #define OPENVDB_TREE_LEAFNODEBOOL_HAS_BEEN_INCLUDED
33 
34 #include <iostream>
35 #include <boost/shared_ptr.hpp>
36 #include <boost/shared_array.hpp>
37 #include <boost/static_assert.hpp>
38 #include <openvdb/Types.h>
39 #include <openvdb/io/Compression.h> // for io::readData(), etc.
40 #include <openvdb/util/NodeMasks.h>
41 #include "LeafNode.h"
42 #include "Iterator.h"
43 #include "Util.h"
44 
45 
46 namespace openvdb {
48 namespace OPENVDB_VERSION_NAME {
49 namespace tree {
50 
53 template<Index Log2Dim>
54 class LeafNode<bool, Log2Dim>
55 {
56 public:
58  typedef boost::shared_ptr<LeafNodeType> Ptr;
59  typedef bool ValueType;
61 
62  // These static declarations must be on separate lines to avoid VC9 compiler errors.
63  static const Index LOG2DIM = Log2Dim; // needed by parent nodes
64  static const Index TOTAL = Log2Dim; // needed by parent nodes
65  static const Index DIM = 1 << TOTAL; // dimension along one coordinate direction
66  static const Index NUM_VALUES = 1 << 3 * Log2Dim;
67  static const Index NUM_VOXELS = NUM_VALUES; // total number of voxels represented by this node
68  static const Index SIZE = NUM_VALUES;
69  static const Index LEVEL = 0; // level 0 = leaf
70 
73  template<typename ValueType>
74  struct ValueConverter { typedef LeafNode<ValueType, Log2Dim> Type; };
75 
76  class Buffer
77  {
78  public:
79  Buffer() {}
80  Buffer(bool on) : mData(on) {}
81  Buffer(const NodeMaskType& other): mData(other) {}
82  Buffer(const Buffer& other): mData(other.mData) {}
83  ~Buffer() {}
84  void fill(bool val) { mData.set(val); }
85  Buffer& operator=(const Buffer& b) { if (&b != this) { mData = b.mData; } return *this; }
86 
87  const bool& getValue(Index i) const
88  {
89  assert(i < SIZE);
90  return mData.isOn(i) ? LeafNode::sOn : LeafNode::sOff;
91  }
92  const bool& operator[](Index i) const { return this->getValue(i); }
93 
94  bool operator==(const Buffer& other) const { return mData == other.mData; }
95  bool operator!=(const Buffer& other) const { return mData != other.mData; }
96 
97  void setValue(Index i, bool val) { assert(i < SIZE); mData.set(i, val); }
98 
99  void swap(Buffer& other) { if (&other != this) std::swap(mData, other.mData); }
100 
101  Index memUsage() const { return mData.memUsage(); }
102  static Index size() { return SIZE; }
103 
104  private:
105  friend class ::TestLeaf;
106  // Allow the parent LeafNode to access this Buffer's bit mask.
107  friend class LeafNode;
108 
109  NodeMaskType mData;
110  }; // class Buffer
111 
112 
114  LeafNode();
115 
120  explicit LeafNode(const Coord& xyz, bool value = false, bool active = false);
121 
123  LeafNode(const LeafNode&);
124 
126  template<typename ValueType>
128 
131  template<typename ValueType>
133  bool offValue, bool onValue, TopologyCopy);
134  template<typename ValueType>
136  bool background, TopologyCopy);
137 
139  ~LeafNode();
140 
141  //
142  // Statistics
143  //
145  static Index log2dim() { return Log2Dim; }
147  static Index dim() { return DIM; }
148  static Index size() { return SIZE; }
149  static Index numValues() { return SIZE; }
150  static Index getLevel() { return LEVEL; }
151  static void getNodeLog2Dims(std::vector<Index>& dims) { dims.push_back(Log2Dim); }
152  static Index getChildDim() { return 1; }
153 
154  static Index32 leafCount() { return 1; }
155  static Index32 nonLeafCount() { return 0; }
156 
158  Index64 onVoxelCount() const { return mValueMask.countOn(); }
160  Index64 offVoxelCount() const { return mValueMask.countOff(); }
161  Index64 onLeafVoxelCount() const { return onVoxelCount(); }
162  Index64 offLeafVoxelCount() const { return offVoxelCount(); }
163 
165  bool isEmpty() const { return mValueMask.isOff(); }
167  bool isDense() const { return mValueMask.isOn(); }
168 
170  Index64 memUsage() const;
171 
174  void evalActiveVoxelBoundingBox(CoordBBox& bbox) const;
175 
178  CoordBBox getNodeBoundingBox() const { return CoordBBox::createCube(mOrigin, DIM); }
179 
181  void setOrigin(const Coord& origin) { mOrigin = origin; }
183  const Coord& origin() const { return mOrigin; }
185  const Coord& getOrigin() const { return mOrigin; }
186  void getOrigin(Coord& origin) const { origin = mOrigin; }
187  void getOrigin(Int32& x, Int32& y, Int32& z) const { mOrigin.asXYZ(x, y, z); }
189 
191  static Index coord2offset(const Coord& xyz);
194  static Coord offset2coord(Index n);
196  Coord offset2globalCoord(Index n) const;
197 
199  std::string str() const;
200 
203  template<typename OtherType, Index OtherLog2Dim>
204  bool hasSameTopology(const LeafNode<OtherType, OtherLog2Dim>* other) const;
205 
207  bool operator==(const LeafNode&) const;
208  bool operator!=(const LeafNode&) const;
209 
210  //
211  // Buffer management
212  //
215  void swap(Buffer& other) { mBuffer.swap(other); }
216  const Buffer& buffer() const { return mBuffer; }
217  Buffer& buffer() { return mBuffer; }
218 
219  //
220  // I/O methods
221  //
223  void readTopology(std::istream&, bool fromHalf = false);
225  void writeTopology(std::ostream&, bool toHalf = false) const;
226 
228  void readBuffers(std::istream&, bool fromHalf = false);
230  void writeBuffers(std::ostream&, bool toHalf = false) const;
231 
232  //
233  // Accessor methods
234  //
236  const bool& getValue(const Coord& xyz) const;
238  const bool& getValue(Index offset) const;
239 
243  bool probeValue(const Coord& xyz, bool& val) const;
244 
246  static Index getValueLevel(const Coord&) { return LEVEL; }
247 
249  void setActiveState(const Coord& xyz, bool on);
250 
252  void setValueOff(const Coord& xyz) { mValueMask.setOff(this->coord2offset(xyz)); }
254  void setValueOff(Index offset) { assert(offset < SIZE); mValueMask.setOff(offset); }
256  void setValueOff(const Coord& xyz, bool val);
257 
259  void setValueOn(const Coord& xyz) { mValueMask.setOn(this->coord2offset(xyz)); }
261  void setValueOn(Index offset) { assert(offset < SIZE); mValueMask.setOn(offset); }
263  void setValueOn(const Coord& xyz, bool val);
265  void setValue(const Coord& xyz, bool val) { this->setValueOn(xyz, val); };
266 
269  void setValueOnMin(const Coord& xyz, bool val);
272  void setValueOnMax(const Coord& xyz, bool val);
275  void setValueOnSum(const Coord& xyz, bool val);
276 
279  void setValueOnly(const Coord& xyz, bool val) {
280  this->setValueOnly(LeafNode::coord2offset(xyz), val);
281  }
284  void setValueOnly(Index offset, bool val) { assert(offset<SIZE); mBuffer.setValue(offset,val); }
285 
287  OPENVDB_DEPRECATED void addValue(bool val);
289  OPENVDB_DEPRECATED void scaleValue(bool scale);
290 
292  void setValuesOn() { mValueMask.setOn(); }
294  void setValuesOff() { mValueMask.setOff(); }
295 
297  bool isValueOn(const Coord& xyz) const { return mValueMask.isOn(this->coord2offset(xyz)); }
299  bool isValueOn(Index offset) const { assert(offset < SIZE); return mValueMask.isOn(offset); }
300 
302  static bool hasActiveTiles() { return false; }
303 
306  void fill(const CoordBBox& bbox, bool value, bool active = true);
307 
309  void fill(const bool& value);
310 
312  void fill(const bool& value, bool active);
313 
325  template<typename DenseT>
326  void copyToDense(const CoordBBox& bbox, DenseT& dense) const;
327 
344  template<typename DenseT>
345  void copyFromDense(const CoordBBox& bbox, const DenseT& dense, bool background, bool tolerance);
346 
349  template<typename AccessorT>
350  const bool& getValueAndCache(const Coord& xyz, AccessorT&) const {return this->getValue(xyz);}
351 
354  template<typename AccessorT>
355  bool isValueOnAndCache(const Coord& xyz, AccessorT&) const { return this->isValueOn(xyz); }
356 
359  template<typename AccessorT>
360  void setValueAndCache(const Coord& xyz, bool val, AccessorT&) { this->setValueOn(xyz, val); }
361 
365  template<typename AccessorT>
366  void setValueOnlyAndCache(const Coord& xyz, bool val, AccessorT&) {this->setValueOnly(xyz,val);}
367 
370  template<typename AccessorT>
371  void setValueOffAndCache(const Coord& xyz, bool value, AccessorT&)
372  {
373  this->setValueOff(xyz, value);
374  }
375 
379  template<typename AccessorT>
380  void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&)
381  {
382  this->setActiveState(xyz, on);
383  }
384 
388  template<typename AccessorT>
389  bool probeValueAndCache(const Coord& xyz, bool& val, AccessorT&) const
390  {
391  return this->probeValue(xyz, val);
392  }
393 
396  template<typename AccessorT>
397  static Index getValueLevelAndCache(const Coord&, AccessorT&) { return LEVEL; }
398 
402  const bool& getFirstValue() const { if (mValueMask.isOn(0)) return sOn; else return sOff; }
406  const bool& getLastValue() const { if (mValueMask.isOn(SIZE-1)) return sOn; else return sOff; }
407 
411  bool isConstant(bool& constValue, bool& state, bool tolerance = 0) const;
413  bool isInactive() const { return mValueMask.isOff(); }
414 
415  void resetBackground(bool oldBackground, bool newBackground);
416 
417  void negate() { mBuffer.mData.toggle(); }
418 
419  void merge(const LeafNode& other);
420 
422 
429  template<typename OtherType>
430  void topologyUnion(const LeafNode<OtherType, Log2Dim>& other);
431 
443  template<typename OtherType>
444  void topologyIntersection(const LeafNode<OtherType, Log2Dim>& other, const bool&);
445 
457  template<typename OtherType>
458  void topologyDifference(const LeafNode<OtherType, Log2Dim>& other, const bool&);
459 
460  template<typename CombineOp>
461  void combine(const LeafNode& other, CombineOp& op);
462  template<typename CombineOp>
463  void combine(bool, bool valueIsActive, CombineOp& op);
464 
465  template<typename CombineOp>
466  void combine2(const LeafNode& other, bool, bool valueIsActive, CombineOp&);
467  template<typename CombineOp>
468  void combine2(bool, const LeafNode& other, bool valueIsActive, CombineOp&);
469  template<typename CombineOp>
470  void combine2(const LeafNode& b0, const LeafNode& b1, CombineOp&);
471 
476  template<typename BBoxOp> void visitActiveBBox(BBoxOp&) const;
477 
478  template<typename VisitorOp> void visit(VisitorOp&);
479  template<typename VisitorOp> void visit(VisitorOp&) const;
480 
481  template<typename OtherLeafNodeType, typename VisitorOp>
482  void visit2Node(OtherLeafNodeType& other, VisitorOp&);
483  template<typename OtherLeafNodeType, typename VisitorOp>
484  void visit2Node(OtherLeafNodeType& other, VisitorOp&) const;
485  template<typename IterT, typename VisitorOp>
486  void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false);
487  template<typename IterT, typename VisitorOp>
488  void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false) const;
489 
491  void signedFloodFill(bool) {}
494  void signedFloodFill(bool, bool) {}
495  template<typename PruneOp> void pruneOp(PruneOp&) {}
496  void prune(const ValueType& /*tolerance*/ = zeroVal<ValueType>()) {}
497  void pruneInactive(const ValueType&) {}
498  void addLeaf(LeafNode*) {}
499  template<typename AccessorT>
500  void addLeafAndCache(LeafNode*, AccessorT&) {}
501  template<typename NodeT>
502  NodeT* stealNode(const Coord&, const ValueType&, bool) { return NULL; }
503  template<typename NodeT>
504  NodeT* probeNode(const Coord&) { return NULL; }
505  template<typename NodeT>
506  const NodeT* probeConstNode(const Coord&) const { return NULL; }
507  void addTile(Index, const Coord&, bool, bool) {}
508  template<typename AccessorT>
509  void addTileAndCache(Index, const Coord&, const ValueType&, bool, AccessorT&) {}
511 
513  LeafNode* touchLeaf(const Coord&) { return this; }
515  template<typename AccessorT>
516  LeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; }
517  LeafNode* probeLeaf(const Coord&) { return this; }
518  template<typename AccessorT>
519  LeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; }
520  template<typename NodeT, typename AccessorT>
521  NodeT* probeNodeAndCache(const Coord&, AccessorT&)
522  {
524  if (!(boost::is_same<NodeT,LeafNode>::value)) return NULL;
525  return reinterpret_cast<NodeT*>(this);
527  }
529 
530  const LeafNode* probeLeaf(const Coord&) const { return this; }
532  template<typename AccessorT>
533  const LeafNode* probeLeafAndCache(const Coord&, AccessorT&) const { return this; }
534  const LeafNode* probeConstLeaf(const Coord&) const { return this; }
535  template<typename AccessorT>
536  const LeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const { return this; }
537  template<typename NodeT, typename AccessorT>
538  const NodeT* probeConstNodeAndCache(const Coord&, AccessorT&) const
539  {
541  if (!(boost::is_same<NodeT,LeafNode>::value)) return NULL;
542  return reinterpret_cast<const NodeT*>(this);
544  }
546  template<typename NodeT>
548  static bool hasNodeType() { return (boost::is_same<NodeT,LeafNode>::value); }
549 
550  void merge(const LeafNode& other, bool, bool) { this->merge(other); }
551 
552  //
553  // Iterators
554  //
555 protected:
559 
560  template<typename MaskIterT, typename NodeT, typename ValueT>
561  struct ValueIter:
562  // Derives from SparseIteratorBase, but can also be used as a dense iterator,
563  // if MaskIterT is a dense mask iterator type.
564  public SparseIteratorBase<MaskIterT, ValueIter<MaskIterT, NodeT, ValueT>, NodeT, ValueT>
565  {
567 
569  ValueIter(const MaskIterT& iter, NodeT* parent): BaseT(iter, parent) {}
570 
571  const bool& getItem(Index pos) const { return this->parent().getValue(pos); }
572  const bool& getValue() const { return this->getItem(this->pos()); }
573 
574  // Note: setItem() can't be called on const iterators.
575  void setItem(Index pos, bool value) const { this->parent().setValueOnly(pos, value); }
576  // Note: setValue() can't be called on const iterators.
577  void setValue(bool value) const { this->setItem(this->pos(), value); }
578  };
579 
581  template<typename MaskIterT, typename NodeT>
582  struct ChildIter:
583  public SparseIteratorBase<MaskIterT, ChildIter<MaskIterT, NodeT>, NodeT, bool>
584  {
586  ChildIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase<
587  MaskIterT, ChildIter<MaskIterT, NodeT>, NodeT, bool>(iter, parent) {}
588  };
589 
590  template<typename NodeT, typename ValueT>
591  struct DenseIter: public DenseIteratorBase<
592  MaskDenseIter, DenseIter<NodeT, ValueT>, NodeT, /*ChildT=*/void, ValueT>
593  {
596 
598  DenseIter(const MaskDenseIter& iter, NodeT* parent): BaseT(iter, parent) {}
599 
600  bool getItem(Index pos, void*& child, NonConstValueT& value) const
601  {
602  value = this->parent().getValue(pos);
603  child = NULL;
604  return false; // no child
605  }
606 
607  // Note: setItem() can't be called on const iterators.
608  //void setItem(Index pos, void* child) const {}
609 
610  // Note: unsetItem() can't be called on const iterators.
611  void unsetItem(Index pos, const ValueT& val) const {this->parent().setValueOnly(pos, val);}
612  };
613 
614 public:
615  typedef ValueIter<MaskOnIter, LeafNode, bool> ValueOnIter;
616  typedef ValueIter<MaskOnIter, const LeafNode, const bool> ValueOnCIter;
617  typedef ValueIter<MaskOffIter, LeafNode, bool> ValueOffIter;
618  typedef ValueIter<MaskOffIter, const LeafNode, const bool> ValueOffCIter;
619  typedef ValueIter<MaskDenseIter, LeafNode, bool> ValueAllIter;
620  typedef ValueIter<MaskDenseIter, const LeafNode, const bool> ValueAllCIter;
621  typedef ChildIter<MaskOnIter, LeafNode> ChildOnIter;
622  typedef ChildIter<MaskOnIter, const LeafNode> ChildOnCIter;
623  typedef ChildIter<MaskOffIter, LeafNode> ChildOffIter;
624  typedef ChildIter<MaskOffIter, const LeafNode> ChildOffCIter;
625  typedef DenseIter<LeafNode, bool> ChildAllIter;
626  typedef DenseIter<const LeafNode, const bool> ChildAllCIter;
627 
628  ValueOnCIter cbeginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); }
629  ValueOnCIter beginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); }
630  ValueOnIter beginValueOn() { return ValueOnIter(mValueMask.beginOn(), this); }
631  ValueOffCIter cbeginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); }
632  ValueOffCIter beginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); }
633  ValueOffIter beginValueOff() { return ValueOffIter(mValueMask.beginOff(), this); }
634  ValueAllCIter cbeginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); }
635  ValueAllCIter beginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); }
636  ValueAllIter beginValueAll() { return ValueAllIter(mValueMask.beginDense(), this); }
637 
638  ValueOnCIter cendValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); }
639  ValueOnCIter endValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); }
640  ValueOnIter endValueOn() { return ValueOnIter(mValueMask.endOn(), this); }
641  ValueOffCIter cendValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); }
642  ValueOffCIter endValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); }
643  ValueOffIter endValueOff() { return ValueOffIter(mValueMask.endOff(), this); }
644  ValueAllCIter cendValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); }
645  ValueAllCIter endValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); }
646  ValueAllIter endValueAll() { return ValueAllIter(mValueMask.endDense(), this); }
647 
648  // Note that [c]beginChildOn() and [c]beginChildOff() actually return end iterators,
649  // because leaf nodes have no children.
650  ChildOnCIter cbeginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
651  ChildOnCIter beginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
652  ChildOnIter beginChildOn() { return ChildOnIter(mValueMask.endOn(), this); }
653  ChildOffCIter cbeginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
654  ChildOffCIter beginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
655  ChildOffIter beginChildOff() { return ChildOffIter(mValueMask.endOff(), this); }
656  ChildAllCIter cbeginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); }
657  ChildAllCIter beginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); }
658  ChildAllIter beginChildAll() { return ChildAllIter(mValueMask.beginDense(), this); }
659 
660  ChildOnCIter cendChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
661  ChildOnCIter endChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
662  ChildOnIter endChildOn() { return ChildOnIter(mValueMask.endOn(), this); }
663  ChildOffCIter cendChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
664  ChildOffCIter endChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
665  ChildOffIter endChildOff() { return ChildOffIter(mValueMask.endOff(), this); }
666  ChildAllCIter cendChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); }
667  ChildAllCIter endChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); }
668  ChildAllIter endChildAll() { return ChildAllIter(mValueMask.endDense(), this); }
669 
670  //
671  // Mask accessors
672  //
673  bool isValueMaskOn(Index n) const { return mValueMask.isOn(n); }
674  bool isValueMaskOn() const { return mValueMask.isOn(); }
675  bool isValueMaskOff(Index n) const { return mValueMask.isOff(n); }
676  bool isValueMaskOff() const { return mValueMask.isOff(); }
677  const NodeMaskType& getValueMask() const { return mValueMask; }
678  NodeMaskType& getValueMask() { return mValueMask; }
679  void setValueMask(const NodeMaskType& mask) { mValueMask = mask; }
680  bool isChildMaskOn(Index) const { return false; } // leaf nodes have no children
681  bool isChildMaskOff(Index) const { return true; }
682  bool isChildMaskOff() const { return true; }
683 protected:
684  void setValueMask(Index n, bool on) { mValueMask.set(n, on); }
685  void setValueMaskOn(Index n) { mValueMask.setOn(n); }
686  void setValueMaskOff(Index n) { mValueMask.setOff(n); }
687 
689  static void evalNodeOrigin(Coord& xyz) { xyz &= ~(DIM - 1); }
690 
691  template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
692  static inline void doVisit(NodeT&, VisitorOp&);
693 
694  template<typename NodeT, typename OtherNodeT, typename VisitorOp,
695  typename ChildAllIterT, typename OtherChildAllIterT>
696  static inline void doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp&);
697 
698  template<typename NodeT, typename VisitorOp,
699  typename ChildAllIterT, typename OtherChildAllIterT>
700  static inline void doVisit2(NodeT& self, OtherChildAllIterT&, VisitorOp&, bool otherIsLHS);
701 
702 
706  Buffer mBuffer;
709 
710  // These static declarations must be on separate lines to avoid VC9 compiler errors.
711  static const bool sOn;
712  static const bool sOff;
713 
714 private:
717  template<typename, Index> friend class LeafNode;
718 
719  friend struct ValueIter<MaskOnIter, LeafNode, bool>;
720  friend struct ValueIter<MaskOffIter, LeafNode, bool>;
721  friend struct ValueIter<MaskDenseIter, LeafNode, bool>;
722  friend struct ValueIter<MaskOnIter, const LeafNode, bool>;
723  friend struct ValueIter<MaskOffIter, const LeafNode, bool>;
724  friend struct ValueIter<MaskDenseIter, const LeafNode, bool>;
725 
727  friend class IteratorBase<MaskOnIter, LeafNode>;
733 
734  // Disallow copying.
735  LeafNode& operator=(const LeafNode&);
736 
737 }; // class LeafNode<bool>
738 
739 
744 template<Index Log2Dim> const bool LeafNode<bool, Log2Dim>::sOn = true;
745 template<Index Log2Dim> const bool LeafNode<bool, Log2Dim>::sOff = false;
746 
747 
749 
750 
751 template<Index Log2Dim>
752 inline
754 {
755 }
756 
757 
758 template<Index Log2Dim>
759 inline
760 LeafNode<bool, Log2Dim>::LeafNode(const Coord& xyz, bool value, bool active):
761  mValueMask(active),
762  mBuffer(value),
763  mOrigin(xyz & (~(DIM - 1)))
764 {
765 }
766 
767 
768 template<Index Log2Dim>
769 template<typename ValueT>
770 inline
772  mValueMask(other.getValueMask()),
773  mBuffer(other.getValueMask()), // value = active state
774  mOrigin(other.getOrigin())
775 {
776 }
777 
778 
779 template<Index Log2Dim>
780 template<typename ValueT>
781 inline
783  bool offValue, bool onValue, TopologyCopy):
784  mValueMask(other.getValueMask()),
785  mBuffer(other.getValueMask()),
786  mOrigin(other.getOrigin())
787 {
788  if (offValue) { if (!onValue) mBuffer.mData.toggle(); else mBuffer.mData.setOn(); }
789 }
790 
791 
792 template<Index Log2Dim>
793 template<typename ValueT>
794 inline
796  bool background, TopologyCopy):
797  mValueMask(other.getValueMask()),
798  mBuffer(background),
799  mOrigin(other.getOrigin())
800 {
801 }
802 
803 
804 template<Index Log2Dim>
805 inline
807  mValueMask(other.mValueMask),
808  mBuffer(other.mBuffer),
809  mOrigin(other.mOrigin)
810 {
811 }
812 
813 
814 template<Index Log2Dim>
815 inline
817 {
818 }
819 
820 
822 
823 
824 template<Index Log2Dim>
825 inline Index64
827 {
828  return sizeof(mOrigin) + mValueMask.memUsage() + mBuffer.memUsage();
829 }
830 
831 
832 template<Index Log2Dim>
833 inline void
835 {
836  const CoordBBox this_bbox = this->getNodeBoundingBox();
837  if (bbox.isInside(this_bbox)) {
838  // nothing to do
839  } else if (this->isDense()) {
840  bbox.expand(this_bbox);
841  } else {
842  for (ValueOnCIter iter=this->cbeginValueOn(); iter; ++iter) bbox.expand(iter.getCoord());
843  }
844 }
845 
846 
847 template<Index Log2Dim>
848 template<typename OtherType, Index OtherLog2Dim>
849 inline bool
851 {
852  assert(other);
853  return (Log2Dim == OtherLog2Dim && mValueMask == other->getValueMask());
854 }
855 
856 
857 template<Index Log2Dim>
858 inline std::string
860 {
861  std::ostringstream ostr;
862  ostr << "LeafNode @" << mOrigin << ": ";
863  for (Index32 n = 0; n < SIZE; ++n) ostr << (mValueMask.isOn(n) ? '#' : '.');
864  return ostr.str();
865 }
866 
867 
869 
870 
871 template<Index Log2Dim>
872 inline Index
874 {
875  assert ((xyz[0] & DIM-1u) < DIM && (xyz[1] & DIM-1u) < DIM && (xyz[2] & DIM-1u) < DIM);
876  return ((xyz[0] & DIM-1u) << 2*Log2Dim) + ((xyz[1] & DIM-1u) << Log2Dim) + (xyz[2] & DIM-1u);
877 }
878 
879 
880 template<Index Log2Dim>
881 inline Coord
883 {
884  assert(n < (1 << 3*Log2Dim));
885  Coord xyz;
886  xyz.setX(n >> 2*Log2Dim);
887  n &= ((1 << 2*Log2Dim) - 1);
888  xyz.setY(n >> Log2Dim);
889  xyz.setZ(n & ((1 << Log2Dim) - 1));
890  return xyz;
891 }
892 
893 
894 template<Index Log2Dim>
895 inline Coord
897 {
898  return (this->offset2coord(n) + this->getOrigin());
899 }
900 
901 
903 
904 
905 template<Index Log2Dim>
906 inline void
907 LeafNode<bool, Log2Dim>::readTopology(std::istream& is, bool /*fromHalf*/)
908 {
909  mValueMask.load(is);
910 }
911 
912 
913 template<Index Log2Dim>
914 inline void
915 LeafNode<bool, Log2Dim>::writeTopology(std::ostream& os, bool /*toHalf*/) const
916 {
917  mValueMask.save(os);
918 }
919 
920 
921 template<Index Log2Dim>
922 inline void
923 LeafNode<bool, Log2Dim>::readBuffers(std::istream& is, bool /*fromHalf*/)
924 {
925  // Read in the value mask.
926  mValueMask.load(is);
927  // Read in the origin.
928  is.read(reinterpret_cast<char*>(&mOrigin), sizeof(Coord::ValueType) * 3);
929 
931  // Read in the mask for the voxel values.
932  mBuffer.mData.load(is);
933  } else {
934  // Older files stored one or more bool arrays.
935 
936  // Read in the number of buffers, which should now always be one.
937  int8_t numBuffers = 0;
938  is.read(reinterpret_cast<char*>(&numBuffers), sizeof(int8_t));
939 
940  // Read in the buffer.
941  // (Note: prior to the bool leaf optimization, buffers were always compressed.)
942  boost::shared_array<bool> buf(new bool[SIZE]);
943  io::readData<bool>(is, buf.get(), SIZE, /*isCompressed=*/true);
944 
945  // Transfer values to mBuffer.
946  mBuffer.mData.setOff();
947  for (Index i = 0; i < SIZE; ++i) {
948  if (buf[i]) mBuffer.mData.setOn(i);
949  }
950 
951  if (numBuffers > 1) {
952  // Read in and discard auxiliary buffers that were created with
953  // earlier versions of the library.
954  for (int i = 1; i < numBuffers; ++i) {
955  io::readData<bool>(is, buf.get(), SIZE, /*isCompressed=*/true);
956  }
957  }
958  }
959 }
960 
961 
962 template<Index Log2Dim>
963 inline void
964 LeafNode<bool, Log2Dim>::writeBuffers(std::ostream& os, bool /*toHalf*/) const
965 {
966  // Write out the value mask.
967  mValueMask.save(os);
968  // Write out the origin.
969  os.write(reinterpret_cast<const char*>(&mOrigin), sizeof(Coord::ValueType) * 3);
970  // Write out the voxel values.
971  mBuffer.mData.save(os);
972 }
973 
974 
976 
977 
978 template<Index Log2Dim>
979 inline bool
981 {
982  return (mValueMask == other.mValueMask && mBuffer.mData == other.mBuffer.mData);
983 }
984 
985 
986 template<Index Log2Dim>
987 inline bool
989 {
990  return !(this->operator==(other));
991 }
992 
993 
995 
996 
997 template<Index Log2Dim>
998 inline bool
999 LeafNode<bool, Log2Dim>::isConstant(bool& constValue, bool& state, bool tolerance) const
1000 {
1001  if (!(mValueMask.isOn() || mValueMask.isOff())) return false;
1002 
1003  // Note: if tolerance is true (i.e., 1), then all boolean values compare equal.
1004  if (!tolerance && !(mBuffer.mData.isOn() || mBuffer.mData.isOff())) return false;
1005 
1006  state = mValueMask.isOn();
1007  constValue = mBuffer.mData.isOn();
1008  return true;
1009 }
1010 
1011 
1013 
1014 
1015 template<Index Log2Dim>
1016 inline const bool&
1018 {
1019  // This *CANNOT* use operator ? because Visual C++
1020  if (mBuffer.mData.isOn(this->coord2offset(xyz))) return sOn; else return sOff;
1021 }
1022 
1023 
1024 template<Index Log2Dim>
1025 inline const bool&
1027 {
1028  assert(offset < SIZE);
1029  // This *CANNOT* use operator ? for Windows
1030  if (mBuffer.mData.isOn(offset)) return sOn; else return sOff;
1031 }
1032 
1033 
1034 template<Index Log2Dim>
1035 inline bool
1036 LeafNode<bool, Log2Dim>::probeValue(const Coord& xyz, bool& val) const
1037 {
1038  const Index offset = this->coord2offset(xyz);
1039  val = mBuffer.mData.isOn(offset);
1040  return mValueMask.isOn(offset);
1041 }
1042 
1043 
1044 template<Index Log2Dim>
1045 inline void
1047 {
1048  const Index offset = this->coord2offset(xyz);
1049  mValueMask.setOn(offset);
1050  mBuffer.mData.set(offset, val);
1051 }
1052 
1053 
1054 template<Index Log2Dim>
1055 inline void
1057 {
1058  mValueMask.set(this->coord2offset(xyz), on);
1059 }
1060 
1061 
1062 template<Index Log2Dim>
1063 inline void
1065 {
1066  const Index offset = this->coord2offset(xyz);
1067  mValueMask.setOff(offset);
1068  mBuffer.mData.set(offset, val);
1069 }
1070 
1071 
1072 template<Index Log2Dim>
1073 inline void
1075 {
1076  const Index offset = this->coord2offset(xyz);
1077  mValueMask.setOn(offset);
1078  mBuffer.mData.set(offset, val && mBuffer.mData.isOn(offset));
1079 }
1080 
1081 
1082 template<Index Log2Dim>
1083 inline void
1085 {
1086  const Index offset = this->coord2offset(xyz);
1087  mValueMask.setOn(offset);
1088  mBuffer.mData.set(offset, val || mBuffer.mData.isOn(offset));
1089 }
1090 
1091 
1092 template<Index Log2Dim>
1093 inline void
1095 {
1096  const Index offset = this->coord2offset(xyz);
1097  mValueMask.setOn(offset);
1098  mBuffer.mData.set(offset, val || mBuffer.mData.isOn(offset)); // true + true = true
1099 }
1100 
1101 
1102 template<Index Log2Dim>
1103 inline void
1105 {
1106  if (val) mBuffer.mData |= mValueMask; // set all active voxels to true
1107 }
1108 
1109 
1110 template<Index Log2Dim>
1111 inline void
1113 {
1114  if (!val) mBuffer.mData &= !mValueMask; // set all active voxels to false
1115 }
1116 
1117 
1119 
1120 
1121 template<Index Log2Dim>
1122 inline void
1123 LeafNode<bool, Log2Dim>::resetBackground(bool oldBackground, bool newBackground)
1124 {
1125  if (newBackground != oldBackground) {
1126  // Flip mBuffer's background bits and zero its foreground bits.
1127  NodeMaskType bgMask = !(mBuffer.mData | mValueMask);
1128  // Overwrite mBuffer's background bits, leaving its foreground bits intact.
1129  mBuffer.mData = (mBuffer.mData & mValueMask) | bgMask;
1130  }
1131 }
1132 
1133 
1134 template<Index Log2Dim>
1135 inline void
1137 {
1138  for (typename NodeMaskType::OnIterator iter = other.mValueMask.beginOn(); iter; ++iter) {
1139  const Index n = iter.pos();
1140  if (mValueMask.isOn(n)) continue;
1141  mBuffer.mData.set(n, other.mBuffer.mData.isOn(n));
1142  mValueMask.setOn(n);
1143  }
1144 }
1145 
1146 
1147 template<Index Log2Dim>
1148 template<typename OtherType>
1149 inline void
1151 {
1152  mValueMask |= other.getValueMask();
1153 }
1154 
1155 template<Index Log2Dim>
1156 template<typename OtherType>
1157 inline void
1159  const bool&)
1160 {
1161  mValueMask &= other.getValueMask();
1162 }
1163 
1164 template<Index Log2Dim>
1165 template<typename OtherType>
1166 inline void
1168  const bool&)
1169 {
1170  mValueMask &= !other.getValueMask();
1171 }
1172 
1173 template<Index Log2Dim>
1174 inline void
1175 LeafNode<bool, Log2Dim>::fill(const CoordBBox& bbox, bool value, bool active)
1176 {
1177  for (Int32 x = bbox.min().x(); x <= bbox.max().x(); ++x) {
1178  const Index offsetX = (x&DIM-1u)<<2*Log2Dim;
1179  for (Int32 y = bbox.min().y(); y <= bbox.max().y(); ++y) {
1180  const Index offsetXY = offsetX + ((y&DIM-1u)<< Log2Dim);
1181  for (Int32 z = bbox.min().z(); z <= bbox.max().z(); ++z) {
1182  const Index offset = offsetXY + (z&DIM-1u);
1183  mValueMask.set(offset, active);
1184  mBuffer.mData.set(offset, value);
1185  }
1186  }
1187  }
1188 }
1189 
1190 template<Index Log2Dim>
1191 inline void
1193 {
1194  mBuffer.fill(value);
1195 }
1196 
1197 template<Index Log2Dim>
1198 inline void
1199 LeafNode<bool, Log2Dim>::fill(const bool& value, bool active)
1200 {
1201  mBuffer.fill(value);
1202  mValueMask.set(active);
1203 }
1204 
1205 
1207 
1208 
1209 template<Index Log2Dim>
1210 template<typename DenseT>
1211 inline void
1212 LeafNode<bool, Log2Dim>::copyToDense(const CoordBBox& bbox, DenseT& dense) const
1213 {
1214  const size_t xStride = dense.xStride(), yStride = dense.yStride();// zStride=1
1215  const Coord& min = dense.bbox().min();
1216  bool* t0 = dense.data() + bbox.min()[2]-min[2];//target array
1217  const Int32 n0 = bbox.min()[2]&DIM-1u;
1218  for (Int32 x = bbox.min()[0], ex=bbox.max()[0]+1; x<ex; ++x) {
1219  bool* t1 = t0 + xStride*(x-min[0]);
1220  const Int32 n1 = n0 + ((x&DIM-1u)<<2*LOG2DIM);
1221  for (Int32 y = bbox.min()[1], ey=bbox.max()[1]+1; y<ey; ++y) {
1222  bool* t2 = t1 + yStride*(y-min[1]);
1223  Int32 n2 = n1 + ((y&DIM-1u)<<LOG2DIM) ;
1224  for (Int32 z = bbox.min()[2], ez=bbox.max()[2]+1; z<ez ; ++z) {
1225  *t2++ = mBuffer.mData.isOn(n2++);
1226  }
1227  }
1228  }
1229 }
1230 
1231 
1232 template<Index Log2Dim>
1233 template<typename DenseT>
1234 inline void
1235 LeafNode<bool, Log2Dim>::copyFromDense(const CoordBBox& bbox, const DenseT& dense,
1236  bool background, bool tolerance)
1237 {
1238  const size_t xStride = dense.xStride(), yStride = dense.yStride();// zStride=1
1239  const Coord& min = dense.bbox().min();
1240  const bool* s0 = dense.data() + bbox.min()[2]-min[2];//source
1241  const Int32 n0 = bbox.min()[2]&DIM-1u;
1242  for (Int32 x = bbox.min()[0], ex=bbox.max()[0]+1; x<ex; ++x) {
1243  const bool* s1 = s0 + xStride*(x-min[0]);
1244  const Int32 n1 = n0 + ((x&DIM-1u)<<2*LOG2DIM);
1245  for (Int32 y = bbox.min()[1], ey=bbox.max()[1]+1; y<ey; ++y) {
1246  const bool* s2 = s1 + yStride*(y-min[1]);
1247  Int32 n2 = n1 + ((y&DIM-1u)<<LOG2DIM) ;
1248  for (Int32 z = bbox.min()[2], ez=bbox.max()[2]+1; z<ez ; ++z, ++n2, ++s2) {
1249  // Note: if tolerance is true (i.e., 1), then all boolean values compare equal.
1250  if (tolerance || background == *s2) {
1251  mValueMask.setOff(n2);
1252  mBuffer.mData.set(n2, background);
1253  } else {
1254  mValueMask.setOn(n2);
1255  mBuffer.mData.set(n2, *s2);
1256  }
1257  }
1258  }
1259  }
1260 }
1261 
1262 
1264 
1265 
1266 template<Index Log2Dim>
1267 template<typename CombineOp>
1268 inline void
1269 LeafNode<bool, Log2Dim>::combine(const LeafNode& other, CombineOp& op)
1270 {
1271  CombineArgs<bool> args;
1272  for (Index i = 0; i < SIZE; ++i) {
1273  bool result = false, aVal = mBuffer.mData.isOn(i), bVal = other.mBuffer.mData.isOn(i);
1274  op(args.setARef(aVal)
1275  .setAIsActive(mValueMask.isOn(i))
1276  .setBRef(bVal)
1277  .setBIsActive(other.mValueMask.isOn(i))
1278  .setResultRef(result));
1279  mValueMask.set(i, args.resultIsActive());
1280  mBuffer.mData.set(i, result);
1281  }
1282 }
1283 
1284 
1285 template<Index Log2Dim>
1286 template<typename CombineOp>
1287 inline void
1288 LeafNode<bool, Log2Dim>::combine(bool value, bool valueIsActive, CombineOp& op)
1289 {
1290  CombineArgs<bool> args;
1291  args.setBRef(value).setBIsActive(valueIsActive);
1292  for (Index i = 0; i < SIZE; ++i) {
1293  bool result = false, aVal = mBuffer.mData.isOn(i);
1294  op(args.setARef(aVal)
1295  .setAIsActive(mValueMask.isOn(i))
1296  .setResultRef(result));
1297  mValueMask.set(i, args.resultIsActive());
1298  mBuffer.mData.set(i, result);
1299  }
1300 }
1301 
1302 
1304 
1305 
1306 template<Index Log2Dim>
1307 template<typename CombineOp>
1308 inline void
1310  bool valueIsActive, CombineOp& op)
1311 {
1312  CombineArgs<bool> args;
1313  args.setBRef(value).setBIsActive(valueIsActive);
1314  for (Index i = 0; i < SIZE; ++i) {
1315  bool result = false, aVal = other.mBuffer.mData.isOn(i);
1316  op(args.setARef(aVal)
1317  .setAIsActive(other.mValueMask.isOn(i))
1318  .setResultRef(result));
1319  mValueMask.set(i, args.resultIsActive());
1320  mBuffer.mData.set(i, result);
1321  }
1322 }
1323 
1324 
1325 template<Index Log2Dim>
1326 template<typename CombineOp>
1327 inline void
1329  bool valueIsActive, CombineOp& op)
1330 {
1331  CombineArgs<bool> args;
1332  args.setARef(value).setAIsActive(valueIsActive);
1333  for (Index i = 0; i < SIZE; ++i) {
1334  bool result = false, bVal = other.mBuffer.mData.isOn(i);
1335  op(args.setBRef(bVal)
1336  .setBIsActive(other.mValueMask.isOn(i))
1337  .setResultRef(result));
1338  mValueMask.set(i, args.resultIsActive());
1339  mBuffer.mData.set(i, result);
1340  }
1341 }
1342 
1343 
1344 template<Index Log2Dim>
1345 template<typename CombineOp>
1346 inline void
1347 LeafNode<bool, Log2Dim>::combine2(const LeafNode& b0, const LeafNode& b1, CombineOp& op)
1348 {
1349  CombineArgs<bool> args;
1350  for (Index i = 0; i < SIZE; ++i) {
1351  // Default behavior: output voxel is active if either input voxel is active.
1352  mValueMask.set(i, b0.mValueMask.isOn(i) || b1.mValueMask.isOn(i));
1353 
1354  bool result = false, b0Val = b0.mBuffer.mData.isOn(i), b1Val = b1.mBuffer.mData.isOn(i);
1355  op(args.setARef(b0Val)
1356  .setAIsActive(b0.mValueMask.isOn(i))
1357  .setBRef(b1Val)
1358  .setBIsActive(b1.mValueMask.isOn(i))
1359  .setResultRef(result));
1360  mValueMask.set(i, args.resultIsActive());
1361  mBuffer.mData.set(i, result);
1362  }
1363 }
1364 
1365 
1367 
1368 template<Index Log2Dim>
1369 template<typename BBoxOp>
1370 inline void
1372 {
1373  if (op.template descent<LEVEL>()) {
1374  for (ValueOnCIter i=this->cbeginValueOn(); i; ++i) {
1375 #ifdef _MSC_VER
1376  op.operator()<LEVEL>(CoordBBox(i.getCoord(),1));
1377 #else
1378  op.template operator()<LEVEL>(CoordBBox(i.getCoord(),1));
1379 #endif
1380  }
1381  } else {
1382 #ifdef _MSC_VER
1383  op.operator()<LEVEL>(this->getNodeBoundingBox());
1384 #else
1385  op.template operator()<LEVEL>(this->getNodeBoundingBox());
1386 #endif
1387  }
1388 }
1389 
1390 
1391 template<Index Log2Dim>
1392 template<typename VisitorOp>
1393 inline void
1395 {
1396  doVisit<LeafNode, VisitorOp, ChildAllIter>(*this, op);
1397 }
1398 
1399 
1400 template<Index Log2Dim>
1401 template<typename VisitorOp>
1402 inline void
1404 {
1405  doVisit<const LeafNode, VisitorOp, ChildAllCIter>(*this, op);
1406 }
1407 
1408 
1409 template<Index Log2Dim>
1410 template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
1411 inline void
1412 LeafNode<bool, Log2Dim>::doVisit(NodeT& self, VisitorOp& op)
1413 {
1414  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1415  op(iter);
1416  }
1417 }
1418 
1419 
1421 
1422 
1423 template<Index Log2Dim>
1424 template<typename OtherLeafNodeType, typename VisitorOp>
1425 inline void
1426 LeafNode<bool, Log2Dim>::visit2Node(OtherLeafNodeType& other, VisitorOp& op)
1427 {
1428  doVisit2Node<LeafNode, OtherLeafNodeType, VisitorOp, ChildAllIter,
1429  typename OtherLeafNodeType::ChildAllIter>(*this, other, op);
1430 }
1431 
1432 
1433 template<Index Log2Dim>
1434 template<typename OtherLeafNodeType, typename VisitorOp>
1435 inline void
1436 LeafNode<bool, Log2Dim>::visit2Node(OtherLeafNodeType& other, VisitorOp& op) const
1437 {
1438  doVisit2Node<const LeafNode, OtherLeafNodeType, VisitorOp, ChildAllCIter,
1439  typename OtherLeafNodeType::ChildAllCIter>(*this, other, op);
1440 }
1441 
1442 
1443 template<Index Log2Dim>
1444 template<
1445  typename NodeT,
1446  typename OtherNodeT,
1447  typename VisitorOp,
1448  typename ChildAllIterT,
1449  typename OtherChildAllIterT>
1450 inline void
1451 LeafNode<bool, Log2Dim>::doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp& op)
1452 {
1453  // Allow the two nodes to have different ValueTypes, but not different dimensions.
1454  BOOST_STATIC_ASSERT(OtherNodeT::SIZE == NodeT::SIZE);
1455  BOOST_STATIC_ASSERT(OtherNodeT::LEVEL == NodeT::LEVEL);
1456 
1457  ChildAllIterT iter = self.beginChildAll();
1458  OtherChildAllIterT otherIter = other.beginChildAll();
1459 
1460  for ( ; iter && otherIter; ++iter, ++otherIter) {
1461  op(iter, otherIter);
1462  }
1463 }
1464 
1465 
1467 
1468 
1469 template<Index Log2Dim>
1470 template<typename IterT, typename VisitorOp>
1471 inline void
1472 LeafNode<bool, Log2Dim>::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS)
1473 {
1474  doVisit2<LeafNode, VisitorOp, ChildAllIter, IterT>(*this, otherIter, op, otherIsLHS);
1475 }
1476 
1477 
1478 template<Index Log2Dim>
1479 template<typename IterT, typename VisitorOp>
1480 inline void
1481 LeafNode<bool, Log2Dim>::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS) const
1482 {
1483  doVisit2<const LeafNode, VisitorOp, ChildAllCIter, IterT>(*this, otherIter, op, otherIsLHS);
1484 }
1485 
1486 
1487 template<Index Log2Dim>
1488 template<
1489  typename NodeT,
1490  typename VisitorOp,
1491  typename ChildAllIterT,
1492  typename OtherChildAllIterT>
1493 inline void
1494 LeafNode<bool, Log2Dim>::doVisit2(NodeT& self, OtherChildAllIterT& otherIter,
1495  VisitorOp& op, bool otherIsLHS)
1496 {
1497  if (!otherIter) return;
1498 
1499  if (otherIsLHS) {
1500  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1501  op(otherIter, iter);
1502  }
1503  } else {
1504  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1505  op(iter, otherIter);
1506  }
1507  }
1508 }
1509 
1510 } // namespace tree
1511 } // namespace OPENVDB_VERSION_NAME
1512 } // namespace openvdb
1513 
1514 #endif // OPENVDB_TREE_LEAFNODEBOOL_HAS_BEEN_INCLUDED
1515 
1516 // Copyright (c) 2012-2013 DreamWorks Animation LLC
1517 // All rights reserved. This software is distributed under the
1518 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )