GCC Code Coverage Report


Directory: ./
File: openvdb/openvdb/tree/InternalNode.h
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 721 793 90.9%
Functions: 3127 5597 55.9%
Branches: 806 2265 35.6%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 //
4 /// @file InternalNode.h
5 ///
6 /// @brief Internal table nodes for OpenVDB trees
7
8 #ifndef OPENVDB_TREE_INTERNALNODE_HAS_BEEN_INCLUDED
9 #define OPENVDB_TREE_INTERNALNODE_HAS_BEEN_INCLUDED
10
11 #include <openvdb/Platform.h>
12 #include <openvdb/util/NodeMasks.h>
13 #include <openvdb/io/Compression.h> // for io::readCompressedValues(), etc.
14 #include <openvdb/math/Math.h> // for math::isExactlyEqual(), etc.
15 #include <openvdb/version.h>
16 #include <openvdb/Types.h>
17 #include "Iterator.h"
18 #include "NodeUnion.h"
19 #include <tbb/parallel_for.h>
20 #include <memory>
21 #include <type_traits>
22
23
24 namespace openvdb {
25 OPENVDB_USE_VERSION_NAMESPACE
26 namespace OPENVDB_VERSION_NAME {
27 namespace tree {
28
29 template<typename, Index, typename> struct SameInternalConfig; // forward declaration
30
31
32 template<typename _ChildNodeType, Index Log2Dim>
33 class InternalNode
34 {
35 public:
36 using ChildNodeType = _ChildNodeType;
37 using LeafNodeType = typename ChildNodeType::LeafNodeType;
38 using ValueType = typename ChildNodeType::ValueType;
39 using BuildType = typename ChildNodeType::BuildType;
40 using UnionType = NodeUnion<ValueType, ChildNodeType>;
41 using NodeMaskType = util::NodeMask<Log2Dim>;
42
43 static const Index
44 LOG2DIM = Log2Dim, // log2 of tile count in one dimension
45 TOTAL = Log2Dim + ChildNodeType::TOTAL, // log2 of voxel count in one dimension
46 DIM = 1 << TOTAL, // total voxel count in one dimension
47 NUM_VALUES = 1 << (3 * Log2Dim), // total voxel count represented by this node
48 LEVEL = 1 + ChildNodeType::LEVEL; // level 0 = leaf
49 static const Index64
50 NUM_VOXELS = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node
51
52 /// @brief ValueConverter<T>::Type is the type of an InternalNode having the same
53 /// child hierarchy and dimensions as this node but a different value type, T.
54 template<typename OtherValueType>
55 struct ValueConverter {
56 using Type = InternalNode<typename ChildNodeType::template ValueConverter<
57 OtherValueType>::Type, Log2Dim>;
58 };
59
60 /// @brief SameConfiguration<OtherNodeType>::value is @c true if and only if OtherNodeType
61 /// is the type of an InternalNode with the same dimensions as this node and whose
62 /// ChildNodeType has the same configuration as this node's ChildNodeType.
63 template<typename OtherNodeType>
64 struct SameConfiguration {
65 static const bool value =
66 SameInternalConfig<ChildNodeType, Log2Dim, OtherNodeType>::value;
67 };
68
69
70 /// @brief Default constructor
71 /// @warning The resulting InternalNode is uninitialized
72 InternalNode() {}
73
74 /// @brief Constructor of an InternalNode with dense inactive tiles of the specified value.
75 /// @param offValue Background value used for inactive values
76 explicit InternalNode(const ValueType& offValue);
77
78 /// @brief Constructs an InternalNode with dense tiles
79 /// @param origin The location in index space of the fist tile value
80 /// @param fillValue Value assigned to all the tiles
81 /// @param active State assigned to all the tiles
82 InternalNode(const Coord& origin, const ValueType& fillValue, bool active = false);
83
84 InternalNode(PartialCreate, const Coord&, const ValueType& fillValue, bool active = false);
85
86 /// @brief Deep copy constructor
87 ///
88 /// @note This method is multi-threaded!
89 InternalNode(const InternalNode&);
90
91 /// @brief Value conversion copy constructor
92 ///
93 /// @note This method is multi-threaded!
94 template<typename OtherChildNodeType>
95 explicit InternalNode(const InternalNode<OtherChildNodeType, Log2Dim>& other);
96
97 /// @brief Topology copy constructor
98 ///
99 /// @note This method is multi-threaded!
100 template<typename OtherChildNodeType>
101 InternalNode(const InternalNode<OtherChildNodeType, Log2Dim>& other,
102 const ValueType& background, TopologyCopy);
103
104 /// @brief Topology copy constructor
105 ///
106 /// @note This method is multi-threaded!
107 template<typename OtherChildNodeType>
108 InternalNode(const InternalNode<OtherChildNodeType, Log2Dim>& other,
109 const ValueType& offValue, const ValueType& onValue, TopologyCopy);
110
111 ~InternalNode();
112
113 protected:
114 using MaskOnIterator = typename NodeMaskType::OnIterator;
115 using MaskOffIterator = typename NodeMaskType::OffIterator;
116 using MaskDenseIterator = typename NodeMaskType::DenseIterator;
117
118 // Type tags to disambiguate template instantiations
119 struct ValueOn {}; struct ValueOff {}; struct ValueAll {};
120 struct ChildOn {}; struct ChildOff {}; struct ChildAll {};
121
122 // The following class templates implement the iterator interfaces specified in Iterator.h
123 // by providing getItem(), setItem() and/or modifyItem() methods.
124
125 // Sparse iterator that visits child nodes of an InternalNode
126 template<typename NodeT, typename ChildT, typename MaskIterT, typename TagT>
127 struct ChildIter: public SparseIteratorBase<
128 MaskIterT, ChildIter<NodeT, ChildT, MaskIterT, TagT>, NodeT, ChildT>
129 {
130 ChildIter() {}
131 ChildIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase<
132 MaskIterT, ChildIter<NodeT, ChildT, MaskIterT, TagT>, NodeT, ChildT>(iter, parent) {}
133
134 137723072 ChildT& getItem(Index pos) const
135 {
136
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 68861536 times.
275446144 assert(this->parent().isChildMaskOn(pos));
137 137723072 return *(this->parent().getChildNode(pos));
138 }
139
140 // Note: setItem() can't be called on const iterators.
141 void setItem(Index pos, const ChildT& c) const { this->parent().resetChildNode(pos, &c); }
142
143 // Note: modifyItem() isn't implemented, since it's not useful for child node pointers.
144 };// ChildIter
145
146 // Sparse iterator that visits tile values of an InternalNode
147 template<typename NodeT, typename ValueT, typename MaskIterT, typename TagT>
148 struct ValueIter: public SparseIteratorBase<
149 MaskIterT, ValueIter<NodeT, ValueT, MaskIterT, TagT>, NodeT, ValueT>
150 {
151 ValueIter() {}
152 ValueIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase<
153 MaskIterT, ValueIter<NodeT, ValueT, MaskIterT, TagT>, NodeT, ValueT>(iter, parent) {}
154
155
9/34
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✓ Branch 81 taken 1 times.
✗ Branch 82 not taken.
✓ Branch 84 taken 1 times.
✗ Branch 85 not taken.
✓ Branch 87 taken 1 times.
✗ Branch 88 not taken.
✓ Branch 90 taken 1 times.
✗ Branch 91 not taken.
✓ Branch 93 taken 1 times.
✗ Branch 94 not taken.
✓ Branch 96 taken 1 times.
✗ Branch 97 not taken.
✓ Branch 99 taken 1 times.
✗ Branch 100 not taken.
✓ Branch 102 taken 1 times.
✗ Branch 103 not taken.
✓ Branch 105 taken 1 times.
✗ Branch 106 not taken.
2073830124 const ValueT& getItem(Index pos) const { return this->parent().mNodes[pos].getValue(); }
156
157 // Note: setItem() can't be called on const iterators.
158
4/15
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 23 taken 99214 times.
✗ Branch 24 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✓ Branch 29 taken 2174 times.
✗ Branch 30 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✓ Branch 35 taken 12 times.
✗ Branch 36 not taken.
84793180 void setItem(Index pos, const ValueT& v) const { this->parent().mNodes[pos].setValue(v); }
159
160 // Note: modifyItem() can't be called on const iterators.
161 template<typename ModifyOp>
162 void modifyItem(Index pos, const ModifyOp& op) const
163 {
164 1188 op(this->parent().mNodes[pos].getValue());
165 }
166 };// ValueIter
167
168 // Dense iterator that visits both tiles and child nodes of an InternalNode
169 template<typename NodeT, typename ChildT, typename ValueT, typename TagT>
170 struct DenseIter: public DenseIteratorBase<
171 MaskDenseIterator, DenseIter<NodeT, ChildT, ValueT, TagT>, NodeT, ChildT, ValueT>
172 {
173 using BaseT = DenseIteratorBase<MaskDenseIterator, DenseIter, NodeT, ChildT, ValueT>;
174 using NonConstValueT = typename BaseT::NonConstValueType;
175
176 DenseIter() {}
177 DenseIter(const MaskDenseIterator& iter, NodeT* parent):
178 DenseIteratorBase<MaskDenseIterator, DenseIter, NodeT, ChildT, ValueT>(iter, parent) {}
179
180 4743176 bool getItem(Index pos, ChildT*& child, NonConstValueT& value) const
181 {
182
2/2
✓ Branch 1 taken 555 times.
✓ Branch 2 taken 2371033 times.
9486352 if (this->parent().isChildMaskOn(pos)) {
183 1110 child = this->parent().getChildNode(pos);
184 1110 return true;
185 }
186 4742066 child = nullptr;
187 4742066 value = this->parent().mNodes[pos].getValue();
188 4742066 return false;
189 }
190
191 // Note: setItem() can't be called on const iterators.
192 void setItem(Index pos, ChildT* child) const
193 {
194 this->parent().resetChildNode(pos, child);
195 }
196
197 // Note: unsetItem() can't be called on const iterators.
198 void unsetItem(Index pos, const ValueT& value) const
199 {
200 this->parent().unsetChildNode(pos, value);
201 }
202 };// DenseIter
203
204 public:
205 // Iterators (see Iterator.h for usage)
206 using ChildOnIter = ChildIter<InternalNode, ChildNodeType, MaskOnIterator, ChildOn>;
207 using ChildOnCIter = ChildIter<const InternalNode,const ChildNodeType,MaskOnIterator,ChildOn>;
208 using ChildOffIter = ValueIter<InternalNode, const ValueType, MaskOffIterator, ChildOff>;
209 using ChildOffCIter = ValueIter<const InternalNode,const ValueType,MaskOffIterator,ChildOff>;
210 using ChildAllIter = DenseIter<InternalNode, ChildNodeType, ValueType, ChildAll>;
211 using ChildAllCIter = DenseIter<const InternalNode,const ChildNodeType, ValueType, ChildAll>;
212
213 using ValueOnIter = ValueIter<InternalNode, const ValueType, MaskOnIterator, ValueOn>;
214 using ValueOnCIter = ValueIter<const InternalNode, const ValueType, MaskOnIterator, ValueOn>;
215 using ValueOffIter = ValueIter<InternalNode, const ValueType, MaskOffIterator, ValueOff>;
216 using ValueOffCIter = ValueIter<const InternalNode,const ValueType,MaskOffIterator,ValueOff>;
217 using ValueAllIter = ValueIter<InternalNode, const ValueType, MaskOffIterator, ValueAll>;
218 using ValueAllCIter = ValueIter<const InternalNode,const ValueType,MaskOffIterator,ValueAll>;
219
220
12/24
✓ Branch 110 taken 1 times.
✗ Branch 111 not taken.
✓ Branch 114 taken 1 times.
✗ Branch 115 not taken.
✓ Branch 118 taken 1 times.
✗ Branch 119 not taken.
✓ Branch 122 taken 1 times.
✗ Branch 123 not taken.
✓ Branch 126 taken 1 times.
✗ Branch 127 not taken.
✓ Branch 130 taken 1 times.
✗ Branch 131 not taken.
✓ Branch 134 taken 1 times.
✗ Branch 135 not taken.
✓ Branch 325 taken 1 times.
✗ Branch 326 not taken.
✓ Branch 329 taken 1 times.
✗ Branch 330 not taken.
✓ Branch 333 taken 1 times.
✗ Branch 334 not taken.
✓ Branch 337 taken 1 times.
✗ Branch 338 not taken.
✓ Branch 341 taken 1 times.
✗ Branch 342 not taken.
524713 ChildOnCIter cbeginChildOn() const { return ChildOnCIter(mChildMask.beginOn(), this); }
221 64 ChildOffCIter cbeginChildOff() const { return ChildOffCIter(mChildMask.beginOff(), this); }
222 180 ChildAllCIter cbeginChildAll() const { return ChildAllCIter(mChildMask.beginDense(), this); }
223 76956 ChildOnCIter beginChildOn() const { return cbeginChildOn(); }
224 ChildOffCIter beginChildOff() const { return cbeginChildOff(); }
225 90 ChildAllCIter beginChildAll() const { return cbeginChildAll(); }
226
1/2
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
817281 ChildOnIter beginChildOn() { return ChildOnIter(mChildMask.beginOn(), this); }
227 ChildOffIter beginChildOff() { return ChildOffIter(mChildMask.beginOff(), this); }
228 294 ChildAllIter beginChildAll() { return ChildAllIter(mChildMask.beginDense(), this); }
229
230
12/138
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 14 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 6 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✓ Branch 21 taken 8 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✓ Branch 24 taken 6 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✓ Branch 27 taken 8 times.
✓ Branch 28 taken 5 times.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✓ Branch 31 taken 5 times.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✓ Branch 48 taken 3 times.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✓ Branch 51 taken 3 times.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 72 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
✗ Branch 75 not taken.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✗ Branch 78 not taken.
✗ Branch 80 not taken.
✗ Branch 81 not taken.
✗ Branch 82 not taken.
✗ Branch 84 not taken.
✗ Branch 85 not taken.
✗ Branch 86 not taken.
✗ Branch 88 not taken.
✗ Branch 89 not taken.
✗ Branch 90 not taken.
✗ Branch 92 not taken.
✗ Branch 93 not taken.
✗ Branch 94 not taken.
✗ Branch 96 not taken.
✗ Branch 97 not taken.
✗ Branch 98 not taken.
✗ Branch 100 not taken.
✗ Branch 101 not taken.
✗ Branch 102 not taken.
✗ Branch 104 not taken.
✗ Branch 105 not taken.
✗ Branch 106 not taken.
✗ Branch 108 not taken.
✗ Branch 109 not taken.
✗ Branch 110 not taken.
✗ Branch 112 not taken.
✗ Branch 113 not taken.
✗ Branch 114 not taken.
✗ Branch 116 not taken.
✗ Branch 117 not taken.
✗ Branch 121 not taken.
✗ Branch 122 not taken.
✗ Branch 124 not taken.
✗ Branch 125 not taken.
✗ Branch 129 not taken.
✗ Branch 130 not taken.
✗ Branch 132 not taken.
✗ Branch 133 not taken.
✗ Branch 137 not taken.
✗ Branch 138 not taken.
✗ Branch 140 not taken.
✗ Branch 141 not taken.
✗ Branch 145 not taken.
✗ Branch 146 not taken.
✗ Branch 148 not taken.
✗ Branch 149 not taken.
✗ Branch 153 not taken.
✗ Branch 154 not taken.
✗ Branch 156 not taken.
✗ Branch 157 not taken.
✗ Branch 161 not taken.
✗ Branch 162 not taken.
✗ Branch 164 not taken.
✗ Branch 165 not taken.
✗ Branch 169 not taken.
✗ Branch 170 not taken.
✗ Branch 172 not taken.
✗ Branch 173 not taken.
✗ Branch 177 not taken.
✗ Branch 178 not taken.
✗ Branch 180 not taken.
✗ Branch 181 not taken.
375138 ValueOnCIter cbeginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); }
231 /// @warning This iterator will also visit child nodes so use isChildMaskOn to skip them!
232 1088 ValueOffCIter cbeginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); }
233
13/26
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 26 taken 1 times.
✗ Branch 27 not taken.
✗ Branch 29 not taken.
✓ Branch 30 taken 1 times.
✗ Branch 32 not taken.
✓ Branch 33 taken 1 times.
✓ Branch 36 taken 1 times.
✗ Branch 37 not taken.
✓ Branch 40 taken 1 times.
✗ Branch 41 not taken.
✓ Branch 44 taken 1 times.
✗ Branch 45 not taken.
✗ Branch 47 not taken.
✓ Branch 48 taken 1 times.
✗ Branch 50 not taken.
✓ Branch 51 taken 1 times.
✓ Branch 54 taken 1 times.
✗ Branch 55 not taken.
✓ Branch 58 taken 1 times.
✗ Branch 59 not taken.
✓ Branch 62 taken 1 times.
✗ Branch 63 not taken.
1872 ValueAllCIter cbeginValueAll() const { return ValueAllCIter(mChildMask.beginOff(), this); }
234 ValueOnCIter beginValueOn() const { return cbeginValueOn(); }
235 /// @warning This iterator will also visit child nodes so use isChildMaskOn to skip them!
236 ValueOffCIter beginValueOff() const { return cbeginValueOff(); }
237 182 ValueAllCIter beginValueAll() const { return cbeginValueAll(); }
238
40/80
✗ Branch 4 not taken.
✓ Branch 5 taken 102 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 68 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 156 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 104 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 171 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 114 times.
✗ Branch 28 not taken.
✓ Branch 29 taken 150 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 100 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 153 times.
✗ Branch 39 not taken.
✓ Branch 40 taken 102 times.
✗ Branch 44 not taken.
✓ Branch 45 taken 162 times.
✗ Branch 47 not taken.
✓ Branch 48 taken 108 times.
✗ Branch 52 not taken.
✓ Branch 53 taken 165 times.
✗ Branch 55 not taken.
✓ Branch 56 taken 110 times.
✗ Branch 60 not taken.
✓ Branch 61 taken 174 times.
✗ Branch 63 not taken.
✓ Branch 64 taken 116 times.
✗ Branch 68 not taken.
✓ Branch 69 taken 186 times.
✗ Branch 71 not taken.
✓ Branch 72 taken 124 times.
✗ Branch 76 not taken.
✓ Branch 77 taken 306 times.
✗ Branch 79 not taken.
✓ Branch 80 taken 204 times.
✗ Branch 84 not taken.
✓ Branch 85 taken 357 times.
✗ Branch 87 not taken.
✓ Branch 88 taken 238 times.
✗ Branch 92 not taken.
✓ Branch 93 taken 105 times.
✗ Branch 95 not taken.
✓ Branch 96 taken 70 times.
✗ Branch 100 not taken.
✓ Branch 101 taken 105 times.
✗ Branch 103 not taken.
✓ Branch 104 taken 70 times.
✗ Branch 108 not taken.
✓ Branch 109 taken 105 times.
✗ Branch 111 not taken.
✓ Branch 112 taken 70 times.
✗ Branch 116 not taken.
✓ Branch 117 taken 1302 times.
✗ Branch 119 not taken.
✓ Branch 120 taken 868 times.
✗ Branch 124 not taken.
✓ Branch 125 taken 78 times.
✗ Branch 127 not taken.
✓ Branch 128 taken 52 times.
✗ Branch 132 not taken.
✓ Branch 133 taken 765 times.
✗ Branch 135 not taken.
✓ Branch 136 taken 510 times.
✗ Branch 140 not taken.
✓ Branch 141 taken 231 times.
✗ Branch 143 not taken.
✓ Branch 144 taken 154 times.
✗ Branch 148 not taken.
✓ Branch 149 taken 757 times.
✗ Branch 151 not taken.
✓ Branch 152 taken 510 times.
✗ Branch 155 not taken.
✓ Branch 156 taken 1092 times.
✗ Branch 158 not taken.
✓ Branch 159 taken 728 times.
56615 ValueOnIter beginValueOn() { return ValueOnIter(mValueMask.beginOn(), this); }
239 /// @warning This iterator will also visit child nodes so use isChildMaskOn to skip them!
240
4/160
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✗ Branch 79 not taken.
✗ Branch 80 not taken.
✗ Branch 82 not taken.
✗ Branch 83 not taken.
✗ Branch 85 not taken.
✗ Branch 86 not taken.
✗ Branch 88 not taken.
✗ Branch 89 not taken.
✗ Branch 91 not taken.
✗ Branch 92 not taken.
✗ Branch 94 not taken.
✗ Branch 95 not taken.
✗ Branch 97 not taken.
✗ Branch 98 not taken.
✗ Branch 100 not taken.
✗ Branch 101 not taken.
✗ Branch 103 not taken.
✗ Branch 104 not taken.
✗ Branch 106 not taken.
✗ Branch 107 not taken.
✗ Branch 109 not taken.
✗ Branch 110 not taken.
✗ Branch 112 not taken.
✗ Branch 113 not taken.
✗ Branch 115 not taken.
✗ Branch 116 not taken.
✗ Branch 118 not taken.
✗ Branch 119 not taken.
✗ Branch 121 not taken.
✗ Branch 122 not taken.
✗ Branch 124 not taken.
✗ Branch 125 not taken.
✗ Branch 127 not taken.
✗ Branch 128 not taken.
✗ Branch 130 not taken.
✗ Branch 131 not taken.
✗ Branch 133 not taken.
✗ Branch 134 not taken.
✗ Branch 136 not taken.
✗ Branch 137 not taken.
✗ Branch 139 not taken.
✗ Branch 140 not taken.
✗ Branch 142 not taken.
✗ Branch 143 not taken.
✗ Branch 145 not taken.
✗ Branch 146 not taken.
✗ Branch 148 not taken.
✗ Branch 149 not taken.
✗ Branch 151 not taken.
✗ Branch 152 not taken.
✗ Branch 154 not taken.
✗ Branch 155 not taken.
✗ Branch 157 not taken.
✗ Branch 158 not taken.
✗ Branch 160 not taken.
✗ Branch 161 not taken.
✗ Branch 163 not taken.
✗ Branch 164 not taken.
✗ Branch 166 not taken.
✗ Branch 167 not taken.
✗ Branch 169 not taken.
✗ Branch 170 not taken.
✗ Branch 172 not taken.
✗ Branch 173 not taken.
✗ Branch 175 not taken.
✗ Branch 176 not taken.
✗ Branch 178 not taken.
✗ Branch 179 not taken.
✗ Branch 181 not taken.
✗ Branch 182 not taken.
✗ Branch 184 not taken.
✗ Branch 185 not taken.
✗ Branch 187 not taken.
✗ Branch 188 not taken.
✗ Branch 190 not taken.
✗ Branch 191 not taken.
✗ Branch 193 not taken.
✗ Branch 194 not taken.
✗ Branch 196 not taken.
✗ Branch 197 not taken.
✗ Branch 199 not taken.
✗ Branch 200 not taken.
✗ Branch 202 not taken.
✗ Branch 203 not taken.
✗ Branch 205 not taken.
✗ Branch 206 not taken.
✗ Branch 208 not taken.
✗ Branch 209 not taken.
✗ Branch 211 not taken.
✗ Branch 212 not taken.
✗ Branch 214 not taken.
✗ Branch 215 not taken.
✗ Branch 217 not taken.
✓ Branch 218 taken 1 times.
✗ Branch 220 not taken.
✓ Branch 221 taken 1 times.
✗ Branch 223 not taken.
✓ Branch 224 taken 1 times.
✗ Branch 226 not taken.
✓ Branch 227 taken 1 times.
✗ Branch 229 not taken.
✗ Branch 230 not taken.
✗ Branch 232 not taken.
✗ Branch 233 not taken.
✗ Branch 235 not taken.
✗ Branch 236 not taken.
✗ Branch 238 not taken.
✗ Branch 239 not taken.
931 ValueOffIter beginValueOff() { return ValueOffIter(mValueMask.beginOff(), this); }
241
0/80
✗ Branch 81 not taken.
✗ Branch 82 not taken.
✗ Branch 84 not taken.
✗ Branch 85 not taken.
✗ Branch 87 not taken.
✗ Branch 88 not taken.
✗ Branch 90 not taken.
✗ Branch 91 not taken.
✗ Branch 93 not taken.
✗ Branch 94 not taken.
✗ Branch 96 not taken.
✗ Branch 97 not taken.
✗ Branch 99 not taken.
✗ Branch 100 not taken.
✗ Branch 102 not taken.
✗ Branch 103 not taken.
✗ Branch 105 not taken.
✗ Branch 106 not taken.
✗ Branch 108 not taken.
✗ Branch 109 not taken.
✗ Branch 111 not taken.
✗ Branch 112 not taken.
✗ Branch 114 not taken.
✗ Branch 115 not taken.
✗ Branch 117 not taken.
✗ Branch 118 not taken.
✗ Branch 120 not taken.
✗ Branch 121 not taken.
✗ Branch 123 not taken.
✗ Branch 124 not taken.
✗ Branch 126 not taken.
✗ Branch 127 not taken.
✗ Branch 129 not taken.
✗ Branch 130 not taken.
✗ Branch 132 not taken.
✗ Branch 133 not taken.
✗ Branch 135 not taken.
✗ Branch 136 not taken.
✗ Branch 138 not taken.
✗ Branch 139 not taken.
✗ Branch 141 not taken.
✗ Branch 142 not taken.
✗ Branch 144 not taken.
✗ Branch 145 not taken.
✗ Branch 147 not taken.
✗ Branch 148 not taken.
✗ Branch 150 not taken.
✗ Branch 151 not taken.
✗ Branch 153 not taken.
✗ Branch 154 not taken.
✗ Branch 156 not taken.
✗ Branch 157 not taken.
✗ Branch 159 not taken.
✗ Branch 160 not taken.
✗ Branch 162 not taken.
✗ Branch 163 not taken.
✗ Branch 165 not taken.
✗ Branch 166 not taken.
✗ Branch 168 not taken.
✗ Branch 169 not taken.
✗ Branch 171 not taken.
✗ Branch 172 not taken.
✗ Branch 174 not taken.
✗ Branch 175 not taken.
✗ Branch 177 not taken.
✗ Branch 178 not taken.
✗ Branch 180 not taken.
✗ Branch 181 not taken.
✗ Branch 183 not taken.
✗ Branch 184 not taken.
✗ Branch 186 not taken.
✗ Branch 187 not taken.
✗ Branch 189 not taken.
✗ Branch 190 not taken.
✗ Branch 192 not taken.
✗ Branch 193 not taken.
✗ Branch 195 not taken.
✗ Branch 196 not taken.
✗ Branch 198 not taken.
✗ Branch 199 not taken.
12248 ValueAllIter beginValueAll() { return ValueAllIter(mChildMask.beginOff(), this); }
242
243
244 /// @return The dimension of this InternalNode
245 /// @details The number of voxels in one coordinate direction covered by this node
246 static Index dim() { return DIM; }
247 /// @return The level of this node
248 /// @details Level 0 is by definition the level of the leaf nodes
249 static Index getLevel() { return LEVEL; }
250 /// @brief Populated an std::vector with the dimension of all the
251 /// nodes in the branch starting with this node.
252 static void getNodeLog2Dims(std::vector<Index>& dims);
253 /// @return The dimension of the child nodes of this node.
254 /// @details The number of voxels in one coordinate direction
255 /// covered by a child node of this node.
256 static Index getChildDim() { return ChildNodeType::DIM; }
257
258 /// Return the linear table offset of the given global or local coordinates.
259 static Index coordToOffset(const Coord& xyz);
260 /// @brief Return the local coordinates for a linear table offset,
261 /// where offset 0 has coordinates (0, 0, 0).
262 static void offsetToLocalCoord(Index n, Coord& xyz);
263 /// Return the global coordinates for a linear table offset.
264 Coord offsetToGlobalCoord(Index n) const;
265
266 /// Return the grid index coordinates of this node's local origin.
267
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
5637 const Coord& origin() const { return mOrigin; }
268 /// Set the grid index coordinates of this node's local origin.
269
1/18
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 19 taken 8 times.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
8 void setOrigin(const Coord& origin) { mOrigin = origin; }
270
271 #if OPENVDB_ABI_VERSION_NUMBER >= 9
272 /// Return the transient data value.
273
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
3 Index32 transientData() const { return mTransientData; }
274 /// Set the transient data value.
275
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 void setTransientData(Index32 transientData) { mTransientData = transientData; }
276 #endif
277
278 Index32 leafCount() const;
279 void nodeCount(std::vector<Index32> &vec) const;
280 Index32 nonLeafCount() const;
281 Index32 childCount() const;
282 Index64 onVoxelCount() const;
283 Index64 offVoxelCount() const;
284 Index64 onLeafVoxelCount() const;
285 Index64 offLeafVoxelCount() const;
286 Index64 onTileCount() const;
287
288 /// Return the total amount of memory in bytes occupied by this node and its children.
289 Index64 memUsage() const;
290
291 /// @brief Expand the specified bounding box so that it includes the active tiles
292 /// of this internal node as well as all the active values in its child nodes.
293 /// If visitVoxels is false LeafNodes will be approximated as dense, i.e. with all
294 /// voxels active. Else the individual active voxels are visited to produce a tight bbox.
295 void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const;
296
297 /// @brief Return the bounding box of this node, i.e., the full index space
298 /// spanned by the node regardless of its content.
299 43662 CoordBBox getNodeBoundingBox() const { return CoordBBox::createCube(mOrigin, DIM); }
300
301 /// @return True if this node contains no child nodes.
302 bool isEmpty() const { return mChildMask.isOff(); }
303
304 /// Return @c true if all of this node's table entries have the same active state
305 /// and the same constant value to within the given tolerance,
306 /// and return that value in @a firstValue and the active state in @a state.
307 ///
308 /// @note This method also returns @c false if this node contains any child nodes.
309 bool isConstant(ValueType& firstValue, bool& state,
310
13/52
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 10 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 16 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 19 taken 9 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 9 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✓ Branch 27 taken 9 times.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✓ Branch 31 taken 9 times.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✓ Branch 35 taken 9 times.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✓ Branch 39 taken 9 times.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✓ Branch 43 taken 12 times.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✓ Branch 47 taken 12 times.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✓ Branch 51 taken 12 times.
136 const ValueType& tolerance = zeroVal<ValueType>()) const;
311
312 /// Return @c true if all of this node's tables entries have
313 /// the same active @a state and the range of its values satisfy
314 /// (@a maxValue - @a minValue) <= @a tolerance.
315 ///
316 /// @param minValue Is updated with the minimum of all values IF method
317 /// returns @c true. Else the value is undefined!
318 /// @param maxValue Is updated with the maximum of all values IF method
319 /// returns @c true. Else the value is undefined!
320 /// @param state Is updated with the state of all values IF method
321 /// returns @c true. Else the value is undefined!
322 /// @param tolerance The tolerance used to determine if values are
323 /// approximately constant.
324 ///
325 /// @note This method also returns @c false if this node contains any child nodes.
326 bool isConstant(ValueType& minValue, ValueType& maxValue,
327 bool& state, const ValueType& tolerance = zeroVal<ValueType>()) const;
328
329 /// Return @c true if this node has no children and only contains inactive values.
330
7/8
✓ Branch 0 taken 2942 times.
✓ Branch 1 taken 12468 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 2931 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 23 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
67483 bool isInactive() const { return this->isChildMaskOff() && this->isValueMaskOff(); }
331
332 /// Return @c true if the voxel at the given coordinates is active.
333 bool isValueOn(const Coord& xyz) const;
334 /// Return @c true if the voxel at the given offset is active.
335 19 bool isValueOn(Index offset) const { return mValueMask.isOn(offset); }
336
337 /// Return @c true if this node or any of its child nodes have any active tiles.
338 bool hasActiveTiles() const;
339
340 const ValueType& getValue(const Coord& xyz) const;
341 bool probeValue(const Coord& xyz, ValueType& value) const;
342
343 /// @brief Return the level of the tree (0 = leaf) at which the value
344 /// at the given coordinates resides.
345 Index getValueLevel(const Coord& xyz) const;
346
347 /// @brief If the first entry in this node's table is a tile, return the tile's value.
348 /// Otherwise, return the result of calling getFirstValue() on the child.
349 const ValueType& getFirstValue() const;
350 /// @brief If the last entry in this node's table is a tile, return the tile's value.
351 /// Otherwise, return the result of calling getLastValue() on the child.
352 const ValueType& getLastValue() const;
353
354 /// Set the active state of the voxel at the given coordinates but don't change its value.
355 void setActiveState(const Coord& xyz, bool on);
356 /// Set the value of the voxel at the given coordinates but don't change its active state.
357 void setValueOnly(const Coord& xyz, const ValueType& value);
358 /// Mark the voxel at the given coordinates as active but don't change its value.
359 void setValueOn(const Coord& xyz);
360 /// Set the value of the voxel at the given coordinates and mark the voxel as active.
361 void setValueOn(const Coord& xyz, const ValueType& value);
362 /// Mark the voxel at the given coordinates as inactive but don't change its value.
363 void setValueOff(const Coord& xyz);
364 /// Set the value of the voxel at the given coordinates and mark the voxel as inactive.
365 void setValueOff(const Coord& xyz, const ValueType& value);
366
367 /// @brief Apply a functor to the value of the voxel at the given coordinates
368 /// and mark the voxel as active.
369 template<typename ModifyOp>
370 void modifyValue(const Coord& xyz, const ModifyOp& op);
371 /// Apply a functor to the voxel at the given coordinates.
372 template<typename ModifyOp>
373 void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op);
374
375 /// Return the value of the voxel at the given coordinates and, if necessary, update
376 /// the accessor with pointers to the nodes along the path from the root node to
377 /// the node containing the voxel.
378 /// @note Used internally by ValueAccessor.
379 template<typename AccessorT>
380 const ValueType& getValueAndCache(const Coord& xyz, AccessorT&) const;
381
382 /// Return @c true if the voxel at the given coordinates is active and, if necessary,
383 /// update the accessor with pointers to the nodes along the path from the root node
384 /// to the node containing the voxel.
385 /// @note Used internally by ValueAccessor.
386 template<typename AccessorT>
387 bool isValueOnAndCache(const Coord& xyz, AccessorT&) const;
388
389 /// Change the value of the voxel at the given coordinates and mark it as active.
390 /// If necessary, update the accessor with pointers to the nodes along the path
391 /// from the root node to the node containing the voxel.
392 /// @note Used internally by ValueAccessor.
393 template<typename AccessorT>
394 void setValueAndCache(const Coord& xyz, const ValueType& value, AccessorT&);
395
396 /// Set the value of the voxel at the given coordinate but preserves its active state.
397 /// If necessary, update the accessor with pointers to the nodes along the path
398 /// from the root node to the node containing the voxel.
399 /// @note Used internally by ValueAccessor.
400 template<typename AccessorT>
401 void setValueOnlyAndCache(const Coord& xyz, const ValueType& value, AccessorT&);
402
403 /// @brief Apply a functor to the value of the voxel at the given coordinates
404 /// and mark the voxel as active.
405 /// If necessary, update the accessor with pointers to the nodes along the path
406 /// from the root node to the node containing the voxel.
407 /// @note Used internally by ValueAccessor.
408 template<typename ModifyOp, typename AccessorT>
409 void modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&);
410
411 /// Apply a functor to the voxel at the given coordinates.
412 /// If necessary, update the accessor with pointers to the nodes along the path
413 /// from the root node to the node containing the voxel.
414 /// @note Used internally by ValueAccessor.
415 template<typename ModifyOp, typename AccessorT>
416 void modifyValueAndActiveStateAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&);
417
418 /// Change the value of the voxel at the given coordinates and mark it as inactive.
419 /// If necessary, update the accessor with pointers to the nodes along the path
420 /// from the root node to the node containing the voxel.
421 /// @note Used internally by ValueAccessor.
422 template<typename AccessorT>
423 void setValueOffAndCache(const Coord& xyz, const ValueType& value, AccessorT&);
424
425 /// Set the active state of the voxel at the given coordinates without changing its value.
426 /// If necessary, update the accessor with pointers to the nodes along the path
427 /// from the root node to the node containing the voxel.
428 /// @note Used internally by ValueAccessor.
429 template<typename AccessorT>
430 void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&);
431
432 /// Return, in @a value, the value of the voxel at the given coordinates and,
433 /// if necessary, update the accessor with pointers to the nodes along
434 /// the path from the root node to the node containing the voxel.
435 /// @return @c true if the voxel at the given coordinates is active
436 /// @note Used internally by ValueAccessor.
437 template<typename AccessorT>
438 bool probeValueAndCache(const Coord& xyz, ValueType& value, AccessorT&) const;
439
440 /// @brief Return the level of the tree (0 = leaf) at which the value
441 /// at the given coordinates resides.
442 ///
443 /// If necessary, update the accessor with pointers to the nodes along the path
444 /// from the root node to the node containing the voxel.
445 /// @note Used internally by ValueAccessor.
446 template<typename AccessorT>
447 Index getValueLevelAndCache(const Coord& xyz, AccessorT&) const;
448
449 /// Mark all values (both tiles and voxels) as active.
450 void setValuesOn();
451
452 //
453 // I/O
454 //
455 void writeTopology(std::ostream&, bool toHalf = false) const;
456 void readTopology(std::istream&, bool fromHalf = false);
457 void writeBuffers(std::ostream&, bool toHalf = false) const;
458 void readBuffers(std::istream&, bool fromHalf = false);
459 void readBuffers(std::istream&, const CoordBBox&, bool fromHalf = false);
460
461
462 //
463 // Aux methods
464 //
465
466 /// Change the sign of all the values represented in this node and its child nodes.
467 void negate();
468
469 /// @brief Set all voxels within a given axis-aligned box to a constant value.
470 /// @param bbox inclusive coordinates of opposite corners of an axis-aligned box
471 /// @param value the value to which to set voxels within the box
472 /// @param active if true, mark voxels within the box as active,
473 /// otherwise mark them as inactive
474 /// @note This operation generates a sparse, but not always optimally sparse,
475 /// representation of the filled box. Follow fill operations with a prune()
476 /// operation for optimal sparseness.
477 void fill(const CoordBBox& bbox, const ValueType& value, bool active = true);
478
479 /// @brief Set all voxels within a given axis-aligned box to a constant value
480 /// and ensure that those voxels are all represented at the leaf level.
481 /// @param bbox inclusive coordinates of opposite corners of an axis-aligned box.
482 /// @param value the value to which to set voxels within the box.
483 /// @param active if true, mark voxels within the box as active,
484 /// otherwise mark them as inactive.
485 /// @sa voxelizeActiveTiles()
486 void denseFill(const CoordBBox& bbox, const ValueType& value, bool active = true);
487
488 /// @brief Densify active tiles, i.e., replace them with leaf-level active voxels.
489 /// @param threaded if true, this operation is multi-threaded (over the internal nodes).
490 /// @sa denseFill()
491 void voxelizeActiveTiles(bool threaded = true);
492
493 /// @brief Copy into a dense grid the values of the voxels that lie within
494 /// a given bounding box.
495 /// @param bbox inclusive bounding box of the voxels to be copied into the dense grid
496 /// @param dense dense grid with a stride in @e z of one (see tools::Dense
497 /// in tools/Dense.h for the required API)
498 /// @note @a bbox is assumed to be identical to or contained in the coordinate domains
499 /// of both the dense grid and this node, i.e., no bounds checking is performed.
500 template<typename DenseT>
501 void copyToDense(const CoordBBox& bbox, DenseT& dense) const;
502
503 /// @brief Efficiently merge another tree into this tree using one of several schemes.
504 /// @warning This operation cannibalizes the other tree.
505 template<MergePolicy Policy>
506 void merge(InternalNode& other, const ValueType& background, const ValueType& otherBackground);
507
508 /// @brief Merge, using one of several schemes, this node (and its descendants)
509 /// with a tile of the same dimensions and the given value and active state.
510 template<MergePolicy Policy> void merge(const ValueType& tileValue, bool tileActive);
511
512 /// @brief Union this branch's set of active values with the other branch's
513 /// active values. The value type of the other branch can be different.
514 /// @details The resulting state of a value is active if the corresponding value
515 /// was already active OR if it is active in the other tree. Also, a resulting
516 /// value maps to a voxel if the corresponding value already mapped to a voxel
517 /// OR if it is a voxel in the other tree. Thus, a resulting value can only
518 /// map to a tile if the corresponding value already mapped to a tile
519 /// AND if it is a tile value in other tree.
520 ///
521 /// Specifically, active tiles and voxels in this branch are not changed, and
522 /// tiles or voxels that were inactive in this branch but active in the other branch
523 /// are marked as active in this branch but left with their original values.
524 template<typename OtherChildNodeType>
525 void topologyUnion(const InternalNode<OtherChildNodeType, Log2Dim>& other, const bool preserveTiles = false);
526
527 /// @brief Intersects this tree's set of active values with the active values
528 /// of the other tree, whose @c ValueType may be different.
529 /// @details The resulting state of a value is active only if the corresponding
530 /// value was already active AND if it is active in the other tree. Also, a
531 /// resulting value maps to a voxel if the corresponding value
532 /// already mapped to an active voxel in either of the two grids
533 /// and it maps to an active tile or voxel in the other grid.
534 ///
535 /// @note This operation can delete branches in this grid if they
536 /// overlap with inactive tiles in the other grid. Likewise active
537 /// voxels can be turned into inactive voxels resulting in leaf
538 /// nodes with no active values. Thus, it is recommended to
539 /// subsequently call prune.
540 template<typename OtherChildNodeType>
541 void topologyIntersection(const InternalNode<OtherChildNodeType, Log2Dim>& other,
542 const ValueType& background);
543
544 /// @brief Difference this node's set of active values with the active values
545 /// of the other node, whose @c ValueType may be different. So a
546 /// resulting voxel will be active only if the original voxel is
547 /// active in this node and inactive in the other node.
548 ///
549 /// @details The last dummy argument is required to match the signature
550 /// for InternalNode::topologyDifference.
551 ///
552 /// @note This operation modifies only active states, not
553 /// values. Also note that this operation can result in all voxels
554 /// being inactive so consider subsequently calling prune.
555 template<typename OtherChildNodeType>
556 void topologyDifference(const InternalNode<OtherChildNodeType, Log2Dim>& other,
557 const ValueType& background);
558
559 template<typename CombineOp>
560 void combine(InternalNode& other, CombineOp&);
561 template<typename CombineOp>
562 void combine(const ValueType& value, bool valueIsActive, CombineOp&);
563
564 template<typename CombineOp, typename OtherNodeType /*= InternalNode*/>
565 void combine2(const InternalNode& other0, const OtherNodeType& other1, CombineOp&);
566 template<typename CombineOp, typename OtherNodeType /*= InternalNode*/>
567 void combine2(const ValueType& value, const OtherNodeType& other, bool valIsActive, CombineOp&);
568 template<typename CombineOp, typename OtherValueType>
569 void combine2(const InternalNode& other, const OtherValueType&, bool valIsActive, CombineOp&);
570
571 /// @brief Calls the templated functor BBoxOp with bounding box
572 /// information for all active tiles and leaf nodes in this node.
573 /// An additional level argument is provided for each callback.
574 ///
575 /// @note The bounding boxes are guaranteed to be non-overlapping.
576 template<typename BBoxOp> void visitActiveBBox(BBoxOp&) const;
577
578 template<typename VisitorOp> void visit(VisitorOp&);
579 template<typename VisitorOp> void visit(VisitorOp&) const;
580
581 template<typename OtherNodeType, typename VisitorOp>
582 void visit2Node(OtherNodeType& other, VisitorOp&);
583 template<typename OtherNodeType, typename VisitorOp>
584 void visit2Node(OtherNodeType& other, VisitorOp&) const;
585 template<typename IterT, typename VisitorOp>
586 void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false);
587 template<typename IterT, typename VisitorOp>
588 void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false) const;
589
590 /// Set all voxels that lie outside the given axis-aligned box to the background.
591 void clip(const CoordBBox&, const ValueType& background);
592
593 /// @brief Reduce the memory footprint of this tree by replacing with tiles
594 /// any nodes whose values are all the same (optionally to within a tolerance)
595 /// and have the same active state.
596 void prune(const ValueType& tolerance = zeroVal<ValueType>());
597
598 /// @brief Add the specified leaf to this node, possibly creating a child branch
599 /// in the process. If the leaf node already exists, replace it.
600 void addLeaf(LeafNodeType* leaf);
601
602 /// @brief Same as addLeaf() except, if necessary, update the accessor with pointers
603 /// to the nodes along the path from the root node to the node containing the coordinate.
604 template<typename AccessorT>
605 void addLeafAndCache(LeafNodeType* leaf, AccessorT&);
606
607 /// @brief Return a pointer to the node of type @c NodeT that contains voxel (x, y, z)
608 /// and replace it with a tile of the specified value and state.
609 /// If no such node exists, leave the tree unchanged and return @c nullptr.
610 ///
611 /// @note The caller takes ownership of the node and is responsible for deleting it.
612 ///
613 /// @warning Since this method potentially removes nodes and branches of the tree,
614 /// it is important to clear the caches of all ValueAccessors associated with this tree.
615 template<typename NodeT>
616 NodeT* stealNode(const Coord& xyz, const ValueType& value, bool state);
617
618 /// @brief Add the given child node at this level deducing the offset from it's origin.
619 /// If a child node with this offset already exists, delete the old node and add the
620 /// new node in its place (i.e. ownership of the new child node is transferred to
621 /// this InternalNode)
622 /// @return @c true if inserting the child has been successful, otherwise the caller
623 /// retains ownership of the node and is responsible for deleting it.
624 bool addChild(ChildNodeType* child);
625
626 /// @brief Add a tile at the specified tree level that contains voxel (x, y, z),
627 /// possibly creating a parent branch or deleting a child branch in the process.
628 void addTile(Index level, const Coord& xyz, const ValueType& value, bool state);
629
630 /// @brief Delete any existing child branch at the specified offset and add a tile.
631 void addTile(Index offset, const ValueType& value, bool state);
632
633 /// @brief Same as addTile() except, if necessary, update the accessor with pointers
634 /// to the nodes along the path from the root node to the node containing (x, y, z).
635 template<typename AccessorT>
636 void addTileAndCache(Index level, const Coord& xyz, const ValueType&, bool state, AccessorT&);
637
638 //@{
639 /// @brief Return a pointer to the node that contains voxel (x, y, z).
640 /// If no such node exists, return nullptr.
641 template<typename NodeType> NodeType* probeNode(const Coord& xyz);
642 template<typename NodeType> const NodeType* probeConstNode(const Coord& xyz) const;
643 //@}
644
645 //@{
646 /// @brief Same as probeNode() except, if necessary, update the accessor with pointers
647 /// to the nodes along the path from the root node to the node containing (x, y, z).
648 template<typename NodeType, typename AccessorT>
649 NodeType* probeNodeAndCache(const Coord& xyz, AccessorT&);
650 template<typename NodeType, typename AccessorT>
651 const NodeType* probeConstNodeAndCache(const Coord& xyz, AccessorT&) const;
652 //@}
653
654 //@{
655 /// @brief Return a pointer to the leaf node that contains voxel (x, y, z).
656 /// If no such node exists, return @c nullptr.
657 LeafNodeType* probeLeaf(const Coord& xyz);
658 const LeafNodeType* probeConstLeaf(const Coord& xyz) const;
659 const LeafNodeType* probeLeaf(const Coord& xyz) const;
660 //@}
661
662 //@{
663 /// @brief Same as probeLeaf() except, if necessary, update the accessor with pointers
664 /// to the nodes along the path from the root node to the node containing (x, y, z).
665 template<typename AccessorT>
666 LeafNodeType* probeLeafAndCache(const Coord& xyz, AccessorT& acc);
667 template<typename AccessorT>
668 const LeafNodeType* probeConstLeafAndCache(const Coord& xyz, AccessorT& acc) const;
669 template<typename AccessorT>
670 const LeafNodeType* probeLeafAndCache(const Coord& xyz, AccessorT& acc) const;
671 //@}
672
673 /// @brief Return the leaf node that contains voxel (x, y, z).
674 /// If no such node exists, create one, but preserve the values and
675 /// active states of all voxels.
676 ///
677 /// @details Use this method to preallocate a static tree topology
678 /// over which to safely perform multithreaded processing.
679 LeafNodeType* touchLeaf(const Coord& xyz);
680
681 /// @brief Same as touchLeaf() except, if necessary, update the accessor with pointers
682 /// to the nodes along the path from the root node to the node containing the coordinate.
683 template<typename AccessorT>
684 LeafNodeType* touchLeafAndCache(const Coord& xyz, AccessorT&);
685
686 //@{
687 /// @brief Adds all nodes of a certain type to a container with the following API:
688 /// @code
689 /// struct ArrayT {
690 /// using value_type = ...;// defines the type of nodes to be added to the array
691 /// void push_back(value_type nodePtr);// method that add nodes to the array
692 /// };
693 /// @endcode
694 /// @details An example of a wrapper around a c-style array is:
695 /// @code
696 /// struct MyArray {
697 /// using value_type = LeafType*;
698 /// value_type* ptr;
699 /// MyArray(value_type* array) : ptr(array) {}
700 /// void push_back(value_type leaf) { *ptr++ = leaf; }
701 ///};
702 /// @endcode
703 /// @details An example that constructs a list of pointer to all leaf nodes is:
704 /// @code
705 /// std::vector<const LeafNodeType*> array;//most std contains have the required API
706 /// array.reserve(tree.leafCount());//this is a fast preallocation.
707 /// tree.getNodes(array);
708 /// @endcode
709 template<typename ArrayT>
710 void getNodes(ArrayT& array);
711 template<typename ArrayT>
712 void getNodes(ArrayT& array) const;
713 //@}
714
715 /// @brief Steals all nodes of a certain type from the tree and
716 /// adds them to a container with the following API:
717 /// @code
718 /// struct ArrayT {
719 /// using value_type = ...;// defines the type of nodes to be added to the array
720 /// void push_back(value_type nodePtr);// method that add nodes to the array
721 /// };
722 /// @endcode
723 /// @details An example of a wrapper around a c-style array is:
724 /// @code
725 /// struct MyArray {
726 /// using value_type = LeafType*;
727 /// value_type* ptr;
728 /// MyArray(value_type* array) : ptr(array) {}
729 /// void push_back(value_type leaf) { *ptr++ = leaf; }
730 ///};
731 /// @endcode
732 /// @details An example that constructs a list of pointer to all leaf nodes is:
733 /// @code
734 /// std::vector<const LeafNodeType*> array;//most std contains have the required API
735 /// array.reserve(tree.leafCount());//this is a fast preallocation.
736 /// tree.stealNodes(array);
737 /// @endcode
738 template<typename ArrayT>
739 void stealNodes(ArrayT& array, const ValueType& value, bool state);
740
741 /// @brief Change inactive tiles or voxels with value oldBackground to newBackground
742 /// or -oldBackground to -newBackground. Active values are unchanged.
743 void resetBackground(const ValueType& oldBackground, const ValueType& newBackground);
744
745 /// @brief Return @c true if the given tree branch has the same node and active value
746 /// topology as this tree branch (but possibly a different @c ValueType).
747 template<typename OtherChildNodeType, Index OtherLog2Dim>
748 bool hasSameTopology(const InternalNode<OtherChildNodeType, OtherLog2Dim>* other) const;
749
750 protected:
751 //@{
752 /// Allow iterators to call mask accessor methods (setValueMask(), setChildMask(), etc.).
753 /// @todo Make mask accessors public?
754 friend class IteratorBase<MaskOnIterator, InternalNode>;
755 friend class IteratorBase<MaskOffIterator, InternalNode>;
756 friend class IteratorBase<MaskDenseIterator, InternalNode>;
757 //@}
758
759 /// @brief During topology-only construction, access is needed
760 /// to protected/private members of other template instances.
761 template<typename, Index> friend class InternalNode;
762
763 // Mask accessors
764 public:
765 497658246 bool isValueMaskOn(Index n) const { return mValueMask.isOn(n); }
766 bool isValueMaskOn() const { return mValueMask.isOn(); }
767 462844 bool isValueMaskOff(Index n) const { return mValueMask.isOff(n); }
768 bool isValueMaskOff() const { return mValueMask.isOff(); }
769 4492402214 bool isChildMaskOn(Index n) const { return mChildMask.isOn(n); }
770 6348730 bool isChildMaskOff(Index n) const { return mChildMask.isOff(n); }
771 bool isChildMaskOff() const { return mChildMask.isOff(); }
772 4265256 const NodeMaskType& getValueMask() const { return mValueMask; }
773 178580 const NodeMaskType& getChildMask() const { return mChildMask; }
774 4 NodeMaskType getValueOffMask() const
775 {
776 NodeMaskType mask = mValueMask;
777 mask |= mChildMask;
778 mask.toggle();
779 4 return mask;
780 }
781
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
4268657 const UnionType* getTable() const { return mNodes; }
782 protected:
783 //@{
784 /// Use a mask accessor to ensure consistency between the child and value masks;
785 /// i.e., the value mask should always be off wherever the child mask is on.
786
1/2
✓ Branch 1 taken 351119 times.
✗ Branch 2 not taken.
702238 void setValueMask(Index n, bool on) { mValueMask.set(n, mChildMask.isOn(n) ? false : on); }
787 //@}
788
789 void makeChildNodeEmpty(Index n, const ValueType& value);
790 void setChildNode( Index i, ChildNodeType* child);//assumes a tile
791 void resetChildNode(Index i, ChildNodeType* child);//checks for an existing child
792 ChildNodeType* unsetChildNode(Index i, const ValueType& value);
793
794 template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
795 static inline void doVisit(NodeT&, VisitorOp&);
796
797 template<typename NodeT, typename OtherNodeT, typename VisitorOp,
798 typename ChildAllIterT, typename OtherChildAllIterT>
799 static inline void doVisit2Node(NodeT&, OtherNodeT&, VisitorOp&);
800
801 template<typename NodeT, typename VisitorOp,
802 typename ChildAllIterT, typename OtherChildAllIterT>
803 static inline void doVisit2(NodeT&, OtherChildAllIterT&, VisitorOp&, bool otherIsLHS);
804
805 ///@{
806 /// @brief Returns a pointer to the child node at the linear offset n.
807 /// @warning This protected method assumes that a child node exists at
808 /// the specified linear offset!
809 ChildNodeType* getChildNode(Index n);
810 const ChildNodeType* getChildNode(Index n) const;
811 ///@}
812
813 ///@{
814 /// @brief Protected member classes for recursive multi-threading
815 struct VoxelizeActiveTiles;
816 template<typename OtherInternalNode> struct DeepCopy;
817 template<typename OtherInternalNode> struct TopologyCopy1;
818 template<typename OtherInternalNode> struct TopologyCopy2;
819 template<typename OtherInternalNode> struct TopologyUnion;
820 template<typename OtherInternalNode> struct TopologyDifference;
821 template<typename OtherInternalNode> struct TopologyIntersection;
822 ///@}
823
824 UnionType mNodes[NUM_VALUES];
825 NodeMaskType mChildMask, mValueMask;
826 /// Global grid index coordinates (x,y,z) of the local origin of this node
827 Coord mOrigin;
828 #if OPENVDB_ABI_VERSION_NUMBER >= 9
829 /// Transient data (not serialized)
830 Index32 mTransientData = 0;
831 #endif
832 }; // class InternalNode
833
834
835 ////////////////////////////////////////
836
837
838 //@{
839 /// Helper metafunction used to implement InternalNode::SameConfiguration
840 /// (which, as an inner class, can't be independently specialized)
841 template<typename ChildT1, Index Dim1, typename NodeT2>
842 struct SameInternalConfig {
843 static const bool value = false;
844 };
845
846 template<typename ChildT1, Index Dim1, typename ChildT2>
847 struct SameInternalConfig<ChildT1, Dim1, InternalNode<ChildT2, Dim1> > {
848 static const bool value = ChildT1::template SameConfiguration<ChildT2>::value;
849 };
850 //@}
851
852
853 ////////////////////////////////////////
854
855
856 template<typename ChildT, Index Log2Dim>
857 inline
858 InternalNode<ChildT, Log2Dim>::InternalNode(const ValueType& background)
859 {
860 for (Index i = 0; i < NUM_VALUES; ++i) mNodes[i].setValue(background);
861 }
862
863
864 template<typename ChildT, Index Log2Dim>
865 inline
866 477391 InternalNode<ChildT, Log2Dim>::InternalNode(const Coord& origin, const ValueType& val, bool active):
867 mOrigin(origin[0] & ~(DIM - 1), // zero out the low-order bits
868 origin[1] & ~(DIM - 1),
869
40/56
✓ Branch 0 taken 3005841216 times.
✓ Branch 1 taken 214417 times.
✓ Branch 2 taken 37449 times.
✓ Branch 3 taken 176838 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1536 times.
✓ Branch 9 taken 24 times.
✓ Branch 10 taken 132 times.
✓ Branch 11 taken 22 times.
✓ Branch 12 taken 20480 times.
✓ Branch 13 taken 42 times.
✓ Branch 14 taken 2000000 times.
✓ Branch 15 taken 31290 times.
✓ Branch 16 taken 128 times.
✓ Branch 17 taken 31252 times.
✓ Branch 18 taken 1281 times.
✓ Branch 19 taken 21 times.
✓ Branch 20 taken 128 times.
✓ Branch 21 taken 22 times.
✓ Branch 22 taken 513 times.
✓ Branch 23 taken 9 times.
✓ Branch 24 taken 64 times.
✓ Branch 25 taken 1 times.
✓ Branch 26 taken 1 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 1108224 times.
✓ Branch 29 taken 17316 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 15625 times.
✓ Branch 32 taken 8320 times.
✓ Branch 33 taken 130 times.
✓ Branch 34 taken 256 times.
✓ Branch 35 taken 4 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 4 times.
✓ Branch 38 taken 1664 times.
✓ Branch 39 taken 26 times.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✓ Branch 44 taken 25600 times.
✓ Branch 45 taken 400 times.
✗ Branch 46 not taken.
✓ Branch 47 taken 400 times.
✓ Branch 48 taken 256 times.
✓ Branch 49 taken 4 times.
✓ Branch 50 taken 256 times.
✓ Branch 51 taken 4 times.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
6015712911 origin[2] & ~(DIM - 1))
870 {
871
12/20
✓ Branch 0 taken 37449 times.
✓ Branch 1 taken 176838 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 22 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 31294 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 17 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 15629 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 400 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
475398 if (active) mValueMask.setOn();
872
30/40
✓ Branch 0 taken 3005841216 times.
✓ Branch 1 taken 214417 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1536 times.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 20608 times.
✓ Branch 7 taken 42 times.
✓ Branch 8 taken 2000128 times.
✓ Branch 9 taken 31252 times.
✓ Branch 10 taken 1152 times.
✓ Branch 11 taken 18 times.
✓ Branch 12 taken 320 times.
✓ Branch 13 taken 5 times.
✓ Branch 14 taken 576 times.
✓ Branch 15 taken 9 times.
✓ Branch 16 taken 1000000 times.
✓ Branch 17 taken 15625 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 108160 times.
✓ Branch 21 taken 1690 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✓ Branch 24 taken 8320 times.
✓ Branch 25 taken 130 times.
✓ Branch 26 taken 256 times.
✓ Branch 27 taken 4 times.
✓ Branch 28 taken 1664 times.
✓ Branch 29 taken 26 times.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✓ Branch 32 taken 25600 times.
✓ Branch 33 taken 400 times.
✓ Branch 34 taken 256 times.
✓ Branch 35 taken 4 times.
✓ Branch 36 taken 256 times.
✓ Branch 37 taken 4 times.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
6015285391 for (Index i = 0; i < NUM_VALUES; ++i) mNodes[i].setValue(val);
873 427522 }
874
875
876 // For InternalNodes, the PartialCreate constructor is identical to its
877 // non-PartialCreate counterpart.
878 template<typename ChildT, Index Log2Dim>
879 inline
880 1010 InternalNode<ChildT, Log2Dim>::InternalNode(PartialCreate,
881 const Coord& origin, const ValueType& val, bool active)
882
3/12
✓ Branch 0 taken 9222144 times.
✓ Branch 1 taken 505 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 505 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
18446308 : mOrigin(origin[0] & ~(DIM-1), origin[1] & ~(DIM-1), origin[2] & ~(DIM-1))
883 {
884
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 505 times.
1010 if (active) mValueMask.setOn();
885
2/12
✓ Branch 0 taken 9222144 times.
✓ Branch 1 taken 505 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
18445298 for (Index i = 0; i < NUM_VALUES; ++i) mNodes[i].setValue(val);
886 }
887
888 template<typename ChildT, Index Log2Dim>
889 template<typename OtherInternalNode>
890 struct InternalNode<ChildT, Log2Dim>::DeepCopy
891 {
892
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
7997 DeepCopy(const OtherInternalNode* source, InternalNode* target) : s(source), t(target) {
893
2/12
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
7997 tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
894 //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//serial
895 }
896 2351522 void operator()(const tbb::blocked_range<Index> &r) const {
897
2/2
✓ Branch 0 taken 129753088 times.
✓ Branch 1 taken 1175761 times.
261857698 for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
898
2/2
✓ Branch 1 taken 129671652 times.
✓ Branch 2 taken 81436 times.
259506176 if (s->mChildMask.isOff(i)) {
899 260195248 t->mNodes[i].setValue(ValueType(s->mNodes[i].getValue()));
900 } else {
901
1/2
✓ Branch 2 taken 79303 times.
✗ Branch 3 not taken.
162872 t->mNodes[i].setChild(new ChildNodeType(*(s->mNodes[i].getChild())));
902 }
903 }
904 2351522 }
905 const OtherInternalNode* s;
906 InternalNode* t;
907 };// DeepCopy
908
909 template<typename ChildT, Index Log2Dim>
910 inline
911 9094 InternalNode<ChildT, Log2Dim>::InternalNode(const InternalNode& other)
912 : mChildMask(other.mChildMask)
913 , mValueMask(other.mValueMask)
914 , mOrigin(other.mOrigin)
915 #if OPENVDB_ABI_VERSION_NUMBER >= 9
916
3/4
✓ Branch 0 taken 85803008 times.
✓ Branch 1 taken 4547 times.
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
171624204 , mTransientData(other.mTransientData)
917 #endif
918 {
919 DeepCopy<InternalNode<ChildT, Log2Dim> > tmp(&other, this);
920 9094 }
921
922
923 // Copy-construct from a node with the same configuration but a different ValueType.
924 template<typename ChildT, Index Log2Dim>
925 template<typename OtherChildNodeType>
926 inline
927 6900 InternalNode<ChildT, Log2Dim>::InternalNode(const InternalNode<OtherChildNodeType, Log2Dim>& other)
928 : mChildMask(other.mChildMask)
929 , mValueMask(other.mValueMask)
930 , mOrigin(other.mOrigin)
931 #if OPENVDB_ABI_VERSION_NUMBER >= 9
932
2/2
✓ Branch 0 taken 43950080 times.
✓ Branch 1 taken 3450 times.
87913960 , mTransientData(other.mTransientData)
933 #endif
934 {
935 DeepCopy<InternalNode<OtherChildNodeType, Log2Dim> > tmp(&other, this);
936 6900 }
937
938 template<typename ChildT, Index Log2Dim>
939 template<typename OtherInternalNode>
940 struct InternalNode<ChildT, Log2Dim>::TopologyCopy1
941 {
942 44950 TopologyCopy1(const OtherInternalNode* source, InternalNode* target,
943 44950 const ValueType& background) : s(source), t(target), b(background) {
944 44950 tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
945 //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//serial
946 }
947 12655502 void operator()(const tbb::blocked_range<Index> &r) const {
948
2/2
✓ Branch 0 taken 622682112 times.
✓ Branch 1 taken 6327751 times.
1258019726 for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
949
2/2
✓ Branch 1 taken 1185679 times.
✓ Branch 2 taken 621496433 times.
1245364224 if (s->isChildMaskOn(i)) {
950
1/2
✓ Branch 1 taken 108558 times.
✗ Branch 2 not taken.
2435382 t->mNodes[i].setChild(new ChildNodeType(*(s->mNodes[i].getChild()),
951
1/2
✓ Branch 1 taken 108558 times.
✗ Branch 2 not taken.
797056 b, TopologyCopy()));
952 } else {
953 1242992866 t->mNodes[i].setValue(b);
954 }
955 }
956 12655502 }
957 const OtherInternalNode* s;
958 InternalNode* t;
959 const ValueType &b;
960 };// TopologyCopy1
961
962 template<typename ChildT, Index Log2Dim>
963 template<typename OtherChildNodeType>
964 inline
965 89900 InternalNode<ChildT, Log2Dim>::InternalNode(const InternalNode<OtherChildNodeType, Log2Dim>& other,
966 const ValueType& background, TopologyCopy)
967 : mChildMask(other.mChildMask)
968 , mValueMask(other.mValueMask)
969 , mOrigin(other.mOrigin)
970 #if OPENVDB_ABI_VERSION_NUMBER >= 9
971
2/2
✓ Branch 0 taken 622682112 times.
✓ Branch 1 taken 44950 times.
1245544024 , mTransientData(other.mTransientData)
972 #endif
973 {
974 TopologyCopy1<InternalNode<OtherChildNodeType, Log2Dim> > tmp(&other, this, background);
975 89900 }
976
977 template<typename ChildT, Index Log2Dim>
978 template<typename OtherInternalNode>
979 struct InternalNode<ChildT, Log2Dim>::TopologyCopy2
980 {
981 172 TopologyCopy2(const OtherInternalNode* source, InternalNode* target,
982 const ValueType& offValue, const ValueType& onValue)
983 172 : s(source), t(target), offV(offValue), onV(onValue) {
984 172 tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
985 }
986 43682 void operator()(const tbb::blocked_range<Index> &r) const {
987
2/2
✓ Branch 0 taken 1894400 times.
✓ Branch 1 taken 21841 times.
3832482 for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
988
2/2
✓ Branch 1 taken 14460 times.
✓ Branch 2 taken 1879940 times.
3788800 if (s->isChildMaskOn(i)) {
989
1/2
✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
57840 t->mNodes[i].setChild(new ChildNodeType(*(s->mNodes[i].getChild()),
990
1/2
✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
28920 offV, onV, TopologyCopy()));
991 } else {
992
2/2
✓ Branch 1 taken 164 times.
✓ Branch 2 taken 1879776 times.
3759880 t->mNodes[i].setValue(s->isValueMaskOn(i) ? onV : offV);
993 }
994 }
995 43682 }
996 const OtherInternalNode* s;
997 InternalNode* t;
998 const ValueType &offV, &onV;
999 };// TopologyCopy2
1000
1001 template<typename ChildT, Index Log2Dim>
1002 template<typename OtherChildNodeType>
1003 inline
1004 344 InternalNode<ChildT, Log2Dim>::InternalNode(const InternalNode<OtherChildNodeType, Log2Dim>& other,
1005 const ValueType& offValue,
1006 const ValueType& onValue, TopologyCopy)
1007 : mChildMask(other.mChildMask)
1008 , mValueMask(other.mValueMask)
1009 , mOrigin(other.mOrigin)
1010 #if OPENVDB_ABI_VERSION_NUMBER >= 9
1011
2/2
✓ Branch 0 taken 1894400 times.
✓ Branch 1 taken 172 times.
3789424 , mTransientData(other.mTransientData)
1012 #endif
1013 {
1014 TopologyCopy2<InternalNode<OtherChildNodeType, Log2Dim> > tmp(&other, this, offValue, onValue);
1015 344 }
1016
1017
1018 template<typename ChildT, Index Log2Dim>
1019 inline
1020 634548 InternalNode<ChildT, Log2Dim>::~InternalNode()
1021 {
1022
2/2
✓ Branch 0 taken 297102 times.
✓ Branch 1 taken 317274 times.
1228752 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
1023
1/2
✓ Branch 0 taken 297102 times.
✗ Branch 1 not taken.
641680 delete mNodes[iter.pos()].getChild();
1024 }
1025
3/4
✓ Branch 0 taken 487 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10129984 times.
✓ Branch 3 taken 487 times.
20895490 }
1026
1027
1028 ////////////////////////////////////////
1029
1030
1031 template<typename ChildT, Index Log2Dim>
1032 inline Index32
1033 214937 InternalNode<ChildT, Log2Dim>::leafCount() const
1034 {
1035
7/14
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 21 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 9 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 155 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 174 times.
✗ Branch 20 not taken.
217684 if (ChildNodeType::getLevel() == 0) return mChildMask.countOn();
1036 Index32 sum = 0;
1037
2/2
✓ Branch 0 taken 108674 times.
✓ Branch 1 taken 107475 times.
432262 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1038 217325 sum += iter->leafCount();
1039 }
1040 return sum;
1041 }
1042
1043 template<typename ChildT, Index Log2Dim>
1044 inline void
1045
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 336 times.
672 InternalNode<ChildT, Log2Dim>::nodeCount(std::vector<Index32> &vec) const
1046 {
1047
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 336 times.
672 assert(vec.size() > ChildNodeType::LEVEL);
1048 672 const auto count = mChildMask.countOn();
1049
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
48 if (ChildNodeType::LEVEL > 0 && count > 0) {
1050
2/2
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 24 times.
1296 for (auto iter = this->cbeginChildOn(); iter; ++iter) iter->nodeCount(vec);
1051 }
1052 672 vec[ChildNodeType::LEVEL] += count;
1053 }
1054
1055
1056 template<typename ChildT, Index Log2Dim>
1057 inline Index32
1058 2405 InternalNode<ChildT, Log2Dim>::nonLeafCount() const
1059 {
1060 Index32 sum = 1;
1061 if (ChildNodeType::getLevel() == 0) return sum;
1062
2/2
✓ Branch 0 taken 1394 times.
✓ Branch 1 taken 1209 times.
5170 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1063 2765 sum += iter->nonLeafCount();
1064 }
1065 return sum;
1066 }
1067
1068
1069 template<typename ChildT, Index Log2Dim>
1070 inline Index32
1071 InternalNode<ChildT, Log2Dim>::childCount() const
1072 {
1073
20/511
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✓ Branch 42 taken 3 times.
✓ Branch 43 taken 3 times.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✓ Branch 46 taken 1 times.
✗ Branch 47 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✗ Branch 79 not taken.
✗ Branch 80 not taken.
✗ Branch 82 not taken.
✗ Branch 83 not taken.
✗ Branch 85 not taken.
✗ Branch 86 not taken.
✗ Branch 88 not taken.
✗ Branch 89 not taken.
✗ Branch 91 not taken.
✗ Branch 92 not taken.
✗ Branch 94 not taken.
✗ Branch 95 not taken.
✗ Branch 97 not taken.
✗ Branch 98 not taken.
✗ Branch 100 not taken.
✗ Branch 101 not taken.
✗ Branch 103 not taken.
✗ Branch 104 not taken.
✗ Branch 106 not taken.
✗ Branch 107 not taken.
✗ Branch 109 not taken.
✗ Branch 110 not taken.
✗ Branch 112 not taken.
✗ Branch 113 not taken.
✗ Branch 115 not taken.
✗ Branch 116 not taken.
✗ Branch 117 not taken.
✗ Branch 118 not taken.
✗ Branch 119 not taken.
✗ Branch 120 not taken.
✗ Branch 121 not taken.
✗ Branch 122 not taken.
✗ Branch 123 not taken.
✓ Branch 124 taken 1 times.
✗ Branch 125 not taken.
✗ Branch 126 not taken.
✗ Branch 127 not taken.
✗ Branch 128 not taken.
✗ Branch 129 not taken.
✗ Branch 130 not taken.
✗ Branch 131 not taken.
✗ Branch 132 not taken.
✗ Branch 133 not taken.
✗ Branch 134 not taken.
✗ Branch 135 not taken.
✗ Branch 136 not taken.
✗ Branch 137 not taken.
✗ Branch 138 not taken.
✗ Branch 139 not taken.
✗ Branch 140 not taken.
✗ Branch 141 not taken.
✗ Branch 142 not taken.
✗ Branch 143 not taken.
✗ Branch 144 not taken.
✗ Branch 145 not taken.
✗ Branch 146 not taken.
✗ Branch 147 not taken.
✗ Branch 148 not taken.
✗ Branch 149 not taken.
✗ Branch 150 not taken.
✗ Branch 151 not taken.
✗ Branch 152 not taken.
✗ Branch 153 not taken.
✗ Branch 154 not taken.
✗ Branch 155 not taken.
✗ Branch 156 not taken.
✗ Branch 157 not taken.
✗ Branch 158 not taken.
✗ Branch 159 not taken.
✗ Branch 160 not taken.
✗ Branch 161 not taken.
✗ Branch 162 not taken.
✗ Branch 163 not taken.
✗ Branch 164 not taken.
✗ Branch 165 not taken.
✓ Branch 166 taken 8 times.
✗ Branch 167 not taken.
✗ Branch 168 not taken.
✓ Branch 169 taken 8 times.
✗ Branch 170 not taken.
✓ Branch 171 taken 1 times.
✗ Branch 172 not taken.
✗ Branch 173 not taken.
✓ Branch 174 taken 1 times.
✗ Branch 175 not taken.
✗ Branch 176 not taken.
✓ Branch 177 taken 1 times.
✗ Branch 178 not taken.
✗ Branch 179 not taken.
✓ Branch 180 taken 1 times.
✗ Branch 181 not taken.
✗ Branch 182 not taken.
✓ Branch 183 taken 1 times.
✗ Branch 184 not taken.
✗ Branch 185 not taken.
✓ Branch 186 taken 1 times.
✗ Branch 187 not taken.
✗ Branch 188 not taken.
✓ Branch 189 taken 1 times.
✗ Branch 190 not taken.
✗ Branch 191 not taken.
✗ Branch 193 not taken.
✗ Branch 194 not taken.
✗ Branch 196 not taken.
✗ Branch 197 not taken.
✗ Branch 199 not taken.
✗ Branch 200 not taken.
✗ Branch 202 not taken.
✗ Branch 203 not taken.
✗ Branch 205 not taken.
✗ Branch 206 not taken.
✗ Branch 208 not taken.
✗ Branch 209 not taken.
✗ Branch 211 not taken.
✗ Branch 212 not taken.
✗ Branch 214 not taken.
✗ Branch 215 not taken.
✗ Branch 217 not taken.
✗ Branch 218 not taken.
✗ Branch 220 not taken.
✗ Branch 221 not taken.
✗ Branch 223 not taken.
✗ Branch 224 not taken.
✗ Branch 226 not taken.
✗ Branch 227 not taken.
✗ Branch 229 not taken.
✗ Branch 230 not taken.
✗ Branch 232 not taken.
✗ Branch 233 not taken.
✗ Branch 235 not taken.
✗ Branch 236 not taken.
✗ Branch 238 not taken.
✗ Branch 239 not taken.
✗ Branch 241 not taken.
✗ Branch 242 not taken.
✗ Branch 244 not taken.
✗ Branch 245 not taken.
✗ Branch 247 not taken.
✗ Branch 248 not taken.
✗ Branch 250 not taken.
✗ Branch 251 not taken.
✗ Branch 253 not taken.
✗ Branch 254 not taken.
✗ Branch 256 not taken.
✗ Branch 257 not taken.
✗ Branch 259 not taken.
✗ Branch 260 not taken.
✗ Branch 262 not taken.
✗ Branch 263 not taken.
✗ Branch 265 not taken.
✗ Branch 266 not taken.
✗ Branch 268 not taken.
✗ Branch 269 not taken.
✗ Branch 271 not taken.
✗ Branch 272 not taken.
✗ Branch 274 not taken.
✗ Branch 275 not taken.
✗ Branch 277 not taken.
✗ Branch 278 not taken.
✗ Branch 280 not taken.
✗ Branch 281 not taken.
✗ Branch 283 not taken.
✗ Branch 284 not taken.
✗ Branch 286 not taken.
✗ Branch 287 not taken.
✗ Branch 289 not taken.
✗ Branch 290 not taken.
✗ Branch 292 not taken.
✗ Branch 293 not taken.
✗ Branch 295 not taken.
✗ Branch 296 not taken.
✗ Branch 298 not taken.
✗ Branch 299 not taken.
✗ Branch 301 not taken.
✗ Branch 302 not taken.
✗ Branch 304 not taken.
✗ Branch 305 not taken.
✗ Branch 307 not taken.
✗ Branch 308 not taken.
✗ Branch 310 not taken.
✗ Branch 311 not taken.
✗ Branch 313 not taken.
✗ Branch 314 not taken.
✗ Branch 316 not taken.
✗ Branch 317 not taken.
✓ Branch 319 taken 1 times.
✗ Branch 320 not taken.
✓ Branch 322 taken 1 times.
✗ Branch 323 not taken.
✓ Branch 325 taken 1 times.
✗ Branch 326 not taken.
✓ Branch 328 taken 1 times.
✗ Branch 329 not taken.
✓ Branch 331 taken 1 times.
✗ Branch 332 not taken.
✓ Branch 334 taken 1 times.
✗ Branch 335 not taken.
✗ Branch 337 not taken.
✗ Branch 338 not taken.
✗ Branch 340 not taken.
✗ Branch 341 not taken.
✗ Branch 343 not taken.
✗ Branch 344 not taken.
✗ Branch 346 not taken.
✗ Branch 347 not taken.
✗ Branch 349 not taken.
✗ Branch 350 not taken.
✗ Branch 352 not taken.
✗ Branch 353 not taken.
✗ Branch 355 not taken.
✗ Branch 356 not taken.
✗ Branch 358 not taken.
✗ Branch 359 not taken.
✗ Branch 361 not taken.
✗ Branch 362 not taken.
✗ Branch 364 not taken.
✗ Branch 365 not taken.
✗ Branch 367 not taken.
✗ Branch 368 not taken.
✗ Branch 370 not taken.
✗ Branch 371 not taken.
✗ Branch 373 not taken.
✗ Branch 374 not taken.
✗ Branch 376 not taken.
✗ Branch 377 not taken.
✗ Branch 379 not taken.
✗ Branch 380 not taken.
✗ Branch 382 not taken.
✗ Branch 383 not taken.
✗ Branch 385 not taken.
✗ Branch 386 not taken.
✗ Branch 388 not taken.
✗ Branch 389 not taken.
✗ Branch 391 not taken.
✗ Branch 392 not taken.
✗ Branch 394 not taken.
✗ Branch 395 not taken.
✗ Branch 397 not taken.
✗ Branch 398 not taken.
✗ Branch 400 not taken.
✗ Branch 401 not taken.
✗ Branch 403 not taken.
✗ Branch 404 not taken.
✗ Branch 406 not taken.
✗ Branch 407 not taken.
✗ Branch 409 not taken.
✗ Branch 410 not taken.
✗ Branch 412 not taken.
✗ Branch 413 not taken.
✗ Branch 415 not taken.
✗ Branch 416 not taken.
✗ Branch 418 not taken.
✗ Branch 419 not taken.
✗ Branch 421 not taken.
✗ Branch 422 not taken.
✗ Branch 424 not taken.
✗ Branch 425 not taken.
✗ Branch 427 not taken.
✗ Branch 428 not taken.
✗ Branch 430 not taken.
✗ Branch 431 not taken.
✗ Branch 433 not taken.
✗ Branch 434 not taken.
✗ Branch 436 not taken.
✗ Branch 437 not taken.
✗ Branch 439 not taken.
✗ Branch 440 not taken.
✗ Branch 442 not taken.
✗ Branch 443 not taken.
✗ Branch 445 not taken.
✗ Branch 446 not taken.
✗ Branch 448 not taken.
✗ Branch 449 not taken.
✗ Branch 451 not taken.
✗ Branch 452 not taken.
✗ Branch 454 not taken.
✗ Branch 455 not taken.
✗ Branch 457 not taken.
✗ Branch 458 not taken.
✗ Branch 460 not taken.
✗ Branch 461 not taken.
✗ Branch 463 not taken.
✗ Branch 464 not taken.
✗ Branch 466 not taken.
✗ Branch 467 not taken.
✗ Branch 469 not taken.
✗ Branch 470 not taken.
✗ Branch 472 not taken.
✗ Branch 473 not taken.
✗ Branch 475 not taken.
✗ Branch 476 not taken.
✗ Branch 478 not taken.
✗ Branch 479 not taken.
✗ Branch 481 not taken.
✗ Branch 482 not taken.
✗ Branch 484 not taken.
✗ Branch 485 not taken.
✗ Branch 487 not taken.
✗ Branch 488 not taken.
✗ Branch 490 not taken.
✗ Branch 491 not taken.
✗ Branch 493 not taken.
✗ Branch 494 not taken.
✗ Branch 496 not taken.
✗ Branch 497 not taken.
✗ Branch 499 not taken.
✗ Branch 500 not taken.
✗ Branch 502 not taken.
✗ Branch 503 not taken.
✗ Branch 505 not taken.
✗ Branch 506 not taken.
✗ Branch 508 not taken.
✗ Branch 509 not taken.
✗ Branch 511 not taken.
✗ Branch 512 not taken.
✗ Branch 514 not taken.
✗ Branch 515 not taken.
✗ Branch 517 not taken.
✗ Branch 518 not taken.
✗ Branch 520 not taken.
✗ Branch 521 not taken.
✗ Branch 523 not taken.
✗ Branch 524 not taken.
✗ Branch 526 not taken.
✗ Branch 527 not taken.
✗ Branch 529 not taken.
✗ Branch 530 not taken.
✗ Branch 532 not taken.
✗ Branch 533 not taken.
✗ Branch 535 not taken.
✗ Branch 536 not taken.
✗ Branch 538 not taken.
✗ Branch 539 not taken.
✗ Branch 541 not taken.
✗ Branch 542 not taken.
✗ Branch 544 not taken.
✗ Branch 545 not taken.
✗ Branch 547 not taken.
✗ Branch 548 not taken.
✗ Branch 550 not taken.
✗ Branch 551 not taken.
✗ Branch 553 not taken.
✗ Branch 554 not taken.
✗ Branch 556 not taken.
✗ Branch 557 not taken.
✗ Branch 559 not taken.
✗ Branch 560 not taken.
✗ Branch 562 not taken.
✗ Branch 563 not taken.
✗ Branch 565 not taken.
✗ Branch 566 not taken.
✗ Branch 568 not taken.
✗ Branch 569 not taken.
✗ Branch 571 not taken.
✗ Branch 572 not taken.
✗ Branch 574 not taken.
✗ Branch 575 not taken.
✗ Branch 577 not taken.
✗ Branch 578 not taken.
✗ Branch 580 not taken.
✗ Branch 581 not taken.
✗ Branch 583 not taken.
✗ Branch 584 not taken.
✗ Branch 586 not taken.
✗ Branch 587 not taken.
✗ Branch 589 not taken.
✗ Branch 590 not taken.
✗ Branch 592 not taken.
✗ Branch 593 not taken.
✗ Branch 595 not taken.
✗ Branch 596 not taken.
✗ Branch 598 not taken.
✗ Branch 599 not taken.
✗ Branch 601 not taken.
✗ Branch 602 not taken.
✗ Branch 604 not taken.
✗ Branch 605 not taken.
✗ Branch 607 not taken.
✗ Branch 608 not taken.
✗ Branch 610 not taken.
✗ Branch 611 not taken.
✗ Branch 613 not taken.
✗ Branch 614 not taken.
✗ Branch 616 not taken.
✗ Branch 617 not taken.
✗ Branch 619 not taken.
✗ Branch 620 not taken.
✗ Branch 622 not taken.
✗ Branch 623 not taken.
✗ Branch 625 not taken.
✗ Branch 626 not taken.
✗ Branch 628 not taken.
✗ Branch 629 not taken.
✗ Branch 631 not taken.
✗ Branch 632 not taken.
✗ Branch 634 not taken.
✗ Branch 635 not taken.
✗ Branch 637 not taken.
✗ Branch 638 not taken.
✗ Branch 640 not taken.
✗ Branch 641 not taken.
✗ Branch 643 not taken.
✗ Branch 644 not taken.
✗ Branch 646 not taken.
✗ Branch 647 not taken.
✗ Branch 649 not taken.
✗ Branch 650 not taken.
✗ Branch 652 not taken.
✗ Branch 653 not taken.
✗ Branch 655 not taken.
✗ Branch 656 not taken.
✗ Branch 658 not taken.
✗ Branch 659 not taken.
✗ Branch 661 not taken.
✗ Branch 662 not taken.
✗ Branch 664 not taken.
✗ Branch 665 not taken.
✗ Branch 667 not taken.
✗ Branch 668 not taken.
✗ Branch 670 not taken.
✗ Branch 671 not taken.
✗ Branch 673 not taken.
✗ Branch 674 not taken.
✗ Branch 676 not taken.
✗ Branch 677 not taken.
✗ Branch 679 not taken.
✗ Branch 680 not taken.
✗ Branch 682 not taken.
✗ Branch 683 not taken.
✗ Branch 685 not taken.
✗ Branch 686 not taken.
✗ Branch 688 not taken.
✗ Branch 689 not taken.
✗ Branch 691 not taken.
✗ Branch 692 not taken.
✗ Branch 694 not taken.
✗ Branch 695 not taken.
✗ Branch 697 not taken.
✗ Branch 698 not taken.
✗ Branch 700 not taken.
✗ Branch 701 not taken.
✗ Branch 703 not taken.
✗ Branch 704 not taken.
✗ Branch 706 not taken.
✗ Branch 707 not taken.
✗ Branch 709 not taken.
✗ Branch 710 not taken.
✗ Branch 712 not taken.
✗ Branch 713 not taken.
✗ Branch 715 not taken.
✗ Branch 716 not taken.
✗ Branch 718 not taken.
✗ Branch 719 not taken.
171188 return this->getChildMask().countOn();
1074 }
1075
1076
1077 template<typename ChildT, Index Log2Dim>
1078 inline Index64
1079 InternalNode<ChildT, Log2Dim>::onVoxelCount() const
1080 {
1081 Index64 sum = ChildT::NUM_VOXELS * mValueMask.countOn();
1082 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1083 sum += iter->onVoxelCount();
1084 }
1085 return sum;
1086 }
1087
1088
1089 template<typename ChildT, Index Log2Dim>
1090 inline Index64
1091 InternalNode<ChildT, Log2Dim>::offVoxelCount() const
1092 {
1093 Index64 sum = ChildT::NUM_VOXELS * (NUM_VALUES-mValueMask.countOn()-mChildMask.countOn());
1094 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1095 sum += iter->offVoxelCount();
1096 }
1097 return sum;
1098 }
1099
1100
1101 template<typename ChildT, Index Log2Dim>
1102 inline Index64
1103 InternalNode<ChildT, Log2Dim>::onLeafVoxelCount() const
1104 {
1105 Index64 sum = 0;
1106 for (ChildOnCIter iter = this->beginChildOn(); iter; ++iter) {
1107 sum += mNodes[iter.pos()].getChild()->onLeafVoxelCount();
1108 }
1109 return sum;
1110 }
1111
1112
1113 template<typename ChildT, Index Log2Dim>
1114 inline Index64
1115 InternalNode<ChildT, Log2Dim>::offLeafVoxelCount() const
1116 {
1117 Index64 sum = 0;
1118 for (ChildOnCIter iter = this->beginChildOn(); iter; ++iter) {
1119 sum += mNodes[iter.pos()].getChild()->offLeafVoxelCount();
1120 }
1121 return sum;
1122 }
1123
1124 template<typename ChildT, Index Log2Dim>
1125 inline Index64
1126 1 InternalNode<ChildT, Log2Dim>::onTileCount() const
1127 {
1128 3 Index64 sum = mValueMask.countOn();
1129
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (ChildOnCIter iter = this->cbeginChildOn(); LEVEL>1 && iter; ++iter) {
1130 2 sum += iter->onTileCount();
1131 }
1132 1 return sum;
1133 }
1134
1135 template<typename ChildT, Index Log2Dim>
1136 inline Index64
1137 InternalNode<ChildT, Log2Dim>::memUsage() const
1138 {
1139 Index64 sum = NUM_VALUES * sizeof(UnionType) + mChildMask.memUsage()
1140 + mValueMask.memUsage() + sizeof(mOrigin);
1141 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1142 sum += iter->memUsage();
1143 }
1144 return sum;
1145 }
1146
1147
1148 template<typename ChildT, Index Log2Dim>
1149 inline void
1150 5828 InternalNode<ChildT, Log2Dim>::evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels) const
1151 {
1152 11656 if (bbox.isInside(this->getNodeBoundingBox())) return;
1153
1154
2/2
✓ Branch 0 taken 13628 times.
✓ Branch 1 taken 2761 times.
32778 for (ValueOnCIter i = this->cbeginValueOn(); i; ++i) {
1155 27256 bbox.expand(i.getCoord(), ChildT::DIM);
1156 }
1157
2/2
✓ Branch 0 taken 120649 times.
✓ Branch 1 taken 2761 times.
246820 for (ChildOnCIter i = this->cbeginChildOn(); i; ++i) {
1158 241298 i->evalActiveBoundingBox(bbox, visitVoxels);
1159 }
1160 }
1161
1162
1163 ////////////////////////////////////////
1164
1165
1166 template<typename ChildT, Index Log2Dim>
1167 inline void
1168 864 InternalNode<ChildT, Log2Dim>::prune(const ValueType& tolerance)
1169 {
1170 864 bool state = false;
1171 736 ValueType value = zeroVal<ValueType>();
1172
2/2
✓ Branch 0 taken 22128 times.
✓ Branch 1 taken 432 times.
45120 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
1173 const Index i = iter.pos();
1174 ChildT* child = mNodes[i].getChild();
1175
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
434 child->prune(tolerance);
1176
2/5
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
✓ Branch 2 taken 21938 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
44256 if (child->isConstant(value, state, tolerance)) {
1177
1/2
✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
734 delete child;
1178 380 mChildMask.setOff(i);
1179
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 132 times.
380 mValueMask.set(i, state);
1180 mNodes[i].setValue(value);
1181 }
1182 }
1183 }
1184
1185
1186 ////////////////////////////////////////
1187
1188
1189 template<typename ChildT, Index Log2Dim>
1190 template<typename NodeT>
1191 inline NodeT*
1192 126866 InternalNode<ChildT, Log2Dim>::stealNode(const Coord& xyz, const ValueType& value, bool state)
1193 {
1194 if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
1195 NodeT::LEVEL > ChildT::LEVEL) return nullptr;
1196 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
1197 const Index n = this->coordToOffset(xyz);
1198
2/2
✓ Branch 0 taken 63431 times.
✓ Branch 1 taken 2 times.
126866 if (mChildMask.isOff(n)) return nullptr;
1199 ChildT* child = mNodes[n].getChild();
1200 if (std::is_same<NodeT, ChildT>::value) {
1201 63498 mChildMask.setOff(n);
1202
2/2
✓ Branch 0 taken 3174 times.
✓ Branch 1 taken 28575 times.
63498 mValueMask.set(n, state);
1203 mNodes[n].setValue(value);
1204 }
1205 return (std::is_same<NodeT, ChildT>::value)
1206 63364 ? reinterpret_cast<NodeT*>(child)
1207 126862 : child->template stealNode<NodeT>(xyz, value, state);
1208 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
1209 }
1210
1211
1212 ////////////////////////////////////////
1213
1214
1215 template<typename ChildT, Index Log2Dim>
1216 template<typename NodeT>
1217 inline NodeT*
1218 156456 InternalNode<ChildT, Log2Dim>::probeNode(const Coord& xyz)
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
2/2
✓ Branch 0 taken 60650 times.
✓ Branch 1 taken 19306 times.
156456 if (mChildMask.isOff(n)) return nullptr;
1225 ChildT* child = mNodes[n].getChild();
1226 return (std::is_same<NodeT, ChildT>::value)
1227 76382 ? reinterpret_cast<NodeT*>(child)
1228 117844 : child->template probeNode<NodeT>(xyz);
1229 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
1230 }
1231
1232
1233 template<typename ChildT, Index Log2Dim>
1234 template<typename NodeT, typename AccessorT>
1235 inline NodeT*
1236 7144828 InternalNode<ChildT, Log2Dim>::probeNodeAndCache(const Coord& xyz, AccessorT& acc)
1237 {
1238 if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
1239 NodeT::LEVEL > ChildT::LEVEL) return nullptr;
1240 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
1241 const Index n = this->coordToOffset(xyz);
1242
2/2
✓ Branch 0 taken 3063946 times.
✓ Branch 1 taken 508468 times.
7144828 if (mChildMask.isOff(n)) return nullptr;
1243 ChildT* child = mNodes[n].getChild();
1244 6127892 acc.insert(xyz, child);
1245 return (std::is_same<NodeT, ChildT>::value)
1246 1690896 ? reinterpret_cast<NodeT*>(child)
1247 6127892 : child->template probeNodeAndCache<NodeT>(xyz, acc);
1248 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
1249 }
1250
1251
1252 template<typename ChildT, Index Log2Dim>
1253 template<typename NodeT>
1254 inline const NodeT*
1255 358846 InternalNode<ChildT, Log2Dim>::probeConstNode(const Coord& xyz) 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
2/2
✓ Branch 0 taken 166101 times.
✓ Branch 1 taken 13322 times.
358846 if (mChildMask.isOff(n)) return nullptr;
1262 const ChildT* child = mNodes[n].getChild();
1263 return (std::is_same<NodeT, ChildT>::value)
1264 179202 ? reinterpret_cast<const NodeT*>(child)
1265 332202 : child->template probeConstNode<NodeT>(xyz);
1266 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
1267 }
1268
1269
1270 template<typename ChildT, Index Log2Dim>
1271 template<typename NodeT, typename AccessorT>
1272 inline const NodeT*
1273 806133010 InternalNode<ChildT, Log2Dim>::probeConstNodeAndCache(const Coord& xyz, AccessorT& acc) const
1274 {
1275 if ((NodeT::LEVEL == ChildT::LEVEL && !(std::is_same<NodeT, ChildT>::value)) ||
1276 NodeT::LEVEL > ChildT::LEVEL) return nullptr;
1277 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
1278 const Index n = this->coordToOffset(xyz);
1279
2/2
✓ Branch 0 taken 1273827 times.
✓ Branch 1 taken 401792678 times.
806133010 if (mChildMask.isOff(n)) return nullptr;
1280 const ChildT* child = mNodes[n].getChild();
1281 2547654 acc.insert(xyz, child);
1282 return (std::is_same<NodeT, ChildT>::value)
1283 1541734 ? reinterpret_cast<const NodeT*>(child)
1284 2547654 : child->template probeConstNodeAndCache<NodeT>(xyz, acc);
1285 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
1286 }
1287
1288
1289 ////////////////////////////////////////
1290
1291
1292 template<typename ChildT, Index Log2Dim>
1293 inline typename ChildT::LeafNodeType*
1294 InternalNode<ChildT, Log2Dim>::probeLeaf(const Coord& xyz)
1295 {
1296 1 return this->template probeNode<LeafNodeType>(xyz);
1297 }
1298
1299
1300 template<typename ChildT, Index Log2Dim>
1301 template<typename AccessorT>
1302 inline typename ChildT::LeafNodeType*
1303 InternalNode<ChildT, Log2Dim>::probeLeafAndCache(const Coord& xyz, AccessorT& acc)
1304 {
1305 return this->template probeNodeAndCache<LeafNodeType>(xyz, acc);
1306 }
1307
1308
1309 template<typename ChildT, Index Log2Dim>
1310 template<typename AccessorT>
1311 inline const typename ChildT::LeafNodeType*
1312 InternalNode<ChildT, Log2Dim>::probeLeafAndCache(const Coord& xyz, AccessorT& acc) const
1313 {
1314 return this->probeConstLeafAndCache(xyz, acc);
1315 }
1316
1317
1318 template<typename ChildT, Index Log2Dim>
1319 inline const typename ChildT::LeafNodeType*
1320 InternalNode<ChildT, Log2Dim>::probeConstLeaf(const Coord& xyz) const
1321 {
1322 return this->template probeConstNode<LeafNodeType>(xyz);
1323 }
1324
1325
1326 template<typename ChildT, Index Log2Dim>
1327 template<typename AccessorT>
1328 inline const typename ChildT::LeafNodeType*
1329 InternalNode<ChildT, Log2Dim>::probeConstLeafAndCache(const Coord& xyz, AccessorT& acc) const
1330 {
1331 return this->template probeConstNodeAndCache<LeafNodeType>(xyz, acc);
1332 }
1333
1334
1335 ////////////////////////////////////////
1336
1337
1338 template<typename ChildT, Index Log2Dim>
1339 inline void
1340 773192 InternalNode<ChildT, Log2Dim>::addLeaf(LeafNodeType* leaf)
1341 {
1342
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 386596 times.
773192 assert(leaf != nullptr);
1343 const Coord& xyz = leaf->origin();
1344 const Index n = this->coordToOffset(xyz);
1345 ChildT* child = nullptr;
1346
2/2
✓ Branch 0 taken 349129 times.
✓ Branch 1 taken 37467 times.
773192 if (mChildMask.isOff(n)) {
1347 if (ChildT::LEVEL>0) {
1348 40814 child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n));
1349 } else {
1350 child = reinterpret_cast<ChildT*>(leaf);
1351 }
1352 698258 this->setChildNode(n, child);
1353 } else {
1354 if (ChildT::LEVEL>0) {
1355 child = mNodes[n].getChild();
1356 } else {
1357
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
4 delete mNodes[n].getChild();
1358 child = reinterpret_cast<ChildT*>(leaf);
1359 mNodes[n].setChild(child);
1360 }
1361 }
1362 115746 child->addLeaf(leaf);
1363 773192 }
1364
1365
1366 template<typename ChildT, Index Log2Dim>
1367 template<typename AccessorT>
1368 inline void
1369 247342 InternalNode<ChildT, Log2Dim>::addLeafAndCache(LeafNodeType* leaf, AccessorT& acc)
1370 {
1371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 123671 times.
247342 assert(leaf != nullptr);
1372 const Coord& xyz = leaf->origin();
1373 const Index n = this->coordToOffset(xyz);
1374 ChildT* child = nullptr;
1375
2/2
✓ Branch 0 taken 122423 times.
✓ Branch 1 taken 1248 times.
247342 if (mChildMask.isOff(n)) {
1376 if (ChildT::LEVEL>0) {
1377 6408 child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n));
1378 6408 acc.insert(xyz, child);//we only cache internal nodes
1379 } else {
1380 child = reinterpret_cast<ChildT*>(leaf);
1381 }
1382 244846 this->setChildNode(n, child);
1383 } else {
1384 if (ChildT::LEVEL>0) {
1385 child = mNodes[n].getChild();
1386 2464 acc.insert(xyz, child);//we only cache internal nodes
1387 } else {
1388
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
64 delete mNodes[n].getChild();
1389 child = reinterpret_cast<ChildT*>(leaf);
1390 mNodes[n].setChild(child);
1391 }
1392 }
1393 8872 child->addLeafAndCache(leaf, acc);
1394 247342 }
1395
1396
1397 ////////////////////////////////////////
1398
1399
1400 template<typename ChildT, Index Log2Dim>
1401 inline bool
1402 151160 InternalNode<ChildT, Log2Dim>::addChild(ChildT* child)
1403 {
1404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 75580 times.
151160 assert(child);
1405 const Coord& xyz = child->origin();
1406 // verify that the child belongs in this internal node
1407 2 if (Coord((xyz & ~(DIM-1))) != this->origin()) return false;
1408 // compute the offset and insert the child node
1409 const Index n = this->coordToOffset(xyz);
1410 // this also deletes an existing child node
1411 151158 this->resetChildNode(n, child);
1412 151158 return true;
1413 }
1414
1415
1416 template<typename ChildT, Index Log2Dim>
1417 inline void
1418 646716 InternalNode<ChildT, Log2Dim>::addTile(Index n, const ValueType& value, bool state)
1419 {
1420
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 323358 times.
646716 assert(n < NUM_VALUES);
1421 646716 this->makeChildNodeEmpty(n, value);
1422
2/2
✓ Branch 0 taken 51040 times.
✓ Branch 1 taken 272318 times.
646716 mValueMask.set(n, state);
1423 646716 }
1424
1425
1426 template<typename ChildT, Index Log2Dim>
1427 inline void
1428 35504 InternalNode<ChildT, Log2Dim>::addTile(Index level, const Coord& xyz,
1429 const ValueType& value, bool state)
1430 {
1431
1/2
✓ Branch 0 taken 17752 times.
✗ Branch 1 not taken.
35504 if (LEVEL >= level) {
1432 const Index n = this->coordToOffset(xyz);
1433
2/2
✓ Branch 0 taken 14292 times.
✓ Branch 1 taken 3460 times.
35504 if (mChildMask.isOff(n)) {// tile case
1434
2/2
✓ Branch 0 taken 3673 times.
✓ Branch 1 taken 10619 times.
28584 if (LEVEL > level) {
1435
1/2
✓ Branch 3 taken 94 times.
✗ Branch 4 not taken.
7346 ChildT* child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n));
1436 7346 this->setChildNode(n, child);
1437 7346 child->addTile(level, xyz, value, state);
1438 } else {
1439
2/2
✓ Branch 0 taken 10605 times.
✓ Branch 1 taken 14 times.
21238 mValueMask.set(n, state);
1440 mNodes[n].setValue(value);
1441 }
1442 } else {// child branch case
1443 ChildT* child = mNodes[n].getChild();
1444
2/2
✓ Branch 0 taken 3459 times.
✓ Branch 1 taken 1 times.
6920 if (LEVEL > level) {
1445 6918 child->addTile(level, xyz, value, state);
1446 } else {
1447
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
2 delete child;
1448 2 mChildMask.setOff(n);
1449
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
2 mValueMask.set(n, state);
1450 mNodes[n].setValue(value);
1451 }
1452 }
1453 }
1454 35504 }
1455
1456
1457 template<typename ChildT, Index Log2Dim>
1458 template<typename AccessorT>
1459 inline void
1460 14654 InternalNode<ChildT, Log2Dim>::addTileAndCache(Index level, const Coord& xyz,
1461 const ValueType& value, bool state, AccessorT& acc)
1462 {
1463
1/2
✓ Branch 0 taken 7327 times.
✗ Branch 1 not taken.
14654 if (LEVEL >= level) {
1464 const Index n = this->coordToOffset(xyz);
1465
2/2
✓ Branch 0 taken 353 times.
✓ Branch 1 taken 6974 times.
14654 if (mChildMask.isOff(n)) {// tile case
1466
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 342 times.
706 if (LEVEL > level) {
1467
0/2
✗ Branch 3 not taken.
✗ Branch 4 not taken.
22 ChildT* child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n));
1468 22 this->setChildNode(n, child);
1469 22 acc.insert(xyz, child);
1470 22 child->addTileAndCache(level, xyz, value, state, acc);
1471 } else {
1472
1/2
✓ Branch 0 taken 342 times.
✗ Branch 1 not taken.
684 mValueMask.set(n, state);
1473 mNodes[n].setValue(value);
1474 }
1475 } else {// child branch case
1476 ChildT* child = mNodes[n].getChild();
1477
2/2
✓ Branch 0 taken 1238 times.
✓ Branch 1 taken 5736 times.
13948 if (LEVEL > level) {
1478 2476 acc.insert(xyz, child);
1479 2476 child->addTileAndCache(level, xyz, value, state, acc);
1480 } else {
1481
1/2
✓ Branch 0 taken 5736 times.
✗ Branch 1 not taken.
11472 delete child;
1482 11472 mChildMask.setOff(n);
1483
1/2
✓ Branch 0 taken 5736 times.
✗ Branch 1 not taken.
11472 mValueMask.set(n, state);
1484 mNodes[n].setValue(value);
1485 }
1486 }
1487 }
1488 14654 }
1489
1490
1491 ////////////////////////////////////////
1492
1493
1494 template<typename ChildT, Index Log2Dim>
1495 inline typename ChildT::LeafNodeType*
1496 15760 InternalNode<ChildT, Log2Dim>::touchLeaf(const Coord& xyz)
1497 {
1498 const Index n = this->coordToOffset(xyz);
1499 ChildT* child = nullptr;
1500
2/2
✓ Branch 0 taken 3507 times.
✓ Branch 1 taken 4373 times.
15760 if (mChildMask.isOff(n)) {
1501
1/2
✓ Branch 3 taken 83 times.
✗ Branch 4 not taken.
7014 child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n));
1502 7014 this->setChildNode(n, child);
1503 } else {
1504 child = mNodes[n].getChild();
1505 }
1506 15760 return child->touchLeaf(xyz);
1507 }
1508
1509
1510 template<typename ChildT, Index Log2Dim>
1511 template<typename AccessorT>
1512 inline typename ChildT::LeafNodeType*
1513 1027698 InternalNode<ChildT, Log2Dim>::touchLeafAndCache(const Coord& xyz, AccessorT& acc)
1514 {
1515 const Index n = this->coordToOffset(xyz);
1516
2/2
✓ Branch 0 taken 170184 times.
✓ Branch 1 taken 343665 times.
1027698 if (mChildMask.isOff(n)) {
1517
1/2
✓ Branch 3 taken 7674 times.
✗ Branch 4 not taken.
340368 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), mValueMask.isOn(n)));
1518 }
1519 1027698 acc.insert(xyz, mNodes[n].getChild());
1520 1027698 return mNodes[n].getChild()->touchLeafAndCache(xyz, acc);
1521 }
1522
1523
1524 ////////////////////////////////////////
1525
1526
1527 template<typename ChildT, Index Log2Dim>
1528 inline bool
1529
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
68606 InternalNode<ChildT, Log2Dim>::isConstant(ValueType& firstValue, bool& state,
1530 const ValueType& tolerance) const
1531 {
1532
3/6
✓ Branch 0 taken 32155 times.
✓ Branch 1 taken 2148 times.
✓ Branch 2 taken 32147 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
132916 if (!mChildMask.isOff() || !mValueMask.isConstant(state)) return false;// early termination
1533
1534 64272 firstValue = mNodes[0].getValue();
1535
2/6
✓ Branch 0 taken 133849709 times.
✓ Branch 1 taken 32147 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
267763712 for (Index i = 1; i < NUM_VALUES; ++i) {
1536
2/6
✓ Branch 0 taken 133403354 times.
✓ Branch 1 taken 188370 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
267183448 if (!math::isApproxEqual(mNodes[i].getValue(), firstValue, tolerance)) {
1537 return false; // early termination
1538 }
1539 }
1540 return true;
1541 }
1542
1543
1544 ////////////////////////////////////////
1545
1546
1547 template<typename ChildT, Index Log2Dim>
1548 inline bool
1549
1/2
✓ Branch 0 taken 296 times.
✗ Branch 1 not taken.
3146 InternalNode<ChildT, Log2Dim>::isConstant(ValueType& minValue,
1550 ValueType& maxValue,
1551 bool& state,
1552 const ValueType& tolerance) const
1553 {
1554
1555
3/4
✓ Branch 0 taken 316 times.
✓ Branch 1 taken 1257 times.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
3186 if (!mChildMask.isOff() || !mValueMask.isConstant(state)) return false;// early termination
1556 630 minValue = maxValue = mNodes[0].getValue();
1557
2/2
✓ Branch 0 taken 350917 times.
✓ Branch 1 taken 315 times.
702464 for (Index i = 1; i < NUM_VALUES; ++i) {
1558 const ValueType& v = mNodes[i].getValue();
1559
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 350917 times.
✗ Branch 2 not taken.
701834 if (v < minValue) {
1560 if ((maxValue - v) > tolerance) return false;// early termination
1561 minValue = v;
1562
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 350917 times.
✗ Branch 2 not taken.
701834 } else if (v > maxValue) {
1563 if ((v - minValue) > tolerance) return false;// early termination
1564 maxValue = v;
1565 }
1566 }
1567 return true;
1568 }
1569
1570
1571 ////////////////////////////////////////
1572
1573
1574 template<typename ChildT, Index Log2Dim>
1575 inline bool
1576 18422 InternalNode<ChildT, Log2Dim>::hasActiveTiles() const
1577 {
1578 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
1579
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
18949 const bool anyActiveTiles = !mValueMask.isOff();
1580
2/2
✓ Branch 0 taken 9361 times.
✓ Branch 1 taken 5 times.
18422 if (LEVEL==1 || anyActiveTiles) return anyActiveTiles;
1581
2/2
✓ Branch 0 taken 9383 times.
✓ Branch 1 taken 6816 times.
31792 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
1582
2/2
✓ Branch 0 taken 2545 times.
✓ Branch 1 taken 6838 times.
18453 if (iter->hasActiveTiles()) return true;
1583 }
1584 13339 return false;
1585 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
1586 }
1587
1588
1589 template<typename ChildT, Index Log2Dim>
1590 inline bool
1591 126779646 InternalNode<ChildT, Log2Dim>::isValueOn(const Coord& xyz) const
1592 {
1593 const Index n = this->coordToOffset(xyz);
1594
2/2
✓ Branch 0 taken 2554922 times.
✓ Branch 1 taken 60834901 times.
131889490 if (this->isChildMaskOff(n)) return this->isValueMaskOn(n);
1595 121669802 return mNodes[n].getChild()->isValueOn(xyz);
1596 }
1597
1598 template<typename ChildT, Index Log2Dim>
1599 template<typename AccessorT>
1600 inline bool
1601 501093166 InternalNode<ChildT, Log2Dim>::isValueOnAndCache(const Coord& xyz, AccessorT& acc) const
1602 {
1603 const Index n = this->coordToOffset(xyz);
1604
2/2
✓ Branch 0 taken 246271400 times.
✓ Branch 1 taken 4275183 times.
993635966 if (this->isChildMaskOff(n)) return this->isValueMaskOn(n);
1605 8550240 acc.insert(xyz, mNodes[n].getChild());
1606 8550366 return mNodes[n].getChild()->isValueOnAndCache(xyz, acc);
1607 }
1608
1609
1610 template<typename ChildT, Index Log2Dim>
1611 inline const typename ChildT::ValueType&
1612 114326376 InternalNode<ChildT, Log2Dim>::getValue(const Coord& xyz) const
1613 {
1614 const Index n = this->coordToOffset(xyz);
1615
2/2
✓ Branch 0 taken 17301502 times.
✓ Branch 1 taken 19461938 times.
105703538 return this->isChildMaskOff(n) ? mNodes[n].getValue()
1616
2/2
✓ Branch 0 taken 4311419 times.
✓ Branch 1 taken 16088329 times.
114326376 : mNodes[n].getChild()->getValue(xyz);
1617 }
1618
1619 template<typename ChildT, Index Log2Dim>
1620 template<typename AccessorT>
1621 inline const typename ChildT::ValueType&
1622 10331632662 InternalNode<ChildT, Log2Dim>::getValueAndCache(const Coord& xyz, AccessorT& acc) const
1623 {
1624 const Index n = this->coordToOffset(xyz);
1625
2/2
✓ Branch 0 taken 196770741 times.
✓ Branch 1 taken 4969045590 times.
10331632662 if (this->isChildMaskOn(n)) {
1626 393486194 acc.insert(xyz, mNodes[n].getChild());
1627 393541482 return mNodes[n].getChild()->getValueAndCache(xyz, acc);
1628 }
1629 9938091180 return mNodes[n].getValue();
1630 }
1631
1632
1633 template<typename ChildT, Index Log2Dim>
1634 inline Index
1635 620218 InternalNode<ChildT, Log2Dim>::getValueLevel(const Coord& xyz) const
1636 {
1637 const Index n = this->coordToOffset(xyz);
1638
2/2
✓ Branch 0 taken 310030 times.
✓ Branch 1 taken 79 times.
620218 return this->isChildMaskOff(n) ? LEVEL : mNodes[n].getChild()->getValueLevel(xyz);
1639 }
1640
1641 template<typename ChildT, Index Log2Dim>
1642 template<typename AccessorT>
1643 inline Index
1644 12770174 InternalNode<ChildT, Log2Dim>::getValueLevelAndCache(const Coord& xyz, AccessorT& acc) const
1645 {
1646 const Index n = this->coordToOffset(xyz);
1647
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 6384853 times.
12770174 if (this->isChildMaskOn(n)) {
1648 234 acc.insert(xyz, mNodes[n].getChild());
1649 468 return mNodes[n].getChild()->getValueLevelAndCache(xyz, acc);
1650 }
1651 return LEVEL;
1652 }
1653
1654
1655 template<typename ChildT, Index Log2Dim>
1656 inline bool
1657 639002 InternalNode<ChildT, Log2Dim>::probeValue(const Coord& xyz, ValueType& value) const
1658 {
1659 const Index n = this->coordToOffset(xyz);
1660
2/2
✓ Branch 0 taken 311415 times.
✓ Branch 1 taken 8086 times.
639002 if (this->isChildMaskOff(n)) {
1661 622830 value = mNodes[n].getValue();
1662 622830 return this->isValueMaskOn(n);
1663 }
1664 16172 return mNodes[n].getChild()->probeValue(xyz, value);
1665 }
1666
1667 template<typename ChildT, Index Log2Dim>
1668 template<typename AccessorT>
1669 inline bool
1670 2617807248 InternalNode<ChildT, Log2Dim>::probeValueAndCache(const Coord& xyz,
1671 ValueType& value, AccessorT& acc) const
1672 {
1673 const Index n = this->coordToOffset(xyz);
1674
2/2
✓ Branch 0 taken 148297750 times.
✓ Branch 1 taken 1160605874 times.
2617807248 if (this->isChildMaskOn(n)) {
1675 296595500 acc.insert(xyz, mNodes[n].getChild());
1676 296595500 return mNodes[n].getChild()->probeValueAndCache(xyz, value, acc);
1677 }
1678 2321211544 value = mNodes[n].getValue();
1679 2321211748 return this->isValueMaskOn(n);
1680 }
1681
1682
1683 template<typename ChildT, Index Log2Dim>
1684 inline void
1685 136 InternalNode<ChildT, Log2Dim>::setValueOff(const Coord& xyz)
1686 {
1687 const Index n = this->coordToOffset(xyz);
1688 bool hasChild = this->isChildMaskOn(n);
1689
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
140 if (!hasChild && this->isValueMaskOn(n)) {
1690 // If the voxel belongs to a constant tile that is active,
1691 // a child subtree must be constructed.
1692 hasChild = true;
1693
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
6 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), /*active=*/true));
1694 }
1695
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
136 if (hasChild) mNodes[n].getChild()->setValueOff(xyz);
1696 136 }
1697
1698
1699 template<typename ChildT, Index Log2Dim>
1700 inline void
1701 InternalNode<ChildT, Log2Dim>::setValueOn(const Coord& xyz)
1702 {
1703 const Index n = this->coordToOffset(xyz);
1704 bool hasChild = this->isChildMaskOn(n);
1705 if (!hasChild && !this->isValueMaskOn(n)) {
1706 // If the voxel belongs to a constant tile that is inactive,
1707 // a child subtree must be constructed.
1708 hasChild = true;
1709 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), /*active=*/false));
1710 }
1711 if (hasChild) mNodes[n].getChild()->setValueOn(xyz);
1712 }
1713
1714
1715 template<typename ChildT, Index Log2Dim>
1716 inline void
1717 648 InternalNode<ChildT, Log2Dim>::setValueOff(const Coord& xyz, const ValueType& value)
1718 {
1719 const Index n = InternalNode::coordToOffset(xyz);
1720 bool hasChild = this->isChildMaskOn(n);
1721
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 284 times.
648 if (!hasChild) {
1722 const bool active = this->isValueMaskOn(n);
1723
3/4
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
80 if (active || !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1724 // If the voxel belongs to a tile that is either active or that
1725 // has a constant value that is different from the one provided,
1726 // a child subtree must be constructed.
1727 hasChild = true;
1728
1/2
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
82 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1729 }
1730 }
1731
1/2
✓ Branch 0 taken 284 times.
✗ Branch 1 not taken.
648 if (hasChild) mNodes[n].getChild()->setValueOff(xyz, value);
1732 648 }
1733
1734 template<typename ChildT, Index Log2Dim>
1735 template<typename AccessorT>
1736 inline void
1737 478163502 InternalNode<ChildT, Log2Dim>::setValueOffAndCache(const Coord& xyz,
1738 const ValueType& value, AccessorT& acc)
1739 {
1740 const Index n = InternalNode::coordToOffset(xyz);
1741 bool hasChild = this->isChildMaskOn(n);
1742
2/2
✓ Branch 0 taken 239017631 times.
✓ Branch 1 taken 64120 times.
478163502 if (!hasChild) {
1743 const bool active = this->isValueMaskOn(n);
1744
3/4
✓ Branch 0 taken 239017631 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 911 times.
✓ Branch 3 taken 188264252 times.
478035262 if (active || !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1745 // If the voxel belongs to a tile that is either active or that
1746 // has a constant value that is different from the one provided,
1747 // a child subtree must be constructed.
1748 hasChild = true;
1749
1/2
✓ Branch 2 taken 925 times.
✗ Branch 3 not taken.
1982 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1750 }
1751 }
1752
2/2
✓ Branch 0 taken 64120 times.
✓ Branch 1 taken 239016640 times.
478161520 if (hasChild) {
1753 ChildT* child = mNodes[n].getChild();
1754 130222 acc.insert(xyz, child);
1755 132 child->setValueOffAndCache(xyz, value, acc);
1756 }
1757 478163502 }
1758
1759
1760 template<typename ChildT, Index Log2Dim>
1761 inline void
1762 1266024 InternalNode<ChildT, Log2Dim>::setValueOn(const Coord& xyz, const ValueType& value)
1763 {
1764 const Index n = this->coordToOffset(xyz);
1765 bool hasChild = this->isChildMaskOn(n);
1766
2/2
✓ Branch 0 taken 127912 times.
✓ Branch 1 taken 505100 times.
1266024 if (!hasChild) {
1767 const bool active = this->isValueMaskOn(n); // tile's active state
1768
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 127900 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
255824 if (!active || !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1769 // If the voxel belongs to a tile that is either inactive or that
1770 // has a constant value that is different from the one provided,
1771 // a child subtree must be constructed.
1772 hasChild = true;
1773
1/2
✓ Branch 2 taken 98467 times.
✗ Branch 3 not taken.
287128 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1774 }
1775 }
1776
1/2
✓ Branch 0 taken 505100 times.
✗ Branch 1 not taken.
1266024 if (hasChild) mNodes[n].getChild()->setValueOn(xyz, value);
1777 1266024 }
1778
1779 template<typename ChildT, Index Log2Dim>
1780 template<typename AccessorT>
1781 inline void
1782 43143130 InternalNode<ChildT, Log2Dim>::setValueAndCache(const Coord& xyz,
1783 const ValueType& value, AccessorT& acc)
1784 {
1785 const Index n = this->coordToOffset(xyz);
1786 bool hasChild = this->isChildMaskOn(n);
1787
2/2
✓ Branch 0 taken 478865 times.
✓ Branch 1 taken 21092700 times.
43143130 if (!hasChild) {
1788 const bool active = this->isValueMaskOn(n);
1789
3/4
✓ Branch 0 taken 246 times.
✓ Branch 1 taken 478619 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 246 times.
957730 if (!active || !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1790 // If the voxel belongs to a tile that is either inactive or that
1791 // has a constant value that is different from the one provided,
1792 // a child subtree must be constructed.
1793 hasChild = true;
1794
1/2
✓ Branch 2 taken 439025 times.
✗ Branch 3 not taken.
1019738 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1795 }
1796 }
1797
2/2
✓ Branch 0 taken 21092700 times.
✓ Branch 1 taken 246 times.
42185892 if (hasChild) {
1798 43127900 acc.insert(xyz, mNodes[n].getChild());
1799 11704886 mNodes[n].getChild()->setValueAndCache(xyz, value, acc);
1800 }
1801 43143130 }
1802
1803
1804 template<typename ChildT, Index Log2Dim>
1805 inline void
1806 64 InternalNode<ChildT, Log2Dim>::setValueOnly(const Coord& xyz, const ValueType& value)
1807 {
1808 const Index n = this->coordToOffset(xyz);
1809 bool hasChild = this->isChildMaskOn(n);
1810
3/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
64 if (!hasChild && !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1811 // If the voxel has a tile value that is different from the one provided,
1812 // a child subtree must be constructed.
1813 const bool active = this->isValueMaskOn(n);
1814 hasChild = true;
1815
1/2
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
40 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1816 }
1817
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
64 if (hasChild) mNodes[n].getChild()->setValueOnly(xyz, value);
1818 64 }
1819
1820 template<typename ChildT, Index Log2Dim>
1821 template<typename AccessorT>
1822 inline void
1823 89196 InternalNode<ChildT, Log2Dim>::setValueOnlyAndCache(const Coord& xyz,
1824 const ValueType& value, AccessorT& acc)
1825 {
1826 const Index n = this->coordToOffset(xyz);
1827 bool hasChild = this->isChildMaskOn(n);
1828
3/4
✓ Branch 0 taken 25129 times.
✓ Branch 1 taken 19469 times.
✓ Branch 2 taken 25129 times.
✗ Branch 3 not taken.
89196 if (!hasChild && !math::isExactlyEqual(mNodes[n].getValue(), value)) {
1829 // If the voxel has a tile value that is different from the one provided,
1830 // a child subtree must be constructed.
1831 const bool active = this->isValueMaskOn(n);
1832 hasChild = true;
1833
1/2
✓ Branch 2 taken 23815 times.
✗ Branch 3 not taken.
50258 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1834 }
1835
1/2
✓ Branch 0 taken 19469 times.
✗ Branch 1 not taken.
38938 if (hasChild) {
1836 89196 acc.insert(xyz, mNodes[n].getChild());
1837 6984 mNodes[n].getChild()->setValueOnlyAndCache(xyz, value, acc);
1838 }
1839 }
1840
1841
1842 template<typename ChildT, Index Log2Dim>
1843 inline void
1844 132 InternalNode<ChildT, Log2Dim>::setActiveState(const Coord& xyz, bool on)
1845 {
1846 const Index n = this->coordToOffset(xyz);
1847 bool hasChild = this->isChildMaskOn(n);
1848
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 16 times.
132 if (!hasChild) {
1849
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 2 times.
100 if (on != this->isValueMaskOn(n)) {
1850 // If the voxel belongs to a tile with the wrong active state,
1851 // then a child subtree must be constructed.
1852 // 'on' is the voxel's new state, therefore '!on' is the tile's current state
1853 hasChild = true;
1854
1/2
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
98 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), !on));
1855 }
1856 }
1857
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 2 times.
132 if (hasChild) mNodes[n].getChild()->setActiveState(xyz, on);
1858 132 }
1859
1860 template<typename ChildT, Index Log2Dim>
1861 template<typename AccessorT>
1862 inline void
1863 23142398 InternalNode<ChildT, Log2Dim>::setActiveStateAndCache(const Coord& xyz, bool on, AccessorT& acc)
1864 {
1865 const Index n = this->coordToOffset(xyz);
1866 bool hasChild = this->isChildMaskOn(n);
1867
2/2
✓ Branch 0 taken 1340532 times.
✓ Branch 1 taken 10230667 times.
23142398 if (!hasChild) {
1868
1/2
✓ Branch 0 taken 1340532 times.
✗ Branch 1 not taken.
2681064 if (on != this->isValueMaskOn(n)) {
1869 // If the voxel belongs to a tile with the wrong active state,
1870 // then a child subtree must be constructed.
1871 // 'on' is the voxel's new state, therefore '!on' is the tile's current state
1872 hasChild = true;
1873
1/2
✓ Branch 2 taken 1269 times.
✗ Branch 3 not taken.
2681064 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), !on));
1874 }
1875 }
1876
1/2
✓ Branch 0 taken 10230667 times.
✗ Branch 1 not taken.
20461334 if (hasChild) {
1877 ChildT* child = mNodes[n].getChild();
1878 23142398 acc.insert(xyz, child);
1879 23142398 child->setActiveStateAndCache(xyz, on, acc);
1880 }
1881 23142398 }
1882
1883
1884 template<typename ChildT, Index Log2Dim>
1885 inline void
1886 20 InternalNode<ChildT, Log2Dim>::setValuesOn()
1887 {
1888 20 mValueMask = !mChildMask;
1889
2/2
✓ Branch 0 taken 2729 times.
✓ Branch 1 taken 10 times.
5478 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
1890 4 mNodes[iter.pos()].getChild()->setValuesOn();
1891 }
1892 }
1893
1894
1895 template<typename ChildT, Index Log2Dim>
1896 template<typename ModifyOp>
1897 inline void
1898 26 InternalNode<ChildT, Log2Dim>::modifyValue(const Coord& xyz, const ModifyOp& op)
1899 {
1900 const Index n = InternalNode::coordToOffset(xyz);
1901 bool hasChild = this->isChildMaskOn(n);
1902
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 8 times.
26 if (!hasChild) {
1903 // Need to create a child if the tile is inactive,
1904 // in order to activate voxel (x, y, z).
1905 const bool active = this->isValueMaskOn(n);
1906 10 bool createChild = !active;
1907
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
10 if (!createChild) {
1908 // Need to create a child if applying the functor
1909 // to the tile value produces a different value.
1910 const ValueType& tileVal = mNodes[n].getValue();
1911
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
10 ValueType modifiedVal = tileVal;
1912 op(modifiedVal);
1913 10 createChild = !math::isExactlyEqual(tileVal, modifiedVal);
1914 }
1915
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
10 if (createChild) {
1916 hasChild = true;
1917
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
12 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1918 }
1919 }
1920
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
26 if (hasChild) mNodes[n].getChild()->modifyValue(xyz, op);
1921 26 }
1922
1923 template<typename ChildT, Index Log2Dim>
1924 template<typename ModifyOp, typename AccessorT>
1925 inline void
1926 266527302 InternalNode<ChildT, Log2Dim>::modifyValueAndCache(const Coord& xyz, const ModifyOp& op,
1927 AccessorT& acc)
1928 {
1929 const Index n = InternalNode::coordToOffset(xyz);
1930 bool hasChild = this->isChildMaskOn(n);
1931
2/2
✓ Branch 0 taken 16868 times.
✓ Branch 1 taken 133246783 times.
266527302 if (!hasChild) {
1932 // Need to create a child if the tile is inactive,
1933 // in order to activate voxel (x, y, z).
1934 const bool active = this->isValueMaskOn(n);
1935 33736 bool createChild = !active;
1936
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16868 times.
33736 if (!createChild) {
1937 // Need to create a child if applying the functor
1938 // to the tile value produces a different value.
1939 const ValueType& tileVal = mNodes[n].getValue();
1940 ValueType modifiedVal = tileVal;
1941 op(modifiedVal);
1942 createChild = !math::isExactlyEqual(tileVal, modifiedVal);
1943 }
1944
1/2
✓ Branch 0 taken 16868 times.
✗ Branch 1 not taken.
33736 if (createChild) {
1945 hasChild = true;
1946
1/2
✓ Branch 2 taken 16489 times.
✗ Branch 3 not taken.
33736 this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active));
1947 }
1948 }
1949
1/2
✓ Branch 0 taken 133246783 times.
✗ Branch 1 not taken.
266493566 if (hasChild) {
1950 ChildNodeType* child = mNodes[n].getChild();
1951 266527302 acc.insert(xyz, child);
1952 34772582 child->modifyValueAndCache(xyz, op, acc);
1953 }
1954 }
1955
1956
1957 template<typename ChildT, Index Log2Dim>
1958 template<typename ModifyOp>
1959 inline void
1960 16 InternalNode<ChildT, Log2Dim>::modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
1961 {
1962 const Index n = InternalNode::coordToOffset(xyz);
1963 bool hasChild = this->isChildMaskOn(n);
1964
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
16 if (!hasChild) {
1965 const bool tileState = this->isValueMaskOn(n);
1966 const ValueType& tileVal = mNodes[n].getValue();
1967 bool modifiedState = !tileState;
1968 ValueType modifiedVal = tileVal;
1969 op(modifiedVal, modifiedState);
1970 // Need to create a child if applying the functor to the tile
1971 // produces a different value or active state.
1972 if (modifiedState != tileState || !math::isExactlyEqual(modifiedVal, tileVal)) {
1973 hasChild = true;
1974 this->setChildNode(n, new ChildNodeType(xyz, tileVal, tileState));
1975 }
1976 }
1977
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
16 if (hasChild) mNodes[n].getChild()->modifyValueAndActiveState(xyz, op);
1978 16 }
1979
1980 template<typename ChildT, Index Log2Dim>
1981 template<typename ModifyOp, typename AccessorT>
1982 inline void
1983 InternalNode<ChildT, Log2Dim>::modifyValueAndActiveStateAndCache(
1984 const Coord& xyz, const ModifyOp& op, AccessorT& acc)
1985 {
1986 const Index n = InternalNode::coordToOffset(xyz);
1987 bool hasChild = this->isChildMaskOn(n);
1988 if (!hasChild) {
1989 const bool tileState = this->isValueMaskOn(n);
1990 const ValueType& tileVal = mNodes[n].getValue();
1991 bool modifiedState = !tileState;
1992 ValueType modifiedVal = tileVal;
1993 op(modifiedVal, modifiedState);
1994 // Need to create a child if applying the functor to the tile
1995 // produces a different value or active state.
1996 if (modifiedState != tileState || !math::isExactlyEqual(modifiedVal, tileVal)) {
1997 hasChild = true;
1998 this->setChildNode(n, new ChildNodeType(xyz, tileVal, tileState));
1999 }
2000 }
2001 if (hasChild) {
2002 ChildNodeType* child = mNodes[n].getChild();
2003 acc.insert(xyz, child);
2004 child->modifyValueAndActiveStateAndCache(xyz, op, acc);
2005 }
2006 }
2007
2008
2009 ////////////////////////////////////////
2010
2011
2012 template<typename ChildT, Index Log2Dim>
2013 inline void
2014 194 InternalNode<ChildT, Log2Dim>::clip(const CoordBBox& clipBBox, const ValueType& background)
2015 {
2016 194 CoordBBox nodeBBox = this->getNodeBoundingBox();
2017 if (!clipBBox.hasOverlap(nodeBBox)) {
2018 // This node lies completely outside the clipping region. Fill it with background tiles.
2019 72 this->fill(nodeBBox, background, /*active=*/false);
2020 } else if (clipBBox.isInside(nodeBBox)) {
2021 // This node lies completely inside the clipping region. Leave it intact.
2022 return;
2023 }
2024
2025 // This node isn't completely contained inside the clipping region.
2026 // Clip tiles and children, and replace any that lie outside the region
2027 // with background tiles.
2028
2029
2/2
✓ Branch 0 taken 1687552 times.
✓ Branch 1 taken 97 times.
3375298 for (Index pos = 0; pos < NUM_VALUES; ++pos) {
2030 3375104 const Coord xyz = this->offsetToGlobalCoord(pos); // tile or child origin
2031
2/2
✓ Branch 0 taken 487168 times.
✓ Branch 1 taken 1200384 times.
3375104 CoordBBox tileBBox(xyz, xyz.offsetBy(ChildT::DIM - 1)); // tile or child bounds
2032 if (!clipBBox.hasOverlap(tileBBox)) {
2033 // This table entry lies completely outside the clipping region.
2034 // Replace it with a background tile.
2035 3374940 this->makeChildNodeEmpty(pos, background);
2036 3374940 mValueMask.setOff(pos);
2037 } else if (!clipBBox.isInside(tileBBox)) {
2038 // This table entry does not lie completely inside the clipping region
2039 // and must be clipped.
2040
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 25 times.
158 if (this->isChildMaskOn(pos)) {
2041 108 mNodes[pos].getChild()->clip(clipBBox, background);
2042 } else {
2043 // Replace this tile with a background tile, then fill the clip region
2044 // with the tile's original value. (This might create a child branch.)
2045 50 tileBBox.intersect(clipBBox);
2046 50 const ValueType val = mNodes[pos].getValue();
2047 const bool on = this->isValueMaskOn(pos);
2048 mNodes[pos].setValue(background);
2049 50 mValueMask.setOff(pos);
2050
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
50 this->fill(tileBBox, val, on);
2051 }
2052 } else {
2053 // This table entry lies completely inside the clipping region. Leave it intact.
2054 }
2055 }
2056 }
2057
2058
2059 ////////////////////////////////////////
2060
2061
2062 template<typename ChildT, Index Log2Dim>
2063 inline void
2064 30036 InternalNode<ChildT, Log2Dim>::fill(const CoordBBox& bbox, const ValueType& value, bool active)
2065 {
2066 30036 auto clippedBBox = this->getNodeBoundingBox();
2067 30036 clippedBBox.intersect(bbox);
2068 if (!clippedBBox) return;
2069
2070 // Iterate over the fill region in axis-aligned, tile-sized chunks.
2071 // (The first and last chunks along each axis might be smaller than a tile.)
2072 Coord xyz, tileMin, tileMax;
2073
2/2
✓ Branch 0 taken 40090 times.
✓ Branch 1 taken 15018 times.
110216 for (int x = clippedBBox.min().x(); x <= clippedBBox.max().x(); x = tileMax.x() + 1) {
2074 xyz.setX(x);
2075
2/2
✓ Branch 0 taken 318163 times.
✓ Branch 1 taken 40090 times.
716506 for (int y = clippedBBox.min().y(); y <= clippedBBox.max().y(); y = tileMax.y() + 1) {
2076 xyz.setY(y);
2077
2/2
✓ Branch 0 taken 4160096 times.
✓ Branch 1 taken 318163 times.
8956518 for (int z = clippedBBox.min().z(); z <= clippedBBox.max().z(); z = tileMax.z() + 1) {
2078 xyz.setZ(z);
2079
2080 // Get the bounds of the tile that contains voxel (x, y, z).
2081 const Index n = this->coordToOffset(xyz);
2082 8320192 tileMin = this->offsetToGlobalCoord(n);
2083
2/2
✓ Branch 0 taken 4146735 times.
✓ Branch 1 taken 13361 times.
8320192 tileMax = tileMin.offsetBy(ChildT::DIM - 1);
2084
2085 if (xyz != tileMin || Coord::lessThan(clippedBBox.max(), tileMax)) {
2086 // If the box defined by (xyz, clippedBBox.max()) doesn't completely enclose
2087 // the tile to which xyz belongs, create a child node (or retrieve
2088 // the existing one).
2089 ChildT* child = nullptr;
2090
2/2
✓ Branch 0 taken 400627 times.
✓ Branch 1 taken 14087 times.
829428 if (this->isChildMaskOff(n)) {
2091 // Replace the tile with a newly-created child that is initialized
2092 // with the tile's value and active state.
2093
1/2
✓ Branch 2 taken 146660 times.
✗ Branch 3 not taken.
801254 child = new ChildT{xyz, mNodes[n].getValue(), this->isValueMaskOn(n)};
2094 801254 this->setChildNode(n, child);
2095 } else {
2096 child = mNodes[n].getChild();
2097 }
2098
2099 // Forward the fill request to the child.
2100
1/2
✓ Branch 0 taken 414714 times.
✗ Branch 1 not taken.
829428 if (child) {
2101 829428 const Coord tmp = Coord::minComponent(clippedBBox.max(), tileMax);
2102 829428 child->fill(CoordBBox(xyz, tmp), value, active);
2103 }
2104
2105 } else {
2106 // If the box given by (xyz, clippedBBox.max()) completely encloses
2107 // the tile to which xyz belongs, create the tile (if it
2108 // doesn't already exist) and give it the fill value.
2109 7490764 this->makeChildNodeEmpty(n, value);
2110
2/2
✓ Branch 0 taken 3019088 times.
✓ Branch 1 taken 726294 times.
7490764 mValueMask.set(n, active);
2111 }
2112 }
2113 }
2114 }
2115 }
2116
2117
2118 template<typename ChildT, Index Log2Dim>
2119 inline void
2120 416 InternalNode<ChildT, Log2Dim>::denseFill(const CoordBBox& bbox, const ValueType& value, bool active)
2121 {
2122 416 auto clippedBBox = this->getNodeBoundingBox();
2123 416 clippedBBox.intersect(bbox);
2124 if (!clippedBBox) return;
2125
2126 // Iterate over the fill region in axis-aligned, tile-sized chunks.
2127 // (The first and last chunks along each axis might be smaller than a tile.)
2128 Coord xyz, tileMin, tileMax;
2129
2/2
✓ Branch 0 taken 1012 times.
✓ Branch 1 taken 408 times.
1440 for (int x = clippedBBox.min().x(); x <= clippedBBox.max().x(); x = tileMax.x() + 1) {
2130 xyz.setX(x);
2131
2/2
✓ Branch 0 taken 3224 times.
✓ Branch 1 taken 1012 times.
4272 for (int y = clippedBBox.min().y(); y <= clippedBBox.max().y(); y = tileMax.y() + 1) {
2132 xyz.setY(y);
2133
2/2
✓ Branch 0 taken 11924 times.
✓ Branch 1 taken 3224 times.
15256 for (int z = clippedBBox.min().z(); z <= clippedBBox.max().z(); z = tileMax.z() + 1) {
2134 xyz.setZ(z);
2135
2136 // Get the table index of the tile that contains voxel (x, y, z).
2137 const auto n = this->coordToOffset(xyz);
2138
2139 // Retrieve the child node at index n, or replace the tile at index n with a child.
2140 ChildT* child = nullptr;
2141
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 11858 times.
12008 if (this->isChildMaskOn(n)) {
2142 child = mNodes[n].getChild();
2143 } else {
2144 // Replace the tile with a newly-created child that is filled
2145 // with the tile's value and active state.
2146
1/2
✓ Branch 2 taken 11858 times.
✗ Branch 3 not taken.
11876 child = new ChildT{xyz, mNodes[n].getValue(), this->isValueMaskOn(n)};
2147 11876 this->setChildNode(n, child);
2148 }
2149
2150 // Get the bounds of the tile that contains voxel (x, y, z).
2151 12008 tileMin = this->offsetToGlobalCoord(n);
2152 12008 tileMax = tileMin.offsetBy(ChildT::DIM - 1);
2153
2154 // Forward the fill request to the child.
2155 12008 child->denseFill(CoordBBox{xyz, clippedBBox.max()}, value, active);
2156 }
2157 }
2158 }
2159 }
2160
2161
2162 ////////////////////////////////////////
2163
2164
2165 template<typename ChildT, Index Log2Dim>
2166 template<typename DenseT>
2167 inline void
2168 4956 InternalNode<ChildT, Log2Dim>::copyToDense(const CoordBBox& bbox, DenseT& dense) const
2169 {
2170 using DenseValueType = typename DenseT::ValueType;
2171
2172 const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride();
2173 const Coord& min = dense.bbox().min();
2174
2/2
✓ Branch 0 taken 3040 times.
✓ Branch 1 taken 2478 times.
11036 for (Coord xyz = bbox.min(), max; xyz[0] <= bbox.max()[0]; xyz[0] = max[0] + 1) {
2175
2/2
✓ Branch 0 taken 4137 times.
✓ Branch 1 taken 3040 times.
14354 for (xyz[1] = bbox.min()[1]; xyz[1] <= bbox.max()[1]; xyz[1] = max[1] + 1) {
2176
2/2
✓ Branch 0 taken 5443 times.
✓ Branch 1 taken 4137 times.
19160 for (xyz[2] = bbox.min()[2]; xyz[2] <= bbox.max()[2]; xyz[2] = max[2] + 1) {
2177 const Index n = this->coordToOffset(xyz);
2178 // Get max coordinates of the child node that contains voxel xyz.
2179 10886 max = this->offsetToGlobalCoord(n).offsetBy(ChildT::DIM-1);
2180
2181 // Get the bbox of the interection of bbox and the child node
2182 10886 CoordBBox sub(xyz, Coord::minComponent(bbox.max(), max));
2183
2184
2/2
✓ Branch 0 taken 4306 times.
✓ Branch 1 taken 1137 times.
10886 if (this->isChildMaskOn(n)) {//is a child
2185 8612 mNodes[n].getChild()->copyToDense(sub, dense);
2186 } else {//a tile value
2187 2274 const ValueType value = mNodes[n].getValue();
2188 sub.translate(-min);
2189 2274 DenseValueType* a0 = dense.data() + zStride*sub.min()[2];
2190
2/2
✓ Branch 0 taken 4023 times.
✓ Branch 1 taken 1137 times.
10320 for (Int32 x=sub.min()[0], ex=sub.max()[0]+1; x<ex; ++x) {
2191 8046 DenseValueType* a1 = a0 + x*xStride;
2192
2/2
✓ Branch 0 taken 14253 times.
✓ Branch 1 taken 4023 times.
36552 for (Int32 y=sub.min()[1], ey=sub.max()[1]+1; y<ey; ++y) {
2193 28506 DenseValueType* a2 = a1 + y*yStride;
2194 28506 for (Int32 z = sub.min()[2], ez = sub.max()[2]+1;
2195
2/2
✓ Branch 0 taken 42274 times.
✓ Branch 1 taken 14253 times.
113054 z < ez; ++z, a2 += zStride)
2196 {
2197 84548 *a2 = DenseValueType(value);
2198 }
2199 }
2200 }
2201 }
2202 }
2203 }
2204 }
2205 4956 }
2206
2207
2208 ////////////////////////////////////////
2209
2210
2211 template<typename ChildT, Index Log2Dim>
2212 inline void
2213 1012 InternalNode<ChildT, Log2Dim>::writeTopology(std::ostream& os, bool toHalf) const
2214 {
2215 mChildMask.save(os);
2216 mValueMask.save(os);
2217
2218 {
2219 // Copy all of this node's values into an array.
2220
2/2
✓ Branch 1 taken 1806336 times.
✓ Branch 2 taken 98 times.
3613684 std::unique_ptr<ValueType[]> valuePtr(new ValueType[NUM_VALUES]);
2221 ValueType* values = valuePtr.get();
2222 196 const ValueType zero = zeroVal<ValueType>();
2223
2/2
✓ Branch 0 taken 9226240 times.
✓ Branch 1 taken 506 times.
18453492 for (Index i = 0; i < NUM_VALUES; ++i) {
2224
2/4
✓ Branch 1 taken 9198097 times.
✓ Branch 2 taken 28143 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
22056398 values[i] = (mChildMask.isOff(i) ? mNodes[i].getValue() : zero);
2225 }
2226 // Compress (optionally) and write out the contents of the array.
2227
1/2
✓ Branch 1 taken 506 times.
✗ Branch 2 not taken.
1012 io::writeCompressedValues(os, values, NUM_VALUES, mValueMask, mChildMask, toHalf);
2228 }
2229 // Write out the child nodes in order.
2230
2/2
✓ Branch 0 taken 28143 times.
✓ Branch 1 taken 506 times.
57298 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
2231 512 iter->writeTopology(os, toHalf);
2232 }
2233 }
2234
2235
2236 template<typename ChildT, Index Log2Dim>
2237 inline void
2238 1010 InternalNode<ChildT, Log2Dim>::readTopology(std::istream& is, bool fromHalf)
2239 {
2240
2/2
✓ Branch 1 taken 303 times.
✓ Branch 2 taken 202 times.
2020 const ValueType background = (!io::getGridBackgroundValuePtr(is) ? zeroVal<ValueType>()
2241 1010 : *static_cast<const ValueType*>(io::getGridBackgroundValuePtr(is)));
2242
2243 mChildMask.load(is);
2244 mValueMask.load(is);
2245
2246
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 505 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1010 if (io::getFormatVersion(is) < OPENVDB_FILE_VERSION_INTERNALNODE_COMPRESSION) {
2247 for (Index i = 0; i < NUM_VALUES; ++i) {
2248 if (this->isChildMaskOn(i)) {
2249 ChildNodeType* child =
2250 new ChildNodeType(PartialCreate(), offsetToGlobalCoord(i), background);
2251 mNodes[i].setChild(child);
2252 child->readTopology(is);
2253 } else {
2254 ValueType value;
2255 is.read(reinterpret_cast<char*>(&value), sizeof(ValueType));
2256 mNodes[i].setValue(value);
2257 }
2258 }
2259 } else {
2260 const bool oldVersion =
2261
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
1010 (io::getFormatVersion(is) < OPENVDB_FILE_VERSION_NODE_MASK_COMPRESSION);
2262
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 505 times.
1010 const Index numValues = (oldVersion ? mChildMask.countOff() : NUM_VALUES);
2263 {
2264 // Read in (and uncompress, if necessary) all of this node's values
2265 // into a contiguous array.
2266
2/4
✓ Branch 1 taken 3723264 times.
✓ Branch 2 taken 202 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
7447538 std::unique_ptr<ValueType[]> valuePtr(new ValueType[numValues]);
2267 ValueType* values = valuePtr.get();
2268
1/2
✓ Branch 1 taken 505 times.
✗ Branch 2 not taken.
1010 io::readCompressedValues(is, values, numValues, mValueMask, fromHalf);
2269
2270 // Copy values from the array into this node's table.
2271
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 505 times.
1010 if (oldVersion) {
2272 Index n = 0;
2273 for (ValueAllIter iter = this->beginValueAll(); iter; ++iter) {
2274 mNodes[iter.pos()].setValue(values[n++]);
2275 }
2276 assert(n == numValues);
2277 } else {
2278
2/2
✓ Branch 0 taken 9198703 times.
✓ Branch 1 taken 505 times.
18398416 for (ValueAllIter iter = this->beginValueAll(); iter; ++iter) {
2279
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
18397406 mNodes[iter.pos()].setValue(values[iter.pos()]);
2280 }
2281 }
2282 }
2283 // Read in all child nodes and insert them into the table at their proper locations.
2284
2/2
✓ Branch 0 taken 23441 times.
✓ Branch 1 taken 505 times.
47892 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
2285
3/9
✓ Branch 1 taken 23441 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 23441 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10219 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
46894 ChildNodeType* child = new ChildNodeType(PartialCreate(), iter.getCoord(), background);
2286 mNodes[iter.pos()].setChild(child);
2287
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
510 child->readTopology(is, fromHalf);
2288 }
2289 }
2290 }
2291
2292
2293 ////////////////////////////////////////
2294
2295
2296 template<typename ChildT, Index Log2Dim>
2297 inline const typename ChildT::ValueType&
2298 1554 InternalNode<ChildT, Log2Dim>::getFirstValue() const
2299 {
2300
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 743 times.
1554 return (this->isChildMaskOn(0) ? mNodes[0].getChild()->getFirstValue() : mNodes[0].getValue());
2301 }
2302
2303
2304 template<typename ChildT, Index Log2Dim>
2305 inline const typename ChildT::ValueType&
2306 4295 InternalNode<ChildT, Log2Dim>::getLastValue() const
2307 {
2308 const Index n = NUM_VALUES - 1;
2309
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 2078 times.
4295 return (this->isChildMaskOn(n) ? mNodes[n].getChild()->getLastValue() : mNodes[n].getValue());
2310 }
2311
2312
2313 ////////////////////////////////////////
2314
2315
2316 template<typename ChildT, Index Log2Dim>
2317 inline void
2318 7 InternalNode<ChildT, Log2Dim>::negate()
2319 {
2320
2/2
✓ Branch 0 taken 102400 times.
✓ Branch 1 taken 4 times.
200711 for (Index i = 0; i < NUM_VALUES; ++i) {
2321
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102400 times.
200704 if (this->isChildMaskOn(i)) {
2322 mNodes[i].getChild()->negate();
2323 } else {
2324 mNodes[i].setValue(math::negative(mNodes[i].getValue()));
2325 }
2326 }
2327
2328 7 }
2329
2330
2331 ////////////////////////////////////////
2332
2333
2334 template<typename ChildT, Index Log2Dim>
2335 struct InternalNode<ChildT, Log2Dim>::VoxelizeActiveTiles
2336 {
2337 32326 VoxelizeActiveTiles(InternalNode &node) : mNode(&node) {
2338 //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//single thread for debugging
2339 32326 tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
2340
2341 node.mChildMask |= node.mValueMask;
2342 node.mValueMask.setOff();
2343 32160 }
2344 4626874 void operator()(const tbb::blocked_range<Index> &r) const
2345 {
2346
2/2
✓ Branch 0 taken 219318656 times.
✓ Branch 1 taken 2313437 times.
443264186 for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
2347
2/2
✓ Branch 1 taken 43559920 times.
✓ Branch 2 taken 175758736 times.
438637312 if (mNode->mChildMask.isOn(i)) {// Loop over node's child nodes
2348 12754 mNode->mNodes[i].getChild()->voxelizeActiveTiles(true);
2349
2/2
✓ Branch 1 taken 20730988 times.
✓ Branch 2 taken 198236082 times.
437934140 } else if (mNode->mValueMask.isOn(i)) {// Loop over node's active tiles
2350 41461976 const Coord &ijk = mNode->offsetToGlobalCoord(i);
2351
1/2
✓ Branch 2 taken 574236 times.
✗ Branch 3 not taken.
41461976 ChildNodeType *child = new ChildNodeType(ijk, mNode->mNodes[i].getValue(), true);
2352 8992 child->voxelizeActiveTiles(true);
2353 41461976 mNode->mNodes[i].setChild(child);
2354 }
2355 }
2356 4626874 }
2357 InternalNode* mNode;
2358 };// VoxelizeActiveTiles
2359
2360 template<typename ChildT, Index Log2Dim>
2361 inline void
2362 32800 InternalNode<ChildT, Log2Dim>::voxelizeActiveTiles(bool threaded)
2363 {
2364
2/2
✓ Branch 0 taken 16258 times.
✓ Branch 1 taken 142 times.
32800 if (threaded) {
2365 32184 VoxelizeActiveTiles tmp(*this);
2366 } else {
2367
2/2
✓ Branch 0 taken 8452 times.
✓ Branch 1 taken 142 times.
17188 for (ValueOnIter iter = this->beginValueOn(); iter; ++iter) {
2368 16904 this->setChildNode(iter.pos(),
2369
1/2
✓ Branch 3 taken 8322 times.
✗ Branch 4 not taken.
50712 new ChildNodeType(iter.getCoord(), iter.getValue(), true));
2370 }
2371
2/2
✓ Branch 0 taken 8458 times.
✓ Branch 1 taken 142 times.
17200 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter)
2372 268 iter->voxelizeActiveTiles(false);
2373 }
2374 32800 }
2375
2376
2377 ////////////////////////////////////////
2378
2379
2380 template<typename ChildT, Index Log2Dim>
2381 template<MergePolicy Policy>
2382 inline void
2383 170264 InternalNode<ChildT, Log2Dim>::merge(InternalNode& other,
2384 const ValueType& background, const ValueType& otherBackground)
2385 {
2386 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
2387
2388 switch (Policy) {
2389
2390 case MERGE_ACTIVE_STATES:
2391 default:
2392 {
2393
2/2
✓ Branch 0 taken 212294 times.
✓ Branch 1 taken 85108 times.
594804 for (ChildOnIter iter = other.beginChildOn(); iter; ++iter) {
2394 const Index n = iter.pos();
2395
2/2
✓ Branch 1 taken 129694 times.
✓ Branch 2 taken 82600 times.
424588 if (mChildMask.isOn(n)) {
2396 // Merge this node's child with the other node's child.
2397 88452 mNodes[n].getChild()->template merge<MERGE_ACTIVE_STATES>(*iter,
2398 background, otherBackground);
2399
2/2
✓ Branch 1 taken 82403 times.
✓ Branch 2 taken 197 times.
165200 } else if (mValueMask.isOff(n)) {
2400 // Replace this node's inactive tile with the other node's child
2401 // and replace the other node's child with a tile of undefined value
2402 // (which is okay since the other tree is assumed to be cannibalized
2403 // in the process of merging).
2404 ChildNodeType* child = other.mNodes[n].getChild();
2405 164806 other.mChildMask.setOff(n);
2406 35174 child->resetBackground(otherBackground, background);
2407 164806 this->setChildNode(n, child);
2408 }
2409 }
2410
2411 // Copy active tile values.
2412
2/2
✓ Branch 0 taken 5799 times.
✓ Branch 1 taken 85108 times.
181814 for (ValueOnCIter iter = other.cbeginValueOn(); iter; ++iter) {
2413 const Index n = iter.pos();
2414
2/2
✓ Branch 1 taken 1539 times.
✓ Branch 2 taken 4260 times.
11598 if (mValueMask.isOff(n)) {
2415 // Replace this node's child or inactive tile with the other node's active tile.
2416 3078 this->makeChildNodeEmpty(n, iter.getValue());
2417 3078 mValueMask.setOn(n);
2418 }
2419 }
2420 break;
2421 }
2422
2423 case MERGE_NODES:
2424 {
2425
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 8 times.
28 for (ChildOnIter iter = other.beginChildOn(); iter; ++iter) {
2426 const Index n = iter.pos();
2427
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
12 if (mChildMask.isOn(n)) {
2428 // Merge this node's child with the other node's child.
2429 8 mNodes[n].getChild()->template merge<Policy>(*iter, background, otherBackground);
2430 } else {
2431 // Replace this node's tile (regardless of its active state) with
2432 // the other node's child and replace the other node's child with
2433 // a tile of undefined value (which is okay since the other tree
2434 // is assumed to be cannibalized in the process of merging).
2435 ChildNodeType* child = other.mNodes[n].getChild();
2436 other.mChildMask.setOff(n);
2437 child->resetBackground(otherBackground, background);
2438 this->setChildNode(n, child);
2439 }
2440 }
2441 break;
2442 }
2443
2444 case MERGE_ACTIVE_STATES_AND_NODES:
2445 {
2446 // Transfer children from the other tree to this tree.
2447
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 16 times.
118 for (ChildOnIter iter = other.beginChildOn(); iter; ++iter) {
2448 const Index n = iter.pos();
2449
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 33 times.
86 if (mChildMask.isOn(n)) {
2450 // Merge this node's child with the other node's child.
2451 18 mNodes[n].getChild()->template merge<Policy>(*iter, background, otherBackground);
2452 } else {
2453 // Replace this node's tile with the other node's child, leaving the other
2454 // node with an inactive tile of undefined value (which is okay since
2455 // the other tree is assumed to be cannibalized in the process of merging).
2456 ChildNodeType* child = other.mNodes[n].getChild();
2457 66 other.mChildMask.setOff(n);
2458 66 child->resetBackground(otherBackground, background);
2459
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
66 if (mValueMask.isOn(n)) {
2460 // Merge the child with this node's active tile.
2461 child->template merge<Policy>(mNodes[n].getValue(), /*on=*/true);
2462 mValueMask.setOff(n);
2463 }
2464 66 mChildMask.setOn(n);
2465 mNodes[n].setChild(child);
2466 }
2467 }
2468
2469 // Merge active tiles into this tree.
2470
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
36 for (ValueOnCIter iter = other.cbeginValueOn(); iter; ++iter) {
2471 const Index n = iter.pos();
2472
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 if (mChildMask.isOn(n)) {
2473 // Merge the other node's active tile into this node's child.
2474
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
4 mNodes[n].getChild()->template merge<Policy>(iter.getValue(), /*on=*/true);
2475 } else if (mValueMask.isOff(n)) {
2476 // Replace this node's inactive tile with the other node's active tile.
2477 mNodes[n].setValue(iter.getValue());
2478 mValueMask.setOn(n);
2479 }
2480 }
2481 break;
2482 }
2483
2484 }
2485 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
2486 }
2487
2488
2489 template<typename ChildT, Index Log2Dim>
2490 template<MergePolicy Policy>
2491 inline void
2492 InternalNode<ChildT, Log2Dim>::merge(const ValueType& tileValue, bool tileActive)
2493 {
2494 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
2495
2496 if (Policy != MERGE_ACTIVE_STATES_AND_NODES) return;
2497
2498 // For MERGE_ACTIVE_STATES_AND_NODES, inactive tiles in the other tree are ignored.
2499 if (!tileActive) return;
2500
2501 // Iterate over this node's children and inactive tiles.
2502 for (ValueOffIter iter = this->beginValueOff(); iter; ++iter) {
2503 const Index n = iter.pos();
2504 if (mChildMask.isOn(n)) {
2505 // Merge the other node's active tile into this node's child.
2506 mNodes[n].getChild()->template merge<Policy>(tileValue, /*on=*/true);
2507 } else {
2508 // Replace this node's inactive tile with the other node's active tile.
2509 iter.setValue(tileValue);
2510 mValueMask.setOn(n);
2511 }
2512 }
2513 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
2514 }
2515
2516
2517 ////////////////////////////////////////
2518
2519
2520 template<typename ChildT, Index Log2Dim>
2521 template<typename OtherInternalNode>
2522 struct InternalNode<ChildT, Log2Dim>::TopologyUnion
2523 {
2524 using W = typename NodeMaskType::Word;
2525 struct A { inline void operator()(W &tV, const W& sV, const W& tC) const
2526 3997568 { tV = (tV | sV) & ~tC; }
2527 };
2528 29752 TopologyUnion(const OtherInternalNode* source, InternalNode* target, const bool preserveTiles)
2529 29752 : s(source), t(target), mPreserveTiles(preserveTiles) {
2530 //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//single thread for debugging
2531 29752 tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
2532
2533 // Bit processing is done in a single thread!
2534
2/2
✓ Branch 0 taken 9609 times.
✓ Branch 1 taken 5267 times.
29752 if (!mPreserveTiles) t->mChildMask |= s->mChildMask;//serial but very fast bitwise post-process
2535 42136 else t->mChildMask |= (s->mChildMask & !t->mValueMask);
2536
2537 A op;
2538 29752 t->mValueMask.foreach(s->mValueMask, t->mChildMask, op);
2539
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14876 times.
59504 assert((t->mValueMask & t->mChildMask).isOff());//no overlapping active tiles or child nodes
2540 29752 }
2541 4363708 void operator()(const tbb::blocked_range<Index> &r) const {
2542
2/2
✓ Branch 0 taken 255844352 times.
✓ Branch 1 taken 2181854 times.
516052412 for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
2543
2/2
✓ Branch 1 taken 68381 times.
✓ Branch 2 taken 255775971 times.
511688704 if (s->mChildMask.isOn(i)) {// Loop over other node's child nodes
2544 const typename OtherInternalNode::ChildNodeType& other = *(s->mNodes[i].getChild());
2545
2/2
✓ Branch 1 taken 37219 times.
✓ Branch 2 taken 31162 times.
136762 if (t->mChildMask.isOn(i)) {//this has a child node
2546 16156 t->mNodes[i].getChild()->topologyUnion(other, mPreserveTiles);
2547 } else {// this is a tile so replace it with a child branch with identical topology
2548
4/4
✓ Branch 0 taken 3265 times.
✓ Branch 1 taken 27897 times.
✓ Branch 3 taken 3232 times.
✓ Branch 4 taken 33 times.
62324 if (!mPreserveTiles || t->mValueMask.isOff(i)) { // force child topology
2549
2/4
✓ Branch 1 taken 6915 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1698 times.
✗ Branch 5 not taken.
62258 ChildT* child = new ChildT(other, t->mNodes[i].getValue(), TopologyCopy());
2550
2/2
✓ Branch 1 taken 91 times.
✓ Branch 2 taken 31038 times.
62258 if (t->mValueMask.isOn(i)) child->setValuesOn();//activate all values
2551 62258 t->mNodes[i].setChild(child);
2552 }
2553 }
2554
4/4
✓ Branch 1 taken 41175 times.
✓ Branch 2 taken 255734796 times.
✓ Branch 4 taken 178 times.
✓ Branch 5 taken 40997 times.
511551942 } else if (s->mValueMask.isOn(i) && t->mChildMask.isOn(i)) {
2555 2 t->mNodes[i].getChild()->setValuesOn();
2556 }
2557 }
2558 4363708 }
2559 const OtherInternalNode* s;
2560 InternalNode* t;
2561 const bool mPreserveTiles;
2562 };// TopologyUnion
2563
2564 template<typename ChildT, Index Log2Dim>
2565 template<typename OtherChildT>
2566 inline void
2567 InternalNode<ChildT, Log2Dim>::topologyUnion(const InternalNode<OtherChildT, Log2Dim>& other, const bool preserveTiles)
2568 {
2569
27/68
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 250 times.
✓ Branch 10 taken 623 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2619 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 14 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 45 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 75 times.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✓ Branch 29 taken 69 times.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✓ Branch 32 taken 65 times.
✗ Branch 33 not taken.
✓ Branch 35 taken 69 times.
✗ Branch 36 not taken.
✓ Branch 38 taken 66 times.
✗ Branch 39 not taken.
✓ Branch 41 taken 66 times.
✗ Branch 42 not taken.
✓ Branch 44 taken 69 times.
✗ Branch 45 not taken.
✓ Branch 47 taken 75 times.
✗ Branch 48 not taken.
✓ Branch 50 taken 116 times.
✗ Branch 51 not taken.
✓ Branch 53 taken 130 times.
✗ Branch 54 not taken.
✓ Branch 56 taken 49 times.
✗ Branch 57 not taken.
✓ Branch 59 taken 49 times.
✗ Branch 60 not taken.
✓ Branch 62 taken 67 times.
✗ Branch 63 not taken.
✓ Branch 65 taken 449 times.
✗ Branch 66 not taken.
✓ Branch 68 taken 34 times.
✗ Branch 69 not taken.
✓ Branch 71 taken 286 times.
✗ Branch 72 not taken.
✓ Branch 74 taken 99 times.
✗ Branch 75 not taken.
✓ Branch 77 taken 273 times.
✗ Branch 78 not taken.
✓ Branch 80 taken 398 times.
✗ Branch 81 not taken.
✓ Branch 83 taken 720 times.
✗ Branch 84 not taken.
✗ Branch 86 not taken.
✗ Branch 87 not taken.
14876 TopologyUnion<InternalNode<OtherChildT, Log2Dim> > tmp(&other, this, preserveTiles);
2570 14876 }
2571
2572 template<typename ChildT, Index Log2Dim>
2573 template<typename OtherInternalNode>
2574 struct InternalNode<ChildT, Log2Dim>::TopologyIntersection
2575 {
2576 using W = typename NodeMaskType::Word;
2577 struct A { inline void operator()(W &tC, const W& sC, const W& sV, const W& tV) const
2578 214912 { tC = (tC & (sC | sV)) | (tV & sC); }
2579 };
2580 1494 TopologyIntersection(const OtherInternalNode* source, InternalNode* target,
2581 1494 const ValueType& background) : s(source), t(target), b(background) {
2582 //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//single thread for debugging
2583 1494 tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
2584
2585 // Bit processing is done in a single thread!
2586 A op;
2587 1494 t->mChildMask.foreach(s->mChildMask, s->mValueMask, t->mValueMask, op);
2588
2589 1494 t->mValueMask &= s->mValueMask;
2590
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 747 times.
2988 assert((t->mValueMask & t->mChildMask).isOff());//no overlapping active tiles or child nodes
2591 1494 }
2592 216068 void operator()(const tbb::blocked_range<Index> &r) const {
2593
2/2
✓ Branch 0 taken 13754368 times.
✓ Branch 1 taken 108034 times.
27724804 for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
2594
2/2
✓ Branch 1 taken 13761 times.
✓ Branch 2 taken 13740607 times.
27508736 if (t->mChildMask.isOn(i)) {// Loop over this node's child nodes
2595 ChildT* child = t->mNodes[i].getChild();
2596
2/2
✓ Branch 1 taken 8426 times.
✓ Branch 2 taken 5335 times.
27522 if (s->mChildMask.isOn(i)) {//other also has a child node
2597 748 child->topologyIntersection(*(s->mNodes[i].getChild()), b);
2598
2/2
✓ Branch 1 taken 4884 times.
✓ Branch 2 taken 451 times.
10670 } else if (s->mValueMask.isOff(i)) {//other is an inactive tile
2599
1/2
✓ Branch 0 taken 4884 times.
✗ Branch 1 not taken.
15856 delete child;//convert child to an inactive tile
2600 9768 t->mNodes[i].setValue(b);
2601 }
2602
4/4
✓ Branch 1 taken 3438 times.
✓ Branch 2 taken 13737169 times.
✓ Branch 4 taken 50 times.
✓ Branch 5 taken 3388 times.
27481214 } else if (t->mValueMask.isOn(i) && s->mChildMask.isOn(i)) {//active tile -> a branch
2603
1/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
100 t->mNodes[i].setChild(new ChildT(*(s->mNodes[i].getChild()),
2604 t->mNodes[i].getValue(), TopologyCopy()));
2605 }
2606 }
2607 216068 }
2608 const OtherInternalNode* s;
2609 InternalNode* t;
2610 const ValueType& b;
2611 };// TopologyIntersection
2612
2613 template<typename ChildT, Index Log2Dim>
2614 template<typename OtherChildT>
2615 inline void
2616 InternalNode<ChildT, Log2Dim>::topologyIntersection(
2617 const InternalNode<OtherChildT, Log2Dim>& other, const ValueType& background)
2618 {
2619
8/47
✓ Branch 2 taken 279 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 40 times.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 8 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 9 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✓ Branch 38 taken 21 times.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
747 TopologyIntersection<InternalNode<OtherChildT, Log2Dim> > tmp(&other, this, background);
2620 747 }
2621
2622 template<typename ChildT, Index Log2Dim>
2623 template<typename OtherInternalNode>
2624 struct InternalNode<ChildT, Log2Dim>::TopologyDifference
2625 {
2626 using W = typename NodeMaskType::Word;
2627 struct A {inline void operator()(W &tC, const W& sC, const W& sV, const W& tV) const
2628 102912 { tC = (tC & (sC | ~sV)) | (tV & sC); }
2629 };
2630 struct B {inline void operator()(W &tV, const W& sC, const W& sV, const W& tC) const
2631 102912 { tV &= ~((tC & sV) | (sC | sV)); }
2632 };
2633 724 TopologyDifference(const OtherInternalNode* source, InternalNode* target,
2634 724 const ValueType& background) : s(source), t(target), b(background) {
2635 //(*this)(tbb::blocked_range<Index>(0, NUM_VALUES));//single thread for debugging
2636 724 tbb::parallel_for(tbb::blocked_range<Index>(0, NUM_VALUES), *this);
2637
2638 // Bit processing is done in a single thread!
2639 724 const NodeMaskType oldChildMask(t->mChildMask);//important to avoid cross pollution
2640 A op1;
2641 724 t->mChildMask.foreach(s->mChildMask, s->mValueMask, t->mValueMask, op1);
2642
2643 B op2;
2644 724 t->mValueMask.foreach(t->mChildMask, s->mValueMask, oldChildMask, op2);
2645
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 362 times.
1448 assert((t->mValueMask & t->mChildMask).isOff());//no overlapping active tiles or child nodes
2646 724 }
2647 109050 void operator()(const tbb::blocked_range<Index> &r) const {
2648
2/2
✓ Branch 0 taken 6586368 times.
✓ Branch 1 taken 54525 times.
13281786 for (Index i = r.begin(), end=r.end(); i!=end; ++i) {
2649
2/2
✓ Branch 1 taken 18267 times.
✓ Branch 2 taken 6568101 times.
13172736 if (t->mChildMask.isOn(i)) {// Loop over this node's child nodes
2650 ChildT* child = t->mNodes[i].getChild();
2651
2/2
✓ Branch 1 taken 12108 times.
✓ Branch 2 taken 6159 times.
36534 if (s->mChildMask.isOn(i)) {
2652 24216 child->topologyDifference(*(s->mNodes[i].getChild()), b);
2653
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6159 times.
12318 } else if (s->mValueMask.isOn(i)) {
2654 delete child;//convert child to an inactive tile
2655 t->mNodes[i].setValue(b);
2656 }
2657
2/2
✓ Branch 1 taken 42765 times.
✓ Branch 2 taken 6525336 times.
13136202 } else if (t->mValueMask.isOn(i)) {//this is an active tile
2658
2/2
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 42725 times.
85530 if (s->mChildMask.isOn(i)) {
2659 const typename OtherInternalNode::ChildNodeType& other =
2660 *(s->mNodes[i].getChild());
2661
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
80 ChildT* child = new ChildT(other.origin(), t->mNodes[i].getValue(), true);
2662 80 child->topologyDifference(other, b);
2663 80 t->mNodes[i].setChild(child);//replace the active tile with a child branch
2664 }
2665 }
2666 }
2667 109050 }
2668 const OtherInternalNode* s;
2669 InternalNode* t;
2670 const ValueType& b;
2671 };// TopologyDifference
2672
2673 template<typename ChildT, Index Log2Dim>
2674 template<typename OtherChildT>
2675 inline void
2676 InternalNode<ChildT, Log2Dim>::topologyDifference(const InternalNode<OtherChildT, Log2Dim>& other,
2677 const ValueType& background)
2678 {
2679
3/11
✓ Branch 3 taken 113 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 11 taken 64 times.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
362 TopologyDifference<InternalNode<OtherChildT, Log2Dim> > tmp(&other, this, background);
2680 359 }
2681
2682
2683 ////////////////////////////////////////
2684
2685
2686 template<typename ChildT, Index Log2Dim>
2687 template<typename CombineOp>
2688 inline void
2689 148 InternalNode<ChildT, Log2Dim>::combine(InternalNode& other, CombineOp& op)
2690 {
2691 76 const ValueType zero = zeroVal<ValueType>();
2692
2693 CombineArgs<ValueType> args;
2694
2695
2/2
✓ Branch 0 taken 1363968 times.
✓ Branch 1 taken 74 times.
2728084 for (Index i = 0; i < NUM_VALUES; ++i) {
2696
4/4
✓ Branch 0 taken 1363566 times.
✓ Branch 1 taken 402 times.
✓ Branch 2 taken 1363208 times.
✓ Branch 3 taken 358 times.
5455068 if (this->isChildMaskOff(i) && other.isChildMaskOff(i)) {
2697 // Both this node and the other node have constant values (tiles).
2698 // Combine the two values and store the result as this node's new tile value.
2699 2431520 op(args.setARef(mNodes[i].getValue())
2700 .setAIsActive(isValueMaskOn(i))
2701 .setBRef(other.mNodes[i].getValue())
2702 .setBIsActive(other.isValueMaskOn(i)));
2703 mNodes[i].setValue(args.result());
2704 mValueMask.set(i, args.resultIsActive());
2705
4/4
✓ Branch 0 taken 402 times.
✓ Branch 1 taken 358 times.
✓ Branch 2 taken 99 times.
✓ Branch 3 taken 303 times.
2324 } else if (this->isChildMaskOn(i) && other.isChildMaskOff(i)) {
2706 // Combine this node's child with the other node's constant value.
2707 ChildNodeType* child = mNodes[i].getChild();
2708
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 303 times.
606 assert(child);
2709 if (child) {
2710 606 child->combine(other.mNodes[i].getValue(), other.isValueMaskOn(i), op);
2711 }
2712
3/4
✓ Branch 0 taken 358 times.
✓ Branch 1 taken 99 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 358 times.
1630 } else if (this->isChildMaskOff(i) && other.isChildMaskOn(i)) {
2713 // Combine this node's constant value with the other node's child.
2714 ChildNodeType* child = other.mNodes[i].getChild();
2715
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 358 times.
716 assert(child);
2716 if (child) {
2717 // Combine this node's constant value with the other node's child,
2718 // but use a new functor in which the A and B values are swapped,
2719 // since the constant value is the A value, not the B value.
2720 SwappedCombineOp<ValueType, CombineOp> swappedOp(op);
2721 716 child->combine(mNodes[i].getValue(), isValueMaskOn(i), swappedOp);
2722
2723 // Steal the other node's child.
2724 716 other.mChildMask.setOff(i);
2725 other.mNodes[i].setValue(zero);
2726 716 this->setChildNode(i, child);
2727 }
2728
2729 } else /*if (isChildMaskOn(i) && other.isChildMaskOn(i))*/ {
2730 // Combine this node's child with the other node's child.
2731 ChildNodeType
2732 *child = mNodes[i].getChild(),
2733 *otherChild = other.mNodes[i].getChild();
2734
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
198 assert(child);
2735
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
198 assert(otherChild);
2736 if (child && otherChild) {
2737 198 child->combine(*otherChild, op);
2738 }
2739 }
2740 }
2741 148 }
2742
2743
2744 template<typename ChildT, Index Log2Dim>
2745 template<typename CombineOp>
2746 inline void
2747 12 InternalNode<ChildT, Log2Dim>::combine(const ValueType& value, bool valueIsActive, CombineOp& op)
2748 {
2749 CombineArgs<ValueType> args;
2750
2751
2/2
✓ Branch 0 taken 110592 times.
✓ Branch 1 taken 6 times.
221196 for (Index i = 0; i < NUM_VALUES; ++i) {
2752
2/2
✓ Branch 0 taken 110577 times.
✓ Branch 1 taken 15 times.
221184 if (this->isChildMaskOff(i)) {
2753 // Combine this node's constant value with the given constant value.
2754 221154 op(args.setARef(mNodes[i].getValue())
2755 .setAIsActive(isValueMaskOn(i))
2756 .setBRef(value)
2757 .setBIsActive(valueIsActive));
2758 mNodes[i].setValue(args.result());
2759 mValueMask.set(i, args.resultIsActive());
2760 } else /*if (isChildMaskOn(i))*/ {
2761 // Combine this node's child with the given constant value.
2762 ChildNodeType* child = mNodes[i].getChild();
2763
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
30 assert(child);
2764 30 if (child) child->combine(value, valueIsActive, op);
2765 }
2766 }
2767 }
2768
2769
2770 ////////////////////////////////////////
2771
2772
2773 template<typename ChildT, Index Log2Dim>
2774 template<typename CombineOp, typename OtherNodeType>
2775 inline void
2776 16 InternalNode<ChildT, Log2Dim>::combine2(const InternalNode& other0, const OtherNodeType& other1,
2777 CombineOp& op)
2778 {
2779 CombineArgs<ValueType, typename OtherNodeType::ValueType> args;
2780
2781
2/2
✓ Branch 0 taken 147456 times.
✓ Branch 1 taken 8 times.
294928 for (Index i = 0; i < NUM_VALUES; ++i) {
2782
3/4
✓ Branch 0 taken 147448 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 147448 times.
✗ Branch 3 not taken.
589808 if (other0.isChildMaskOff(i) && other1.isChildMaskOff(i)) {
2783 op(args.setARef(other0.mNodes[i].getValue())
2784 .setAIsActive(other0.isValueMaskOn(i))
2785 .setBRef(other1.mNodes[i].getValue())
2786 .setBIsActive(other1.isValueMaskOn(i)));
2787 // Replace child i with a constant value.
2788 294896 this->makeChildNodeEmpty(i, args.result());
2789
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 147448 times.
294896 mValueMask.set(i, args.resultIsActive());
2790 } else {
2791
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
16 if (this->isChildMaskOff(i)) {
2792 // Add a new child with the same coordinates, etc. as the other node's child.
2793 const Coord& childOrigin = other0.isChildMaskOn(i)
2794
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
16 ? other0.mNodes[i].getChild()->origin()
2795 : other1.mNodes[i].getChild()->origin();
2796
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
16 this->setChildNode(i, new ChildNodeType(childOrigin, mNodes[i].getValue()));
2797 }
2798
2799
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
16 if (other0.isChildMaskOff(i)) {
2800 // Combine node1's child with node0's constant value
2801 // and write the result into child i.
2802 mNodes[i].getChild()->combine2(other0.mNodes[i].getValue(),
2803 *other1.mNodes[i].getChild(), other0.isValueMaskOn(i), op);
2804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
16 } else if (other1.isChildMaskOff(i)) {
2805 // Combine node0's child with node1's constant value
2806 // and write the result into child i.
2807 mNodes[i].getChild()->combine2(*other0.mNodes[i].getChild(),
2808 other1.mNodes[i].getValue(), other1.isValueMaskOn(i), op);
2809 } else {
2810 // Combine node0's child with node1's child
2811 // and write the result into child i.
2812 16 mNodes[i].getChild()->combine2(*other0.mNodes[i].getChild(),
2813 *other1.mNodes[i].getChild(), op);
2814 }
2815 }
2816 }
2817 16 }
2818
2819
2820 template<typename ChildT, Index Log2Dim>
2821 template<typename CombineOp, typename OtherNodeType>
2822 inline void
2823 InternalNode<ChildT, Log2Dim>::combine2(const ValueType& value, const OtherNodeType& other,
2824 bool valueIsActive, CombineOp& op)
2825 {
2826 CombineArgs<ValueType, typename OtherNodeType::ValueType> args;
2827
2828 for (Index i = 0; i < NUM_VALUES; ++i) {
2829 if (other.isChildMaskOff(i)) {
2830 op(args.setARef(value)
2831 .setAIsActive(valueIsActive)
2832 .setBRef(other.mNodes[i].getValue())
2833 .setBIsActive(other.isValueMaskOn(i)));
2834 // Replace child i with a constant value.
2835 this->makeChildNodeEmpty(i, args.result());
2836 mValueMask.set(i, args.resultIsActive());
2837 } else {
2838 typename OtherNodeType::ChildNodeType* otherChild = other.mNodes[i].getChild();
2839 assert(otherChild);
2840 if (this->isChildMaskOff(i)) {
2841 // Add a new child with the same coordinates, etc.
2842 // as the other node's child.
2843 this->setChildNode(i, new ChildNodeType(*otherChild));
2844 }
2845 // Combine the other node's child with a constant value
2846 // and write the result into child i.
2847 mNodes[i].getChild()->combine2(value, *otherChild, valueIsActive, op);
2848 }
2849 }
2850 }
2851
2852
2853 template<typename ChildT, Index Log2Dim>
2854 template<typename CombineOp, typename OtherValueType>
2855 inline void
2856 InternalNode<ChildT, Log2Dim>::combine2(const InternalNode& other, const OtherValueType& value,
2857 bool valueIsActive, CombineOp& op)
2858 {
2859 CombineArgs<ValueType, OtherValueType> args;
2860
2861 for (Index i = 0; i < NUM_VALUES; ++i) {
2862 if (other.isChildMaskOff(i)) {
2863 op(args.setARef(other.mNodes[i].getValue())
2864 .setAIsActive(other.isValueMaskOn(i))
2865 .setBRef(value)
2866 .setBIsActive(valueIsActive));
2867 // Replace child i with a constant value.
2868 this->makeChildNodeEmpty(i, args.result());
2869 mValueMask.set(i, args.resultIsActive());
2870 } else {
2871 ChildNodeType* otherChild = other.mNodes[i].getChild();
2872 assert(otherChild);
2873 if (this->isChildMaskOff(i)) {
2874 // Add a new child with the same coordinates, etc. as the other node's child.
2875 this->setChildNode(i,
2876 new ChildNodeType(otherChild->origin(), mNodes[i].getValue()));
2877 }
2878 // Combine the other node's child with a constant value
2879 // and write the result into child i.
2880 mNodes[i].getChild()->combine2(*otherChild, value, valueIsActive, op);
2881 }
2882 }
2883 }
2884
2885
2886 ////////////////////////////////////////
2887
2888
2889 template<typename ChildT, Index Log2Dim>
2890 template<typename BBoxOp>
2891 inline void
2892 20 InternalNode<ChildT, Log2Dim>::visitActiveBBox(BBoxOp& op) const
2893 {
2894
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 10 times.
28 for (ValueOnCIter i = this->cbeginValueOn(); i; ++i) {
2895 16 op.template operator()<LEVEL>(CoordBBox::createCube(i.getCoord(), ChildNodeType::DIM));
2896 }
2897 if (op.template descent<LEVEL>()) {
2898
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 10 times.
44 for (ChildOnCIter i = this->cbeginChildOn(); i; ++i) i->visitActiveBBox(op);
2899 } else {
2900 for (ChildOnCIter i = this->cbeginChildOn(); i; ++i) {
2901 op.template operator()<LEVEL>(i->getNodeBoundingBox());
2902 }
2903 }
2904 20 }
2905
2906
2907 template<typename ChildT, Index Log2Dim>
2908 template<typename VisitorOp>
2909 inline void
2910 InternalNode<ChildT, Log2Dim>::visit(VisitorOp& op)
2911 {
2912
10/20
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 8 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
45 doVisit<InternalNode, VisitorOp, ChildAllIter>(*this, op);
2913 45 }
2914
2915
2916 template<typename ChildT, Index Log2Dim>
2917 template<typename VisitorOp>
2918 inline void
2919 InternalNode<ChildT, Log2Dim>::visit(VisitorOp& op) const
2920 {
2921
10/20
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 16 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 16 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 16 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 2 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 2 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 2 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 2 times.
✗ Branch 29 not taken.
90 doVisit<const InternalNode, VisitorOp, ChildAllCIter>(*this, op);
2922 90 }
2923
2924
2925 template<typename ChildT, Index Log2Dim>
2926 template<typename NodeT, typename VisitorOp, typename ChildAllIterT>
2927 inline void
2928 270 InternalNode<ChildT, Log2Dim>::doVisit(NodeT& self, VisitorOp& op)
2929 {
2930 typename NodeT::ValueType val;
2931
3/3
✓ Branch 0 taken 655360 times.
✓ Branch 1 taken 327770 times.
✓ Branch 2 taken 45 times.
1966440 for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
2932
3/4
✓ Branch 1 taken 983040 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 163840 times.
✓ Branch 4 taken 819200 times.
1966080 if (op(iter)) continue;
2933
2/2
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 819000 times.
1638400 if (typename ChildAllIterT::ChildNodeType* child = iter.probeChild(val)) {
2934 child->visit(op);
2935 }
2936 }
2937 270 }
2938
2939
2940 ////////////////////////////////////////
2941
2942
2943 template<typename ChildT, Index Log2Dim>
2944 template<typename OtherNodeType, typename VisitorOp>
2945 inline void
2946 InternalNode<ChildT, Log2Dim>::visit2Node(OtherNodeType& other, VisitorOp& op)
2947 {
2948 doVisit2Node<InternalNode, OtherNodeType, VisitorOp, ChildAllIter,
2949
2/4
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
45 typename OtherNodeType::ChildAllIter>(*this, other, op);
2950 45 }
2951
2952
2953 template<typename ChildT, Index Log2Dim>
2954 template<typename OtherNodeType, typename VisitorOp>
2955 inline void
2956 InternalNode<ChildT, Log2Dim>::visit2Node(OtherNodeType& other, VisitorOp& op) const
2957 {
2958 doVisit2Node<const InternalNode, OtherNodeType, VisitorOp, ChildAllCIter,
2959 typename OtherNodeType::ChildAllCIter>(*this, other, op);
2960 }
2961
2962
2963 template<typename ChildT, Index Log2Dim>
2964 template<
2965 typename NodeT,
2966 typename OtherNodeT,
2967 typename VisitorOp,
2968 typename ChildAllIterT,
2969 typename OtherChildAllIterT>
2970 inline void
2971 90 InternalNode<ChildT, Log2Dim>::doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp& op)
2972 {
2973 // Allow the two nodes to have different ValueTypes, but not different dimensions.
2974 static_assert(OtherNodeT::NUM_VALUES == NodeT::NUM_VALUES,
2975 "visit2() requires nodes to have the same dimensions");
2976 static_assert(OtherNodeT::LEVEL == NodeT::LEVEL,
2977 "visit2() requires nodes to be at the same tree level");
2978
2979 typename NodeT::ValueType val;
2980 typename OtherNodeT::ValueType otherVal;
2981
2982 90 ChildAllIterT iter = self.beginChildAll();
2983 90 OtherChildAllIterT otherIter = other.beginChildAll();
2984
2985
3/4
✓ Branch 0 taken 327680 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 327680 times.
✗ Branch 3 not taken.
1310810 for ( ; iter && otherIter; ++iter, ++otherIter)
2986 {
2987 655360 const size_t skipBranch = static_cast<size_t>(op(iter, otherIter));
2988
2989 typename ChildAllIterT::ChildNodeType* child =
2990
2/2
✓ Branch 0 taken 294912 times.
✓ Branch 1 taken 32768 times.
655360 (skipBranch & 1U) ? nullptr : iter.probeChild(val);
2991 typename OtherChildAllIterT::ChildNodeType* otherChild =
2992
2/2
✓ Branch 0 taken 294912 times.
✓ Branch 1 taken 32768 times.
655360 (skipBranch & 2U) ? nullptr : otherIter.probeChild(otherVal);
2993
2994
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 327616 times.
655360 if (child != nullptr && otherChild != nullptr) {
2995 child->visit2Node(*otherChild, op);
2996
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 327608 times.
655232 } else if (child != nullptr) {
2997 child->visit2(otherIter, op);
2998
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 327600 times.
655216 } else if (otherChild != nullptr) {
2999 otherChild->visit2(iter, op, /*otherIsLHS=*/true);
3000 }
3001 }
3002 90 }
3003
3004
3005 ////////////////////////////////////////
3006
3007
3008 template<typename ChildT, Index Log2Dim>
3009 template<typename OtherChildAllIterType, typename VisitorOp>
3010 inline void
3011 InternalNode<ChildT, Log2Dim>::visit2(OtherChildAllIterType& otherIter,
3012 VisitorOp& op, bool otherIsLHS)
3013 {
3014
2/8
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
4 doVisit2<InternalNode, VisitorOp, ChildAllIter, OtherChildAllIterType>(
3015 *this, otherIter, op, otherIsLHS);
3016 8 }
3017
3018
3019 template<typename ChildT, Index Log2Dim>
3020 template<typename OtherChildAllIterType, typename VisitorOp>
3021 inline void
3022 InternalNode<ChildT, Log2Dim>::visit2(OtherChildAllIterType& otherIter,
3023 VisitorOp& op, bool otherIsLHS) const
3024 {
3025 doVisit2<const InternalNode, VisitorOp, ChildAllCIter, OtherChildAllIterType>(
3026 *this, otherIter, op, otherIsLHS);
3027 }
3028
3029
3030 template<typename ChildT, Index Log2Dim>
3031 template<typename NodeT, typename VisitorOp, typename ChildAllIterT, typename OtherChildAllIterT>
3032 inline void
3033
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
16 InternalNode<ChildT, Log2Dim>::doVisit2(NodeT& self, OtherChildAllIterT& otherIter,
3034 VisitorOp& op, bool otherIsLHS)
3035 {
3036
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
16 if (!otherIter) return;
3037
3038
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
16 const size_t skipBitMask = (otherIsLHS ? 2U : 1U);
3039
3040 typename NodeT::ValueType val;
3041
2/2
✓ Branch 1 taken 147456 times.
✓ Branch 2 taken 8 times.
294944 for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
3042 const size_t skipBranch = static_cast<size_t>(
3043
2/2
✓ Branch 0 taken 110592 times.
✓ Branch 1 taken 36864 times.
294912 otherIsLHS ? op(otherIter, iter) : op(iter, otherIter));
3044
3045 typename ChildAllIterT::ChildNodeType* child =
3046
2/2
✓ Branch 0 taken 143360 times.
✓ Branch 1 taken 4096 times.
294912 (skipBranch & skipBitMask) ? nullptr : iter.probeChild(val);
3047
3048
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 143353 times.
286720 if (child != nullptr) child->visit2(otherIter, op, otherIsLHS);
3049 }
3050 }
3051
3052
3053 ////////////////////////////////////////
3054
3055
3056 template<typename ChildT, Index Log2Dim>
3057 inline void
3058 2168 InternalNode<ChildT, Log2Dim>::writeBuffers(std::ostream& os, bool toHalf) const
3059 {
3060
2/2
✓ Branch 0 taken 91958 times.
✓ Branch 1 taken 1084 times.
186084 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
3061 183916 iter->writeBuffers(os, toHalf);
3062 }
3063 }
3064
3065
3066 template<typename ChildT, Index Log2Dim>
3067 inline void
3068 3706 InternalNode<ChildT, Log2Dim>::readBuffers(std::istream& is, bool fromHalf)
3069 {
3070
2/2
✓ Branch 0 taken 131427 times.
✓ Branch 1 taken 1853 times.
266560 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
3071 262854 iter->readBuffers(is, fromHalf);
3072 }
3073 }
3074
3075
3076 template<typename ChildT, Index Log2Dim>
3077 inline void
3078 100 InternalNode<ChildT, Log2Dim>::readBuffers(std::istream& is,
3079 const CoordBBox& clipBBox, bool fromHalf)
3080 {
3081
2/2
✓ Branch 0 taken 376 times.
✓ Branch 1 taken 50 times.
852 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
3082 // Stream in the branch rooted at this child.
3083 // (We can't skip over children that lie outside the clipping region,
3084 // because buffers are serialized in depth-first order and need to be
3085 // unserialized in the same order.)
3086 752 iter->readBuffers(is, clipBBox, fromHalf);
3087 }
3088
3089 // Get this tree's background value.
3090 100 ValueType background = zeroVal<ValueType>();
3091
1/4
✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
100 if (const void* bgPtr = io::getGridBackgroundValuePtr(is)) {
3092 100 background = *static_cast<const ValueType*>(bgPtr);
3093 }
3094
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
100 this->clip(clipBBox, background);
3095 }
3096
3097
3098 ////////////////////////////////////////
3099
3100
3101 template<typename ChildT, Index Log2Dim>
3102 void
3103 146844 InternalNode<ChildT, Log2Dim>::getNodeLog2Dims(std::vector<Index>& dims)
3104 {
3105 146844 dims.push_back(Log2Dim);
3106 73422 ChildNodeType::getNodeLog2Dims(dims);
3107 146844 }
3108
3109
3110 template<typename ChildT, Index Log2Dim>
3111 inline void
3112 446148910 InternalNode<ChildT, Log2Dim>::offsetToLocalCoord(Index n, Coord &xyz)
3113 {
3114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 223074455 times.
446148910 assert(n<(1<<3*Log2Dim));
3115 446148910 xyz.setX(n >> 2*Log2Dim);
3116 446148910 n &= ((1<<2*Log2Dim)-1);
3117 446148910 xyz.setY(n >> Log2Dim);
3118 446148910 xyz.setZ(n & ((1<<Log2Dim)-1));
3119 446148910 }
3120
3121
3122 template<typename ChildT, Index Log2Dim>
3123 inline Index
3124 InternalNode<ChildT, Log2Dim>::coordToOffset(const Coord& xyz)
3125 {
3126 7671356178 return (((xyz[0] & (DIM-1u)) >> ChildNodeType::TOTAL) << 2*Log2Dim)
3127 7671356178 + (((xyz[1] & (DIM-1u)) >> ChildNodeType::TOTAL) << Log2Dim)
3128 7671356178 + ((xyz[2] & (DIM-1u)) >> ChildNodeType::TOTAL);
3129 }
3130
3131
3132 template<typename ChildT, Index Log2Dim>
3133 inline Coord
3134 446083374 InternalNode<ChildT, Log2Dim>::offsetToGlobalCoord(Index n) const
3135 {
3136 Coord local;
3137 446083374 this->offsetToLocalCoord(n, local);
3138 local <<= ChildT::TOTAL;
3139 446083374 return local + this->origin();
3140 }
3141
3142
3143 ////////////////////////////////////////
3144
3145
3146 template<typename ChildT, Index Log2Dim>
3147 template<typename ArrayT>
3148 inline void
3149 139918 InternalNode<ChildT, Log2Dim>::getNodes(ArrayT& array)
3150 {
3151 using T = typename ArrayT::value_type;
3152 static_assert(std::is_pointer<T>::value, "argument to getNodes() must be a pointer array");
3153 using ArrayChildT = typename std::conditional<
3154 std::is_const<typename std::remove_pointer<T>::type>::value, const ChildT, ChildT>::type;
3155
2/2
✓ Branch 0 taken 182528 times.
✓ Branch 1 taken 77204 times.
488923 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
3156 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
3157 if (std::is_same<T, ArrayChildT*>::value) {
3158 346253 array.push_back(reinterpret_cast<T>(mNodes[iter.pos()].getChild()));
3159 } else {
3160 2752 iter->getNodes(array);//descent
3161 }
3162 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
3163 }
3164 139918 }
3165
3166 template<typename ChildT, Index Log2Dim>
3167 template<typename ArrayT>
3168 inline void
3169 7110 InternalNode<ChildT, Log2Dim>::getNodes(ArrayT& array) const
3170 {
3171 using T = typename ArrayT::value_type;
3172 static_assert(std::is_pointer<T>::value, "argument to getNodes() must be a pointer array");
3173 static_assert(std::is_const<typename std::remove_pointer<T>::type>::value,
3174 "argument to getNodes() must be an array of const node pointers");
3175
2/2
✓ Branch 0 taken 26603 times.
✓ Branch 1 taken 3555 times.
60316 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
3176 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
3177 if (std::is_same<T, const ChildT*>::value) {
3178 52844 array.push_back(reinterpret_cast<T>(mNodes[iter.pos()].getChild()));
3179 } else {
3180 362 iter->getNodes(array);//descent
3181 }
3182 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
3183 }
3184 7110 }
3185
3186
3187 ////////////////////////////////////////
3188
3189
3190 template<typename ChildT, Index Log2Dim>
3191 template<typename ArrayT>
3192 inline void
3193 441638 InternalNode<ChildT, Log2Dim>::stealNodes(ArrayT& array, const ValueType& value, bool state)
3194 {
3195 using T = typename ArrayT::value_type;
3196 static_assert(std::is_pointer<T>::value, "argument to stealNodes() must be a pointer array");
3197 using ArrayChildT = typename std::conditional<
3198 std::is_const<typename std::remove_pointer<T>::type>::value, const ChildT, ChildT>::type;
3199 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
3200
2/2
✓ Branch 0 taken 24981846 times.
✓ Branch 1 taken 220819 times.
50405330 for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) {
3201 const Index n = iter.pos();
3202 if (std::is_same<T, ArrayChildT*>::value) {
3203 49652608 array.push_back(reinterpret_cast<T>(mNodes[n].getChild()));
3204
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24826304 times.
49652608 mValueMask.set(n, state);
3205 mNodes[n].setValue(value);
3206 } else {
3207 311084 iter->stealNodes(array, value, state);//descent
3208 }
3209 }
3210 if (std::is_same<T, ArrayChildT*>::value) mChildMask.setOff();
3211 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
3212 441638 }
3213
3214
3215 ////////////////////////////////////////
3216
3217
3218 template<typename ChildT, Index Log2Dim>
3219 inline void
3220
2/2
✓ Branch 0 taken 732 times.
✓ Branch 1 taken 5763 times.
12990 InternalNode<ChildT, Log2Dim>::resetBackground(const ValueType& oldBackground,
3221 const ValueType& newBackground)
3222 {
3223
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 5763 times.
11570 if (math::isExactlyEqual(oldBackground, newBackground)) return;
3224
2/2
✓ Branch 0 taken 462848 times.
✓ Branch 1 taken 22 times.
925740 for (Index i = 0; i < NUM_VALUES; ++i) {
3225
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 462844 times.
925696 if (this->isChildMaskOn(i)) {
3226 8 mNodes[i].getChild()->resetBackground(oldBackground, newBackground);
3227
2/2
✓ Branch 0 taken 462843 times.
✓ Branch 1 taken 1 times.
925688 } else if (this->isValueMaskOff(i)) {
3228
2/2
✓ Branch 0 taken 176123 times.
✓ Branch 1 taken 286720 times.
925686 if (math::isApproxEqual(mNodes[i].getValue(), oldBackground)) {
3229 mNodes[i].setValue(newBackground);
3230
2/2
✓ Branch 0 taken 98304 times.
✓ Branch 1 taken 188416 times.
573440 } else if (math::isApproxEqual(mNodes[i].getValue(), math::negative(oldBackground))) {
3231 mNodes[i].setValue(math::negative(newBackground));
3232 }
3233 }
3234 }
3235 }
3236
3237 template<typename ChildT, Index Log2Dim>
3238 template<typename OtherChildNodeType, Index OtherLog2Dim>
3239 inline bool
3240 14612 InternalNode<ChildT, Log2Dim>::hasSameTopology(
3241 const InternalNode<OtherChildNodeType, OtherLog2Dim>* other) const
3242 {
3243
3/4
✓ Branch 0 taken 7298 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 7298 times.
✗ Branch 3 not taken.
29208 if (Log2Dim != OtherLog2Dim || mChildMask != other->mChildMask ||
3244 mValueMask != other->mValueMask) return false;
3245
2/2
✓ Branch 0 taken 11843 times.
✓ Branch 1 taken 7298 times.
38282 for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) {
3246
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1440 times.
✓ Branch 2 taken 10403 times.
23686 if (!iter->hasSameTopology(other->mNodes[iter.pos()].getChild())) return false;
3247 }
3248 14596 return true;
3249 }
3250
3251
3252 template<typename ChildT, Index Log2Dim>
3253 inline void
3254 151158 InternalNode<ChildT, Log2Dim>::resetChildNode(Index i, ChildNodeType* child)
3255 {
3256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 75579 times.
151158 assert(child);
3257
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 75578 times.
151158 if (this->isChildMaskOn(i)) {
3258
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
4 delete mNodes[i].getChild();
3259 } else {
3260 151156 mChildMask.setOn(i);
3261 151156 mValueMask.setOff(i);
3262 }
3263 mNodes[i].setChild(child);
3264 151158 }
3265
3266 template<typename ChildT, Index Log2Dim>
3267 inline void
3268 6285596 InternalNode<ChildT, Log2Dim>::setChildNode(Index i, ChildNodeType* child)
3269 {
3270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3142798 times.
6285596 assert(child);
3271
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3142798 times.
6285596 assert(mChildMask.isOff(i));
3272 6285596 mChildMask.setOn(i);
3273 6285596 mValueMask.setOff(i);
3274 mNodes[i].setChild(child);
3275 6285596 }
3276
3277
3278 template<typename ChildT, Index Log2Dim>
3279 inline ChildT*
3280 11810394 InternalNode<ChildT, Log2Dim>::unsetChildNode(Index i, const ValueType& value)
3281 {
3282
2/2
✓ Branch 0 taken 5868325 times.
✓ Branch 1 taken 36872 times.
11810394 if (this->isChildMaskOff(i)) {
3283 mNodes[i].setValue(value);
3284 11736650 return nullptr;
3285 }
3286 ChildNodeType* child = mNodes[i].getChild();
3287 73744 mChildMask.setOff(i);
3288 mNodes[i].setValue(value);
3289 73744 return child;
3290 }
3291
3292
3293 template<typename ChildT, Index Log2Dim>
3294 inline void
3295 11810394 InternalNode<ChildT, Log2Dim>::makeChildNodeEmpty(Index n, const ValueType& value)
3296 {
3297
2/2
✓ Branch 1 taken 36872 times.
✓ Branch 2 taken 5868325 times.
11869202 delete this->unsetChildNode(n, value);
3298 11810394 }
3299
3300 template<typename ChildT, Index Log2Dim>
3301 inline ChildT*
3302 43990496 InternalNode<ChildT, Log2Dim>::getChildNode(Index n)
3303 {
3304
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21905157 times.
43990496 assert(this->isChildMaskOn(n));
3305 43990496 return mNodes[n].getChild();
3306 }
3307
3308
3309 template<typename ChildT, Index Log2Dim>
3310 inline const ChildT*
3311 46776752 InternalNode<ChildT, Log2Dim>::getChildNode(Index n) const
3312 {
3313 46776752 assert(this->isChildMaskOn(n));
3314 46776752 return mNodes[n].getChild();
3315 }
3316
3317 } // namespace tree
3318 } // namespace OPENVDB_VERSION_NAME
3319 } // namespace openvdb
3320
3321 #endif // OPENVDB_TREE_INTERNALNODE_HAS_BEEN_INCLUDED
3322