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>
28 #include <type_traits>
39 template<
typename Gr
idOrTreeT>
40 inline void csgUnion(GridOrTreeT& a, GridOrTreeT& b,
bool prune =
true);
44 template<
typename Gr
idOrTreeT>
49 template<
typename Gr
idOrTreeT>
55 template<
typename Gr
idOrTreeT>
56 inline typename GridOrTreeT::Ptr
csgUnionCopy(
const GridOrTreeT& a,
const GridOrTreeT& b);
60 template<
typename Gr
idOrTreeT>
61 inline typename GridOrTreeT::Ptr
csgIntersectionCopy(
const GridOrTreeT& a,
const GridOrTreeT& b);
65 template<
typename Gr
idOrTreeT>
66 inline typename GridOrTreeT::Ptr
csgDifferenceCopy(
const GridOrTreeT& a,
const GridOrTreeT& b);
70 template<
typename Gr
idOrTreeT>
71 inline void compMax(GridOrTreeT& a, GridOrTreeT& b);
74 template<
typename Gr
idOrTreeT>
75 inline void compMin(GridOrTreeT& a, GridOrTreeT& b);
78 template<
typename Gr
idOrTreeT>
79 inline void compSum(GridOrTreeT& a, GridOrTreeT& b);
82 template<
typename Gr
idOrTreeT>
83 inline void compMul(GridOrTreeT& a, GridOrTreeT& b);
86 template<
typename Gr
idOrTreeT>
87 inline void compDiv(GridOrTreeT& a, GridOrTreeT& b);
90 template<
typename Gr
idOrTreeT>
91 inline void compReplace(GridOrTreeT& a,
const GridOrTreeT& b);
100 template<
typename T>
inline
101 const typename std::enable_if<!VecTraits<T>::IsVec, T>::type&
104 template<
typename T>
inline
105 const typename std::enable_if<!VecTraits<T>::IsVec, T>::type&
110 template<
typename T>
inline
111 const typename std::enable_if<VecTraits<T>::IsVec, T>::type&
112 min(
const T& a,
const T& b)
114 const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
115 return (aMag < bMag ? a : (bMag < aMag ? b :
std::min(a, b)));
118 template<
typename T>
inline
119 const typename std::enable_if<VecTraits<T>::IsVec, T>::type&
120 max(
const T& a,
const T& b)
122 const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
123 return (aMag < bMag ? b : (bMag < aMag ? a :
std::max(a, b)));
127 template<
typename T>
inline
128 typename std::enable_if<!std::is_integral<T>::value, T>::type
129 divide(
const T& a,
const T& b) {
return a / b; }
131 template<
typename T>
inline
132 typename std::enable_if<std::is_integral<T>::value, T>::type
136 if (b != zero)
return a / b;
137 if (a == zero)
return 0;
144 inline bool divide(
bool a,
bool ) {
return a; }
149 enum CSGOperation { CSG_UNION, CSG_INTERSECTION, CSG_DIFFERENCE };
151 template<
typename TreeType, CSGOperation Operation>
152 struct BuildPrimarySegment
154 using ValueType =
typename TreeType::ValueType;
155 using TreePtrType =
typename TreeType::Ptr;
156 using LeafNodeType =
typename TreeType::LeafNodeType;
157 using NodeMaskType =
typename LeafNodeType::NodeMaskType;
158 using RootNodeType =
typename TreeType::RootNodeType;
159 using NodeChainType =
typename RootNodeType::NodeChainType;
160 using InternalNodeType =
typename NodeChainType::template Get<1>;
162 BuildPrimarySegment(
const TreeType& lhs,
const TreeType& rhs)
163 : mSegment(new TreeType(lhs.background()))
169 void operator()()
const
171 std::vector<const LeafNodeType*> leafNodes;
174 std::vector<const InternalNodeType*> internalNodes;
175 mLhsTree->getNodes(internalNodes);
177 ProcessInternalNodes op(internalNodes, *mRhsTree, *mSegment, leafNodes);
178 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
181 ProcessLeafNodes op(leafNodes, *mRhsTree, *mSegment);
182 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
185 TreePtrType& segment() {
return mSegment; }
189 struct ProcessInternalNodes {
191 ProcessInternalNodes(std::vector<const InternalNodeType*>& lhsNodes,
192 const TreeType& rhsTree, TreeType& outputTree,
193 std::vector<const LeafNodeType*>& outputLeafNodes)
194 : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front())
196 , mLocalTree(mRhsTree->background())
197 , mOutputTree(&outputTree)
199 , mOutputLeafNodes(&outputLeafNodes)
203 ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
204 : mLhsNodes(other.mLhsNodes)
205 , mRhsTree(other.mRhsTree)
206 , mLocalTree(mRhsTree->background())
207 , mOutputTree(&mLocalTree)
209 , mOutputLeafNodes(&mLocalLeafNodes)
213 void join(ProcessInternalNodes& other)
215 mOutputTree->merge(*other.mOutputTree);
216 mOutputLeafNodes->insert(mOutputLeafNodes->end(),
217 other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
220 void operator()(
const tbb::blocked_range<size_t>& range)
222 tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
223 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
225 std::vector<const LeafNodeType*> tmpLeafNodes;
227 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
229 const InternalNodeType& lhsNode = *mLhsNodes[n];
230 const Coord& ijk = lhsNode.origin();
231 const InternalNodeType * rhsNode =
232 rhsAcc.template probeConstNode<InternalNodeType>(ijk);
235 lhsNode.getNodes(*mOutputLeafNodes);
237 if (Operation == CSG_INTERSECTION) {
238 if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
239 tmpLeafNodes.clear();
240 lhsNode.getNodes(tmpLeafNodes);
241 for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
242 outputAcc.addLeaf(
new LeafNodeType(*tmpLeafNodes[i]));
246 if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
247 tmpLeafNodes.clear();
248 lhsNode.getNodes(tmpLeafNodes);
249 for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
250 outputAcc.addLeaf(
new LeafNodeType(*tmpLeafNodes[i]));
258 InternalNodeType
const *
const *
const mLhsNodes;
259 TreeType
const *
const mRhsTree;
261 TreeType *
const mOutputTree;
263 std::vector<const LeafNodeType*> mLocalLeafNodes;
264 std::vector<const LeafNodeType*> *
const mOutputLeafNodes;
267 struct ProcessLeafNodes {
269 ProcessLeafNodes(std::vector<const LeafNodeType*>& lhsNodes,
270 const TreeType& rhsTree, TreeType& output)
271 : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front())
273 , mLocalTree(mRhsTree->background())
274 , mOutputTree(&output)
278 ProcessLeafNodes(ProcessLeafNodes& other, tbb::split)
279 : mLhsNodes(other.mLhsNodes)
280 , mRhsTree(other.mRhsTree)
281 , mLocalTree(mRhsTree->background())
282 , mOutputTree(&mLocalTree)
286 void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
288 void operator()(
const tbb::blocked_range<size_t>& range)
290 tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
291 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
293 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
295 const LeafNodeType& lhsNode = *mLhsNodes[n];
296 const Coord& ijk = lhsNode.origin();
298 const LeafNodeType* rhsNodePt = rhsAcc.probeConstLeaf(ijk);
302 LeafNodeType* outputNode = outputAcc.touchLeaf(ijk);
303 ValueType * outputData = outputNode->buffer().data();
304 NodeMaskType& outputMask = outputNode->getValueMask();
306 const ValueType * lhsData = lhsNode.buffer().data();
307 const NodeMaskType& lhsMask = lhsNode.getValueMask();
309 const ValueType * rhsData = rhsNodePt->buffer().data();
310 const NodeMaskType& rhsMask = rhsNodePt->getValueMask();
312 if (Operation == CSG_INTERSECTION) {
313 for (
Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
314 const bool fromRhs = lhsData[pos] < rhsData[pos];
315 outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
316 outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
318 }
else if (Operation == CSG_DIFFERENCE){
319 for (
Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
321 const bool fromRhs = lhsData[pos] < rhsVal;
322 outputData[pos] = fromRhs ? rhsVal : lhsData[pos];
323 outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
326 for (
Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
327 const bool fromRhs = lhsData[pos] > rhsData[pos];
328 outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
329 outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
334 if (Operation == CSG_INTERSECTION) {
335 if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
336 outputAcc.addLeaf(
new LeafNodeType(lhsNode));
339 if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
340 outputAcc.addLeaf(
new LeafNodeType(lhsNode));
347 LeafNodeType
const *
const *
const mLhsNodes;
348 TreeType
const *
const mRhsTree;
350 TreeType *
const mOutputTree;
353 TreePtrType mSegment;
354 TreeType
const *
const mLhsTree;
355 TreeType
const *
const mRhsTree;
359 template<
typename TreeType, CSGOperation Operation>
360 struct BuildSecondarySegment
362 using ValueType =
typename TreeType::ValueType;
363 using TreePtrType =
typename TreeType::Ptr;
364 using LeafNodeType =
typename TreeType::LeafNodeType;
365 using NodeMaskType =
typename LeafNodeType::NodeMaskType;
366 using RootNodeType =
typename TreeType::RootNodeType;
367 using NodeChainType =
typename RootNodeType::NodeChainType;
368 using InternalNodeType =
typename NodeChainType::template Get<1>;
370 BuildSecondarySegment(
const TreeType& lhs,
const TreeType& rhs)
371 : mSegment(new TreeType(lhs.background()))
377 void operator()()
const
379 std::vector<const LeafNodeType*> leafNodes;
382 std::vector<const InternalNodeType*> internalNodes;
383 mRhsTree->getNodes(internalNodes);
385 ProcessInternalNodes op(internalNodes, *mLhsTree, *mSegment, leafNodes);
386 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
389 ProcessLeafNodes op(leafNodes, *mLhsTree, *mSegment);
390 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
393 TreePtrType& segment() {
return mSegment; }
397 struct ProcessInternalNodes {
399 ProcessInternalNodes(std::vector<const InternalNodeType*>& rhsNodes,
400 const TreeType& lhsTree, TreeType& outputTree,
401 std::vector<const LeafNodeType*>& outputLeafNodes)
402 : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front())
404 , mLocalTree(mLhsTree->background())
405 , mOutputTree(&outputTree)
407 , mOutputLeafNodes(&outputLeafNodes)
411 ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
412 : mRhsNodes(other.mRhsNodes)
413 , mLhsTree(other.mLhsTree)
414 , mLocalTree(mLhsTree->background())
415 , mOutputTree(&mLocalTree)
417 , mOutputLeafNodes(&mLocalLeafNodes)
421 void join(ProcessInternalNodes& other)
423 mOutputTree->merge(*other.mOutputTree);
424 mOutputLeafNodes->insert(mOutputLeafNodes->end(),
425 other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
428 void operator()(
const tbb::blocked_range<size_t>& range)
430 tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
431 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
433 std::vector<const LeafNodeType*> tmpLeafNodes;
435 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
437 const InternalNodeType& rhsNode = *mRhsNodes[n];
438 const Coord& ijk = rhsNode.origin();
439 const InternalNodeType * lhsNode =
440 lhsAcc.template probeConstNode<InternalNodeType>(ijk);
443 rhsNode.getNodes(*mOutputLeafNodes);
445 if (Operation == CSG_INTERSECTION) {
446 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
447 tmpLeafNodes.clear();
448 rhsNode.getNodes(tmpLeafNodes);
449 for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
450 outputAcc.addLeaf(
new LeafNodeType(*tmpLeafNodes[i]));
453 }
else if (Operation == CSG_DIFFERENCE) {
454 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
455 tmpLeafNodes.clear();
456 rhsNode.getNodes(tmpLeafNodes);
457 for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
458 LeafNodeType* outputNode =
new LeafNodeType(*tmpLeafNodes[i]);
459 outputNode->negate();
460 outputAcc.addLeaf(outputNode);
464 if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
465 tmpLeafNodes.clear();
466 rhsNode.getNodes(tmpLeafNodes);
467 for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
468 outputAcc.addLeaf(
new LeafNodeType(*tmpLeafNodes[i]));
476 InternalNodeType
const *
const *
const mRhsNodes;
477 TreeType
const *
const mLhsTree;
479 TreeType *
const mOutputTree;
481 std::vector<const LeafNodeType*> mLocalLeafNodes;
482 std::vector<const LeafNodeType*> *
const mOutputLeafNodes;
485 struct ProcessLeafNodes {
487 ProcessLeafNodes(std::vector<const LeafNodeType*>& rhsNodes,
488 const TreeType& lhsTree, TreeType& output)
489 : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front())
491 , mLocalTree(mLhsTree->background())
492 , mOutputTree(&output)
496 ProcessLeafNodes(ProcessLeafNodes& rhs, tbb::split)
497 : mRhsNodes(rhs.mRhsNodes)
498 , mLhsTree(rhs.mLhsTree)
499 , mLocalTree(mLhsTree->background())
500 , mOutputTree(&mLocalTree)
504 void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
506 void operator()(
const tbb::blocked_range<size_t>& range)
508 tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
509 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
511 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
513 const LeafNodeType& rhsNode = *mRhsNodes[n];
514 const Coord& ijk = rhsNode.origin();
516 const LeafNodeType* lhsNode = lhsAcc.probeConstLeaf(ijk);
519 if (Operation == CSG_INTERSECTION) {
520 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
521 outputAcc.addLeaf(
new LeafNodeType(rhsNode));
523 }
else if (Operation == CSG_DIFFERENCE) {
524 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
525 LeafNodeType* outputNode =
new LeafNodeType(rhsNode);
526 outputNode->negate();
527 outputAcc.addLeaf(outputNode);
530 if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
531 outputAcc.addLeaf(
new LeafNodeType(rhsNode));
538 LeafNodeType
const *
const *
const mRhsNodes;
539 TreeType
const *
const mLhsTree;
541 TreeType *
const mOutputTree;
544 TreePtrType mSegment;
545 TreeType
const *
const mLhsTree;
546 TreeType
const *
const mRhsTree;
550 template<CSGOperation Operation,
typename TreeType>
551 inline typename TreeType::Ptr
552 doCSGCopy(
const TreeType& lhs,
const TreeType& rhs)
554 BuildPrimarySegment<TreeType, Operation> primary(lhs, rhs);
555 BuildSecondarySegment<TreeType, Operation> secondary(lhs, rhs);
558 tbb::task_group tasks;
560 tasks.run(secondary);
563 primary.segment()->merge(*secondary.segment());
568 return primary.segment();
575 template<
typename TreeType>
576 struct GridOrTreeConstructor
578 using TreeTypePtr =
typename TreeType::Ptr;
579 static TreeTypePtr construct(
const TreeType&, TreeTypePtr& tree) {
return tree; }
583 template<
typename TreeType>
584 struct GridOrTreeConstructor<
Grid<TreeType> >
586 using GridType = Grid<TreeType>;
588 using TreeTypePtr =
typename TreeType::Ptr;
590 static GridTypePtr construct(
const GridType& grid, TreeTypePtr& tree) {
591 GridTypePtr maskGrid(GridType::create(tree));
592 maskGrid->setTransform(grid.transform().copy());
593 maskGrid->insertMeta(grid);
602 template <
typename LeafT>
603 using LeafPairList = std::vector<std::pair<LeafT*, LeafT*>>;
609 template <
typename TreeT>
610 inline void transferLeafNodes(TreeT &srcTree, TreeT &dstTree,
611 LeafPairList<typename TreeT::LeafNodeType> &overlapping)
613 using LeafT =
typename TreeT::LeafNodeType;
614 tree::ValueAccessor<TreeT> acc(dstTree);
615 std::vector<LeafT*> srcLeafNodes;
616 srcLeafNodes.reserve(srcTree.leafCount());
617 srcTree.stealNodes(srcLeafNodes);
619 for (LeafT *srcLeaf : srcLeafNodes) {
620 LeafT *dstLeaf = acc.probeLeaf(srcLeaf->origin());
622 overlapping.emplace_back(dstLeaf, srcLeaf);
624 acc.addLeaf(srcLeaf);
630 template <
typename TreeT,
typename OpT>
632 typename std::enable_if<
633 !std::is_same<typename TreeT::ValueType, bool>::value &&
634 !std::is_same<typename TreeT::BuildType, ValueMask>::value &&
635 std::is_same<
typename TreeT::LeafNodeType::Buffer::ValueType,
636 typename TreeT::LeafNodeType::Buffer::StorageType>::value>::type
637 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
639 using LeafT =
typename TreeT::LeafNodeType;
640 LeafPairList<LeafT> overlapping;
641 transferLeafNodes(srcTree, dstTree, overlapping);
643 using RangeT = tbb::blocked_range<size_t>;
644 tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](
const RangeT& r) {
645 for (auto i = r.begin(); i != r.end(); ++i) {
646 LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
647 dstLeaf->getValueMask() |= srcLeaf->getValueMask();
648 auto *ptr = dstLeaf->buffer().data();
649 for (auto v = srcLeaf->cbeginValueOn(); v; ++v) op(ptr[v.pos()], *v);
656 template <
typename TreeT,
typename OpT>
658 typename std::enable_if<
659 std::is_same<typename TreeT::BuildType, ValueMask>::value &&
660 std::is_same<typename TreeT::ValueType, bool>::value>::type
661 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT)
663 using LeafT =
typename TreeT::LeafNodeType;
664 LeafPairList<LeafT> overlapping;
665 transferLeafNodes(srcTree, dstTree, overlapping);
667 using RangeT = tbb::blocked_range<size_t>;
668 tbb::parallel_for(RangeT(0, overlapping.size()), [&overlapping](
const RangeT& r) {
669 for (auto i = r.begin(); i != r.end(); ++i) {
670 overlapping[i].first->getValueMask() |= overlapping[i].second->getValueMask();
671 delete overlapping[i].second;
677 template <
typename TreeT,
typename OpT>
679 typename std::enable_if<
680 std::is_same<typename TreeT::ValueType, bool>::value &&
681 !std::is_same<typename TreeT::BuildType, ValueMask>::value>::type
682 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
684 using LeafT =
typename TreeT::LeafNodeType;
685 LeafPairList<LeafT> overlapping;
686 transferLeafNodes(srcTree, dstTree, overlapping);
688 using RangeT = tbb::blocked_range<size_t>;
689 using WordT =
typename LeafT::Buffer::WordType;
690 tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](
const RangeT& r) {
691 for (auto i = r.begin(); i != r.end(); ++i) {
692 LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
693 WordT *w1 = dstLeaf->buffer().data();
694 const WordT *w2 = srcLeaf->buffer().data();
695 const WordT *w3 = &(srcLeaf->getValueMask().template getWord<WordT>(0));
696 for (Index32 n = LeafT::Buffer::WORD_COUNT; n--; ++w1) {
697 WordT tmp = *w1, state = *w3++;
699 *w1 = (state & tmp) | (~state & *w1);
701 dstLeaf->getValueMask() |= srcLeaf->getValueMask();
708 template <
typename TreeT>
711 using ValueT =
typename TreeT::ValueType;
713 void operator()(ValueT& dst,
const ValueT& src)
const { dst = src; }
716 template <
typename TreeT>
717 inline void validateLevelSet(
const TreeT& tree,
const std::string& gridName = std::string(
""))
719 using ValueT =
typename TreeT::ValueType;
720 const ValueT zero = zeroVal<ValueT>();
721 if (!(tree.background() > zero)) {
722 std::stringstream ss;
723 ss <<
"expected grid ";
724 if (!gridName.empty()) ss << gridName <<
" ";
725 ss <<
"outside value > 0, got " << tree.background();
728 if (!(-tree.background() < zero)) {
729 std::stringstream ss;
730 ss <<
"expected grid ";
731 if (!gridName.empty()) ss << gridName <<
" ";
732 ss <<
"inside value < 0, got " << -tree.background();
742 template<
typename Gr
idOrTreeT>
744 compMax(GridOrTreeT& aTree, GridOrTreeT& bTree)
747 using TreeT =
typename Adapter::TreeType;
748 using ValueT =
typename TreeT::ValueType;
754 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op,
false);
758 template<
typename Gr
idOrTreeT>
760 compMin(GridOrTreeT& aTree, GridOrTreeT& bTree)
763 using TreeT =
typename Adapter::TreeType;
764 using ValueT =
typename TreeT::ValueType;
770 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op,
false);
774 template<
typename Gr
idOrTreeT>
776 compSum(GridOrTreeT& aTree, GridOrTreeT& bTree)
779 using TreeT =
typename Adapter::TreeType;
785 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op,
false);
789 template<
typename Gr
idOrTreeT>
791 compMul(GridOrTreeT& aTree, GridOrTreeT& bTree)
794 using TreeT =
typename Adapter::TreeType;
800 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op,
false);
804 template<
typename Gr
idOrTreeT>
806 compDiv(GridOrTreeT& aTree, GridOrTreeT& bTree)
809 using TreeT =
typename Adapter::TreeType;
815 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op,
false);
822 template<
typename TreeT>
830 void operator()(
const typename TreeT::ValueOnCIter& iter)
const
833 iter.getBoundingBox(bbox);
834 aTree->fill(bbox, *iter);
837 void operator()(
const typename TreeT::LeafCIter& leafIter)
const
840 for (
typename TreeT::LeafCIter::LeafNodeT::ValueOnCIter iter =
841 leafIter->cbeginValueOn(); iter; ++iter)
843 acc.
setValue(iter.getCoord(), *iter);
849 template<
typename Gr
idOrTreeT>
854 using TreeT =
typename Adapter::TreeType;
855 using ValueOnCIterT =
typename TreeT::ValueOnCIter;
858 Adapter::tree(aTree).topologyUnion(Adapter::tree(bTree));
863 ValueOnCIterT iter = bTree.cbeginValueOn();
864 iter.setMaxDepth(iter.getLeafDepth() - 1);
865 foreach(iter, op,
false);
868 foreach(Adapter::tree(bTree).cbeginLeaf(), op);
875 template<
typename Gr
idOrTreeT>
880 using TreeT =
typename Adapter::TreeType;
881 TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
882 composite::validateLevelSet(aTree,
"A");
883 composite::validateLevelSet(bTree,
"B");
890 template<
typename Gr
idOrTreeT>
895 using TreeT =
typename Adapter::TreeType;
896 TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
897 composite::validateLevelSet(aTree,
"A");
898 composite::validateLevelSet(bTree,
"B");
905 template<
typename Gr
idOrTreeT>
910 using TreeT =
typename Adapter::TreeType;
911 TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
912 composite::validateLevelSet(aTree,
"A");
913 composite::validateLevelSet(bTree,
"B");
921 template<
typename Gr
idOrTreeT>
922 inline typename GridOrTreeT::Ptr
926 using TreePtrT =
typename Adapter::TreeType::Ptr;
928 TreePtrT output = composite::doCSGCopy<composite::CSG_UNION>(
929 Adapter::tree(a), Adapter::tree(b));
931 return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
935 template<
typename Gr
idOrTreeT>
936 inline typename GridOrTreeT::Ptr
940 using TreePtrT =
typename Adapter::TreeType::Ptr;
942 TreePtrT output = composite::doCSGCopy<composite::CSG_INTERSECTION>(
943 Adapter::tree(a), Adapter::tree(b));
945 return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
949 template<
typename Gr
idOrTreeT>
950 inline typename GridOrTreeT::Ptr
954 using TreePtrT =
typename Adapter::TreeType::Ptr;
956 TreePtrT output = composite::doCSGCopy<composite::CSG_DIFFERENCE>(
957 Adapter::tree(a), Adapter::tree(b));
959 return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
985 template<
typename TreeT,
typename OpT = composite::CopyOp<TreeT> >
989 composite::doCompActiveLeafVoxels<TreeT, OpT>(srcTree, dstTree, op);
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Functions to efficiently merge grids.
Defined various multi-threaded utility functions for trees.
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:451
CombineArgs & setResult(const AValueType &val)
Set the output value.
Definition: Types.h:500
const AValueType & a() const
Get the A input value.
Definition: Types.h:490
const BValueType & b() const
Get the B input value.
Definition: Types.h:492
SharedPtr< Grid > Ptr
Definition: Grid.h:579
Tag dispatch class that distinguishes constructors that steal.
Definition: Types.h:568
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:248
Definition: NodeManager.h:890
void foreachTopDown(const NodeOp &op, bool threaded=true, size_t leafGrainSize=1, size_t nonLeafGrainSize=1)
Threaded method that applies a user-supplied functor to all the nodes in the tree.
Definition: NodeManager.h:976
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:250
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:127
Index32 Index
Definition: Types.h:54
openvdb::GridBase Grid
Definition: Utils.h:33
Definition: Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
This adapter allows code that is templated on a Tree type to accept either a Tree type or a Grid type...
Definition: Grid.h:1071
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:180