31 #ifndef OPENVDB_TOOLS_DENSESPARSETOOLS_HAS_BEEN_INCLUDED 32 #define OPENVDB_TOOLS_DENSESPARSETOOLS_HAS_BEEN_INCLUDED 34 #include <tbb/parallel_reduce.h> 35 #include <tbb/blocked_range3d.h> 36 #include <tbb/blocked_range2d.h> 37 #include <tbb/blocked_range.h> 116 template<
typename OpType,
typename DenseType>
117 typename OpType::ResultTreeType::Ptr
119 const typename OpType::ResultValueType& background,
120 bool threaded =
true);
125 template<
typename DenseType,
typename TreeType>
129 using Type =
typename TreeType::template ValueConverter<ValueType>::Type;
142 template<
typename DenseType,
typename MaskTreeType>
145 const MaskTreeType& mask,
146 const typename DenseType::ValueType& background,
147 bool threaded =
true);
170 template<
typename ValueT,
typename OpType>
187 template<DSCompositeOp,
typename TreeT>
191 const typename TreeT::ValueType beta,
192 const typename TreeT::ValueType strength,
193 bool threaded =
true);
199 template<
typename OpType,
typename DenseType>
203 using Index = openvdb::math::Coord::ValueType;
209 using MaskTree =
typename ResultTreeType::template ValueConverter<ValueMask>::Type;
211 using Range3d = tbb::blocked_range3d<Index, Index, Index>;
214 const DenseType& mDense;
215 const OpType& mFunctor;
217 const openvdb::math::CoordBBox mBBox;
219 typename ResultTreeType::Ptr mMask;
220 openvdb::math::Coord mMin;
225 mDense(dense), mFunctor(functor),
226 mBackground(background),
233 const openvdb::math::CoordBBox& bbox,
234 const OpType& functor,
236 mDense(dense), mFunctor(functor),
237 mBackground(background),
243 if (!dense.bbox().isInside(mBBox)) {
249 mDense(other.mDense), mFunctor(other.mFunctor),
250 mBackground(other.mBackground), mBBox(other.mBBox),
251 mWidth(other.mWidth),
256 typename ResultTreeType::Ptr
extract(
bool threaded =
true)
263 openvdb::math::Coord padded_min = mBBox.min();
264 openvdb::math::Coord padded_max = mBBox.max();
267 padded_min &= ~(mWidth - 1);
268 padded_max &= ~(mWidth - 1);
270 padded_max[0] += mWidth - 1;
271 padded_max[1] += mWidth - 1;
272 padded_max[2] += mWidth - 1;
278 const Index xleafCount = ( padded_max.x() - padded_min.x() + 1 ) / mWidth;
279 const Index yleafCount = ( padded_max.y() - padded_min.y() + 1 ) / mWidth;
280 const Index zleafCount = ( padded_max.z() - padded_min.z() + 1 ) / mWidth;
284 Range3d leafRange(0, xleafCount, 1,
290 tbb::parallel_reduce(leafRange, *
this);
303 const Index imin = range.pages().begin();
304 const Index imax = range.pages().end();
306 const Index jmin = range.rows().begin();
307 const Index jmax = range.rows().end();
309 const Index kmin = range.cols().begin();
310 const Index kmax = range.cols().end();
316 for (
Index i = imin; i < imax; ++i) {
317 for (
Index j = jmin; j < jmax; ++j) {
318 for (
Index k = kmin; k < kmax; ++k) {
321 const openvdb::math::Coord origin =
322 mMin + openvdb::math::Coord(mWidth * i,
326 if (leaf ==
nullptr) {
329 leaf->setOrigin(origin);
330 leaf->fill(mBackground);
331 leaf->setValuesOff();
336 openvdb::math::CoordBBox localBBox = leaf->getNodeBoundingBox();
341 localBBox.intersect(mBBox);
345 if (localBBox.empty())
continue;
348 const openvdb::math::Coord start = localBBox.getStart();
349 const openvdb::math::Coord end = localBBox.getEnd();
356 openvdb::math::Coord ijk;
359 for (ijk[0] = start.x(); ijk[0] < end.x(); ++ijk[0] ) {
360 for (ijk[1] = start.y(); ijk[1] < end.y(); ++ijk[1] ) {
361 for (ijk[2] = start.z(),
362 offset = ResultLeafNodeType::coordToOffset(ijk),
363 dp = &mDense.getValue(ijk);
364 ijk[2] < end.z(); ++ijk[2], ++offset, ++dp) {
366 mFunctor(*dp, offset, leaf);
373 openvdb::math::Coord ijk;
375 for (ijk[2] = start.z(); ijk[2] < end.z(); ++ijk[2]) {
376 for (ijk[1] = start.y(); ijk[1] < end.y(); ++ijk[1]) {
377 for (ijk[0] = start.x(),
378 dp = &mDense.getValue(ijk);
379 ijk[0] < end.x(); ++ijk[0], ++dp) {
381 mFunctor(*dp, ijk, leaf);
390 if (!leaf->isEmpty()) {
391 mMask->addLeaf(leaf);
401 if (leaf !=
nullptr)
delete leaf;
405 mMask->merge(*rhs.mMask);
410 template<
typename OpType,
typename DenseType>
411 typename OpType::ResultTreeType::Ptr
413 const typename OpType::ResultValueType& background,
422 return extractor.
extract(threaded);
429 template<
typename DenseType,
typename MaskTreeType>
439 using MaskTree =
typename ResultTreeType::template ValueConverter<ValueMask>::Type;
441 using MaskLeafVec = std::vector<const typename MaskTree::LeafNodeType*>;
448 mDense(dense), mBackground(background), mBBox(dense.bbox()),
454 mDense(other.mDense), mBackground(other.mBackground), mBBox(other.mBBox),
455 mLeafVec(other.mLeafVec), mResult( new
ResultTreeType(mBackground))
458 typename ResultTreeType::Ptr
extract(
bool threaded =
true)
460 tbb::blocked_range<size_t> range(0, mLeafVec.size());
463 tbb::parallel_reduce(range, *
this);
480 for (
size_t idx = range.begin(); idx < range.end(); ++ idx) {
486 openvdb::math::CoordBBox localBBox = maskLeaf->getNodeBoundingBox();
490 localBBox.intersect(mBBox);
494 if (localBBox.empty())
continue;
498 if (leaf ==
nullptr) {
501 leaf->setOrigin(maskLeaf->origin());
502 leaf->fill(mBackground);
503 leaf->setValuesOff();
509 const openvdb::math::Coord start = localBBox.getStart();
510 const openvdb::math::Coord end = localBBox.getEnd();
512 openvdb::math::Coord ijk;
515 && maskLeaf->isDense()) {
519 for (ijk[0] = start.x(); ijk[0] < end.x(); ++ijk[0] ) {
520 for (ijk[1] = start.y(); ijk[1] < end.y(); ++ijk[1] ) {
521 for (ijk[2] = start.z(),
522 offset = ResultLeafNodeType::coordToOffset(ijk),
523 src = &mDense.getValue(ijk);
524 ijk[2] < end.z(); ++ijk[2], ++offset, ++src) {
527 leaf->setValueOn(offset, *src);
536 for (ijk[0] = start.x(); ijk[0] < end.x(); ++ijk[0] ) {
537 for (ijk[1] = start.y(); ijk[1] < end.y(); ++ijk[1] ) {
538 for (ijk[2] = start.z(),
539 offset = ResultLeafNodeType::coordToOffset(ijk);
540 ijk[2] < end.z(); ++ijk[2], ++offset) {
542 if (maskLeaf->isValueOn(offset)) {
544 leaf->setValueOn(offset, denseValue);
552 if (!leaf->isEmpty()) {
553 mResult->addLeaf(leaf);
560 if (leaf !=
nullptr)
delete leaf;
564 mResult->merge(*rhs.mResult);
569 const DenseType& mDense;
570 const ResultValueType mBackground;
571 const openvdb::math::CoordBBox& mBBox;
572 const MaskLeafVec& mLeafVec;
574 typename ResultTreeType::Ptr mResult;
580 template<
typename _ResultTreeType,
typename DenseValueType>
586 template<
typename CoordOrIndex>
inline void 589 leaf->setValueOn(offset, a);
594 template<
typename DenseType,
typename MaskTreeType>
595 typename DSConverter<DenseType, MaskTreeType>::Type::Ptr
597 const MaskTreeType& maskProxy,
598 const typename DenseType::ValueType& background,
602 using DenseValueType =
typename LeafExtractor::DenseValueType;
603 using ResultTreeType =
typename LeafExtractor::ResultTreeType;
604 using MaskLeafVec =
typename LeafExtractor::MaskLeafVec;
606 using MaskLeafCIter =
typename LeafExtractor::MaskLeafCIter;
615 const size_t leafCount = maskTree.
leafCount();
616 MaskLeafVec leafarray(leafCount);
617 MaskLeafCIter leafiter = maskTree.
cbeginLeaf();
618 for (
size_t n = 0; n != leafCount; ++n, ++leafiter) {
619 leafarray[n] = leafiter.
getLeaf();
625 LeafExtractor leafextractor(dense, background, leafarray);
626 typename ResultTreeType::Ptr resultTree = leafextractor.extract(threaded);
636 typename MaskTreeType::ValueOnCIter tileIter(maskProxy);
637 tileIter.setMaxDepth(MaskTreeType::ValueOnCIter::LEAF_DEPTH - 1);
641 if (!tileIter)
return resultTree;
643 ExtractionRule allrule;
649 for ( ; tileIter; ++tileIter) {
653 tileIter.getBoundingBox(bbox);
656 if (bbox.
empty())
continue;
659 typename ResultTreeType::Ptr fromTileTree = copyData.
extract(threaded);
660 resultTree->merge(*fromTileTree);
670 template<
typename _ValueT,
typename OpType>
676 using IntType = openvdb::math::Coord::ValueType;
677 using RangeType = tbb::blocked_range2d<IntType, IntType>;
682 openvdb::math::CoordBBox mBBox;
686 mDense(dense), mOp(functor), mBBox(dense.bbox())
690 mBBox.intersect(bbox);
694 mDense(other.mDense), mOp(other.mOp), mBBox(other.mBBox) {}
700 if (mBBox.empty())
return;
703 const openvdb::math::Coord start = mBBox.getStart();
704 const openvdb::math::Coord end = mBBox.getEnd();
707 const RangeType range(start.x(), end.x(), 1,
708 start.y(), end.y(), 1);
711 tbb::parallel_for(range, *
this);
722 const size_t zlength = size_t(mBBox.max().z() - mBBox.min().z() + 1);
724 const IntType imin = range.rows().begin();
725 const IntType imax = range.rows().end();
726 const IntType jmin = range.cols().begin();
727 const IntType jmax = range.cols().end();
730 openvdb::math::Coord xyz(imin, jmin, mBBox.min().z());
731 for (xyz[0] = imin; xyz[0] != imax; ++xyz[0]) {
732 for (xyz[1] = jmin; xyz[1] != jmax; ++xyz[1]) {
734 mOp.transform(mDense, xyz, zlength);
744 template<
typename ValueT,
typename Po
intWiseOp>
752 ValueT* dp = const_cast<ValueT*>(&dense.
getValue(ijk));
754 for (
size_t offset = 0; offset < size; ++offset) {
755 dp[offset] = mOp(dp[offset]);
764 template<
typename ValueT,
typename Po
intwiseOpT>
768 const PointwiseOpT& functor,
bool parallel)
778 transformer.
apply(parallel);
782 template<
typename CompositeMethod,
typename _TreeT>
787 using ValueT =
typename TreeT::ValueType;
788 using LeafT =
typename TreeT::LeafNodeType;
789 using MaskTreeT =
typename TreeT::template ValueConverter<ValueMask>::Type;
792 using Index = openvdb::math::Coord::ValueType;
793 using Range3d = tbb::blocked_range3d<Index, Index, Index>;
797 mDense(dense), mSource(source), mAlpha(alpha), mBeta(beta), mStrength(strength)
801 mDense(other.mDense), mSource(other.mSource), mAlpha(other.mAlpha),
802 mBeta(other.mBeta), mStrength(other.mStrength) {}
807 const ValueT beta = mBeta;
808 const ValueT strength = mStrength;
813 maskTree.topologyUnion(mAlpha);
818 openvdb::tree::LeafManager<const MaskTreeT> maskLeafs(maskTree);
819 maskLeafs.foreach(*
this, threaded);
824 typename MaskTreeT::ValueOnCIter citer = maskTree.cbeginValueOn();
825 citer.setMaxDepth(MaskTreeT::ValueOnCIter::LEAF_DEPTH - 1);
832 for (; citer; ++citer) {
834 const openvdb::math::Coord org = citer.getCoord();
846 openvdb::math::CoordBBox localBBox = citer.getBoundingBox();
847 localBBox.intersect(mDense.bbox());
851 if (localBBox.empty())
continue;
854 compositeFromTile(mDense, localBBox, sourceValue,
855 alphaValue, beta, strength, threaded);
863 using ULeaf = UniformLeaf;
864 openvdb::math::CoordBBox localBBox = maskLeaf.getNodeBoundingBox();
865 localBBox.intersect(mDense.bbox());
869 if (localBBox.empty())
return;
871 const openvdb::math::Coord org = maskLeaf.origin();
872 const LeafT* alphaLeaf = mAlpha.probeLeaf(org);
873 const LeafT* sourceLeaf = mSource.probeLeaf(org);
878 ULeaf uniformSource(mSource.getValue(org));
883 ULeaf uniformAlpha(mAlpha.getValue(org));
885 compositeFromLeaf(mDense, localBBox, uniformSource, uniformAlpha,
889 compositeFromLeaf(mDense, localBBox, uniformSource, *alphaLeaf,
896 ULeaf uniformAlpha(mAlpha.getValue(org));
898 compositeFromLeaf(mDense, localBBox, *sourceLeaf, uniformAlpha,
902 compositeFromLeaf(mDense, localBBox, *sourceLeaf, *alphaLeaf,
909 template<
typename LeafT1,
typename LeafT2>
911 const LeafT1& source,
const LeafT2& alpha,
914 using IntType = openvdb::math::Coord::ValueType;
916 const ValueT sbeta = strength * beta;
917 openvdb::math::Coord ijk = bbox.min();
920 if (alpha.isDense() ) {
923 const IntType size = bbox.max().z() + 1 - bbox.min().z();
925 for (ijk[0] = bbox.min().x(); ijk[0] < bbox.max().x() + 1; ++ijk[0]) {
926 for (ijk[1] = bbox.min().y(); ijk[1] < bbox.max().y() + 1; ++ijk[1]) {
929 const ValueT* a = &alpha.getValue(ijk);
930 const ValueT* s = &source.getValue(ijk);
932 for (IntType idx = 0; idx < size; ++idx) {
933 d[idx] = CompositeMethod::apply(d[idx], a[idx], s[idx],
934 strength, beta, sbeta);
942 for (ijk[0] = bbox.min().x(); ijk[0] < bbox.max().x() + 1; ++ijk[0]) {
943 for (ijk[1] = bbox.min().y(); ijk[1] < bbox.max().y() + 1; ++ijk[1]) {
944 for (ijk[2] = bbox.min().z(); ijk[2] < bbox.max().z() + 1; ++ijk[2]) {
946 if (alpha.isValueOn(ijk)) {
948 alpha.getValue(ijk), source.getValue(ijk), strength, beta, sbeta));
961 using TileTransformer = UniformTransformer;
962 TileTransformer functor(sourceValue, alphaValue, beta, strength);
973 const openvdb::math::CoordBBox& bbox = mDense.bbox();
975 Range3d range(bbox.min().x(), bbox.max().x(), LeafT::DIM,
976 bbox.min().y(), bbox.max().y(), LeafT::DIM,
977 bbox.min().z(), bbox.max().z(), LeafT::DIM);
983 tbb::parallel_for(range, *
this);
998 const ValueT strength = mStrength;
999 const ValueT beta = mBeta;
1000 const ValueT sbeta = strength * beta;
1003 const Index imin = range.pages().begin();
1004 const Index imax = range.pages().end();
1006 const Index jmin = range.rows().begin();
1007 const Index jmax = range.rows().end();
1009 const Index kmin = range.cols().begin();
1010 const Index kmax = range.cols().end();
1013 for (ijk[0] = imin; ijk[0] < imax; ++ijk[0]) {
1014 for (ijk[1] = jmin; ijk[1] < jmax; ++ijk[1]) {
1015 for (ijk[2] = kmin; ijk[2] < kmax; ++ijk[2]) {
1016 const ValueT d_old = mDense.getValue(ijk);
1020 mDense.setValue(ijk,
1021 CompositeMethod::apply(d_old, alpha, src, strength, beta, sbeta));
1031 class UniformTransformer
1034 UniformTransformer(
const ValueT& source,
const ValueT& alpha,
const ValueT& _beta,
1035 const ValueT& _strength) :
1036 mSource(source), mAlpha(alpha), mBeta(_beta),
1037 mStrength(_strength), mSBeta(_strength * _beta)
1040 ValueT operator()(
const ValueT& input)
const 1042 return CompositeMethod::apply(input, mAlpha, mSource, mStrength, mBeta, mSBeta);
1046 const ValueT mSource;
1047 const ValueT mAlpha;
1049 const ValueT mStrength;
1050 const ValueT mSBeta;
1057 struct Line { ValueT mValues[LeafT::DIM]; };
1058 class UniformLeaf :
private Line
1061 using ValueT =
typename LeafT::ValueType;
1064 UniformLeaf(
const ValueT& value) : BaseT(init(value)) {}
1066 static const BaseT init(
const ValueT& value) {
1069 tmp.mValues[i] = value;
1074 bool isDense()
const {
return true; }
1075 bool isValueOn(openvdb::math::Coord&)
const {
return true; }
1077 const ValueT& getValue(
const openvdb::math::Coord&)
const {
return BaseT::mValues[0]; }
1082 const TreeT& mSource;
1083 const TreeT& mAlpha;
1092 template<
typename ValueT>
1096 static inline ValueT
apply(
const ValueT u,
const ValueT alpha,
1098 const ValueT strength,
1101 {
return (u + strength * alpha * (beta * v - u)); }
1104 template<
typename ValueT>
1107 static inline ValueT
apply(
const ValueT u,
const ValueT alpha,
1112 {
return (u + sbeta * alpha * v); }
1115 template<
typename ValueT>
1118 static inline ValueT
apply(
const ValueT u,
const ValueT alpha,
1123 {
return (u - sbeta * alpha * v); }
1126 template<
typename ValueT>
1129 static inline ValueT
apply(
const ValueT u,
const ValueT alpha,
1134 {
return ( ( 1 - s * alpha) * u + s * alpha *
std::min(u, beta * v) ); }
1137 template<
typename ValueT>
1140 static inline ValueT
apply(
const ValueT u,
const ValueT alpha,
1145 {
return ( ( 1 - s * alpha ) * u + s * alpha *
std::min(u, beta * v) ); }
1148 template<
typename ValueT>
1151 static inline ValueT
apply(
const ValueT u,
const ValueT alpha,
1156 {
return ( ( 1 + alpha * (sbeta * v - s)) * u ); }
1161 template<DSCompositeOp OP,
typename ValueT>
1165 template<
typename ValueT>
1168 template<
typename ValueT>
1171 template<
typename ValueT>
1174 template<
typename ValueT>
1177 template<
typename ValueT>
1180 template<
typename ValueT>
1187 template<DSCompositeOp OpT,
typename TreeT>
1191 const TreeT& source,
const TreeT& alpha,
1192 const typename TreeT::ValueType beta,
1193 const typename TreeT::ValueType strength,
1196 using ValueT =
typename TreeT::ValueType;
1198 using Method =
typename Translator::OpT;
1219 #endif //OPENVDB_TOOLS_DENSESPARSETOOLS_HAS_BEEN_INCLUDED
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
Index32 leafCount() const override
Return the number of leaf nodes.
Definition: Tree.h:368
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:52
Index32 Index
Definition: Types.h:61
This file defines a simple dense grid and efficient converters to and from VDB grids.
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:750
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:128
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:275
Definition: Exceptions.h:40
tree::Tree4< ValueMask, 5, 4, 3 >::Type MaskTree
Definition: openvdb.h:54
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:257
LeafIteratorBase< const Tree, typename RootNodeType::ChildOnCIter > LeafCIter
Iterator over all leaf nodes in this tree.
Definition: Tree.h:1167
typename RootNodeType::LeafNodeType LeafNodeType
Definition: Tree.h:212
LeafCIter cbeginLeaf() const
Return an iterator over all leaf nodes in this tree.
Definition: Tree.h:1181
bool isZero(const Type &x)
Return true if x is exactly equal to zero.
Definition: Math.h:308
Definition: Exceptions.h:92
void intersect(const CoordBBox &bbox)
Intersect this bounding box with the given bounding box.
Definition: Coord.h:471
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:180
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
bool empty() const
Return true if this bounding box is empty (i.e., encloses no coordinates).
Definition: Coord.h:383
LeafNodeT * getLeaf() const
Return the leaf node to which the iterator is pointing.
Definition: TreeIterator.h:1261