16 #ifndef OPENVDB_TOOLS_MORPHOLOGY_HAS_BEEN_INCLUDED    17 #define OPENVDB_TOOLS_MORPHOLOGY_HAS_BEEN_INCLUDED    29 #include <tbb/task_arena.h>    30 #include <tbb/enumerable_thread_specific.h>    31 #include <tbb/parallel_for.h>    33 #include <type_traits>   107 template<
typename TreeOrLeafManagerT>
   109     const int iterations = 1,
   112     const bool threaded = 
true);
   138 template<
typename TreeOrLeafManagerT>
   140     const int iterations = 1,
   143     const bool threaded = 
true);
   149 namespace morphology {
   152 template<
typename TreeType>
   159     using MaskTreeT = 
typename TreeType::template ValueConverter<ValueMask>::Type;
   164         : mManagerPtr(new tree::LeafManager<TreeType>(tree))
   165         , mManager(*mManagerPtr)
   169         : mManagerPtr(nullptr)
   177     inline void setThreaded(
const bool threaded) { mThreaded = threaded; }
   191         const bool prune = 
false);
   206         const bool prune = 
false,
   207         const bool preserveMaskLeafNodes = 
false);
   215         if (masks.size() < mManager.leafCount()) {
   216             masks.resize(mManager.leafCount());
   219         if (this->getThreaded()) {
   221             tbb::parallel_for(mManager.getRange(),
   222                 [&](
const tbb::blocked_range<size_t>& r){
   223                 for (
size_t idx = r.begin(); idx < r.end(); ++idx)
   224                     masks[idx] = mManager.leaf(idx).getValueMask();
   228             for (
size_t idx = 0; idx < mManager.leafCount(); ++idx) {
   229                 masks[idx] = mManager.leaf(idx).getValueMask();
   243         static const Int32 LOG2DIM = 
static_cast<Int32>(LeafType::LOG2DIM);
   246         using Word = 
typename std::conditional<LOG2DIM == 3, uint8_t,
   247             typename std::conditional<LOG2DIM == 4, uint16_t,
   248             typename std::conditional<LOG2DIM == 5, uint32_t,
   249             typename std::conditional<LOG2DIM == 6, uint64_t,
   250                 void>::type>::type>::type>::type;
   253             "Unsupported Node Dimension for node mask dilation/erosion");
   259             , mAccessor(&accessor)
   275             const MaskType mask = leaf.getValueMask();
   276             this->dilate(leaf, mask);
   294             mNeighbors[0] = &(leaf.getValueMask());
   295             this->setOrigin(leaf.origin());
   299                 case NN_FACE             : { this->dilate6(mask);  
return; }
   301                     assert(
false && 
"Unknown op during dilation."); 
return;
   319             MaskType mask = leaf.getValueMask();
   320             this->erode(leaf, mask);
   340             mNeighbors[0] = 
const_cast<MaskType*
>(&leaf.getValueMask());
   341             this->setOrigin(leaf.origin());
   345                 case NN_FACE             : { this->erode6(mask);  
return; }
   347                     assert(
false && 
"Unknown op during erosion."); 
return;
   363         void dilate18(
const MaskType& mask);
   364         void dilate26(
const MaskType& mask);
   374         inline void setOrigin(
const Coord& origin) { mOrigin = &origin; }
   375         inline const Coord& getOrigin()
 const { 
return *mOrigin; }
   376         inline void clear() { std::fill(mNeighbors.begin(), mNeighbors.end(), 
nullptr); }
   378         inline void scatter(
size_t n, 
int indx)
   380             assert(n < mNeighbors.size());
   381             assert(mNeighbors[n]);
   382             mNeighbors[n]->template getWord<Word>(indx) |= mWord;
   385         template<
int DX, 
int DY, 
int DZ>
   386         inline void scatter(
size_t n, 
int indx)
   388             assert(n < mNeighbors.size());
   389             if (!mNeighbors[n]) {
   390                 mNeighbors[n] = this->getNeighbor<DX,DY,DZ,true>();
   392             assert(mNeighbors[n]);
   393             this->scatter(n, indx - (DIM - 1)*(DY + DX*DIM));
   395         inline Word gather(
size_t n, 
int indx)
   397             assert(n < mNeighbors.size());
   398             return mNeighbors[n]->template getWord<Word>(indx);
   400         template<
int DX, 
int DY, 
int DZ>
   401         inline Word gather(
size_t n, 
int indx)
   403             assert(n < mNeighbors.size());
   404             if (!mNeighbors[n]) {
   405                 mNeighbors[n] = this->getNeighbor<DX,DY,DZ,false>();
   407             return this->gather(n, indx - (DIM -1)*(DY + DX*DIM));
   410         void scatterFacesXY(
int x, 
int y, 
int i1, 
int n, 
int i2);
   411         void scatterEdgesXY(
int x, 
int y, 
int i1, 
int n, 
int i2);
   412         Word gatherFacesXY(
int x, 
int y, 
int i1, 
int n, 
int i2);
   414         Word gatherEdgesXY(
int x, 
int y, 
int i1, 
int n, 
int i2);
   416         template<
int DX, 
int DY, 
int DZ, 
bool Create>
   419             const Coord xyz = mOrigin->offsetBy(DX*DIM, DY*DIM, DZ*DIM);
   420             auto* leaf = mAccessor->probeLeaf(xyz);
   421             if (leaf) 
return &(leaf->getValueMask());
   422             if (mAccessor->isValueOn(xyz)) 
return &mOnTile;
   423             if (!Create)                   
return &mOffTile;
   424             leaf = mAccessor->touchLeaf(xyz);
   425             return &(leaf->getValueMask());
   429         const Coord* mOrigin;
   430         std::vector<MaskType*> mNeighbors;
   438     std::unique_ptr<tree::LeafManager<TreeType>> mManagerPtr;
   444 template <
typename TreeT>
   445 typename std::enable_if<std::is_same<TreeT, typename TreeT::template ValueConverter<ValueMask>::Type>
::value,
   446     typename TreeT::template ValueConverter<ValueMask>::Type*>::type
   449 template <
typename TreeT>
   450 typename std::enable_if<!std::is_same<TreeT, typename TreeT::template ValueConverter<ValueMask>::Type>
::value,
   451     typename TreeT::template ValueConverter<ValueMask>::Type*>::type
   455 template <
typename TreeType>
   460     if (iter == 0) 
return;
   461     const size_t leafCount = mManager.leafCount();
   462     if (leafCount == 0) 
return;
   463     auto& tree = mManager.tree();
   493         auto computeWavefront = [&](
const size_t idx) {
   494             auto& leaf = manager.
leaf(idx);
   495             auto& nodemask = leaf.getValueMask();
   496             if (
const auto* original = tree.probeConstLeaf(leaf.origin())) {
   497                 nodemask ^= original->getValueMask();
   504                 assert(!nodemask.isOn());
   508         if (this->getThreaded()) {
   509             tbb::parallel_for(manager.
getRange(),
   510                 [&](
const tbb::blocked_range<size_t>& r){
   511                 for (
size_t idx = r.begin(); idx < r.end(); ++idx) {
   512                     computeWavefront(idx);
   517             for (
size_t idx = 0; idx < manager.
leafCount(); ++idx) {
   518                 computeWavefront(idx);
   526         auto subtractTopology = [&](
const size_t idx) {
   527             auto& leaf = mManager.leaf(idx);
   528             const auto* maskleaf = mask.probeConstLeaf(leaf.origin());
   530             leaf.getValueMask() -= maskleaf->getValueMask();
   533         if (this->getThreaded()) {
   534             tbb::parallel_for(mManager.getRange(),
   535                 [&](
const tbb::blocked_range<size_t>& r){
   536                 for (
size_t idx = r.begin(); idx < r.end(); ++idx) {
   537                     subtractTopology(idx);
   542             for (
size_t idx = 0; idx < leafCount; ++idx) {
   543                 subtractTopology(idx);
   551         std::vector<MaskType> nodeMasks;
   552         this->copyMasks(nodeMasks);
   554         if (this->getThreaded()) {
   555             const auto range = mManager.getRange();
   556             for (
size_t i = 0; i < iter; ++i) {
   559                 tbb::parallel_for(range,
   560                     [&](
const tbb::blocked_range<size_t>& r) {
   563                     for (
size_t idx = r.begin(); idx < r.end(); ++idx) {
   564                         const auto& leaf = mManager.leaf(idx);
   565                         if (leaf.isEmpty()) 
continue;
   568                         cache.
erode(leaf, newMask);
   573                 tbb::parallel_for(range,
   574                     [&](
const tbb::blocked_range<size_t>& r){
   575                     for (
size_t idx = r.begin(); idx < r.end(); ++idx)
   576                         mManager.leaf(idx).setValueMask(nodeMasks[idx]);
   583             for (
size_t i = 0; i < iter; ++i) {
   586                 for (
size_t idx = 0; idx < leafCount; ++idx) {
   587                     const auto& leaf = mManager.leaf(idx);
   588                     if (leaf.isEmpty()) 
continue;
   591                     cache.
erode(leaf, newMask);
   594                 for (
size_t idx = 0; idx < leafCount; ++idx) {
   595                     mManager.leaf(idx).setValueMask(nodeMasks[idx]);
   604             zeroVal<typename TreeType::ValueType>(),
   605             this->getThreaded());
   606         mManager.rebuild(!this->getThreaded());
   610 template <
typename TreeType>
   614     const bool preserveMaskLeafNodes)
   616     if (iter == 0) 
return;
   618     const bool threaded = this->getThreaded();
   624     auto dilate = [iter, nn, threaded](
auto& manager, 
const bool collapse) {
   626         using LeafManagerT = 
typename std::decay<decltype(manager)>::type;
   627         using TreeT = 
typename LeafManagerT::TreeType;
   628         using ValueT = 
typename TreeT::ValueType;
   629         using LeafT = 
typename TreeT::LeafNodeType;
   635         TreeT& tree = manager.tree();
   640         std::vector<MaskType> nodeMasks;
   641         std::vector<std::unique_ptr<LeafT>> nodes;
   642         const ValueT& bg = tree.background();
   643         const bool steal = iter > 1;
   645         for (
size_t i = 0; i < iter; ++i) {
   646             if (i > 0) manager.rebuild(!threaded);
   648             const size_t leafCount = manager.leafCount();
   649             if (leafCount == 0) 
return;
   658             manager.foreach([&](LeafT& leaf, 
const size_t idx) {
   660                 const MaskType& oldMask = nodeMasks[idx];
   661                 const bool dense = oldMask.isOn();
   662                 cache.
dilate(leaf, oldMask);
   667                     accessor.
addTile(1, leaf.origin(), bg, 
true);
   672                         tree.template stealNode<LeafT>(leaf.origin(),
   673                             zeroVal<ValueT>(), 
true));
   678         if (nodes.empty()) 
return;
   680         for (
auto& node : nodes) {
   681             accessor.
addLeaf(node.release());
   691         dilate(mManager, isMask && prune);
   692         if (!isMask && prune) {
   694                 zeroVal<typename TreeType::ValueType>(),
   706         std::vector<MaskLeafT*> array;
   711             topology.topologyUnion(mManager.tree());
   712             array.reserve(mManager.leafCount());
   713             topology.stealNodes(array);
   715         else if (preserveMaskLeafNodes) {
   717             array.resize(mManager.leafCount());
   718             tbb::parallel_for(mManager.getRange(),
   719                 [&](
const tbb::blocked_range<size_t>& r){
   720                 for (
size_t idx = r.begin(); idx < r.end(); ++idx) {
   721                     array[idx] = 
new MaskLeafT(mManager.leaf(idx));
   726             array.reserve(mManager.leafCount());
   727             mask->stealNodes(array);
   731         const size_t numThreads = size_t(tbb::this_task_arena::max_concurrency());
   732         const size_t subTreeSize = 
math::Max(
size_t(1), array.size()/(2*numThreads));
   735         tbb::enumerable_thread_specific<std::unique_ptr<MaskTreeT>> pool;
   737         tbb::parallel_for(tbb::blocked_range<MaskLeafT**>(start, start + array.size(), subTreeSize),
   738             [&](
const tbb::blocked_range<MaskLeafT**>& range) {
   739                 std::unique_ptr<MaskTreeT> mask(
new MaskTreeT);
   740                 for (
MaskLeafT** it = range.begin(); it != range.end(); ++it) mask->addLeaf(*it);
   742                 dilate(manager, prune);
   743                 auto& subtree = pool.local();
   744                 if (!subtree) subtree = std::move(mask);
   749             auto piter = pool.begin();
   750             MaskTreeT& subtree = mask ? *mask : **piter++;
   751             for (; piter != pool.end(); ++piter) subtree.merge(**piter);
   754             if (prune) 
tools::prune(subtree, zeroVal<typename MaskTreeT::ValueType>(), threaded);
   757             if (!mask) mManager.tree().topologyUnion(subtree, 
true);
   762     mManager.rebuild(!threaded);
   766 template <
typename TreeType>
   770     for (
int x = 0; x < DIM; ++x) {
   771         for (
int y = 0, n = (x << LOG2DIM); y < DIM; ++y, ++n) {
   773             if (Word& w = mask.template getWord<Word>(n)) {
   776                     (Word(w<<1 | (this->
template gather<0,0,-1>(1, n)>>(DIM-1))) &
   777                      Word(w>>1 | (this->
template gather<0,0, 1>(2, n)<<(DIM-1)))));
   778                 w = Word(w & this->gatherFacesXY(x, y, 0, n, 3));
   784 template <
typename TreeType>
   788     for (
int x = 0; x < DIM; ++x ) {
   789         for (
int y = 0, n = (x << LOG2DIM);
   792             if (
const Word w = mask.template getWord<Word>(n)) {
   794                 this->mWord = Word(w | (w>>1) | (w<<1));
   797                 if ( (this->mWord = Word(w<<(DIM-1))) ) {
   798                     this->
template scatter< 0, 0,-1>(1, n);
   801                 if ( (this->mWord = Word(w>>(DIM-1))) ) {
   802                     this->
template scatter< 0, 0, 1>(2, n);
   806                 this->scatterFacesXY(x, y, 0, n, 3);
   812 template <
typename TreeType>
   817     const Coord origin = this->getOrigin();
   818     const Coord orig_mz = origin.offsetBy(0, 0, -DIM);
   819     const Coord orig_pz = origin.offsetBy(0, 0,  DIM);
   820     for (
int x = 0; x < DIM; ++x ) {
   821         for (
int y = 0, n = (x << LOG2DIM); y < DIM; ++y, ++n) {
   822             if (
const Word w = mask.template getWord<Word>(n)) {
   824                     this->mWord = Word(w | (w>>1) | (w<<1));
   825                     this->setOrigin(origin);
   827                     this->scatterFacesXY(x, y, 0, n, 3);
   829                     this->scatterEdgesXY(x, y, 0, n, 3);
   831                 if ( (this->mWord = Word(w<<(DIM-1))) ) {
   832                     this->setOrigin(origin);
   833                     this->
template scatter< 0, 0,-1>(1, n);
   834                     this->setOrigin(orig_mz);
   835                     this->scatterFacesXY(x, y, 1, n, 11);
   837                 if ( (this->mWord = Word(w>>(DIM-1))) ) {
   838                     this->setOrigin(origin);
   839                     this->
template scatter< 0, 0, 1>(2, n);
   840                     this->setOrigin(orig_pz);
   841                     this->scatterFacesXY(x, y, 2, n, 15);
   849 template <
typename TreeType>
   854     const Coord origin = this->getOrigin();
   855     const Coord orig_mz = origin.offsetBy(0, 0, -DIM);
   856     const Coord orig_pz = origin.offsetBy(0, 0,  DIM);
   857     for (
int x = 0; x < DIM; ++x) {
   858         for (
int y = 0, n = (x << LOG2DIM); y < DIM; ++y, ++n) {
   859             if (
const Word w = mask.template getWord<Word>(n)) {
   861                     this->mWord = Word(w | (w>>1) | (w<<1));
   862                     this->setOrigin(origin);
   864                     this->scatterFacesXY(x, y, 0, n, 3);
   865                     this->scatterEdgesXY(x, y, 0, n, 3);
   867                 if ( (this->mWord = Word(w<<(DIM-1))) ) {
   868                     this->setOrigin(origin);
   869                     this->
template scatter< 0, 0,-1>(1, n);
   870                     this->setOrigin(orig_mz);
   871                     this->scatterFacesXY(x, y, 1, n, 11);
   872                     this->scatterEdgesXY(x, y, 1, n, 11);
   874                 if ( (this->mWord = Word(w>>(DIM-1))) ) {
   875                     this->setOrigin(origin);
   876                     this->
template scatter< 0, 0, 1>(2, n);
   877                     this->setOrigin(orig_pz);
   878                     this->scatterFacesXY(x, y, 2, n, 19);
   879                     this->scatterEdgesXY(x, y, 2, n, 19);
   886 template<
typename TreeType>
   892         this->scatter(i1, n-DIM);
   894         this->
template scatter<-1, 0, 0>(i2, n);
   898         this->scatter(i1, n+DIM);
   900         this->
template scatter< 1, 0, 0>(i2+1, n);
   904         this->scatter(i1, n-1);
   906         this->
template scatter< 0,-1, 0>(i2+2, n);
   910         this->scatter(i1, n+1);
   912         this->
template scatter< 0, 1, 0>(i2+3, n);
   917 template<
typename TreeType>
   923             this->scatter(i1, n-DIM-1);
   925             this->
template scatter< 0,-1, 0>(i2+2, n-DIM);
   928             this->scatter(i1, n-DIM+1);
   930             this->
template scatter< 0, 1, 0>(i2+3, n-DIM);
   934             this->
template scatter<-1, 0, 0>(i2  , n+1);
   936             this->
template scatter<-1, 1, 0>(i2+7, n  );
   939             this->
template scatter<-1, 0, 0>(i2  , n-1);
   941             this->
template scatter<-1,-1, 0>(i2+4, n  );
   946             this->scatter(i1, n+DIM-1);
   948             this->
template scatter< 0,-1, 0>(i2+2, n+DIM);
   951             this->scatter(i1, n+DIM+1);
   953             this->
template scatter< 0, 1, 0>(i2+3, n+DIM);
   957             this->
template scatter< 1, 0, 0>(i2+1, n-1);
   959             this->
template scatter< 1,-1, 0>(i2+6, n  );
   962             this->
template scatter< 1, 0, 0>(i2+1, n+1);
   964             this->
template scatter< 1, 1, 0>(i2+5, n  );
   970 template<
typename TreeType>
   976         this->gather(i1, n - DIM) :
   977         this->
template gather<-1,0,0>(i2, n);
   980     w = Word(w & (x < DIM - 1 ?
   981         this->gather(i1, n + DIM) :
   982         this->
template gather<1,0,0>(i2 + 1, n)));
   985     w = Word(w & (y > 0 ?
   986         this->gather(i1, n - 1) :
   987         this->
template gather<0,-1,0>(i2 + 2, n)));
   990     w = Word(w & (y < DIM - 1 ?
   991         this->gather(i1, n + 1) :
   992         this->
template gather<0,1,0>(i2+3, n)));
   998 template<
typename TreeType>
  1005         w &= y > 0 ?          this->gather(i1, n-DIM-1) :
  1006                               this->
template gather< 0,-1, 0>(i2+2, n-DIM);
  1007         w &= y < DIM-1 ? this->gather(i1, n-DIM+1) :
  1008                               this->
template gather< 0, 1, 0>(i2+3, n-DIM);
  1010         w &= y < DIM-1 ? this->
template gather<-1, 0, 0>(i2  , n+1):
  1011                               this->
template gather<-1, 1, 0>(i2+7, n  );
  1012         w &= y > 0 ?          this->
template gather<-1, 0, 0>(i2  , n-1):
  1013                               this->
template gather<-1,-1, 0>(i2+4, n  );
  1016         w &= y > 0 ?          this->gather(i1, n+DIM-1) :
  1017                               this->
template gather< 0,-1, 0>(i2+2, n+DIM);
  1018         w &= y < DIM-1 ? this->gather(i1, n+DIM+1) :
  1019                               this->
template gather< 0, 1, 0>(i2+3, n+DIM);
  1021         w &= y > 0          ? this->
template gather< 1, 0, 0>(i2+1, n-1):
  1022                               this->
template gather< 1,-1, 0>(i2+6, n  );
  1023         w &= y < DIM-1 ? this->
template gather< 1, 0, 0>(i2+1, n+1):
  1024                               this->
template gather< 1, 1, 0>(i2+5, n  );
  1038 namespace morph_internal {
  1039 template <
typename T> 
struct Adapter {
  1041     static TreeType& 
get(T& tree) { 
return tree; }
  1042     static void sync(T&) {} 
  1044 template <
typename T>
  1045 struct Adapter<openvdb::tree::LeafManager<T>> {
  1047     static TreeType& 
get(openvdb::tree::LeafManager<T>& M) { 
return M.tree(); }
  1048     static void sync(openvdb::tree::LeafManager<T>& M) { M.rebuild(); }
  1054 template<
typename TreeOrLeafManagerT>
  1056                    const int iterations,
  1059                    const bool threaded)
  1061     using AdapterT = morph_internal::Adapter<TreeOrLeafManagerT>;
  1062     using TreeT = 
typename AdapterT::TreeType;
  1063     using MaskT = 
typename TreeT::template ValueConverter<ValueMask>::Type;
  1065     if (iterations <= 0) 
return;
  1071         morph.
dilateVoxels(static_cast<size_t>(iterations), nn, 
false);
  1078     auto& tree = AdapterT::get(treeOrLeafM);
  1086         tree.voxelizeActiveTiles();
  1087         AdapterT::sync(treeOrLeafM);
  1091         if (mode == PRESERVE_TILES) {
  1092             morph.
dilateVoxels(static_cast<size_t>(iterations), nn, 
true);
  1096             morph.
dilateVoxels(static_cast<size_t>(iterations), nn, 
false);
  1110     assert(mode == PRESERVE_TILES);
  1113     topology.topologyUnion(tree);
  1114     topology.voxelizeActiveTiles();
  1118     morph.
dilateVoxels(static_cast<size_t>(iterations), nn, 
true);
  1120     tree.topologyUnion(topology, 
true);
  1126     tools::prune(tree, zeroVal<typename TreeT::ValueType>(), threaded);
  1127     AdapterT::sync(treeOrLeafM);
  1131 template<
typename TreeOrLeafManagerT>
  1133                       const int iterations,
  1136                       const bool threaded)
  1138     using AdapterT = morph_internal::Adapter<TreeOrLeafManagerT>;
  1139     using TreeT = 
typename AdapterT::TreeType;
  1140     using MaskT = 
typename TreeT::template ValueConverter<ValueMask>::Type;
  1142     if (iterations <= 0) 
return;
  1147     if (mode == PRESERVE_TILES) {
  1148         auto& tree = AdapterT::get(treeOrLeafM);
  1150         topology.topologyUnion(tree);
  1151         topology.voxelizeActiveTiles();
  1156             morph.
erodeVoxels(static_cast<size_t>(iterations), nn, 
false);
  1161         tools::prune(topology, zeroVal<typename MaskT::ValueType>(), threaded);
  1162         tree.topologyIntersection(topology);
  1163         AdapterT::sync(treeOrLeafM);
  1170         auto& tree = AdapterT::get(treeOrLeafM);
  1171         if (tree.hasActiveTiles()) {
  1172             tree.voxelizeActiveTiles();
  1173             AdapterT::sync(treeOrLeafM);
  1180     morph.
erodeVoxels(static_cast<size_t>(iterations), nn, 
false);
  1200 template<
typename TreeType>
  1201 OPENVDB_DEPRECATED_MESSAGE(
"Switch to tools::dilateActiveValues. Use tools::IGNORE_TILES to maintain same (but perhaps unintended) behaviour")
  1206     if (iterations <= 0) 
return;
  1210     morph.
dilateVoxels(static_cast<size_t>(iterations), nn, 
false);
  1227 template<
typename TreeType>
  1228 OPENVDB_DEPRECATED_MESSAGE(
"Switch to tools::dilateActiveValues. Use tools::IGNORE_TILES to maintain same (but perhaps unintended) behaviour")
  1233     if (iterations <= 0) 
return;
  1236     morph.
dilateVoxels(static_cast<size_t>(iterations), nn, 
false);
  1245 template<
typename TreeType>
  1246 OPENVDB_DEPRECATED_MESSAGE(
"Switch to tools::erodeActiveValues. Use tools::IGNORE_TILES to maintain same (but perhaps unintended) behaviour")
  1251     if (iterations > 0) {
  1254         morph.
erodeVoxels(static_cast<size_t>(iterations), nn, 
false);
  1260 template<
typename TreeType>
  1261 OPENVDB_DEPRECATED_MESSAGE(
"Switch to tools::erodeActiveValues. Use tools::IGNORE_TILES to maintain same (but perhaps unintended) behaviour")
  1266     if (iterations <= 0) 
return;
  1269     morph.
erodeVoxels(static_cast<size_t>(iterations), nn, 
false);
  1280 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION  1282 #ifdef OPENVDB_INSTANTIATE_MORPHOLOGY  1286 #define _FUNCTION(TreeT) \  1287     void dilateActiveValues(TreeT&, \  1288         const int, const NearestNeighbors, const TilePolicy, const bool)  1292 #define _FUNCTION(TreeT) \  1293     void dilateActiveValues(tree::LeafManager<TreeT>&, \  1294         const int, const NearestNeighbors, const TilePolicy, const bool)  1298 #define _FUNCTION(TreeT) \  1299     void erodeActiveValues(TreeT&, \  1300         const int, const NearestNeighbors, const TilePolicy, const bool)  1304 #define _FUNCTION(TreeT) \  1305     void erodeActiveValues(tree::LeafManager<TreeT>&, \  1306         const int, const NearestNeighbors, const TilePolicy, const bool)  1310 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION  1317 #endif // OPENVDB_TOOLS_MORPHOLOGY_HAS_BEEN_INCLUDED Definition: Exceptions.h:61
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
Implementation of topological activation/deactivation. 
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors. 
Definition: Types.h:644
Defined various multi-threaded utility functions for trees. 
#define OPENVDB_ALL_TREE_INSTANTIATE(Function)        
Definition: version.h.in:151
size_t leafCount() const 
Return the number of leaf nodes. 
Definition: LeafManager.h:287
void addTile(Index level, const Coord &xyz, const ValueType &value, bool state)
Add a tile at the specified tree level that contains voxel (x, y, z), possibly deleting existing node...
Definition: ValueAccessor.h:337
Definition: Exceptions.h:13
ValueT value
Definition: GridBuilder.h:1287
const Type & Max(const Type &a, const Type &b)
Return the maximum of two values. 
Definition: Math.h:598
int32_t Int32
Definition: Types.h:56
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
RangeType getRange(size_t grainsize=1) const 
Return a tbb::blocked_range of leaf array indices. 
Definition: LeafManager.h:342
void addLeaf(LeafNodeT *leaf)
Add the specified leaf to this tree, possibly creating a child branch in the process. If the leaf node already exists, replace it. 
Definition: ValueAccessor.h:329
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
LeafType & leaf(size_t leafIdx) const 
Return a pointer to the leaf node at index leafIdx in the array. 
Definition: LeafManager.h:318
#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:202