Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright Contributors to the OpenVDB Project | ||
2 | // SPDX-License-Identifier: MPL-2.0 | ||
3 | // | ||
4 | /// @file Composite.h | ||
5 | /// | ||
6 | /// @brief Functions to efficiently perform various compositing operations on grids | ||
7 | /// | ||
8 | /// @authors Peter Cucka, Mihai Alden, Ken Museth | ||
9 | |||
10 | #ifndef OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED | ||
11 | #define OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED | ||
12 | |||
13 | #include <openvdb/Platform.h> | ||
14 | #include <openvdb/Exceptions.h> | ||
15 | #include <openvdb/Types.h> | ||
16 | #include <openvdb/Grid.h> | ||
17 | #include <openvdb/math/Math.h> // for isExactlyEqual() | ||
18 | #include <openvdb/openvdb.h> | ||
19 | #include "Merge.h" | ||
20 | #include "ValueTransformer.h" // for transformValues() | ||
21 | #include "Prune.h"// for prune | ||
22 | #include "SignedFloodFill.h" // for signedFloodFill() | ||
23 | |||
24 | #include <tbb/blocked_range.h> | ||
25 | #include <tbb/parallel_for.h> | ||
26 | #include <tbb/parallel_reduce.h> | ||
27 | #include <tbb/task_group.h> | ||
28 | |||
29 | #include <type_traits> | ||
30 | #include <functional> | ||
31 | |||
32 | namespace openvdb { | ||
33 | OPENVDB_USE_VERSION_NAMESPACE | ||
34 | namespace OPENVDB_VERSION_NAME { | ||
35 | namespace tools { | ||
36 | |||
37 | /// @brief Given two level set grids, replace the A grid with the union of A and B. | ||
38 | /// @throw ValueError if the background value of either grid is not greater than zero. | ||
39 | /// @note This operation always leaves the B grid empty. | ||
40 | template<typename GridOrTreeT> | ||
41 | void csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune = true); | ||
42 | /// @brief Given two level set grids, replace the A grid with the intersection of A and B. | ||
43 | /// @throw ValueError if the background value of either grid is not greater than zero. | ||
44 | /// @note This operation always leaves the B grid empty. | ||
45 | template<typename GridOrTreeT> | ||
46 | void csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune = true); | ||
47 | /// @brief Given two level set grids, replace the A grid with the difference A / B. | ||
48 | /// @throw ValueError if the background value of either grid is not greater than zero. | ||
49 | /// @note This operation always leaves the B grid empty. | ||
50 | template<typename GridOrTreeT> | ||
51 | void csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune = true); | ||
52 | |||
53 | /// @brief Threaded CSG union operation that produces a new grid or tree from | ||
54 | /// immutable inputs. | ||
55 | /// @return The CSG union of the @a and @b level set inputs. | ||
56 | template<typename GridOrTreeT> | ||
57 | typename GridOrTreeT::Ptr csgUnionCopy(const GridOrTreeT& a, const GridOrTreeT& b); | ||
58 | /// @brief Threaded CSG intersection operation that produces a new grid or tree from | ||
59 | /// immutable inputs. | ||
60 | /// @return The CSG intersection of the @a and @b level set inputs. | ||
61 | template<typename GridOrTreeT> | ||
62 | typename GridOrTreeT::Ptr csgIntersectionCopy(const GridOrTreeT& a, const GridOrTreeT& b); | ||
63 | /// @brief Threaded CSG difference operation that produces a new grid or tree from | ||
64 | /// immutable inputs. | ||
65 | /// @return The CSG difference of the @a and @b level set inputs. | ||
66 | template<typename GridOrTreeT> | ||
67 | typename GridOrTreeT::Ptr csgDifferenceCopy(const GridOrTreeT& a, const GridOrTreeT& b); | ||
68 | |||
69 | /// @brief Given grids A and B, compute max(a, b) per voxel (using sparse traversal). | ||
70 | /// Store the result in the A grid and leave the B grid empty. | ||
71 | template<typename GridOrTreeT> | ||
72 | void compMax(GridOrTreeT& a, GridOrTreeT& b); | ||
73 | /// @brief Given grids A and B, compute min(a, b) per voxel (using sparse traversal). | ||
74 | /// Store the result in the A grid and leave the B grid empty. | ||
75 | template<typename GridOrTreeT> | ||
76 | void compMin(GridOrTreeT& a, GridOrTreeT& b); | ||
77 | /// @brief Given grids A and B, compute a + b per voxel (using sparse traversal). | ||
78 | /// Store the result in the A grid and leave the B grid empty. | ||
79 | template<typename GridOrTreeT> | ||
80 | void compSum(GridOrTreeT& a, GridOrTreeT& b); | ||
81 | /// @brief Given grids A and B, compute a * b per voxel (using sparse traversal). | ||
82 | /// Store the result in the A grid and leave the B grid empty. | ||
83 | template<typename GridOrTreeT> | ||
84 | void compMul(GridOrTreeT& a, GridOrTreeT& b); | ||
85 | /// @brief Given grids A and B, compute a / b per voxel (using sparse traversal). | ||
86 | /// Store the result in the A grid and leave the B grid empty. | ||
87 | template<typename GridOrTreeT> | ||
88 | void compDiv(GridOrTreeT& a, GridOrTreeT& b); | ||
89 | |||
90 | /// Copy the active voxels of B into A. | ||
91 | template<typename GridOrTreeT> | ||
92 | void compReplace(GridOrTreeT& a, const GridOrTreeT& b); | ||
93 | |||
94 | |||
95 | //////////////////////////////////////// | ||
96 | |||
97 | |||
98 | namespace composite { | ||
99 | |||
100 | // composite::min() and composite::max() for non-vector types compare with operator<(). | ||
101 | template<typename T> inline | ||
102 | const typename std::enable_if<!VecTraits<T>::IsVec, T>::type& // = T if T is not a vector type | ||
103 | min(const T& a, const T& b) { return std::min(a, b); } | ||
104 | |||
105 | template<typename T> inline | ||
106 | const typename std::enable_if<!VecTraits<T>::IsVec, T>::type& | ||
107 | max(const T& a, const T& b) { return std::max(a, b); } | ||
108 | |||
109 | |||
110 | // composite::min() and composite::max() for OpenVDB vector types compare by magnitude. | ||
111 | template<typename T> inline | ||
112 | const typename std::enable_if<VecTraits<T>::IsVec, T>::type& // = T if T is a vector type | ||
113 |
2/2✓ Branch 0 taken 37375 times.
✓ Branch 1 taken 37375 times.
|
149500 | min(const T& a, const T& b) |
114 | { | ||
115 | const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr(); | ||
116 |
3/4✓ Branch 0 taken 37375 times.
✓ Branch 1 taken 37375 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 37375 times.
|
149500 | return (aMag < bMag ? a : (bMag < aMag ? b : std::min(a, b))); |
117 | } | ||
118 | |||
119 | template<typename T> inline | ||
120 | const typename std::enable_if<VecTraits<T>::IsVec, T>::type& | ||
121 |
2/2✓ Branch 0 taken 37375 times.
✓ Branch 1 taken 37375 times.
|
149500 | max(const T& a, const T& b) |
122 | { | ||
123 | const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr(); | ||
124 |
3/4✓ Branch 0 taken 37375 times.
✓ Branch 1 taken 37375 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 37375 times.
|
149500 | return (aMag < bMag ? b : (bMag < aMag ? a : std::max(a, b))); |
125 | } | ||
126 | |||
127 | |||
128 | template<typename T> inline | ||
129 | typename std::enable_if<!std::is_integral<T>::value, T>::type // = T if T is not an integer type | ||
130 | 112125 | divide(const T& a, const T& b) { return a / b; } | |
131 | |||
132 | template<typename T> inline | ||
133 | typename std::enable_if<std::is_integral<T>::value, T>::type // = T if T is an integer type | ||
134 | divide(const T& a, const T& b) | ||
135 | { | ||
136 | const T zero(0); | ||
137 |
2/8✗ Branch 0 not taken.
✓ Branch 1 taken 37375 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 37375 times.
|
74750 | if (b != zero) return a / b; |
138 |
4/8✓ Branch 0 taken 1 times.
✓ Branch 1 taken 37374 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 37374 times.
✓ Branch 7 taken 1 times.
|
74750 | if (a == zero) return 0; |
139 |
2/8✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 37372 times.
|
37374 | return (a > 0 ? std::numeric_limits<T>::max() : -std::numeric_limits<T>::max()); |
140 | } | ||
141 | |||
142 | // If b is true, return a / 1 = a. | ||
143 | // If b is false and a is true, return 1 / 0 = inf = MAX_BOOL = 1 = a. | ||
144 | // If b is false and a is false, return 0 / 0 = NaN = 0 = a. | ||
145 | inline bool divide(bool a, bool /*b*/) { return a; } | ||
146 | |||
147 | |||
148 | /// @cond OPENVDB_DOCS_INTERNAL | ||
149 | |||
150 | enum CSGOperation { CSG_UNION, CSG_INTERSECTION, CSG_DIFFERENCE }; | ||
151 | |||
152 | template<typename TreeType, CSGOperation Operation> | ||
153 | 3 | struct BuildPrimarySegment | |
154 | { | ||
155 | using ValueType = typename TreeType::ValueType; | ||
156 | using TreePtrType = typename TreeType::Ptr; | ||
157 | using LeafNodeType = typename TreeType::LeafNodeType; | ||
158 | using NodeMaskType = typename LeafNodeType::NodeMaskType; | ||
159 | using RootNodeType = typename TreeType::RootNodeType; | ||
160 | using NodeChainType = typename RootNodeType::NodeChainType; | ||
161 | using InternalNodeType = typename NodeChainType::template Get<1>; | ||
162 | |||
163 | 6 | BuildPrimarySegment(const TreeType& lhs, const TreeType& rhs) | |
164 | 6 | : mSegment(new TreeType(lhs.background())) | |
165 | , mLhsTree(&lhs) | ||
166 | 6 | , mRhsTree(&rhs) | |
167 | { | ||
168 | } | ||
169 | |||
170 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | void operator()() const |
171 | { | ||
172 | std::vector<const LeafNodeType*> leafNodes; | ||
173 | |||
174 | { | ||
175 | std::vector<const InternalNodeType*> internalNodes; | ||
176 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | mLhsTree->getNodes(internalNodes); |
177 | |||
178 | 12 | ProcessInternalNodes op(internalNodes, *mRhsTree, *mSegment, leafNodes); | |
179 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op); |
180 | } | ||
181 | |||
182 | 6 | ProcessLeafNodes op(leafNodes, *mRhsTree, *mSegment); | |
183 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op); |
184 | } | ||
185 | |||
186 | TreePtrType& segment() { return mSegment; } | ||
187 | |||
188 | private: | ||
189 | |||
190 | struct ProcessInternalNodes { | ||
191 | |||
192 |
3/12✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
3 | ProcessInternalNodes(std::vector<const InternalNodeType*>& lhsNodes, |
193 | const TreeType& rhsTree, TreeType& outputTree, | ||
194 | std::vector<const LeafNodeType*>& outputLeafNodes) | ||
195 |
3/12✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
3 | : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front()) |
196 | , mRhsTree(&rhsTree) | ||
197 | , mLocalTree(mRhsTree->background()) | ||
198 | , mOutputTree(&outputTree) | ||
199 | , mLocalLeafNodes() | ||
200 |
3/12✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
|
3 | , mOutputLeafNodes(&outputLeafNodes) |
201 | { | ||
202 | } | ||
203 | |||
204 | 5 | ProcessInternalNodes(ProcessInternalNodes& other, tbb::split) | |
205 | 5 | : mLhsNodes(other.mLhsNodes) | |
206 | 5 | , mRhsTree(other.mRhsTree) | |
207 | , mLocalTree(mRhsTree->background()) | ||
208 | , mOutputTree(&mLocalTree) | ||
209 | , mLocalLeafNodes() | ||
210 | 5 | , mOutputLeafNodes(&mLocalLeafNodes) | |
211 | { | ||
212 | } | ||
213 | |||
214 | 10 | void join(ProcessInternalNodes& other) | |
215 | { | ||
216 | 10 | mOutputTree->merge(*other.mOutputTree); | |
217 | 20 | mOutputLeafNodes->insert(mOutputLeafNodes->end(), | |
218 | 10 | other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end()); | |
219 | } | ||
220 | |||
221 | 48 | void operator()(const tbb::blocked_range<size_t>& range) | |
222 | { | ||
223 | 48 | tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree); | |
224 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
48 | tree::ValueAccessor<TreeType> outputAcc(*mOutputTree); |
225 | |||
226 | std::vector<const LeafNodeType*> tmpLeafNodes; | ||
227 | |||
228 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
|
96 | for (size_t n = range.begin(), N = range.end(); n < N; ++n) { |
229 | |||
230 | 48 | const InternalNodeType& lhsNode = *mLhsNodes[n]; | |
231 | const Coord& ijk = lhsNode.origin(); | ||
232 | 48 | const InternalNodeType * rhsNode = | |
233 | rhsAcc.template probeConstNode<InternalNodeType>(ijk); | ||
234 | |||
235 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
|
48 | if (rhsNode) { |
236 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
24 | lhsNode.getNodes(*mOutputLeafNodes); |
237 | } else { | ||
238 | if (Operation == CSG_INTERSECTION) { | ||
239 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
8 | if (rhsAcc.getValue(ijk) < ValueType(0.0)) { |
240 | tmpLeafNodes.clear(); | ||
241 | ✗ | lhsNode.getNodes(tmpLeafNodes); | |
242 | ✗ | for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) { | |
243 | ✗ | outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i])); | |
244 | } | ||
245 | } | ||
246 | } else { // Union & Difference | ||
247 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
|
16 | if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) { |
248 | tmpLeafNodes.clear(); | ||
249 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
16 | lhsNode.getNodes(tmpLeafNodes); |
250 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 8 times.
|
200 | for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) { |
251 |
3/6✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 92 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 92 times.
✗ Branch 8 not taken.
|
184 | outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i])); |
252 | } | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | } // end range loop | ||
257 | } | ||
258 | |||
259 | InternalNodeType const * const * const mLhsNodes; | ||
260 | TreeType const * const mRhsTree; | ||
261 | TreeType mLocalTree; | ||
262 | TreeType * const mOutputTree; | ||
263 | |||
264 | std::vector<const LeafNodeType*> mLocalLeafNodes; | ||
265 | std::vector<const LeafNodeType*> * const mOutputLeafNodes; | ||
266 | }; // struct ProcessInternalNodes | ||
267 | |||
268 |
3/12✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 21 taken 1 times.
✗ Branch 22 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✓ Branch 29 taken 1 times.
✗ Branch 30 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
|
14 | struct ProcessLeafNodes { |
269 | |||
270 |
3/12✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
3 | ProcessLeafNodes(std::vector<const LeafNodeType*>& lhsNodes, |
271 | const TreeType& rhsTree, TreeType& output) | ||
272 |
3/12✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
3 | : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front()) |
273 | , mRhsTree(&rhsTree) | ||
274 | , mLocalTree(mRhsTree->background()) | ||
275 |
3/12✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
|
3 | , mOutputTree(&output) |
276 | { | ||
277 | } | ||
278 | |||
279 | 11 | ProcessLeafNodes(ProcessLeafNodes& other, tbb::split) | |
280 | 11 | : mLhsNodes(other.mLhsNodes) | |
281 | 11 | , mRhsTree(other.mRhsTree) | |
282 | , mLocalTree(mRhsTree->background()) | ||
283 | 11 | , mOutputTree(&mLocalTree) | |
284 | { | ||
285 | } | ||
286 | |||
287 | 11 | void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); } | |
288 | |||
289 | 324 | void operator()(const tbb::blocked_range<size_t>& range) | |
290 | { | ||
291 | 324 | tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree); | |
292 |
1/2✓ Branch 1 taken 162 times.
✗ Branch 2 not taken.
|
324 | tree::ValueAccessor<TreeType> outputAcc(*mOutputTree); |
293 | |||
294 |
2/2✓ Branch 0 taken 162 times.
✓ Branch 1 taken 162 times.
|
648 | for (size_t n = range.begin(), N = range.end(); n < N; ++n) { |
295 | |||
296 | 324 | const LeafNodeType& lhsNode = *mLhsNodes[n]; | |
297 | const Coord& ijk = lhsNode.origin(); | ||
298 | |||
299 | const LeafNodeType* rhsNodePt = rhsAcc.probeConstLeaf(ijk); | ||
300 | |||
301 |
2/2✓ Branch 0 taken 123 times.
✓ Branch 1 taken 39 times.
|
324 | if (rhsNodePt) { // combine overlapping nodes |
302 | |||
303 |
1/2✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
|
246 | LeafNodeType* outputNode = outputAcc.touchLeaf(ijk); |
304 |
1/2✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
|
246 | ValueType * outputData = outputNode->buffer().data(); |
305 | NodeMaskType& outputMask = outputNode->getValueMask(); | ||
306 | |||
307 |
1/2✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
|
246 | const ValueType * lhsData = lhsNode.buffer().data(); |
308 | const NodeMaskType& lhsMask = lhsNode.getValueMask(); | ||
309 | |||
310 |
1/2✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
|
246 | const ValueType * rhsData = rhsNodePt->buffer().data(); |
311 | const NodeMaskType& rhsMask = rhsNodePt->getValueMask(); | ||
312 | |||
313 | if (Operation == CSG_INTERSECTION) { | ||
314 |
2/2✓ Branch 0 taken 20992 times.
✓ Branch 1 taken 41 times.
|
42066 | for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) { |
315 | 41984 | const bool fromRhs = lhsData[pos] < rhsData[pos]; | |
316 |
2/2✓ Branch 0 taken 13294 times.
✓ Branch 1 taken 7698 times.
|
41984 | outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos]; |
317 |
2/2✓ Branch 0 taken 7698 times.
✓ Branch 1 taken 13294 times.
|
41984 | outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos)); |
318 | } | ||
319 | } else if (Operation == CSG_DIFFERENCE){ | ||
320 |
2/2✓ Branch 0 taken 20992 times.
✓ Branch 1 taken 41 times.
|
42066 | for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) { |
321 |
2/2✓ Branch 0 taken 14883 times.
✓ Branch 1 taken 6109 times.
|
41984 | const ValueType rhsVal = math::negative(rhsData[pos]); |
322 | 41984 | const bool fromRhs = lhsData[pos] < rhsVal; | |
323 |
2/2✓ Branch 0 taken 14883 times.
✓ Branch 1 taken 6109 times.
|
41984 | outputData[pos] = fromRhs ? rhsVal : lhsData[pos]; |
324 |
2/2✓ Branch 0 taken 6109 times.
✓ Branch 1 taken 14883 times.
|
41984 | outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos)); |
325 | } | ||
326 | } else { // Union | ||
327 |
2/2✓ Branch 0 taken 20992 times.
✓ Branch 1 taken 41 times.
|
42066 | for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) { |
328 | 41984 | const bool fromRhs = lhsData[pos] > rhsData[pos]; | |
329 |
2/2✓ Branch 0 taken 12521 times.
✓ Branch 1 taken 8471 times.
|
41984 | outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos]; |
330 |
2/2✓ Branch 0 taken 8471 times.
✓ Branch 1 taken 12521 times.
|
41984 | outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos)); |
331 | } | ||
332 | } | ||
333 | |||
334 | } else { | ||
335 | if (Operation == CSG_INTERSECTION) { | ||
336 |
3/4✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 10 times.
|
26 | if (rhsAcc.getValue(ijk) < ValueType(0.0)) { |
337 |
3/6✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
|
6 | outputAcc.addLeaf(new LeafNodeType(lhsNode)); |
338 | } | ||
339 | } else { // Union & Difference | ||
340 |
3/4✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 6 times.
|
52 | if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) { |
341 |
3/6✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
|
40 | outputAcc.addLeaf(new LeafNodeType(lhsNode)); |
342 | } | ||
343 | } | ||
344 | } | ||
345 | } // end range loop | ||
346 | } | ||
347 | |||
348 | LeafNodeType const * const * const mLhsNodes; | ||
349 | TreeType const * const mRhsTree; | ||
350 | TreeType mLocalTree; | ||
351 | TreeType * const mOutputTree; | ||
352 | }; // struct ProcessLeafNodes | ||
353 | |||
354 | TreePtrType mSegment; | ||
355 | TreeType const * const mLhsTree; | ||
356 | TreeType const * const mRhsTree; | ||
357 | }; // struct BuildPrimarySegment | ||
358 | |||
359 | |||
360 | template<typename TreeType, CSGOperation Operation> | ||
361 |
3/12✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
|
6 | struct BuildSecondarySegment |
362 | { | ||
363 | using ValueType = typename TreeType::ValueType; | ||
364 | using TreePtrType = typename TreeType::Ptr; | ||
365 | using LeafNodeType = typename TreeType::LeafNodeType; | ||
366 | using NodeMaskType = typename LeafNodeType::NodeMaskType; | ||
367 | using RootNodeType = typename TreeType::RootNodeType; | ||
368 | using NodeChainType = typename RootNodeType::NodeChainType; | ||
369 | using InternalNodeType = typename NodeChainType::template Get<1>; | ||
370 | |||
371 | 6 | BuildSecondarySegment(const TreeType& lhs, const TreeType& rhs) | |
372 | 6 | : mSegment(new TreeType(lhs.background())) | |
373 | , mLhsTree(&lhs) | ||
374 | 6 | , mRhsTree(&rhs) | |
375 | { | ||
376 | } | ||
377 | |||
378 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | void operator()() const |
379 | { | ||
380 | std::vector<const LeafNodeType*> leafNodes; | ||
381 | |||
382 | { | ||
383 | std::vector<const InternalNodeType*> internalNodes; | ||
384 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | mRhsTree->getNodes(internalNodes); |
385 | |||
386 | 12 | ProcessInternalNodes op(internalNodes, *mLhsTree, *mSegment, leafNodes); | |
387 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op); |
388 | } | ||
389 | |||
390 | 6 | ProcessLeafNodes op(leafNodes, *mLhsTree, *mSegment); | |
391 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op); |
392 | } | ||
393 | |||
394 | TreePtrType& segment() { return mSegment; } | ||
395 | |||
396 | private: | ||
397 | |||
398 | struct ProcessInternalNodes { | ||
399 | |||
400 |
3/12✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
3 | ProcessInternalNodes(std::vector<const InternalNodeType*>& rhsNodes, |
401 | const TreeType& lhsTree, TreeType& outputTree, | ||
402 | std::vector<const LeafNodeType*>& outputLeafNodes) | ||
403 |
3/12✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
3 | : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front()) |
404 | , mLhsTree(&lhsTree) | ||
405 | , mLocalTree(mLhsTree->background()) | ||
406 | , mOutputTree(&outputTree) | ||
407 | , mLocalLeafNodes() | ||
408 |
3/12✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
|
3 | , mOutputLeafNodes(&outputLeafNodes) |
409 | { | ||
410 | } | ||
411 | |||
412 | ✗ | ProcessInternalNodes(ProcessInternalNodes& other, tbb::split) | |
413 | ✗ | : mRhsNodes(other.mRhsNodes) | |
414 | ✗ | , mLhsTree(other.mLhsTree) | |
415 | , mLocalTree(mLhsTree->background()) | ||
416 | , mOutputTree(&mLocalTree) | ||
417 | , mLocalLeafNodes() | ||
418 | ✗ | , mOutputLeafNodes(&mLocalLeafNodes) | |
419 | { | ||
420 | } | ||
421 | |||
422 | ✗ | void join(ProcessInternalNodes& other) | |
423 | { | ||
424 | ✗ | mOutputTree->merge(*other.mOutputTree); | |
425 | ✗ | mOutputLeafNodes->insert(mOutputLeafNodes->end(), | |
426 | ✗ | other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end()); | |
427 | } | ||
428 | |||
429 | 24 | void operator()(const tbb::blocked_range<size_t>& range) | |
430 | { | ||
431 | 24 | tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree); | |
432 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
24 | tree::ValueAccessor<TreeType> outputAcc(*mOutputTree); |
433 | |||
434 | std::vector<const LeafNodeType*> tmpLeafNodes; | ||
435 | |||
436 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
|
48 | for (size_t n = range.begin(), N = range.end(); n < N; ++n) { |
437 | |||
438 | 24 | const InternalNodeType& rhsNode = *mRhsNodes[n]; | |
439 | const Coord& ijk = rhsNode.origin(); | ||
440 | 24 | const InternalNodeType * lhsNode = | |
441 | lhsAcc.template probeConstNode<InternalNodeType>(ijk); | ||
442 | |||
443 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
24 | if (lhsNode) { |
444 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
24 | rhsNode.getNodes(*mOutputLeafNodes); |
445 | } else { | ||
446 | if (Operation == CSG_INTERSECTION) { | ||
447 | ✗ | if (lhsAcc.getValue(ijk) < ValueType(0.0)) { | |
448 | tmpLeafNodes.clear(); | ||
449 | ✗ | rhsNode.getNodes(tmpLeafNodes); | |
450 | ✗ | for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) { | |
451 | ✗ | outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i])); | |
452 | } | ||
453 | } | ||
454 | } else if (Operation == CSG_DIFFERENCE) { | ||
455 | ✗ | if (lhsAcc.getValue(ijk) < ValueType(0.0)) { | |
456 | tmpLeafNodes.clear(); | ||
457 | ✗ | rhsNode.getNodes(tmpLeafNodes); | |
458 | ✗ | for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) { | |
459 | ✗ | LeafNodeType* outputNode = new LeafNodeType(*tmpLeafNodes[i]); | |
460 | ✗ | outputNode->negate(); | |
461 | ✗ | outputAcc.addLeaf(outputNode); | |
462 | } | ||
463 | } | ||
464 | } else { // Union | ||
465 | ✗ | if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) { | |
466 | tmpLeafNodes.clear(); | ||
467 | ✗ | rhsNode.getNodes(tmpLeafNodes); | |
468 | ✗ | for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) { | |
469 | ✗ | outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i])); | |
470 | } | ||
471 | } | ||
472 | } | ||
473 | } | ||
474 | } // end range loop | ||
475 | } | ||
476 | |||
477 | InternalNodeType const * const * const mRhsNodes; | ||
478 | TreeType const * const mLhsTree; | ||
479 | TreeType mLocalTree; | ||
480 | TreeType * const mOutputTree; | ||
481 | |||
482 | std::vector<const LeafNodeType*> mLocalLeafNodes; | ||
483 | std::vector<const LeafNodeType*> * const mOutputLeafNodes; | ||
484 | }; // struct ProcessInternalNodes | ||
485 | |||
486 |
3/12✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 21 taken 1 times.
✗ Branch 22 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✓ Branch 29 taken 1 times.
✗ Branch 30 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
|
3 | struct ProcessLeafNodes { |
487 | |||
488 |
3/12✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
3 | ProcessLeafNodes(std::vector<const LeafNodeType*>& rhsNodes, |
489 | const TreeType& lhsTree, TreeType& output) | ||
490 |
3/12✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
3 | : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front()) |
491 | , mLhsTree(&lhsTree) | ||
492 | , mLocalTree(mLhsTree->background()) | ||
493 |
3/12✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
|
3 | , mOutputTree(&output) |
494 | { | ||
495 | } | ||
496 | |||
497 | ✗ | ProcessLeafNodes(ProcessLeafNodes& rhs, tbb::split) | |
498 | ✗ | : mRhsNodes(rhs.mRhsNodes) | |
499 | ✗ | , mLhsTree(rhs.mLhsTree) | |
500 | , mLocalTree(mLhsTree->background()) | ||
501 | ✗ | , mOutputTree(&mLocalTree) | |
502 | { | ||
503 | } | ||
504 | |||
505 | ✗ | void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); } | |
506 | |||
507 | 570 | void operator()(const tbb::blocked_range<size_t>& range) | |
508 | { | ||
509 | 570 | tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree); | |
510 |
1/2✓ Branch 1 taken 285 times.
✗ Branch 2 not taken.
|
570 | tree::ValueAccessor<TreeType> outputAcc(*mOutputTree); |
511 | |||
512 |
2/2✓ Branch 0 taken 285 times.
✓ Branch 1 taken 285 times.
|
1140 | for (size_t n = range.begin(), N = range.end(); n < N; ++n) { |
513 | |||
514 | 570 | const LeafNodeType& rhsNode = *mRhsNodes[n]; | |
515 | const Coord& ijk = rhsNode.origin(); | ||
516 | |||
517 | const LeafNodeType* lhsNode = lhsAcc.probeConstLeaf(ijk); | ||
518 | |||
519 |
2/2✓ Branch 0 taken 162 times.
✓ Branch 1 taken 123 times.
|
570 | if (!lhsNode) { |
520 | if (Operation == CSG_INTERSECTION) { | ||
521 |
2/4✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 54 times.
|
108 | if (lhsAcc.getValue(ijk) < ValueType(0.0)) { |
522 | ✗ | outputAcc.addLeaf(new LeafNodeType(rhsNode)); | |
523 | } | ||
524 | } else if (Operation == CSG_DIFFERENCE) { | ||
525 |
2/4✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 54 times.
|
108 | if (lhsAcc.getValue(ijk) < ValueType(0.0)) { |
526 | ✗ | LeafNodeType* outputNode = new LeafNodeType(rhsNode); | |
527 | ✗ | outputNode->negate(); | |
528 | ✗ | outputAcc.addLeaf(outputNode); | |
529 | } | ||
530 | } else { // Union | ||
531 |
2/4✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
✗ Branch 4 not taken.
|
108 | if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) { |
532 |
3/6✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 54 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 54 times.
✗ Branch 8 not taken.
|
108 | outputAcc.addLeaf(new LeafNodeType(rhsNode)); |
533 | } | ||
534 | } | ||
535 | } | ||
536 | } // end range loop | ||
537 | } | ||
538 | |||
539 | LeafNodeType const * const * const mRhsNodes; | ||
540 | TreeType const * const mLhsTree; | ||
541 | TreeType mLocalTree; | ||
542 | TreeType * const mOutputTree; | ||
543 | }; // struct ProcessLeafNodes | ||
544 | |||
545 | TreePtrType mSegment; | ||
546 | TreeType const * const mLhsTree; | ||
547 | TreeType const * const mRhsTree; | ||
548 | }; // struct BuildSecondarySegment | ||
549 | |||
550 | |||
551 | template<CSGOperation Operation, typename TreeType> | ||
552 | typename TreeType::Ptr | ||
553 | 6 | doCSGCopy(const TreeType& lhs, const TreeType& rhs) | |
554 | { | ||
555 | 6 | BuildPrimarySegment<TreeType, Operation> primary(lhs, rhs); | |
556 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | BuildSecondarySegment<TreeType, Operation> secondary(lhs, rhs); |
557 | |||
558 | // Exploiting nested parallelism | ||
559 | tbb::task_group tasks; | ||
560 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | tasks.run(primary); |
561 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | tasks.run(secondary); |
562 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | tasks.wait(); |
563 | |||
564 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | primary.segment()->merge(*secondary.segment()); |
565 | |||
566 | // The leafnode (level = 0) sign is set in the segment construction. | ||
567 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | tools::signedFloodFill(*primary.segment(), /*threaded=*/true, /*grainSize=*/1, /*minLevel=*/1); |
568 | |||
569 | 6 | return primary.segment(); | |
570 | } | ||
571 | |||
572 | |||
573 | //////////////////////////////////////// | ||
574 | |||
575 | |||
576 | template<typename TreeType> | ||
577 | struct GridOrTreeConstructor | ||
578 | { | ||
579 | using TreeTypePtr = typename TreeType::Ptr; | ||
580 | static TreeTypePtr construct(const TreeType&, TreeTypePtr& tree) { return tree; } | ||
581 | }; | ||
582 | |||
583 | |||
584 | template<typename TreeType> | ||
585 | struct GridOrTreeConstructor<Grid<TreeType> > | ||
586 | { | ||
587 | using GridType = Grid<TreeType>; | ||
588 | using GridTypePtr = typename Grid<TreeType>::Ptr; | ||
589 | using TreeTypePtr = typename TreeType::Ptr; | ||
590 | |||
591 | 6 | static GridTypePtr construct(const GridType& grid, TreeTypePtr& tree) { | |
592 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
12 | GridTypePtr maskGrid(GridType::create(tree)); |
593 |
3/8✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
|
12 | maskGrid->setTransform(grid.transform().copy()); |
594 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | maskGrid->insertMeta(grid); |
595 | 6 | return maskGrid; | |
596 | } | ||
597 | }; | ||
598 | |||
599 | |||
600 | //////////////////////////////////////// | ||
601 | |||
602 | /// List of pairs of leaf node pointers | ||
603 | template <typename LeafT> | ||
604 | using LeafPairList = std::vector<std::pair<LeafT*, LeafT*>>; | ||
605 | |||
606 | /// Transfers leaf nodes from a source tree into a | ||
607 | /// destination tree, unless it already exists in the destination tree | ||
608 | /// in which case pointers to both leaf nodes are added to a list for | ||
609 | /// subsequent compositing operations. | ||
610 | template <typename TreeT> | ||
611 | 10 | void transferLeafNodes(TreeT &srcTree, TreeT &dstTree, | |
612 | LeafPairList<typename TreeT::LeafNodeType> &overlapping) | ||
613 | { | ||
614 | using LeafT = typename TreeT::LeafNodeType; | ||
615 | tree::ValueAccessor<TreeT> acc(dstTree);//destination | ||
616 | std::vector<LeafT*> srcLeafNodes; | ||
617 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
10 | srcLeafNodes.reserve(srcTree.leafCount()); |
618 | srcTree.stealNodes(srcLeafNodes); | ||
619 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
10 | srcTree.clear(); |
620 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
|
30 | for (LeafT *srcLeaf : srcLeafNodes) { |
621 | 20 | LeafT *dstLeaf = acc.probeLeaf(srcLeaf->origin()); | |
622 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
20 | if (dstLeaf) { |
623 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
10 | overlapping.emplace_back(dstLeaf, srcLeaf);//dst, src |
624 | } else { | ||
625 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
10 | acc.addLeaf(srcLeaf); |
626 | } | ||
627 | } | ||
628 | 10 | } | |
629 | |||
630 | /// Template specialization of compActiveLeafVoxels | ||
631 | template <typename TreeT, typename OpT> | ||
632 | inline | ||
633 | typename std::enable_if< | ||
634 | !std::is_same<typename TreeT::ValueType, bool>::value && | ||
635 | !std::is_same<typename TreeT::BuildType, ValueMask>::value && | ||
636 | std::is_same<typename TreeT::LeafNodeType::Buffer::ValueType, | ||
637 | typename TreeT::LeafNodeType::Buffer::StorageType>::value>::type | ||
638 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op) |
639 | { | ||
640 | using LeafT = typename TreeT::LeafNodeType; | ||
641 | LeafPairList<LeafT> overlapping;//dst, src | ||
642 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
6 | transferLeafNodes(srcTree, dstTree, overlapping); |
643 | |||
644 | using RangeT = tbb::blocked_range<size_t>; | ||
645 |
2/6✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
12 | tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](const RangeT& r) { |
646 |
6/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
|
6 | for (auto i = r.begin(); i != r.end(); ++i) { |
647 | 3 | LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second; | |
648 | dstLeaf->getValueMask() |= srcLeaf->getValueMask(); | ||
649 | 3 | auto *ptr = dstLeaf->buffer().data(); | |
650 |
6/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
|
8 | for (auto v = srcLeaf->cbeginValueOn(); v; ++v) op(ptr[v.pos()], *v); |
651 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
6 | delete srcLeaf; |
652 | } | ||
653 | }); | ||
654 | 6 | } | |
655 | |||
656 | /// Template specialization of compActiveLeafVoxels | ||
657 | template <typename TreeT, typename OpT> | ||
658 | inline | ||
659 | typename std::enable_if< | ||
660 | std::is_same<typename TreeT::BuildType, ValueMask>::value && | ||
661 | std::is_same<typename TreeT::ValueType, bool>::value>::type | ||
662 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT) |
663 | { | ||
664 | using LeafT = typename TreeT::LeafNodeType; | ||
665 | LeafPairList<LeafT> overlapping;//dst, src | ||
666 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | transferLeafNodes(srcTree, dstTree, overlapping); |
667 | |||
668 | using RangeT = tbb::blocked_range<size_t>; | ||
669 |
3/8✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
4 | tbb::parallel_for(RangeT(0, overlapping.size()), [&overlapping](const RangeT& r) { |
670 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (auto i = r.begin(); i != r.end(); ++i) { |
671 | 1 | overlapping[i].first->getValueMask() |= overlapping[i].second->getValueMask(); | |
672 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | delete overlapping[i].second; |
673 | } | ||
674 | }); | ||
675 | 1 | } | |
676 | |||
677 | /// Template specialization of compActiveLeafVoxels | ||
678 | template <typename TreeT, typename OpT> | ||
679 | inline | ||
680 | typename std::enable_if< | ||
681 | std::is_same<typename TreeT::ValueType, bool>::value && | ||
682 | !std::is_same<typename TreeT::BuildType, ValueMask>::value>::type | ||
683 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op) |
684 | { | ||
685 | using LeafT = typename TreeT::LeafNodeType; | ||
686 | LeafPairList<LeafT> overlapping;//dst, src | ||
687 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | transferLeafNodes(srcTree, dstTree, overlapping); |
688 | |||
689 | using RangeT = tbb::blocked_range<size_t>; | ||
690 | using WordT = typename LeafT::Buffer::WordType; | ||
691 |
2/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
3 | tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](const RangeT& r) { |
692 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (auto i = r.begin(); i != r.end(); ++i) { |
693 | 1 | LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second; | |
694 | WordT *w1 = dstLeaf->buffer().data(); | ||
695 | const WordT *w2 = srcLeaf->buffer().data(); | ||
696 | const WordT *w3 = &(srcLeaf->getValueMask().template getWord<WordT>(0)); | ||
697 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
|
9 | for (Index32 n = LeafT::Buffer::WORD_COUNT; n--; ++w1) { |
698 | 8 | WordT tmp = *w1, state = *w3++; | |
699 | 8 | op (tmp, *w2++); | |
700 | 8 | *w1 = (state & tmp) | (~state & *w1);//inactive values are unchanged | |
701 | } | ||
702 | dstLeaf->getValueMask() |= srcLeaf->getValueMask(); | ||
703 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | delete srcLeaf; |
704 | } | ||
705 | }); | ||
706 | 1 | } | |
707 | |||
708 | /// Default functor for compActiveLeafVoxels | ||
709 | template <typename TreeT> | ||
710 | struct CopyOp | ||
711 | { | ||
712 | using ValueT = typename TreeT::ValueType; | ||
713 | CopyOp() = default; | ||
714 | 1 | void operator()(ValueT& dst, const ValueT& src) const { dst = src; } | |
715 | }; | ||
716 | |||
717 | template <typename TreeT> | ||
718 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
113 | void validateLevelSet(const TreeT& tree, const std::string& gridName = std::string("")) |
719 | { | ||
720 | using ValueT = typename TreeT::ValueType; | ||
721 | const ValueT zero = zeroVal<ValueT>(); | ||
722 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 60 times.
|
113 | if (!(tree.background() > zero)) { |
723 | 6 | std::stringstream ss; | |
724 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | ss << "expected grid "; |
725 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
|
6 | if (!gridName.empty()) ss << gridName << " "; |
726 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | ss << "outside value > 0, got " << tree.background(); |
727 |
2/6✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
15 | OPENVDB_THROW(ValueError, ss.str()); |
728 | } | ||
729 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
|
110 | if (!(-tree.background() < zero)) { |
730 | ✗ | std::stringstream ss; | |
731 | ✗ | ss << "expected grid "; | |
732 | ✗ | if (!gridName.empty()) ss << gridName << " "; | |
733 | ✗ | ss << "inside value < 0, got " << -tree.background(); | |
734 | ✗ | OPENVDB_THROW(ValueError, ss.str()); | |
735 | } | ||
736 | 110 | } | |
737 | |||
738 | /// @endcond | ||
739 | |||
740 | } // namespace composite | ||
741 | |||
742 | |||
743 | template<typename GridOrTreeT> | ||
744 | void | ||
745 | 14 | compMax(GridOrTreeT& aTree, GridOrTreeT& bTree) | |
746 | { | ||
747 | using Adapter = TreeAdapter<GridOrTreeT>; | ||
748 | using TreeT = typename Adapter::TreeType; | ||
749 | using ValueT = typename TreeT::ValueType; | ||
750 | struct Local { | ||
751 |
2/2✓ Branch 0 taken 71564 times.
✓ Branch 1 taken 572868 times.
|
793933 | static inline void op(CombineArgs<ValueT>& args) { |
752 | 74750 | args.setResult(composite::max(args.a(), args.b())); | |
753 | 793933 | } | |
754 | }; | ||
755 | Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false); | ||
756 | 14 | } | |
757 | |||
758 | |||
759 | template<typename GridOrTreeT> | ||
760 | void | ||
761 | 8 | compMin(GridOrTreeT& aTree, GridOrTreeT& bTree) | |
762 | { | ||
763 | using Adapter = TreeAdapter<GridOrTreeT>; | ||
764 | using TreeT = typename Adapter::TreeType; | ||
765 | using ValueT = typename TreeT::ValueType; | ||
766 | struct Local { | ||
767 | 149500 | static inline void op(CombineArgs<ValueT>& args) { | |
768 | 74750 | args.setResult(composite::min(args.a(), args.b())); | |
769 | } | ||
770 | }; | ||
771 | Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false); | ||
772 | } | ||
773 | |||
774 | |||
775 | template<typename GridOrTreeT> | ||
776 | void | ||
777 | 10 | compSum(GridOrTreeT& aTree, GridOrTreeT& bTree) | |
778 | { | ||
779 | using Adapter = TreeAdapter<GridOrTreeT>; | ||
780 | using TreeT = typename Adapter::TreeType; | ||
781 | struct Local { | ||
782 | 196584 | static inline void op(CombineArgs<typename TreeT::ValueType>& args) { | |
783 | 196584 | args.setResult(args.a() + args.b()); | |
784 | } | ||
785 | }; | ||
786 | Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false); | ||
787 | } | ||
788 | |||
789 | |||
790 | template<typename GridOrTreeT> | ||
791 | void | ||
792 | 8 | compMul(GridOrTreeT& aTree, GridOrTreeT& bTree) | |
793 | { | ||
794 | using Adapter = TreeAdapter<GridOrTreeT>; | ||
795 | using TreeT = typename Adapter::TreeType; | ||
796 | struct Local { | ||
797 | 149500 | static inline void op(CombineArgs<typename TreeT::ValueType>& args) { | |
798 | 149500 | args.setResult(args.a() * args.b()); | |
799 | } | ||
800 | }; | ||
801 | Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false); | ||
802 | 8 | } | |
803 | |||
804 | |||
805 | template<typename GridOrTreeT> | ||
806 | void | ||
807 | 13 | compDiv(GridOrTreeT& aTree, GridOrTreeT& bTree) | |
808 | { | ||
809 | using Adapter = TreeAdapter<GridOrTreeT>; | ||
810 | using TreeT = typename Adapter::TreeType; | ||
811 | struct Local { | ||
812 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37375 times.
|
261625 | static inline void op(CombineArgs<typename TreeT::ValueType>& args) { |
813 | 74750 | args.setResult(composite::divide(args.a(), args.b())); | |
814 | 261625 | } | |
815 | }; | ||
816 | Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false); | ||
817 | 13 | } | |
818 | |||
819 | |||
820 | //////////////////////////////////////// | ||
821 | |||
822 | |||
823 | template<typename TreeT> | ||
824 | struct CompReplaceOp | ||
825 | { | ||
826 | TreeT* const aTree; | ||
827 | |||
828 | 4 | CompReplaceOp(TreeT& _aTree): aTree(&_aTree) {} | |
829 | |||
830 | /// @note fill operation is not thread safe | ||
831 | ✗ | void operator()(const typename TreeT::ValueOnCIter& iter) const | |
832 | { | ||
833 | ✗ | CoordBBox bbox; | |
834 | ✗ | iter.getBoundingBox(bbox); | |
835 | ✗ | aTree->fill(bbox, *iter); | |
836 | } | ||
837 | |||
838 | 8 | void operator()(const typename TreeT::LeafCIter& leafIter) const | |
839 | { | ||
840 | 8 | tree::ValueAccessor<TreeT> acc(*aTree); | |
841 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4 times.
|
36 | for (typename TreeT::LeafCIter::LeafNodeT::ValueOnCIter iter = |
842 | leafIter->cbeginValueOn(); iter; ++iter) | ||
843 | { | ||
844 |
2/6✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
28 | acc.setValue(iter.getCoord(), *iter); |
845 | } | ||
846 | } | ||
847 | }; | ||
848 | |||
849 | |||
850 | template<typename GridOrTreeT> | ||
851 | void | ||
852 | 8 | compReplace(GridOrTreeT& aTree, const GridOrTreeT& bTree) | |
853 | { | ||
854 | using Adapter = TreeAdapter<GridOrTreeT>; | ||
855 | using TreeT = typename Adapter::TreeType; | ||
856 | using ValueOnCIterT = typename TreeT::ValueOnCIter; | ||
857 | |||
858 | // Copy active states (but not values) from B to A. | ||
859 | Adapter::tree(aTree).topologyUnion(Adapter::tree(bTree)); | ||
860 | |||
861 | CompReplaceOp<TreeT> op(Adapter::tree(aTree)); | ||
862 | |||
863 | // Copy all active tile values from B to A. | ||
864 | ValueOnCIterT iter = bTree.cbeginValueOn(); | ||
865 | 8 | iter.setMaxDepth(iter.getLeafDepth() - 1); // don't descend into leaf nodes | |
866 | 8 | foreach(iter, op, /*threaded=*/false); | |
867 | |||
868 | // Copy all active voxel values from B to A. | ||
869 | 8 | foreach(Adapter::tree(bTree).cbeginLeaf(), op); | |
870 | } | ||
871 | |||
872 | |||
873 | //////////////////////////////////////// | ||
874 | |||
875 | |||
876 | template<typename GridOrTreeT> | ||
877 | void | ||
878 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
46 | csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune) |
879 | { | ||
880 | using Adapter = TreeAdapter<GridOrTreeT>; | ||
881 | using TreeT = typename Adapter::TreeType; | ||
882 | TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b); | ||
883 |
3/4✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25 times.
✓ Branch 5 taken 1 times.
|
47 | composite::validateLevelSet(aTree, "A"); |
884 |
2/4✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
|
45 | composite::validateLevelSet(bTree, "B"); |
885 | 45 | CsgUnionOp<TreeT> op(bTree, Steal()); | |
886 | 45 | tree::DynamicNodeManager<TreeT> nodeManager(aTree); | |
887 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
45 | nodeManager.foreachTopDown(op); |
888 |
2/4✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 25 times.
✗ Branch 4 not taken.
|
45 | if (prune) tools::pruneLevelSet(aTree); |
889 | 45 | } | |
890 | |||
891 | template<typename GridOrTreeT> | ||
892 | void | ||
893 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
1 | csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune) |
894 | { | ||
895 | using Adapter = TreeAdapter<GridOrTreeT>; | ||
896 | using TreeT = typename Adapter::TreeType; | ||
897 | TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b); | ||
898 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
2 | composite::validateLevelSet(aTree, "A"); |
899 | ✗ | composite::validateLevelSet(bTree, "B"); | |
900 | ✗ | CsgIntersectionOp<TreeT> op(bTree, Steal()); | |
901 | ✗ | tree::DynamicNodeManager<TreeT> nodeManager(aTree); | |
902 | ✗ | nodeManager.foreachTopDown(op); | |
903 | ✗ | if (prune) tools::pruneLevelSet(aTree); | |
904 | } | ||
905 | |||
906 | template<typename GridOrTreeT> | ||
907 | void | ||
908 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
11 | csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune) |
909 | { | ||
910 | using Adapter = TreeAdapter<GridOrTreeT>; | ||
911 | using TreeT = typename Adapter::TreeType; | ||
912 | TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b); | ||
913 |
3/4✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 1 times.
|
12 | composite::validateLevelSet(aTree, "A"); |
914 |
3/6✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
|
20 | composite::validateLevelSet(bTree, "B"); |
915 | CsgDifferenceOp<TreeT> op(bTree, Steal()); | ||
916 | 10 | tree::DynamicNodeManager<TreeT> nodeManager(aTree); | |
917 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
10 | nodeManager.foreachTopDown(op); |
918 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
|
10 | if (prune) tools::pruneLevelSet(aTree); |
919 | } | ||
920 | |||
921 | |||
922 | template<typename GridOrTreeT> | ||
923 | typename GridOrTreeT::Ptr | ||
924 | 2 | csgUnionCopy(const GridOrTreeT& a, const GridOrTreeT& b) | |
925 | { | ||
926 | using Adapter = TreeAdapter<GridOrTreeT>; | ||
927 | using TreePtrT = typename Adapter::TreeType::Ptr; | ||
928 | |||
929 | 2 | TreePtrT output = composite::doCSGCopy<composite::CSG_UNION>( | |
930 | Adapter::tree(a), Adapter::tree(b)); | ||
931 | |||
932 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
4 | return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output); |
933 | } | ||
934 | |||
935 | |||
936 | template<typename GridOrTreeT> | ||
937 | typename GridOrTreeT::Ptr | ||
938 | 2 | csgIntersectionCopy(const GridOrTreeT& a, const GridOrTreeT& b) | |
939 | { | ||
940 | using Adapter = TreeAdapter<GridOrTreeT>; | ||
941 | using TreePtrT = typename Adapter::TreeType::Ptr; | ||
942 | |||
943 | 2 | TreePtrT output = composite::doCSGCopy<composite::CSG_INTERSECTION>( | |
944 | Adapter::tree(a), Adapter::tree(b)); | ||
945 | |||
946 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
4 | return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output); |
947 | } | ||
948 | |||
949 | |||
950 | template<typename GridOrTreeT> | ||
951 | typename GridOrTreeT::Ptr | ||
952 | 1 | csgDifferenceCopy(const GridOrTreeT& a, const GridOrTreeT& b) | |
953 | { | ||
954 | using Adapter = TreeAdapter<GridOrTreeT>; | ||
955 | using TreePtrT = typename Adapter::TreeType::Ptr; | ||
956 | |||
957 | 1 | TreePtrT output = composite::doCSGCopy<composite::CSG_DIFFERENCE>( | |
958 | Adapter::tree(a), Adapter::tree(b)); | ||
959 | |||
960 | 2 | return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output); | |
961 | } | ||
962 | |||
963 | //////////////////////////////////////////////////////// | ||
964 | |||
965 | /// @brief Composite the active values in leaf nodes, i.e. active | ||
966 | /// voxels, of a source tree into a destination tree. | ||
967 | /// | ||
968 | /// @param srcTree source tree from which active voxels are composited. | ||
969 | /// | ||
970 | /// @param dstTree destination tree into which active voxels are composited. | ||
971 | /// | ||
972 | /// @param op a functor of the form <tt>void op(T& dst, const T& src)</tt>, | ||
973 | /// where @c T is the @c ValueType of the tree, that composites | ||
974 | /// a source value into a destination value. By default | ||
975 | /// it copies the value from src to dst. | ||
976 | /// | ||
977 | /// @details All active voxels in the source tree will | ||
978 | /// be active in the destination tree, and their value is | ||
979 | /// determined by a use-defined functor (OpT op) that operates on the | ||
980 | /// source and destination values. The only exception is when | ||
981 | /// the tree type is MaskTree, in which case no functor is | ||
982 | /// needed since by defintion a MaskTree has no values (only topology). | ||
983 | /// | ||
984 | /// @warning This function only operated on leaf node values, | ||
985 | /// i.e. tile values are ignored. | ||
986 | template<typename TreeT, typename OpT = composite::CopyOp<TreeT> > | ||
987 | void | ||
988 | 10 | compActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op = composite::CopyOp<TreeT>()) | |
989 | { | ||
990 | 10 | composite::doCompActiveLeafVoxels<TreeT, OpT>(srcTree, dstTree, op); | |
991 | 10 | } | |
992 | |||
993 | |||
994 | //////////////////////////////////////// | ||
995 | |||
996 | |||
997 | // Explicit Template Instantiation | ||
998 | |||
999 | #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION | ||
1000 | |||
1001 | #ifdef OPENVDB_INSTANTIATE_COMPOSITE | ||
1002 | #include <openvdb/util/ExplicitInstantiation.h> | ||
1003 | #endif | ||
1004 | |||
1005 | #define _FUNCTION(TreeT) \ | ||
1006 | void csgUnion(TreeT&, TreeT&, bool) | ||
1007 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
1008 | #undef _FUNCTION | ||
1009 | |||
1010 | #define _FUNCTION(TreeT) \ | ||
1011 | void csgUnion(Grid<TreeT>&, Grid<TreeT>&, bool) | ||
1012 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
1013 | #undef _FUNCTION | ||
1014 | |||
1015 | #define _FUNCTION(TreeT) \ | ||
1016 | void csgIntersection(TreeT&, TreeT&, bool) | ||
1017 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
1018 | #undef _FUNCTION | ||
1019 | |||
1020 | #define _FUNCTION(TreeT) \ | ||
1021 | void csgIntersection(Grid<TreeT>&, Grid<TreeT>&, bool) | ||
1022 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
1023 | #undef _FUNCTION | ||
1024 | |||
1025 | #define _FUNCTION(TreeT) \ | ||
1026 | void csgDifference(TreeT&, TreeT&, bool) | ||
1027 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
1028 | #undef _FUNCTION | ||
1029 | |||
1030 | #define _FUNCTION(TreeT) \ | ||
1031 | void csgDifference(Grid<TreeT>&, Grid<TreeT>&, bool) | ||
1032 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
1033 | #undef _FUNCTION | ||
1034 | |||
1035 | #define _FUNCTION(TreeT) \ | ||
1036 | TreeT::Ptr csgUnionCopy(const TreeT&, const TreeT&) | ||
1037 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
1038 | #undef _FUNCTION | ||
1039 | |||
1040 | #define _FUNCTION(TreeT) \ | ||
1041 | Grid<TreeT>::Ptr csgUnionCopy(const Grid<TreeT>&, const Grid<TreeT>&) | ||
1042 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
1043 | #undef _FUNCTION | ||
1044 | |||
1045 | #define _FUNCTION(TreeT) \ | ||
1046 | TreeT::Ptr csgIntersectionCopy(const TreeT&, const TreeT&) | ||
1047 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
1048 | #undef _FUNCTION | ||
1049 | |||
1050 | #define _FUNCTION(TreeT) \ | ||
1051 | Grid<TreeT>::Ptr csgIntersectionCopy(const Grid<TreeT>&, const Grid<TreeT>&) | ||
1052 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
1053 | #undef _FUNCTION | ||
1054 | |||
1055 | #define _FUNCTION(TreeT) \ | ||
1056 | TreeT::Ptr csgDifferenceCopy(const TreeT&, const TreeT&) | ||
1057 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
1058 | #undef _FUNCTION | ||
1059 | |||
1060 | #define _FUNCTION(TreeT) \ | ||
1061 | Grid<TreeT>::Ptr csgDifferenceCopy(const Grid<TreeT>&, const Grid<TreeT>&) | ||
1062 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
1063 | #undef _FUNCTION | ||
1064 | |||
1065 | #define _FUNCTION(TreeT) \ | ||
1066 | void compMax(TreeT&, TreeT&) | ||
1067 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
1068 | #undef _FUNCTION | ||
1069 | |||
1070 | #define _FUNCTION(TreeT) \ | ||
1071 | void compMax(Grid<TreeT>&, Grid<TreeT>&) | ||
1072 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
1073 | #undef _FUNCTION | ||
1074 | |||
1075 | #define _FUNCTION(TreeT) \ | ||
1076 | void compMin(TreeT&, TreeT&) | ||
1077 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
1078 | #undef _FUNCTION | ||
1079 | |||
1080 | #define _FUNCTION(TreeT) \ | ||
1081 | void compMin(Grid<TreeT>&, Grid<TreeT>&) | ||
1082 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
1083 | #undef _FUNCTION | ||
1084 | |||
1085 | #define _FUNCTION(TreeT) \ | ||
1086 | void compSum(TreeT&, TreeT&) | ||
1087 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
1088 | #undef _FUNCTION | ||
1089 | |||
1090 | #define _FUNCTION(TreeT) \ | ||
1091 | void compSum(Grid<TreeT>&, Grid<TreeT>&) | ||
1092 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
1093 | #undef _FUNCTION | ||
1094 | |||
1095 | #define _FUNCTION(TreeT) \ | ||
1096 | void compDiv(TreeT&, TreeT&) | ||
1097 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
1098 | #undef _FUNCTION | ||
1099 | |||
1100 | #define _FUNCTION(TreeT) \ | ||
1101 | void compDiv(Grid<TreeT>&, Grid<TreeT>&) | ||
1102 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
1103 | #undef _FUNCTION | ||
1104 | |||
1105 | #define _FUNCTION(TreeT) \ | ||
1106 | void compReplace(TreeT&, const TreeT&) | ||
1107 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
1108 | #undef _FUNCTION | ||
1109 | |||
1110 | #define _FUNCTION(TreeT) \ | ||
1111 | void compReplace(Grid<TreeT>&, const Grid<TreeT>&) | ||
1112 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
1113 | #undef _FUNCTION | ||
1114 | |||
1115 | #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION | ||
1116 | |||
1117 | |||
1118 | } // namespace tools | ||
1119 | } // namespace OPENVDB_VERSION_NAME | ||
1120 | } // namespace openvdb | ||
1121 | |||
1122 | #endif // OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED | ||
1123 |