4#ifndef OPENVDB_TOOLS_DENSESPARSETOOLS_HAS_BEEN_INCLUDED 
    5#define OPENVDB_TOOLS_DENSESPARSETOOLS_HAS_BEEN_INCLUDED 
    7#include <tbb/parallel_reduce.h> 
    8#include <tbb/blocked_range3d.h> 
    9#include <tbb/blocked_range2d.h> 
   10#include <tbb/blocked_range.h> 
   89template<
typename OpType, 
typename DenseType>
 
   90typename OpType::ResultTreeType::Ptr
 
   92                  const typename OpType::ResultValueType& background,
 
   93                  bool threaded = 
true);
 
   98template<
typename DenseType, 
typename TreeType>
 
  102    using Type = 
typename TreeType::template ValueConverter<ValueType>::Type;
 
 
  115template<
typename DenseType, 
typename MaskTreeType>
 
  118                          const MaskTreeType& mask,
 
  119                          const typename DenseType::ValueType& background,
 
  143template<
typename ValueT, 
typename OpType>
 
  160template<DSCompositeOp, 
typename TreeT>
 
  161void compositeToDense(Dense<typename TreeT::ValueType, LayoutZYX>& dense,
 
  164                      const typename TreeT::ValueType beta,
 
  165                      const typename TreeT::ValueType strength,
 
  166                      bool threaded = 
true);
 
  172template<
typename OpType, 
typename DenseType>
 
  176    using Index = openvdb::math::Coord::ValueType;
 
  182    using MaskTree = 
typename ResultTreeType::template ValueConverter<ValueMask>::Type;
 
  184    using Range3d = tbb::blocked_range3d<Index, Index, Index>;
 
  187    const DenseType&                     mDense;
 
  188    const OpType&                        mFunctor;
 
  190    const openvdb::math::CoordBBox       mBBox;
 
  192    typename ResultTreeType::Ptr         mMask;
 
  193    openvdb::math::Coord                 mMin;
 
  198        mDense(dense), mFunctor(functor),
 
  199        mBackground(background),
 
 
  206                    const openvdb::math::CoordBBox& bbox,
 
  207                    const OpType& functor,
 
  209        mDense(dense), mFunctor(functor),
 
  210        mBackground(background),
 
  216        if (!dense.bbox().isInside(mBBox)) {
 
  217            OPENVDB_THROW(ValueError, 
"Data extraction window out of bound");
 
 
  222        mDense(other.mDense), mFunctor(other.mFunctor),
 
  223        mBackground(other.mBackground), mBBox(other.mBBox),
 
  224        mWidth(other.mWidth),
 
 
  236        openvdb::math::Coord padded_min = mBBox.min();
 
  237        openvdb::math::Coord padded_max = mBBox.max();
 
  240        padded_min &= ~(mWidth - 1);
 
  241        padded_max &= ~(mWidth - 1);
 
  243        padded_max[0] += mWidth - 1;
 
  244        padded_max[1] += mWidth - 1;
 
  245        padded_max[2] += mWidth - 1;
 
  251        const Index xleafCount = ( padded_max.x() - padded_min.x() + 1 ) / mWidth;
 
  252        const Index yleafCount = ( padded_max.y() - padded_min.y() + 1 ) / mWidth;
 
  253        const Index zleafCount = ( padded_max.z() - padded_min.z() + 1 ) / mWidth;
 
  257        Range3d  leafRange(0, xleafCount, 1,
 
  263            tbb::parallel_reduce(leafRange, *
this);
 
 
  276        const Index imin = range.pages().begin();
 
  277        const Index imax = range.pages().end();
 
  279        const Index jmin = range.rows().begin();
 
  280        const Index jmax = range.rows().end();
 
  282        const Index kmin = range.cols().begin();
 
  283        const Index kmax = range.cols().end();
 
  289        for (
Index i = imin; i < imax; ++i) {
 
  290            for (
Index j = jmin; j < jmax; ++j) {
 
  291                for (
Index k = kmin; k < kmax; ++k) {
 
  294                    const openvdb::math::Coord origin =
 
  295                        mMin + openvdb::math::Coord(mWidth * i,
 
  299                    if (leaf == 
nullptr) {
 
  302                        leaf->setOrigin(origin);
 
  303                        leaf->fill(mBackground);
 
  304                        leaf->setValuesOff();
 
  309                    openvdb::math::CoordBBox localBBox = leaf->getNodeBoundingBox();
 
  314                    localBBox.intersect(mBBox);
 
  318                    if (localBBox.empty()) 
continue;
 
  321                    const openvdb::math::Coord start = localBBox.getStart();
 
  322                    const openvdb::math::Coord end   = localBBox.getEnd();
 
  327                    if (mDense.memoryLayout() == openvdb::tools::LayoutZYX) {
 
  329                        openvdb::math::Coord ijk;
 
  332                        for (ijk[0] = start.x(); ijk[0] < end.x(); ++ijk[0] ) {
 
  333                            for (ijk[1] = start.y(); ijk[1] < end.y(); ++ijk[1] ) {
 
  334                                for (ijk[2] = start.z(),
 
  335                                         offset = ResultLeafNodeType::coordToOffset(ijk),
 
  336                                         dp = &mDense.getValue(ijk);
 
  337                                     ijk[2] < end.z(); ++ijk[2], ++offset, ++dp) {
 
  339                                    mFunctor(*dp, offset, leaf);
 
  346                        openvdb::math::Coord ijk;
 
  348                        for (ijk[2] = start.z(); ijk[2] < end.z(); ++ijk[2]) {
 
  349                            for (ijk[1] = start.y(); ijk[1] < end.y(); ++ijk[1]) {
 
  350                                for (ijk[0] = start.x(),
 
  351                                         dp = &mDense.getValue(ijk);
 
  352                                     ijk[0] < end.x(); ++ijk[0], ++dp) {
 
  354                                    mFunctor(*dp, ijk, leaf);
 
  363                    if (!leaf->isEmpty()) {
 
  364                        mMask->addLeaf(leaf);
 
 
  378        mMask->merge(*rhs.mMask);
 
 
 
  383template<
typename OpType, 
typename DenseType>
 
  384typename OpType::ResultTreeType::Ptr
 
  386                  const typename OpType::ResultValueType& background,
 
 
  402template<
typename DenseType, 
typename MaskTreeType>
 
  412    using MaskTree = 
typename ResultTreeType::template ValueConverter<ValueMask>::Type;
 
  414    using MaskLeafVec = std::vector<const typename MaskTree::LeafNodeType*>;
 
  421        mDense(dense), mBackground(background), mBBox(dense.bbox()),
 
 
  427        mDense(other.mDense), mBackground(other.mBackground), mBBox(other.mBBox),
 
  428        mLeafVec(other.mLeafVec), mResult( new 
ResultTreeType(mBackground))
 
 
  433        tbb::blocked_range<size_t> range(0, mLeafVec.size());
 
  436            tbb::parallel_reduce(range, *
this);
 
 
  453        for (
size_t idx = range.begin(); idx < range.end(); ++ idx) {
 
  459            openvdb::math::CoordBBox localBBox = maskLeaf->getNodeBoundingBox();
 
  463            localBBox.intersect(mBBox);
 
  467            if (localBBox.empty()) 
continue;
 
  471            if (leaf == 
nullptr) {
 
  474                leaf->setOrigin(maskLeaf->origin());
 
  475                leaf->fill(mBackground);
 
  476                leaf->setValuesOff();
 
  482            const openvdb::math::Coord start = localBBox.getStart();
 
  483            const openvdb::math::Coord end   = localBBox.getEnd();
 
  485            openvdb::math::Coord ijk;
 
  487            if (mDense.memoryLayout() == openvdb::tools::LayoutZYX
 
  488                  && maskLeaf->isDense()) {
 
  492                for (ijk[0] = start.x(); ijk[0] < end.x(); ++ijk[0] ) {
 
  493                    for (ijk[1] = start.y(); ijk[1] < end.y(); ++ijk[1] ) {
 
  494                        for (ijk[2] = start.z(),
 
  495                                 offset = ResultLeafNodeType::coordToOffset(ijk),
 
  496                                 src  = &mDense.getValue(ijk);
 
  497                             ijk[2] < end.z(); ++ijk[2], ++offset, ++src) {
 
  500                            leaf->setValueOn(offset, *src);
 
  509                for (ijk[0] = start.x(); ijk[0] < end.x(); ++ijk[0] ) {
 
  510                    for (ijk[1] = start.y(); ijk[1] < end.y(); ++ijk[1] ) {
 
  511                        for (ijk[2] = start.z(),
 
  512                                 offset = ResultLeafNodeType::coordToOffset(ijk);
 
  513                             ijk[2] < end.z(); ++ijk[2], ++offset) {
 
  515                            if (maskLeaf->isValueOn(offset)) {
 
  517                                leaf->setValueOn(offset, denseValue);
 
  525            if (!leaf->isEmpty()) {
 
  526                mResult->addLeaf(leaf);
 
 
  537        mResult->merge(*rhs.mResult);
 
 
  542    const DenseType&                   mDense;
 
  543    const ResultValueType              mBackground;
 
  544    const openvdb::math::CoordBBox&    mBBox;
 
  545    const MaskLeafVec&                 mLeafVec;
 
  547    typename ResultTreeType::Ptr       mResult;
 
 
  553template<
typename _ResultTreeType, 
typename DenseValueType>
 
  559    template<
typename CoordOrIndex> 
inline void 
  562        leaf->setValueOn(offset, a);
 
 
 
  567template<
typename DenseType, 
typename MaskTreeType>
 
  568typename DSConverter<DenseType, MaskTreeType>::Type::Ptr
 
  570                          const MaskTreeType& maskProxy,
 
  571                          const typename DenseType::ValueType& background,
 
  575    using DenseValueType = 
typename LeafExtractor::DenseValueType;
 
  576    using ResultTreeType = 
typename LeafExtractor::ResultTreeType;
 
  577    using MaskLeafVec = 
typename LeafExtractor::MaskLeafVec;
 
  578    using MaskTree = 
typename LeafExtractor::MaskTree;
 
  579    using MaskLeafCIter = 
typename LeafExtractor::MaskLeafCIter;
 
  588    const size_t leafCount = maskTree.
leafCount();
 
  589    MaskLeafVec leafarray(leafCount);
 
  590    MaskLeafCIter leafiter = maskTree.
cbeginLeaf();
 
  591    for (
size_t n = 0; n != leafCount; ++n, ++leafiter) {
 
  592        leafarray[n] = leafiter.getLeaf();
 
  598    LeafExtractor leafextractor(dense, background, leafarray);
 
  599    typename ResultTreeType::Ptr resultTree = leafextractor.extract(
threaded);
 
  609    typename MaskTreeType::ValueOnCIter tileIter(maskProxy);
 
  610    tileIter.setMaxDepth(MaskTreeType::ValueOnCIter::LEAF_DEPTH - 1);
 
  614    if (!tileIter) 
return resultTree;
 
  616    ExtractionRule allrule;
 
  622    for ( ; tileIter; ++tileIter) {
 
  626        tileIter.getBoundingBox(bbox);
 
  629        if (bbox.
empty()) 
continue;
 
  632        typename ResultTreeType::Ptr fromTileTree = copyData.
extract(
threaded);
 
  633        resultTree->merge(*fromTileTree);
 
 
  643template<
typename _ValueT, 
typename OpType>
 
  649    using IntType = openvdb::math::Coord::ValueType;
 
  650    using RangeType = tbb::blocked_range2d<IntType, IntType>;
 
  655    openvdb::math::CoordBBox mBBox;
 
  659        mDense(dense), mOp(functor), mBBox(dense.bbox())
 
  663        mBBox.intersect(bbox);
 
 
  667        mDense(other.mDense), mOp(other.mOp), mBBox(other.mBBox) {}
 
 
  673        if (mBBox.empty()) 
return;
 
  676        const openvdb::math::Coord start = mBBox.getStart();
 
  677        const openvdb::math::Coord end   = mBBox.getEnd();
 
  680        const RangeType range(start.x(), end.x(), 1,
 
  681                              start.y(), end.y(), 1);
 
  684            tbb::parallel_for(range, *
this);
 
 
  695        const size_t zlength = size_t(mBBox.max().z() - mBBox.min().z() + 1);
 
  697        const IntType imin = range.rows().begin();
 
  698        const IntType imax = range.rows().end();
 
  699        const IntType jmin = range.cols().begin();
 
  700        const IntType jmax = range.cols().end();
 
  703        openvdb::math::Coord xyz(imin, jmin, mBBox.min().z());
 
  704        for (xyz[0] = imin; xyz[0] != imax; ++xyz[0]) {
 
  705            for (xyz[1] = jmin; xyz[1] != jmax; ++xyz[1]) {
 
  707                mOp.transform(mDense, xyz, zlength);
 
 
 
  717template<
typename ValueT, 
typename Po
intWiseOp>
 
  725        ValueT* dp = 
const_cast<ValueT*
>(&dense.
getValue(ijk));
 
  727        for (
size_t offset = 0; offset < size; ++offset) {
 
  728            dp[offset] = 
mOp(dp[offset]);
 
 
 
  737template<
typename ValueT, 
typename Po
intwiseOpT>
 
  741               const PointwiseOpT& functor, 
bool parallel)
 
  751    transformer.
apply(parallel);
 
 
  755template<
typename CompositeMethod, 
typename _TreeT>
 
  760    using ValueT = 
typename TreeT::ValueType;
 
  761    using LeafT = 
typename TreeT::LeafNodeType;
 
  762    using MaskTreeT = 
typename TreeT::template ValueConverter<ValueMask>::Type;
 
  765    using Index = openvdb::math::Coord::ValueType;
 
  766    using Range3d = tbb::blocked_range3d<Index, Index, Index>;
 
  770        mDense(dense), mSource(source), mAlpha(alpha), mBeta(beta), mStrength(strength)
 
 
  774        mDense(other.mDense), mSource(other.mSource), mAlpha(other.mAlpha),
 
  775        mBeta(other.mBeta), mStrength(other.mStrength) {}
 
 
  780        const ValueT beta = mBeta;
 
  781        const ValueT strength = mStrength;
 
  786        maskTree.topologyUnion(mAlpha);
 
  791        openvdb::tree::LeafManager<const MaskTreeT> maskLeafs(maskTree);
 
  797        typename MaskTreeT::ValueOnCIter citer = maskTree.cbeginValueOn();
 
  798        citer.setMaxDepth(MaskTreeT::ValueOnCIter::LEAF_DEPTH - 1);
 
  805        for (; citer; ++citer) {
 
  807            const openvdb::math::Coord org = citer.getCoord();
 
  814            if (openvdb::math::isZero(alphaValue) &&
 
  815                openvdb::math::isZero(sourceValue)) 
continue;
 
  819            openvdb::math::CoordBBox localBBox = citer.getBoundingBox();
 
  820            localBBox.intersect(mDense.bbox());
 
  824            if (localBBox.empty()) 
continue;
 
  828                              alphaValue, beta, strength, 
threaded);
 
 
  836        using ULeaf = UniformLeaf;
 
  837        openvdb::math::CoordBBox localBBox = maskLeaf.getNodeBoundingBox();
 
  838        localBBox.intersect(mDense.bbox());
 
  842        if (localBBox.empty()) 
return;
 
  844        const openvdb::math::Coord org = maskLeaf.origin();
 
  845        const LeafT* alphaLeaf = mAlpha.probeLeaf(org);
 
  846        const LeafT* sourceLeaf   = mSource.probeLeaf(org);
 
  851            ULeaf uniformSource(mSource.getValue(org));
 
  856                ULeaf uniformAlpha(mAlpha.getValue(org));
 
  869                ULeaf uniformAlpha(mAlpha.getValue(org));
 
 
  882    template<
typename LeafT1, 
typename LeafT2>
 
  884                                         const LeafT1& source, 
const LeafT2& alpha,
 
  887        using IntType = openvdb::math::Coord::ValueType;
 
  889        const ValueT sbeta = strength * beta;
 
  890        openvdb::math::Coord ijk = bbox.min();
 
  893        if (alpha.isDense() ) {
 
  896            const IntType size = bbox.max().z() + 1 - bbox.min().z();
 
  898            for (ijk[0] = bbox.min().x(); ijk[0] < bbox.max().x() + 1; ++ijk[0]) {
 
  899                for (ijk[1] = bbox.min().y(); ijk[1] < bbox.max().y() + 1; ++ijk[1]) {
 
  902                    const ValueT* a = &alpha.getValue(ijk);
 
  903                    const ValueT* s = &source.getValue(ijk);
 
  905                    for (IntType idx = 0; idx < size; ++idx) {
 
  906                        d[idx] = CompositeMethod::apply(d[idx], a[idx], s[idx],
 
  907                                                        strength, beta, sbeta);
 
  915            for (ijk[0] = bbox.min().x(); ijk[0] < bbox.max().x() + 1; ++ijk[0]) {
 
  916                for (ijk[1] = bbox.min().y(); ijk[1] < bbox.max().y() + 1; ++ijk[1]) {
 
  917                    for (ijk[2] = bbox.min().z(); ijk[2] < bbox.max().z() + 1; ++ijk[2]) {
 
  919                        if (alpha.isValueOn(ijk)) {
 
  921                                alpha.getValue(ijk), source.getValue(ijk), strength, beta, sbeta));
 
 
  934        using TileTransformer = UniformTransformer;
 
  935        TileTransformer functor(sourceValue, alphaValue, beta, strength);
 
 
  946        const openvdb::math::CoordBBox& bbox = mDense.bbox();
 
  948        Range3d  range(bbox.min().x(), bbox.max().x(), LeafT::DIM,
 
  949                       bbox.min().y(), bbox.max().y(), LeafT::DIM,
 
  950                       bbox.min().z(), bbox.max().z(), LeafT::DIM);
 
  956            tbb::parallel_for(range, *
this);
 
 
  971        const ValueT strength = mStrength;
 
  972        const ValueT beta     = mBeta;
 
  973        const ValueT sbeta    = strength * beta;
 
  976        const Index imin = range.pages().begin();
 
  977        const Index imax = range.pages().end();
 
  979        const Index jmin = range.rows().begin();
 
  980        const Index jmax = range.rows().end();
 
  982        const Index kmin = range.cols().begin();
 
  983        const Index kmax = range.cols().end();
 
  986        for (ijk[0] = imin; ijk[0] < imax; ++ijk[0]) {
 
  987            for (ijk[1] = jmin; ijk[1] < jmax; ++ijk[1]) {
 
  988                for (ijk[2] = kmin; ijk[2] < kmax; ++ijk[2]) {
 
  989                    const ValueT d_old = mDense.getValue(ijk);
 
  994                        CompositeMethod::apply(d_old, alpha, src, strength, beta, sbeta));
 
 
 1004    class UniformTransformer
 
 1007        UniformTransformer(
const ValueT& source, 
const ValueT& alpha, 
const ValueT& _beta,
 
 1008                           const ValueT& _strength) :
 
 1009            mSource(source), mAlpha(alpha), mBeta(_beta),
 
 1010            mStrength(_strength), mSBeta(_strength * _beta)
 
 1013        ValueT operator()(
const ValueT& input)
 const 
 1015            return CompositeMethod::apply(input, mAlpha, mSource, mStrength, mBeta, mSBeta);
 
 1019        const ValueT mSource;
 
 1020        const ValueT mAlpha;
 
 1022        const ValueT mStrength;
 
 1023        const ValueT mSBeta;
 
 1030    struct Line {  ValueT mValues[LeafT::DIM]; };
 
 1031    class UniformLeaf : 
private Line
 
 1034        using ValueT = 
typename LeafT::ValueType;
 
 1037        UniformLeaf(
const ValueT& value) : BaseT(init(value)) {}
 
 1039        static const BaseT init(
const ValueT& value) {
 
 1042                tmp.mValues[i] = value;
 
 1047        bool isDense()
 const { 
return true; }
 
 1048        bool isValueOn(openvdb::math::Coord&)
 const { 
return true; }
 
 1050        const ValueT& getValue(
const openvdb::math::Coord&)
 const { 
return  BaseT::mValues[0]; }
 
 1055    const TreeT&  mSource;
 
 1056    const TreeT&  mAlpha;
 
 
 1066    template<
typename ValueT>
 
 1069        static inline ValueT 
apply(
const ValueT u, 
const ValueT alpha,
 
 1071                                   const ValueT strength,
 
 1074        { 
return (u + strength * alpha * (beta * v - u)); }
 
 
 
 1077    template<
typename ValueT>
 
 1080        static inline ValueT 
apply(
const ValueT u, 
const ValueT alpha,
 
 1085        { 
return (u + sbeta * alpha * v); }
 
 
 
 1088    template<
typename ValueT>
 
 1091        static inline ValueT 
apply(
const ValueT u, 
const ValueT alpha,
 
 1096        { 
return (u - sbeta * alpha * v); }
 
 
 
 1099    template<
typename ValueT>
 
 1102        static inline ValueT 
apply(
const ValueT u, 
const ValueT alpha,
 
 1107        { 
return ( ( 1 - s * alpha) * u + s * alpha * std::min(u, beta * v) ); }
 
 
 
 1110    template<
typename ValueT>
 
 1113        static inline ValueT 
apply(
const ValueT u, 
const ValueT alpha,
 
 1118        { 
return ( ( 1 - s * alpha ) * u + s * alpha * std::min(u, beta * v) ); }
 
 
 
 1121    template<
typename ValueT>
 
 1124        static inline ValueT 
apply(
const ValueT u, 
const ValueT alpha,
 
 1129        { 
return ( ( 1 + alpha * (sbeta * v - s)) * u ); }
 
 
 
 1135    template<DSCompositeOp OP, 
typename ValueT>
 
 1138    template<
typename ValueT>
 
 1141    template<
typename ValueT>
 
 1144    template<
typename ValueT>
 
 1147    template<
typename ValueT>
 
 1150    template<
typename ValueT>
 
 1153    template<
typename ValueT>
 
 
 1160template<DSCompositeOp OpT, 
typename TreeT>
 
 1164    const TreeT& source, 
const TreeT& alpha,
 
 1165    const typename TreeT::ValueType beta,
 
 1166    const typename TreeT::ValueType strength,
 
 1169    using ValueT = 
typename TreeT::ValueType;
 
 1171    using Method = 
typename Translator::OpT;
 
 1173    if (openvdb::math::isZero(strength)) 
return;
 
 1177    if (openvdb::math::isZero(alpha.background()) &&
 
 1178        openvdb::math::isZero(source.background()))
 
 
This file defines a simple dense grid and efficient converters to and from VDB grids.
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition Types.h:683
Axis-aligned bounding box of signed integer coordinates.
Definition Coord.h:252
bool empty() const
Return true if this bounding box is empty (i.e., encloses no coordinates).
Definition Coord.h:359
void intersect(const CoordBBox &bbox)
Intersect this bounding box with the given bounding box.
Definition Coord.h:447
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
LeafCIter cbeginLeaf() const
Definition Tree.h:1047
LeafIteratorBase< const Tree, typename RootNodeType::ChildOnCIter > LeafCIter
Definition Tree.h:1033
Index64 leafCount() const override
Return the number of leaf nodes.
Definition Tree.h:363
typename RootNodeType::LeafNodeType LeafNodeType
Definition Tree.h:203
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition ValueAccessor.h:455
ValueAccessorImpl< TreeType, IsSafe, MutexType, openvdb::make_index_sequence< CacheLevels > > ValueAccessor
Default alias for a ValueAccessor. This is simply a helper alias for the generic definition but takes...
Definition ValueAccessor.h:86
Index32 Index
Definition Types.h:54
tree::Tree4< ValueMask, 5, 4, 3 >::Type MaskTree
Definition openvdb.h:58
Definition Exceptions.h:13
#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:218