OpenVDB: InternalNode.h Source File

OpenVDB 4.0.2

InternalNode.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2017 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 //
34
35 #ifndef OPENVDB_TREE_INTERNALNODE_HAS_BEEN_INCLUDED
36 #define OPENVDB_TREE_INTERNALNODE_HAS_BEEN_INCLUDED
37
38 #include <openvdb/Platform.h>
39 #include <openvdb/util/NodeMasks.h>
40 #include <openvdb/io/Compression.h> // for io::readCompressedValues(), etc.
41 #include <openvdb/math/Math.h> // for math::isExactlyEqual(), etc.
42 #include <openvdb/version.h>
43 #include <openvdb/Types.h>
44 #include "Iterator.h"
45 #include "NodeUnion.h"
46 #include <tbb/parallel_for.h>
47 #include <memory>
48 #include <type_traits>
49
50
51 namespace openvdb {
52 OPENVDB_USE_VERSION_NAMESPACE
53 namespace OPENVDB_VERSION_NAME {
54 namespace tree {
55
56 template<typename, Index, typename> struct SameInternalConfig; // forward declaration
57
58
59 template<typename _ChildNodeType, Index Log2Dim>
60 class InternalNode
61 {
62 public:
63 using ChildNodeType = _ChildNodeType;
64 using LeafNodeType = typename ChildNodeType::LeafNodeType;
65 using ValueType = typename ChildNodeType::ValueType;
66 using BuildType = typename ChildNodeType::BuildType;
67 using UnionType = NodeUnion<ValueType, ChildNodeType>;
68 using NodeMaskType = util::NodeMask<Log2Dim>;
69
70 static const Index
71 LOG2DIM = Log2Dim, // log2 of tile count in one dimension
72 TOTAL = Log2Dim + ChildNodeType::TOTAL, // log2 of voxel count in one dimension
73 DIM = 1 << TOTAL, // total voxel count in one dimension
74 NUM_VALUES = 1 << (3 * Log2Dim), // total voxel count represented by this node
75 LEVEL = 1 + ChildNodeType::LEVEL; // level 0 = leaf
76 static const Index64
77 NUM_VOXELS = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node
78
81 template<typename OtherValueType>
82 struct ValueConverter {
83 using Type = InternalNode<typename ChildNodeType::template ValueConverter<
84 OtherValueType>::Type, Log2Dim>;
85 };
86
90 template<typename OtherNodeType>
91 struct SameConfiguration {
92 static const bool value =
93 SameInternalConfig<ChildNodeType, Log2Dim, OtherNodeType>::value;
94 };
95
96
99 InternalNode() {}
100
103 explicit InternalNode(const ValueType& offValue);
104
109 InternalNode(const Coord& origin, const ValueType& fillValue, bool active = false);
110
111 #ifndef OPENVDB_2_ABI_COMPATIBLE
112 InternalNode(PartialCreate, const Coord&, const ValueType& fillValue, bool active = false);
113 #endif
114
118 InternalNode(const InternalNode&);
119
123 template<typename OtherChildNodeType>
124 explicit InternalNode(const InternalNode<OtherChildNodeType, Log2Dim>& other);
125
129 template<typename OtherChildNodeType>
130 InternalNode(const InternalNode<OtherChildNodeType, Log2Dim>& other,
131 const ValueType& background, TopologyCopy);
132
136 template<typename OtherChildNodeType>
137 InternalNode(const InternalNode<OtherChildNodeType, Log2Dim>& other,
138 const ValueType& offValue, const ValueType& onValue, TopologyCopy);
139
140 virtual ~InternalNode();
141
142 protected:
143 using MaskOnIterator = typename NodeMaskType::OnIterator;
144 using MaskOffIterator = typename NodeMaskType::OffIterator;
145 using MaskDenseIterator = typename NodeMaskType::DenseIterator;
146
147 // Type tags to disambiguate template instantiations
148 struct ValueOn {}; struct ValueOff {}; struct ValueAll {};
149 struct ChildOn {}; struct ChildOff {}; struct ChildAll {};
150
151 // The following class templates implement the iterator interfaces specified in Iterator.h
152 // by providing getItem(), setItem() and/or modifyItem() methods.
153
154 // Sparse iterator that visits child nodes of an InternalNode
155 template<typename NodeT, typename ChildT, typename MaskIterT, typename TagT>
156 struct ChildIter: public SparseIteratorBase<
157 MaskIterT, ChildIter<NodeT, ChildT, MaskIterT, TagT>, NodeT, ChildT>
158 {
159 ChildIter() {}
160 ChildIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase<
161 MaskIterT, ChildIter<NodeT, ChildT, MaskIterT, TagT>, NodeT, ChildT>(iter, parent) {}
162
163 ChildT& getItem(Index pos) const
164 {
165 assert(this->parent().isChildMaskOn(pos));
166 return *(this->parent().getChildNode(pos));
167 }
168
169 // Note: setItem() can't be called on const iterators.
170 void setItem(Index pos, const ChildT& c) const { this->parent().resetChildNode(pos, &c); }
171
172 // Note: modifyItem() isn't implemented, since it's not useful for child node pointers.
173 };// ChildIter
174
175 // Sparse iterator that visits tile values of an InternalNode
176 template<typename NodeT, typename ValueT, typename MaskIterT, typename TagT>
177 struct ValueIter: public SparseIteratorBase<
178 MaskIterT, ValueIter<NodeT, ValueT, MaskIterT, TagT>, NodeT, ValueT>
179 {
180 ValueIter() {}
181 ValueIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase<
182 MaskIterT, ValueIter<NodeT, ValueT, MaskIterT, TagT>, NodeT, ValueT>(iter, parent) {}
183
184 const ValueT& getItem(Index pos) const { return this->parent().mNodes[pos].getValue(); }
185
186 // Note: setItem() can't be called on const iterators.
187 void setItem(Index pos, const ValueT& v) const { this->parent().mNodes[pos].setValue(v); }
188
189 // Note: modifyItem() can't be called on const iterators.
190 template<typename ModifyOp>
191 void modifyItem(Index pos, const ModifyOp& op) const
192 {
193 op(this->parent().mNodes[pos].getValue());
194 }
195 };// ValueIter
196
197 // Dense iterator that visits both tiles and child nodes of an InternalNode
198 template<typename NodeT, typename ChildT, typename ValueT, typename TagT>
199 struct DenseIter: public DenseIteratorBase<
200 MaskDenseIterator, DenseIter<NodeT, ChildT, ValueT, TagT>, NodeT, ChildT, ValueT>
201 {
202 using BaseT = DenseIteratorBase<MaskDenseIterator, DenseIter, NodeT, ChildT, ValueT>;
203 using NonConstValueT = typename BaseT::NonConstValueType;
204
205 DenseIter() {}
206 DenseIter(const MaskDenseIterator& iter, NodeT* parent):
207 DenseIteratorBase<MaskDenseIterator, DenseIter, NodeT, ChildT, ValueT>(iter, parent) {}
208
209 bool getItem(Index pos, ChildT*& child, NonConstValueT& value) const
210 {
211 if (this->parent().isChildMaskOn(pos)) {
212 child = this->parent().getChildNode(pos);
213 return true;
214 }
215 child = nullptr;
216 value = this->parent().mNodes[pos].getValue();
217 return false;
218 }
219
220 // Note: setItem() can't be called on const iterators.
221 void setItem(Index pos, ChildT* child) const
222 {
223 this->parent().resetChildNode(pos, child);
224 }
225
226 // Note: unsetItem() can't be called on const iterators.
227 void unsetItem(Index pos, const ValueT& value) const
228 {
229 this->parent().unsetChildNode(pos, value);
230 }
231 };// DenseIter
232
233 public:
234 // Iterators (see Iterator.h for usage)
235 using ChildOnIter = ChildIter<InternalNode, ChildNodeType, MaskOnIterator, ChildOn>;
236 using ChildOnCIter = ChildIter<const InternalNode,const ChildNodeType,MaskOnIterator,ChildOn>;
237 using ChildOffIter = ValueIter<InternalNode, const ValueType, MaskOffIterator, ChildOff>;
238 using ChildOffCIter = ValueIter<const InternalNode,const ValueType,MaskOffIterator,ChildOff>;
239 using ChildAllIter = DenseIter<InternalNode, ChildNodeType, ValueType, ChildAll>;
240 using ChildAllCIter = DenseIter<const InternalNode,const ChildNodeType, ValueType, ChildAll>;
241
242 using ValueOnIter = ValueIter<InternalNode, const ValueType, MaskOnIterator, ValueOn>;
243 using ValueOnCIter = ValueIter<const InternalNode, const ValueType, MaskOnIterator, ValueOn>;
244 using ValueOffIter = ValueIter<InternalNode, const ValueType, MaskOffIterator, ValueOff>;
245 using ValueOffCIter = ValueIter<const InternalNode,const ValueType,MaskOffIterator,ValueOff>;
246 using ValueAllIter = ValueIter<InternalNode, const ValueType, MaskOffIterator, ValueAll>;
247 using ValueAllCIter = ValueIter<const InternalNode,const ValueType,MaskOffIterator,ValueAll>;
248
249 ChildOnCIter cbeginChildOn() const { return ChildOnCIter(mChildMask.beginOn(), this); }
250 ChildOffCIter cbeginChildOff() const { return ChildOffCIter(mChildMask.beginOff(), this); }
251 ChildAllCIter cbeginChildAll() const { return ChildAllCIter(mChildMask.beginDense(), this); }
252 ChildOnCIter beginChildOn() const { return cbeginChildOn(); }
253 ChildOffCIter beginChildOff() const { return cbeginChildOff(); }
254 ChildAllCIter beginChildAll() const { return cbeginChildAll(); }
255 ChildOnIter beginChildOn() { return ChildOnIter(mChildMask.beginOn(), this); }
256 ChildOffIter beginChildOff() { return ChildOffIter(mChildMask.beginOff(), this); }
257 ChildAllIter beginChildAll() { return ChildAllIter(mChildMask.beginDense(), this); }
258
259 ValueOnCIter cbeginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); }
261 ValueOffCIter cbeginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); }
262 ValueAllCIter cbeginValueAll() const { return ValueAllCIter(mChildMask.beginOff(), this); }
263 ValueOnCIter beginValueOn() const { return cbeginValueOn(); }
265 ValueOffCIter beginValueOff() const { return cbeginValueOff(); }
266 ValueAllCIter beginValueAll() const { return cbeginValueAll(); }
267 ValueOnIter beginValueOn() { return ValueOnIter(mValueMask.beginOn(), this); }
269 ValueOffIter beginValueOff() { return ValueOffIter(mValueMask.beginOff(), this); }
270 ValueAllIter beginValueAll() { return ValueAllIter(mChildMask.beginOff(), this); }
271
272
275 static Index dim() { return DIM; }
278 static Index getLevel() { return LEVEL; }
281 static void getNodeLog2Dims(std::vector<Index>& dims);
285 static Index getChildDim() { return ChildNodeType::DIM; }
286
288 static Index coordToOffset(const Coord& xyz);
291 static void offsetToLocalCoord(Index n, Coord& xyz);
293 Coord offsetToGlobalCoord(Index n) const;
294
296 const Coord& origin() const { return mOrigin; }
298 void setOrigin(const Coord& origin) { mOrigin = origin; }
299
300 Index32 leafCount() const;
301 Index32 nonLeafCount() const;
302 Index64 onVoxelCount() const;
303 Index64 offVoxelCount() const;
304 Index64 onLeafVoxelCount() const;
305 Index64 offLeafVoxelCount() const;
306 Index64 onTileCount() const;
307
309 Index64 memUsage() const;
310
315 void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const;
316
319 CoordBBox getNodeBoundingBox() const { return CoordBBox::createCube(mOrigin, DIM); }
320
322 bool isEmpty() const { return mChildMask.isOff(); }
323
329 bool isConstant(ValueType& firstValue, bool& state,
330 const ValueType& tolerance = zeroVal<ValueType>()) const;
331
346 bool isConstant(ValueType& minValue, ValueType& maxValue,
347 bool& state, const ValueType& tolerance = zeroVal<ValueType>()) const;
348
350 bool isInactive() const { return this->isChildMaskOff() && this->isValueMaskOff(); }
351
353 bool isValueOn(const Coord& xyz) const;
355 bool isValueOn(Index offset) const { return mValueMask.isOn(offset); }
356
358 bool hasActiveTiles() const;
359
360 const ValueType& getValue(const Coord& xyz) const;
361 bool probeValue(const Coord& xyz, ValueType& value) const;
362
365 Index getValueLevel(const Coord& xyz) const;
366
369 const ValueType& getFirstValue() const;
372 const ValueType& getLastValue() const;
373
375 void setActiveState(const Coord& xyz, bool on);
377 void setValueOnly(const Coord& xyz, const ValueType& value);
379 void setValueOn(const Coord& xyz);
381 void setValueOn(const Coord& xyz, const ValueType& value);
383 void setValueOff(const Coord& xyz);
385 void setValueOff(const Coord& xyz, const ValueType& value);
386
389 template<typename ModifyOp>
390 void modifyValue(const Coord& xyz, const ModifyOp& op);
392 template<typename ModifyOp>
393 void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op);
394
399 template<typename AccessorT>
400 const ValueType& getValueAndCache(const Coord& xyz, AccessorT&) const;
401
406 template<typename AccessorT>
407 bool isValueOnAndCache(const Coord& xyz, AccessorT&) const;
408
413 template<typename AccessorT>
414 void setValueAndCache(const Coord& xyz, const ValueType& value, AccessorT&);
415
420 template<typename AccessorT>
421 void setValueOnlyAndCache(const Coord& xyz, const ValueType& value, AccessorT&);
422
428 template<typename ModifyOp, typename AccessorT>
429 void modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&);
430
435 template<typename ModifyOp, typename AccessorT>
436 void modifyValueAndActiveStateAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&);
437
442 template<typename AccessorT>
443 void setValueOffAndCache(const Coord& xyz, const ValueType& value, AccessorT&);
444
449 template<typename AccessorT>
450 void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&);
451
457 template<typename AccessorT>
458 bool probeValueAndCache(const Coord& xyz, ValueType& value, AccessorT&) const;
459
466 template<typename AccessorT>
467 Index getValueLevelAndCache(const Coord& xyz, AccessorT&) const;
468
470 void setValuesOn();
471
472 //
473 // I/O
474 //
475 void writeTopology(std::ostream&, bool toHalf = false) const;
476 void readTopology(std::istream&, bool fromHalf = false);
477 void writeBuffers(std::ostream&, bool toHalf = false) const;
478 void readBuffers(std::istream&, bool fromHalf = false);
479 void readBuffers(std::istream&, const CoordBBox&, bool fromHalf = false);
480
481
482 //
483 // Aux methods
484 //
485
487 void negate();
488
497 void fill(const CoordBBox& bbox, const ValueType& value, bool active = true);
498
506 void denseFill(const CoordBBox& bbox, const ValueType& value, bool active = true);
507
511 void voxelizeActiveTiles(bool threaded = true);
512
520 template<typename DenseT>
521 void copyToDense(const CoordBBox& bbox, DenseT& dense) const;
522
525 template<MergePolicy Policy>
526 void merge(InternalNode& other, const ValueType& background, const ValueType& otherBackground);
527
530 template<MergePolicy Policy> void merge(const ValueType& tileValue, bool tileActive);
531
544 template<typename OtherChildNodeType>
545 void topologyUnion(const InternalNode<OtherChildNodeType, Log2Dim>& other);
546
560 template<typename OtherChildNodeType>
561 void topologyIntersection(const InternalNode<OtherChildNodeType, Log2Dim>& other,
562 const ValueType& background);
563
575 template<typename OtherChildNodeType>
576 void topologyDifference(const InternalNode<OtherChildNodeType, Log2Dim>& other,
577 const ValueType& background);
578
579 template<typename CombineOp>
580 void combine(InternalNode& other, CombineOp&);
581 template<typename CombineOp>
582 void combine(const ValueType& value, bool valueIsActive, CombineOp&);
583
584 template<typename CombineOp, typename OtherNodeType /*= InternalNode*/>
585 void combine2(const InternalNode& other0, const OtherNodeType& other1, CombineOp&);
586 template<typename CombineOp, typename OtherNodeType /*= InternalNode*/>
587 void combine2(const ValueType& value, const OtherNodeType& other, bool valIsActive, CombineOp&);
588 template<typename CombineOp, typename OtherValueType>
589 void combine2(const InternalNode& other, const OtherValueType&, bool valIsActive, CombineOp&);
590
596 template<typename BBoxOp> void visitActiveBBox(BBoxOp&) const;
597
598 template<typename VisitorOp> void visit(VisitorOp&);
599 template<typename VisitorOp> void visit(VisitorOp&) const;
600
601 template<typename OtherNodeType, typename VisitorOp>
602 void visit2Node(OtherNodeType& other, VisitorOp&);
603 template<typename OtherNodeType, typename VisitorOp>
604 void visit2Node(OtherNodeType& other, VisitorOp&) const;
605 template<typename IterT, typename VisitorOp>
606 void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false);
607 template<typename IterT, typename VisitorOp>
608 void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false) const;
609
611 void clip(const CoordBBox&, const ValueType& background);
612
616 void prune(const ValueType& tolerance = zeroVal<ValueType>());
617
620 void addLeaf(LeafNodeType* leaf);
621
624 template<typename AccessorT>
625 void addLeafAndCache(LeafNodeType* leaf, AccessorT&);
626
635 template<typename NodeT>
636 NodeT* stealNode(const Coord& xyz, const ValueType& value, bool state);
637
640 void addTile(Index level, const Coord& xyz, const ValueType& value, bool state);
641
643 void addTile(Index offset, const ValueType& value, bool state);
644
647 template<typename AccessorT>
648 void addTileAndCache(Index level, const Coord& xyz, const ValueType&, bool state, AccessorT&);
649
651 template<typename NodeType> NodeType* probeNode(const Coord& xyz);
654 template<typename NodeType> const NodeType* probeConstNode(const Coord& xyz) const;
656
658 template<typename NodeType, typename AccessorT>
661 NodeType* probeNodeAndCache(const Coord& xyz, AccessorT&);
662 template<typename NodeType, typename AccessorT>
663 const NodeType* probeConstNodeAndCache(const Coord& xyz, AccessorT&) const;
665
667 LeafNodeType* probeLeaf(const Coord& xyz);
670 const LeafNodeType* probeConstLeaf(const Coord& xyz) const;
671 const LeafNodeType* probeLeaf(const Coord& xyz) const;
673
675 template<typename AccessorT>
678 LeafNodeType* probeLeafAndCache(const Coord& xyz, AccessorT& acc);
679 template<typename AccessorT>
680 const LeafNodeType* probeConstLeafAndCache(const Coord& xyz, AccessorT& acc) const;
681 template<typename AccessorT>
682 const LeafNodeType* probeLeafAndCache(const Coord& xyz, AccessorT& acc) const;
684
691 LeafNodeType* touchLeaf(const Coord& xyz);
692
695 template<typename AccessorT>
696 LeafNodeType* touchLeafAndCache(const Coord& xyz, AccessorT&);
697
699 template<typename ArrayT>
722 void getNodes(ArrayT& array);
723 template<typename ArrayT>
724 void getNodes(ArrayT& array) const;
726
750 template<typename ArrayT>
751 void stealNodes(ArrayT& array, const ValueType& value, bool state);
752
755 void resetBackground(const ValueType& oldBackground, const ValueType& newBackground);
756
759 template<typename OtherChildNodeType, Index OtherLog2Dim>
760 bool hasSameTopology(const InternalNode<OtherChildNodeType, OtherLog2Dim>* other) const;
761
762 protected:
764 friend class IteratorBase<MaskOnIterator, InternalNode>;
767 friend class IteratorBase<MaskOffIterator, InternalNode>;
768 friend class IteratorBase<MaskDenseIterator, InternalNode>;
770
773 template<typename, Index> friend class InternalNode;
774
775 // Mask accessors
776 public:
777 bool isValueMaskOn(Index n) const { return mValueMask.isOn(n); }
778 bool isValueMaskOn() const { return mValueMask.isOn(); }
779 bool isValueMaskOff(Index n) const { return mValueMask.isOff(n); }
780 bool isValueMaskOff() const { return mValueMask.isOff(); }
781 bool isChildMaskOn(Index n) const { return mChildMask.isOn(n); }
782 bool isChildMaskOff(Index n) const { return mChildMask.isOff(n); }
783 bool isChildMaskOff() const { return mChildMask.isOff(); }
784 const NodeMaskType& getValueMask() const { return mValueMask; }
785 const NodeMaskType& getChildMask() const { return mChildMask; }
786 NodeMaskType getValueOffMask() const
787 {
788 NodeMaskType mask = mValueMask;
789 mask |= mChildMask;
790 mask.toggle();
791 return mask;
792 }
793 const UnionType* getTable() const { return mNodes; }
794 protected:
796 void setValueMask(Index n, bool on) { mValueMask.set(n, mChildMask.isOn(n) ? false : on); }
800
801 void makeChildNodeEmpty(Index n, const ValueType& value);
802 void setChildNode( Index i, ChildNodeType* child);//assumes a tile
803 void resetChildNode(Index i, ChildNodeType* child);//checks for an existing child
804 ChildNodeType* unsetChildNode(Index i, const ValueType& value);
805
806 template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
807 static inline void doVisit(NodeT&, VisitorOp&);
808
809 template<typename NodeT, typename OtherNodeT, typename VisitorOp,
810 typename ChildAllIterT, typename OtherChildAllIterT>
811 static inline void doVisit2Node(NodeT&, OtherNodeT&, VisitorOp&);
812
813 template<typename NodeT, typename VisitorOp,
814 typename ChildAllIterT, typename OtherChildAllIterT>
815 static inline void doVisit2(NodeT&, OtherChildAllIterT&, VisitorOp&, bool otherIsLHS);
816
821 ChildNodeType* getChildNode(Index n);
822 const ChildNodeType* getChildNode(Index n) const;
824
827 struct VoxelizeActiveTiles;
828 template<typename OtherInternalNode> struct DeepCopy;
829 template<typename OtherInternalNode> struct TopologyCopy1;
830 template<typename OtherInternalNode> struct TopologyCopy2;
831 template<typename OtherInternalNode> struct TopologyUnion;
832 template<typename OtherInternalNode> struct TopologyDifference;
833 template<typename OtherInternalNode> struct TopologyIntersection;
835
836 UnionType mNodes[NUM_VALUES];
837 NodeMaskType mChildMask, mValueMask;
839 Coord mOrigin;
840 }; // class InternalNode
841
842
844
845
847 template<typename ChildT1, Index Dim1, typename NodeT2>
850 struct SameInternalConfig {
851 static const bool value = false;
852 };
853
854 template<typename ChildT1, Index Dim1, typename ChildT2>
855 struct SameInternalConfig<ChildT1, Dim1, InternalNode<ChildT2, Dim1> > {
856 static const bool value = ChildT1::template SameConfiguration<ChildT2>::value;
857 };
859
860
862
863
864 template<typename ChildT, Index Log2Dim>
865 inline
866 InternalNode<ChildT, Log2Dim>::InternalNode(const ValueType& background)
867 {
868 for (Index i = 0; i < NUM_VALUES; ++i) mNodes[i].setValue(background);
869 }
870
871
872 template<typename ChildT, Index Log2Dim>
873 inline
874 InternalNode<ChildT, Log2Dim>::InternalNode(const Coord& origin, const ValueType& val, bool active):
875 mOrigin(origin[0] & ~(DIM - 1), // zero out the low-order bits
876 origin[1] & ~(DIM - 1),
877 origin[2] & ~(DIM - 1))
878 {
879 if (active) mValueMask.setOn();
880 for (Index i = 0; i < NUM_VALUES; ++i) mNodes[i].setValue(val);
881 }
882
883
884 #ifndef OPENVDB_2_ABI_COMPATIBLE
885 // For InternalNodes, the PartialCreate constructor is identical to its
886 // non-PartialCreate counterpart.
887 template<typename ChildT, Index Log2Dim>
888 inline
889 InternalNode<ChildT, Log2Dim>::InternalNode(PartialCreate,
890 const Coord& origin, const ValueType& val, bool active)
891 : mOrigin(origin[0] & ~(DIM-1), origin[1] & ~(DIM-1), origin[2] & ~(DIM-1))
892 {
893 if (active) mValueMask.setOn();
894 for (Index i = 0; i < NUM_VALUES; ++i) mNodes[i].setValue(val);
895 }
896 #endif
897
898 template<typename ChildT, Index Log2Dim>
899 template<typename OtherInternalNode>
900 struct InternalNode<ChildT, Log2Dim>::DeepCopy
901 {
902 DeepCopy(const OtherInternalNode* source, InternalNode* target) : s(source), t(target) {
903 tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
904 //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//serial
905 }
906 void operator()(const tbb::blocked_range<Index> &r) const {
907 for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
908 if (s->mChildMask.isOff(i)) {
909 t->mNodes[i].setValue(ValueType(s->mNodes[i].getValue()));
910 } else {
911 t->mNodes[i].setChild(new ChildNodeType(*(s->mNodes[i].getChild())));
912 }
913 }
914 }
915 const OtherInternalNode* s;
916 InternalNode* t;
917 };// DeepCopy
918
919 template<typename ChildT, Index Log2Dim>
920 inline
921 InternalNode<ChildT, Log2Dim>::InternalNode(const InternalNode& other):
922 mChildMask(other.mChildMask),
923 mValueMask(other.mValueMask),
924 mOrigin(other.mOrigin)
925 {
926 DeepCopy<InternalNode<ChildT, Log2Dim> > tmp(&other, this);
927 }
928
929
930 // Copy-construct from a node with the same configuration but a different ValueType.
931 template<typename ChildT, Index Log2Dim>
932 template<typename OtherChildNodeType>
933 inline
934 InternalNode<ChildT, Log2Dim>::InternalNode(const InternalNode<OtherChildNodeType, Log2Dim>& other)
935 : mChildMask(other.mChildMask)
936 , mValueMask(other.mValueMask)
937 , mOrigin(other.mOrigin)
938 {
939 DeepCopy<InternalNode<OtherChildNodeType, Log2Dim> > tmp(&other, this);
940 }
941
942 template<typename ChildT, Index Log2Dim>
943 template<typename OtherInternalNode>
944 struct InternalNode<ChildT, Log2Dim>::TopologyCopy1
945 {
946 TopologyCopy1(const OtherInternalNode* source, InternalNode* target,
947 const ValueType& background) : s(source), t(target), b(background) {
948 tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
949 //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//serial
950 }
951 void operator()(const tbb::blocked_range<Index> &r) const {
952 for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
953 if (s->isChildMaskOn(i)) {
954 t->mNodes[i].setChild(new ChildNodeType(*(s->mNodes[i].getChild()),
955 b, TopologyCopy()));
956 } else {
957 t->mNodes[i].setValue(b);
958 }
959 }
960 }
961 const OtherInternalNode* s;
962 InternalNode* t;
963 const ValueType &b;
964 };// TopologyCopy1
965
966 template<typename ChildT, Index Log2Dim>
967 template<typename OtherChildNodeType>
968 inline
969 InternalNode<ChildT, Log2Dim>::InternalNode(const InternalNode<OtherChildNodeType, Log2Dim>& other,
970 const ValueType& background, TopologyCopy):
971 mChildMask(other.mChildMask),
972 mValueMask(other.mValueMask),
973 mOrigin(other.mOrigin)
974 {
975 TopologyCopy1<InternalNode<OtherChildNodeType, Log2Dim> > tmp(&other, this, background);
976 }
977
978 template<typename ChildT, Index Log2Dim>
979 template<typename OtherInternalNode>
980 struct InternalNode<ChildT, Log2Dim>::TopologyCopy2
981 {
982 TopologyCopy2(const OtherInternalNode* source, InternalNode* target,
983 const ValueType& offValue, const ValueType& onValue)
984 : s(source), t(target), offV(offValue), onV(onValue) {
985 tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
986 }
987 void operator()(const tbb::blocked_range<Index> &r) const {
988 for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
989 if (s->isChildMaskOn(i)) {
990 t->mNodes[i].setChild(new ChildNodeType(*(s->mNodes[i].getChild()),
991 offV, onV, TopologyCopy()));
992 } else {
993 t->mNodes[i].setValue(s->isValueMaskOn(i) ? onV : offV);
994 }
995 }
996 }
997 const OtherInternalNode* s;
998 InternalNode* t;
999 const ValueType &offV, &onV;
1000 };// TopologyCopy2
1001
1002 template<typename ChildT, Index Log2Dim>
1003 template<typename OtherChildNodeType>
1004 inline
1005 InternalNode<ChildT, Log2Dim>::InternalNode(const InternalNode<OtherChildNodeType, Log2Dim>& other,
1006 const ValueType& offValue,
1007 const ValueType& onValue, TopologyCopy):
1008 mChildMask(other.mChildMask),
1009 mValueMask(other.mValueMask),
1010 mOrigin(other.mOrigin)
1011 {
1012 TopologyCopy2<InternalNode<OtherChildNodeType, Log2Dim> > tmp(&other, this, offValue, onValue);
1013 }
1014
1015
1016 template<typename ChildT, Index Log2Dim>
1017 inline
1018 InternalNode<ChildT, Log2Dim>::~InternalNode()
1019 {
1020 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
1021 delete mNodes[iter.pos()].getChild();
1022 }
1023 }
1024
1025
1027
1028
1029 template<typename ChildT, Index Log2Dim>
1030 inline Index32
1031 InternalNode<ChildT, Log2Dim>::leafCount() const
1032 {
1033 if (ChildNodeType::getLevel() == 0) return mChildMask.countOn();
1034 Index32 sum = 0;
1035 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1036 sum += iter->leafCount();
1037 }
1038 return sum;
1039 }
1040
1041
1042 template<typename ChildT, Index Log2Dim>
1043 inline Index32
1044 InternalNode<ChildT, Log2Dim>::nonLeafCount() const
1045 {
1046 Index32 sum = 1;
1047 if (ChildNodeType::getLevel() == 0) return sum;
1048 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1049 sum += iter->nonLeafCount();
1050 }
1051 return sum;
1052 }
1053
1054
1055 template<typename ChildT, Index Log2Dim>
1056 inline Index64
1057 InternalNode<ChildT, Log2Dim>::onVoxelCount() const
1058 {
1059 Index64 sum = ChildT::NUM_VOXELS * mValueMask.countOn();
1060 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1061 sum += iter->onVoxelCount();
1062 }
1063 return sum;
1064 }
1065
1066
1067 template<typename ChildT, Index Log2Dim>
1068 inline Index64
1069 InternalNode<ChildT, Log2Dim>::offVoxelCount() const
1070 {
1071 Index64 sum = ChildT::NUM_VOXELS * (NUM_VALUES-mValueMask.countOn()-mChildMask.countOn());
1072 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1073 sum += iter->offVoxelCount();
1074 }
1075 return sum;
1076 }
1077
1078
1079 template<typename ChildT, Index Log2Dim>
1080 inline Index64
1081 InternalNode<ChildT, Log2Dim>::onLeafVoxelCount() const
1082 {
1083 Index64 sum = 0;
1084 for (ChildOnCIter iter = this->beginChildOn(); iter; ++iter) {
1085 sum += mNodes[iter.pos()].getChild()->onLeafVoxelCount();
1086 }
1087 return sum;
1088 }
1089
1090
1091 template<typename ChildT, Index Log2Dim>
1092 inline Index64
1093 InternalNode<ChildT, Log2Dim>::offLeafVoxelCount() const
1094 {
1095 Index64 sum = 0;
1096 for (ChildOnCIter iter = this->beginChildOn(); iter; ++iter) {
1097 sum += mNodes[iter.pos()].getChild()->offLeafVoxelCount();
1098 }
1099 return sum;
1100 }
1101
1102 template<typename ChildT, Index Log2Dim>
1103 inline Index64
1104 InternalNode<ChildT, Log2Dim>::onTileCount() const
1105 {
1106 Index64 sum = mValueMask.countOn();
1107 for (ChildOnCIter iter = this->cbeginChildOn(); LEVEL>1 && iter; ++iter) {
1108 sum += iter->onTileCount();
1109 }
1110 return sum;
1111 }
1112
1113 template<typename ChildT, Index Log2Dim>
1114 inline Index64
1115 InternalNode<ChildT, Log2Dim>::memUsage() const
1116 {
1117 Index64 sum = NUM_VALUES * sizeof(UnionType) + mChildMask.memUsage()
1118 + mValueMask.memUsage() + sizeof(mOrigin);
1119 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1120 sum += iter->memUsage();
1121 }
1122 return sum;
1123 }
1124
1125
1126 template<typename ChildT, Index Log2Dim>
1127 inline void
1128 InternalNode<ChildT, Log2Dim>::evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels) const
1129 {
1130 if (bbox.isInside(this->getNodeBoundingBox())) return;
1131
1132 for (ValueOnCIter i = this->cbeginValueOn(); i; ++i) {
1133 bbox.expand(i.getCoord(), ChildT::DIM);
1134 }
1135 for (ChildOnCIter i = this->cbeginChildOn(); i; ++i) {
1136 i->evalActiveBoundingBox(bbox, visitVoxels);
1137 }
1138 }
1139
1140
1142
1143
1144 template<typename ChildT, Index Log2Dim>
1145 inline void
1146 InternalNode<ChildT, Log2Dim>::prune(const ValueType& tolerance)
1147 {
1148 bool state = false;
1149 ValueType value = zeroVal<ValueType>();
1150 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
1151 const Index i = iter.pos();
1152 ChildT* child = mNodes[i].getChild();
1153 child->prune(tolerance);
1154 if (child->isConstant(value, state, tolerance)) {
1155 delete child;
1156 mChildMask.setOff(i);
1157 mValueMask.set(i, state);
1158 mNodes[i].setValue(value);
1159 }
1160 }
1161 }
1162
1163
1165
1166
1167 template<typename ChildT, Index Log2Dim>
1168 template<typename NodeT>
1169 inline NodeT*
1170 InternalNode<ChildT, Log2Dim>::stealNode(const Coord& xyz, const ValueType& value, bool state)
1171 {
1172 if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
1173 NodeT::LEVEL > ChildT::LEVEL) return nullptr;
1174 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
1175 const Index n = this->coordToOffset(xyz);
1176 if (mChildMask.isOff(n)) return nullptr;
1177 ChildT* child = mNodes[n].getChild();
1178 if (std::is_same<NodeT, ChildT>::value) {
1179 mChildMask.setOff(n);
1180 mValueMask.set(n, state);
1181 mNodes[n].setValue(value);
1182 }
1183 return (std::is_same<NodeT, ChildT>::value)
1184 ? reinterpret_cast<NodeT*>(child)
1185 : child->template stealNode<NodeT>(xyz, value, state);
1186 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
1187 }
1188
1189
1191
1192
1193 template<typename ChildT, Index Log2Dim>
1194 template<typename NodeT>
1195 inline NodeT*
1196 InternalNode<ChildT, Log2Dim>::probeNode(const Coord& xyz)
1197 {
1198 if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
1199 NodeT::LEVEL > ChildT::LEVEL) return nullptr;
1200 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
1201 const Index n = this->coordToOffset(xyz);
1202 if (mChildMask.isOff(n)) return nullptr;
1203 ChildT* child = mNodes[n].getChild();
1204 return (std::is_same<NodeT, ChildT>::value)
1205 ? reinterpret_cast<NodeT*>(child)
1206 : child->template probeNode<NodeT>(xyz);
1207 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
1208 }
1209
1210
1211 template<typename ChildT, Index Log2Dim>
1212 template<typename NodeT, typename AccessorT>
1213 inline NodeT*
1214 InternalNode<ChildT, Log2Dim>::probeNodeAndCache(const Coord& xyz, AccessorT& acc)
1215 {
1216 if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
1217 NodeT::LEVEL > ChildT::LEVEL) return nullptr;
1218 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
1219 const Index n = this->coordToOffset(xyz);
1220 if (mChildMask.isOff(n)) return nullptr;
1221 ChildT* child = mNodes[n].getChild();
1222 acc.insert(xyz, child);
1223 return (std::is_same<NodeT, ChildT>::value)
1224 ? reinterpret_cast<NodeT*>(child)
1225 : child->template probeNodeAndCache<NodeT>(xyz, acc);
1226 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
1227 }
1228
1229
1230 template<typename ChildT, Index Log2Dim>
1231 template<typename NodeT>
1232 inline const NodeT*
1233 InternalNode<ChildT, Log2Dim>::probeConstNode(const Coord& xyz) const
1234 {
1235 if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
1236 NodeT::LEVEL > ChildT::LEVEL) return nullptr;
1237 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
1238 const Index n = this->coordToOffset(xyz);
1239 if (mChildMask.isOff(n)) return nullptr;
1240 const ChildT* child = mNodes[n].getChild();
1241 return (std::is_same<NodeT, ChildT>::value)
1242 ? reinterpret_cast<const NodeT*>(child)
1243 : child->template probeConstNode<NodeT>(xyz);
1244 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
1245 }
1246
1247
1248 template<typename ChildT, Index Log2Dim>
1249 template<typename NodeT, typename AccessorT>
1250 inline const NodeT*
1251 InternalNode<ChildT, Log2Dim>::probeConstNodeAndCache(const Coord& xyz, AccessorT& acc) const
1252 {
1253 if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
1254 NodeT::LEVEL > ChildT::LEVEL) return nullptr;
1255 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
1256 const Index n = this->coordToOffset(xyz);
1257 if (mChildMask.isOff(n)) return nullptr;
1258 const ChildT* child = mNodes[n].getChild();
1259 acc.insert(xyz, child);
1260 return (std::is_same<NodeT, ChildT>::value)
1261 ? reinterpret_cast<const NodeT*>(child)
1262 : child->template probeConstNodeAndCache<NodeT>(xyz, acc);
1263 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
1264 }
1265
1266
1268
1269
1270 template<typename ChildT, Index Log2Dim>
1271 inline typename ChildT::LeafNodeType*
1272 InternalNode<ChildT, Log2Dim>::probeLeaf(const Coord& xyz)
1273 {
1274 return this->template probeNode<LeafNodeType>(xyz);
1275 }
1276
1277
1278 template<typename ChildT, Index Log2Dim>
1279 template<typename AccessorT>
1280 inline typename ChildT::LeafNodeType*
1281 InternalNode<ChildT, Log2Dim>::probeLeafAndCache(const Coord& xyz, AccessorT& acc)
1282 {
1283 return this->template probeNodeAndCache<LeafNodeType>(xyz, acc);
1284 }
1285
1286
1287 template<typename ChildT, Index Log2Dim>
1288 template<typename AccessorT>
1289 inline const typename ChildT::LeafNodeType*
1290 InternalNode<ChildT, Log2Dim>::probeLeafAndCache(const Coord& xyz, AccessorT& acc) const
1291 {
1292 return this->probeConstLeafAndCache(xyz, acc);
1293 }
1294
1295
1296 template<typename ChildT, Index Log2Dim>
1297 inline const typename ChildT::LeafNodeType*
1298 InternalNode<ChildT, Log2Dim>::probeConstLeaf(const Coord& xyz) const
1299 {
1300 return this->template probeConstNode<LeafNodeType>(xyz);
1301 }
1302
1303
1304 template<typename ChildT, Index Log2Dim>
1305 template<typename AccessorT>
1306 inline const typename ChildT::LeafNodeType*
1307 InternalNode<ChildT, Log2Dim>::probeConstLeafAndCache(const Coord& xyz, AccessorT& acc) const
1308 {
1309 return this->template probeConstNodeAndCache<LeafNodeType>(xyz, acc);
1310 }
1311
1312
1314
1315
1316 template<typename ChildT, Index Log2Dim>
1317 inline void
1318 InternalNode<ChildT, Log2Dim>::addLeaf(LeafNodeType* leaf)
1319 {
1320 assert(leaf != nullptr);
1321 const Coord& xyz = leaf->origin();
1322 const Index n = this->coordToOffset(xyz);
1323 ChildT* child = nullptr;
1324 if (mChildMask.isOff(n)) {
1325 if (ChildT::LEVEL>0) {
1326 child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n));
1327 } else {
1328 child = reinterpret_cast<ChildT*>(leaf);
1329 }
1330 this->setChildNode(n, child);
1331 } else {
1332 if (ChildT::LEVEL>0) {
1333 child = mNodes[n].getChild();
1334 } else {
1335 delete mNodes[n].getChild();
1336 child = reinterpret_cast<ChildT*>(leaf);
1337 mNodes[n].setChild(child);
1338 }
1339 }
1340 child->addLeaf(leaf);
1341 }
1342
1343
1344 template<typename ChildT, Index Log2Dim>
1345 template<typename AccessorT>
1346 inline void
1347 InternalNode<ChildT, Log2Dim>::addLeafAndCache(LeafNodeType* leaf, AccessorT& acc)
1348 {
1349 assert(leaf != nullptr);
1350 const Coord& xyz = leaf->origin();
1351 const Index n = this->coordToOffset(xyz);
1352 ChildT* child = nullptr;
1353 if (mChildMask.isOff(n)) {
1354 if (ChildT::LEVEL>0) {
1355 child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n));
1356 acc.insert(xyz, child);//we only cache internal nodes
1357 } else {
1358 child = reinterpret_cast<ChildT*>(leaf);
1359 }
1360 this->setChildNode(n, child);
1361 } else {
1362 if (ChildT::LEVEL>0) {
1363 child = mNodes[n].getChild();
1364 acc.insert(xyz, child);//we only cache internal nodes
1365 } else {
1366 delete mNodes[n].getChild();
1367 child = reinterpret_cast<ChildT*>(leaf);
1368 mNodes[n].setChild(child);
1369 }
1370 }
1371 child->addLeafAndCache(leaf, acc);
1372 }
1373
1374
1376
1377
1378 template<typename ChildT, Index Log2Dim>
1379 inline void
1380 InternalNode<ChildT, Log2Dim>::addTile(Index n, const ValueType& value, bool state)
1381 {
1382 assert(n < NUM_VALUES);
1383 this->makeChildNodeEmpty(n, value);
1384 mValueMask.set(n, state);
1385 }
1386
1387
1388 template<typename ChildT, Index Log2Dim>
1389 inline void
1390 InternalNode<ChildT, Log2Dim>::addTile(Index level, const Coord& xyz,
1391 const ValueType& value, bool state)
1392 {
1393 if (LEVEL >= level) {
1394 const Index n = this->coordToOffset(xyz);
1395 if (mChildMask.isOff(n)) {// tile case
1396 if (LEVEL > level) {
1397 ChildT* child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n));
1398 this->setChildNode(n, child);
1399 child->addTile(level, xyz, value, state);
1400 } else {
1401 mValueMask.set(n, state);
1402 mNodes[n].setValue(value);
1403 }
1404 } else {// child branch case
1405 ChildT* child = mNodes[n].getChild();
1406 if (LEVEL > level) {
1407 child->addTile(level, xyz, value, state);
1408 } else {
1409 delete child;
1410 mChildMask.setOff(n);
1411 mValueMask.set(n, state);
1412 mNodes[n].setValue(value);
1413 }
1414 }
1415 }
1416 }
1417
1418
1419 template<typename ChildT, Index Log2Dim>
1420 template<typename AccessorT>
1421 inline void
1422 InternalNode<ChildT, Log2Dim>::addTileAndCache(Index level, const Coord& xyz,
1423 const ValueType& value, bool state, AccessorT& acc)
1424 {
1425 if (LEVEL >= level) {
1426 const Index n = this->coordToOffset(xyz);
1427 if (mChildMask.isOff(n)) {// tile case
1428 if (LEVEL > level) {
1429 ChildT* child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n));
1430 this->setChildNode(n, child);
1431 acc.insert(xyz, child);
1432 child->addTileAndCache(level, xyz, value, state, acc);
1433 } else {
1434 mValueMask.set(n, state);
1435 mNodes[n].setValue(value);
1436 }
1437 } else {// child branch case
1438 ChildT* child = mNodes[n].getChild();
1439 if (LEVEL > level) {
1440 acc.insert(xyz, child);
1441 child->addTileAndCache(level, xyz, value, state, acc);
1442 } else {
1443 delete child;
1444 mChildMask.setOff(n);
1445 mValueMask.set(n, state);
1446 mNodes[n].setValue(value);
1447 }
1448 }
1449 }
1450 }
1451
1452
1454
1455
1456 template<typename ChildT, Index Log2Dim>
1457 inline typename ChildT::LeafNodeType*
1458 InternalNode<ChildT, Log2Dim>::touchLeaf(const Coord& xyz)
1459 {
1460 const Index n = this->coordToOffset(xyz);
1461 ChildT* child = nullptr;
1462 if (mChildMask.isOff(n)) {
1463 child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n));
1464 this->setChildNode(n, child);
1465 } else {
1466 child = mNodes[n].getChild();
1467 }
1468 return child->touchLeaf(xyz);
1469 }
1470
1471
1472 template<typename ChildT, Index Log2Dim>
1473 template<typename AccessorT>
1474 inline typename ChildT::LeafNodeType*
1475 InternalNode<ChildT, Log2Dim>::touchLeafAndCache(const Coord& xyz, AccessorT& acc)
1476 {
1477 const Index n = this->coordToOffset(xyz);
1478 if (mChildMask.isOff(n)) {
1479 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), mValueMask.isOn(n)));
1480 }
1481 acc.insert(xyz, mNodes[n].getChild());
1482 return mNodes[n].getChild()->touchLeafAndCache(xyz, acc);
1483 }
1484
1485
1487
1488
1489 template<typename ChildT, Index Log2Dim>
1490 inline bool
1491 InternalNode<ChildT, Log2Dim>::isConstant(ValueType& firstValue, bool& state,
1492 const ValueType& tolerance) const
1493 {
1494 if (!mChildMask.isOff() || !mValueMask.isConstant(state)) return false;// early termination
1495
1496 firstValue = mNodes[0].getValue();
1497 for (Index i = 1; i < NUM_VALUES; ++i) {
1498 if (!math::isApproxEqual(mNodes[i].getValue(), firstValue, tolerance)) {
1499 return false; // early termination
1500 }
1501 }
1502 return true;
1503 }
1504
1505
1507
1508
1509 template<typename ChildT, Index Log2Dim>
1510 inline bool
1511 InternalNode<ChildT, Log2Dim>::isConstant(ValueType& minValue,
1512 ValueType& maxValue,
1513 bool& state,
1514 const ValueType& tolerance) const
1515 {
1516
1517 if (!mChildMask.isOff() || !mValueMask.isConstant(state)) return false;// early termination
1518 minValue = maxValue = mNodes[0].getValue();
1519 for (Index i = 1; i < NUM_VALUES; ++i) {
1520 const ValueType& v = mNodes[i].getValue();
1521 if (v < minValue) {
1522 if ((maxValue - v) > tolerance) return false;// early termination
1523 minValue = v;
1524 } else if (v > maxValue) {
1525 if ((v - minValue) > tolerance) return false;// early termination
1526 maxValue = v;
1527 }
1528 }
1529 return true;
1530 }
1531
1532
1534
1535
1536 template<typename ChildT, Index Log2Dim>
1537 inline bool
1538 InternalNode<ChildT, Log2Dim>::hasActiveTiles() const
1539 {
1540 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
1541 const bool anyActiveTiles = !mValueMask.isOff();
1542 if (LEVEL==1 || anyActiveTiles) return anyActiveTiles;
1543 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1544 if (iter->hasActiveTiles()) return true;
1545 }
1546 return false;
1547 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
1548 }
1549
1550
1551 template<typename ChildT, Index Log2Dim>
1552 inline bool
1553 InternalNode<ChildT, Log2Dim>::isValueOn(const Coord& xyz) const
1554 {
1555 const Index n = this->coordToOffset(xyz);
1556 if (this->isChildMaskOff(n)) return this->isValueMaskOn(n);
1557 return mNodes[n].getChild()->isValueOn(xyz);
1558 }
1559
1560 template<typename ChildT, Index Log2Dim>
1561 template<typename AccessorT>
1562 inline bool
1563 InternalNode<ChildT, Log2Dim>::isValueOnAndCache(const Coord& xyz, AccessorT& acc) const
1564 {
1565 const Index n = this->coordToOffset(xyz);
1566 if (this->isChildMaskOff(n)) return this->isValueMaskOn(n);
1567 acc.insert(xyz, mNodes[n].getChild());
1568 return mNodes[n].getChild()->isValueOnAndCache(xyz, acc);
1569 }
1570
1571
1572 template<typename ChildT, Index Log2Dim>
1573 inline const typename ChildT::ValueType&
1574 InternalNode<ChildT, Log2Dim>::getValue(const Coord& xyz) const
1575 {
1576 const Index n = this->coordToOffset(xyz);
1577 return this->isChildMaskOff(n) ? mNodes[n].getValue()
1578 : mNodes[n].getChild()->getValue(xyz);
1579 }
1580
1581 template<typename ChildT, Index Log2Dim>
1582 template<typename AccessorT>
1583 inline const typename ChildT::ValueType&
1584 InternalNode<ChildT, Log2Dim>::getValueAndCache(const Coord& xyz, AccessorT& acc) const
1585 {
1586 const Index n = this->coordToOffset(xyz);
1587 if (this->isChildMaskOn(n)) {
1588 acc.insert(xyz, mNodes[n].getChild());
1589 return mNodes[n].getChild()->getValueAndCache(xyz, acc);
1590 }
1591 return mNodes[n].getValue();
1592 }
1593
1594
1595 template<typename ChildT, Index Log2Dim>
1596 inline Index
1597 InternalNode<ChildT, Log2Dim>::getValueLevel(const Coord& xyz) const
1598 {
1599 const Index n = this->coordToOffset(xyz);
1600 return this->isChildMaskOff(n) ? LEVEL : mNodes[n].getChild()->getValueLevel(xyz);
1601 }
1602
1603 template<typename ChildT, Index Log2Dim>
1604 template<typename AccessorT>
1605 inline Index
1606 InternalNode<ChildT, Log2Dim>::getValueLevelAndCache(const Coord& xyz, AccessorT& acc) const
1607 {
1608 const Index n = this->coordToOffset(xyz);
1609 if (this->isChildMaskOn(n)) {
1610 acc.insert(xyz, mNodes[n].getChild());
1611 return mNodes[n].getChild()->getValueLevelAndCache(xyz, acc);
1612 }
1613 return LEVEL;
1614 }
1615
1616
1617 template<typename ChildT, Index Log2Dim>
1618 inline bool
1619 InternalNode<ChildT, Log2Dim>::probeValue(const Coord& xyz, ValueType& value) const
1620 {
1621 const Index n = this->coordToOffset(xyz);
1622 if (this->isChildMaskOff(n)) {
1623 value = mNodes[n].getValue();
1624 return this->isValueMaskOn(n);
1625 }
1626 return mNodes[n].getChild()->probeValue(xyz, value);
1627 }
1628
1629 template<typename ChildT, Index Log2Dim>
1630 template<typename AccessorT>
1631 inline bool
1632 InternalNode<ChildT, Log2Dim>::probeValueAndCache(const Coord& xyz,
1633 ValueType& value, AccessorT& acc) const
1634 {
1635 const Index n = this->coordToOffset(xyz);
1636 if (this->isChildMaskOn(n)) {
1637 acc.insert(xyz, mNodes[n].getChild());
1638 return mNodes[n].getChild()->probeValueAndCache(xyz, value, acc);
1639 }
1640 value = mNodes[n].getValue();
1641 return this->isValueMaskOn(n);
1642 }
1643
1644
1645 template<typename ChildT, Index Log2Dim>
1646 inline void
1647 InternalNode<ChildT, Log2Dim>::setValueOff(const Coord& xyz)
1648 {
1649 const Index n = this->coordToOffset(xyz);
1650 bool hasChild = this->isChildMaskOn(n);
1651 if (!hasChild && this->isValueMaskOn(n)) {
1652 // If the voxel belongs to a constant tile that is active,
1653 // a child subtree must be constructed.
1654 hasChild = true;
1655 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), /*active=*/true));
1656 }
1657 if (hasChild) mNodes[n].getChild()->setValueOff(xyz);
1658 }
1659
1660
1661 template<typename ChildT, Index Log2Dim>
1662 inline void
1663 InternalNode<ChildT, Log2Dim>::setValueOn(const Coord& xyz)
1664 {
1665 const Index n = this->coordToOffset(xyz);
1666 bool hasChild = this->isChildMaskOn(n);
1667 if (!hasChild && !this->isValueMaskOn(n)) {
1668 // If the voxel belongs to a constant tile that is inactive,
1669 // a child subtree must be constructed.
1670 hasChild = true;
1671 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), /*active=*/false));
1672 }
1673 if (hasChild) mNodes[n].getChild()->setValueOn(xyz);
1674 }
1675
1676
1677 template<typename ChildT, Index Log2Dim>
1678 inline void
1679 InternalNode<ChildT, Log2Dim>::setValueOff(const Coord& xyz, const ValueType& value)
1680 {
1681 const Index n = InternalNode::coordToOffset(xyz);
1682 bool hasChild = this->isChildMaskOn(n);
1683 if (!hasChild) {
1684 const bool active = this->isValueMaskOn(n);
1685 if (active || !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1686 // If the voxel belongs to a tile that is either active or that
1687 // has a constant value that is different from the one provided,
1688 // a child subtree must be constructed.
1689 hasChild = true;
1690 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1691 }
1692 }
1693 if (hasChild) mNodes[n].getChild()->setValueOff(xyz, value);
1694 }
1695
1696 template<typename ChildT, Index Log2Dim>
1697 template<typename AccessorT>
1698 inline void
1699 InternalNode<ChildT, Log2Dim>::setValueOffAndCache(const Coord& xyz,
1700 const ValueType& value, AccessorT& acc)
1701 {
1702 const Index n = InternalNode::coordToOffset(xyz);
1703 bool hasChild = this->isChildMaskOn(n);
1704 if (!hasChild) {
1705 const bool active = this->isValueMaskOn(n);
1706 if (active || !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1707 // If the voxel belongs to a tile that is either active or that
1708 // has a constant value that is different from the one provided,
1709 // a child subtree must be constructed.
1710 hasChild = true;
1711 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1712 }
1713 }
1714 if (hasChild) {
1715 ChildT* child = mNodes[n].getChild();
1716 acc.insert(xyz, child);
1717 child->setValueOffAndCache(xyz, value, acc);
1718 }
1719 }
1720
1721
1722 template<typename ChildT, Index Log2Dim>
1723 inline void
1724 InternalNode<ChildT, Log2Dim>::setValueOn(const Coord& xyz, const ValueType& value)
1725 {
1726 const Index n = this->coordToOffset(xyz);
1727 bool hasChild = this->isChildMaskOn(n);
1728 if (!hasChild) {
1729 const bool active = this->isValueMaskOn(n); // tile's active state
1730 if (!active || !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1731 // If the voxel belongs to a tile that is either inactive or that
1732 // has a constant value that is different from the one provided,
1733 // a child subtree must be constructed.
1734 hasChild = true;
1735 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1736 }
1737 }
1738 if (hasChild) mNodes[n].getChild()->setValueOn(xyz, value);
1739 }
1740
1741 template<typename ChildT, Index Log2Dim>
1742 template<typename AccessorT>
1743 inline void
1744 InternalNode<ChildT, Log2Dim>::setValueAndCache(const Coord& xyz,
1745 const ValueType& value, AccessorT& acc)
1746 {
1747 const Index n = this->coordToOffset(xyz);
1748 bool hasChild = this->isChildMaskOn(n);
1749 if (!hasChild) {
1750 const bool active = this->isValueMaskOn(n);
1751 if (!active || !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1752 // If the voxel belongs to a tile that is either inactive or that
1753 // has a constant value that is different from the one provided,
1754 // a child subtree must be constructed.
1755 hasChild = true;
1756 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1757 }
1758 }
1759 if (hasChild) {
1760 acc.insert(xyz, mNodes[n].getChild());
1761 mNodes[n].getChild()->setValueAndCache(xyz, value, acc);
1762 }
1763 }
1764
1765
1766 template<typename ChildT, Index Log2Dim>
1767 inline void
1768 InternalNode<ChildT, Log2Dim>::setValueOnly(const Coord& xyz, const ValueType& value)
1769 {
1770 const Index n = this->coordToOffset(xyz);
1771 bool hasChild = this->isChildMaskOn(n);
1772 if (!hasChild && !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1773 // If the voxel has a tile value that is different from the one provided,
1774 // a child subtree must be constructed.
1775 const bool active = this->isValueMaskOn(n);
1776 hasChild = true;
1777 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1778 }
1779 if (hasChild) mNodes[n].getChild()->setValueOnly(xyz, value);
1780 }
1781
1782 template<typename ChildT, Index Log2Dim>
1783 template<typename AccessorT>
1784 inline void
1785 InternalNode<ChildT, Log2Dim>::setValueOnlyAndCache(const Coord& xyz,
1786 const ValueType& value, AccessorT& acc)
1787 {
1788 const Index n = this->coordToOffset(xyz);
1789 bool hasChild = this->isChildMaskOn(n);
1790 if (!hasChild && !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1791 // If the voxel has a tile value that is different from the one provided,
1792 // a child subtree must be constructed.
1793 const bool active = this->isValueMaskOn(n);
1794 hasChild = true;
1795 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1796 }
1797 if (hasChild) {
1798 acc.insert(xyz, mNodes[n].getChild());
1799 mNodes[n].getChild()->setValueOnlyAndCache(xyz, value, acc);
1800 }
1801 }
1802
1803
1804 template<typename ChildT, Index Log2Dim>
1805 inline void
1806 InternalNode<ChildT, Log2Dim>::setActiveState(const Coord& xyz, bool on)
1807 {
1808 const Index n = this->coordToOffset(xyz);
1809 bool hasChild = this->isChildMaskOn(n);
1810 if (!hasChild) {
1811 if (on != this->isValueMaskOn(n)) {
1812 // If the voxel belongs to a tile with the wrong active state,
1813 // then a child subtree must be constructed.
1814 // 'on' is the voxel's new state, therefore '!on' is the tile's current state
1815 hasChild = true;
1816 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), !on));
1817 }
1818 }
1819 if (hasChild) mNodes[n].getChild()->setActiveState(xyz, on);
1820 }
1821
1822 template<typename ChildT, Index Log2Dim>
1823 template<typename AccessorT>
1824 inline void
1825 InternalNode<ChildT, Log2Dim>::setActiveStateAndCache(const Coord& xyz, bool on, AccessorT& acc)
1826 {
1827 const Index n = this->coordToOffset(xyz);
1828 bool hasChild = this->isChildMaskOn(n);
1829 if (!hasChild) {
1830 if (on != this->isValueMaskOn(n)) {
1831 // If the voxel belongs to a tile with the wrong active state,
1832 // then a child subtree must be constructed.
1833 // 'on' is the voxel's new state, therefore '!on' is the tile's current state
1834 hasChild = true;
1835 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), !on));
1836 }
1837 }
1838 if (hasChild) {
1839 ChildT* child = mNodes[n].getChild();
1840 acc.insert(xyz, child);
1841 child->setActiveStateAndCache(xyz, on, acc);
1842 }
1843 }
1844
1845
1846 template<typename ChildT, Index Log2Dim>
1847 inline void
1848 InternalNode<ChildT, Log2Dim>::setValuesOn()
1849 {
1850 mValueMask = !mChildMask;
1851 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
1852 mNodes[iter.pos()].getChild()->setValuesOn();
1853 }
1854 }
1855
1856
1857 template<typename ChildT, Index Log2Dim>
1858 template<typename ModifyOp>
1859 inline void
1860 InternalNode<ChildT, Log2Dim>::modifyValue(const Coord& xyz, const ModifyOp& op)
1861 {
1862 const Index n = InternalNode::coordToOffset(xyz);
1863 bool hasChild = this->isChildMaskOn(n);
1864 if (!hasChild) {
1865 // Need to create a child if the tile is inactive,
1866 // in order to activate voxel (x, y, z).
1867 const bool active = this->isValueMaskOn(n);
1868 bool createChild = !active;
1869 if (!createChild) {
1870 // Need to create a child if applying the functor
1871 // to the tile value produces a different value.
1872 const ValueType& tileVal = mNodes[n].getValue();
1873 ValueType modifiedVal = tileVal;
1874 op(modifiedVal);
1875 createChild = !math::isExactlyEqual(tileVal, modifiedVal);
1876 }
1877 if (createChild) {
1878 hasChild = true;
1879 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1880 }
1881 }
1882 if (hasChild) mNodes[n].getChild()->modifyValue(xyz, op);
1883 }
1884
1885 template<typename ChildT, Index Log2Dim>
1886 template<typename ModifyOp, typename AccessorT>
1887 inline void
1888 InternalNode<ChildT, Log2Dim>::modifyValueAndCache(const Coord& xyz, const ModifyOp& op,
1889 AccessorT& acc)
1890 {
1891 const Index n = InternalNode::coordToOffset(xyz);
1892 bool hasChild = this->isChildMaskOn(n);
1893 if (!hasChild) {
1894 // Need to create a child if the tile is inactive,
1895 // in order to activate voxel (x, y, z).
1896 const bool active = this->isValueMaskOn(n);
1897 bool createChild = !active;
1898 if (!createChild) {
1899 // Need to create a child if applying the functor
1900 // to the tile value produces a different value.
1901 const ValueType& tileVal = mNodes[n].getValue();
1902 ValueType modifiedVal = tileVal;
1903 op(modifiedVal);
1904 createChild = !math::isExactlyEqual(tileVal, modifiedVal);
1905 }
1906 if (createChild) {
1907 hasChild = true;
1908 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1909 }
1910 }
1911 if (hasChild) {
1912 ChildNodeType* child = mNodes[n].getChild();
1913 acc.insert(xyz, child);
1914 child->modifyValueAndCache(xyz, op, acc);
1915 }
1916 }
1917
1918
1919 template<typename ChildT, Index Log2Dim>
1920 template<typename ModifyOp>
1921 inline void
1922 InternalNode<ChildT, Log2Dim>::modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
1923 {
1924 const Index n = InternalNode::coordToOffset(xyz);
1925 bool hasChild = this->isChildMaskOn(n);
1926 if (!hasChild) {
1927 const bool tileState = this->isValueMaskOn(n);
1928 const ValueType& tileVal = mNodes[n].getValue();
1929 bool modifiedState = !tileState;
1930 ValueType modifiedVal = tileVal;
1931 op(modifiedVal, modifiedState);
1932 // Need to create a child if applying the functor to the tile
1933 // produces a different value or active state.
1934 if (modifiedState != tileState || !math::isExactlyEqual(modifiedVal, tileVal)) {
1935 hasChild = true;
1936 this->setChildNode(n, new ChildNodeType(xyz, tileVal, tileState));
1937 }
1938 }
1939 if (hasChild) mNodes[n].getChild()->modifyValueAndActiveState(xyz, op);
1940 }
1941
1942 template<typename ChildT, Index Log2Dim>
1943 template<typename ModifyOp, typename AccessorT>
1944 inline void
1945 InternalNode<ChildT, Log2Dim>::modifyValueAndActiveStateAndCache(
1946 const Coord& xyz, const ModifyOp& op, AccessorT& acc)
1947 {
1948 const Index n = InternalNode::coordToOffset(xyz);
1949 bool hasChild = this->isChildMaskOn(n);
1950 if (!hasChild) {
1951 const bool tileState = this->isValueMaskOn(n);
1952 const ValueType& tileVal = mNodes[n].getValue();
1953 bool modifiedState = !tileState;
1954 ValueType modifiedVal = tileVal;
1955 op(modifiedVal, modifiedState);
1956 // Need to create a child if applying the functor to the tile
1957 // produces a different value or active state.
1958 if (modifiedState != tileState || !math::isExactlyEqual(modifiedVal, tileVal)) {
1959 hasChild = true;
1960 this->setChildNode(n, new ChildNodeType(xyz, tileVal, tileState));
1961 }
1962 }
1963 if (hasChild) {
1964 ChildNodeType* child = mNodes[n].getChild();
1965 acc.insert(xyz, child);
1966 child->modifyValueAndActiveStateAndCache(xyz, op, acc);
1967 }
1968 }
1969
1970
1972
1973
1974 template<typename ChildT, Index Log2Dim>
1975 inline void
1976 InternalNode<ChildT, Log2Dim>::clip(const CoordBBox& clipBBox, const ValueType& background)
1977 {
1978 CoordBBox nodeBBox = this->getNodeBoundingBox();
1979 if (!clipBBox.hasOverlap(nodeBBox)) {
1980 // This node lies completely outside the clipping region. Fill it with background tiles.
1981 this->fill(nodeBBox, background, /*active=*/false);
1982 } else if (clipBBox.isInside(nodeBBox)) {
1983 // This node lies completely inside the clipping region. Leave it intact.
1984 return;
1985 }
1986
1987 // This node isn't completely contained inside the clipping region.
1988 // Clip tiles and children, and replace any that lie outside the region
1989 // with background tiles.
1990
1991 for (Index pos = 0; pos < NUM_VALUES; ++pos) {
1992 const Coord xyz = this->offsetToGlobalCoord(pos); // tile or child origin
1993 CoordBBox tileBBox(xyz, xyz.offsetBy(ChildT::DIM - 1)); // tile or child bounds
1994 if (!clipBBox.hasOverlap(tileBBox)) {
1995 // This table entry lies completely outside the clipping region.
1996 // Replace it with a background tile.
1997 this->makeChildNodeEmpty(pos, background);
1998 mValueMask.setOff(pos);
1999 } else if (!clipBBox.isInside(tileBBox)) {
2000 // This table entry does not lie completely inside the clipping region
2001 // and must be clipped.
2002 if (this->isChildMaskOn(pos)) {
2003 mNodes[pos].getChild()->clip(clipBBox, background);
2004 } else {
2005 // Replace this tile with a background tile, then fill the clip region
2006 // with the tile's original value. (This might create a child branch.)
2007 tileBBox.intersect(clipBBox);
2008 const ValueType val = mNodes[pos].getValue();
2009 const bool on = this->isValueMaskOn(pos);
2010 mNodes[pos].setValue(background);
2011 mValueMask.setOff(pos);
2012 this->fill(tileBBox, val, on);
2013 }
2014 } else {
2015 // This table entry lies completely inside the clipping region. Leave it intact.
2016 }
2017 }
2018 }
2019
2020
2022
2023
2024 template<typename ChildT, Index Log2Dim>
2025 inline void
2026 InternalNode<ChildT, Log2Dim>::fill(const CoordBBox& bbox, const ValueType& value, bool active)
2027 {
2028 auto clippedBBox = this->getNodeBoundingBox();
2029 clippedBBox.intersect(bbox);
2030 if (!clippedBBox) return;
2031
2032 // Iterate over the fill region in axis-aligned, tile-sized chunks.
2033 // (The first and last chunks along each axis might be smaller than a tile.)
2034 Coord xyz, tileMin, tileMax;
2035 for (int x = clippedBBox.min().x(); x <= clippedBBox.max().x(); x = tileMax.x() + 1) {
2036 xyz.setX(x);
2037 for (int y = clippedBBox.min().y(); y <= clippedBBox.max().y(); y = tileMax.y() + 1) {
2038 xyz.setY(y);
2039 for (int z = clippedBBox.min().z(); z <= clippedBBox.max().z(); z = tileMax.z() + 1) {
2040 xyz.setZ(z);
2041
2042 // Get the bounds of the tile that contains voxel (x, y, z).
2043 const Index n = this->coordToOffset(xyz);
2044 tileMin = this->offsetToGlobalCoord(n);
2045 tileMax = tileMin.offsetBy(ChildT::DIM - 1);
2046
2047 if (xyz != tileMin || Coord::lessThan(clippedBBox.max(), tileMax)) {
2048 // If the box defined by (xyz, clippedBBox.max()) doesn't completely enclose
2049 // the tile to which xyz belongs, create a child node (or retrieve
2050 // the existing one).
2051 ChildT* child = nullptr;
2052 if (this->isChildMaskOff(n)) {
2053 // Replace the tile with a newly-created child that is initialized
2054 // with the tile's value and active state.
2055 child = new ChildT{xyz, mNodes[n].getValue(), this->isValueMaskOn(n)};
2056 this->setChildNode(n, child);
2057 } else {
2058 child = mNodes[n].getChild();
2059 }
2060
2061 // Forward the fill request to the child.
2062 if (child) {
2063 const Coord tmp = Coord::minComponent(clippedBBox.max(), tileMax);
2064 child->fill(CoordBBox(xyz, tmp), value, active);
2065 }
2066
2067 } else {
2068 // If the box given by (xyz, clippedBBox.max()) completely encloses
2069 // the tile to which xyz belongs, create the tile (if it
2070 // doesn't already exist) and give it the fill value.
2071 this->makeChildNodeEmpty(n, value);
2072 mValueMask.set(n, active);
2073 }
2074 }
2075 }
2076 }
2077 }
2078
2079
2080 template<typename ChildT, Index Log2Dim>
2081 inline void
2082 InternalNode<ChildT, Log2Dim>::denseFill(const CoordBBox& bbox, const ValueType& value, bool active)
2083 {
2084 auto clippedBBox = this->getNodeBoundingBox();
2085 clippedBBox.intersect(bbox);
2086 if (!clippedBBox) return;
2087
2088 // Iterate over the fill region in axis-aligned, tile-sized chunks.
2089 // (The first and last chunks along each axis might be smaller than a tile.)
2090 Coord xyz, tileMin, tileMax;
2091 for (int x = clippedBBox.min().x(); x <= clippedBBox.max().x(); x = tileMax.x() + 1) {
2092 xyz.setX(x);
2093 for (int y = clippedBBox.min().y(); y <= clippedBBox.max().y(); y = tileMax.y() + 1) {
2094 xyz.setY(y);
2095 for (int z = clippedBBox.min().z(); z <= clippedBBox.max().z(); z = tileMax.z() + 1) {
2096 xyz.setZ(z);
2097
2098 // Get the table index of the tile that contains voxel (x, y, z).
2099 const auto n = this->coordToOffset(xyz);
2100
2101 // Retrieve the child node at index n, or replace the tile at index n with a child.
2102 ChildT* child = nullptr;
2103 if (this->isChildMaskOn(n)) {
2104 child = mNodes[n].getChild();
2105 } else {
2106 // Replace the tile with a newly-created child that is filled
2107 // with the tile's value and active state.
2108 child = new ChildT{xyz, mNodes[n].getValue(), this->isValueMaskOn(n)};
2109 this->setChildNode(n, child);
2110 }
2111
2112 // Get the bounds of the tile that contains voxel (x, y, z).
2113 tileMin = this->offsetToGlobalCoord(n);
2114 tileMax = tileMin.offsetBy(ChildT::DIM - 1);
2115
2116 // Forward the fill request to the child.
2117 child->denseFill(CoordBBox{xyz, clippedBBox.max()}, value, active);
2118 }
2119 }
2120 }
2121 }
2122
2123
2125
2126
2127 template<typename ChildT, Index Log2Dim>
2128 template<typename DenseT>
2129 inline void
2130 InternalNode<ChildT, Log2Dim>::copyToDense(const CoordBBox& bbox, DenseT& dense) const
2131 {
2132 using DenseValueType = typename DenseT::ValueType;
2133
2134 const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride();
2135 const Coord& min = dense.bbox().min();
2136 for (Coord xyz = bbox.min(), max; xyz[0] <= bbox.max()[0]; xyz[0] = max[0] + 1) {
2137 for (xyz[1] = bbox.min()[1]; xyz[1] <= bbox.max()[1]; xyz[1] = max[1] + 1) {
2138 for (xyz[2] = bbox.min()[2]; xyz[2] <= bbox.max()[2]; xyz[2] = max[2] + 1) {
2139 const Index n = this->coordToOffset(xyz);
2140 // Get max coordinates of the child node that contains voxel xyz.
2141 max = this->offsetToGlobalCoord(n).offsetBy(ChildT::DIM-1);
2142
2143 // Get the bbox of the interection of bbox and the child node
2144 CoordBBox sub(xyz, Coord::minComponent(bbox.max(), max));
2145
2146 if (this->isChildMaskOn(n)) {//is a child
2147 mNodes[n].getChild()->copyToDense(sub, dense);
2148 } else {//a tile value
2149 const ValueType value = mNodes[n].getValue();
2150 sub.translate(-min);
2151 DenseValueType* a0 = dense.data() + zStride*sub.min()[2];
2152 for (Int32 x=sub.min()[0], ex=sub.max()[0]+1; x<ex; ++x) {
2153 DenseValueType* a1 = a0 + x*xStride;
2154 for (Int32 y=sub.min()[1], ey=sub.max()[1]+1; y<ey; ++y) {
2155 DenseValueType* a2 = a1 + y*yStride;
2156 for (Int32 z = sub.min()[2], ez = sub.max()[2]+1;
2157 z < ez; ++z, a2 += zStride)
2158 {
2159 *a2 = DenseValueType(value);
2160 }
2161 }
2162 }
2163 }
2164 }
2165 }
2166 }
2167 }
2168
2169
2171
2172
2173 template<typename ChildT, Index Log2Dim>
2174 inline void
2175 InternalNode<ChildT, Log2Dim>::writeTopology(std::ostream& os, bool toHalf) const
2176 {
2177 mChildMask.save(os);
2178 mValueMask.save(os);
2179
2180 {
2181 // Copy all of this node's values into an array.
2182 std::unique_ptr<ValueType[]> valuePtr(new ValueType[NUM_VALUES]);
2183 ValueType* values = valuePtr.get();
2184 const ValueType zero = zeroVal<ValueType>();
2185 for (Index i = 0; i < NUM_VALUES; ++i) {
2186 values[i] = (mChildMask.isOff(i) ? mNodes[i].getValue() : zero);
2187 }
2188 // Compress (optionally) and write out the contents of the array.
2189 io::writeCompressedValues(os, values, NUM_VALUES, mValueMask, mChildMask, toHalf);
2190 }
2191 // Write out the child nodes in order.
2192 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
2193 iter->writeTopology(os, toHalf);
2194 }
2195 }
2196
2197
2198 template<typename ChildT, Index Log2Dim>
2199 inline void
2200 InternalNode<ChildT, Log2Dim>::readTopology(std::istream& is, bool fromHalf)
2201 {
2202 #ifndef OPENVDB_2_ABI_COMPATIBLE
2203 const ValueType background = (!io::getGridBackgroundValuePtr(is) ? zeroVal<ValueType>()
2204 : *static_cast<const ValueType*>(io::getGridBackgroundValuePtr(is)));
2205 #endif
2206
2207 mChildMask.load(is);
2208 mValueMask.load(is);
2209
2210 if (io::getFormatVersion(is) < OPENVDB_FILE_VERSION_INTERNALNODE_COMPRESSION) {
2211 for (Index i = 0; i < NUM_VALUES; ++i) {
2212 if (this->isChildMaskOn(i)) {
2213 ChildNodeType* child =
2214 #ifdef OPENVDB_2_ABI_COMPATIBLE
2215 new ChildNodeType(offsetToGlobalCoord(i), zeroVal<ValueType>());
2216 #else
2217 new ChildNodeType(PartialCreate(), offsetToGlobalCoord(i), background);
2218 #endif
2219 mNodes[i].setChild(child);
2220 child->readTopology(is);
2221 } else {
2222 ValueType value;
2223 is.read(reinterpret_cast<char*>(&value), sizeof(ValueType));
2224 mNodes[i].setValue(value);
2225 }
2226 }
2227 } else {
2228 const bool oldVersion =
2229 (io::getFormatVersion(is) < OPENVDB_FILE_VERSION_NODE_MASK_COMPRESSION);
2230 const Index numValues = (oldVersion ? mChildMask.countOff() : NUM_VALUES);
2231 {
2232 // Read in (and uncompress, if necessary) all of this node's values
2233 // into a contiguous array.
2234 std::unique_ptr<ValueType[]> valuePtr(new ValueType[numValues]);
2235 ValueType* values = valuePtr.get();
2236 io::readCompressedValues(is, values, numValues, mValueMask, fromHalf);
2237
2238 // Copy values from the array into this node's table.
2239 if (oldVersion) {
2240 Index n = 0;
2241 for (ValueAllIter iter = this->beginValueAll(); iter; ++iter) {
2242 mNodes[iter.pos()].setValue(values[n++]);
2243 }
2244 assert(n == numValues);
2245 } else {
2246 for (ValueAllIter iter = this->beginValueAll(); iter; ++iter) {
2247 mNodes[iter.pos()].setValue(values[iter.pos()]);
2248 }
2249 }
2250 }
2251 // Read in all child nodes and insert them into the table at their proper locations.
2252 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
2253 #ifdef OPENVDB_2_ABI_COMPATIBLE
2254 ChildNodeType* child = new ChildNodeType(iter.getCoord(), zeroVal<ValueType>());
2255 #else
2256 ChildNodeType* child = new ChildNodeType(PartialCreate(), iter.getCoord(), background);
2257 #endif
2258 mNodes[iter.pos()].setChild(child);
2259 child->readTopology(is, fromHalf);
2260 }
2261 }
2262 }
2263
2264
2266
2267
2268 template<typename ChildT, Index Log2Dim>
2269 inline const typename ChildT::ValueType&
2270 InternalNode<ChildT, Log2Dim>::getFirstValue() const
2271 {
2272 return (this->isChildMaskOn(0) ? mNodes[0].getChild()->getFirstValue() : mNodes[0].getValue());
2273 }
2274
2275
2276 template<typename ChildT, Index Log2Dim>
2277 inline const typename ChildT::ValueType&
2278 InternalNode<ChildT, Log2Dim>::getLastValue() const
2279 {
2280 const Index n = NUM_VALUES - 1;
2281 return (this->isChildMaskOn(n) ? mNodes[n].getChild()->getLastValue() : mNodes[n].getValue());
2282 }
2283
2284
2286
2287
2288 template<typename ChildT, Index Log2Dim>
2289 inline void
2290 InternalNode<ChildT, Log2Dim>::negate()
2291 {
2292 for (Index i = 0; i < NUM_VALUES; ++i) {
2293 if (this->isChildMaskOn(i)) {
2294 mNodes[i].getChild()->negate();
2295 } else {
2296 mNodes[i].setValue(math::negative(mNodes[i].getValue()));
2297 }
2298 }
2299
2300 }
2301
2302
2304
2305
2306 template<typename ChildT, Index Log2Dim>
2307 struct InternalNode<ChildT, Log2Dim>::VoxelizeActiveTiles
2308 {
2309 VoxelizeActiveTiles(InternalNode &node) : mNode(&node) {
2310 //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//single thread for debugging
2311 tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
2312
2313 node.mChildMask |= node.mValueMask;
2314 node.mValueMask.setOff();
2315 }
2316 void operator()(const tbb::blocked_range<Index> &r) const
2317 {
2318 for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
2319 if (mNode->mChildMask.isOn(i)) {// Loop over node's child nodes
2320 mNode->mNodes[i].getChild()->voxelizeActiveTiles(true);
2321 } else if (mNode->mValueMask.isOn(i)) {// Loop over node's active tiles
2322 const Coord &ijk = mNode->offsetToGlobalCoord(i);
2323 ChildNodeType *child = new ChildNodeType(ijk, mNode->mNodes[i].getValue(), true);
2324 child->voxelizeActiveTiles(true);
2325 mNode->mNodes[i].setChild(child);
2326 }
2327 }
2328 }
2329 InternalNode* mNode;
2330 };// VoxelizeActiveTiles
2331
2332 template<typename ChildT, Index Log2Dim>
2333 inline void
2334 InternalNode<ChildT, Log2Dim>::voxelizeActiveTiles(bool threaded)
2335 {
2336 if (threaded) {
2337 VoxelizeActiveTiles tmp(*this);
2338 } else {
2339 for (ValueOnIter iter = this->beginValueOn(); iter; ++iter) {
2340 this->setChildNode(iter.pos(),
2341 new ChildNodeType(iter.getCoord(), iter.getValue(), true));
2342 }
2343 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter)
2344 iter->voxelizeActiveTiles(false);
2345 }
2346 }
2347
2348
2350
2351
2352 template<typename ChildT, Index Log2Dim>
2353 template<MergePolicy Policy>
2354 inline void
2355 InternalNode<ChildT, Log2Dim>::merge(InternalNode& other,
2356 const ValueType& background, const ValueType& otherBackground)
2357 {
2358 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
2359
2360 switch (Policy) {
2361
2362 case MERGE_ACTIVE_STATES:
2363 default:
2364 {
2365 for (ChildOnIter iter = other.beginChildOn(); iter; ++iter) {
2366 const Index n = iter.pos();
2367 if (mChildMask.isOn(n)) {
2368 // Merge this node's child with the other node's child.
2369 mNodes[n].getChild()->template merge<MERGE_ACTIVE_STATES>(*iter,
2370 background, otherBackground);
2371 } else if (mValueMask.isOff(n)) {
2372 // Replace this node's inactive tile with the other node's child
2373 // and replace the other node's child with a tile of undefined value
2374 // (which is okay since the other tree is assumed to be cannibalized
2375 // in the process of merging).
2376 ChildNodeType* child = other.mNodes[n].getChild();
2377 other.mChildMask.setOff(n);
2378 child->resetBackground(otherBackground, background);
2379 this->setChildNode(n, child);
2380 }
2381 }
2382
2383 // Copy active tile values.
2384 for (ValueOnCIter iter = other.cbeginValueOn(); iter; ++iter) {
2385 const Index n = iter.pos();
2386 if (mValueMask.isOff(n)) {
2387 // Replace this node's child or inactive tile with the other node's active tile.
2388 this->makeChildNodeEmpty(n, iter.getValue());
2389 mValueMask.setOn(n);
2390 }
2391 }
2392 break;
2393 }
2394
2395 case MERGE_NODES:
2396 {
2397 for (ChildOnIter iter = other.beginChildOn(); iter; ++iter) {
2398 const Index n = iter.pos();
2399 if (mChildMask.isOn(n)) {
2400 // Merge this node's child with the other node's child.
2401 mNodes[n].getChild()->template merge<Policy>(*iter, background, otherBackground);
2402 } else {
2403 // Replace this node's tile (regardless of its active state) with
2404 // the other node's child and replace the other node's child with
2405 // a tile of undefined value (which is okay since the other tree
2406 // is assumed to be cannibalized in the process of merging).
2407 ChildNodeType* child = other.mNodes[n].getChild();
2408 other.mChildMask.setOff(n);
2409 child->resetBackground(otherBackground, background);
2410 this->setChildNode(n, child);
2411 }
2412 }
2413 break;
2414 }
2415
2416 case MERGE_ACTIVE_STATES_AND_NODES:
2417 {
2418 // Transfer children from the other tree to this tree.
2419 for (ChildOnIter iter = other.beginChildOn(); iter; ++iter) {
2420 const Index n = iter.pos();
2421 if (mChildMask.isOn(n)) {
2422 // Merge this node's child with the other node's child.
2423 mNodes[n].getChild()->template merge<Policy>(*iter, background, otherBackground);
2424 } else {
2425 // Replace this node's tile with the other node's child, leaving the other
2426 // node with an inactive tile of undefined value (which is okay since
2427 // the other tree is assumed to be cannibalized in the process of merging).
2428 ChildNodeType* child = other.mNodes[n].getChild();
2429 other.mChildMask.setOff(n);
2430 child->resetBackground(otherBackground, background);
2431 if (mValueMask.isOn(n)) {
2432 // Merge the child with this node's active tile.
2433 child->template merge<Policy>(mNodes[n].getValue(), /*on=*/true);
2434 mValueMask.setOff(n);
2435 }
2436 mChildMask.setOn(n);
2437 mNodes[n].setChild(child);
2438 }
2439 }
2440
2441 // Merge active tiles into this tree.
2442 for (ValueOnCIter iter = other.cbeginValueOn(); iter; ++iter) {
2443 const Index n = iter.pos();
2444 if (mChildMask.isOn(n)) {
2445 // Merge the other node's active tile into this node's child.
2446 mNodes[n].getChild()->template merge<Policy>(iter.getValue(), /*on=*/true);
2447 } else if (mValueMask.isOff(n)) {
2448 // Replace this node's inactive tile with the other node's active tile.
2449 mNodes[n].setValue(iter.getValue());
2450 mValueMask.setOn(n);
2451 }
2452 }
2453 break;
2454 }
2455
2456 }
2457 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
2458 }
2459
2460
2461 template<typename ChildT, Index Log2Dim>
2462 template<MergePolicy Policy>
2463 inline void
2464 InternalNode<ChildT, Log2Dim>::merge(const ValueType& tileValue, bool tileActive)
2465 {
2466 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
2467
2468 if (Policy != MERGE_ACTIVE_STATES_AND_NODES) return;
2469
2470 // For MERGE_ACTIVE_STATES_AND_NODES, inactive tiles in the other tree are ignored.
2471 if (!tileActive) return;
2472
2473 // Iterate over this node's children and inactive tiles.
2474 for (ValueOffIter iter = this->beginValueOff(); iter; ++iter) {
2475 const Index n = iter.pos();
2476 if (mChildMask.isOn(n)) {
2477 // Merge the other node's active tile into this node's child.
2478 mNodes[n].getChild()->template merge<Policy>(tileValue, /*on=*/true);
2479 } else {
2480 // Replace this node's inactive tile with the other node's active tile.
2481 iter.setValue(tileValue);
2482 mValueMask.setOn(n);
2483 }
2484 }
2485 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
2486 }
2487
2488
2490
2491
2492 template<typename ChildT, Index Log2Dim>
2493 template<typename OtherInternalNode>
2494 struct InternalNode<ChildT, Log2Dim>::TopologyUnion
2495 {
2496 using W = typename NodeMaskType::Word;
2497 struct A { inline void operator()(W &tV, const W& sV, const W& tC) const
2498 { tV = (tV | sV) & ~tC; }
2499 };
2500 TopologyUnion(const OtherInternalNode* source, InternalNode* target) : s(source), t(target) {
2501 //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//single thread for debugging
2502 tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
2503
2504 // Bit processing is done in a single thread!
2505 t->mChildMask |= s->mChildMask;//serial but very fast bitwise post-process
2506 A op;
2507 t->mValueMask.foreach(s->mValueMask, t->mChildMask, op);
2508 assert((t->mValueMask & t->mChildMask).isOff());//no overlapping active tiles or child nodes
2509 }
2510 void operator()(const tbb::blocked_range<Index> &r) const {
2511 for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
2512 if (s->mChildMask.isOn(i)) {// Loop over other node's child nodes
2513 const typename OtherInternalNode::ChildNodeType& other = *(s->mNodes[i].getChild());
2514 if (t->mChildMask.isOn(i)) {//this has a child node
2515 t->mNodes[i].getChild()->topologyUnion(other);
2516 } else {// this is a tile so replace it with a child branch with identical topology
2517 ChildT* child = new ChildT(other, t->mNodes[i].getValue(), TopologyCopy());
2518 if (t->mValueMask.isOn(i)) child->setValuesOn();//activate all values
2519 t->mNodes[i].setChild(child);
2520 }
2521 } else if (s->mValueMask.isOn(i) && t->mChildMask.isOn(i)) {
2522 t->mNodes[i].getChild()->setValuesOn();
2523 }
2524 }
2525 }
2526 const OtherInternalNode* s;
2527 InternalNode* t;
2528 };// TopologyUnion
2529
2530 template<typename ChildT, Index Log2Dim>
2531 template<typename OtherChildT>
2532 inline void
2533 InternalNode<ChildT, Log2Dim>::topologyUnion(const InternalNode<OtherChildT, Log2Dim>& other)
2534 {
2535 TopologyUnion<InternalNode<OtherChildT, Log2Dim> > tmp(&other, this);
2536 }
2537
2538 template<typename ChildT, Index Log2Dim>
2539 template<typename OtherInternalNode>
2540 struct InternalNode<ChildT, Log2Dim>::TopologyIntersection
2541 {
2542 using W = typename NodeMaskType::Word;
2543 struct A { inline void operator()(W &tC, const W& sC, const W& sV, const W& tV) const
2544 { tC = (tC & (sC | sV)) | (tV & sC); }
2545 };
2546 TopologyIntersection(const OtherInternalNode* source, InternalNode* target,
2547 const ValueType& background) : s(source), t(target), b(background) {
2548 //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//single thread for debugging
2549 tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
2550
2551 // Bit processing is done in a single thread!
2552 A op;
2553 t->mChildMask.foreach(s->mChildMask, s->mValueMask, t->mValueMask, op);
2554
2555 t->mValueMask &= s->mValueMask;
2556 assert((t->mValueMask & t->mChildMask).isOff());//no overlapping active tiles or child nodes
2557 }
2558 void operator()(const tbb::blocked_range<Index> &r) const {
2559 for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
2560 if (t->mChildMask.isOn(i)) {// Loop over this node's child nodes
2561 ChildT* child = t->mNodes[i].getChild();
2562 if (s->mChildMask.isOn(i)) {//other also has a child node
2563 child->topologyIntersection(*(s->mNodes[i].getChild()), b);
2564 } else if (s->mValueMask.isOff(i)) {//other is an inactive tile
2565 delete child;//convert child to an inactive tile
2566 t->mNodes[i].setValue(b);
2567 }
2568 } else if (t->mValueMask.isOn(i) && s->mChildMask.isOn(i)) {//active tile -> a branch
2569 t->mNodes[i].setChild(new ChildT(*(s->mNodes[i].getChild()),
2570 t->mNodes[i].getValue(), TopologyCopy()));
2571 }
2572 }
2573 }
2574 const OtherInternalNode* s;
2575 InternalNode* t;
2576 const ValueType& b;
2577 };// TopologyIntersection
2578
2579 template<typename ChildT, Index Log2Dim>
2580 template<typename OtherChildT>
2581 inline void
2582 InternalNode<ChildT, Log2Dim>::topologyIntersection(
2583 const InternalNode<OtherChildT, Log2Dim>& other, const ValueType& background)
2584 {
2585 TopologyIntersection<InternalNode<OtherChildT, Log2Dim> > tmp(&other, this, background);
2586 }
2587
2588 template<typename ChildT, Index Log2Dim>
2589 template<typename OtherInternalNode>
2590 struct InternalNode<ChildT, Log2Dim>::TopologyDifference
2591 {
2592 using W = typename NodeMaskType::Word;
2593 struct A {inline void operator()(W &tC, const W& sC, const W& sV, const W& tV) const
2594 { tC = (tC & (sC | ~sV)) | (tV & sC); }
2595 };
2596 struct B {inline void operator()(W &tV, const W& sC, const W& sV, const W& tC) const
2597 { tV &= ~((tC & sV) | (sC | sV)); }
2598 };
2599 TopologyDifference(const OtherInternalNode* source, InternalNode* target,
2600 const ValueType& background) : s(source), t(target), b(background) {
2601 //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//single thread for debugging
2602 tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
2603
2604 // Bit processing is done in a single thread!
2605 const NodeMaskType oldChildMask(t->mChildMask);//important to avoid cross pollution
2606 A op1;
2607 t->mChildMask.foreach(s->mChildMask, s->mValueMask, t->mValueMask, op1);
2608
2609 B op2;
2610 t->mValueMask.foreach(t->mChildMask, s->mValueMask, oldChildMask, op2);
2611 assert((t->mValueMask & t->mChildMask).isOff());//no overlapping active tiles or child nodes
2612 }
2613 void operator()(const tbb::blocked_range<Index> &r) const {
2614 for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
2615 if (t->mChildMask.isOn(i)) {// Loop over this node's child nodes
2616 ChildT* child = t->mNodes[i].getChild();
2617 if (s->mChildMask.isOn(i)) {
2618 child->topologyDifference(*(s->mNodes[i].getChild()), b);
2619 } else if (s->mValueMask.isOn(i)) {
2620 delete child;//convert child to an inactive tile
2621 t->mNodes[i].setValue(b);
2622 }
2623 } else if (t->mValueMask.isOn(i)) {//this is an active tile
2624 if (s->mChildMask.isOn(i)) {
2625 const typename OtherInternalNode::ChildNodeType& other =
2626 *(s->mNodes[i].getChild());
2627 ChildT* child = new ChildT(other.origin(), t->mNodes[i].getValue(), true);
2628 child->topologyDifference(other, b);
2629 t->mNodes[i].setChild(child);//replace the active tile with a child branch
2630 }
2631 }
2632 }
2633 }
2634 const OtherInternalNode* s;
2635 InternalNode* t;
2636 const ValueType& b;
2637 };// TopologyDifference
2638
2639 template<typename ChildT, Index Log2Dim>
2640 template<typename OtherChildT>
2641 inline void
2642 InternalNode<ChildT, Log2Dim>::topologyDifference(const InternalNode<OtherChildT, Log2Dim>& other,
2643 const ValueType& background)
2644 {
2645 TopologyDifference<InternalNode<OtherChildT, Log2Dim> > tmp(&other, this, background);
2646 }
2647
2648
2650
2651
2652 template<typename ChildT, Index Log2Dim>
2653 template<typename CombineOp>
2654 inline void
2655 InternalNode<ChildT, Log2Dim>::combine(InternalNode& other, CombineOp& op)
2656 {
2657 const ValueType zero = zeroVal<ValueType>();
2658
2659 CombineArgs<ValueType> args;
2660
2661 for (Index i = 0; i < NUM_VALUES; ++i) {
2662 if (this->isChildMaskOff(i) && other.isChildMaskOff(i)) {
2663 // Both this node and the other node have constant values (tiles).
2664 // Combine the two values and store the result as this node's new tile value.
2665 op(args.setARef(mNodes[i].getValue())
2666 .setAIsActive(isValueMaskOn(i))
2667 .setBRef(other.mNodes[i].getValue())
2668 .setBIsActive(other.isValueMaskOn(i)));
2669 mNodes[i].setValue(args.result());
2670 mValueMask.set(i, args.resultIsActive());
2671 } else if (this->isChildMaskOn(i) && other.isChildMaskOff(i)) {
2672 // Combine this node's child with the other node's constant value.
2673 ChildNodeType* child = mNodes[i].getChild();
2674 assert(child);
2675 if (child) {
2676 child->combine(other.mNodes[i].getValue(), other.isValueMaskOn(i), op);
2677 }
2678 } else if (this->isChildMaskOff(i) && other.isChildMaskOn(i)) {
2679 // Combine this node's constant value with the other node's child.
2680 ChildNodeType* child = other.mNodes[i].getChild();
2681 assert(child);
2682 if (child) {
2683 // Combine this node's constant value with the other node's child,
2684 // but use a new functor in which the A and B values are swapped,
2685 // since the constant value is the A value, not the B value.
2686 SwappedCombineOp<ValueType, CombineOp> swappedOp(op);
2687 child->combine(mNodes[i].getValue(), isValueMaskOn(i), swappedOp);
2688
2689 // Steal the other node's child.
2690 other.mChildMask.setOff(i);
2691 other.mNodes[i].setValue(zero);
2692 this->setChildNode(i, child);
2693 }
2694
2695 } else /*if (isChildMaskOn(i) && other.isChildMaskOn(i))*/ {
2696 // Combine this node's child with the other node's child.
2697 ChildNodeType
2698 *child = mNodes[i].getChild(),
2699 *otherChild = other.mNodes[i].getChild();
2700 assert(child);
2701 assert(otherChild);
2702 if (child && otherChild) {
2703 child->combine(*otherChild, op);
2704 }
2705 }
2706 }
2707 }
2708
2709
2710 template<typename ChildT, Index Log2Dim>
2711 template<typename CombineOp>
2712 inline void
2713 InternalNode<ChildT, Log2Dim>::combine(const ValueType& value, bool valueIsActive, CombineOp& op)
2714 {
2715 CombineArgs<ValueType> args;
2716
2717 for (Index i = 0; i < NUM_VALUES; ++i) {
2718 if (this->isChildMaskOff(i)) {
2719 // Combine this node's constant value with the given constant value.
2720 op(args.setARef(mNodes[i].getValue())
2721 .setAIsActive(isValueMaskOn(i))
2722 .setBRef(value)
2723 .setBIsActive(valueIsActive));
2724 mNodes[i].setValue(args.result());
2725 mValueMask.set(i, args.resultIsActive());
2726 } else /*if (isChildMaskOn(i))*/ {
2727 // Combine this node's child with the given constant value.
2728 ChildNodeType* child = mNodes[i].getChild();
2729 assert(child);
2730 if (child) child->combine(value, valueIsActive, op);
2731 }
2732 }
2733 }
2734
2735
2737
2738
2739 template<typename ChildT, Index Log2Dim>
2740 template<typename CombineOp, typename OtherNodeType>
2741 inline void
2742 InternalNode<ChildT, Log2Dim>::combine2(const InternalNode& other0, const OtherNodeType& other1,
2743 CombineOp& op)
2744 {
2745 CombineArgs<ValueType, typename OtherNodeType::ValueType> args;
2746
2747 for (Index i = 0; i < NUM_VALUES; ++i) {
2748 if (other0.isChildMaskOff(i) && other1.isChildMaskOff(i)) {
2749 op(args.setARef(other0.mNodes[i].getValue())
2750 .setAIsActive(other0.isValueMaskOn(i))
2751 .setBRef(other1.mNodes[i].getValue())
2752 .setBIsActive(other1.isValueMaskOn(i)));
2753 // Replace child i with a constant value.
2754 this->makeChildNodeEmpty(i, args.result());
2755 mValueMask.set(i, args.resultIsActive());
2756 } else {
2757 if (this->isChildMaskOff(i)) {
2758 // Add a new child with the same coordinates, etc. as the other node's child.
2759 const Coord& childOrigin = other0.isChildMaskOn(i)
2760 ? other0.mNodes[i].getChild()->origin()
2761 : other1.mNodes[i].getChild()->origin();
2762 this->setChildNode(i, new ChildNodeType(childOrigin, mNodes[i].getValue()));
2763 }
2764
2765 if (other0.isChildMaskOff(i)) {
2766 // Combine node1's child with node0's constant value
2767 // and write the result into child i.
2768 mNodes[i].getChild()->combine2(other0.mNodes[i].getValue(),
2769 *other1.mNodes[i].getChild(), other0.isValueMaskOn(i), op);
2770 } else if (other1.isChildMaskOff(i)) {
2771 // Combine node0's child with node1's constant value
2772 // and write the result into child i.
2773 mNodes[i].getChild()->combine2(*other0.mNodes[i].getChild(),
2774 other1.mNodes[i].getValue(), other1.isValueMaskOn(i), op);
2775 } else {
2776 // Combine node0's child with node1's child
2777 // and write the result into child i.
2778 mNodes[i].getChild()->combine2(*other0.mNodes[i].getChild(),
2779 *other1.mNodes[i].getChild(), op);
2780 }
2781 }
2782 }
2783 }
2784
2785
2786 template<typename ChildT, Index Log2Dim>
2787 template<typename CombineOp, typename OtherNodeType>
2788 inline void
2789 InternalNode<ChildT, Log2Dim>::combine2(const ValueType& value, const OtherNodeType& other,
2790 bool valueIsActive, CombineOp& op)
2791 {
2792 CombineArgs<ValueType, typename OtherNodeType::ValueType> args;
2793
2794 for (Index i = 0; i < NUM_VALUES; ++i) {
2795 if (other.isChildMaskOff(i)) {
2796 op(args.setARef(value)
2797 .setAIsActive(valueIsActive)
2798 .setBRef(other.mNodes[i].getValue())
2799 .setBIsActive(other.isValueMaskOn(i)));
2800 // Replace child i with a constant value.
2801 this->makeChildNodeEmpty(i, args.result());
2802 mValueMask.set(i, args.resultIsActive());
2803 } else {
2804 typename OtherNodeType::ChildNodeType* otherChild = other.mNodes[i].getChild();
2805 assert(otherChild);
2806 if (this->isChildMaskOff(i)) {
2807 // Add a new child with the same coordinates, etc.
2808 // as the other node's child.
2809 this->setChildNode(i, new ChildNodeType(*otherChild));
2810 }
2811 // Combine the other node's child with a constant value
2812 // and write the result into child i.
2813 mNodes[i].getChild()->combine2(value, *otherChild, valueIsActive, op);
2814 }
2815 }
2816 }
2817
2818
2819 template<typename ChildT, Index Log2Dim>
2820 template<typename CombineOp, typename OtherValueType>
2821 inline void
2822 InternalNode<ChildT, Log2Dim>::combine2(const InternalNode& other, const OtherValueType& value,
2823 bool valueIsActive, CombineOp& op)
2824 {
2825 CombineArgs<ValueType, OtherValueType> args;
2826
2827 for (Index i = 0; i < NUM_VALUES; ++i) {
2828 if (other.isChildMaskOff(i)) {
2829 op(args.setARef(other.mNodes[i].getValue())
2830 .setAIsActive(other.isValueMaskOn(i))
2831 .setBRef(value)
2832 .setBIsActive(valueIsActive));
2833 // Replace child i with a constant value.
2834 this->makeChildNodeEmpty(i, args.result());
2835 mValueMask.set(i, args.resultIsActive());
2836 } else {
2837 ChildNodeType* otherChild = other.mNodes[i].getChild();
2838 assert(otherChild);
2839 if (this->isChildMaskOff(i)) {
2840 // Add a new child with the same coordinates, etc. as the other node's child.
2841 this->setChildNode(i,
2842 new ChildNodeType(otherChild->origin(), mNodes[i].getValue()));
2843 }
2844 // Combine the other node's child with a constant value
2845 // and write the result into child i.
2846 mNodes[i].getChild()->combine2(*otherChild, value, valueIsActive, op);
2847 }
2848 }
2849 }
2850
2851
2853
2854
2855 template<typename ChildT, Index Log2Dim>
2856 template<typename BBoxOp>
2857 inline void
2858 InternalNode<ChildT, Log2Dim>::visitActiveBBox(BBoxOp& op) const
2859 {
2860 for (ValueOnCIter i = this->cbeginValueOn(); i; ++i) {
2861 #ifdef _MSC_VER
2862 op.operator()<LEVEL>(CoordBBox::createCube(i.getCoord(), ChildNodeType::DIM));
2863 #else
2864 op.template operator()<LEVEL>(CoordBBox::createCube(i.getCoord(), ChildNodeType::DIM));
2865 #endif
2866 }
2867 if (op.template descent<LEVEL>()) {
2868 for (ChildOnCIter i = this->cbeginChildOn(); i; ++i) i->visitActiveBBox(op);
2869 } else {
2870 for (ChildOnCIter i = this->cbeginChildOn(); i; ++i) {
2871 #ifdef _MSC_VER
2872 op.operator()<LEVEL>(i->getNodeBoundingBox());
2873 #else
2874 op.template operator()<LEVEL>(i->getNodeBoundingBox());
2875 #endif
2876 }
2877 }
2878 }
2879
2880
2881 template<typename ChildT, Index Log2Dim>
2882 template<typename VisitorOp>
2883 inline void
2884 InternalNode<ChildT, Log2Dim>::visit(VisitorOp& op)
2885 {
2886 doVisit<InternalNode, VisitorOp, ChildAllIter>(*this, op);
2887 }
2888
2889
2890 template<typename ChildT, Index Log2Dim>
2891 template<typename VisitorOp>
2892 inline void
2893 InternalNode<ChildT, Log2Dim>::visit(VisitorOp& op) const
2894 {
2895 doVisit<const InternalNode, VisitorOp, ChildAllCIter>(*this, op);
2896 }
2897
2898
2899 template<typename ChildT, Index Log2Dim>
2900 template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
2901 inline void
2902 InternalNode<ChildT, Log2Dim>::doVisit(NodeT& self, VisitorOp& op)
2903 {
2904 typename NodeT::ValueType val;
2905 for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
2906 if (op(iter)) continue;
2907 if (typename ChildAllIterT::ChildNodeType* child = iter.probeChild(val)) {
2908 child->visit(op);
2909 }
2910 }
2911 }
2912
2913
2915
2916
2917 template<typename ChildT, Index Log2Dim>
2918 template<typename OtherNodeType, typename VisitorOp>
2919 inline void
2920 InternalNode<ChildT, Log2Dim>::visit2Node(OtherNodeType& other, VisitorOp& op)
2921 {
2922 doVisit2Node<InternalNode, OtherNodeType, VisitorOp, ChildAllIter,
2923 typename OtherNodeType::ChildAllIter>(*this, other, op);
2924 }
2925
2926
2927 template<typename ChildT, Index Log2Dim>
2928 template<typename OtherNodeType, typename VisitorOp>
2929 inline void
2930 InternalNode<ChildT, Log2Dim>::visit2Node(OtherNodeType& other, VisitorOp& op) const
2931 {
2932 doVisit2Node<const InternalNode, OtherNodeType, VisitorOp, ChildAllCIter,
2933 typename OtherNodeType::ChildAllCIter>(*this, other, op);
2934 }
2935
2936
2937 template<typename ChildT, Index Log2Dim>
2938 template<
2939 typename NodeT,
2940 typename OtherNodeT,
2941 typename VisitorOp,
2942 typename ChildAllIterT,
2943 typename OtherChildAllIterT>
2944 inline void
2945 InternalNode<ChildT, Log2Dim>::doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp& op)
2946 {
2947 // Allow the two nodes to have different ValueTypes, but not different dimensions.
2948 static_assert(OtherNodeT::NUM_VALUES == NodeT::NUM_VALUES,
2949 "visit2() requires nodes to have the same dimensions");
2950 static_assert(OtherNodeT::LEVEL == NodeT::LEVEL,
2951 "visit2() requires nodes to be at the same tree level");
2952
2953 typename NodeT::ValueType val;
2954 typename OtherNodeT::ValueType otherVal;
2955
2956 ChildAllIterT iter = self.beginChildAll();
2957 OtherChildAllIterT otherIter = other.beginChildAll();
2958
2959 for ( ; iter && otherIter; ++iter, ++otherIter)
2960 {
2961 const size_t skipBranch = static_cast<size_t>(op(iter, otherIter));
2962
2963 typename ChildAllIterT::ChildNodeType* child =
2964 (skipBranch & 1U) ? nullptr : iter.probeChild(val);
2965 typename OtherChildAllIterT::ChildNodeType* otherChild =
2966 (skipBranch & 2U) ? nullptr : otherIter.probeChild(otherVal);
2967
2968 if (child != nullptr && otherChild != nullptr) {
2969 child->visit2Node(*otherChild, op);
2970 } else if (child != nullptr) {
2971 child->visit2(otherIter, op);
2972 } else if (otherChild != nullptr) {
2973 otherChild->visit2(iter, op, /*otherIsLHS=*/true);
2974 }
2975 }
2976 }
2977
2978
2980
2981
2982 template<typename ChildT, Index Log2Dim>
2983 template<typename OtherChildAllIterType, typename VisitorOp>
2984 inline void
2985 InternalNode<ChildT, Log2Dim>::visit2(OtherChildAllIterType& otherIter,
2986 VisitorOp& op, bool otherIsLHS)
2987 {
2988 doVisit2<InternalNode, VisitorOp, ChildAllIter, OtherChildAllIterType>(
2989 *this, otherIter, op, otherIsLHS);
2990 }
2991
2992
2993 template<typename ChildT, Index Log2Dim>
2994 template<typename OtherChildAllIterType, typename VisitorOp>
2995 inline void
2996 InternalNode<ChildT, Log2Dim>::visit2(OtherChildAllIterType& otherIter,
2997 VisitorOp& op, bool otherIsLHS) const
2998 {
2999 doVisit2<const InternalNode, VisitorOp, ChildAllCIter, OtherChildAllIterType>(
3000 *this, otherIter, op, otherIsLHS);
3001 }
3002
3003
3004 template<typename ChildT, Index Log2Dim>
3005 template<typename NodeT, typename VisitorOp, typename ChildAllIterT, typename OtherChildAllIterT>
3006 inline void
3007 InternalNode<ChildT, Log2Dim>::doVisit2(NodeT& self, OtherChildAllIterT& otherIter,
3008 VisitorOp& op, bool otherIsLHS)
3009 {
3010 if (!otherIter) return;
3011
3012 const size_t skipBitMask = (otherIsLHS ? 2U : 1U);
3013
3014 typename NodeT::ValueType val;
3015 for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
3016 const size_t skipBranch = static_cast<size_t>(
3017 otherIsLHS ? op(otherIter, iter) : op(iter, otherIter));
3018
3019 typename ChildAllIterT::ChildNodeType* child =
3020 (skipBranch & skipBitMask) ? nullptr : iter.probeChild(val);
3021
3022 if (child != nullptr) child->visit2(otherIter, op, otherIsLHS);
3023 }
3024 }
3025
3026
3028
3029
3030 template<typename ChildT, Index Log2Dim>
3031 inline void
3032 InternalNode<ChildT, Log2Dim>::writeBuffers(std::ostream& os, bool toHalf) const
3033 {
3034 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
3035 iter->writeBuffers(os, toHalf);
3036 }
3037 }
3038
3039
3040 template<typename ChildT, Index Log2Dim>
3041 inline void
3042 InternalNode<ChildT, Log2Dim>::readBuffers(std::istream& is, bool fromHalf)
3043 {
3044 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
3045 iter->readBuffers(is, fromHalf);
3046 }
3047 }
3048
3049
3050 template<typename ChildT, Index Log2Dim>
3051 inline void
3052 InternalNode<ChildT, Log2Dim>::readBuffers(std::istream& is,
3053 const CoordBBox& clipBBox, bool fromHalf)
3054 {
3055 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
3056 // Stream in the branch rooted at this child.
3057 // (We can't skip over children that lie outside the clipping region,
3058 // because buffers are serialized in depth-first order and need to be
3059 // unserialized in the same order.)
3060 iter->readBuffers(is, clipBBox, fromHalf);
3061 }
3062
3063 // Get this tree's background value.
3064 ValueType background = zeroVal<ValueType>();
3065 if (const void* bgPtr = io::getGridBackgroundValuePtr(is)) {
3066 background = *static_cast<const ValueType*>(bgPtr);
3067 }
3068 this->clip(clipBBox, background);
3069 }
3070
3071
3073
3074
3075 template<typename ChildT, Index Log2Dim>
3076 void
3077 InternalNode<ChildT, Log2Dim>::getNodeLog2Dims(std::vector<Index>& dims)
3078 {
3079 dims.push_back(Log2Dim);
3080 ChildNodeType::getNodeLog2Dims(dims);
3081 }
3082
3083
3084 template<typename ChildT, Index Log2Dim>
3085 inline void
3086 InternalNode<ChildT, Log2Dim>::offsetToLocalCoord(Index n, Coord &xyz)
3087 {
3088 assert(n<(1<<3*Log2Dim));
3089 xyz.setX(n >> 2*Log2Dim);
3090 n &= ((1<<2*Log2Dim)-1);
3091 xyz.setY(n >> Log2Dim);
3092 xyz.setZ(n & ((1<<Log2Dim)-1));
3093 }
3094
3095
3096 template<typename ChildT, Index Log2Dim>
3097 inline Index
3098 InternalNode<ChildT, Log2Dim>::coordToOffset(const Coord& xyz)
3099 {
3100 return (((xyz[0] & (DIM-1u)) >> ChildNodeType::TOTAL) << 2*Log2Dim)
3101 + (((xyz[1] & (DIM-1u)) >> ChildNodeType::TOTAL) << Log2Dim)
3102 + ((xyz[2] & (DIM-1u)) >> ChildNodeType::TOTAL);
3103 }
3104
3105
3106 template<typename ChildT, Index Log2Dim>
3107 inline Coord
3108 InternalNode<ChildT, Log2Dim>::offsetToGlobalCoord(Index n) const
3109 {
3110 Coord local;
3111 this->offsetToLocalCoord(n, local);
3112 local <<= ChildT::TOTAL;
3113 return local + this->origin();
3114 }
3115
3116
3118
3119
3120 template<typename ChildT, Index Log2Dim>
3121 template<typename ArrayT>
3122 inline void
3123 InternalNode<ChildT, Log2Dim>::getNodes(ArrayT& array)
3124 {
3125 using T = typename ArrayT::value_type;
3126 static_assert(std::is_pointer<T>::value, "argument to getNodes() must be a pointer array");
3127 using ArrayChildT = typename std::conditional<
3128 std::is_const<typename std::remove_pointer<T>::type>::value, const ChildT, ChildT>::type;
3129 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
3130 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
3131 if (std::is_same<T, ArrayChildT*>::value) {
3132 array.push_back(reinterpret_cast<T>(mNodes[iter.pos()].getChild()));
3133 } else {
3134 iter->getNodes(array);//descent
3135 }
3136 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
3137 }
3138 }
3139
3140 template<typename ChildT, Index Log2Dim>
3141 template<typename ArrayT>
3142 inline void
3143 InternalNode<ChildT, Log2Dim>::getNodes(ArrayT& array) const
3144 {
3145 using T = typename ArrayT::value_type;
3146 static_assert(std::is_pointer<T>::value, "argument to getNodes() must be a pointer array");
3147 static_assert(std::is_const<typename std::remove_pointer<T>::type>::value,
3148 "argument to getNodes() must be an array of const node pointers");
3149 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
3150 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
3151 if (std::is_same<T, const ChildT*>::value) {
3152 array.push_back(reinterpret_cast<T>(mNodes[iter.pos()].getChild()));
3153 } else {
3154 iter->getNodes(array);//descent
3155 }
3156 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
3157 }
3158 }
3159
3160
3162
3163
3164 template<typename ChildT, Index Log2Dim>
3165 template<typename ArrayT>
3166 inline void
3167 InternalNode<ChildT, Log2Dim>::stealNodes(ArrayT& array, const ValueType& value, bool state)
3168 {
3169 using T = typename ArrayT::value_type;
3170 static_assert(std::is_pointer<T>::value, "argument to stealNodes() must be a pointer array");
3171 using ArrayChildT = typename std::conditional<
3172 std::is_const<typename std::remove_pointer<T>::type>::value, const ChildT, ChildT>::type;
3173 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
3174 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
3175 const Index n = iter.pos();
3176 if (std::is_same<T, ArrayChildT*>::value) {
3177 array.push_back(reinterpret_cast<T>(mNodes[n].getChild()));
3178 mValueMask.set(n, state);
3179 mNodes[n].setValue(value);
3180 } else {
3181 iter->stealNodes(array, value, state);//descent
3182 }
3183 }
3184 if (std::is_same<T, ArrayChildT*>::value) mChildMask.setOff();
3185 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
3186 }
3187
3188
3190
3191
3192 template<typename ChildT, Index Log2Dim>
3193 inline void
3194 InternalNode<ChildT, Log2Dim>::resetBackground(const ValueType& oldBackground,
3195 const ValueType& newBackground)
3196 {
3197 if (math::isExactlyEqual(oldBackground, newBackground)) return;
3198 for (Index i = 0; i < NUM_VALUES; ++i) {
3199 if (this->isChildMaskOn(i)) {
3200 mNodes[i].getChild()->resetBackground(oldBackground, newBackground);
3201 } else if (this->isValueMaskOff(i)) {
3202 if (math::isApproxEqual(mNodes[i].getValue(), oldBackground)) {
3203 mNodes[i].setValue(newBackground);
3204 } else if (math::isApproxEqual(mNodes[i].getValue(), math::negative(oldBackground))) {
3205 mNodes[i].setValue(math::negative(newBackground));
3206 }
3207 }
3208 }
3209 }
3210
3211 template<typename ChildT, Index Log2Dim>
3212 template<typename OtherChildNodeType, Index OtherLog2Dim>
3213 inline bool
3214 InternalNode<ChildT, Log2Dim>::hasSameTopology(
3215 const InternalNode<OtherChildNodeType, OtherLog2Dim>* other) const
3216 {
3217 if (Log2Dim != OtherLog2Dim || mChildMask != other->mChildMask ||
3218 mValueMask != other->mValueMask) return false;
3219 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
3220 if (!iter->hasSameTopology(other->mNodes[iter.pos()].getChild())) return false;
3221 }
3222 return true;
3223 }
3224
3225
3226 template<typename ChildT, Index Log2Dim>
3227 inline void
3228 InternalNode<ChildT, Log2Dim>::resetChildNode(Index i, ChildNodeType* child)
3229 {
3230 assert(child);
3231 if (this->isChildMaskOn(i)) {
3232 delete mNodes[i].getChild();
3233 } else {
3234 mChildMask.setOn(i);
3235 mValueMask.setOff(i);
3236 }
3237 mNodes[i].setChild(child);
3238 }
3239
3240 template<typename ChildT, Index Log2Dim>
3241 inline void
3242 InternalNode<ChildT, Log2Dim>::setChildNode(Index i, ChildNodeType* child)
3243 {
3244 assert(child);
3245 assert(mChildMask.isOff(i));
3246 mChildMask.setOn(i);
3247 mValueMask.setOff(i);
3248 mNodes[i].setChild(child);
3249 }
3250
3251
3252 template<typename ChildT, Index Log2Dim>
3253 inline ChildT*
3254 InternalNode<ChildT, Log2Dim>::unsetChildNode(Index i, const ValueType& value)
3255 {
3256 if (this->isChildMaskOff(i)) {
3257 mNodes[i].setValue(value);
3258 return nullptr;
3259 }
3260 ChildNodeType* child = mNodes[i].getChild();
3261 mChildMask.setOff(i);
3262 mNodes[i].setValue(value);
3263 return child;
3264 }
3265
3266
3267 template<typename ChildT, Index Log2Dim>
3268 inline void
3269 InternalNode<ChildT, Log2Dim>::makeChildNodeEmpty(Index n, const ValueType& value)
3270 {
3271 delete this->unsetChildNode(n, value);
3272 }
3273
3274 template<typename ChildT, Index Log2Dim>
3275 inline ChildT*
3276 InternalNode<ChildT, Log2Dim>::getChildNode(Index n)
3277 {
3278 assert(this->isChildMaskOn(n));
3279 return mNodes[n].getChild();
3280 }
3281
3282
3283 template<typename ChildT, Index Log2Dim>
3284 inline const ChildT*
3285 InternalNode<ChildT, Log2Dim>::getChildNode(Index n) const
3286 {
3287 assert(this->isChildMaskOn(n));
3288 return mNodes[n].getChild();
3289 }
3290
3291 } // namespace tree
3292 } // namespace OPENVDB_VERSION_NAME
3293 } // namespace openvdb
3294
3295 #endif // OPENVDB_TREE_INTERNALNODE_HAS_BEEN_INCLUDED
3296
3297 // Copyright (c) 2012-2017 DreamWorks Animation LLC
3298 // All rights reserved. This software is distributed under the
3299 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
openvdb::v4_0_2::tree::NodeUnion::setChild
void setChild(ChildT *child)
Definition: NodeUnion.h:69
openvdb::v4_0_2::math::Coord::offsetBy
Coord offsetBy(Int32 dx, Int32 dy, Int32 dz) const
Definition: Coord.h:115
openvdb::v4_0_2::tree::InternalNode::isValueMaskOff
bool isValueMaskOff(Index n) const
Definition: InternalNode.h:779
openvdb::v4_0_2::tree::InternalNode::ChildAll
Definition: InternalNode.h:149
openvdb::v4_0_2::tree::InternalNode::hasActiveTiles
bool hasActiveTiles() const
Return true if this node or any of its child nodes have any active tiles.
Definition: InternalNode.h:1538
openvdb::v4_0_2::tree::InternalNode::onLeafVoxelCount
Index64 onLeafVoxelCount() const
Definition: InternalNode.h:1081
openvdb::v4_0_2::tree::SparseIteratorBase
Base class for sparse iterators over internal and leaf nodes.
Definition: Iterator.h:143
openvdb::v4_0_2::logging::getLevel
Level getLevel()
Return the current logging level.
Definition: logging.h:164
openvdb::v4_0_2::tree::InternalNode::setValueOff
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don&#39;t change its value.
Definition: InternalNode.h:1647
openvdb::v4_0_2::tree::InternalNode::TopologyIntersection::A::operator()
void operator()(W &tC, const W &sC, const W &sV, const W &tV) const
Definition: InternalNode.h:2543
openvdb::v4_0_2::tools::clip
GridType::Ptr clip(const GridType &grid, const BBoxd &bbox, bool keepInterior=true)
Clip the given grid against a world-space bounding box and return a new grid containing the result...
Definition: Clip.h:375
openvdb::v4_0_2::io::getGridBackgroundValuePtr
OPENVDB_API const void * getGridBackgroundValuePtr(std::ios_base &)
Return a pointer to the background value of the grid currently being read from or written to the give...
openvdb::v4_0_2::tree::InternalNode::TopologyDifference::TopologyDifference
TopologyDifference(const OtherInternalNode *source, InternalNode *target, const ValueType &background)
Definition: InternalNode.h:2599
Types.h
openvdb::v4_0_2::tree::NodeUnion::getValue
const ValueT & getValue() const
Definition: NodeUnion.h:71
Compression.h
openvdb::v4_0_2::tree::InternalNode::touchLeafAndCache
LeafNodeType * touchLeafAndCache(const Coord &xyz, AccessorT &)
Same as touchLeaf() except, if necessary, update the accessor with pointers to the nodes along the pa...
openvdb::v4_0_2::tree::InternalNode::addLeaf
void addLeaf(LeafNodeType *leaf)
Add the specified leaf to this node, possibly creating a child branch in the process. If the leaf node already exists, replace it.
Definition: InternalNode.h:1318
openvdb::v4_0_2::tree::InternalNode::resetChildNode
void resetChildNode(Index i, ChildNodeType *child)
Definition: InternalNode.h:3228
openvdb::v4_0_2::tree::InternalNode::TopologyCopy2::TopologyCopy2
TopologyCopy2(const OtherInternalNode *source, InternalNode *target, const ValueType &offValue, const ValueType &onValue)
Definition: InternalNode.h:982
openvdb::v4_0_2::MERGE_NODES
Definition: Types.h:317
openvdb::v4_0_2::math::Coord::z
Int32 z() const
Definition: Coord.h:156
openvdb::v4_0_2::tree::InternalNode::ChildNodeType
_ChildNodeType ChildNodeType
Definition: InternalNode.h:63
Math.h
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
openvdb::v4_0_2::tree::InternalNode::TopologyUnion::TopologyUnion
TopologyUnion(const OtherInternalNode *source, InternalNode *target)
Definition: InternalNode.h:2500
openvdb::v4_0_2::math::Coord::setZ
Coord & setZ(Int32 z)
Definition: Coord.h:105
openvdb::v4_0_2::tree::InternalNode::readBuffers
void readBuffers(std::istream &, bool fromHalf=false)
Definition: InternalNode.h:3042
openvdb::v4_0_2::tree::InternalNode::isEmpty
bool isEmpty() const
Definition: InternalNode.h:322
openvdb::v4_0_2::tree::InternalNode::DenseIter
Definition: InternalNode.h:199
openvdb::v4_0_2::tree::InternalNode::TopologyDifference
Definition: InternalNode.h:832
openvdb::v4_0_2::util::NodeMask::isOn
bool isOn(Index32 n) const
Return true if the nth bit is on.
Definition: NodeMasks.h:502
openvdb::v4_0_2::tree::InternalNode::mChildMask
NodeMaskType mChildMask
Definition: InternalNode.h:837
openvdb::v4_0_2::tree::InternalNode::cbeginValueOff
ValueOffCIter cbeginValueOff() const
Definition: InternalNode.h:261
openvdb::v4_0_2::tree::IteratorBase
Base class for iterators over internal and leaf nodes.
Definition: Iterator.h:58
openvdb::v4_0_2::tree::InternalNode::probeConstNode
const NodeType * probeConstNode(const Coord &xyz) const
Return a pointer to the node that contains voxel (x, y, z). If no such node exists, return nullptr.
openvdb::v4_0_2::tree::InternalNode::TopologyDifference::b
const ValueType & b
Definition: InternalNode.h:2636
openvdb::v4_0_2::tree::InternalNode::TopologyDifference::operator()
void operator()(const tbb::blocked_range< Index > &r) const
Definition: InternalNode.h:2613
openvdb::v4_0_2::tree::InternalNode::TopologyCopy2::operator()
void operator()(const tbb::blocked_range< Index > &r) const
Definition: InternalNode.h:987
openvdb::v4_0_2::tree::InternalNode::DenseIter::DenseIter
DenseIter()
Definition: InternalNode.h:205
openvdb::v4_0_2::math::Coord::y
Int32 y() const
Definition: Coord.h:155
openvdb::v4_0_2::tree::InternalNode::cbeginChildAll
ChildAllCIter cbeginChildAll() const
Definition: InternalNode.h:251
openvdb::v4_0_2::tree::InternalNode::TopologyDifference::s
const OtherInternalNode * s
Definition: InternalNode.h:2634
openvdb::v4_0_2::Index32
uint32_t Index32
Definition: Types.h:55
openvdb::v4_0_2::math::isExactlyEqual
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:391
openvdb::v4_0_2::tree::InternalNode::stealNodes
void stealNodes(ArrayT &array, const ValueType &value, bool state)
Steals all nodes of a certain type from the tree and adds them to a container with the following API:...
Definition: InternalNode.h:3167
openvdb::v4_0_2::tree::InternalNode::TopologyUnion::A
Definition: InternalNode.h:2497
openvdb::v4_0_2::tree::InternalNode::beginChildOff
ChildOffIter beginChildOff()
Definition: InternalNode.h:256
openvdb::v4_0_2::tree::InternalNode::doVisit2Node
static void doVisit2Node(NodeT &, OtherNodeT &, VisitorOp &)
Definition: InternalNode.h:2945
openvdb::v4_0_2::tree::InternalNode::getChildMask
const NodeMaskType & getChildMask() const
Definition: InternalNode.h:785
openvdb::v4_0_2::tree::InternalNode::ChildAllCIter
DenseIter< const InternalNode, const ChildNodeType, ValueType, ChildAll > ChildAllCIter
Definition: InternalNode.h:240
openvdb::v4_0_2::tree::InternalNode::beginChildAll
ChildAllIter beginChildAll()
Definition: InternalNode.h:257
i
tbb::atomic< Index32 > i
Definition: LeafBuffer.h:71
openvdb::v4_0_2::tree::InternalNode::probeNodeAndCache
NodeType * probeNodeAndCache(const Coord &xyz, AccessorT &)
Same as probeNode() except, if necessary, update the accessor with pointers to the nodes along the pa...
openvdb::v4_0_2::math::isApproxEqual
bool isApproxEqual(const Type &a, const Type &b)
Return true if a is equal to b to within the default floating-point comparison tolerance.
Definition: Math.h:354
openvdb::v4_0_2::tree::InternalNode::modifyValueAndActiveState
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
Definition: InternalNode.h:1922
openvdb::v4_0_2::tree::InternalNode::ChildIter::getItem
ChildT & getItem(Index pos) const
Definition: InternalNode.h:163
openvdb::v4_0_2::tree::InternalNode::setValueOffAndCache
void setValueOffAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
Definition: InternalNode.h:1699
openvdb::v4_0_2::tree::InternalNode::ValueIter::modifyItem
void modifyItem(Index pos, const ModifyOp &op) const
Definition: InternalNode.h:191
openvdb::v4_0_2::tree::InternalNode::touchLeaf
LeafNodeType * touchLeaf(const Coord &xyz)
Return the leaf node that contains voxel (x, y, z). If no such node exists, create one...
Definition: InternalNode.h:1458
openvdb::v4_0_2::tree::InternalNode::TopologyDifference::t
InternalNode * t
Definition: InternalNode.h:2635
openvdb::v4_0_2::tree::InternalNode::getValueLevel
Index getValueLevel(const Coord &xyz) const
Return the level of the tree (0 = leaf) at which the value at the given coordinates resides...
Definition: InternalNode.h:1597
openvdb::v4_0_2::tree::InternalNode::ChildIter::ChildIter
ChildIter()
Definition: InternalNode.h:159
openvdb::v4_0_2::math::CoordBBox
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:261
openvdb::v4_0_2::tree::InternalNode::DIM
static const Index DIM
Definition: InternalNode.h:73
openvdb::v4_0_2::tree::InternalNode::modifyValueAndCache
void modifyValueAndCache(const Coord &xyz, const ModifyOp &op, AccessorT &)
Apply a functor to the value of the voxel at the given coordinates and mark the voxel as active...
Definition: InternalNode.h:1888
openvdb::v4_0_2::tree::InternalNode::mNodes
UnionType mNodes[NUM_VALUES]
Definition: InternalNode.h:833
openvdb::v4_0_2::SwappedCombineOp
Definition: Types.h:462
openvdb::v4_0_2::math::CoordBBox::expand
void expand(ValueType padding)
Pad this bounding box with the specified padding.
Definition: Coord.h:419
openvdb::v4_0_2::tree::InternalNode::topologyDifference
void topologyDifference(const InternalNode< OtherChildNodeType, Log2Dim > &other, const ValueType &background)
Difference this node&#39;s set of active values with the active values of the other node, whose ValueType may be different. So a resulting voxel will be active only if the original voxel is active in this node and inactive in the other node.
openvdb::v4_0_2::tree::InternalNode::beginChildOn
ChildOnIter beginChildOn()
Definition: InternalNode.h:255
openvdb::v4_0_2::tree::InternalNode::VoxelizeActiveTiles
Definition: InternalNode.h:2307
openvdb::v4_0_2::tree::InternalNode::ValueConverter
ValueConverter<T>::Type is the type of an InternalNode having the same child hierarchy and dimensions...
Definition: InternalNode.h:82
openvdb::v4_0_2::tree::InternalNode::prune
void prune(const ValueType &tolerance=zeroVal< ValueType >())
Reduce the memory footprint of this tree by replacing with tiles any nodes whose values are all the s...
Definition: InternalNode.h:1146
openvdb::v4_0_2::tree::InternalNode::TopologyCopy1::s
const OtherInternalNode * s
Definition: InternalNode.h:961
openvdb::v4_0_2::tree::InternalNode::ChildAllIter
DenseIter< InternalNode, ChildNodeType, ValueType, ChildAll > ChildAllIter
Definition: InternalNode.h:239
openvdb::v4_0_2::tree::InternalNode::probeValue
bool probeValue(const Coord &xyz, ValueType &value) const
Definition: InternalNode.h:1619
openvdb::v4_0_2::tree::InternalNode::probeLeafAndCache
LeafNodeType * probeLeafAndCache(const Coord &xyz, AccessorT &acc)
Same as probeLeaf() except, if necessary, update the accessor with pointers to the nodes along the pa...
openvdb::v4_0_2::tree::InternalNode::nonLeafCount
Index32 nonLeafCount() const
Definition: InternalNode.h:1044
openvdb::v4_0_2::tree::InternalNode::TopologyDifference::A
Definition: InternalNode.h:2593
openvdb::v4_0_2::Index
Index32 Index
Definition: Types.h:57
openvdb::v4_0_2::util::DenseMaskIterator
Definition: NodeMasks.h:270
openvdb::v4_0_2::tree::InternalNode::getNodeBoundingBox
CoordBBox getNodeBoundingBox() const
Return the bounding box of this node, i.e., the full index space spanned by the node regardless of it...
Definition: InternalNode.h:319
openvdb::v4_0_2::PartialCreate
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:505
openvdb::v4_0_2::tree::InternalNode::mValueMask
NodeMaskType mValueMask
Definition: InternalNode.h:837
openvdb::v4_0_2::tree::InternalNode::setValuesOn
void setValuesOn()
Mark all values (both tiles and voxels) as active.
Definition: InternalNode.h:1848
openvdb::v4_0_2::tree::InternalNode::DeepCopy::t
InternalNode * t
Definition: InternalNode.h:916
openvdb::v4_0_2::tree::InternalNode::isValueOnAndCache
bool isValueOnAndCache(const Coord &xyz, AccessorT &) const
Definition: InternalNode.h:1563
openvdb::v4_0_2::tree::InternalNode::fill
void fill(const CoordBBox &bbox, const ValueType &value, bool active=true)
Set all voxels within a given axis-aligned box to a constant value.
Definition: InternalNode.h:2026
openvdb::v4_0_2::tree::InternalNode::ChildOn
Definition: InternalNode.h:149
openvdb::v4_0_2::tree::InternalNode::coordToOffset
static Index coordToOffset(const Coord &xyz)
Return the linear table offset of the given global or local coordinates.
Definition: InternalNode.h:3098
openvdb::v4_0_2::tree::InternalNode::addLeafAndCache
void addLeafAndCache(LeafNodeType *leaf, AccessorT &)
Same as addLeaf() except, if necessary, update the accessor with pointers to the nodes along the path...
Definition: InternalNode.h:1347
openvdb::v4_0_2::tree::InternalNode::isValueOn
bool isValueOn(Index offset) const
Return true if the voxel at the given offset is active.
Definition: InternalNode.h:355
openvdb::v4_0_2::tree::InternalNode::DeepCopy::operator()
void operator()(const tbb::blocked_range< Index > &r) const
Definition: InternalNode.h:906
openvdb::v4_0_2::tree::InternalNode::getFirstValue
const ValueType & getFirstValue() const
If the first entry in this node&#39;s table is a tile, return the tile&#39;s value. Otherwise, return the result of calling getFirstValue() on the child.
Definition: InternalNode.h:2270
openvdb::v4_0_2::tree::InternalNode::evalActiveBoundingBox
void evalActiveBoundingBox(CoordBBox &bbox, bool visitVoxels=true) const
Expand the specified bounding box so that it includes the active tiles of this internal node as well ...
Definition: InternalNode.h:1128
openvdb::v4_0_2::tree::InternalNode::ValueIter::setItem
void setItem(Index pos, const ValueT &v) const
Definition: InternalNode.h:187
openvdb::v4_0_2::tree::InternalNode::TopologyCopy1::b
const ValueType & b
Definition: InternalNode.h:963
openvdb::v4_0_2::tree::InternalNode::TopologyUnion
Definition: InternalNode.h:831
openvdb::v4_0_2::tree::InternalNode::dim
static Index dim()
Definition: InternalNode.h:275
openvdb::v4_0_2::tree::InternalNode::getValueMask
const NodeMaskType & getValueMask() const
Definition: InternalNode.h:784
openvdb::v4_0_2::tree::InternalNode::isValueOn
bool isValueOn(const Coord &xyz) const
Return true if the voxel at the given coordinates is active.
Definition: InternalNode.h:1553
openvdb::v4_0_2::tree::InternalNode::probeLeaf
LeafNodeType * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, return nullptr.
Definition: InternalNode.h:1272
openvdb::v4_0_2::tree::InternalNode::copyToDense
void copyToDense(const CoordBBox &bbox, DenseT &dense) const
Copy into a dense grid the values of the voxels that lie within a given bounding box.
Definition: InternalNode.h:2130
openvdb::v4_0_2::tree::InternalNode::topologyUnion
void topologyUnion(const InternalNode< OtherChildNodeType, Log2Dim > &other)
Union this branch&#39;s set of active values with the other branch&#39;s active values. The value type of the...
openvdb::v4_0_2::tree::InternalNode::merge
void merge(InternalNode &other, const ValueType &background, const ValueType &otherBackground)
Efficiently merge another tree into this tree using one of several schemes.
Definition: InternalNode.h:2355
openvdb::v4_0_2::tree::InternalNode::getValueOffMask
NodeMaskType getValueOffMask() const
Definition: InternalNode.h:786
openvdb::v4_0_2::MERGE_ACTIVE_STATES
Definition: Types.h:316
openvdb::v4_0_2::tools::composite::max
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:133
openvdb::v4_0_2::io::writeCompressedValues
void writeCompressedValues(std::ostream &os, ValueT *srcBuf, Index srcCount, const MaskT &valueMask, const MaskT &childMask, bool toHalf)
Definition: Compression.h:462
openvdb::v4_0_2::tree::InternalNode::modifyValue
void modifyValue(const Coord &xyz, const ModifyOp &op)
Apply a functor to the value of the voxel at the given coordinates and mark the voxel as active...
Definition: InternalNode.h:1860
openvdb::v4_0_2::tree::InternalNode::TopologyDifference::B::operator()
void operator()(W &tV, const W &sC, const W &sV, const W &tC) const
Definition: InternalNode.h:2596
openvdb::v4_0_2::tree::InternalNode::modifyValueAndActiveStateAndCache
void modifyValueAndActiveStateAndCache(const Coord &xyz, const ModifyOp &op, AccessorT &)
Definition: InternalNode.h:1945
openvdb::v4_0_2::tree::InternalNode::TopologyUnion::W
typename NodeMaskType::Word W
Definition: InternalNode.h:2496
openvdb::v4_0_2::tree::InternalNode::getTable
const UnionType * getTable() const
Definition: InternalNode.h:793
openvdb::v4_0_2::tools::composite::min
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:129
openvdb::v4_0_2::tree::InternalNode::ValueType
typename ChildNodeType::ValueType ValueType
Definition: InternalNode.h:65
openvdb::v4_0_2::tree::InternalNode::ChildIter::setItem
void setItem(Index pos, const ChildT &c) const
Definition: InternalNode.h:170
openvdb::v4_0_2::CombineArgs::result
const AValueType & result() const
Get the output value.
Definition: Types.h:416
openvdb::v4_0_2::tree::InternalNode::isChildMaskOn
bool isChildMaskOn(Index n) const
Definition: InternalNode.h:781
openvdb::v4_0_2::tree::InternalNode::TopologyCopy2
Definition: InternalNode.h:830
openvdb::v4_0_2::Index64
uint64_t Index64
Definition: Types.h:56
openvdb::v4_0_2::tree::InternalNode::TopologyIntersection
Definition: InternalNode.h:833
openvdb::v4_0_2::tree::InternalNode::TopologyCopy2::onV
const ValueType & onV
Definition: InternalNode.h:999
openvdb::v4_0_2::tree::InternalNode::UnionType
NodeUnion< ValueType, ChildNodeType > UnionType
Definition: InternalNode.h:67
openvdb::v4_0_2::tree::InternalNode::getChildDim
static Index getChildDim()
Definition: InternalNode.h:285
openvdb::v4_0_2::tools::prune
void prune(TreeT &tree, typename TreeT::ValueType tolerance=zeroVal< typename TreeT::ValueType >(), bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing with tiles any nodes whose values are all the same...
Definition: Prune.h:361
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
Definition: version.h:43
openvdb::v4_0_2::util::NodeMask::toggle
void toggle(Index32 n)
Toggle the state of the nth bit.
Definition: NodeMasks.h:483
openvdb::v4_0_2::tree::InternalNode::setValueOnlyAndCache
void setValueOnlyAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
Definition: InternalNode.h:1785
openvdb::v4_0_2::tree::InternalNode::TopologyDifference::A::operator()
void operator()(W &tC, const W &sC, const W &sV, const W &tV) const
Definition: InternalNode.h:2593
openvdb::v4_0_2::tree::InternalNode::isValueMaskOn
bool isValueMaskOn(Index n) const
Definition: InternalNode.h:777
openvdb::v4_0_2::math::CoordBBox::translate
void translate(const Coord &t)
Translate this bounding box by .
Definition: Coord.h:458
openvdb::v4_0_2::tree::InternalNode::isChildMaskOff
bool isChildMaskOff() const
Definition: InternalNode.h:783
openvdb::v4_0_2::tree::InternalNode::cbeginChildOn
ChildOnCIter cbeginChildOn() const
Definition: InternalNode.h:249
openvdb::v4_0_2::tree::InternalNode::probeConstLeaf
const LeafNodeType * probeConstLeaf(const Coord &xyz) const
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, return nullptr.
Definition: InternalNode.h:1298
openvdb::v4_0_2::math::negative
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:108
openvdb::v4_0_2::tree::InternalNode::readTopology
void readTopology(std::istream &, bool fromHalf=false)
Definition: InternalNode.h:2200
openvdb::v4_0_2::tree::InternalNode::memUsage
Index64 memUsage() const
Return the total amount of memory in bytes occupied by this node and its children.
Definition: InternalNode.h:1115
openvdb::v4_0_2::tree::InternalNode::cbeginValueAll
ValueAllCIter cbeginValueAll() const
Definition: InternalNode.h:262
openvdb::v4_0_2::tree::InternalNode::onTileCount
Index64 onTileCount() const
Definition: InternalNode.h:1104
openvdb::v4_0_2::tree::InternalNode::TopologyUnion::operator()
void operator()(const tbb::blocked_range< Index > &r) const
Definition: InternalNode.h:2510
openvdb::v4_0_2::tree::InternalNode::DeepCopy
Definition: InternalNode.h:828
openvdb::v4_0_2::tree::InternalNode::BuildType
typename ChildNodeType::BuildType BuildType
Definition: InternalNode.h:66
openvdb::v4_0_2::tree::InternalNode::MaskOffIterator
typename NodeMaskType::OffIterator MaskOffIterator
Definition: InternalNode.h:144
openvdb::v4_0_2::tree::InternalNode::getValueLevelAndCache
Index getValueLevelAndCache(const Coord &xyz, AccessorT &) const
Return the level of the tree (0 = leaf) at which the value at the given coordinates resides...
Definition: InternalNode.h:1606
openvdb::v4_0_2::tree::InternalNode::probeConstNodeAndCache
const NodeType * probeConstNodeAndCache(const Coord &xyz, AccessorT &) const
Same as probeNode() except, if necessary, update the accessor with pointers to the nodes along the pa...
openvdb::v4_0_2::tree::InternalNode::TopologyDifference::B
Definition: InternalNode.h:2596
openvdb::v4_0_2::tree::InternalNode::probeValueAndCache
bool probeValueAndCache(const Coord &xyz, ValueType &value, AccessorT &) const
Definition: InternalNode.h:1632
openvdb::v4_0_2::tree::InternalNode::TopologyIntersection::s
const OtherInternalNode * s
Definition: InternalNode.h:2574
openvdb::v4_0_2::io::readCompressedValues
void readCompressedValues(std::istream &is, ValueT *destBuf, Index destCount, const MaskT &valueMask, bool fromHalf)
Definition: Compression.h:339
openvdb::v4_0_2::tree::InternalNode::TopologyUnion::t
InternalNode * t
Definition: InternalNode.h:2527
openvdb::v4_0_2::tree::InternalNode::beginChildAll
ChildAllCIter beginChildAll() const
Definition: InternalNode.h:254
openvdb::v4_0_2::tree::InternalNode::leafCount
Index32 leafCount() const
Definition: InternalNode.h:1031
openvdb::v4_0_2::tree::InternalNode::SameConfiguration
SameConfiguration<OtherNodeType>::value is true if and only if OtherNodeType is the type of an Intern...
Definition: InternalNode.h:91
openvdb::v4_0_2::tree::InternalNode::voxelizeActiveTiles
void voxelizeActiveTiles(bool threaded=true)
Densify active tiles, i.e., replace them with leaf-level active voxels.
Definition: InternalNode.h:2334
openvdb::v4_0_2::math::Coord::max
static Coord max()
Return the largest possible coordinate.
Definition: Coord.h:70
openvdb::v4_0_2::tree::NodeUnion< ValueType, ChildNodeType >
openvdb::v4_0_2::tree::InternalNode::doVisit
static void doVisit(NodeT &, VisitorOp &)
Definition: InternalNode.h:2902
openvdb::v4_0_2::tree::InternalNode::resetBackground
void resetBackground(const ValueType &oldBackground, const ValueType &newBackground)
Change inactive tiles or voxels with value oldBackground to newBackground or -oldBackground to -newBa...
Definition: InternalNode.h:3194
openvdb::v4_0_2::util::NodeMask::save
void save(std::ostream &os) const
Definition: NodeMasks.h:565
openvdb::v4_0_2::math::CoordBBox::isInside
bool isInside(const Coord &xyz) const
Return true if point (x, y, z) is inside this bounding box.
Definition: Coord.h:401
openvdb
Definition: Exceptions.h:39
openvdb::v4_0_2::math::Coord::setX
Coord & setX(Int32 x)
Definition: Coord.h:103
openvdb::v4_0_2::tree::InternalNode::isInactive
bool isInactive() const
Return true if this node has no children and only contains inactive values.
Definition: InternalNode.h:350
openvdb::v4_0_2::tree::InternalNode::hasSameTopology
bool hasSameTopology(const InternalNode< OtherChildNodeType, OtherLog2Dim > *other) const
Return true if the given tree branch has the same node and active value topology as this tree branch ...
Definition: InternalNode.h:3214
openvdb::v4_0_2::tree::InternalNode::beginValueOff
ValueOffIter beginValueOff()
Definition: InternalNode.h:269
openvdb::v4_0_2::tree::InternalNode::TopologyCopy1::t
InternalNode * t
Definition: InternalNode.h:962
openvdb::v4_0_2::math::Coord::minComponent
void minComponent(const Coord &other)
Perform a component-wise minimum with the other Coord.
Definition: Coord.h:199
openvdb::v4_0_2::tree::InternalNode::ValueIter::ValueIter
ValueIter()
Definition: InternalNode.h:180
openvdb::v4_0_2::OPENVDB_FILE_VERSION_NODE_MASK_COMPRESSION
Definition: version.h:110
openvdb::v4_0_2::tree::InternalNode::isConstant
bool isConstant(ValueType &firstValue, bool &state, const ValueType &tolerance=zeroVal< ValueType >()) const
Definition: InternalNode.h:1491
OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition: Platform.h:129
openvdb::v4_0_2::tree::InternalNode::visit
void visit(VisitorOp &)
Definition: InternalNode.h:2884
openvdb::v4_0_2::util::NodeMask::countOn
Index32 countOn() const
Return the total number of on bits.
Definition: NodeMasks.h:443
openvdb::v4_0_2::math::CoordBBox::max
const Coord & max() const
Definition: Coord.h:335
openvdb::v4_0_2::tree::InternalNode::DenseIter::unsetItem
void unsetItem(Index pos, const ValueT &value) const
Definition: InternalNode.h:227
openvdb::v4_0_2::util::OffMaskIterator
Definition: NodeMasks.h:239
openvdb::v4_0_2::tree::InternalNode::cbeginValueOn
ValueOnCIter cbeginValueOn() const
Definition: InternalNode.h:259
openvdb::v4_0_2::tree::InternalNode::ValueIter
Definition: InternalNode.h:177
openvdb::v4_0_2::CombineArgs::resultIsActive
bool resultIsActive() const
Definition: Types.h:435
openvdb::v4_0_2::tree::InternalNode::DenseIter::getItem
bool getItem(Index pos, ChildT *&child, NonConstValueT &value) const
Definition: InternalNode.h:209
openvdb::v4_0_2::CombineArgs
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:371
openvdb::v4_0_2::OPENVDB_FILE_VERSION_INTERNALNODE_COMPRESSION
Definition: version.h:101
openvdb::v4_0_2::tree::InternalNode::MaskOnIterator
typename NodeMaskType::OnIterator MaskOnIterator
Definition: InternalNode.h:143
openvdb::v4_0_2::tree::InternalNode::ValueOn
Definition: InternalNode.h:148
openvdb::v4_0_2::tree::InternalNode::clip
void clip(const CoordBBox &, const ValueType &background)
Set all voxels that lie outside the given axis-aligned box to the background.
Definition: InternalNode.h:1976
openvdb::v4_0_2::tree::InternalNode::ValueIter::ValueIter
ValueIter(const MaskIterT &iter, NodeT *parent)
Definition: InternalNode.h:181
openvdb::v4_0_2::tree::InternalNode::setValueOnly
void setValueOnly(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates but don&#39;t change its active state.
Definition: InternalNode.h:1768
openvdb::v4_0_2::tree::InternalNode::TopologyCopy1
Definition: InternalNode.h:829
openvdb::v4_0_2::tree::InternalNode::~InternalNode
virtual ~InternalNode()
Definition: InternalNode.h:1018
openvdb::v4_0_2::tree::InternalNode::ValueOff
Definition: InternalNode.h:148
openvdb::v4_0_2::tree::InternalNode::setActiveStateAndCache
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &)
Definition: InternalNode.h:1825
openvdb::v4_0_2::tree::InternalNode::setValueOn
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don&#39;t change its value.
Definition: InternalNode.h:1663
openvdb::v4_0_2::tree::InternalNode::topologyIntersection
void topologyIntersection(const InternalNode< OtherChildNodeType, Log2Dim > &other, const ValueType &background)
Intersects this tree&#39;s set of active values with the active values of the other tree, whose ValueType may be different.
openvdb::v4_0_2::tree::InternalNode::TopologyDifference::W
typename NodeMaskType::Word W
Definition: InternalNode.h:2592
openvdb::v4_0_2::tree::InternalNode::DenseIter::NonConstValueT
typename BaseT::NonConstValueType NonConstValueT
Definition: InternalNode.h:203
openvdb::v4_0_2::io::getFormatVersion
OPENVDB_API uint32_t getFormatVersion(std::ios_base &)
Return the file format version number associated with the given input stream.
openvdb::v4_0_2::tree::InternalNode::writeTopology
void writeTopology(std::ostream &, bool toHalf=false) const
Definition: InternalNode.h:2175
openvdb::v4_0_2::tree::InternalNode::beginValueOn
ValueOnIter beginValueOn()
Definition: InternalNode.h:267
openvdb::v4_0_2::CombineArgs::setARef
CombineArgs & setARef(const AValueType &a)
Redirect the A value to a new external source.
Definition: Types.h:424
openvdb::v4_0_2::tree::InternalNode::DenseIter::setItem
void setItem(Index pos, ChildT *child) const
Definition: InternalNode.h:221
version.h
openvdb::v4_0_2::tree::InternalNode::combine2
void combine2(const InternalNode &other0, const OtherNodeType &other1, CombineOp &)
Definition: InternalNode.h:2742
openvdb::v4_0_2::MERGE_ACTIVE_STATES_AND_NODES
Definition: Types.h:318
openvdb::v4_0_2::tree::InternalNode::doVisit2
static void doVisit2(NodeT &, OtherChildAllIterT &, VisitorOp &, bool otherIsLHS)
Definition: InternalNode.h:3007
openvdb::v4_0_2::tree::InternalNode::offVoxelCount
Index64 offVoxelCount() const
Definition: InternalNode.h:1069
openvdb::v4_0_2::tree::InternalNode::beginValueAll
ValueAllIter beginValueAll()
Definition: InternalNode.h:270
openvdb::v4_0_2::tree::InternalNode::unsetChildNode
ChildNodeType * unsetChildNode(Index i, const ValueType &value)
Definition: InternalNode.h:3254
openvdb::v4_0_2::math::CoordBBox::createCube
static CoordBBox createCube(const Coord &min, ValueType dim)
Definition: Coord.h:326
openvdb::v4_0_2::tree::InternalNode::TopologyIntersection::W
typename NodeMaskType::Word W
Definition: InternalNode.h:2542
openvdb::v4_0_2::tree::InternalNode::denseFill
void denseFill(const CoordBBox &bbox, const ValueType &value, bool active=true)
Set all voxels within a given axis-aligned box to a constant value and ensure that those voxels are a...
Definition: InternalNode.h:2082
openvdb::v4_0_2::tree::InternalNode::visit2
void visit2(IterT &otherIter, VisitorOp &, bool otherIsLHS=false)
openvdb::v4_0_2::tree::InternalNode::combine
void combine(InternalNode &other, CombineOp &)
Definition: InternalNode.h:2655
openvdb::v4_0_2::tree::InternalNode::addTileAndCache
void addTileAndCache(Index level, const Coord &xyz, const ValueType &, bool state, AccessorT &)
Same as addTile() except, if necessary, update the accessor with pointers to the nodes along the path...
Definition: InternalNode.h:1422
openvdb::v4_0_2::tree::InternalNode::TopologyCopy1::TopologyCopy1
TopologyCopy1(const OtherInternalNode *source, InternalNode *target, const ValueType &background)
Definition: InternalNode.h:946
openvdb::v4_0_2::tree::InternalNode::VoxelizeActiveTiles::VoxelizeActiveTiles
VoxelizeActiveTiles(InternalNode &node)
Definition: InternalNode.h:2309
openvdb::v4_0_2::util::NodeMask::countOff
Index32 countOff() const
Return the total number of on bits.
Definition: NodeMasks.h:450
openvdb::v4_0_2::tree::InternalNode::probeConstLeafAndCache
const LeafNodeType * probeConstLeafAndCache(const Coord &xyz, AccessorT &acc) const
Same as probeLeaf() except, if necessary, update the accessor with pointers to the nodes along the pa...
openvdb::v4_0_2::math::Coord::x
Int32 x() const
Definition: Coord.h:154
openvdb::v4_0_2::tree::InternalNode::ValueAll
Definition: InternalNode.h:148
openvdb::v4_0_2::tree::InternalNode::beginChildOff
ChildOffCIter beginChildOff() const
Definition: InternalNode.h:253
openvdb::v4_0_2::tree::InternalNode::beginValueOn
ValueOnCIter beginValueOn() const
Definition: InternalNode.h:263
OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:130
openvdb::v4_0_2::util::OnMaskIterator
Definition: NodeMasks.h:208
openvdb::v4_0_2::tree::InternalNode::probeNode
NodeType * probeNode(const Coord &xyz)
Return a pointer to the node that contains voxel (x, y, z). If no such node exists, return nullptr.
openvdb::v4_0_2::tree::InternalNode::TopologyIntersection::t
InternalNode * t
Definition: InternalNode.h:2575
openvdb::v4_0_2::tree::InternalNode::beginValueOff
ValueOffCIter beginValueOff() const
Definition: InternalNode.h:265
openvdb::v4_0_2::tree::InternalNode::TopologyIntersection::TopologyIntersection
TopologyIntersection(const OtherInternalNode *source, InternalNode *target, const ValueType &background)
Definition: InternalNode.h:2546
NodeUnion.h
openvdb::v4_0_2::tree::InternalNode::DeepCopy::DeepCopy
DeepCopy(const OtherInternalNode *source, InternalNode *target)
Definition: InternalNode.h:902
openvdb::v4_0_2::util::NodeMask::Word
Index64 Word
Definition: NodeMasks.h:316
openvdb::v4_0_2::util::NodeMask::isConstant
bool isConstant(bool &isOn) const
Definition: NodeMasks.h:526
openvdb::v4_0_2::tree::InternalNode::getChildNode
ChildNodeType * getChildNode(Index n)
Returns a pointer to the child node at the linear offset n.
Definition: InternalNode.h:3276
openvdb::v4_0_2::tree::InternalNode::getNodeLog2Dims
static void getNodeLog2Dims(std::vector< Index > &dims)
Populated an stil::vector with the dimension of all the nodes in the branch starting with this node...
Definition: InternalNode.h:3077
openvdb::v4_0_2::tree::InternalNode::beginValueAll
ValueAllCIter beginValueAll() const
Definition: InternalNode.h:266
openvdb::v4_0_2::tree::InternalNode::TopologyCopy1::operator()
void operator()(const tbb::blocked_range< Index > &r) const
Definition: InternalNode.h:951
openvdb::v4_0_2::tree::InternalNode::TopologyIntersection::b
const ValueType & b
Definition: InternalNode.h:2576
openvdb::v4_0_2::tree::InternalNode::offLeafVoxelCount
Index64 offLeafVoxelCount() const
Definition: InternalNode.h:1093
openvdb::v4_0_2::tree::InternalNode::DenseIter::DenseIter
DenseIter(const MaskDenseIterator &iter, NodeT *parent)
Definition: InternalNode.h:206
Iterator.h
openvdb::v4_0_2::tree::InternalNode::ValueIter::getItem
const ValueT & getItem(Index pos) const
Definition: InternalNode.h:184
openvdb::v4_0_2::tree::InternalNode::isValueMaskOff
bool isValueMaskOff() const
Definition: InternalNode.h:780
openvdb::v4_0_2::util::NodeMask::set
void set(Index32 n, bool On)
Set the nth bit to the specified state.
Definition: NodeMasks.h:462
openvdb::v4_0_2::tree::InternalNode::InternalNode
InternalNode()
Default constructor.
Definition: InternalNode.h:99
openvdb::v4_0_2::TopologyCopy
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:503
openvdb::v4_0_2::math::Coord
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:48
openvdb::v4_0_2::tree::InternalNode::ChildOff
Definition: InternalNode.h:149
openvdb::v4_0_2::tree::InternalNode::negate
void negate()
Change the sign of all the values represented in this node and its child nodes.
Definition: InternalNode.h:2290
openvdb::v4_0_2::tree::InternalNode::getLastValue
const ValueType & getLastValue() const
If the last entry in this node&#39;s table is a tile, return the tile&#39;s value. Otherwise, return the result of calling getLastValue() on the child.
Definition: InternalNode.h:2278
openvdb::v4_0_2::util::NodeMask::memUsage
static Index32 memUsage()
Return the byte size of this NodeMask.
Definition: NodeMasks.h:441
openvdb::v4_0_2::tree::InternalNode::getValueAndCache
const ValueType & getValueAndCache(const Coord &xyz, AccessorT &) const
openvdb::v4_0_2::Int32
int32_t Int32
Definition: Types.h:59
openvdb::v4_0_2::tree::InternalNode::NUM_VALUES
static const Index NUM_VALUES
Definition: InternalNode.h:74
openvdb::v4_0_2::tree::InternalNode::offsetToLocalCoord
static void offsetToLocalCoord(Index n, Coord &xyz)
Return the local coordinates for a linear table offset, where offset 0 has coordinates (0...
Definition: InternalNode.h:3086
openvdb::v4_0_2::util::NodeMask
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation. ...
Definition: NodeMasks.h:307
openvdb::v4_0_2::tree::InternalNode::VoxelizeActiveTiles::mNode
InternalNode * mNode
Definition: InternalNode.h:2329
openvdb::v4_0_2::tree::InternalNode::VoxelizeActiveTiles::operator()
void operator()(const tbb::blocked_range< Index > &r) const
Definition: InternalNode.h:2316
openvdb::v4_0_2::tree::InternalNode::cbeginChildOff
ChildOffCIter cbeginChildOff() const
Definition: InternalNode.h:250
NodeMasks.h
openvdb::v4_0_2::tools::copyToDense
void copyToDense(const GridOrTreeT &sparse, DenseT &dense, bool serial=false)
Populate a dense grid with the values of voxels from a sparse grid, where the sparse grid intersects ...
Definition: Dense.h:445
openvdb::v4_0_2::tree::InternalNode::isValueMaskOn
bool isValueMaskOn() const
Definition: InternalNode.h:778
openvdb::v4_0_2::tree::NodeUnion::setValue
void setValue(const ValueT &val)
Definition: NodeUnion.h:73
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
openvdb::v4_0_2::tree::InternalNode::TopologyCopy2::s
const OtherInternalNode * s
Definition: InternalNode.h:997
openvdb::v4_0_2::tree::InternalNode::ChildIter::ChildIter
ChildIter(const MaskIterT &iter, NodeT *parent)
Definition: InternalNode.h:160
openvdb::v4_0_2::tree::InternalNode::TopologyIntersection::operator()
void operator()(const tbb::blocked_range< Index > &r) const
Definition: InternalNode.h:2558
openvdb::v4_0_2::tree::InternalNode::TopologyUnion::s
const OtherInternalNode * s
Definition: InternalNode.h:2526
openvdb::v4_0_2::tree::InternalNode::onVoxelCount
Index64 onVoxelCount() const
Definition: InternalNode.h:1057
openvdb::v4_0_2::math::Coord::setY
Coord & setY(Int32 y)
Definition: Coord.h:104
openvdb::v4_0_2::tree::InternalNode::setValueAndCache
void setValueAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
Definition: InternalNode.h:1744
openvdb::v4_0_2::tree::InternalNode::beginChildOn
ChildOnCIter beginChildOn() const
Definition: InternalNode.h:252
openvdb::v4_0_2::tree::InternalNode::stealNode
NodeT * stealNode(const Coord &xyz, const ValueType &value, bool state)
Return a pointer to the node of type NodeT that contains voxel (x, y, z) and replace it with a tile o...
Definition: InternalNode.h:1170
openvdb::v4_0_2::util::NodeMask::load
void load(std::istream &is)
Definition: NodeMasks.h:569
openvdb::v4_0_2::math::Coord::lessThan
static bool lessThan(const Coord &a, const Coord &b)
Definition: Coord.h:232
openvdb::v4_0_2::math::CoordBBox::min
const Coord & min() const
Definition: Coord.h:334
openvdb::v4_0_2::util::NodeMask::isOff
bool isOff(Index32 n) const
Return true if the nth bit is off.
Definition: NodeMasks.h:508
openvdb::v4_0_2::tree::InternalNode::getLevel
static Index getLevel()
Definition: InternalNode.h:278
openvdb::v4_0_2::tree::InternalNode::makeChildNodeEmpty
void makeChildNodeEmpty(Index n, const ValueType &value)
Definition: InternalNode.h:3269
openvdb::v4_0_2::tree::InternalNode::setChildNode
void setChildNode(Index i, ChildNodeType *child)
Definition: InternalNode.h:3242
openvdb::v4_0_2::tree::InternalNode::offsetToGlobalCoord
Coord offsetToGlobalCoord(Index n) const
Return the global coordinates for a linear table offset.
Definition: InternalNode.h:3108
openvdb::v4_0_2::tree::InternalNode::visit2Node
void visit2Node(OtherNodeType &other, VisitorOp &)
Definition: InternalNode.h:2920
openvdb::v4_0_2::tree::NodeUnion::getChild
ChildT * getChild() const
Definition: NodeUnion.h:68
openvdb::v4_0_2::tree::InternalNode::setOrigin
void setOrigin(const Coord &origin)
Set the grid index coordinates of this node&#39;s local origin.
Definition: InternalNode.h:298
openvdb::v4_0_2::tree::InternalNode::TopologyIntersection::A
Definition: InternalNode.h:2543
openvdb::v4_0_2::tree::InternalNode::getNodes
void getNodes(ArrayT &array)
Adds all nodes of a certain type to a container with the following API:
Definition: InternalNode.h:3123
openvdb::v4_0_2::tree::InternalNode::TopologyUnion::A::operator()
void operator()(W &tV, const W &sV, const W &tC) const
Definition: InternalNode.h:2497
openvdb::v4_0_2::tree::InternalNode
Definition: InternalNode.h:60
openvdb::v4_0_2::util::NodeMask::setOff
void setOff(Index32 n)
Set the nth bit off.
Definition: NodeMasks.h:457
openvdb::v4_0_2::math::CoordBBox::hasOverlap
bool hasOverlap(const CoordBBox &b) const
Return true if the given bounding box overlaps with this bounding box.
Definition: Coord.h:413
openvdb::v4_0_2::tree::InternalNode::MaskDenseIterator
typename NodeMaskType::DenseIterator MaskDenseIterator
Definition: InternalNode.h:145
openvdb::v4_0_2::tree::InternalNode::setActiveState
void setActiveState(const Coord &xyz, bool on)
Set the active state of the voxel at the given coordinates but don&#39;t change its value.
Definition: InternalNode.h:1806
openvdb::v4_0_2::util::NodeMask::setOn
void setOn(Index32 n)
Set the nth bit on.
Definition: NodeMasks.h:452
openvdb::v4_0_2::tree::InternalNode::writeBuffers
void writeBuffers(std::ostream &, bool toHalf=false) const
Definition: InternalNode.h:3032
openvdb::v4_0_2::tree::InternalNode::ChildIter
Definition: InternalNode.h:156
openvdb::v4_0_2::tree::DenseIteratorBase::NonConstValueType
boost::remove_const< UnsetItemT >::type NonConstValueType
Definition: Iterator.h:212
openvdb::v4_0_2::tree::InternalNode::LeafNodeType
typename ChildNodeType::LeafNodeType LeafNodeType
Definition: InternalNode.h:64
openvdb::v4_0_2::tree::InternalNode::visitActiveBBox
void visitActiveBBox(BBoxOp &) const
Calls the templated functor BBoxOp with bounding box information for all active tiles and leaf nodes ...
Definition: InternalNode.h:2858
openvdb::v4_0_2::tree::InternalNode::origin
const Coord & origin() const
Return the grid index coordinates of this node&#39;s local origin.
Definition: InternalNode.h:296
openvdb::v4_0_2::tree::InternalNode::TopologyCopy2::t
InternalNode * t
Definition: InternalNode.h:998
openvdb::v4_0_2::tree::InternalNode::mOrigin
Coord mOrigin
Global grid index coordinates (x,y,z) of the local origin of this node.
Definition: InternalNode.h:839
openvdb::v4_0_2::tree::DenseIteratorBase
Base class for dense iterators over internal and leaf nodes.
Definition: Iterator.h:206
openvdb::v4_0_2::tree::InternalNode::LEVEL
static const Index LEVEL
Definition: InternalNode.h:75
openvdb::v4_0_2::tree::InternalNode::getValue
const ValueType & getValue(const Coord &xyz) const
Definition: InternalNode.h:1574
openvdb::v4_0_2::tree::InternalNode::isChildMaskOff
bool isChildMaskOff(Index n) const
Definition: InternalNode.h:782
Platform.h
openvdb::v4_0_2::tree::SameInternalConfig
Definition: InternalNode.h:56
openvdb::v4_0_2::tree::InternalNode::DeepCopy::s
const OtherInternalNode * s
Definition: InternalNode.h:915
openvdb::v4_0_2::tree::InternalNode::addTile
void addTile(Index level, const Coord &xyz, const ValueType &value, bool state)
Add a tile at the specified tree level that contains voxel (x, y, z), possibly creating a parent bran...
Definition: InternalNode.h:1390