10#ifndef OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
11#define OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
24#include <tbb/blocked_range.h>
25#include <tbb/parallel_for.h>
26#include <tbb/parallel_reduce.h>
27#include <tbb/task_group.h>
41template<
typename Gr
idOrTreeT>
42void csgUnion(GridOrTreeT& a, GridOrTreeT& b,
bool prune =
true,
bool pruneCancelledTiles =
false);
47template<
typename Gr
idOrTreeT>
48void csgIntersection(GridOrTreeT& a, GridOrTreeT& b,
bool prune =
true,
bool pruneCancelledTiles =
false);
53template<
typename Gr
idOrTreeT>
54void csgDifference(GridOrTreeT& a, GridOrTreeT& b,
bool prune =
true,
bool pruneCancelledTiles =
false);
59template<
typename Gr
idOrTreeT>
60typename GridOrTreeT::Ptr
csgUnionCopy(
const GridOrTreeT& a,
const GridOrTreeT& b);
64template<
typename Gr
idOrTreeT>
69template<
typename Gr
idOrTreeT>
70typename GridOrTreeT::Ptr
csgDifferenceCopy(
const GridOrTreeT& a,
const GridOrTreeT& b);
74template<
typename Gr
idOrTreeT>
75void compMax(GridOrTreeT& a, GridOrTreeT& b);
78template<
typename Gr
idOrTreeT>
79void compMin(GridOrTreeT& a, GridOrTreeT& b);
82template<
typename Gr
idOrTreeT>
83void compSum(GridOrTreeT& a, GridOrTreeT& b);
86template<
typename Gr
idOrTreeT>
87void compMul(GridOrTreeT& a, GridOrTreeT& b);
90template<
typename Gr
idOrTreeT>
91void compDiv(GridOrTreeT& a, GridOrTreeT& b);
94template<
typename Gr
idOrTreeT>
95void compReplace(GridOrTreeT& a,
const GridOrTreeT& b);
104template<
typename T>
inline
105const typename std::enable_if<!VecTraits<T>::IsVec, T>::type&
106min(
const T& a,
const T& b) {
return std::min(a, b); }
108template<
typename T>
inline
109const typename std::enable_if<!VecTraits<T>::IsVec, T>::type&
110max(
const T& a,
const T& b) {
return std::max(a, b); }
114template<
typename T>
inline
115const typename std::enable_if<VecTraits<T>::IsVec, T>::type&
116min(
const T& a,
const T& b)
118 const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
119 return (aMag < bMag ? a : (bMag < aMag ? b : std::min(a, b)));
122template<
typename T>
inline
123const typename std::enable_if<VecTraits<T>::IsVec, T>::type&
124max(
const T& a,
const T& b)
126 const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
127 return (aMag < bMag ? b : (bMag < aMag ? a : std::max(a, b)));
131template<
typename T>
inline
132typename std::enable_if<!std::is_integral<T>::value, T>::type
133divide(
const T& a,
const T& b) {
return a / b; }
135template<
typename T>
inline
136typename std::enable_if<std::is_integral<T>::value, T>::type
140 if (b != zero)
return a / b;
141 if (a == zero)
return 0;
142 return (a > 0 ? std::numeric_limits<T>::max() : -std::numeric_limits<T>::max());
148inline bool divide(
bool a,
bool ) {
return a; }
153enum CSGOperation { CSG_UNION, CSG_INTERSECTION, CSG_DIFFERENCE };
155template<
typename TreeType, CSGOperation Operation>
156struct BuildPrimarySegment
158 using ValueType =
typename TreeType::ValueType;
159 using TreePtrType =
typename TreeType::Ptr;
160 using LeafNodeType =
typename TreeType::LeafNodeType;
161 using NodeMaskType =
typename LeafNodeType::NodeMaskType;
162 using RootNodeType =
typename TreeType::RootNodeType;
163 using NodeChainType =
typename RootNodeType::NodeChainType;
164 using InternalNodeType =
typename NodeChainType::template Get<1>;
166 BuildPrimarySegment(
const TreeType& lhs,
const TreeType& rhs)
167 : mSegment(new TreeType(lhs.background()))
173 void operator()()
const
175 std::vector<const LeafNodeType*> leafNodes;
178 std::vector<const InternalNodeType*> internalNodes;
179 mLhsTree->getNodes(internalNodes);
181 ProcessInternalNodes op(internalNodes, *mRhsTree, *mSegment, leafNodes);
182 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
185 ProcessLeafNodes op(leafNodes, *mRhsTree, *mSegment);
186 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
189 TreePtrType& segment() {
return mSegment; }
193 struct ProcessInternalNodes {
195 ProcessInternalNodes(std::vector<const InternalNodeType*>& lhsNodes,
196 const TreeType& rhsTree, TreeType& outputTree,
197 std::vector<const LeafNodeType*>& outputLeafNodes)
198 : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front())
200 , mLocalTree(mRhsTree->background())
201 , mOutputTree(&outputTree)
203 , mOutputLeafNodes(&outputLeafNodes)
207 ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
208 : mLhsNodes(other.mLhsNodes)
209 , mRhsTree(other.mRhsTree)
210 , mLocalTree(mRhsTree->background())
211 , mOutputTree(&mLocalTree)
213 , mOutputLeafNodes(&mLocalLeafNodes)
217 void join(ProcessInternalNodes& other)
219 mOutputTree->merge(*other.mOutputTree);
220 mOutputLeafNodes->insert(mOutputLeafNodes->end(),
221 other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
224 void operator()(
const tbb::blocked_range<size_t>& range)
226 tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
227 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
229 std::vector<const LeafNodeType*> tmpLeafNodes;
231 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
233 const InternalNodeType& lhsNode = *mLhsNodes[n];
234 const Coord& ijk = lhsNode.origin();
235 const InternalNodeType * rhsNode =
236 rhsAcc.template probeConstNode<InternalNodeType>(ijk);
239 lhsNode.getNodes(*mOutputLeafNodes);
241 if (Operation == CSG_INTERSECTION) {
242 if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
243 tmpLeafNodes.clear();
244 lhsNode.getNodes(tmpLeafNodes);
245 for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
246 outputAcc.addLeaf(
new LeafNodeType(*tmpLeafNodes[i]));
250 if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
251 tmpLeafNodes.clear();
252 lhsNode.getNodes(tmpLeafNodes);
253 for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
254 outputAcc.addLeaf(
new LeafNodeType(*tmpLeafNodes[i]));
262 InternalNodeType
const *
const *
const mLhsNodes;
263 TreeType
const *
const mRhsTree;
265 TreeType *
const mOutputTree;
267 std::vector<const LeafNodeType*> mLocalLeafNodes;
268 std::vector<const LeafNodeType*> *
const mOutputLeafNodes;
271 struct ProcessLeafNodes {
273 ProcessLeafNodes(std::vector<const LeafNodeType*>& lhsNodes,
274 const TreeType& rhsTree, TreeType& output)
275 : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front())
277 , mLocalTree(mRhsTree->background())
278 , mOutputTree(&output)
282 ProcessLeafNodes(ProcessLeafNodes& other, tbb::split)
283 : mLhsNodes(other.mLhsNodes)
284 , mRhsTree(other.mRhsTree)
285 , mLocalTree(mRhsTree->background())
286 , mOutputTree(&mLocalTree)
290 void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
292 void operator()(
const tbb::blocked_range<size_t>& range)
294 tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
295 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
297 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
299 const LeafNodeType& lhsNode = *mLhsNodes[n];
300 const Coord& ijk = lhsNode.origin();
302 const LeafNodeType* rhsNodePt = rhsAcc.probeConstLeaf(ijk);
306 LeafNodeType* outputNode = outputAcc.touchLeaf(ijk);
307 ValueType * outputData = outputNode->buffer().data();
308 NodeMaskType& outputMask = outputNode->getValueMask();
310 const ValueType * lhsData = lhsNode.buffer().data();
311 const NodeMaskType& lhsMask = lhsNode.getValueMask();
313 const ValueType * rhsData = rhsNodePt->buffer().data();
314 const NodeMaskType& rhsMask = rhsNodePt->getValueMask();
316 if (Operation == CSG_INTERSECTION) {
317 for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
318 const bool fromRhs = lhsData[pos] < rhsData[pos];
319 outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
320 outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
322 }
else if (Operation == CSG_DIFFERENCE){
323 for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
324 const ValueType rhsVal = math::negative(rhsData[pos]);
325 const bool fromRhs = lhsData[pos] < rhsVal;
326 outputData[pos] = fromRhs ? rhsVal : lhsData[pos];
327 outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
330 for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
331 const bool fromRhs = lhsData[pos] > rhsData[pos];
332 outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
333 outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
338 if (Operation == CSG_INTERSECTION) {
339 if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
340 outputAcc.addLeaf(
new LeafNodeType(lhsNode));
343 if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
344 outputAcc.addLeaf(
new LeafNodeType(lhsNode));
351 LeafNodeType
const *
const *
const mLhsNodes;
352 TreeType
const *
const mRhsTree;
354 TreeType *
const mOutputTree;
357 TreePtrType mSegment;
358 TreeType
const *
const mLhsTree;
359 TreeType
const *
const mRhsTree;
363template<
typename TreeType, CSGOperation Operation>
364struct BuildSecondarySegment
366 using ValueType =
typename TreeType::ValueType;
367 using TreePtrType =
typename TreeType::Ptr;
368 using LeafNodeType =
typename TreeType::LeafNodeType;
369 using NodeMaskType =
typename LeafNodeType::NodeMaskType;
370 using RootNodeType =
typename TreeType::RootNodeType;
371 using NodeChainType =
typename RootNodeType::NodeChainType;
372 using InternalNodeType =
typename NodeChainType::template Get<1>;
374 BuildSecondarySegment(
const TreeType& lhs,
const TreeType& rhs)
375 : mSegment(new TreeType(lhs.background()))
381 void operator()()
const
383 std::vector<const LeafNodeType*> leafNodes;
386 std::vector<const InternalNodeType*> internalNodes;
387 mRhsTree->getNodes(internalNodes);
389 ProcessInternalNodes op(internalNodes, *mLhsTree, *mSegment, leafNodes);
390 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
393 ProcessLeafNodes op(leafNodes, *mLhsTree, *mSegment);
394 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
397 TreePtrType& segment() {
return mSegment; }
401 struct ProcessInternalNodes {
403 ProcessInternalNodes(std::vector<const InternalNodeType*>& rhsNodes,
404 const TreeType& lhsTree, TreeType& outputTree,
405 std::vector<const LeafNodeType*>& outputLeafNodes)
406 : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front())
408 , mLocalTree(mLhsTree->background())
409 , mOutputTree(&outputTree)
411 , mOutputLeafNodes(&outputLeafNodes)
415 ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
416 : mRhsNodes(other.mRhsNodes)
417 , mLhsTree(other.mLhsTree)
418 , mLocalTree(mLhsTree->background())
419 , mOutputTree(&mLocalTree)
421 , mOutputLeafNodes(&mLocalLeafNodes)
425 void join(ProcessInternalNodes& other)
427 mOutputTree->merge(*other.mOutputTree);
428 mOutputLeafNodes->insert(mOutputLeafNodes->end(),
429 other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
432 void operator()(
const tbb::blocked_range<size_t>& range)
434 tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
435 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
437 std::vector<const LeafNodeType*> tmpLeafNodes;
439 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
441 const InternalNodeType& rhsNode = *mRhsNodes[n];
442 const Coord& ijk = rhsNode.origin();
443 const InternalNodeType * lhsNode =
444 lhsAcc.template probeConstNode<InternalNodeType>(ijk);
447 rhsNode.getNodes(*mOutputLeafNodes);
449 if (Operation == CSG_INTERSECTION) {
450 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
451 tmpLeafNodes.clear();
452 rhsNode.getNodes(tmpLeafNodes);
453 for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
454 outputAcc.addLeaf(
new LeafNodeType(*tmpLeafNodes[i]));
457 }
else if (Operation == CSG_DIFFERENCE) {
458 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
459 tmpLeafNodes.clear();
460 rhsNode.getNodes(tmpLeafNodes);
461 for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
462 LeafNodeType* outputNode =
new LeafNodeType(*tmpLeafNodes[i]);
463 outputNode->negate();
464 outputAcc.addLeaf(outputNode);
468 if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
469 tmpLeafNodes.clear();
470 rhsNode.getNodes(tmpLeafNodes);
471 for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
472 outputAcc.addLeaf(
new LeafNodeType(*tmpLeafNodes[i]));
480 InternalNodeType
const *
const *
const mRhsNodes;
481 TreeType
const *
const mLhsTree;
483 TreeType *
const mOutputTree;
485 std::vector<const LeafNodeType*> mLocalLeafNodes;
486 std::vector<const LeafNodeType*> *
const mOutputLeafNodes;
489 struct ProcessLeafNodes {
491 ProcessLeafNodes(std::vector<const LeafNodeType*>& rhsNodes,
492 const TreeType& lhsTree, TreeType& output)
493 : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front())
495 , mLocalTree(mLhsTree->background())
496 , mOutputTree(&output)
500 ProcessLeafNodes(ProcessLeafNodes& rhs, tbb::split)
501 : mRhsNodes(rhs.mRhsNodes)
502 , mLhsTree(rhs.mLhsTree)
503 , mLocalTree(mLhsTree->background())
504 , mOutputTree(&mLocalTree)
508 void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
510 void operator()(
const tbb::blocked_range<size_t>& range)
512 tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
513 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
515 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
517 const LeafNodeType& rhsNode = *mRhsNodes[n];
518 const Coord& ijk = rhsNode.origin();
520 const LeafNodeType* lhsNode = lhsAcc.probeConstLeaf(ijk);
523 if (Operation == CSG_INTERSECTION) {
524 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
525 outputAcc.addLeaf(
new LeafNodeType(rhsNode));
527 }
else if (Operation == CSG_DIFFERENCE) {
528 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
529 LeafNodeType* outputNode =
new LeafNodeType(rhsNode);
530 outputNode->negate();
531 outputAcc.addLeaf(outputNode);
534 if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
535 outputAcc.addLeaf(
new LeafNodeType(rhsNode));
542 LeafNodeType
const *
const *
const mRhsNodes;
543 TreeType
const *
const mLhsTree;
545 TreeType *
const mOutputTree;
548 TreePtrType mSegment;
549 TreeType
const *
const mLhsTree;
550 TreeType
const *
const mRhsTree;
554template<CSGOperation Operation,
typename TreeType>
555typename TreeType::Ptr
556doCSGCopy(
const TreeType& lhs,
const TreeType& rhs)
558 BuildPrimarySegment<TreeType, Operation> primary(lhs, rhs);
559 BuildSecondarySegment<TreeType, Operation> secondary(lhs, rhs);
562 tbb::task_group tasks;
564 tasks.run(secondary);
567 primary.segment()->merge(*secondary.segment());
570 tools::signedFloodFill(*primary.segment(),
true, 1, 1);
572 return primary.segment();
579template<
typename TreeType>
580struct GridOrTreeConstructor
582 using TreeTypePtr =
typename TreeType::Ptr;
583 static TreeTypePtr construct(
const TreeType&, TreeTypePtr& tree) {
return tree; }
587template<
typename TreeType>
588struct GridOrTreeConstructor<
Grid<TreeType> >
591 using GridTypePtr =
typename Grid<TreeType>::Ptr;
592 using TreeTypePtr =
typename TreeType::Ptr;
594 static GridTypePtr construct(
const GridType& grid, TreeTypePtr& tree) {
595 GridTypePtr maskGrid(GridType::create(tree));
596 maskGrid->setTransform(grid.transform().copy());
597 maskGrid->insertMeta(grid);
606template <
typename LeafT>
607using LeafPairList = std::vector<std::pair<LeafT*, LeafT*>>;
613template <
typename TreeT>
614void transferLeafNodes(TreeT &srcTree, TreeT &dstTree,
615 LeafPairList<typename TreeT::LeafNodeType> &overlapping)
617 using LeafT =
typename TreeT::LeafNodeType;
618 tree::ValueAccessor<TreeT> acc(dstTree);
619 std::vector<LeafT*> srcLeafNodes;
620 srcLeafNodes.reserve(srcTree.leafCount());
621 srcTree.stealNodes(srcLeafNodes);
623 for (LeafT *srcLeaf : srcLeafNodes) {
624 LeafT *dstLeaf = acc.probeLeaf(srcLeaf->origin());
626 overlapping.emplace_back(dstLeaf, srcLeaf);
628 acc.addLeaf(srcLeaf);
634template <
typename TreeT,
typename OpT>
636typename 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
641doCompActiveLeafVoxels(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);
660template <
typename TreeT,
typename OpT>
662typename std::enable_if<
663 std::is_same<typename TreeT::BuildType, ValueMask>::value &&
664 std::is_same<typename TreeT::ValueType, bool>::value>::type
665doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT)
667 using LeafT =
typename TreeT::LeafNodeType;
668 LeafPairList<LeafT> overlapping;
669 transferLeafNodes(srcTree, dstTree, overlapping);
671 using RangeT = tbb::blocked_range<size_t>;
672 tbb::parallel_for(RangeT(0, overlapping.size()), [&overlapping](
const RangeT& r) {
673 for (auto i = r.begin(); i != r.end(); ++i) {
674 overlapping[i].first->getValueMask() |= overlapping[i].second->getValueMask();
675 delete overlapping[i].second;
681template <
typename TreeT,
typename OpT>
683typename std::enable_if<
684 std::is_same<typename TreeT::ValueType, bool>::value &&
685 !std::is_same<typename TreeT::BuildType, ValueMask>::value>::type
686doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
688 using LeafT =
typename TreeT::LeafNodeType;
689 LeafPairList<LeafT> overlapping;
690 transferLeafNodes(srcTree, dstTree, overlapping);
692 using RangeT = tbb::blocked_range<size_t>;
693 using WordT =
typename LeafT::Buffer::WordType;
694 tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](
const RangeT& r) {
695 for (auto i = r.begin(); i != r.end(); ++i) {
696 LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
697 WordT *w1 = dstLeaf->buffer().data();
698 const WordT *w2 = srcLeaf->buffer().data();
699 const WordT *w3 = &(srcLeaf->getValueMask().template getWord<WordT>(0));
700 for (Index32 n = LeafT::Buffer::WORD_COUNT; n--; ++w1) {
701 WordT tmp = *w1, state = *w3++;
703 *w1 = (state & tmp) | (~state & *w1);
705 dstLeaf->getValueMask() |= srcLeaf->getValueMask();
712template <
typename TreeT>
715 using ValueT =
typename TreeT::ValueType;
717 void operator()(ValueT& dst,
const ValueT& src)
const { dst = src; }
720template <
typename TreeT>
721void validateLevelSet(
const TreeT& tree,
const std::string& gridName = std::string(
""))
723 using ValueT =
typename TreeT::ValueType;
724 const ValueT zero = zeroVal<ValueT>();
725 if (!(tree.background() > zero)) {
726 std::stringstream ss;
727 ss <<
"expected grid ";
728 if (!gridName.empty()) ss << gridName <<
" ";
729 ss <<
"outside value > 0, got " << tree.background();
732 if (!(-tree.background() < zero)) {
733 std::stringstream ss;
734 ss <<
"expected grid ";
735 if (!gridName.empty()) ss << gridName <<
" ";
736 ss <<
"inside value < 0, got " << -tree.background();
746template<
typename Gr
idOrTreeT>
748compMax(GridOrTreeT& aTree, GridOrTreeT& bTree)
751 using TreeT =
typename Adapter::TreeType;
752 using ValueT =
typename TreeT::ValueType;
755 args.
setResult(composite::max(args.
a(), args.
b()));
758 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op,
false);
762template<
typename Gr
idOrTreeT>
764compMin(GridOrTreeT& aTree, GridOrTreeT& bTree)
767 using TreeT =
typename Adapter::TreeType;
768 using ValueT =
typename TreeT::ValueType;
771 args.
setResult(composite::min(args.
a(), args.
b()));
774 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op,
false);
778template<
typename Gr
idOrTreeT>
780compSum(GridOrTreeT& aTree, GridOrTreeT& bTree)
783 using TreeT =
typename Adapter::TreeType;
789 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op,
false);
793template<
typename Gr
idOrTreeT>
795compMul(GridOrTreeT& aTree, GridOrTreeT& bTree)
798 using TreeT =
typename Adapter::TreeType;
804 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op,
false);
808template<
typename Gr
idOrTreeT>
810compDiv(GridOrTreeT& aTree, GridOrTreeT& bTree)
813 using TreeT =
typename Adapter::TreeType;
816 args.
setResult(composite::divide(args.
a(), args.
b()));
819 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op,
false);
826template<
typename TreeT>
834 void operator()(
const typename TreeT::ValueOnCIter& iter)
const
837 iter.getBoundingBox(bbox);
838 aTree->fill(bbox, *iter);
841 void operator()(
const typename TreeT::LeafCIter& leafIter)
const
844 for (
typename TreeT::LeafCIter::LeafNodeT::ValueOnCIter iter =
845 leafIter->cbeginValueOn(); iter; ++iter)
847 acc.
setValue(iter.getCoord(), *iter);
853template<
typename Gr
idOrTreeT>
858 using TreeT =
typename Adapter::TreeType;
859 using ValueOnCIterT =
typename TreeT::ValueOnCIter;
862 Adapter::tree(aTree).topologyUnion(Adapter::tree(bTree));
867 ValueOnCIterT iter = bTree.cbeginValueOn();
868 iter.setMaxDepth(iter.getLeafDepth() - 1);
869 foreach(iter, op,
false);
872 foreach(Adapter::tree(bTree).cbeginLeaf(), op);
879template<
typename Gr
idOrTreeT>
881csgUnion(GridOrTreeT& a, GridOrTreeT& b,
bool prune,
bool pruneCancelledTiles)
884 using TreeT =
typename Adapter::TreeType;
885 TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
886 composite::validateLevelSet(aTree,
"A");
887 composite::validateLevelSet(bTree,
"B");
892 if (
prune) tools::pruneLevelSet(aTree);
895template<
typename Gr
idOrTreeT>
900 using TreeT =
typename Adapter::TreeType;
901 TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
902 composite::validateLevelSet(aTree,
"A");
903 composite::validateLevelSet(bTree,
"B");
908 if (
prune) tools::pruneLevelSet(aTree);
911template<
typename Gr
idOrTreeT>
913csgDifference(GridOrTreeT& a, GridOrTreeT& b,
bool prune,
bool pruneCancelledTiles)
916 using TreeT =
typename Adapter::TreeType;
917 TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
918 composite::validateLevelSet(aTree,
"A");
919 composite::validateLevelSet(bTree,
"B");
924 if (
prune) tools::pruneLevelSet(aTree);
928template<
typename Gr
idOrTreeT>
929typename GridOrTreeT::Ptr
933 using TreePtrT =
typename Adapter::TreeType::Ptr;
935 TreePtrT output = composite::doCSGCopy<composite::CSG_UNION>(
936 Adapter::tree(a), Adapter::tree(b));
938 return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
942template<
typename Gr
idOrTreeT>
943typename GridOrTreeT::Ptr
947 using TreePtrT =
typename Adapter::TreeType::Ptr;
949 TreePtrT output = composite::doCSGCopy<composite::CSG_INTERSECTION>(
950 Adapter::tree(a), Adapter::tree(b));
952 return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
956template<
typename Gr
idOrTreeT>
957typename GridOrTreeT::Ptr
961 using TreePtrT =
typename Adapter::TreeType::Ptr;
963 TreePtrT output = composite::doCSGCopy<composite::CSG_DIFFERENCE>(
964 Adapter::tree(a), Adapter::tree(b));
966 return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
992template<
typename TreeT,
typename OpT = composite::CopyOp<TreeT> >
996 composite::doCompActiveLeafVoxels<TreeT, OpT>(srcTree, dstTree, op);
1005#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1007#ifdef OPENVDB_INSTANTIATE_COMPOSITE
1011#define _FUNCTION(TreeT) \
1012 void csgUnion(TreeT&, TreeT&, bool, bool)
1016#define _FUNCTION(TreeT) \
1017 void csgUnion(Grid<TreeT>&, Grid<TreeT>&, bool, bool)
1021#define _FUNCTION(TreeT) \
1022 void csgIntersection(TreeT&, TreeT&, bool, bool)
1026#define _FUNCTION(TreeT) \
1027 void csgIntersection(Grid<TreeT>&, Grid<TreeT>&, bool, bool)
1031#define _FUNCTION(TreeT) \
1032 void csgDifference(TreeT&, TreeT&, bool, bool)
1036#define _FUNCTION(TreeT) \
1037 void csgDifference(Grid<TreeT>&, Grid<TreeT>&, bool, bool)
1041#define _FUNCTION(TreeT) \
1042 TreeT::Ptr csgUnionCopy(const TreeT&, const TreeT&)
1046#define _FUNCTION(TreeT) \
1047 Grid<TreeT>::Ptr csgUnionCopy(const Grid<TreeT>&, const Grid<TreeT>&)
1051#define _FUNCTION(TreeT) \
1052 TreeT::Ptr csgIntersectionCopy(const TreeT&, const TreeT&)
1056#define _FUNCTION(TreeT) \
1057 Grid<TreeT>::Ptr csgIntersectionCopy(const Grid<TreeT>&, const Grid<TreeT>&)
1061#define _FUNCTION(TreeT) \
1062 TreeT::Ptr csgDifferenceCopy(const TreeT&, const TreeT&)
1066#define _FUNCTION(TreeT) \
1067 Grid<TreeT>::Ptr csgDifferenceCopy(const Grid<TreeT>&, const Grid<TreeT>&)
1071#define _FUNCTION(TreeT) \
1072 void compMax(TreeT&, TreeT&)
1076#define _FUNCTION(TreeT) \
1077 void compMax(Grid<TreeT>&, Grid<TreeT>&)
1081#define _FUNCTION(TreeT) \
1082 void compMin(TreeT&, TreeT&)
1086#define _FUNCTION(TreeT) \
1087 void compMin(Grid<TreeT>&, Grid<TreeT>&)
1091#define _FUNCTION(TreeT) \
1092 void compSum(TreeT&, TreeT&)
1096#define _FUNCTION(TreeT) \
1097 void compSum(Grid<TreeT>&, Grid<TreeT>&)
1101#define _FUNCTION(TreeT) \
1102 void compDiv(TreeT&, TreeT&)
1106#define _FUNCTION(TreeT) \
1107 void compDiv(Grid<TreeT>&, Grid<TreeT>&)
1111#define _FUNCTION(TreeT) \
1112 void compReplace(TreeT&, const TreeT&)
1116#define _FUNCTION(TreeT) \
1117 void compReplace(Grid<TreeT>&, const Grid<TreeT>&)
ValueT value
Definition: GridBuilder.h:1290
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:530
const BValueType & b() const
Get the B input value.
Definition: Types.h:571
const AValueType & a() const
Get the A input value.
Definition: Types.h:569
CombineArgs & setResult(const AValueType &val)
Set the output value.
Definition: Types.h:579
Tag dispatch class that distinguishes constructors that steal.
Definition: Types.h:648
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:249
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
Definition: ValueAccessor.h:191
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:266
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:243
openvdb::GridBase Grid
Definition: Utils.h:34
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:1060
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:212
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition: version.h.in:157
#define OPENVDB_VOLUME_TREE_INSTANTIATE(Function)
Definition: version.h.in:160