OpenVDB  1.1.0
LeafNodeBool.h
Go to the documentation of this file.
1 
2 //
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  const Coord& getOrigin() const { return mOrigin; }
182  void getOrigin(Coord& origin) const { origin = mOrigin; }
183  void getOrigin(Int32& x, Int32& y, Int32& z) const { mOrigin.asXYZ(x, y, z); }
184 
186  static Index coord2offset(const Coord& xyz);
189  static Coord offset2coord(Index n);
191  Coord offset2globalCoord(Index n) const;
192 
194  std::string str() const;
195 
198  template<typename OtherType, Index OtherLog2Dim>
199  bool hasSameTopology(const LeafNode<OtherType, OtherLog2Dim>* other) const;
200 
202  bool operator==(const LeafNode&) const;
203  bool operator!=(const LeafNode&) const;
204 
205  //
206  // Buffer management
207  //
210  void swap(Buffer& other) { mBuffer.swap(other); }
211  const Buffer& buffer() const { return mBuffer; }
212  Buffer& buffer() { return mBuffer; }
213 
214  //
215  // I/O methods
216  //
218  void readTopology(std::istream&, bool fromHalf = false);
220  void writeTopology(std::ostream&, bool toHalf = false) const;
221 
223  void readBuffers(std::istream&, bool fromHalf = false);
225  void writeBuffers(std::ostream&, bool toHalf = false) const;
226 
227  //
228  // Accessor methods
229  //
231  const bool& getValue(const Coord& xyz) const;
233  const bool& getValue(Index offset) const;
234 
238  bool probeValue(const Coord& xyz, bool& val) const;
239 
241  static Index getValueLevel(const Coord&) { return LEVEL; }
242 
244  void setActiveState(const Coord& xyz, bool on);
245 
247  void setValueOff(const Coord& xyz) { mValueMask.setOff(this->coord2offset(xyz)); }
249  void setValueOff(Index offset) { assert(offset < SIZE); mValueMask.setOff(offset); }
251  void setValueOff(const Coord& xyz, bool val);
252 
254  void setValueOn(const Coord& xyz) { mValueMask.setOn(this->coord2offset(xyz)); }
256  void setValueOn(Index offset) { assert(offset < SIZE); mValueMask.setOn(offset); }
258  void setValueOn(const Coord& xyz, bool val);
260  void setValue(const Coord& xyz, bool val) { this->setValueOn(xyz, val); };
261 
264  void setValueOnMin(const Coord& xyz, bool val);
267  void setValueOnMax(const Coord& xyz, bool val);
270  void setValueOnSum(const Coord& xyz, bool val);
271 
274  void setValueOnly(const Coord& xyz, bool val) {
275  this->setValueOnly(LeafNode::coord2offset(xyz), val);
276  }
279  void setValueOnly(Index offset, bool val) { assert(offset<SIZE); mBuffer.setValue(offset,val); }
280 
282  void addValue(bool val);
284  void scaleValue(bool scale);
285 
287  void setValuesOn() { mValueMask.setOn(); }
289  void setValuesOff() { mValueMask.setOff(); }
290 
292  bool isValueOn(const Coord& xyz) const { return mValueMask.isOn(this->coord2offset(xyz)); }
294  bool isValueOn(Index offset) const { assert(offset < SIZE); return mValueMask.isOn(offset); }
295 
297  static bool hasActiveTiles() { return false; }
298 
301  void fill(const CoordBBox& bbox, bool value, bool active = true);
302 
304  void fill(const bool& value);
305 
307  void fill(const bool& value, bool active);
308 
311  template<typename AccessorT>
312  const bool& getValueAndCache(const Coord& xyz, AccessorT&) const {return this->getValue(xyz);}
313 
316  template<typename AccessorT>
317  bool isValueOnAndCache(const Coord& xyz, AccessorT&) const { return this->isValueOn(xyz); }
318 
321  template<typename AccessorT>
322  void setValueAndCache(const Coord& xyz, bool val, AccessorT&) { this->setValueOn(xyz, val); }
323 
327  template<typename AccessorT>
328  void setValueOnlyAndCache(const Coord& xyz, bool val, AccessorT&) {this->setValueOnly(xyz,val);}
329 
332  template<typename AccessorT>
333  void setValueOffAndCache(const Coord& xyz, bool value, AccessorT&)
334  {
335  this->setValueOff(xyz, value);
336  }
337 
341  template<typename AccessorT>
342  void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&)
343  {
344  this->setActiveState(xyz, on);
345  }
346 
350  template<typename AccessorT>
351  bool probeValueAndCache(const Coord& xyz, bool& val, AccessorT&) const
352  {
353  return this->probeValue(xyz, val);
354  }
355 
358  template<typename AccessorT>
359  static Index getValueLevelAndCache(const Coord&, AccessorT&) { return LEVEL; }
360 
364  const bool& getFirstValue() const { if (mValueMask.isOn(0)) return sOn; else return sOff; }
368  const bool& getLastValue() const { if (mValueMask.isOn(SIZE-1)) return sOn; else return sOff; }
369 
373  bool isConstant(bool& constValue, bool& state, bool tolerance = 0) const;
375  bool isInactive() const { return mValueMask.isOff(); }
376 
377  void resetBackground(bool oldBackground, bool newBackground);
378 
379  void negate() { mBuffer.mData.toggle(); }
380 
381  void merge(const LeafNode& other);
382 
384 
389  template<typename OtherType>
390  void topologyUnion(const LeafNode<OtherType, Log2Dim>& other);
391 
400  template<typename OtherType>
401  void topologyIntersection(const LeafNode<OtherType, Log2Dim>& other, const bool&);
402 
403  template<typename CombineOp>
404  void combine(const LeafNode& other, CombineOp& op);
405  template<typename CombineOp>
406  void combine(bool, bool valueIsActive, CombineOp& op);
407 
408  template<typename CombineOp>
409  void combine2(const LeafNode& other, bool, bool valueIsActive, CombineOp&);
410  template<typename CombineOp>
411  void combine2(bool, const LeafNode& other, bool valueIsActive, CombineOp&);
412  template<typename CombineOp>
413  void combine2(const LeafNode& b0, const LeafNode& b1, CombineOp&);
414 
419  template<typename BBoxOp> void visitActiveBBox(BBoxOp&) const;
420 
421  template<typename VisitorOp> void visit(VisitorOp&);
422  template<typename VisitorOp> void visit(VisitorOp&) const;
423 
424  template<typename OtherLeafNodeType, typename VisitorOp>
425  void visit2Node(OtherLeafNodeType& other, VisitorOp&);
426  template<typename OtherLeafNodeType, typename VisitorOp>
427  void visit2Node(OtherLeafNodeType& other, VisitorOp&) const;
428  template<typename IterT, typename VisitorOp>
429  void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false);
430  template<typename IterT, typename VisitorOp>
431  void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false) const;
432 
434 
435  void signedFloodFill(bool) {}
437  void signedFloodFill(bool, bool) {}
438  template<typename PruneOp> void pruneOp(PruneOp&) {}
439  void prune(const ValueType& /*tolerance*/ = zeroVal<ValueType>()) {}
440  void pruneInactive(const ValueType&) {}
442 
444 
445  LeafNode* touchLeaf(const Coord&) { return this; }
446  template<typename AccessorT>
447  LeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; }
448  LeafNode* probeLeaf(const Coord&) { return this; }
449  template<typename AccessorT>
450  LeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; }
452 
453 
454  const LeafNode* probeConstLeaf(const Coord&) const { return this; }
455  template<typename AccessorT>
456  const LeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const { return this; }
458 
459  void merge(const LeafNode& other, bool, bool) { this->merge(other); }
460 
461  //
462  // Iterators
463  //
464 protected:
468 
469  template<typename MaskIterT, typename NodeT, typename ValueT>
470  struct ValueIter:
471  // Derives from SparseIteratorBase, but can also be used as a dense iterator,
472  // if MaskIterT is a dense mask iterator type.
473  public SparseIteratorBase<MaskIterT, ValueIter<MaskIterT, NodeT, ValueT>, NodeT, ValueT>
474  {
476 
478  ValueIter(const MaskIterT& iter, NodeT* parent): BaseT(iter, parent) {}
479 
480  const bool& getItem(Index pos) const { return this->parent().getValue(pos); }
481  const bool& getValue() const { return this->getItem(this->pos()); }
482 
483  // Note: setItem() can't be called on const iterators.
484  void setItem(Index pos, bool value) const { this->parent().setValueOnly(pos, value); }
485  // Note: setValue() can't be called on const iterators.
486  void setValue(bool value) const { this->setItem(this->pos(), value); }
487  };
488 
490  template<typename MaskIterT, typename NodeT>
491  struct ChildIter:
492  public SparseIteratorBase<MaskIterT, ChildIter<MaskIterT, NodeT>, NodeT, bool>
493  {
495  ChildIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase<
496  MaskIterT, ChildIter<MaskIterT, NodeT>, NodeT, bool>(iter, parent) {}
497  };
498 
499  template<typename NodeT, typename ValueT>
500  struct DenseIter: public DenseIteratorBase<
501  MaskDenseIter, DenseIter<NodeT, ValueT>, NodeT, /*ChildT=*/void, ValueT>
502  {
505 
507  DenseIter(const MaskDenseIter& iter, NodeT* parent): BaseT(iter, parent) {}
508 
509  bool getItem(Index pos, void*& child, NonConstValueT& value) const
510  {
511  value = this->parent().getValue(pos);
512  child = NULL;
513  return false; // no child
514  }
515 
516  // Note: setItem() can't be called on const iterators.
517  //void setItem(Index pos, void* child) const {}
518 
519  // Note: unsetItem() can't be called on const iterators.
520  void unsetItem(Index pos, const ValueT& val) const {this->parent().setValueOnly(pos, val);}
521  };
522 
523 public:
524  typedef ValueIter<MaskOnIter, LeafNode, bool> ValueOnIter;
525  typedef ValueIter<MaskOnIter, const LeafNode, const bool> ValueOnCIter;
526  typedef ValueIter<MaskOffIter, LeafNode, bool> ValueOffIter;
527  typedef ValueIter<MaskOffIter, const LeafNode, const bool> ValueOffCIter;
528  typedef ValueIter<MaskDenseIter, LeafNode, bool> ValueAllIter;
529  typedef ValueIter<MaskDenseIter, const LeafNode, const bool> ValueAllCIter;
530  typedef ChildIter<MaskOnIter, LeafNode> ChildOnIter;
531  typedef ChildIter<MaskOnIter, const LeafNode> ChildOnCIter;
532  typedef ChildIter<MaskOffIter, LeafNode> ChildOffIter;
533  typedef ChildIter<MaskOffIter, const LeafNode> ChildOffCIter;
534  typedef DenseIter<LeafNode, bool> ChildAllIter;
535  typedef DenseIter<const LeafNode, const bool> ChildAllCIter;
536 
537  ValueOnCIter cbeginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); }
538  ValueOnCIter beginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); }
539  ValueOnIter beginValueOn() { return ValueOnIter(mValueMask.beginOn(), this); }
540  ValueOffCIter cbeginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); }
541  ValueOffCIter beginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); }
542  ValueOffIter beginValueOff() { return ValueOffIter(mValueMask.beginOff(), this); }
543  ValueAllCIter cbeginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); }
544  ValueAllCIter beginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); }
545  ValueAllIter beginValueAll() { return ValueAllIter(mValueMask.beginDense(), this); }
546 
547  ValueOnCIter cendValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); }
548  ValueOnCIter endValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); }
549  ValueOnIter endValueOn() { return ValueOnIter(mValueMask.endOn(), this); }
550  ValueOffCIter cendValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); }
551  ValueOffCIter endValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); }
552  ValueOffIter endValueOff() { return ValueOffIter(mValueMask.endOff(), this); }
553  ValueAllCIter cendValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); }
554  ValueAllCIter endValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); }
555  ValueAllIter endValueAll() { return ValueAllIter(mValueMask.endDense(), this); }
556 
557  // Note that [c]beginChildOn() and [c]beginChildOff() actually return end iterators,
558  // because leaf nodes have no children.
559  ChildOnCIter cbeginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
560  ChildOnCIter beginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
561  ChildOnIter beginChildOn() { return ChildOnIter(mValueMask.endOn(), this); }
562  ChildOffCIter cbeginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
563  ChildOffCIter beginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
564  ChildOffIter beginChildOff() { return ChildOffIter(mValueMask.endOff(), this); }
565  ChildAllCIter cbeginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); }
566  ChildAllCIter beginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); }
567  ChildAllIter beginChildAll() { return ChildAllIter(mValueMask.beginDense(), this); }
568 
569  ChildOnCIter cendChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
570  ChildOnCIter endChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
571  ChildOnIter endChildOn() { return ChildOnIter(mValueMask.endOn(), this); }
572  ChildOffCIter cendChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
573  ChildOffCIter endChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
574  ChildOffIter endChildOff() { return ChildOffIter(mValueMask.endOff(), this); }
575  ChildAllCIter cendChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); }
576  ChildAllCIter endChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); }
577  ChildAllIter endChildAll() { return ChildAllIter(mValueMask.endDense(), this); }
578 
579  //
580  // Mask accessors
581  //
582  bool isValueMaskOn(Index n) const { return mValueMask.isOn(n); }
583  bool isValueMaskOn() const { return mValueMask.isOn(); }
584  bool isValueMaskOff(Index n) const { return mValueMask.isOff(n); }
585  bool isValueMaskOff() const { return mValueMask.isOff(); }
586  const NodeMaskType& getValueMask() const { return mValueMask; }
587  NodeMaskType& getValueMask() { return mValueMask; }
588  void setValueMask(const NodeMaskType& mask) { mValueMask = mask; }
589  bool isChildMaskOn(Index) const { return false; } // leaf nodes have no children
590  bool isChildMaskOff(Index) const { return true; }
591  bool isChildMaskOff() const { return true; }
592 protected:
593  void setValueMask(Index n, bool on) { mValueMask.set(n, on); }
594  void setValueMaskOn(Index n) { mValueMask.setOn(n); }
595  void setValueMaskOff(Index n) { mValueMask.setOff(n); }
596 
598  static void evalNodeOrigin(Coord& xyz) { xyz &= ~(DIM - 1); }
599 
600  template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
601  static inline void doVisit(NodeT&, VisitorOp&);
602 
603  template<typename NodeT, typename OtherNodeT, typename VisitorOp,
604  typename ChildAllIterT, typename OtherChildAllIterT>
605  static inline void doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp&);
606 
607  template<typename NodeT, typename VisitorOp,
608  typename ChildAllIterT, typename OtherChildAllIterT>
609  static inline void doVisit2(NodeT& self, OtherChildAllIterT&, VisitorOp&, bool otherIsLHS);
610 
611 
615  Buffer mBuffer;
618 
619  // These static declarations must be on separate lines to avoid VC9 compiler errors.
620  static const bool sOn;
621  static const bool sOff;
622 
623 private:
626  template<typename, Index> friend class LeafNode;
627 
628  friend struct ValueIter<MaskOnIter, LeafNode, bool>;
629  friend struct ValueIter<MaskOffIter, LeafNode, bool>;
630  friend struct ValueIter<MaskDenseIter, LeafNode, bool>;
631  friend struct ValueIter<MaskOnIter, const LeafNode, bool>;
632  friend struct ValueIter<MaskOffIter, const LeafNode, bool>;
633  friend struct ValueIter<MaskDenseIter, const LeafNode, bool>;
634 
636 
637 
642 
643  // Disallow copying.
644  LeafNode& operator=(const LeafNode&);
645 
646 }; // class LeafNode<bool>
647 
648 
653 template<Index Log2Dim> const bool LeafNode<bool, Log2Dim>::sOn = true;
654 template<Index Log2Dim> const bool LeafNode<bool, Log2Dim>::sOff = false;
655 
656 
658 
659 
660 template<Index Log2Dim>
661 inline
662 LeafNode<bool, Log2Dim>::LeafNode(): mOrigin(0, 0, 0)
663 {
664 }
665 
666 
667 template<Index Log2Dim>
668 inline
669 LeafNode<bool, Log2Dim>::LeafNode(const Coord& xyz, bool value, bool active):
670  mValueMask(active),
671  mBuffer(value),
672  mOrigin(xyz & (~(DIM - 1)))
673 {
674 }
675 
676 
677 template<Index Log2Dim>
678 template<typename ValueT>
679 inline
681  mValueMask(other.getValueMask()),
682  mBuffer(other.getValueMask()), // value = active state
683  mOrigin(other.getOrigin())
684 {
685 }
686 
687 
688 template<Index Log2Dim>
689 template<typename ValueT>
690 inline
692  bool offValue, bool onValue, TopologyCopy):
693  mValueMask(other.getValueMask()),
694  mBuffer(other.getValueMask()),
695  mOrigin(other.getOrigin())
696 {
697  if (offValue) { if (!onValue) mBuffer.mData.toggle(); else mBuffer.mData.setOn(); }
698 }
699 
700 
701 template<Index Log2Dim>
702 template<typename ValueT>
703 inline
705  bool background, TopologyCopy):
706  mValueMask(other.getValueMask()),
707  mBuffer(background),
708  mOrigin(other.getOrigin())
709 {
710 }
711 
712 
713 template<Index Log2Dim>
714 inline
716  mValueMask(other.mValueMask),
717  mBuffer(other.mBuffer),
718  mOrigin(other.mOrigin)
719 {
720 }
721 
722 
723 template<Index Log2Dim>
724 inline
726 {
727 }
728 
729 
731 
732 
733 template<Index Log2Dim>
734 inline Index64
736 {
737  return sizeof(mOrigin) + mValueMask.memUsage() + mBuffer.memUsage();
738 }
739 
740 
741 template<Index Log2Dim>
742 inline void
744 {
745  const CoordBBox this_bbox = this->getNodeBoundingBox();
746  if (bbox.isInside(this_bbox)) {
747  // nothing to do
748  } else if (this->isDense()) {
749  bbox.expand(this_bbox);
750  } else {
751  for (ValueOnCIter iter=this->cbeginValueOn(); iter; ++iter) bbox.expand(iter.getCoord());
752  }
753 }
754 
755 
756 template<Index Log2Dim>
757 template<typename OtherType, Index OtherLog2Dim>
758 inline bool
760 {
761  assert(other);
762  return (Log2Dim == OtherLog2Dim && mValueMask == other->getValueMask());
763 }
764 
765 
766 template<Index Log2Dim>
767 inline std::string
769 {
770  std::ostringstream ostr;
771  ostr << "LeafNode @" << mOrigin << ": ";
772  for (Index32 n = 0; n < SIZE; ++n) ostr << (mValueMask.isOn(n) ? '#' : '.');
773  return ostr.str();
774 }
775 
776 
778 
779 
780 template<Index Log2Dim>
781 inline Index
783 {
784  assert ((xyz[0] & DIM-1u) < DIM && (xyz[1] & DIM-1u) < DIM && (xyz[2] & DIM-1u) < DIM);
785  return ((xyz[0] & DIM-1u) << 2*Log2Dim) + ((xyz[1] & DIM-1u) << Log2Dim) + (xyz[2] & DIM-1u);
786 }
787 
788 
789 template<Index Log2Dim>
790 inline Coord
792 {
793  assert(n < (1 << 3*Log2Dim));
794  Coord xyz;
795  xyz.setX(n >> 2*Log2Dim);
796  n &= ((1 << 2*Log2Dim) - 1);
797  xyz.setY(n >> Log2Dim);
798  xyz.setZ(n & ((1 << Log2Dim) - 1));
799  return xyz;
800 }
801 
802 
803 template<Index Log2Dim>
804 inline Coord
806 {
807  return (this->offset2coord(n) + this->getOrigin());
808 }
809 
810 
812 
813 
814 template<Index Log2Dim>
815 inline void
816 LeafNode<bool, Log2Dim>::readTopology(std::istream& is, bool /*fromHalf*/)
817 {
818  mValueMask.load(is);
819 }
820 
821 
822 template<Index Log2Dim>
823 inline void
824 LeafNode<bool, Log2Dim>::writeTopology(std::ostream& os, bool /*toHalf*/) const
825 {
826  mValueMask.save(os);
827 }
828 
829 
830 template<Index Log2Dim>
831 inline void
832 LeafNode<bool, Log2Dim>::readBuffers(std::istream& is, bool /*fromHalf*/)
833 {
834  // Read in the value mask.
835  mValueMask.load(is);
836  // Read in the origin.
837  is.read(reinterpret_cast<char*>(&mOrigin), sizeof(Coord::ValueType) * 3);
838 
840  // Read in the mask for the voxel values.
841  mBuffer.mData.load(is);
842  } else {
843  // Older files stored one or more bool arrays.
844 
845  // Read in the number of buffers, which should now always be one.
846  int8_t numBuffers = 0;
847  is.read(reinterpret_cast<char*>(&numBuffers), sizeof(int8_t));
848 
849  // Read in the buffer.
850  // (Note: prior to the bool leaf optimization, buffers were always compressed.)
851  boost::shared_array<bool> buf(new bool[SIZE]);
852  io::readData<bool>(is, buf.get(), SIZE, /*isCompressed=*/true);
853 
854  // Transfer values to mBuffer.
855  mBuffer.mData.setOff();
856  for (Index i = 0; i < SIZE; ++i) {
857  if (buf[i]) mBuffer.mData.setOn(i);
858  }
859 
860  if (numBuffers > 1) {
861  // Read in and discard auxiliary buffers that were created with
862  // earlier versions of the library.
863  for (int i = 1; i < numBuffers; ++i) {
864  io::readData<bool>(is, buf.get(), SIZE, /*isCompressed=*/true);
865  }
866  }
867  }
868 }
869 
870 
871 template<Index Log2Dim>
872 inline void
873 LeafNode<bool, Log2Dim>::writeBuffers(std::ostream& os, bool /*toHalf*/) const
874 {
875  // Write out the value mask.
876  mValueMask.save(os);
877  // Write out the origin.
878  os.write(reinterpret_cast<const char*>(&mOrigin), sizeof(Coord::ValueType) * 3);
879  // Write out the voxel values.
880  mBuffer.mData.save(os);
881 }
882 
883 
885 
886 
887 template<Index Log2Dim>
888 inline bool
890 {
891  return (mValueMask == other.mValueMask && mBuffer.mData == other.mBuffer.mData);
892 }
893 
894 
895 template<Index Log2Dim>
896 inline bool
898 {
899  return !(this->operator==(other));
900 }
901 
902 
904 
905 
906 template<Index Log2Dim>
907 inline bool
908 LeafNode<bool, Log2Dim>::isConstant(bool& constValue, bool& state, bool tolerance) const
909 {
910  if (!(mValueMask.isOn() || mValueMask.isOff())) return false;
911 
912  // Note: if tolerance is true (i.e., 1), then all boolean values compare equal.
913  if (!tolerance && !(mBuffer.mData.isOn() || mBuffer.mData.isOff())) return false;
914 
915  state = mValueMask.isOn();
916  constValue = mBuffer.mData.isOn();
917  return true;
918 }
919 
920 
922 
923 
924 template<Index Log2Dim>
925 inline const bool&
927 {
928  // This *CANNOT* use operator ? because Visual C++
929  if (mBuffer.mData.isOn(this->coord2offset(xyz))) return sOn; else return sOff;
930 }
931 
932 
933 template<Index Log2Dim>
934 inline const bool&
936 {
937  assert(offset < SIZE);
938  // This *CANNOT* use operator ? for Windows
939  if (mBuffer.mData.isOn(offset)) return sOn; else return sOff;
940 }
941 
942 
943 template<Index Log2Dim>
944 inline bool
945 LeafNode<bool, Log2Dim>::probeValue(const Coord& xyz, bool& val) const
946 {
947  const Index offset = this->coord2offset(xyz);
948  val = mBuffer.mData.isOn(offset);
949  return mValueMask.isOn(offset);
950 }
951 
952 
953 template<Index Log2Dim>
954 inline void
956 {
957  const Index offset = this->coord2offset(xyz);
958  mValueMask.setOn(offset);
959  mBuffer.mData.set(offset, val);
960 }
961 
962 
963 template<Index Log2Dim>
964 inline void
966 {
967  mValueMask.set(this->coord2offset(xyz), on);
968 }
969 
970 
971 template<Index Log2Dim>
972 inline void
974 {
975  const Index offset = this->coord2offset(xyz);
976  mValueMask.setOff(offset);
977  mBuffer.mData.set(offset, val);
978 }
979 
980 
981 template<Index Log2Dim>
982 inline void
984 {
985  const Index offset = this->coord2offset(xyz);
986  mValueMask.setOn(offset);
987  mBuffer.mData.set(offset, val && mBuffer.mData.isOn(offset));
988 }
989 
990 
991 template<Index Log2Dim>
992 inline void
994 {
995  const Index offset = this->coord2offset(xyz);
996  mValueMask.setOn(offset);
997  mBuffer.mData.set(offset, val || mBuffer.mData.isOn(offset));
998 }
999 
1000 
1001 template<Index Log2Dim>
1002 inline void
1004 {
1005  const Index offset = this->coord2offset(xyz);
1006  mValueMask.setOn(offset);
1007  mBuffer.mData.set(offset, val || mBuffer.mData.isOn(offset)); // true + true = true
1008 }
1009 
1010 
1011 template<Index Log2Dim>
1012 inline void
1014 {
1015  if (val) mBuffer.mData |= mValueMask; // set all active voxels to true
1016 }
1017 
1018 
1019 template<Index Log2Dim>
1020 inline void
1022 {
1023  if (!val) mBuffer.mData &= !mValueMask; // set all active voxels to false
1024 }
1025 
1026 
1028 
1029 
1030 template<Index Log2Dim>
1031 inline void
1032 LeafNode<bool, Log2Dim>::resetBackground(bool oldBackground, bool newBackground)
1033 {
1034  if (newBackground != oldBackground) {
1035  // Flip mBuffer's background bits and zero its foreground bits.
1036  NodeMaskType bgMask = !(mBuffer.mData | mValueMask);
1037  // Overwrite mBuffer's background bits, leaving its foreground bits intact.
1038  mBuffer.mData = (mBuffer.mData & mValueMask) | bgMask;
1039  }
1040 }
1041 
1042 
1043 template<Index Log2Dim>
1044 inline void
1046 {
1047  for (typename NodeMaskType::OnIterator iter = other.mValueMask.beginOn(); iter; ++iter) {
1048  const Index n = iter.pos();
1049  if (mValueMask.isOn(n)) continue;
1050  mBuffer.mData.set(n, other.mBuffer.mData.isOn(n));
1051  mValueMask.setOn(n);
1052  }
1053 }
1054 
1055 
1056 template<Index Log2Dim>
1057 template<typename OtherType>
1058 inline void
1060 {
1061  mValueMask |= other.getValueMask();
1062 }
1063 
1064 template<Index Log2Dim>
1065 template<typename OtherType>
1066 inline void
1068  const bool&)
1069 {
1070  mValueMask &= other.getValueMask();
1071 }
1072 
1073 template<Index Log2Dim>
1074 inline void
1075 LeafNode<bool, Log2Dim>::fill(const CoordBBox& bbox, bool value, bool active)
1076 {
1077  for (Int32 x = bbox.min().x(); x <= bbox.max().x(); ++x) {
1078  const Index offsetX = (x&DIM-1u)<<2*Log2Dim;
1079  for (Int32 y = bbox.min().y(); y <= bbox.max().y(); ++y) {
1080  const Index offsetXY = offsetX + ((y&DIM-1u)<< Log2Dim);
1081  for (Int32 z = bbox.min().z(); z <= bbox.max().z(); ++z) {
1082  const Index offset = offsetXY + (z&DIM-1u);
1083  mValueMask.set(offset, active);
1084  mBuffer.mData.set(offset, value);
1085  }
1086  }
1087  }
1088 }
1089 
1090 template<Index Log2Dim>
1091 inline void
1093 {
1094  mBuffer.fill(value);
1095 }
1096 
1097 template<Index Log2Dim>
1098 inline void
1099 LeafNode<bool, Log2Dim>::fill(const bool& value, bool active)
1100 {
1101  mBuffer.fill(value);
1102  mValueMask.set(active);
1103 }
1104 
1106 
1107 
1108 template<Index Log2Dim>
1109 template<typename CombineOp>
1110 inline void
1111 LeafNode<bool, Log2Dim>::combine(const LeafNode& other, CombineOp& op)
1112 {
1113  CombineArgs<bool> args;
1114  for (Index i = 0; i < SIZE; ++i) {
1115  bool result = false, aVal = mBuffer.mData.isOn(i), bVal = other.mBuffer.mData.isOn(i);
1116  op(args.setARef(aVal)
1117  .setAIsActive(mValueMask.isOn(i))
1118  .setBRef(bVal)
1119  .setBIsActive(other.mValueMask.isOn(i))
1120  .setResultRef(result));
1121  mValueMask.set(i, args.resultIsActive());
1122  mBuffer.mData.set(i, result);
1123  }
1124 }
1125 
1126 
1127 template<Index Log2Dim>
1128 template<typename CombineOp>
1129 inline void
1130 LeafNode<bool, Log2Dim>::combine(bool value, bool valueIsActive, CombineOp& op)
1131 {
1132  CombineArgs<bool> args;
1133  args.setBRef(value).setBIsActive(valueIsActive);
1134  for (Index i = 0; i < SIZE; ++i) {
1135  bool result = false, aVal = mBuffer.mData.isOn(i);
1136  op(args.setARef(aVal)
1137  .setAIsActive(mValueMask.isOn(i))
1138  .setResultRef(result));
1139  mValueMask.set(i, args.resultIsActive());
1140  mBuffer.mData.set(i, result);
1141  }
1142 }
1143 
1144 
1146 
1147 
1148 template<Index Log2Dim>
1149 template<typename CombineOp>
1150 inline void
1152  bool valueIsActive, CombineOp& op)
1153 {
1154  CombineArgs<bool> args;
1155  args.setBRef(value).setBIsActive(valueIsActive);
1156  for (Index i = 0; i < SIZE; ++i) {
1157  bool result = false, aVal = other.mBuffer.mData.isOn(i);
1158  op(args.setARef(aVal)
1159  .setAIsActive(other.mValueMask.isOn(i))
1160  .setResultRef(result));
1161  mValueMask.set(i, args.resultIsActive());
1162  mBuffer.mData.set(i, result);
1163  }
1164 }
1165 
1166 
1167 template<Index Log2Dim>
1168 template<typename CombineOp>
1169 inline void
1171  bool valueIsActive, CombineOp& op)
1172 {
1173  CombineArgs<bool> args;
1174  args.setARef(value).setAIsActive(valueIsActive);
1175  for (Index i = 0; i < SIZE; ++i) {
1176  bool result = false, bVal = other.mBuffer.mData.isOn(i);
1177  op(args.setBRef(bVal)
1178  .setBIsActive(other.mValueMask.isOn(i))
1179  .setResultRef(result));
1180  mValueMask.set(i, args.resultIsActive());
1181  mBuffer.mData.set(i, result);
1182  }
1183 }
1184 
1185 
1186 template<Index Log2Dim>
1187 template<typename CombineOp>
1188 inline void
1189 LeafNode<bool, Log2Dim>::combine2(const LeafNode& b0, const LeafNode& b1, CombineOp& op)
1190 {
1191  CombineArgs<bool> args;
1192  for (Index i = 0; i < SIZE; ++i) {
1193  // Default behavior: output voxel is active if either input voxel is active.
1194  mValueMask.set(i, b0.mValueMask.isOn(i) || b1.mValueMask.isOn(i));
1195 
1196  bool result = false, b0Val = b0.mBuffer.mData.isOn(i), b1Val = b1.mBuffer.mData.isOn(i);
1197  op(args.setARef(b0Val)
1198  .setAIsActive(b0.mValueMask.isOn(i))
1199  .setBRef(b1Val)
1200  .setBIsActive(b1.mValueMask.isOn(i))
1201  .setResultRef(result));
1202  mValueMask.set(i, args.resultIsActive());
1203  mBuffer.mData.set(i, result);
1204  }
1205 }
1206 
1207 
1209 
1210 template<Index Log2Dim>
1211 template<typename BBoxOp>
1212 inline void
1214 {
1215  if (op.template descent<LEVEL>()) {
1216  for (ValueOnCIter i=this->cbeginValueOn(); i; ++i) {
1217 #ifdef _MSC_VER
1218  op.operator()<LEVEL>(CoordBBox(i.getCoord(),1));
1219 #else
1220  op.template operator()<LEVEL>(CoordBBox(i.getCoord(),1));
1221 #endif
1222  }
1223  } else {
1224 #ifdef _MSC_VER
1225  op.operator()<LEVEL>(this->getNodeBoundingBox());
1226 #else
1227  op.template operator()<LEVEL>(this->getNodeBoundingBox());
1228 #endif
1229  }
1230 }
1231 
1232 
1233 template<Index Log2Dim>
1234 template<typename VisitorOp>
1235 inline void
1237 {
1238  doVisit<LeafNode, VisitorOp, ChildAllIter>(*this, op);
1239 }
1240 
1241 
1242 template<Index Log2Dim>
1243 template<typename VisitorOp>
1244 inline void
1246 {
1247  doVisit<const LeafNode, VisitorOp, ChildAllCIter>(*this, op);
1248 }
1249 
1250 
1251 template<Index Log2Dim>
1252 template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
1253 inline void
1254 LeafNode<bool, Log2Dim>::doVisit(NodeT& self, VisitorOp& op)
1255 {
1256  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1257  op(iter);
1258  }
1259 }
1260 
1261 
1263 
1264 
1265 template<Index Log2Dim>
1266 template<typename OtherLeafNodeType, typename VisitorOp>
1267 inline void
1268 LeafNode<bool, Log2Dim>::visit2Node(OtherLeafNodeType& other, VisitorOp& op)
1269 {
1270  doVisit2Node<LeafNode, OtherLeafNodeType, VisitorOp, ChildAllIter,
1271  typename OtherLeafNodeType::ChildAllIter>(*this, other, op);
1272 }
1273 
1274 
1275 template<Index Log2Dim>
1276 template<typename OtherLeafNodeType, typename VisitorOp>
1277 inline void
1278 LeafNode<bool, Log2Dim>::visit2Node(OtherLeafNodeType& other, VisitorOp& op) const
1279 {
1280  doVisit2Node<const LeafNode, OtherLeafNodeType, VisitorOp, ChildAllCIter,
1281  typename OtherLeafNodeType::ChildAllCIter>(*this, other, op);
1282 }
1283 
1284 
1285 template<Index Log2Dim>
1286 template<
1287  typename NodeT,
1288  typename OtherNodeT,
1289  typename VisitorOp,
1290  typename ChildAllIterT,
1291  typename OtherChildAllIterT>
1292 inline void
1293 LeafNode<bool, Log2Dim>::doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp& op)
1294 {
1295  // Allow the two nodes to have different ValueTypes, but not different dimensions.
1296  BOOST_STATIC_ASSERT(OtherNodeT::SIZE == NodeT::SIZE);
1297  BOOST_STATIC_ASSERT(OtherNodeT::LEVEL == NodeT::LEVEL);
1298 
1299  ChildAllIterT iter = self.beginChildAll();
1300  OtherChildAllIterT otherIter = other.beginChildAll();
1301 
1302  for ( ; iter && otherIter; ++iter, ++otherIter) {
1303  op(iter, otherIter);
1304  }
1305 }
1306 
1307 
1309 
1310 
1311 template<Index Log2Dim>
1312 template<typename IterT, typename VisitorOp>
1313 inline void
1314 LeafNode<bool, Log2Dim>::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS)
1315 {
1316  doVisit2<LeafNode, VisitorOp, ChildAllIter, IterT>(*this, otherIter, op, otherIsLHS);
1317 }
1318 
1319 
1320 template<Index Log2Dim>
1321 template<typename IterT, typename VisitorOp>
1322 inline void
1323 LeafNode<bool, Log2Dim>::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS) const
1324 {
1325  doVisit2<const LeafNode, VisitorOp, ChildAllCIter, IterT>(*this, otherIter, op, otherIsLHS);
1326 }
1327 
1328 
1329 template<Index Log2Dim>
1330 template<
1331  typename NodeT,
1332  typename VisitorOp,
1333  typename ChildAllIterT,
1334  typename OtherChildAllIterT>
1335 inline void
1336 LeafNode<bool, Log2Dim>::doVisit2(NodeT& self, OtherChildAllIterT& otherIter,
1337  VisitorOp& op, bool otherIsLHS)
1338 {
1339  if (!otherIter) return;
1340 
1341  if (otherIsLHS) {
1342  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1343  op(otherIter, iter);
1344  }
1345  } else {
1346  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1347  op(iter, otherIter);
1348  }
1349  }
1350 }
1351 
1352 } // namespace tree
1353 } // namespace OPENVDB_VERSION_NAME
1354 } // namespace openvdb
1355 
1356 #endif // OPENVDB_TREE_LEAFNODEBOOL_HAS_BEEN_INCLUDED
1357 
1358 // Copyright (c) 2012-2013 DreamWorks Animation LLC
1359 // All rights reserved. This software is distributed under the
1360 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )