OpenVDB: Composite.h Source File

OpenVDB 6.1.0

Composite.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2019 DreamWorks Animation LLC
4 //
5 // All rights reserved. This software is distributed under the
6 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
7 //
8 // Redistributions of source code must retain the above copyright
9 // and license notice and the following restrictions and disclaimer.
10 //
11 // * Neither the name of DreamWorks Animation nor the names of
12 // its contributors may be used to endorse or promote products derived
13 // from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
27 // LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
28 //
30 //
36
37 #ifndef OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
38 #define OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
39
40 #include <openvdb/Platform.h>
41 #include <openvdb/Exceptions.h>
42 #include <openvdb/Types.h>
43 #include <openvdb/Grid.h>
44 #include <openvdb/math/Math.h> // for isExactlyEqual()
45 #include "ValueTransformer.h" // for transformValues()
46 #include "Prune.h"// for prune
47 #include "SignedFloodFill.h" // for signedFloodFill()
48
49 #include <tbb/blocked_range.h>
50 #include <tbb/parallel_for.h>
51 #include <tbb/parallel_reduce.h>
52 #include <tbb/task_group.h>
53 #include <tbb/task_scheduler_init.h>
54
55 #include <type_traits>
56 #include <functional>
57
58 namespace openvdb {
59 OPENVDB_USE_VERSION_NAMESPACE
60 namespace OPENVDB_VERSION_NAME {
61 namespace tools {
62
66 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
67 inline void csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
71 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
72 inline void csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
76 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
77 inline void csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
78
82 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
83 inline typename GridOrTreeT::Ptr csgUnionCopy(const GridOrTreeT& a, const GridOrTreeT& b);
87 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
88 inline typename GridOrTreeT::Ptr csgIntersectionCopy(const GridOrTreeT& a, const GridOrTreeT& b);
92 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
93 inline typename GridOrTreeT::Ptr csgDifferenceCopy(const GridOrTreeT& a, const GridOrTreeT& b);
94
97 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
98 inline void compMax(GridOrTreeT& a, GridOrTreeT& b);
101 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
102 inline void compMin(GridOrTreeT& a, GridOrTreeT& b);
105 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
106 inline void compSum(GridOrTreeT& a, GridOrTreeT& b);
109 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
110 inline void compMul(GridOrTreeT& a, GridOrTreeT& b);
113 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
114 inline void compDiv(GridOrTreeT& a, GridOrTreeT& b);
115
117 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
118 inline void compReplace(GridOrTreeT& a, const GridOrTreeT& b);
119
120
122
123
124 namespace composite {
125
126 // composite::min() and composite::max() for non-vector types compare with operator<().
127 template<typename T> inline
128 const typename std::enable_if<!VecTraits<T>::IsVec, T>::type& // = T if T is not a vector type
129 min(const T& a, const T& b) { return std::min(a, b); }
130
131 template<typename T> inline
132 const typename std::enable_if<!VecTraits<T>::IsVec, T>::type&
133 max(const T& a, const T& b) { return std::max(a, b); }
134
135
136 // composite::min() and composite::max() for OpenVDB vector types compare by magnitude.
137 template<typename T> inline
138 const typename std::enable_if<VecTraits<T>::IsVec, T>::type& // = T if T is a vector type
139 min(const T& a, const T& b)
140 {
141 const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
142 return (aMag < bMag ? a : (bMag < aMag ? b : std::min(a, b)));
143 }
144
145 template<typename T> inline
146 const typename std::enable_if<VecTraits<T>::IsVec, T>::type&
147 max(const T& a, const T& b)
148 {
149 const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
150 return (aMag < bMag ? b : (bMag < aMag ? a : std::max(a, b)));
151 }
152
153
154 template<typename T> inline
155 typename std::enable_if<!std::is_integral<T>::value, T>::type // = T if T is not an integer type
156 divide(const T& a, const T& b) { return a / b; }
157
158 template<typename T> inline
159 typename std::enable_if<std::is_integral<T>::value, T>::type // = T if T is an integer type
160 divide(const T& a, const T& b)
161 {
162 const T zero(0);
163 if (b != zero) return a / b;
164 if (a == zero) return 0;
165 return (a > 0 ? std::numeric_limits<T>::max() : -std::numeric_limits<T>::max());
166 }
167
168 // If b is true, return a / 1 = a.
169 // If b is false and a is true, return 1 / 0 = inf = MAX_BOOL = 1 = a.
170 // If b is false and a is false, return 0 / 0 = NaN = 0 = a.
171 inline bool divide(bool a, bool /*b*/) { return a; }
172
173
174 enum CSGOperation { CSG_UNION, CSG_INTERSECTION, CSG_DIFFERENCE };
175
176 template<typename TreeType, CSGOperation Operation>
177 struct BuildPrimarySegment
178 {
179 using ValueType = typename TreeType::ValueType;
180 using TreePtrType = typename TreeType::Ptr;
181 using LeafNodeType = typename TreeType::LeafNodeType;
182 using NodeMaskType = typename LeafNodeType::NodeMaskType;
183 using RootNodeType = typename TreeType::RootNodeType;
184 using NodeChainType = typename RootNodeType::NodeChainType;
185 using InternalNodeType = typename boost::mpl::at<NodeChainType, boost::mpl::int_<1> >::type;
186
187 BuildPrimarySegment(const TreeType& lhs, const TreeType& rhs)
188 : mSegment(new TreeType(lhs.background()))
189 , mLhsTree(&lhs)
190 , mRhsTree(&rhs)
191 {
192 }
193
194 void operator()() const
195 {
196 std::vector<const LeafNodeType*> leafNodes;
197
198 {
199 std::vector<const InternalNodeType*> internalNodes;
200 mLhsTree->getNodes(internalNodes);
201
202 ProcessInternalNodes op(internalNodes, *mRhsTree, *mSegment, leafNodes);
203 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
204 }
205
206 ProcessLeafNodes op(leafNodes, *mRhsTree, *mSegment);
207 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
208 }
209
210 TreePtrType& segment() { return mSegment; }
211
212 private:
213
214 struct ProcessInternalNodes {
215
216 ProcessInternalNodes(std::vector<const InternalNodeType*>& lhsNodes,
217 const TreeType& rhsTree, TreeType& outputTree,
218 std::vector<const LeafNodeType*>& outputLeafNodes)
219 : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front())
220 , mRhsTree(&rhsTree)
221 , mLocalTree(mRhsTree->background())
222 , mOutputTree(&outputTree)
223 , mLocalLeafNodes()
224 , mOutputLeafNodes(&outputLeafNodes)
225 {
226 }
227
228 ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
229 : mLhsNodes(other.mLhsNodes)
230 , mRhsTree(other.mRhsTree)
231 , mLocalTree(mRhsTree->background())
232 , mOutputTree(&mLocalTree)
233 , mLocalLeafNodes()
234 , mOutputLeafNodes(&mLocalLeafNodes)
235 {
236 }
237
238 void join(ProcessInternalNodes& other)
239 {
240 mOutputTree->merge(*other.mOutputTree);
241 mOutputLeafNodes->insert(mOutputLeafNodes->end(),
242 other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
243 }
244
245 void operator()(const tbb::blocked_range<size_t>& range)
246 {
247 tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
248 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
249
250 std::vector<const LeafNodeType*> tmpLeafNodes;
251
252 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
253
254 const InternalNodeType& lhsNode = *mLhsNodes[n];
255 const Coord& ijk = lhsNode.origin();
256 const InternalNodeType * rhsNode =
257 rhsAcc.template probeConstNode<InternalNodeType>(ijk);
258
259 if (rhsNode) {
260 lhsNode.getNodes(*mOutputLeafNodes);
261 } else {
262 if (Operation == CSG_INTERSECTION) {
263 if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
264 tmpLeafNodes.clear();
265 lhsNode.getNodes(tmpLeafNodes);
266 for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
267 outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
268 }
269 }
270 } else { // Union & Difference
271 if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
272 tmpLeafNodes.clear();
273 lhsNode.getNodes(tmpLeafNodes);
274 for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
275 outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
276 }
277 }
278 }
279 }
280 } // end range loop
281 }
282
283 InternalNodeType const * const * const mLhsNodes;
284 TreeType const * const mRhsTree;
285 TreeType mLocalTree;
286 TreeType * const mOutputTree;
287
288 std::vector<const LeafNodeType*> mLocalLeafNodes;
289 std::vector<const LeafNodeType*> * const mOutputLeafNodes;
290 }; // struct ProcessInternalNodes
291
292 struct ProcessLeafNodes {
293
294 ProcessLeafNodes(std::vector<const LeafNodeType*>& lhsNodes,
295 const TreeType& rhsTree, TreeType& output)
296 : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front())
297 , mRhsTree(&rhsTree)
298 , mLocalTree(mRhsTree->background())
299 , mOutputTree(&output)
300 {
301 }
302
303 ProcessLeafNodes(ProcessLeafNodes& other, tbb::split)
304 : mLhsNodes(other.mLhsNodes)
305 , mRhsTree(other.mRhsTree)
306 , mLocalTree(mRhsTree->background())
307 , mOutputTree(&mLocalTree)
308 {
309 }
310
311 void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
312
313 void operator()(const tbb::blocked_range<size_t>& range)
314 {
315 tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
316 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
317
318 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
319
320 const LeafNodeType& lhsNode = *mLhsNodes[n];
321 const Coord& ijk = lhsNode.origin();
322
323 const LeafNodeType* rhsNodePt = rhsAcc.probeConstLeaf(ijk);
324
325 if (rhsNodePt) { // combine overlapping nodes
326
327 LeafNodeType* outputNode = outputAcc.touchLeaf(ijk);
328 ValueType * outputData = outputNode->buffer().data();
329 NodeMaskType& outputMask = outputNode->getValueMask();
330
331 const ValueType * lhsData = lhsNode.buffer().data();
332 const NodeMaskType& lhsMask = lhsNode.getValueMask();
333
334 const ValueType * rhsData = rhsNodePt->buffer().data();
335 const NodeMaskType& rhsMask = rhsNodePt->getValueMask();
336
337 if (Operation == CSG_INTERSECTION) {
338 for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
339 const bool fromRhs = lhsData[pos] < rhsData[pos];
340 outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
341 outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
342 }
343 } else if (Operation == CSG_DIFFERENCE){
344 for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
345 const ValueType rhsVal = math::negative(rhsData[pos]);
346 const bool fromRhs = lhsData[pos] < rhsVal;
347 outputData[pos] = fromRhs ? rhsVal : lhsData[pos];
348 outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
349 }
350 } else { // Union
351 for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
352 const bool fromRhs = lhsData[pos] > rhsData[pos];
353 outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
354 outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
355 }
356 }
357
358 } else {
359 if (Operation == CSG_INTERSECTION) {
360 if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
361 outputAcc.addLeaf(new LeafNodeType(lhsNode));
362 }
363 } else { // Union & Difference
364 if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
365 outputAcc.addLeaf(new LeafNodeType(lhsNode));
366 }
367 }
368 }
369 } // end range loop
370 }
371
372 LeafNodeType const * const * const mLhsNodes;
373 TreeType const * const mRhsTree;
374 TreeType mLocalTree;
375 TreeType * const mOutputTree;
376 }; // struct ProcessLeafNodes
377
378 TreePtrType mSegment;
379 TreeType const * const mLhsTree;
380 TreeType const * const mRhsTree;
381 }; // struct BuildPrimarySegment
382
383
384 template<typename TreeType, CSGOperation Operation>
385 struct BuildSecondarySegment
386 {
387 using ValueType = typename TreeType::ValueType;
388 using TreePtrType = typename TreeType::Ptr;
389 using LeafNodeType = typename TreeType::LeafNodeType;
390 using NodeMaskType = typename LeafNodeType::NodeMaskType;
391 using RootNodeType = typename TreeType::RootNodeType;
392 using NodeChainType = typename RootNodeType::NodeChainType;
393 using InternalNodeType = typename boost::mpl::at<NodeChainType, boost::mpl::int_<1> >::type;
394
395 BuildSecondarySegment(const TreeType& lhs, const TreeType& rhs)
396 : mSegment(new TreeType(lhs.background()))
397 , mLhsTree(&lhs)
398 , mRhsTree(&rhs)
399 {
400 }
401
402 void operator()() const
403 {
404 std::vector<const LeafNodeType*> leafNodes;
405
406 {
407 std::vector<const InternalNodeType*> internalNodes;
408 mRhsTree->getNodes(internalNodes);
409
410 ProcessInternalNodes op(internalNodes, *mLhsTree, *mSegment, leafNodes);
411 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
412 }
413
414 ProcessLeafNodes op(leafNodes, *mLhsTree, *mSegment);
415 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
416 }
417
418 TreePtrType& segment() { return mSegment; }
419
420 private:
421
422 struct ProcessInternalNodes {
423
424 ProcessInternalNodes(std::vector<const InternalNodeType*>& rhsNodes,
425 const TreeType& lhsTree, TreeType& outputTree,
426 std::vector<const LeafNodeType*>& outputLeafNodes)
427 : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front())
428 , mLhsTree(&lhsTree)
429 , mLocalTree(mLhsTree->background())
430 , mOutputTree(&outputTree)
431 , mLocalLeafNodes()
432 , mOutputLeafNodes(&outputLeafNodes)
433 {
434 }
435
436 ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
437 : mRhsNodes(other.mRhsNodes)
438 , mLhsTree(other.mLhsTree)
439 , mLocalTree(mLhsTree->background())
440 , mOutputTree(&mLocalTree)
441 , mLocalLeafNodes()
442 , mOutputLeafNodes(&mLocalLeafNodes)
443 {
444 }
445
446 void join(ProcessInternalNodes& other)
447 {
448 mOutputTree->merge(*other.mOutputTree);
449 mOutputLeafNodes->insert(mOutputLeafNodes->end(),
450 other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
451 }
452
453 void operator()(const tbb::blocked_range<size_t>& range)
454 {
455 tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
456 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
457
458 std::vector<const LeafNodeType*> tmpLeafNodes;
459
460 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
461
462 const InternalNodeType& rhsNode = *mRhsNodes[n];
463 const Coord& ijk = rhsNode.origin();
464 const InternalNodeType * lhsNode =
465 lhsAcc.template probeConstNode<InternalNodeType>(ijk);
466
467 if (lhsNode) {
468 rhsNode.getNodes(*mOutputLeafNodes);
469 } else {
470 if (Operation == CSG_INTERSECTION) {
471 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
472 tmpLeafNodes.clear();
473 rhsNode.getNodes(tmpLeafNodes);
474 for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
475 outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
476 }
477 }
478 } else if (Operation == CSG_DIFFERENCE) {
479 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
480 tmpLeafNodes.clear();
481 rhsNode.getNodes(tmpLeafNodes);
482 for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
483 LeafNodeType* outputNode = new LeafNodeType(*tmpLeafNodes[i]);
484 outputNode->negate();
485 outputAcc.addLeaf(outputNode);
486 }
487 }
488 } else { // Union
489 if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
490 tmpLeafNodes.clear();
491 rhsNode.getNodes(tmpLeafNodes);
492 for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
493 outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
494 }
495 }
496 }
497 }
498 } // end range loop
499 }
500
501 InternalNodeType const * const * const mRhsNodes;
502 TreeType const * const mLhsTree;
503 TreeType mLocalTree;
504 TreeType * const mOutputTree;
505
506 std::vector<const LeafNodeType*> mLocalLeafNodes;
507 std::vector<const LeafNodeType*> * const mOutputLeafNodes;
508 }; // struct ProcessInternalNodes
509
510 struct ProcessLeafNodes {
511
512 ProcessLeafNodes(std::vector<const LeafNodeType*>& rhsNodes,
513 const TreeType& lhsTree, TreeType& output)
514 : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front())
515 , mLhsTree(&lhsTree)
516 , mLocalTree(mLhsTree->background())
517 , mOutputTree(&output)
518 {
519 }
520
521 ProcessLeafNodes(ProcessLeafNodes& rhs, tbb::split)
522 : mRhsNodes(rhs.mRhsNodes)
523 , mLhsTree(rhs.mLhsTree)
524 , mLocalTree(mLhsTree->background())
525 , mOutputTree(&mLocalTree)
526 {
527 }
528
529 void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
530
531 void operator()(const tbb::blocked_range<size_t>& range)
532 {
533 tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
534 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
535
536 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
537
538 const LeafNodeType& rhsNode = *mRhsNodes[n];
539 const Coord& ijk = rhsNode.origin();
540
541 const LeafNodeType* lhsNode = lhsAcc.probeConstLeaf(ijk);
542
543 if (!lhsNode) {
544 if (Operation == CSG_INTERSECTION) {
545 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
546 outputAcc.addLeaf(new LeafNodeType(rhsNode));
547 }
548 } else if (Operation == CSG_DIFFERENCE) {
549 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
550 LeafNodeType* outputNode = new LeafNodeType(rhsNode);
551 outputNode->negate();
552 outputAcc.addLeaf(outputNode);
553 }
554 } else { // Union
555 if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
556 outputAcc.addLeaf(new LeafNodeType(rhsNode));
557 }
558 }
559 }
560 } // end range loop
561 }
562
563 LeafNodeType const * const * const mRhsNodes;
564 TreeType const * const mLhsTree;
565 TreeType mLocalTree;
566 TreeType * const mOutputTree;
567 }; // struct ProcessLeafNodes
568
569 TreePtrType mSegment;
570 TreeType const * const mLhsTree;
571 TreeType const * const mRhsTree;
572 }; // struct BuildSecondarySegment
573
574
575 template<CSGOperation Operation, typename TreeType>
576 inline typename TreeType::Ptr
577 doCSGCopy(const TreeType& lhs, const TreeType& rhs)
578 {
579 BuildPrimarySegment<TreeType, Operation> primary(lhs, rhs);
580 BuildSecondarySegment<TreeType, Operation> secondary(lhs, rhs);
581
582 // Exploiting nested parallelism
583 tbb::task_group tasks;
584 tasks.run(primary);
585 tasks.run(secondary);
586 tasks.wait();
587
588 primary.segment()->merge(*secondary.segment());
589
590 // The leafnode (level = 0) sign is set in the segment construction.
591 tools::signedFloodFill(*primary.segment(), /*threaded=*/true, /*grainSize=*/1, /*minLevel=*/1);
592
593 return primary.segment();
594 }
595
596
598
599
600 template<typename TreeType>
601 struct GridOrTreeConstructor
602 {
603 using TreeTypePtr = typename TreeType::Ptr;
604 static TreeTypePtr construct(const TreeType&, TreeTypePtr& tree) { return tree; }
605 };
606
607
608 template<typename TreeType>
609 struct GridOrTreeConstructor<Grid<TreeType> >
610 {
611 using GridType = Grid<TreeType>;
612 using GridTypePtr = typename Grid<TreeType>::Ptr;
613 using TreeTypePtr = typename TreeType::Ptr;
614
615 static GridTypePtr construct(const GridType& grid, TreeTypePtr& tree) {
616 GridTypePtr maskGrid(GridType::create(tree));
617 maskGrid->setTransform(grid.transform().copy());
618 maskGrid->insertMeta(grid);
619 return maskGrid;
620 }
621 };
622
623
625
628 template <typename LeafT>
629 using LeafPairList = std::vector<std::pair<LeafT*, LeafT*>>;
631
637 template <typename TreeT>
638 inline void transferLeafNodes(TreeT &srcTree, TreeT &dstTree,
639 LeafPairList<typename TreeT::LeafNodeType> &overlapping)
640 {
641 using LeafT = typename TreeT::LeafNodeType;
642 tree::ValueAccessor<TreeT> acc(dstTree);//destination
643 std::vector<LeafT*> srcLeafNodes;
644 srcLeafNodes.reserve(srcTree.leafCount());
645 srcTree.stealNodes(srcLeafNodes);
646 srcTree.clear();
647 for (LeafT *srcLeaf : srcLeafNodes) {
648 LeafT *dstLeaf = acc.probeLeaf(srcLeaf->origin());
649 if (dstLeaf) {
650 overlapping.emplace_back(dstLeaf, srcLeaf);//dst, src
651 } else {
652 acc.addLeaf(srcLeaf);
653 }
654 }
655 }
657
660 template <typename TreeT, typename OpT>
661 inline
662 typename std::enable_if<
663 !std::is_same<typename TreeT::ValueType, bool>::value &&
664 !std::is_same<typename TreeT::BuildType, ValueMask>::value &&
665 std::is_same<typename TreeT::LeafNodeType::Buffer::ValueType,
666 typename TreeT::LeafNodeType::Buffer::StorageType>::value>::type
667 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
668 {
669 using LeafT = typename TreeT::LeafNodeType;
670 LeafPairList<LeafT> overlapping;//dst, src
671 transferLeafNodes(srcTree, dstTree, overlapping);
672
673 using RangeT = tbb::blocked_range<size_t>;
674 tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](const RangeT& r) {
675 for (auto i = r.begin(); i != r.end(); ++i) {
676 LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
677 dstLeaf->getValueMask() |= srcLeaf->getValueMask();
678 auto *ptr = dstLeaf->buffer().data();
679 for (auto v = srcLeaf->cbeginValueOn(); v; ++v) op(ptr[v.pos()], *v);
680 delete srcLeaf;
681 }
682 });
683 }
685
688 template <typename TreeT, typename OpT>
689 inline
690 typename std::enable_if<
691 std::is_same<typename TreeT::BuildType, ValueMask>::value &&
692 std::is_same<typename TreeT::ValueType, bool>::value>::type
693 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT)
694 {
695 using LeafT = typename TreeT::LeafNodeType;
696 LeafPairList<LeafT> overlapping;//dst, src
697 transferLeafNodes(srcTree, dstTree, overlapping);
698
699 using RangeT = tbb::blocked_range<size_t>;
700 tbb::parallel_for(RangeT(0, overlapping.size()), [&overlapping](const RangeT& r) {
701 for (auto i = r.begin(); i != r.end(); ++i) {
702 overlapping[i].first->getValueMask() |= overlapping[i].second->getValueMask();
703 delete overlapping[i].second;
704 }
705 });
706 }
707
710 template <typename TreeT, typename OpT>
711 inline
712 typename std::enable_if<
713 std::is_same<typename TreeT::ValueType, bool>::value &&
714 !std::is_same<typename TreeT::BuildType, ValueMask>::value>::type
715 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
716 {
717 using LeafT = typename TreeT::LeafNodeType;
718 LeafPairList<LeafT> overlapping;//dst, src
719 transferLeafNodes(srcTree, dstTree, overlapping);
720
721 using RangeT = tbb::blocked_range<size_t>;
722 using WordT = typename LeafT::Buffer::WordType;
723 tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](const RangeT& r) {
724 for (auto i = r.begin(); i != r.end(); ++i) {
725 LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
726 WordT *w1 = dstLeaf->buffer().data();
727 const WordT *w2 = srcLeaf->buffer().data();
728 const WordT *w3 = &(srcLeaf->getValueMask().template getWord<WordT>(0));
729 for (Index32 n = LeafT::Buffer::WORD_COUNT; n--; ++w1) {
730 WordT tmp = *w1, state = *w3++;
731 op (tmp, *w2++);
732 *w1 = (state & tmp) | (~state & *w1);//inactive values are unchanged
733 }
734 dstLeaf->getValueMask() |= srcLeaf->getValueMask();
735 delete srcLeaf;
736 }
737 });
738 }
740
743 template <typename TreeT>
744 struct CopyOp
745 {
746 using ValueT = typename TreeT::ValueType;
747 CopyOp() = default;
748 void operator()(ValueT& dst, const ValueT& src) const { dst = src; }
749 };
751
752 } // namespace composite
753
754
755 template<typename GridOrTreeT>
756 OPENVDB_STATIC_SPECIALIZATION inline void
757 compMax(GridOrTreeT& aTree, GridOrTreeT& bTree)
758 {
759 using Adapter = TreeAdapter<GridOrTreeT>;
760 using TreeT = typename Adapter::TreeType;
761 using ValueT = typename TreeT::ValueType;
762 struct Local {
763 static inline void op(CombineArgs<ValueT>& args) {
764 args.setResult(composite::max(args.a(), args.b()));
765 }
766 };
767 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
768 }
769
770
771 template<typename GridOrTreeT>
772 OPENVDB_STATIC_SPECIALIZATION inline void
773 compMin(GridOrTreeT& aTree, GridOrTreeT& bTree)
774 {
775 using Adapter = TreeAdapter<GridOrTreeT>;
776 using TreeT = typename Adapter::TreeType;
777 using ValueT = typename TreeT::ValueType;
778 struct Local {
779 static inline void op(CombineArgs<ValueT>& args) {
780 args.setResult(composite::min(args.a(), args.b()));
781 }
782 };
783 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
784 }
785
786
787 template<typename GridOrTreeT>
788 OPENVDB_STATIC_SPECIALIZATION inline void
789 compSum(GridOrTreeT& aTree, GridOrTreeT& bTree)
790 {
791 using Adapter = TreeAdapter<GridOrTreeT>;
792 using TreeT = typename Adapter::TreeType;
793 struct Local {
794 static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
795 args.setResult(args.a() + args.b());
796 }
797 };
798 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
799 }
800
801
802 template<typename GridOrTreeT>
803 OPENVDB_STATIC_SPECIALIZATION inline void
804 compMul(GridOrTreeT& aTree, GridOrTreeT& bTree)
805 {
806 using Adapter = TreeAdapter<GridOrTreeT>;
807 using TreeT = typename Adapter::TreeType;
808 struct Local {
809 static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
810 args.setResult(args.a() * args.b());
811 }
812 };
813 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
814 }
815
816
817 template<typename GridOrTreeT>
818 OPENVDB_STATIC_SPECIALIZATION inline void
819 compDiv(GridOrTreeT& aTree, GridOrTreeT& bTree)
820 {
821 using Adapter = TreeAdapter<GridOrTreeT>;
822 using TreeT = typename Adapter::TreeType;
823 struct Local {
824 static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
825 args.setResult(composite::divide(args.a(), args.b()));
826 }
827 };
828 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
829 }
830
831
833
834
835 template<typename TreeT>
836 struct CompReplaceOp
837 {
838 TreeT* const aTree;
839
840 CompReplaceOp(TreeT& _aTree): aTree(&_aTree) {}
841
843 void operator()(const typename TreeT::ValueOnCIter& iter) const
844 {
845 CoordBBox bbox;
846 iter.getBoundingBox(bbox);
847 aTree->fill(bbox, *iter);
848 }
849
850 void operator()(const typename TreeT::LeafCIter& leafIter) const
851 {
852 tree::ValueAccessor<TreeT> acc(*aTree);
853 for (typename TreeT::LeafCIter::LeafNodeT::ValueOnCIter iter =
854 leafIter->cbeginValueOn(); iter; ++iter)
855 {
856 acc.setValue(iter.getCoord(), *iter);
857 }
858 }
859 };
860
861
862 template<typename GridOrTreeT>
863 OPENVDB_STATIC_SPECIALIZATION inline void
864 compReplace(GridOrTreeT& aTree, const GridOrTreeT& bTree)
865 {
866 using Adapter = TreeAdapter<GridOrTreeT>;
867 using TreeT = typename Adapter::TreeType;
868 using ValueOnCIterT = typename TreeT::ValueOnCIter;
869
870 // Copy active states (but not values) from B to A.
871 Adapter::tree(aTree).topologyUnion(Adapter::tree(bTree));
872
873 CompReplaceOp<TreeT> op(Adapter::tree(aTree));
874
875 // Copy all active tile values from B to A.
876 ValueOnCIterT iter = bTree.cbeginValueOn();
877 iter.setMaxDepth(iter.getLeafDepth() - 1); // don't descend into leaf nodes
878 foreach(iter, op, /*threaded=*/false);
879
880 // Copy all active voxel values from B to A.
881 foreach(Adapter::tree(bTree).cbeginLeaf(), op);
882 }
883
884
886
887
890 template<typename TreeType>
891 class CsgVisitorBase
892 {
893 public:
894 using TreeT = TreeType;
895 using ValueT = typename TreeT::ValueType;
896 using ChildIterT = typename TreeT::LeafNodeType::ChildAllIter;
897
898 enum { STOP = 3 };
899
900 CsgVisitorBase(const TreeT& aTree, const TreeT& bTree):
901 mAOutside(aTree.background()),
902 mAInside(math::negative(mAOutside)),
903 mBOutside(bTree.background()),
904 mBInside(math::negative(mBOutside))
905 {
906 const ValueT zero = zeroVal<ValueT>();
907 if (!(mAOutside > zero)) {
908 OPENVDB_THROW(ValueError,
909 "expected grid A outside value > 0, got " << mAOutside);
910 }
911 if (!(mAInside < zero)) {
912 OPENVDB_THROW(ValueError,
913 "expected grid A inside value < 0, got " << mAInside);
914 }
915 if (!(mBOutside > zero)) {
916 OPENVDB_THROW(ValueError,
917 "expected grid B outside value > 0, got " << mBOutside);
918 }
919 if (!(mBInside < zero)) {
920 OPENVDB_THROW(ValueError,
921 "expected grid B outside value < 0, got " << mBOutside);
922 }
923 }
924
925 protected:
926 ValueT mAOutside, mAInside, mBOutside, mBInside;
927 };
928
929
931
932
933 template<typename TreeType>
934 struct CsgUnionVisitor: public CsgVisitorBase<TreeType>
935 {
936 using TreeT = TreeType;
937 using ValueT = typename TreeT::ValueType;
938 using ChildIterT = typename TreeT::LeafNodeType::ChildAllIter;
939
940 enum { STOP = CsgVisitorBase<TreeT>::STOP };
941
942 CsgUnionVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase<TreeT>(a, b) {}
943
945 template<typename AIterT, typename BIterT>
946 inline int operator()(AIterT&, BIterT&) { return 0; }
947
949 template<typename IterT>
950 inline int operator()(IterT& aIter, IterT& bIter)
951 {
952 ValueT aValue = zeroVal<ValueT>();
953 typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue);
954 if (!aChild && aValue < zeroVal<ValueT>()) {
955 // A is an inside tile. Leave it alone and stop traversing this branch.
956 return STOP;
957 }
958
959 ValueT bValue = zeroVal<ValueT>();
960 typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue);
961 if (!bChild && bValue < zeroVal<ValueT>()) {
962 // B is an inside tile. Make A an inside tile and stop traversing this branch.
963 aIter.setValue(this->mAInside);
964 aIter.setValueOn(bIter.isValueOn());
965 delete aChild;
966 return STOP;
967 }
968
969 if (!aChild && aValue > zeroVal<ValueT>()) {
970 // A is an outside tile. If B has a child, transfer it to A,
971 // otherwise leave A alone.
972 if (bChild) {
973 bIter.setValue(this->mBOutside);
974 bIter.setValueOff();
975 bChild->resetBackground(this->mBOutside, this->mAOutside);
976 aIter.setChild(bChild); // transfer child
977 delete aChild;
978 }
979 return STOP;
980 }
981
982 // If A has a child and B is an outside tile, stop traversing this branch.
983 // Continue traversal only if A and B both have children.
984 return (aChild && bChild) ? 0 : STOP;
985 }
986
988 inline int operator()(ChildIterT& aIter, ChildIterT& bIter)
989 {
990 ValueT aValue, bValue;
991 aIter.probeValue(aValue);
992 bIter.probeValue(bValue);
993 if (aValue > bValue) { // a = min(a, b)
994 aIter.setValue(bValue);
995 aIter.setValueOn(bIter.isValueOn());
996 }
997 return 0;
998 }
999 };
1000
1001
1002
1004
1005
1006 template<typename TreeType>
1007 struct CsgIntersectVisitor: public CsgVisitorBase<TreeType>
1008 {
1009 using TreeT = TreeType;
1010 using ValueT = typename TreeT::ValueType;
1011 using ChildIterT = typename TreeT::LeafNodeType::ChildAllIter;
1012
1013 enum { STOP = CsgVisitorBase<TreeT>::STOP };
1014
1015 CsgIntersectVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase<TreeT>(a, b) {}
1016
1018 template<typename AIterT, typename BIterT>
1019 inline int operator()(AIterT&, BIterT&) { return 0; }
1020
1022 template<typename IterT>
1023 inline int operator()(IterT& aIter, IterT& bIter)
1024 {
1025 ValueT aValue = zeroVal<ValueT>();
1026 typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue);
1027 if (!aChild && !(aValue < zeroVal<ValueT>())) {
1028 // A is an outside tile. Leave it alone and stop traversing this branch.
1029 return STOP;
1030 }
1031
1032 ValueT bValue = zeroVal<ValueT>();
1033 typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue);
1034 if (!bChild && !(bValue < zeroVal<ValueT>())) {
1035 // B is an outside tile. Make A an outside tile and stop traversing this branch.
1036 aIter.setValue(this->mAOutside);
1037 aIter.setValueOn(bIter.isValueOn());
1038 delete aChild;
1039 return STOP;
1040 }
1041
1042 if (!aChild && aValue < zeroVal<ValueT>()) {
1043 // A is an inside tile. If B has a child, transfer it to A,
1044 // otherwise leave A alone.
1045 if (bChild) {
1046 bIter.setValue(this->mBOutside);
1047 bIter.setValueOff();
1048 bChild->resetBackground(this->mBOutside, this->mAOutside);
1049 aIter.setChild(bChild); // transfer child
1050 delete aChild;
1051 }
1052 return STOP;
1053 }
1054
1055 // If A has a child and B is an outside tile, stop traversing this branch.
1056 // Continue traversal only if A and B both have children.
1057 return (aChild && bChild) ? 0 : STOP;
1058 }
1059
1061 inline int operator()(ChildIterT& aIter, ChildIterT& bIter)
1062 {
1063 ValueT aValue, bValue;
1064 aIter.probeValue(aValue);
1065 bIter.probeValue(bValue);
1066 if (aValue < bValue) { // a = max(a, b)
1067 aIter.setValue(bValue);
1068 aIter.setValueOn(bIter.isValueOn());
1069 }
1070 return 0;
1071 }
1072 };
1073
1074
1076
1077
1078 template<typename TreeType>
1079 struct CsgDiffVisitor: public CsgVisitorBase<TreeType>
1080 {
1081 using TreeT = TreeType;
1082 using ValueT = typename TreeT::ValueType;
1083 using ChildIterT = typename TreeT::LeafNodeType::ChildAllIter;
1084
1085 enum { STOP = CsgVisitorBase<TreeT>::STOP };
1086
1087 CsgDiffVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase<TreeT>(a, b) {}
1088
1090 template<typename AIterT, typename BIterT>
1091 inline int operator()(AIterT&, BIterT&) { return 0; }
1092
1094 template<typename IterT>
1095 inline int operator()(IterT& aIter, IterT& bIter)
1096 {
1097 ValueT aValue = zeroVal<ValueT>();
1098 typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue);
1099 if (!aChild && !(aValue < zeroVal<ValueT>())) {
1100 // A is an outside tile. Leave it alone and stop traversing this branch.
1101 return STOP;
1102 }
1103
1104 ValueT bValue = zeroVal<ValueT>();
1105 typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue);
1106 if (!bChild && bValue < zeroVal<ValueT>()) {
1107 // B is an inside tile. Make A an inside tile and stop traversing this branch.
1108 aIter.setValue(this->mAOutside);
1109 aIter.setValueOn(bIter.isValueOn());
1110 delete aChild;
1111 return STOP;
1112 }
1113
1114 if (!aChild && aValue < zeroVal<ValueT>()) {
1115 // A is an inside tile. If B has a child, transfer it to A,
1116 // otherwise leave A alone.
1117 if (bChild) {
1118 bIter.setValue(this->mBOutside);
1119 bIter.setValueOff();
1120 bChild->resetBackground(this->mBOutside, this->mAOutside);
1121 aIter.setChild(bChild); // transfer child
1122 bChild->negate();
1123 delete aChild;
1124 }
1125 return STOP;
1126 }
1127
1128 // If A has a child and B is an outside tile, stop traversing this branch.
1129 // Continue traversal only if A and B both have children.
1130 return (aChild && bChild) ? 0 : STOP;
1131 }
1132
1134 inline int operator()(ChildIterT& aIter, ChildIterT& bIter)
1135 {
1136 ValueT aValue, bValue;
1137 aIter.probeValue(aValue);
1138 bIter.probeValue(bValue);
1139 bValue = math::negative(bValue);
1140 if (aValue < bValue) { // a = max(a, -b)
1141 aIter.setValue(bValue);
1142 aIter.setValueOn(bIter.isValueOn());
1143 }
1144 return 0;
1145 }
1146 };
1147
1148
1150
1151
1152 template<typename GridOrTreeT>
1153 OPENVDB_STATIC_SPECIALIZATION inline void
1154 csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune)
1155 {
1156 using Adapter = TreeAdapter<GridOrTreeT>;
1157 using TreeT = typename Adapter::TreeType;
1158 TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
1159 CsgUnionVisitor<TreeT> visitor(aTree, bTree);
1160 aTree.visit2(bTree, visitor);
1161 if (prune) tools::pruneLevelSet(aTree);
1162 }
1163
1164 template<typename GridOrTreeT>
1165 OPENVDB_STATIC_SPECIALIZATION inline void
1166 csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune)
1167 {
1168 using Adapter = TreeAdapter<GridOrTreeT>;
1169 using TreeT = typename Adapter::TreeType;
1170 TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
1171 CsgIntersectVisitor<TreeT> visitor(aTree, bTree);
1172 aTree.visit2(bTree, visitor);
1173 if (prune) tools::pruneLevelSet(aTree);
1174 }
1175
1176 template<typename GridOrTreeT>
1177 OPENVDB_STATIC_SPECIALIZATION inline void
1178 csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune)
1179 {
1180 using Adapter = TreeAdapter<GridOrTreeT>;
1181 using TreeT = typename Adapter::TreeType;
1182 TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
1183 CsgDiffVisitor<TreeT> visitor(aTree, bTree);
1184 aTree.visit2(bTree, visitor);
1185 if (prune) tools::pruneLevelSet(aTree);
1186 }
1187
1188
1189 template<typename GridOrTreeT>
1190 OPENVDB_STATIC_SPECIALIZATION inline typename GridOrTreeT::Ptr
1191 csgUnionCopy(const GridOrTreeT& a, const GridOrTreeT& b)
1192 {
1193 using Adapter = TreeAdapter<GridOrTreeT>;
1194 using TreePtrT = typename Adapter::TreeType::Ptr;
1195
1196 TreePtrT output = composite::doCSGCopy<composite::CSG_UNION>(
1197 Adapter::tree(a), Adapter::tree(b));
1198
1199 return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
1200 }
1201
1202
1203 template<typename GridOrTreeT>
1204 OPENVDB_STATIC_SPECIALIZATION inline typename GridOrTreeT::Ptr
1205 csgIntersectionCopy(const GridOrTreeT& a, const GridOrTreeT& b)
1206 {
1207 using Adapter = TreeAdapter<GridOrTreeT>;
1208 using TreePtrT = typename Adapter::TreeType::Ptr;
1209
1210 TreePtrT output = composite::doCSGCopy<composite::CSG_INTERSECTION>(
1211 Adapter::tree(a), Adapter::tree(b));
1212
1213 return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
1214 }
1215
1216
1217 template<typename GridOrTreeT>
1218 OPENVDB_STATIC_SPECIALIZATION inline typename GridOrTreeT::Ptr
1219 csgDifferenceCopy(const GridOrTreeT& a, const GridOrTreeT& b)
1220 {
1221 using Adapter = TreeAdapter<GridOrTreeT>;
1222 using TreePtrT = typename Adapter::TreeType::Ptr;
1223
1224 TreePtrT output = composite::doCSGCopy<composite::CSG_DIFFERENCE>(
1225 Adapter::tree(a), Adapter::tree(b));
1226
1227 return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
1228 }
1229
1231
1253 template<typename TreeT, typename OpT = composite::CopyOp<TreeT> >
1254 inline void
1255 compActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op = composite::CopyOp<TreeT>())
1256 {
1257 composite::doCompActiveLeafVoxels<TreeT, OpT>(srcTree, dstTree, op);
1258 }
1259
1260
1261 } // namespace tools
1262 } // namespace OPENVDB_VERSION_NAME
1263 } // namespace openvdb
1264
1265 #endif // OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
1266
1267 // Copyright (c) 2012-2019 DreamWorks Animation LLC
1268 // All rights reserved. This software is distributed under the
1269 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
openvdb::v6_1::tools::composite::BuildPrimarySegment
Definition: Composite.h:177
openvdb::v6_1::tools::CsgVisitorBase::TreeT
TreeType TreeT
Definition: Composite.h:894
openvdb::v6_1::tools::composite::BuildPrimarySegment::ValueType
typename TreeType::ValueType ValueType
Definition: Composite.h:179
Types.h
openvdb::v6_1::tools::CompReplaceOp::operator()
void operator()(const typename TreeT::LeafCIter &leafIter) const
Definition: Composite.h:850
openvdb::v6_1::tools::composite::CSGOperation
CSGOperation
Definition: Composite.h:174
openvdb::v6_1::tools::CsgIntersectVisitor::operator()
int operator()(AIterT &, BIterT &)
Don't process nodes that are at different tree levels.
Definition: Composite.h:1019
openvdb::v6_1::tools::composite::BuildPrimarySegment::operator()
void operator()() const
Definition: Composite.h:194
openvdb::v6_1::tools::composite::CSG_INTERSECTION
Definition: Composite.h:174
openvdb::v6_1::tools::composite::BuildSecondarySegment::InternalNodeType
typename boost::mpl::at< NodeChainType, boost::mpl::int_< 1 > >::type InternalNodeType
Definition: Composite.h:393
Math.h
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
ValueTransformer.h
openvdb::v6_1::tools::CompReplaceOp::aTree
TreeT *const aTree
Definition: Composite.h:838
openvdb::v6_1::tools::composite::BuildSecondarySegment::operator()
void operator()() const
Definition: Composite.h:402
openvdb::v6_1::tools::csgIntersection
void csgIntersection(GridOrTreeT &a, GridOrTreeT &b, bool prune=true)
Given two level set grids, replace the A grid with the intersection of A and B.
Definition: Composite.h:1166
openvdb::v6_1::tools::CompReplaceOp::CompReplaceOp
CompReplaceOp(TreeT &_aTree)
Definition: Composite.h:840
openvdb::v6_1::tools::composite::BuildSecondarySegment::segment
TreePtrType & segment()
Definition: Composite.h:418
openvdb::v6_1::tools::pruneLevelSet
void pruneLevelSet(TreeT &tree, bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing nodes whose values are all inactive with inactive ...
Definition: Prune.h:416
openvdb::v6_1::tools::csgIntersectionCopy
GridOrTreeT::Ptr csgIntersectionCopy(const GridOrTreeT &a, const GridOrTreeT &b)
Threaded CSG intersection operation that produces a new grid or tree from immutable inputs.
Definition: Composite.h:1205
openvdb::v6_1::tools::compMul
void compMul(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute a * b per voxel (using sparse traversal). Store the result in the A grid...
Definition: Composite.h:804
openvdb::v6_1::tools::composite::GridOrTreeConstructor::construct
static TreeTypePtr construct(const TreeType &, TreeTypePtr &tree)
Definition: Composite.h:604
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
openvdb::v6_1::tools::CsgDiffVisitor::operator()
int operator()(IterT &aIter, IterT &bIter)
Process root and internal nodes.
Definition: Composite.h:1095
openvdb::v6_1::tools::composite::BuildSecondarySegment
Definition: Composite.h:385
openvdb::v6_1::tools::composite::BuildPrimarySegment::BuildPrimarySegment
BuildPrimarySegment(const TreeType &lhs, const TreeType &rhs)
Definition: Composite.h:187
openvdb::v6_1::tools::composite::GridOrTreeConstructor< Grid< TreeType > >::GridTypePtr
typename Grid< TreeType >::Ptr GridTypePtr
Definition: Composite.h:612
openvdb::v6_1::tools::composite::BuildSecondarySegment::NodeChainType
typename RootNodeType::NodeChainType NodeChainType
Definition: Composite.h:392
openvdb::v6_1::tools::CsgDiffVisitor::CsgDiffVisitor
CsgDiffVisitor(const TreeT &a, const TreeT &b)
Definition: Composite.h:1087
openvdb::v6_1::tools::CsgVisitorBase::ChildIterT
typename TreeT::LeafNodeType::ChildAllIter ChildIterT
Definition: Composite.h:896
openvdb::v6_1::tree::ValueAccessor< const TreeType >
openvdb::v6_1::tools::CsgIntersectVisitor::operator()
int operator()(ChildIterT &aIter, ChildIterT &bIter)
Process leaf node values.
Definition: Composite.h:1061
openvdb::v6_1::tools::composite::divide
bool divide(bool a, bool)
Definition: Composite.h:171
openvdb::v6_1::tools::csgDifference
void csgDifference(GridOrTreeT &a, GridOrTreeT &b, bool prune=true)
Given two level set grids, replace the A grid with the difference A / B.
Definition: Composite.h:1178
openvdb::v6_1::tools::composite::BuildPrimarySegment::segment
TreePtrType & segment()
Definition: Composite.h:210
openvdb::v6_1::tools::CsgVisitorBase::ValueT
typename TreeT::ValueType ValueT
Definition: Composite.h:895
openvdb::v6_1::tools::composite::BuildPrimarySegment::TreePtrType
typename TreeType::Ptr TreePtrType
Definition: Composite.h:180
openvdb::v6_1::Grid
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:55
openvdb::v6_1::tools::compActiveLeafVoxels
void compActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op=composite::CopyOp< TreeT >())
Composite the active values in leaf nodes, i.e. active voxels, of a source tree into a destination tr...
Definition: Composite.h:1255
openvdb::v6_1::tools::composite::BuildSecondarySegment::RootNodeType
typename TreeType::RootNodeType RootNodeType
Definition: Composite.h:391
openvdb::v6_1::tools::composite::max
const std::enable_if< VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:147
Prune.h
Defined various multi-threaded utility functions for trees.
openvdb::v6_1::tools::composite::BuildPrimarySegment::NodeMaskType
typename LeafNodeType::NodeMaskType NodeMaskType
Definition: Composite.h:182
openvdb::v6_1::tools::compDiv
void compDiv(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute a / b per voxel (using sparse traversal). Store the result in the A grid...
Definition: Composite.h:819
openvdb::v6_1::tools::composite::BuildPrimarySegment::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: Composite.h:181
openvdb::v6_1::tools::CsgUnionVisitor::operator()
int operator()(AIterT &, BIterT &)
Don't process nodes that are at different tree levels.
Definition: Composite.h:946
openvdb::v6_1::tools::CsgUnionVisitor::operator()
int operator()(ChildIterT &aIter, ChildIterT &bIter)
Process leaf node values.
Definition: Composite.h:988
openvdb::v6_1::tools::composite::CSG_UNION
Definition: Composite.h:174
openvdb::v6_1::tools::composite::CSG_DIFFERENCE
Definition: Composite.h:174
Exceptions.h
openvdb::v6_1::tools::composite::BuildSecondarySegment::NodeMaskType
typename LeafNodeType::NodeMaskType NodeMaskType
Definition: Composite.h:390
openvdb::v6_1::tools::signedFloodFill
void signedFloodFill(TreeOrLeafManagerT &tree, bool threaded=true, size_t grainSize=1, Index minLevel=0)
Set the values of all inactive voxels and tiles of a narrow-band level set from the signs of the acti...
Definition: SignedFloodFill.h:294
openvdb::v6_1::tools::CsgVisitorBase::mBOutside
ValueT mBOutside
Definition: Composite.h:926
openvdb::v6_1::math::Coord::data
const Int32 * data() const
Definition: Coord.h:167
openvdb::v6_1::tools::csgUnion
void csgUnion(GridOrTreeT &a, GridOrTreeT &b, bool prune=true)
Given two level set grids, replace the A grid with the union of A and B.
Definition: Composite.h:1154
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:125
openvdb::v6_1::math::Transform::copy
Ptr copy() const
Definition: Transform.h:77
openvdb::v6_1::tools::CompReplaceOp
Definition: Composite.h:836
openvdb::v6_1::tools::CsgVisitorBase
Definition: Composite.h:891
openvdb::v6_1::CombineArgs::b
const BValueType & b() const
Get the B input value.
Definition: Types.h:659
openvdb::v6_1::CombineArgs::a
const AValueType & a() const
Get the A input value.
Definition: Types.h:657
openvdb::v6_1::tools::composite::GridOrTreeConstructor< Grid< TreeType > >::TreeTypePtr
typename TreeType::Ptr TreeTypePtr
Definition: Composite.h:613
openvdb::v6_1::tools::composite::BuildPrimarySegment::RootNodeType
typename TreeType::RootNodeType RootNodeType
Definition: Composite.h:183
openvdb::v6_1::tools::CsgVisitorBase::CsgVisitorBase
CsgVisitorBase(const TreeT &aTree, const TreeT &bTree)
Definition: Composite.h:900
openvdb::v6_1::Index
Index32 Index
Definition: Types.h:61
SignedFloodFill.h
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
openvdb::v6_1::tools::composite::GridOrTreeConstructor
Definition: Composite.h:601
openvdb::v6_1::tools::composite::doCSGCopy
TreeType::Ptr doCSGCopy(const TreeType &lhs, const TreeType &rhs)
Definition: Composite.h:577
openvdb::v6_1::tools::composite::min
const std::enable_if< VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:139
openvdb
Definition: Exceptions.h:40
openvdb::v6_1::tools::compMin
void compMin(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute min(a, b) per voxel (using sparse traversal). Store the result in the A ...
Definition: Composite.h:773
openvdb::v6_1::tools::CsgUnionVisitor::CsgUnionVisitor
CsgUnionVisitor(const TreeT &a, const TreeT &b)
Definition: Composite.h:942
openvdb::v6_1::math::CoordBBox
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:271
openvdb::v6_1::tools::CsgIntersectVisitor::CsgIntersectVisitor
CsgIntersectVisitor(const TreeT &a, const TreeT &b)
Definition: Composite.h:1015
openvdb::v6_1::tools::CsgDiffVisitor::operator()
int operator()(ChildIterT &aIter, ChildIterT &bIter)
Process leaf node values.
Definition: Composite.h:1134
openvdb::v6_1::tools::composite::BuildSecondarySegment::TreePtrType
typename TreeType::Ptr TreePtrType
Definition: Composite.h:388
openvdb::v6_1::CombineArgs
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:617
openvdb::v6_1::GridBase::transform
math::Transform & transform()
Return a reference to this grid's transform, which might be shared with other grids.
Definition: Grid.h:426
openvdb::v6_1::tools::composite::BuildPrimarySegment::NodeChainType
typename RootNodeType::NodeChainType NodeChainType
Definition: Composite.h:184
openvdb::v6_1::tools::composite::GridOrTreeConstructor::TreeTypePtr
typename TreeType::Ptr TreeTypePtr
Definition: Composite.h:603
openvdb::v6_1::tools::composite::BuildSecondarySegment::ValueType
typename TreeType::ValueType ValueType
Definition: Composite.h:387
openvdb::v6_1::tools::composite::BuildSecondarySegment::LeafNodeType
typename TreeType::LeafNodeType LeafNodeType
Definition: Composite.h:389
openvdb::v6_1::math::Coord
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:52
OPENVDB_STATIC_SPECIALIZATION
#define OPENVDB_STATIC_SPECIALIZATION
Macro for determining if there are sufficient C++0x/C++11 features.
Definition: Platform.h:111
openvdb::v6_1::tools::CsgIntersectVisitor::operator()
int operator()(IterT &aIter, IterT &bIter)
Process root and internal nodes.
Definition: Composite.h:1023
Grid.h
openvdb::v6_1::tools::compSum
void compSum(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute a + b per voxel (using sparse traversal). Store the result in the A grid...
Definition: Composite.h:789
openvdb::v6_1::math::negative
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:108
openvdb::v6_1::ValueError
Definition: Exceptions.h:92
openvdb::v6_1::tools::CsgDiffVisitor::operator()
int operator()(AIterT &, BIterT &)
Don't process nodes that are at different tree levels.
Definition: Composite.h:1091
openvdb::v6_1::tools::CsgDiffVisitor
Definition: Composite.h:1079
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:177
openvdb::v6_1::tools::composite::BuildPrimarySegment::InternalNodeType
typename boost::mpl::at< NodeChainType, boost::mpl::int_< 1 > >::type InternalNodeType
Definition: Composite.h:185
openvdb::v6_1::tools::CsgUnionVisitor::operator()
int operator()(IterT &aIter, IterT &bIter)
Process root and internal nodes.
Definition: Composite.h:950
openvdb::v6_1::Grid::Ptr
SharedPtr< Grid > Ptr
Definition: Grid.h:592
openvdb::v6_1::tools::csgDifferenceCopy
GridOrTreeT::Ptr csgDifferenceCopy(const GridOrTreeT &a, const GridOrTreeT &b)
Threaded CSG difference operation that produces a new grid or tree from immutable inputs.
Definition: Composite.h:1219
openvdb::v6_1::tools::composite::BuildSecondarySegment::BuildSecondarySegment
BuildSecondarySegment(const TreeType &lhs, const TreeType &rhs)
Definition: Composite.h:395
openvdb::v6_1::tools::compReplace
void compReplace(GridOrTreeT &a, const GridOrTreeT &b)
Copy the active voxels of B into A.
Definition: Composite.h:864
openvdb::v6_1::tree::ValueAccessor::setValue
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active.
Definition: ValueAccessor.h:288
openvdb::v6_1::tools::CsgUnionVisitor
Definition: Composite.h:934
openvdb::v6_1::tools::CompReplaceOp::operator()
void operator()(const typename TreeT::ValueOnCIter &iter) const
Definition: Composite.h:843
openvdb::v6_1::tools::composite::GridOrTreeConstructor< Grid< TreeType > >::construct
static GridTypePtr construct(const GridType &grid, TreeTypePtr &tree)
Definition: Composite.h:615
openvdb::v6_1::tools::prune
void prune(TreeT &tree, typename TreeT::ValueType tolerance=zeroVal< typename TreeT::ValueType >(), bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing with tiles any nodes whose values are all the same...
Definition: Prune.h:361
openvdb::v6_1::CombineArgs::setResult
CombineArgs & setResult(const AValueType &val)
Set the output value.
Definition: Types.h:667
openvdb::v6_1::tools::csgUnionCopy
GridOrTreeT::Ptr csgUnionCopy(const GridOrTreeT &a, const GridOrTreeT &b)
Threaded CSG union operation that produces a new grid or tree from immutable inputs.
Definition: Composite.h:1191
openvdb::v6_1::tools::CsgIntersectVisitor
Definition: Composite.h:1007
openvdb::v6_1::tools::compMax
void compMax(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute max(a, b) per voxel (using sparse traversal). Store the result in the A ...
Definition: Composite.h:757
openvdb::v6_1::TreeAdapter
This adapter allows code that is templated on a Tree type to accept either a Tree type or a Grid type...
Definition: Grid.h:1036
Platform.h
openvdb::v6_1::Index32
uint32_t Index32
Definition: Types.h:59