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