OpenVDB  0.104.0
LeafNodeBool.h
Go to the documentation of this file.
1 
2 //
3 // Copyright (c) 2012 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  OPENVDB_DEPRECATED const Buffer& getBuffer() const { return mBuffer; }
212  const Buffer& buffer() const { return mBuffer; }
213  Buffer& buffer() { return mBuffer; }
214 
215  //
216  // I/O methods
217  //
219  void readTopology(std::istream&, bool fromHalf = false);
221  void writeTopology(std::ostream&, bool toHalf = false) const;
222 
224  void readBuffers(std::istream&, bool fromHalf = false);
226  void writeBuffers(std::ostream&, bool toHalf = false) const;
227 
228  //
229  // Accessor methods
230  //
232  const bool& getValue(const Coord& xyz) const;
234  const bool& getValue(Index offset) const;
235 
239  bool probeValue(const Coord& xyz, bool& val) const;
240 
242  static Index getValueLevel(const Coord&) { return LEVEL; }
243 
245  void setActiveState(const Coord& xyz, bool on);
246 
248  void setValueOff(const Coord& xyz) { mValueMask.setOff(this->coord2offset(xyz)); }
250  void setValueOff(Index offset) { assert(offset < SIZE); mValueMask.setOff(offset); }
252  void setValueOff(const Coord& xyz, bool val);
253 
255  void setValueOn(const Coord& xyz) { mValueMask.setOn(this->coord2offset(xyz)); }
257  void setValueOn(Index offset) { assert(offset < SIZE); mValueMask.setOn(offset); }
259  void setValueOn(const Coord& xyz, bool val);
261  void setValue(const Coord& xyz, bool val) { this->setValueOn(xyz, val); };
262 
265  void setValueOnMin(const Coord& xyz, bool val);
268  void setValueOnMax(const Coord& xyz, bool val);
271  void setValueOnSum(const Coord& xyz, bool val);
272 
275  void setValueOnly(const Coord& xyz, bool val) {
276  this->setValueOnly(LeafNode::coord2offset(xyz), val);
277  }
278  OPENVDB_DEPRECATED void resetValue(const Coord& xyz, bool val) {
279  mBuffer.mData.set(this->coord2offset(xyz), val);
280  }
283  void setValueOnly(Index offset, bool val) { assert(offset<SIZE); mBuffer.setValue(offset,val); }
284  OPENVDB_DEPRECATED void resetValue(Index offset, bool val) { mBuffer.setValue(offset, val); }
285 
287  void addValue(bool val);
289  void scaleValue(bool scale);
290 
293  OPENVDB_DEPRECATED void setValueMaskOn() { mValueMask.setOn(); }
296  OPENVDB_DEPRECATED void setValueMaskOff() { mValueMask.setOff(); }
297 
299  void setValuesOn() { mValueMask.setOn(); }
301  void setValuesOff() { mValueMask.setOff(); }
302 
304  bool isValueOn(const Coord& xyz) const { return mValueMask.isOn(this->coord2offset(xyz)); }
306  bool isValueOn(Index offset) const { assert(offset < SIZE); return mValueMask.isOn(offset); }
307 
309  static bool hasActiveTiles() { return false; }
310 
313  void fill(const CoordBBox& bbox, bool value, bool active = true);
314 
316  void fill(const bool& value);
317 
319  void fill(const bool& value, bool active);
320 
323  template<typename AccessorT>
324  const bool& getValueAndCache(const Coord& xyz, AccessorT&) const {return this->getValue(xyz);}
325 
328  template<typename AccessorT>
329  bool isValueOnAndCache(const Coord& xyz, AccessorT&) const { return this->isValueOn(xyz); }
330 
333  template<typename AccessorT>
334  void setValueAndCache(const Coord& xyz, bool val, AccessorT&) { this->setValueOn(xyz, val); }
335 
339  template<typename AccessorT>
340  void setValueOnlyAndCache(const Coord& xyz, bool val, AccessorT&) {this->setValueOnly(xyz,val);}
341 
344  template<typename AccessorT>
345  void setValueOffAndCache(const Coord& xyz, bool value, AccessorT&)
346  {
347  this->setValueOff(xyz, value);
348  }
349 
353  template<typename AccessorT>
354  void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&)
355  {
356  this->setActiveState(xyz, on);
357  }
358 
362  template<typename AccessorT>
363  bool probeValueAndCache(const Coord& xyz, bool& val, AccessorT&) const
364  {
365  return this->probeValue(xyz, val);
366  }
367 
371  template<typename AccessorT>
372  OPENVDB_DEPRECATED const ValueType& getValue(const Coord& xyz, bool& state, int& level, AccessorT&) const
373  {
374  const Index offset = this->coord2offset(xyz);
375  state = mValueMask.isOn(offset);
376  level = LEVEL;
377  // This *CANNOT* use operator ? for Windows
378  if (mBuffer.mData.isOn(offset)) return sOn; else return sOff;
379  }
380  template<typename ProbeType, typename AccessorT>
381  OPENVDB_DEPRECATED const ValueType& probe(const Coord& xyz, ProbeType& p, AccessorT&) const
382  {
383  const Index offset = this->coord2offset(xyz);
384  p.setState(mValueMask.isOn(offset));
385  p.setLevel(LEVEL);
386  // This *CANNOT* use operator ? for Windows
387  if (mBuffer.mData.isOn(offset)) return sOn; else return sOff;
388  }
389  template<bool State, bool Level, typename AccessorT>
390  OPENVDB_DEPRECATED const ValueType& probe(const Coord& xyz, bool& state, int& level, AccessorT&) const
391  {
392  const Index offset = this->coord2offset(xyz);
393  if (State) state = mValueMask.isOn(offset);
394  if (Level) level = LEVEL;
395  // This *CANNOT* use operator ? for Windows
396  if (mBuffer.mData.isOn(offset)) return sOn; else return sOff;
397  }
400  template<typename AccessorT>
401  static Index getValueLevelAndCache(const Coord&, AccessorT&) { return LEVEL; }
402 
404  template<typename AccessorT>
405  OPENVDB_DEPRECATED void updateCache(const Coord&, AccessorT&) const {}
406 
410  const bool& getFirstValue() const { if (mValueMask.isOn(0)) return sOn; else return sOff; }
414  const bool& getLastValue() const { if (mValueMask.isOn(SIZE-1)) return sOn; else return sOff; }
415 
419  bool isConstant(bool& constValue, bool& state, bool tolerance = 0) const;
421  bool isInactive() const { return mValueMask.isOff(); }
422 
423  void resetBackground(bool oldBackground, bool newBackground);
424 
425  void negate() { mBuffer.mData.toggle(); }
426 
427  void merge(const LeafNode& other);
428 
430 
435  template<typename OtherType>
436  void topologyUnion(const LeafNode<OtherType, Log2Dim>& other);
437 
446  template<typename OtherType>
447  void topologyIntersection(const LeafNode<OtherType, Log2Dim>& other, const bool&);
448 
449  template<typename CombineOp>
450  void combine(const LeafNode& other, CombineOp& op);
451  template<typename CombineOp>
452  void combine(bool, bool valueIsActive, CombineOp& op);
453 
454  template<typename CombineOp>
455  void combine2(const LeafNode& other, bool, bool valueIsActive, CombineOp&);
456  template<typename CombineOp>
457  void combine2(bool, const LeafNode& other, bool valueIsActive, CombineOp&);
458  template<typename CombineOp>
459  void combine2(const LeafNode& b0, const LeafNode& b1, CombineOp&);
460 
465  template<typename BBoxOp> void visitActiveBBox(BBoxOp&) const;
466 
467  template<typename VisitorOp> void visit(VisitorOp&);
468  template<typename VisitorOp> void visit(VisitorOp&) const;
469 
470  template<typename OtherLeafNodeType, typename VisitorOp>
471  void visit2Node(OtherLeafNodeType& other, VisitorOp&);
472  template<typename OtherLeafNodeType, typename VisitorOp>
473  void visit2Node(OtherLeafNodeType& other, VisitorOp&) const;
474  template<typename IterT, typename VisitorOp>
475  void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false);
476  template<typename IterT, typename VisitorOp>
477  void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false) const;
478 
480 
481  void signedFloodFill(bool) {}
482  template<typename PruneOp> void pruneOp(PruneOp&) {}
483  void prune(const ValueType& /*tolerance*/ = zeroVal<ValueType>()) {}
484  void pruneInactive(const ValueType&) {}
486 
488 
489  LeafNode* touchLeaf(const Coord&) { return this; }
490  template<typename AccessorT>
491  LeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; }
492  LeafNode* probeLeaf(const Coord&) { return this; }
493  template<typename AccessorT>
494  LeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; }
496 
497 
498  const LeafNode* probeConstLeaf(const Coord&) const { return this; }
499  template<typename AccessorT>
500  const LeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const { return this; }
502 
503  void merge(const LeafNode& other, bool, bool) { this->merge(other); }
504 
505  //
506  // Iterators
507  //
508 protected:
512 
513  template<typename MaskIterT, typename NodeT, typename ValueT>
514  struct ValueIter:
515  // Derives from SparseIteratorBase, but can also be used as a dense iterator,
516  // if MaskIterT is a dense mask iterator type.
517  public SparseIteratorBase<MaskIterT, ValueIter<MaskIterT, NodeT, ValueT>, NodeT, ValueT>
518  {
520 
522  ValueIter(const MaskIterT& iter, NodeT* parent): BaseT(iter, parent) {}
523 
524  const bool& getItem(Index pos) const { return this->parent().getValue(pos); }
525  const bool& getValue() const { return this->getItem(this->pos()); }
526 
527  // Note: setItem() can't be called on const iterators.
528  void setItem(Index pos, bool value) const { this->parent().setValueOnly(pos, value); }
529  // Note: setValue() can't be called on const iterators.
530  void setValue(bool value) const { this->setItem(this->pos(), value); }
531  };
532 
534  template<typename MaskIterT, typename NodeT>
535  struct ChildIter:
536  public SparseIteratorBase<MaskIterT, ChildIter<MaskIterT, NodeT>, NodeT, bool>
537  {
539  ChildIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase<
540  MaskIterT, ChildIter<MaskIterT, NodeT>, NodeT, bool>(iter, parent) {}
541  };
542 
543  template<typename NodeT, typename ValueT>
544  struct DenseIter: public DenseIteratorBase<
545  MaskDenseIter, DenseIter<NodeT, ValueT>, NodeT, /*ChildT=*/void, ValueT>
546  {
549 
551  DenseIter(const MaskDenseIter& iter, NodeT* parent): BaseT(iter, parent) {}
552 
553  bool getItem(Index pos, void*& child, NonConstValueT& value) const
554  {
555  value = this->parent().getValue(pos);
556  child = NULL;
557  return false; // no child
558  }
559 
560  // Note: setItem() can't be called on const iterators.
561  //void setItem(Index pos, void* child) const {}
562 
563  // Note: unsetItem() can't be called on const iterators.
564  void unsetItem(Index pos, const ValueT& val) const {this->parent().setValueOnly(pos, val);}
565  };
566 
567 public:
568  typedef ValueIter<MaskOnIter, LeafNode, bool> ValueOnIter;
569  typedef ValueIter<MaskOnIter, const LeafNode, const bool> ValueOnCIter;
570  typedef ValueIter<MaskOffIter, LeafNode, bool> ValueOffIter;
571  typedef ValueIter<MaskOffIter, const LeafNode, const bool> ValueOffCIter;
572  typedef ValueIter<MaskDenseIter, LeafNode, bool> ValueAllIter;
573  typedef ValueIter<MaskDenseIter, const LeafNode, const bool> ValueAllCIter;
574  typedef ChildIter<MaskOnIter, LeafNode> ChildOnIter;
575  typedef ChildIter<MaskOnIter, const LeafNode> ChildOnCIter;
576  typedef ChildIter<MaskOffIter, LeafNode> ChildOffIter;
577  typedef ChildIter<MaskOffIter, const LeafNode> ChildOffCIter;
578  typedef DenseIter<LeafNode, bool> ChildAllIter;
579  typedef DenseIter<const LeafNode, const bool> ChildAllCIter;
580 
581  ValueOnCIter cbeginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); }
582  ValueOnCIter beginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); }
583  ValueOnIter beginValueOn() { return ValueOnIter(mValueMask.beginOn(), this); }
584  ValueOffCIter cbeginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); }
585  ValueOffCIter beginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); }
586  ValueOffIter beginValueOff() { return ValueOffIter(mValueMask.beginOff(), this); }
587  ValueAllCIter cbeginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); }
588  ValueAllCIter beginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); }
589  ValueAllIter beginValueAll() { return ValueAllIter(mValueMask.beginDense(), this); }
590 
591  ValueOnCIter cendValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); }
592  ValueOnCIter endValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); }
593  ValueOnIter endValueOn() { return ValueOnIter(mValueMask.endOn(), this); }
594  ValueOffCIter cendValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); }
595  ValueOffCIter endValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); }
596  ValueOffIter endValueOff() { return ValueOffIter(mValueMask.endOff(), this); }
597  ValueAllCIter cendValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); }
598  ValueAllCIter endValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); }
599  ValueAllIter endValueAll() { return ValueAllIter(mValueMask.endDense(), this); }
600 
601  // Note that [c]beginChildOn() and [c]beginChildOff() actually return end iterators,
602  // because leaf nodes have no children.
603  ChildOnCIter cbeginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
604  ChildOnCIter beginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
605  ChildOnIter beginChildOn() { return ChildOnIter(mValueMask.endOn(), this); }
606  ChildOffCIter cbeginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
607  ChildOffCIter beginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
608  ChildOffIter beginChildOff() { return ChildOffIter(mValueMask.endOff(), this); }
609  ChildAllCIter cbeginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); }
610  ChildAllCIter beginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); }
611  ChildAllIter beginChildAll() { return ChildAllIter(mValueMask.beginDense(), this); }
612 
613  ChildOnCIter cendChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
614  ChildOnCIter endChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); }
615  ChildOnIter endChildOn() { return ChildOnIter(mValueMask.endOn(), this); }
616  ChildOffCIter cendChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
617  ChildOffCIter endChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); }
618  ChildOffIter endChildOff() { return ChildOffIter(mValueMask.endOff(), this); }
619  ChildAllCIter cendChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); }
620  ChildAllCIter endChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); }
621  ChildAllIter endChildAll() { return ChildAllIter(mValueMask.endDense(), this); }
622 
623  //
624  // Mask accessors
625  //
626  bool isValueMaskOn(Index n) const { return mValueMask.isOn(n); }
627  bool isValueMaskOn() const { return mValueMask.isOn(); }
628  bool isValueMaskOff(Index n) const { return mValueMask.isOff(n); }
629  bool isValueMaskOff() const { return mValueMask.isOff(); }
630  const NodeMaskType& getValueMask() const { return mValueMask; }
631  NodeMaskType& getValueMask() { return mValueMask; }
632  bool isChildMaskOn(Index) const { return false; } // leaf nodes have no children
633  bool isChildMaskOff(Index) const { return true; }
634  bool isChildMaskOff() const { return true; }
635 protected:
636  void setValueMask(Index n, bool on) { mValueMask.set(n, on); }
637  void setValueMaskOn(Index n) { setValueMask(n, true); }
638  void setValueMaskOff(Index n) { mValueMask.setOff(n); }
639 
641  static void evalNodeOrigin(Coord& xyz) { xyz &= ~(DIM - 1); }
642 
643  template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
644  static inline void doVisit(NodeT&, VisitorOp&);
645 
646  template<typename NodeT, typename OtherNodeT, typename VisitorOp,
647  typename ChildAllIterT, typename OtherChildAllIterT>
648  static inline void doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp&);
649 
650  template<typename NodeT, typename VisitorOp,
651  typename ChildAllIterT, typename OtherChildAllIterT>
652  static inline void doVisit2(NodeT& self, OtherChildAllIterT&, VisitorOp&, bool otherIsLHS);
653 
654 
658  Buffer mBuffer;
661 
662  // These static declarations must be on separate lines to avoid VC9 compiler errors.
663  static const bool sOn;
664  static const bool sOff;
665 
666 private:
669  template<typename, Index> friend class LeafNode;
670 
671  friend struct ValueIter<MaskOnIter, LeafNode, bool>;
672  friend struct ValueIter<MaskOffIter, LeafNode, bool>;
673  friend struct ValueIter<MaskDenseIter, LeafNode, bool>;
674  friend struct ValueIter<MaskOnIter, const LeafNode, bool>;
675  friend struct ValueIter<MaskOffIter, const LeafNode, bool>;
676  friend struct ValueIter<MaskDenseIter, const LeafNode, bool>;
677 
679 
680 
685 
686  // Disallow copying.
687  LeafNode& operator=(const LeafNode&);
688 
689 }; // class LeafNode<bool>
690 
691 
696 template<Index Log2Dim> const bool LeafNode<bool, Log2Dim>::sOn = true;
697 template<Index Log2Dim> const bool LeafNode<bool, Log2Dim>::sOff = false;
698 
699 
701 
702 
703 template<Index Log2Dim>
704 inline
706 {
707 }
708 
709 
710 template<Index Log2Dim>
711 inline
712 LeafNode<bool, Log2Dim>::LeafNode(const Coord& xyz, bool value, bool active):
713  mValueMask(active),
714  mBuffer(value),
715  mOrigin(xyz & (~(DIM - 1)))
716 {
717 }
718 
719 
720 template<Index Log2Dim>
721 template<typename ValueT>
722 inline
724  mValueMask(other.getValueMask()),
725  mBuffer(other.getValueMask()), // value = active state
726  mOrigin(other.getOrigin())
727 {
728 }
729 
730 
731 template<Index Log2Dim>
732 template<typename ValueT>
733 inline
735  bool offValue, bool onValue, TopologyCopy):
736  mValueMask(other.getValueMask()),
737  mBuffer(other.getValueMask()),
738  mOrigin(other.getOrigin())
739 {
740  if (offValue) { if (!onValue) mBuffer.mData.toggle(); else mBuffer.mData.setOn(); }
741 }
742 
743 
744 template<Index Log2Dim>
745 template<typename ValueT>
746 inline
748  bool background, TopologyCopy):
749  mValueMask(other.getValueMask()),
750  mBuffer(background),
751  mOrigin(other.getOrigin())
752 {
753 }
754 
755 
756 template<Index Log2Dim>
757 inline
759  mValueMask(other.mValueMask),
760  mBuffer(other.mBuffer),
761  mOrigin(other.mOrigin)
762 {
763 }
764 
765 
766 template<Index Log2Dim>
767 inline
769 {
770 }
771 
772 
774 
775 
776 template<Index Log2Dim>
777 inline Index64
779 {
780  return sizeof(mOrigin) + mValueMask.memUsage() + mBuffer.memUsage();
781 }
782 
783 
784 template<Index Log2Dim>
785 inline void
787 {
788  const CoordBBox this_bbox = this->getNodeBoundingBox();
789  if (bbox.isInside(this_bbox)) {
790  // nothing to do
791  } else if (this->isDense()) {
792  bbox.expand(this_bbox);
793  } else {
794  for (ValueOnCIter iter=this->cbeginValueOn(); iter; ++iter) bbox.expand(iter.getCoord());
795  }
796 }
797 
798 
799 template<Index Log2Dim>
800 template<typename OtherType, Index OtherLog2Dim>
801 inline bool
803 {
804  assert(other);
805  return (Log2Dim == OtherLog2Dim && mValueMask == other->getValueMask());
806 }
807 
808 
809 template<Index Log2Dim>
810 inline std::string
812 {
813  std::ostringstream ostr;
814  ostr << "LeafNode @" << mOrigin << ": ";
815  for (Index32 n = 0; n < SIZE; ++n) ostr << (mValueMask.isOn(n) ? '#' : '.');
816  return ostr.str();
817 }
818 
819 
821 
822 
823 template<Index Log2Dim>
824 inline Index
826 {
827  assert ((xyz[0] & DIM-1u) < DIM && (xyz[1] & DIM-1u) < DIM && (xyz[2] & DIM-1u) < DIM);
828  return ((xyz[0] & DIM-1u) << 2*Log2Dim) + ((xyz[1] & DIM-1u) << Log2Dim) + (xyz[2] & DIM-1u);
829 }
830 
831 
832 template<Index Log2Dim>
833 inline Coord
835 {
836  assert(n < (1 << 3*Log2Dim));
837  Coord xyz;
838  xyz.setX(n >> 2*Log2Dim);
839  n &= ((1 << 2*Log2Dim) - 1);
840  xyz.setY(n >> Log2Dim);
841  xyz.setZ(n & ((1 << Log2Dim) - 1));
842  return xyz;
843 }
844 
845 
846 template<Index Log2Dim>
847 inline Coord
849 {
850  return (this->offset2coord(n) + this->getOrigin());
851 }
852 
853 
855 
856 
857 template<Index Log2Dim>
858 inline void
859 LeafNode<bool, Log2Dim>::readTopology(std::istream& is, bool /*fromHalf*/)
860 {
861  mValueMask.load(is);
862 }
863 
864 
865 template<Index Log2Dim>
866 inline void
867 LeafNode<bool, Log2Dim>::writeTopology(std::ostream& os, bool /*toHalf*/) const
868 {
869  mValueMask.save(os);
870 }
871 
872 
873 template<Index Log2Dim>
874 inline void
875 LeafNode<bool, Log2Dim>::readBuffers(std::istream& is, bool /*fromHalf*/)
876 {
877  // Read in the value mask.
878  mValueMask.load(is);
879  // Read in the origin.
880  is.read(reinterpret_cast<char*>(&mOrigin), sizeof(Coord::ValueType) * 3);
881 
883  // Read in the mask for the voxel values.
884  mBuffer.mData.load(is);
885  } else {
886  // Older files stored one or more bool arrays.
887 
888  // Read in the number of buffers, which should now always be one.
889  int8_t numBuffers = 0;
890  is.read(reinterpret_cast<char*>(&numBuffers), sizeof(int8_t));
891 
892  // Read in the buffer.
893  // (Note: prior to the bool leaf optimization, buffers were always compressed.)
894  boost::shared_array<bool> buf(new bool[SIZE]);
895  io::readData<bool>(is, buf.get(), SIZE, /*isCompressed=*/true);
896 
897  // Transfer values to mBuffer.
898  mBuffer.mData.setOff();
899  for (Index i = 0; i < SIZE; ++i) {
900  if (buf[i]) mBuffer.mData.setOn(i);
901  }
902 
903  if (numBuffers > 1) {
904  // Read in and discard auxiliary buffers that were created with
905  // earlier versions of the library.
906  for (int i = 1; i < numBuffers; ++i) {
907  io::readData<bool>(is, buf.get(), SIZE, /*isCompressed=*/true);
908  }
909  }
910  }
911 }
912 
913 
914 template<Index Log2Dim>
915 inline void
916 LeafNode<bool, Log2Dim>::writeBuffers(std::ostream& os, bool /*toHalf*/) const
917 {
918  // Write out the value mask.
919  mValueMask.save(os);
920  // Write out the origin.
921  os.write(reinterpret_cast<const char*>(&mOrigin), sizeof(Coord::ValueType) * 3);
922  // Write out the voxel values.
923  mBuffer.mData.save(os);
924 }
925 
926 
928 
929 
930 template<Index Log2Dim>
931 inline bool
933 {
934  return (mValueMask == other.mValueMask && mBuffer.mData == other.mBuffer.mData);
935 }
936 
937 
938 template<Index Log2Dim>
939 inline bool
941 {
942  return !(this->operator==(other));
943 }
944 
945 
947 
948 
949 template<Index Log2Dim>
950 inline bool
951 LeafNode<bool, Log2Dim>::isConstant(bool& constValue, bool& state, bool tolerance) const
952 {
953  if (!(mValueMask.isOn() || mValueMask.isOff())) return false;
954 
955  // Note: if tolerance is true (i.e., 1), then all boolean values compare equal.
956  if (!tolerance && !(mBuffer.mData.isOn() || mBuffer.mData.isOff())) return false;
957 
958  state = mValueMask.isOn();
959  constValue = mBuffer.mData.isOn();
960  return true;
961 }
962 
963 
965 
966 
967 template<Index Log2Dim>
968 inline const bool&
970 {
971  // This *CANNOT* use operator ? because Visual C++
972  if (mBuffer.mData.isOn(this->coord2offset(xyz))) return sOn; else return sOff;
973 }
974 
975 
976 template<Index Log2Dim>
977 inline const bool&
979 {
980  assert(offset < SIZE);
981  // This *CANNOT* use operator ? for Windows
982  if (mBuffer.mData.isOn(offset)) return sOn; else return sOff;
983 }
984 
985 
986 template<Index Log2Dim>
987 inline bool
988 LeafNode<bool, Log2Dim>::probeValue(const Coord& xyz, bool& val) const
989 {
990  const Index offset = this->coord2offset(xyz);
991  val = mBuffer.mData.isOn(offset);
992  return mValueMask.isOn(offset);
993 }
994 
995 
996 template<Index Log2Dim>
997 inline void
999 {
1000  const Index offset = this->coord2offset(xyz);
1001  mValueMask.setOn(offset);
1002  mBuffer.mData.set(offset, val);
1003 }
1004 
1005 
1006 template<Index Log2Dim>
1007 inline void
1009 {
1010  mValueMask.set(this->coord2offset(xyz), on);
1011 }
1012 
1013 
1014 template<Index Log2Dim>
1015 inline void
1017 {
1018  const Index offset = this->coord2offset(xyz);
1019  mValueMask.setOff(offset);
1020  mBuffer.mData.set(offset, val);
1021 }
1022 
1023 
1024 template<Index Log2Dim>
1025 inline void
1027 {
1028  const Index offset = this->coord2offset(xyz);
1029  mValueMask.setOn(offset);
1030  mBuffer.mData.set(offset, val && mBuffer.mData.isOn(offset));
1031 }
1032 
1033 
1034 template<Index Log2Dim>
1035 inline void
1037 {
1038  const Index offset = this->coord2offset(xyz);
1039  mValueMask.setOn(offset);
1040  mBuffer.mData.set(offset, val || mBuffer.mData.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 || mBuffer.mData.isOn(offset)); // true + true = true
1051 }
1052 
1053 
1054 template<Index Log2Dim>
1055 inline void
1057 {
1058  if (val) mBuffer.mData |= mValueMask; // set all active voxels to true
1059 }
1060 
1061 
1062 template<Index Log2Dim>
1063 inline void
1065 {
1066  if (!val) mBuffer.mData &= !mValueMask; // set all active voxels to false
1067 }
1068 
1069 
1071 
1072 
1073 template<Index Log2Dim>
1074 inline void
1075 LeafNode<bool, Log2Dim>::resetBackground(bool oldBackground, bool newBackground)
1076 {
1077  if (newBackground != oldBackground) {
1078  // Flip mBuffer's background bits and zero its foreground bits.
1079  NodeMaskType bgMask = !(mBuffer.mData | mValueMask);
1080  // Overwrite mBuffer's background bits, leaving its foreground bits intact.
1081  mBuffer.mData = (mBuffer.mData & mValueMask) | bgMask;
1082  }
1083 }
1084 
1085 
1086 template<Index Log2Dim>
1087 inline void
1089 {
1090  for (typename NodeMaskType::OnIterator iter = other.mValueMask.beginOn(); iter; ++iter) {
1091  const Index n = iter.pos();
1092  if (mValueMask.isOn(n)) continue;
1093  mBuffer.mData.set(n, other.mBuffer.mData.isOn(n));
1094  mValueMask.setOn(n);
1095  }
1096 }
1097 
1098 
1099 template<Index Log2Dim>
1100 template<typename OtherType>
1101 inline void
1103 {
1104  mValueMask |= other.getValueMask();
1105 }
1106 
1107 template<Index Log2Dim>
1108 template<typename OtherType>
1109 inline void
1111  const bool&)
1112 {
1113  mValueMask &= other.getValueMask();
1114 }
1115 
1116 template<Index Log2Dim>
1117 inline void
1118 LeafNode<bool, Log2Dim>::fill(const CoordBBox& bbox, bool value, bool active)
1119 {
1120  for (Int32 x = bbox.min().x(); x <= bbox.max().x(); ++x) {
1121  const Index offsetX = (x&DIM-1u)<<2*Log2Dim;
1122  for (Int32 y = bbox.min().y(); y <= bbox.max().y(); ++y) {
1123  const Index offsetXY = offsetX + ((y&DIM-1u)<< Log2Dim);
1124  for (Int32 z = bbox.min().z(); z <= bbox.max().z(); ++z) {
1125  const Index offset = offsetXY + (z&DIM-1u);
1126  mValueMask.set(offset, active);
1127  mBuffer.mData.set(offset, value);
1128  }
1129  }
1130  }
1131 }
1132 
1133 template<Index Log2Dim>
1134 inline void
1136 {
1137  mBuffer.fill(value);
1138 }
1139 
1140 template<Index Log2Dim>
1141 inline void
1142 LeafNode<bool, Log2Dim>::fill(const bool& value, bool active)
1143 {
1144  mBuffer.fill(value);
1145  mValueMask.set(active);
1146 }
1147 
1149 
1150 
1151 template<Index Log2Dim>
1152 template<typename CombineOp>
1153 inline void
1154 LeafNode<bool, Log2Dim>::combine(const LeafNode& other, CombineOp& op)
1155 {
1156  CombineArgs<bool> args;
1157  for (Index i = 0; i < SIZE; ++i) {
1158  bool result = false, aVal = mBuffer.mData.isOn(i), bVal = other.mBuffer.mData.isOn(i);
1159  op(args.setARef(aVal)
1160  .setAIsActive(mValueMask.isOn(i))
1161  .setBRef(bVal)
1162  .setBIsActive(other.mValueMask.isOn(i))
1163  .setResultRef(result));
1164  mValueMask.set(i, args.resultIsActive());
1165  mBuffer.mData.set(i, result);
1166  }
1167 }
1168 
1169 
1170 template<Index Log2Dim>
1171 template<typename CombineOp>
1172 inline void
1173 LeafNode<bool, Log2Dim>::combine(bool value, bool valueIsActive, CombineOp& op)
1174 {
1175  CombineArgs<bool> args;
1176  args.setBRef(value).setBIsActive(valueIsActive);
1177  for (Index i = 0; i < SIZE; ++i) {
1178  bool result = false, aVal = mBuffer.mData.isOn(i);
1179  op(args.setARef(aVal)
1180  .setAIsActive(mValueMask.isOn(i))
1181  .setResultRef(result));
1182  mValueMask.set(i, args.resultIsActive());
1183  mBuffer.mData.set(i, result);
1184  }
1185 }
1186 
1187 
1189 
1190 
1191 template<Index Log2Dim>
1192 template<typename CombineOp>
1193 inline void
1195  bool valueIsActive, CombineOp& op)
1196 {
1197  CombineArgs<bool> args;
1198  args.setBRef(value).setBIsActive(valueIsActive);
1199  for (Index i = 0; i < SIZE; ++i) {
1200  bool result = false, aVal = other.mBuffer.mData.isOn(i);
1201  op(args.setARef(aVal)
1202  .setAIsActive(other.mValueMask.isOn(i))
1203  .setResultRef(result));
1204  mValueMask.set(i, args.resultIsActive());
1205  mBuffer.mData.set(i, result);
1206  }
1207 }
1208 
1209 
1210 template<Index Log2Dim>
1211 template<typename CombineOp>
1212 inline void
1214  bool valueIsActive, CombineOp& op)
1215 {
1216  CombineArgs<bool> args;
1217  args.setARef(value).setAIsActive(valueIsActive);
1218  for (Index i = 0; i < SIZE; ++i) {
1219  bool result = false, bVal = other.mBuffer.mData.isOn(i);
1220  op(args.setBRef(bVal)
1221  .setBIsActive(other.mValueMask.isOn(i))
1222  .setResultRef(result));
1223  mValueMask.set(i, args.resultIsActive());
1224  mBuffer.mData.set(i, result);
1225  }
1226 }
1227 
1228 
1229 template<Index Log2Dim>
1230 template<typename CombineOp>
1231 inline void
1232 LeafNode<bool, Log2Dim>::combine2(const LeafNode& b0, const LeafNode& b1, CombineOp& op)
1233 {
1234  CombineArgs<bool> args;
1235  for (Index i = 0; i < SIZE; ++i) {
1236  // Default behavior: output voxel is active if either input voxel is active.
1237  mValueMask.set(i, b0.mValueMask.isOn(i) || b1.mValueMask.isOn(i));
1238 
1239  bool result = false, b0Val = b0.mBuffer.mData.isOn(i), b1Val = b1.mBuffer.mData.isOn(i);
1240  op(args.setARef(b0Val)
1241  .setAIsActive(b0.mValueMask.isOn(i))
1242  .setBRef(b1Val)
1243  .setBIsActive(b1.mValueMask.isOn(i))
1244  .setResultRef(result));
1245  mValueMask.set(i, args.resultIsActive());
1246  mBuffer.mData.set(i, result);
1247  }
1248 }
1249 
1250 
1252 
1253 template<Index Log2Dim>
1254 template<typename BBoxOp>
1255 inline void
1257 {
1258  if (op.template descent<LEVEL>()) {
1259  for (ValueOnCIter i=this->cbeginValueOn(); i; ++i) {
1260 #ifdef _MSC_VER
1261  op.operator()<LEVEL>(CoordBBox(i.getCoord(),1));
1262 #else
1263  op.template operator()<LEVEL>(CoordBBox(i.getCoord(),1));
1264 #endif
1265  }
1266  } else {
1267 #ifdef _MSC_VER
1268  op.operator()<LEVEL>(this->getNodeBoundingBox());
1269 #else
1270  op.template operator()<LEVEL>(this->getNodeBoundingBox());
1271 #endif
1272  }
1273 }
1274 
1275 
1276 template<Index Log2Dim>
1277 template<typename VisitorOp>
1278 inline void
1280 {
1281  doVisit<LeafNode, VisitorOp, ChildAllIter>(*this, op);
1282 }
1283 
1284 
1285 template<Index Log2Dim>
1286 template<typename VisitorOp>
1287 inline void
1289 {
1290  doVisit<const LeafNode, VisitorOp, ChildAllCIter>(*this, op);
1291 }
1292 
1293 
1294 template<Index Log2Dim>
1295 template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
1296 inline void
1297 LeafNode<bool, Log2Dim>::doVisit(NodeT& self, VisitorOp& op)
1298 {
1299  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1300  op(iter);
1301  }
1302 }
1303 
1304 
1306 
1307 
1308 template<Index Log2Dim>
1309 template<typename OtherLeafNodeType, typename VisitorOp>
1310 inline void
1311 LeafNode<bool, Log2Dim>::visit2Node(OtherLeafNodeType& other, VisitorOp& op)
1312 {
1313  doVisit2Node<LeafNode, OtherLeafNodeType, VisitorOp, ChildAllIter,
1314  typename OtherLeafNodeType::ChildAllIter>(*this, other, op);
1315 }
1316 
1317 
1318 template<Index Log2Dim>
1319 template<typename OtherLeafNodeType, typename VisitorOp>
1320 inline void
1321 LeafNode<bool, Log2Dim>::visit2Node(OtherLeafNodeType& other, VisitorOp& op) const
1322 {
1323  doVisit2Node<const LeafNode, OtherLeafNodeType, VisitorOp, ChildAllCIter,
1324  typename OtherLeafNodeType::ChildAllCIter>(*this, other, op);
1325 }
1326 
1327 
1328 template<Index Log2Dim>
1329 template<
1330  typename NodeT,
1331  typename OtherNodeT,
1332  typename VisitorOp,
1333  typename ChildAllIterT,
1334  typename OtherChildAllIterT>
1335 inline void
1336 LeafNode<bool, Log2Dim>::doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp& op)
1337 {
1338  // Allow the two nodes to have different ValueTypes, but not different dimensions.
1339  BOOST_STATIC_ASSERT(OtherNodeT::SIZE == NodeT::SIZE);
1340  BOOST_STATIC_ASSERT(OtherNodeT::LEVEL == NodeT::LEVEL);
1341 
1342  ChildAllIterT iter = self.beginChildAll();
1343  OtherChildAllIterT otherIter = other.beginChildAll();
1344 
1345  for ( ; iter && otherIter; ++iter, ++otherIter) {
1346  op(iter, otherIter);
1347  }
1348 }
1349 
1350 
1352 
1353 
1354 template<Index Log2Dim>
1355 template<typename IterT, typename VisitorOp>
1356 inline void
1357 LeafNode<bool, Log2Dim>::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS)
1358 {
1359  doVisit2<LeafNode, VisitorOp, ChildAllIter, IterT>(*this, otherIter, op, otherIsLHS);
1360 }
1361 
1362 
1363 template<Index Log2Dim>
1364 template<typename IterT, typename VisitorOp>
1365 inline void
1366 LeafNode<bool, Log2Dim>::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS) const
1367 {
1368  doVisit2<const LeafNode, VisitorOp, ChildAllCIter, IterT>(*this, otherIter, op, otherIsLHS);
1369 }
1370 
1371 
1372 template<Index Log2Dim>
1373 template<
1374  typename NodeT,
1375  typename VisitorOp,
1376  typename ChildAllIterT,
1377  typename OtherChildAllIterT>
1378 inline void
1379 LeafNode<bool, Log2Dim>::doVisit2(NodeT& self, OtherChildAllIterT& otherIter,
1380  VisitorOp& op, bool otherIsLHS)
1381 {
1382  if (!otherIter) return;
1383 
1384  if (otherIsLHS) {
1385  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1386  op(otherIter, iter);
1387  }
1388  } else {
1389  for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
1390  op(iter, otherIter);
1391  }
1392  }
1393 }
1394 
1395 } // namespace tree
1396 } // namespace OPENVDB_VERSION_NAME
1397 } // namespace openvdb
1398 
1399 #endif // OPENVDB_TREE_LEAFNODEBOOL_HAS_BEEN_INCLUDED
1400 
1401 // Copyright (c) 2012 DreamWorks Animation LLC
1402 // All rights reserved. This software is distributed under the
1403 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )