10 #ifndef OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
11 #define OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
23 #include <tbb/blocked_range.h>
24 #include <tbb/parallel_for.h>
25 #include <tbb/parallel_reduce.h>
26 #include <tbb/task_group.h>
27 #include <tbb/task_scheduler_init.h>
29 #include <type_traits>
40 template<
typename Gr
idOrTreeT>
41 inline void csgUnion(GridOrTreeT& a, GridOrTreeT& b,
bool prune =
true);
45 template<
typename Gr
idOrTreeT>
50 template<
typename Gr
idOrTreeT>
56 template<
typename Gr
idOrTreeT>
57 inline typename GridOrTreeT::Ptr
csgUnionCopy(
const GridOrTreeT& a,
const GridOrTreeT& b);
61 template<
typename Gr
idOrTreeT>
62 inline typename GridOrTreeT::Ptr
csgIntersectionCopy(
const GridOrTreeT& a,
const GridOrTreeT& b);
66 template<
typename Gr
idOrTreeT>
67 inline typename GridOrTreeT::Ptr
csgDifferenceCopy(
const GridOrTreeT& a,
const GridOrTreeT& b);
71 template<
typename Gr
idOrTreeT>
72 inline void compMax(GridOrTreeT& a, GridOrTreeT& b);
75 template<
typename Gr
idOrTreeT>
76 inline void compMin(GridOrTreeT& a, GridOrTreeT& b);
79 template<
typename Gr
idOrTreeT>
80 inline void compSum(GridOrTreeT& a, GridOrTreeT& b);
83 template<
typename Gr
idOrTreeT>
84 inline void compMul(GridOrTreeT& a, GridOrTreeT& b);
87 template<
typename Gr
idOrTreeT>
88 inline void compDiv(GridOrTreeT& a, GridOrTreeT& b);
91 template<
typename Gr
idOrTreeT>
92 inline void compReplace(GridOrTreeT& a,
const GridOrTreeT& b);
101 template<
typename T>
inline
102 const typename std::enable_if<!VecTraits<T>::IsVec, T>::type&
105 template<
typename T>
inline
106 const typename std::enable_if<!VecTraits<T>::IsVec, T>::type&
111 template<
typename T>
inline
112 const typename std::enable_if<VecTraits<T>::IsVec, T>::type&
113 min(
const T& a,
const T& b)
115 const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
116 return (aMag < bMag ? a : (bMag < aMag ? b :
std::min(a, b)));
119 template<
typename T>
inline
120 const typename std::enable_if<VecTraits<T>::IsVec, T>::type&
121 max(
const T& a,
const T& b)
123 const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
124 return (aMag < bMag ? b : (bMag < aMag ? a :
std::max(a, b)));
128 template<
typename T>
inline
129 typename std::enable_if<!std::is_integral<T>::value, T>::type
130 divide(
const T& a,
const T& b) {
return a / b; }
132 template<
typename T>
inline
133 typename std::enable_if<std::is_integral<T>::value, T>::type
137 if (b != zero)
return a / b;
138 if (a == zero)
return 0;
145 inline bool divide(
bool a,
bool ) {
return a; }
150 template<
typename TreeType, CSGOperation Operation>
162 : mSegment(new TreeType(lhs.background()))
170 std::vector<const LeafNodeType*> leafNodes;
173 std::vector<const InternalNodeType*> internalNodes;
174 mLhsTree->getNodes(internalNodes);
176 ProcessInternalNodes op(internalNodes, *mRhsTree, *mSegment, leafNodes);
177 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
180 ProcessLeafNodes op(leafNodes, *mRhsTree, *mSegment);
181 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
188 struct ProcessInternalNodes {
190 ProcessInternalNodes(std::vector<const InternalNodeType*>& lhsNodes,
191 const TreeType& rhsTree, TreeType& outputTree,
192 std::vector<const LeafNodeType*>& outputLeafNodes)
193 : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front())
195 , mLocalTree(mRhsTree->background())
196 , mOutputTree(&outputTree)
198 , mOutputLeafNodes(&outputLeafNodes)
202 ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
203 : mLhsNodes(other.mLhsNodes)
204 , mRhsTree(other.mRhsTree)
205 , mLocalTree(mRhsTree->background())
206 , mOutputTree(&mLocalTree)
208 , mOutputLeafNodes(&mLocalLeafNodes)
212 void join(ProcessInternalNodes& other)
214 mOutputTree->merge(*other.mOutputTree);
215 mOutputLeafNodes->insert(mOutputLeafNodes->end(),
216 other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
219 void operator()(
const tbb::blocked_range<size_t>& range)
224 std::vector<const LeafNodeType*> tmpLeafNodes;
226 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
228 const InternalNodeType& lhsNode = *mLhsNodes[n];
229 const Coord& ijk = lhsNode.origin();
230 const InternalNodeType * rhsNode =
231 rhsAcc.template probeConstNode<InternalNodeType>(ijk);
234 lhsNode.getNodes(*mOutputLeafNodes);
237 if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
238 tmpLeafNodes.clear();
239 lhsNode.getNodes(tmpLeafNodes);
240 for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
241 outputAcc.addLeaf(
new LeafNodeType(*tmpLeafNodes[i]));
245 if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
246 tmpLeafNodes.clear();
247 lhsNode.getNodes(tmpLeafNodes);
248 for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
249 outputAcc.addLeaf(
new LeafNodeType(*tmpLeafNodes[i]));
257 InternalNodeType
const *
const *
const mLhsNodes;
258 TreeType
const *
const mRhsTree;
260 TreeType *
const mOutputTree;
262 std::vector<const LeafNodeType*> mLocalLeafNodes;
263 std::vector<const LeafNodeType*> *
const mOutputLeafNodes;
266 struct ProcessLeafNodes {
268 ProcessLeafNodes(std::vector<const LeafNodeType*>& lhsNodes,
269 const TreeType& rhsTree, TreeType& output)
270 : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front())
272 , mLocalTree(mRhsTree->background())
273 , mOutputTree(&output)
277 ProcessLeafNodes(ProcessLeafNodes& other, tbb::split)
278 : mLhsNodes(other.mLhsNodes)
279 , mRhsTree(other.mRhsTree)
280 , mLocalTree(mRhsTree->background())
281 , mOutputTree(&mLocalTree)
285 void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
287 void operator()(
const tbb::blocked_range<size_t>& range)
289 tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
290 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
292 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
294 const LeafNodeType& lhsNode = *mLhsNodes[n];
295 const Coord& ijk = lhsNode.origin();
297 const LeafNodeType* rhsNodePt = rhsAcc.probeConstLeaf(ijk);
301 LeafNodeType* outputNode = outputAcc.touchLeaf(ijk);
302 ValueType * outputData = outputNode->buffer().
data();
303 NodeMaskType& outputMask = outputNode->getValueMask();
305 const ValueType * lhsData = lhsNode.buffer().data();
306 const NodeMaskType& lhsMask = lhsNode.getValueMask();
308 const ValueType * rhsData = rhsNodePt->buffer().data();
309 const NodeMaskType& rhsMask = rhsNodePt->getValueMask();
312 for (
Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
313 const bool fromRhs = lhsData[pos] < rhsData[pos];
314 outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
315 outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
318 for (
Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
320 const bool fromRhs = lhsData[pos] < rhsVal;
321 outputData[pos] = fromRhs ? rhsVal : lhsData[pos];
322 outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
325 for (
Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
326 const bool fromRhs = lhsData[pos] > rhsData[pos];
327 outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
328 outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
334 if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
335 outputAcc.addLeaf(
new LeafNodeType(lhsNode));
338 if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
339 outputAcc.addLeaf(
new LeafNodeType(lhsNode));
346 LeafNodeType
const *
const *
const mLhsNodes;
347 TreeType
const *
const mRhsTree;
349 TreeType *
const mOutputTree;
352 TreePtrType mSegment;
353 TreeType
const *
const mLhsTree;
354 TreeType
const *
const mRhsTree;
358 template<
typename TreeType, CSGOperation Operation>
370 : mSegment(new TreeType(lhs.background()))
378 std::vector<const LeafNodeType*> leafNodes;
381 std::vector<const InternalNodeType*> internalNodes;
382 mRhsTree->getNodes(internalNodes);
384 ProcessInternalNodes op(internalNodes, *mLhsTree, *mSegment, leafNodes);
385 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
388 ProcessLeafNodes op(leafNodes, *mLhsTree, *mSegment);
389 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
396 struct ProcessInternalNodes {
398 ProcessInternalNodes(std::vector<const InternalNodeType*>& rhsNodes,
399 const TreeType& lhsTree, TreeType& outputTree,
400 std::vector<const LeafNodeType*>& outputLeafNodes)
401 : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front())
403 , mLocalTree(mLhsTree->background())
404 , mOutputTree(&outputTree)
406 , mOutputLeafNodes(&outputLeafNodes)
410 ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
411 : mRhsNodes(other.mRhsNodes)
412 , mLhsTree(other.mLhsTree)
413 , mLocalTree(mLhsTree->background())
414 , mOutputTree(&mLocalTree)
416 , mOutputLeafNodes(&mLocalLeafNodes)
420 void join(ProcessInternalNodes& other)
422 mOutputTree->merge(*other.mOutputTree);
423 mOutputLeafNodes->insert(mOutputLeafNodes->end(),
424 other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
427 void operator()(
const tbb::blocked_range<size_t>& range)
432 std::vector<const LeafNodeType*> tmpLeafNodes;
434 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
436 const InternalNodeType& rhsNode = *mRhsNodes[n];
437 const Coord& ijk = rhsNode.origin();
438 const InternalNodeType * lhsNode =
439 lhsAcc.template probeConstNode<InternalNodeType>(ijk);
442 rhsNode.getNodes(*mOutputLeafNodes);
445 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
446 tmpLeafNodes.clear();
447 rhsNode.getNodes(tmpLeafNodes);
448 for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
449 outputAcc.addLeaf(
new LeafNodeType(*tmpLeafNodes[i]));
453 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
454 tmpLeafNodes.clear();
455 rhsNode.getNodes(tmpLeafNodes);
456 for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
457 LeafNodeType* outputNode =
new LeafNodeType(*tmpLeafNodes[i]);
458 outputNode->negate();
459 outputAcc.addLeaf(outputNode);
463 if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
464 tmpLeafNodes.clear();
465 rhsNode.getNodes(tmpLeafNodes);
466 for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
467 outputAcc.addLeaf(
new LeafNodeType(*tmpLeafNodes[i]));
475 InternalNodeType
const *
const *
const mRhsNodes;
476 TreeType
const *
const mLhsTree;
478 TreeType *
const mOutputTree;
480 std::vector<const LeafNodeType*> mLocalLeafNodes;
481 std::vector<const LeafNodeType*> *
const mOutputLeafNodes;
484 struct ProcessLeafNodes {
486 ProcessLeafNodes(std::vector<const LeafNodeType*>& rhsNodes,
487 const TreeType& lhsTree, TreeType& output)
488 : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front())
490 , mLocalTree(mLhsTree->background())
491 , mOutputTree(&output)
495 ProcessLeafNodes(ProcessLeafNodes& rhs, tbb::split)
496 : mRhsNodes(rhs.mRhsNodes)
497 , mLhsTree(rhs.mLhsTree)
498 , mLocalTree(mLhsTree->background())
499 , mOutputTree(&mLocalTree)
503 void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
505 void operator()(
const tbb::blocked_range<size_t>& range)
507 tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
508 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
510 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
512 const LeafNodeType& rhsNode = *mRhsNodes[n];
513 const Coord& ijk = rhsNode.origin();
515 const LeafNodeType* lhsNode = lhsAcc.probeConstLeaf(ijk);
519 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
520 outputAcc.addLeaf(
new LeafNodeType(rhsNode));
523 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
524 LeafNodeType* outputNode =
new LeafNodeType(rhsNode);
525 outputNode->negate();
526 outputAcc.addLeaf(outputNode);
529 if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
530 outputAcc.addLeaf(
new LeafNodeType(rhsNode));
537 LeafNodeType
const *
const *
const mRhsNodes;
538 TreeType
const *
const mLhsTree;
540 TreeType *
const mOutputTree;
543 TreePtrType mSegment;
544 TreeType
const *
const mLhsTree;
545 TreeType
const *
const mRhsTree;
549 template<CSGOperation Operation,
typename TreeType>
550 inline typename TreeType::Ptr
557 tbb::task_group tasks;
559 tasks.run(secondary);
574 template<
typename TreeType>
582 template<
typename TreeType>
591 maskGrid->setTransform(grid.transform().
copy());
592 maskGrid->insertMeta(grid);
602 template <
typename LeafT>
603 using LeafPairList = std::vector<std::pair<LeafT*, LeafT*>>;
611 template <
typename TreeT>
612 inline void transferLeafNodes(TreeT &srcTree, TreeT &dstTree,
613 LeafPairList<typename TreeT::LeafNodeType> &overlapping)
615 using LeafT =
typename TreeT::LeafNodeType;
617 std::vector<LeafT*> srcLeafNodes;
618 srcLeafNodes.reserve(srcTree.leafCount());
619 srcTree.stealNodes(srcLeafNodes);
621 for (LeafT *srcLeaf : srcLeafNodes) {
622 LeafT *dstLeaf = acc.probeLeaf(srcLeaf->origin());
624 overlapping.emplace_back(dstLeaf, srcLeaf);
626 acc.addLeaf(srcLeaf);
634 template <
typename TreeT,
typename OpT>
636 typename std::enable_if<
637 !std::is_same<typename TreeT::ValueType, bool>::value &&
638 !std::is_same<typename TreeT::BuildType, ValueMask>::value &&
639 std::is_same<
typename TreeT::LeafNodeType::Buffer::ValueType,
640 typename TreeT::LeafNodeType::Buffer::StorageType>::value>::type
641 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
643 using LeafT =
typename TreeT::LeafNodeType;
644 LeafPairList<LeafT> overlapping;
645 transferLeafNodes(srcTree, dstTree, overlapping);
647 using RangeT = tbb::blocked_range<size_t>;
648 tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](
const RangeT& r) {
649 for (auto i = r.begin(); i != r.end(); ++i) {
650 LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
651 dstLeaf->getValueMask() |= srcLeaf->getValueMask();
652 auto *ptr = dstLeaf->buffer().data();
653 for (auto v = srcLeaf->cbeginValueOn(); v; ++v) op(ptr[v.pos()], *v);
662 template <
typename TreeT,
typename OpT>
664 typename std::enable_if<
665 std::is_same<typename TreeT::BuildType, ValueMask>::value &&
666 std::is_same<typename TreeT::ValueType, bool>::value>::type
667 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT)
669 using LeafT =
typename TreeT::LeafNodeType;
670 LeafPairList<LeafT> overlapping;
671 transferLeafNodes(srcTree, dstTree, overlapping);
673 using RangeT = tbb::blocked_range<size_t>;
674 tbb::parallel_for(RangeT(0, overlapping.size()), [&overlapping](
const RangeT& r) {
675 for (auto i = r.begin(); i != r.end(); ++i) {
676 overlapping[i].first->getValueMask() |= overlapping[i].second->getValueMask();
677 delete overlapping[i].second;
684 template <
typename TreeT,
typename OpT>
686 typename std::enable_if<
687 std::is_same<typename TreeT::ValueType, bool>::value &&
688 !std::is_same<typename TreeT::BuildType, ValueMask>::value>::type
689 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
691 using LeafT =
typename TreeT::LeafNodeType;
692 LeafPairList<LeafT> overlapping;
693 transferLeafNodes(srcTree, dstTree, overlapping);
695 using RangeT = tbb::blocked_range<size_t>;
696 using WordT =
typename LeafT::Buffer::WordType;
697 tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](
const RangeT& r) {
698 for (auto i = r.begin(); i != r.end(); ++i) {
699 LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
700 WordT *w1 = dstLeaf->buffer().data();
701 const WordT *w2 = srcLeaf->buffer().data();
702 const WordT *w3 = &(srcLeaf->getValueMask().template getWord<WordT>(0));
703 for (Index32 n = LeafT::Buffer::WORD_COUNT; n--; ++w1) {
704 WordT tmp = *w1, state = *w3++;
706 *w1 = (state & tmp) | (~state & *w1);
708 dstLeaf->getValueMask() |= srcLeaf->getValueMask();
717 template <
typename TreeT>
720 using ValueT =
typename TreeT::ValueType;
722 void operator()(ValueT& dst,
const ValueT& src)
const { dst = src; }
726 template <
typename TreeT>
727 inline void validateLevelSet(
const TreeT& tree,
const std::string& gridName = std::string(
""))
729 using ValueT =
typename TreeT::ValueType;
730 const ValueT zero = zeroVal<ValueT>();
731 if (!(tree.background() > zero)) {
732 std::stringstream ss;
733 ss <<
"expected grid ";
734 if (!gridName.empty()) ss << gridName <<
" ";
735 ss <<
"outside value > 0, got " << tree.background();
738 if (!(-tree.background() < zero)) {
739 std::stringstream ss;
740 ss <<
"expected grid ";
741 if (!gridName.empty()) ss << gridName <<
" ";
742 ss <<
"inside value < 0, got " << -tree.background();
750 template<
typename Gr
idOrTreeT>
752 compMax(GridOrTreeT& aTree, GridOrTreeT& bTree)
755 using TreeT =
typename Adapter::TreeType;
756 using ValueT =
typename TreeT::ValueType;
762 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op,
false);
766 template<
typename Gr
idOrTreeT>
768 compMin(GridOrTreeT& aTree, GridOrTreeT& bTree)
771 using TreeT =
typename Adapter::TreeType;
772 using ValueT =
typename TreeT::ValueType;
778 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op,
false);
782 template<
typename Gr
idOrTreeT>
784 compSum(GridOrTreeT& aTree, GridOrTreeT& bTree)
787 using TreeT =
typename Adapter::TreeType;
793 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op,
false);
797 template<
typename Gr
idOrTreeT>
799 compMul(GridOrTreeT& aTree, GridOrTreeT& bTree)
802 using TreeT =
typename Adapter::TreeType;
808 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op,
false);
812 template<
typename Gr
idOrTreeT>
814 compDiv(GridOrTreeT& aTree, GridOrTreeT& bTree)
817 using TreeT =
typename Adapter::TreeType;
823 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op,
false);
830 template<
typename TreeT>
838 void operator()(
const typename TreeT::ValueOnCIter& iter)
const
841 iter.getBoundingBox(bbox);
842 aTree->fill(bbox, *iter);
845 void operator()(
const typename TreeT::LeafCIter& leafIter)
const
848 for (
typename TreeT::LeafCIter::LeafNodeT::ValueOnCIter iter =
849 leafIter->cbeginValueOn(); iter; ++iter)
851 acc.
setValue(iter.getCoord(), *iter);
857 template<
typename Gr
idOrTreeT>
862 using TreeT =
typename Adapter::TreeType;
863 using ValueOnCIterT =
typename TreeT::ValueOnCIter;
866 Adapter::tree(aTree).topologyUnion(Adapter::tree(bTree));
871 ValueOnCIterT iter = bTree.cbeginValueOn();
872 iter.setMaxDepth(iter.getLeafDepth() - 1);
873 foreach(iter, op,
false);
876 foreach(Adapter::tree(bTree).cbeginLeaf(), op);
883 template<
typename Gr
idOrTreeT>
888 using TreeT =
typename Adapter::TreeType;
889 TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
898 template<
typename Gr
idOrTreeT>
903 using TreeT =
typename Adapter::TreeType;
904 TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
913 template<
typename Gr
idOrTreeT>
918 using TreeT =
typename Adapter::TreeType;
919 TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
929 template<
typename Gr
idOrTreeT>
930 inline typename GridOrTreeT::Ptr
934 using TreePtrT =
typename Adapter::TreeType::Ptr;
936 TreePtrT output = composite::doCSGCopy<composite::CSG_UNION>(
937 Adapter::tree(a), Adapter::tree(b));
943 template<
typename Gr
idOrTreeT>
944 inline typename GridOrTreeT::Ptr
948 using TreePtrT =
typename Adapter::TreeType::Ptr;
950 TreePtrT output = composite::doCSGCopy<composite::CSG_INTERSECTION>(
951 Adapter::tree(a), Adapter::tree(b));
957 template<
typename Gr
idOrTreeT>
958 inline typename GridOrTreeT::Ptr
962 using TreePtrT =
typename Adapter::TreeType::Ptr;
964 TreePtrT output = composite::doCSGCopy<composite::CSG_DIFFERENCE>(
965 Adapter::tree(a), Adapter::tree(b));
993 template<
typename TreeT,
typename OpT = composite::CopyOp<TreeT> >
997 composite::doCompActiveLeafVoxels<TreeT, OpT>(srcTree, dstTree, op);
1005 #endif // OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED