OpenVDB: InternalNode.h Source File

OpenVDB 5.2.0

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