46 #ifndef OPENVDB_TOOLS_MORPHOLOGY_HAS_BEEN_INCLUDED 47 #define OPENVDB_TOOLS_MORPHOLOGY_HAS_BEEN_INCLUDED 57 #include <tbb/tbb_thread.h> 58 #include <tbb/task_scheduler_init.h> 59 #include <tbb/enumerable_thread_specific.h> 60 #include <tbb/parallel_for.h> 61 #include <type_traits> 211 template<
typename Gr
idOrTree>
214 const typename GridOrTree::ValueType& value,
215 const typename GridOrTree::ValueType& tolerance = zeroVal<typename GridOrTree::ValueType>()
221 template<
typename Gr
idOrTree>
224 const typename GridOrTree::ValueType& value,
225 const typename GridOrTree::ValueType& tolerance = zeroVal<typename GridOrTree::ValueType>()
243 template<
typename TreeType>
250 mOwnsManager(true), mManager(new
ManagerType(tree)), mAcc(tree), mSteps(1) {}
252 mOwnsManager(false), mManager(mgr), mAcc(mgr->tree()), mSteps(1) {}
256 void dilateVoxels6();
258 void dilateVoxels18();
260 void dilateVoxels26();
288 static const int LEAF_DIM = LeafType::DIM;
289 static const int LEAF_LOG2DIM = LeafType::LOG2DIM;
297 inline void clear() { leaf =
nullptr; init =
true; }
298 template<
int DX,
int DY,
int DZ>
303 Coord orig = xyz.
offsetBy(DX*LEAF_DIM, DY*LEAF_DIM, DZ*LEAF_DIM);
307 #ifndef _MSC_VER // Visual C++ doesn't guarantee thread-safe initialization of local statics 310 const int N = (LEAF_DIM - 1)*(DY + DX*LEAF_DIM);
311 if (leaf) leaf->getValueMask().template getWord<Word>(indx-N) |= mask;
314 template<
int DX,
int DY,
int DZ>
319 Coord orig = xyz.
offsetBy(DX*LEAF_DIM, DY*LEAF_DIM, DZ*LEAF_DIM);
321 isOn = leaf ? false : acc.
isValueOn(orig);
323 #ifndef _MSC_VER // Visual C++ doesn't guarantee thread-safe initialization of local statics 326 const int N = (LEAF_DIM -1 )*(DY + DX*LEAF_DIM);
327 return leaf ? leaf->getValueMask().template getWord<Word>(indx-N)
336 onTile.setValuesOn();
341 inline void clear() {
for (
size_t i = 0; i < size; ++i) leafs[i] =
nullptr; }
346 leafs[n]->getValueMask().template getWord<Word>(indx) |= mask;
348 template<
int DX,
int DY,
int DZ>
352 const Coord xyz = origin->
offsetBy(DX*LEAF_DIM, DY*LEAF_DIM, DZ*LEAF_DIM);
353 leafs[n] = acc.probeLeaf(xyz);
354 if (!leafs[n]) leafs[n] = acc.isValueOn(xyz) ? &onTile : acc.touchLeaf(xyz);
356 this->scatter(n, indx - (LEAF_DIM - 1)*(DY + DX*LEAF_DIM));
361 return leafs[n]->getValueMask().template getWord<Word>(indx);
363 template<
int DX,
int DY,
int DZ>
367 const Coord xyz = origin->
offsetBy(DX*LEAF_DIM, DY*LEAF_DIM, DZ*LEAF_DIM);
368 leafs[n] = acc.probeLeaf(xyz);
369 if (!leafs[n]) leafs[n] = acc.isValueOn(xyz) ? &onTile : &offTile;
371 return this->gather(n, indx - (LEAF_DIM -1 )*(DY + DX*LEAF_DIM));
374 void scatterFacesXY(
int x,
int y,
int i1,
int n,
int i2);
377 void scatterEdgesXY(
int x,
int y,
int i1,
int n,
int i2);
379 Word gatherFacesXY(
int x,
int y,
int i1,
int n,
int i2);
381 Word gatherEdgesXY(
int x,
int y,
int i1,
int n,
int i2);
392 typedef tbb::blocked_range<size_t>
RangeT;
394 : mTask(0), mSavedMasks(masks) , mManager(manager) {}
397 void erode6(
const RangeT&)
const;
398 void erode18(
const RangeT&)
const;
399 void erode26(
const RangeT&)
const;
401 using FuncT =
typename std::function<void (
ErodeVoxelsOp*,
const RangeT&)>;
403 std::vector<MaskType>& mSavedMasks;
409 : mMasks(masks) , mManager(manager), mSaveMasks(true) {}
411 void save() { mSaveMasks =
true; tbb::parallel_for(mManager.
getRange(), *
this); }
412 void update() { mSaveMasks =
false; tbb::parallel_for(mManager.
getRange(), *
this); }
413 void operator()(
const tbb::blocked_range<size_t>& range)
const 416 for (
size_t i = range.begin(); i < range.end(); ++i) {
417 mMasks[i] = mManager.
leaf(i).getValueMask();
420 for (
size_t i = range.begin(); i < range.end(); ++i) {
421 mManager.
leaf(i).setValueMask(mMasks[i]);
426 std::vector<MaskType>& mMasks;
433 : mMasks(masks), mManager(manager) {}
436 for (
size_t i=r.begin(); i<r.end(); ++i) mManager.
leaf(i).setValueMask(mMasks[i]);
443 : mMasks(masks), mManager(manager) {}
446 for (
size_t i=r.begin(); i<r.end(); ++i) mMasks[i]=mManager.
leaf(i).getValueMask();
455 template<
typename TreeType>
459 for (
int i=0; i<iterations; ++i) {
462 this->dilateVoxels18();
465 this->dilateVoxels26();
469 this->dilateVoxels6();
475 template<
typename TreeType>
480 const int leafCount = static_cast<int>(mManager->leafCount());
483 std::vector<MaskType> savedMasks(leafCount);
484 this->copyMasks(savedMasks, *mManager);
486 for (
int leafIdx = 0; leafIdx < leafCount; ++leafIdx) {
487 const MaskType& oldMask = savedMasks[leafIdx];
488 cache[0] = &mManager->leaf(leafIdx);
490 for (
int x = 0; x < LEAF_DIM; ++x ) {
491 for (
int y = 0, n = (x << LEAF_LOG2DIM); y < LEAF_DIM; ++y, ++n) {
493 if (
const Word w = oldMask.template getWord<Word>(n)) {
496 cache.mask =
Word(w | (w>>1) | (w<<1)); cache.scatter(0, n);
499 if ( (cache.mask =
Word(w<<(LEAF_DIM-1))) ) {
500 cache.template scatter< 0, 0,-1>(1, n);
503 if ( (cache.mask =
Word(w>>(LEAF_DIM-1))) ) {
504 cache.template scatter< 0, 0, 1>(2, n);
507 cache.mask = w; cache.scatterFacesXY(x, y, 0, n, 3);
514 mManager->rebuildLeafArray();
518 template<
typename TreeType>
523 const int leafCount = static_cast<int>(mManager->leafCount());
526 std::vector<MaskType> savedMasks(leafCount);
527 this->copyMasks(savedMasks, *mManager);
529 Coord orig_mz, orig_pz;
530 for (
int leafIdx = 0; leafIdx < leafCount; ++leafIdx) {
531 const MaskType& oldMask = savedMasks[leafIdx];
532 cache[0] = &mManager->leaf(leafIdx);
533 orig_mz = cache[0]->origin().
offsetBy(0, 0, -LEAF_DIM);
534 orig_pz = cache[0]->origin().
offsetBy(0, 0, LEAF_DIM);
535 for (
int x = 0; x < LEAF_DIM; ++x ) {
536 for (
int y = 0, n = (x << LEAF_LOG2DIM); y < LEAF_DIM; ++y, ++n) {
537 if (
const Word w = oldMask.template getWord<Word>(n)) {
539 cache.mask =
Word(w | (w>>1) | (w<<1));
540 cache.setOrigin(cache[0]->origin());
542 cache.scatterFacesXY(x, y, 0, n, 3);
544 cache.scatterEdgesXY(x, y, 0, n, 3);
546 if ( (cache.mask =
Word(w<<(LEAF_DIM-1))) ) {
547 cache.setOrigin(cache[0]->origin());
548 cache.template scatter< 0, 0,-1>(1, n);
549 cache.setOrigin(orig_mz);
550 cache.scatterFacesXY(x, y, 1, n, 11);
552 if ( (cache.mask =
Word(w>>(LEAF_DIM-1))) ) {
553 cache.setOrigin(cache[0]->origin());
554 cache.template scatter< 0, 0, 1>(2, n);
555 cache.setOrigin(orig_pz);
556 cache.scatterFacesXY(x, y, 2, n, 15);
564 mManager->rebuildLeafArray();
568 template<
typename TreeType>
572 const int leafCount = static_cast<int>(mManager->leafCount());
575 std::vector<MaskType> savedMasks(leafCount);
576 this->copyMasks(savedMasks, *mManager);
578 Coord orig_mz, orig_pz;
579 for (
int leafIdx = 0; leafIdx < leafCount; ++leafIdx) {
580 const MaskType& oldMask = savedMasks[leafIdx];
581 cache[0] = &mManager->leaf(leafIdx);
582 orig_mz = cache[0]->origin().
offsetBy(0, 0, -LEAF_DIM);
583 orig_pz = cache[0]->origin().
offsetBy(0, 0, LEAF_DIM);
584 for (
int x = 0; x < LEAF_DIM; ++x ) {
585 for (
int y = 0, n = (x << LEAF_LOG2DIM); y < LEAF_DIM; ++y, ++n) {
586 if (
const Word w = oldMask.template getWord<Word>(n)) {
588 cache.mask =
Word(w | (w>>1) | (w<<1));
589 cache.setOrigin(cache[0]->origin());
591 cache.scatterFacesXY(x, y, 0, n, 3);
592 cache.scatterEdgesXY(x, y, 0, n, 3);
594 if ( (cache.mask =
Word(w<<(LEAF_DIM-1))) ) {
595 cache.setOrigin(cache[0]->origin());
596 cache.template scatter< 0, 0,-1>(1, n);
597 cache.setOrigin(orig_mz);
598 cache.scatterFacesXY(x, y, 1, n, 11);
599 cache.scatterEdgesXY(x, y, 1, n, 11);
601 if ( (cache.mask =
Word(w>>(LEAF_DIM-1))) ) {
602 cache.setOrigin(cache[0]->origin());
603 cache.template scatter< 0, 0, 1>(2, n);
604 cache.setOrigin(orig_pz);
605 cache.scatterFacesXY(x, y, 2, n, 19);
606 cache.scatterEdgesXY(x, y, 2, n, 19);
614 mManager->rebuildLeafArray();
618 template<
typename TreeType>
624 this->scatter(i1, n-LEAF_DIM);
626 this->
template scatter<-1, 0, 0>(i2, n);
629 if (x < LEAF_DIM-1) {
630 this->scatter(i1, n+LEAF_DIM);
632 this->
template scatter< 1, 0, 0>(i2+1, n);
636 this->scatter(i1, n-1);
638 this->
template scatter< 0,-1, 0>(i2+2, n);
641 if (y < LEAF_DIM-1) {
642 this->scatter(i1, n+1);
644 this->
template scatter< 0, 1, 0>(i2+3, n);
649 template<
typename TreeType>
655 this->scatter(i1, n-LEAF_DIM-1);
657 this->
template scatter< 0,-1, 0>(i2+2, n-LEAF_DIM);
659 if (y < LEAF_DIM-1) {
660 this->scatter(i1, n-LEAF_DIM+1);
662 this->
template scatter< 0, 1, 0>(i2+3, n-LEAF_DIM);
665 if (y < LEAF_DIM-1) {
666 this->
template scatter<-1, 0, 0>(i2 , n+1);
668 this->
template scatter<-1, 1, 0>(i2+7, n );
671 this->
template scatter<-1, 0, 0>(i2 , n-1);
673 this->
template scatter<-1,-1, 0>(i2+4, n );
676 if (x < LEAF_DIM-1) {
678 this->scatter(i1, n+LEAF_DIM-1);
680 this->
template scatter< 0,-1, 0>(i2+2, n+LEAF_DIM);
682 if (y < LEAF_DIM-1) {
683 this->scatter(i1, n+LEAF_DIM+1);
685 this->
template scatter< 0, 1, 0>(i2+3, n+LEAF_DIM);
689 this->
template scatter< 1, 0, 0>(i2+1, n-1);
691 this->
template scatter< 1,-1, 0>(i2+6, n );
693 if (y < LEAF_DIM-1) {
694 this->
template scatter< 1, 0, 0>(i2+1, n+1);
696 this->
template scatter< 1, 1, 0>(i2+5, n );
702 template<
typename TreeType>
706 namespace ph = std::placeholders;
709 mTask = std::bind(&ErodeVoxelsOp::erode18, ph::_1, ph::_2);
712 mTask = std::bind(&ErodeVoxelsOp::erode26, ph::_1, ph::_2);
716 mTask = std::bind(&ErodeVoxelsOp::erode6, ph::_1, ph::_2);
718 tbb::parallel_for(mManager.getRange(), *
this);
722 template<
typename TreeType>
727 Word w = x>0 ? this->gather(i1,n-LEAF_DIM) : this->
template gather<-1,0,0>(i2, n);
730 w =
Word(w & (x<LEAF_DIM-1?this->gather(i1,n+LEAF_DIM):this->
template gather<1,0,0>(i2+1,n)));
733 w =
Word(w & (y>0 ? this->gather(i1, n-1) : this->
template gather<0,-1,0>(i2+2, n)));
736 w =
Word(w & (y<LEAF_DIM-1 ? this->gather(i1, n+1) : this->
template gather<0,1,0>(i2+3, n)));
742 template<
typename TreeType>
749 w &= y > 0 ? this->gather(i1, n-LEAF_DIM-1) :
750 this->
template gather< 0,-1, 0>(i2+2, n-LEAF_DIM);
751 w &= y < LEAF_DIM-1 ? this->gather(i1, n-LEAF_DIM+1) :
752 this->
template gather< 0, 1, 0>(i2+3, n-LEAF_DIM);
754 w &= y < LEAF_DIM-1 ? this->
template gather<-1, 0, 0>(i2 , n+1):
755 this->
template gather<-1, 1, 0>(i2+7, n );
756 w &= y > 0 ? this->
template gather<-1, 0, 0>(i2 , n-1):
757 this->
template gather<-1,-1, 0>(i2+4, n );
759 if (x < LEAF_DIM-1) {
760 w &= y > 0 ? this->gather(i1, n+LEAF_DIM-1) :
761 this->
template gather< 0,-1, 0>(i2+2, n+LEAF_DIM);
762 w &= y < LEAF_DIM-1 ? this->gather(i1, n+LEAF_DIM+1) :
763 this->
template gather< 0, 1, 0>(i2+3, n+LEAF_DIM);
765 w &= y > 0 ? this->
template gather< 1, 0, 0>(i2+1, n-1):
766 this->
template gather< 1,-1, 0>(i2+6, n );
767 w &= y < LEAF_DIM-1 ? this->
template gather< 1, 0, 0>(i2+1, n+1):
768 this->
template gather< 1, 1, 0>(i2+5, n );
775 template <
typename TreeType>
780 for (
size_t leafIdx = range.begin(); leafIdx < range.end(); ++leafIdx) {
781 cache[0] = &mManager.leaf(leafIdx);
782 if (cache[0]->isEmpty())
continue;
784 MaskType& newMask = mSavedMasks[leafIdx];
785 for (
int x = 0; x < LEAF_DIM; ++x ) {
786 for (
int y = 0, n = (x << LEAF_LOG2DIM); y < LEAF_DIM; ++y, ++n) {
788 if (
Word& w = newMask.template getWord<Word>(n)) {
792 (
Word(w<<1 | (cache.template gather<0,0,-1>(1, n)>>(LEAF_DIM-1))) &
793 Word(w>>1 | (cache.template gather<0,0, 1>(2, n)<<(LEAF_DIM-1)))));
795 w =
Word(w & cache.gatherFacesXY(x, y, 0, n, 3));
804 template <
typename TreeType>
812 template <
typename TreeType>
820 template<
typename TreeType>
825 const size_t leafCount = mManager->leafCount();
828 std::vector<MaskType> savedMasks(leafCount);
829 this->copyMasks(savedMasks, *mManager);
833 for (
int i = 0; i < mSteps; ++i) {
845 template<
typename TreeType>
849 if (iterations > 0 ) {
855 template<
typename TreeType>
859 if (iterations > 0 ) {
865 template<
typename TreeType>
869 if (iterations > 0 ) {
875 template<
typename TreeType>
879 if (iterations > 0 ) {
889 namespace activation {
891 template<
typename TreeType>
895 typedef typename TreeType::ValueType
ValueT;
903 void operator()(
const typename TreeType::ValueOnIter& it)
const 910 void operator()(
const typename TreeType::ValueOffIter& it)
const 913 it.setActiveState(
true);
917 void operator()(
const typename TreeType::LeafIter& lit)
const 919 typedef typename TreeType::LeafNodeType LeafT;
922 for (
typename LeafT::ValueOffIter it = leaf.beginValueOff(); it; ++it) {
924 leaf.setValueOn(it.pos());
928 for (
typename LeafT::ValueOnIter it = leaf.beginValueOn(); it; ++it) {
930 leaf.setValueOff(it.pos());
938 const ValueT mValue, mTolerance;
944 template<
typename Gr
idOrTree>
946 activate(GridOrTree& gridOrTree,
const typename GridOrTree::ValueType& value,
947 const typename GridOrTree::ValueType& tolerance)
950 typedef typename Adapter::TreeType TreeType;
952 TreeType& tree = Adapter::tree(gridOrTree);
957 foreach(tree.beginLeaf(), op);
961 typename TreeType::ValueOffIter it = tree.beginValueOff();
962 it.setMaxDepth(tree.treeDepth() - 2);
963 foreach(it, op,
false);
967 template<
typename Gr
idOrTree>
969 deactivate(GridOrTree& gridOrTree,
const typename GridOrTree::ValueType& value,
970 const typename GridOrTree::ValueType& tolerance)
973 typedef typename Adapter::TreeType TreeType;
975 TreeType& tree = Adapter::tree(gridOrTree);
980 foreach(tree.beginLeaf(), op);
984 typename TreeType::ValueOnIter it = tree.beginValueOn();
985 it.setMaxDepth(tree.treeDepth() - 2);
986 foreach(it, op,
false);
991 template<
typename TreeT>
994 typedef typename TreeT::template ValueConverter<ValueMask>::Type MaskT;
995 typedef tbb::enumerable_thread_specific<MaskT> PoolT;
996 typedef typename MaskT::LeafNodeType LeafT;
1007 : mIter(iterations), mNN(nn), mPool(nullptr), mLeafs(nullptr)
1009 const size_t numLeafs = this->init( tree, mode );
1010 const size_t numThreads = size_t(tbb::task_scheduler_init::default_num_threads());
1011 const size_t grainSize =
math::Max(
size_t(1), numLeafs/(2*numThreads));
1017 tbb::parallel_for(tbb::blocked_range<LeafT**>(mLeafs, mLeafs+numLeafs, grainSize), *
this);
1021 typedef typename PoolT::iterator IterT;
1022 for (IterT it=pool.begin(); it!=pool.end(); ++it) mask.merge(*it);
1026 tree.topologyUnion(mask);
1033 for (LeafT** it=r.begin(); it!=r.end(); ++it) mask.addLeaf( *it );
1042 typedef LeafT* value_type;
1044 MyArray(value_type* array) : ptr(array) {}
1045 void push_back(value_type leaf) { *ptr++ = leaf; }
1049 size_t linearize(MaskT& mask,
TilePolicy mode)
1052 const size_t numLeafs = mask.leafCount();
1053 mLeafs =
new LeafT*[numLeafs];
1054 MyArray tmp(mLeafs);
1055 mask.stealNodes(tmp);
1059 template<
typename T>
1060 typename std::enable_if<std::is_same<T, MaskT>::value,
size_t>::type
1063 return this->linearize(tree, mode);
1066 template<
typename T>
1067 typename std::enable_if<!std::is_same<T, MaskT>::value,
size_t>::type
1070 MaskT mask(tree,
false,
true, TopologyCopy());
1071 return this->linearize(mask, mode);
1076 template<
typename TreeType>
1083 template<
typename TreeType>
1090 if (iterations > 0 ) {
1100 #endif // OPENVDB_TOOLS_MORPHOLOGY_HAS_BEEN_INCLUDED LeafNodeT * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z), or nullptr if no such node exists.
Definition: ValueAccessor.h:417
This adapter allows code that is templated on a Tree type to accept either a Tree type or a Grid type...
Definition: Grid.h:944
void rebuildLeafArray()
Remove the auxiliary buffers and rebuild the leaf array.
Definition: LeafManager.h:316
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:264
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:51
Defined various multi-threaded utility functions for trees.
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:136
Definition: Exceptions.h:40
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:110
const Type & Max(const Type &a, const Type &b)
Return the maximum of two values.
Definition: Math.h:549
bool isApproxEqual(const Type &a, const Type &b)
Return true if a is equal to b to within the default floating-point comparison tolerance.
Definition: Math.h:358
LeafType & leaf(size_t leafIdx) const
Return a pointer to the leaf node at index leafIdx in the array.
Definition: LeafManager.h:359
const TreeType & tree() const
Return a const reference to tree associated with this manager.
Definition: LeafManager.h:343
LeafNodeT * touchLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists,...
Definition: ValueAccessor.h:386
RangeType getRange(size_t grainsize=1) const
Return a tbb::blocked_range of leaf array indices.
Definition: LeafManager.h:383
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:188
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
Definition: Exceptions.h:88
Coord offsetBy(Int32 dx, Int32 dy, Int32 dz) const
Definition: Coord.h:118