9#ifndef OPENVDB_TOOLS_CLIP_HAS_BEEN_INCLUDED 
   10#define OPENVDB_TOOLS_CLIP_HAS_BEEN_INCLUDED 
   19#include <tbb/blocked_range.h> 
   20#include <tbb/parallel_reduce.h> 
   38template<
typename Gr
idType>
 
   40clip(
const GridType& grid, 
const BBoxd& bbox, 
bool keepInterior = 
true);
 
   49template<
typename Gr
idType>
 
   51clip(
const GridType& grid, 
const math::NonlinearFrustumMap& frustum, 
bool keepInterior = 
true);
 
   65template<
typename Gr
idType, 
typename MaskTreeType>
 
   74namespace clip_internal {
 
   82template<
typename TreeT>
 
   83class MaskInteriorVoxels
 
   86    using ValueT = 
typename TreeT::ValueType;
 
   87    using LeafNodeT = 
typename TreeT::LeafNodeType;
 
   89    MaskInteriorVoxels(
const TreeT& 
tree): mAcc(
tree) {}
 
   91    template<
typename LeafNodeType>
 
   92    void operator()(LeafNodeType& leaf, 
size_t )
 const 
   94        const auto* refLeaf = mAcc.probeConstLeaf(leaf.origin());
 
   96            for (
auto iter = leaf.beginValueOff(); iter; ++iter) {
 
   97                const auto pos = iter.pos();
 
  104     tree::ValueAccessor<const TreeT> mAcc;
 
  111template<
typename TreeT>
 
  115    using MaskTreeT = 
typename TreeT::template ValueConverter<MaskValueType>::Type;
 
  116    using MaskLeafManagerT = tree::LeafManager<const MaskTreeT>;
 
  118    CopyLeafNodes(
const TreeT&, 
const MaskLeafManagerT&);
 
  120    void run(
bool threaded = 
true);
 
  122    typename TreeT::Ptr tree()
 const { 
return mNewTree; }
 
  124    CopyLeafNodes(CopyLeafNodes&, tbb::split);
 
  125    void operator()(
const tbb::blocked_range<size_t>&);
 
  126    void join(
const CopyLeafNodes& rhs) { mNewTree->merge(*rhs.mNewTree); }
 
  129    const MaskTreeT* mClipMask;
 
  131    const MaskLeafManagerT* mLeafNodes;
 
  132    typename TreeT::Ptr mNewTree;
 
  136template<
typename TreeT>
 
  137CopyLeafNodes<TreeT>::CopyLeafNodes(
const TreeT& tree, 
const MaskLeafManagerT& leafNodes)
 
  139    , mLeafNodes(&leafNodes)
 
  140    , mNewTree(new TreeT(mTree->background()))
 
  145template<
typename TreeT>
 
  146CopyLeafNodes<TreeT>::CopyLeafNodes(CopyLeafNodes& rhs, tbb::split)
 
  148    , mLeafNodes(rhs.mLeafNodes)
 
  149    , mNewTree(new TreeT(mTree->background()))
 
  154template<
typename TreeT>
 
  156CopyLeafNodes<TreeT>::run(
bool threaded)
 
  158    if (threaded) tbb::parallel_reduce(mLeafNodes->getRange(), *
this);
 
  159    else (*
this)(mLeafNodes->getRange());
 
  163template<
typename TreeT>
 
  165CopyLeafNodes<TreeT>::operator()(
const tbb::blocked_range<size_t>& range)
 
  170    for (
auto n = range.begin(); n != range.end(); ++n) {
 
  171        const auto& maskLeaf = mLeafNodes->leaf(n);
 
  172        const auto& ijk = maskLeaf.origin();
 
  173        const auto* refLeaf = refAcc.probeConstLeaf(ijk);
 
  175        auto* newLeaf = acc.touchLeaf(ijk);
 
  178            for (
auto it = maskLeaf.cbeginValueOn(); it; ++it) {
 
  179                const auto pos = it.pos();
 
  180                newLeaf->setValueOnly(pos, refLeaf->getValue(pos));
 
  181                newLeaf->setActiveState(pos, refLeaf->isValueOn(pos));
 
  184            typename TreeT::ValueType value;
 
  185            bool isActive = refAcc.probeValue(ijk, value);
 
  187            for (
auto it = maskLeaf.cbeginValueOn(); it; ++it) {
 
  188                const auto pos = it.pos();
 
  189                newLeaf->setValueOnly(pos, value);
 
  190                newLeaf->setActiveState(pos, isActive);
 
  202    static const char* name() { 
return "bin"; }
 
  203    static int radius() { 
return 2; }
 
  204    static bool mipmap() { 
return false; }
 
  205    static bool consistent() { 
return true; }
 
  207    template<
class TreeT>
 
  208    static bool sample(
const TreeT& inTree,
 
  209        const Vec3R& inCoord, 
typename TreeT::ValueType& result)
 
  211        return inTree.probeValue(Coord::floor(inCoord), result);
 
  220template<
typename FromGr
idT, 
typename ToGr
idT>
 
  223    using FromGridCPtrT = 
typename FromGridT::ConstPtr;
 
  224    using ToGridPtrT = 
typename ToGridT::Ptr;
 
  225    ToGridPtrT operator()(
const FromGridCPtrT& grid) { 
return ToGridPtrT(
new ToGridT(*grid)); }
 
  230template<
typename Gr
idT>
 
  231struct ConvertGrid<GridT, GridT>
 
  233    using GridCPtrT = 
typename GridT::ConstPtr;
 
  234    GridCPtrT operator()(
const GridCPtrT& grid) { 
return grid; }
 
  244template<
typename Gr
idT>
 
  245typename std::enable_if<!std::is_same<MaskValueType, typename GridT::BuildType>::value,
 
  246    typename GridT::template ValueConverter<MaskValueType>::Type::Ptr>::type
 
  247convertToMaskGrid(
const GridT& grid)
 
  249    using MaskGridT = 
typename GridT::template ValueConverter<MaskValueType>::Type;
 
  250    auto mask = MaskGridT::create(
false);
 
  251    mask->topologyUnion(grid);
 
  252    mask->setTransform(grid.constTransform().copy());
 
  258template<
typename Gr
idT>
 
  259typename std::enable_if<std::is_same<MaskValueType, typename GridT::BuildType>::value,
 
  260    typename GridT::ConstPtr>::type
 
  261convertToMaskGrid(
const GridT& grid)
 
  271template<
typename Gr
idType>
 
  272typename GridType::Ptr
 
  274    const GridType& grid,
 
  275    const typename GridType::template ValueConverter<MaskValueType>::Type& clipMask,
 
  278    using TreeT = 
typename GridType::TreeType;
 
  279    using MaskTreeT = 
typename GridType::TreeType::template ValueConverter<MaskValueType>::Type;
 
  281    const auto gridClass = grid.getGridClass();
 
  282    const auto& 
tree = grid.tree();
 
  284    MaskTreeT gridMask(
false);
 
  285    gridMask.topologyUnion(
tree);
 
  289        leafNodes.foreach(MaskInteriorVoxels<TreeT>(
tree));
 
  293        typename MaskTreeT::ValueAllIter iter(gridMask);
 
  294        iter.setMaxDepth(MaskTreeT::ValueAllIter::LEAF_DEPTH - 1);
 
  296        for ( ; iter; ++iter) {
 
  302        gridMask.topologyIntersection(clipMask.constTree());
 
  304        gridMask.topologyDifference(clipMask.constTree());
 
  307    auto outGrid = grid.copyWithNewTree();
 
  311        CopyLeafNodes<TreeT> maskOp(
tree, leafNodes);
 
  313        outGrid->setTree(maskOp.tree());
 
  320        typename TreeT::ValueAllIter it(
outGrid->tree());
 
  321        it.setMaxDepth(TreeT::ValueAllIter::LEAF_DEPTH - 1);
 
  323            Coord ijk = it.getCoord();
 
  325            if (maskAcc.isValueOn(ijk)) {
 
  326                typename TreeT::ValueType value;
 
  327                bool isActive = refAcc.probeValue(ijk, value);
 
  330                if (!isActive) it.setValueOff();
 
  335    outGrid->setTransform(grid.transform().copy());
 
  350template<
typename Gr
idType>
 
  351typename GridType::Ptr
 
  352clip(
const GridType& grid, 
const BBoxd& bbox, 
bool keepInterior)
 
  354    using MaskValueT = clip_internal::MaskValueType;
 
  355    using MaskGridT = 
typename GridType::template ValueConverter<MaskValueT>::Type;
 
  358    Vec3d idxMin, idxMax;
 
  363    MaskGridT clipMask(
false);
 
  364    clipMask.fill(region, 
true, 
true);
 
  366    return clip_internal::doClip(grid, clipMask, keepInterior);
 
 
  371template<
typename SrcGr
idType, 
typename ClipTreeType>
 
  372typename SrcGridType::Ptr
 
  373clip(
const SrcGridType& srcGrid, 
const Grid<ClipTreeType>& clipGrid, 
bool keepInterior)
 
  375    using MaskValueT = clip_internal::MaskValueType;
 
  377    using SrcMaskGridType = 
typename SrcGridType::template ValueConverter<MaskValueT>::Type;
 
  378    using ClipMaskGridType = 
typename ClipGridType::template ValueConverter<MaskValueT>::Type;
 
  381    auto maskGrid = clip_internal::convertToMaskGrid(clipGrid);
 
  384    if (srcGrid.constTransform() != maskGrid->constTransform()) {
 
  385        auto resampledMask = ClipMaskGridType::create(
false);
 
  386        resampledMask->setTransform(srcGrid.constTransform().copy());
 
  389        maskGrid = resampledMask;
 
  393    auto clipMask = clip_internal::ConvertGrid<
 
  394        ClipMaskGridType, SrcMaskGridType>()(maskGrid);
 
  397    return clip_internal::doClip(srcGrid, *clipMask, keepInterior);
 
  402template<
typename Gr
idType>
 
  403typename GridType::Ptr
 
  406    using ValueT = 
typename GridType::ValueType;
 
  407    using TreeT = 
typename GridType::TreeType;
 
  408    using LeafT = 
typename TreeT::LeafNodeType;
 
  410    const auto& gridXform = inGrid.transform();
 
  411    const auto frustumIndexBBox = frustumMap.
getBBox();
 
  414    auto frustumContainsCoord = [&](
const Coord& ijk) -> 
bool {
 
  415        auto xyz = gridXform.indexToWorld(ijk);
 
  417        return frustumIndexBBox.isInside(xyz);
 
  422    auto toFrustumIndexSpace = [&](
const CoordBBox& inBBox) -> 
BBoxd {
 
  423        const Coord bounds[2] = { inBBox.min(), inBBox.max() };
 
  426        for (
int i = 0; i < 8; ++i) {
 
  427            ijk[0] = bounds[(i & 1) >> 0][0];
 
  428            ijk[1] = bounds[(i & 2) >> 1][1];
 
  429            ijk[2] = bounds[(i & 4) >> 2][2];
 
  430            auto xyz = gridXform.indexToWorld(ijk);
 
  438    auto outGrid = inGrid.copyWithNewTree();
 
  444    const auto& bg = 
outGrid->background();
 
  446    auto outAcc = 
outGrid->getAccessor();
 
  452    auto tileIter = inGrid.beginValueAll();
 
  453    tileIter.setMaxDepth(GridType::ValueAllIter::LEAF_DEPTH - 1);
 
  455    for ( ; tileIter; ++tileIter) {
 
  456        const bool tileActive = tileIter.isValueOn();
 
  457        const auto& tileValue = tileIter.getValue();
 
  463        tileIter.getBoundingBox(tileBBox);
 
  464        const auto tileFrustumBBox = toFrustumIndexSpace(tileBBox);
 
  467        enum class CopyTile { kNone, kPartial, kFull };
 
  468        auto copyTile = CopyTile::kNone;
 
  470            if (frustumIndexBBox.isInside(tileFrustumBBox)) {
 
  471                copyTile = CopyTile::kFull;
 
  472            } 
else if (frustumIndexBBox.hasOverlap(tileFrustumBBox)) {
 
  473                copyTile = CopyTile::kPartial;
 
  476            if (!frustumIndexBBox.hasOverlap(tileFrustumBBox)) {
 
  477                copyTile = CopyTile::kFull;
 
  478            } 
else if (!frustumIndexBBox.isInside(tileFrustumBBox)) {
 
  479                copyTile = CopyTile::kPartial;
 
  483            case CopyTile::kNone:
 
  485            case CopyTile::kFull:
 
  487                outAcc.addTile(tileIter.getLevel(), tileBBox.
min(), tileValue, tileActive);
 
  489            case CopyTile::kPartial:
 
  491                for (std::vector<CoordBBox> bboxVec = { tileBBox }; !bboxVec.empty(); ) {
 
  496                    if (bboxVec.back().volume() > 64 && bboxVec.back().is_divisible()) {
 
  498                        bboxVec.emplace_back(bboxVec.back(), tbb::split{});
 
  501                    auto subBBox = bboxVec.back();
 
  506                        if (!frustumIndexBBox.hasOverlap(toFrustumIndexSpace(subBBox))) 
continue;
 
  508                        if (frustumIndexBBox.isInside(toFrustumIndexSpace(subBBox))) 
continue;
 
  512                    for (
const auto& ijk: subBBox) {
 
  513                        if (frustumContainsCoord(ijk) == keepInterior) {
 
  515                                outAcc.setValueOn(ijk, tileValue);
 
  517                                outAcc.setValueOff(ijk, tileValue);
 
  530    for (
auto leafIter = inGrid.constTree().beginLeaf(); leafIter; ++leafIter) {
 
  531        const auto leafBBox = leafIter->getNodeBoundingBox();
 
  532        const auto leafFrustumBBox = toFrustumIndexSpace(leafBBox);
 
  534            if (frustumIndexBBox.hasOverlap(leafFrustumBBox)) {
 
  535                outAcc.touchLeaf(leafBBox.min());
 
  538            if (!frustumIndexBBox.hasOverlap(leafFrustumBBox)
 
  539                || !frustumIndexBBox.isInside(leafFrustumBBox))
 
  541                outAcc.touchLeaf(leafBBox.min());
 
  550        [&](LeafT& leaf, 
size_t ) {
 
  551            auto inAcc = inGrid.getConstAccessor();
 
  553            for (
auto voxelIter = leaf.beginValueAll(); voxelIter; ++voxelIter) {
 
  554                const auto ijk = voxelIter.getCoord();
 
  555                if (frustumContainsCoord(ijk) == keepInterior) {
 
  556                    const bool active = inAcc.probeValue(ijk, val);
 
  557                    voxelIter.setValue(val);
 
  558                    voxelIter.setValueOn(active);
 
 
  573#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION 
  575#ifdef OPENVDB_INSTANTIATE_CLIP 
  579#define _FUNCTION(TreeT) \ 
  580    Grid<TreeT>::Ptr clip(const Grid<TreeT>&, const BBoxd&, bool) 
  584#define _FUNCTION(TreeT) \ 
  585    Grid<TreeT>::Ptr clip(const Grid<TreeT>&, const math::NonlinearFrustumMap&, bool) 
  589#define _FUNCTION(TreeT) \ 
  590    Grid<TreeT>::Ptr clip_internal::doClip(const Grid<TreeT>&, const MaskGrid&, bool) 
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
Defined various multi-threaded utility functions for trees.
static Coord floor(const Vec3< T > &xyz)
Return the largest integer coordinates that are not greater than xyz (node centered conversion).
Definition Coord.h:57
Container class that associates a tree with a transform and metadata.
Definition Grid.h:571
const Vec3T & max() const
Return a const reference to the maximum point of this bounding box.
Definition BBox.h:64
void expand(ElementType padding)
Pad this bounding box.
Definition BBox.h:321
const Vec3T & min() const
Return a const reference to the minimum point of this bounding box.
Definition BBox.h:62
Axis-aligned bounding box of signed integer coordinates.
Definition Coord.h:252
const Coord & min() const
Definition Coord.h:324
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
This map is composed of three steps. First it will take a box of size (Lx X Ly X Lz) defined by a mem...
Definition Maps.h:1892
const BBoxd & getBBox() const
Return the bounding box that defines the frustum in pre-image space.
Definition Maps.h:2363
Vec3d applyInverseMap(const Vec3d &in) const override
Return the pre-image of in under the map.
Definition Maps.h:2103
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition LeafManager.h:86
void foreach(const LeafOp &op, bool threaded=true, size_t grainSize=1)
Threaded method that applies a user-supplied functor to each leaf node in the LeafManager.
Definition LeafManager.h:484
OPENVDB_AX_API void run(const char *ax, openvdb::GridBase &grid, const AttributeBindings &bindings={})
Run a full AX pipeline (parse, compile and execute) on a single OpenVDB Grid.
bool isApproxEqual(const Type &a, const Type &b, const Type &tolerance)
Return true if a is equal to b to within the given tolerance.
Definition Math.h:406
OPENVDB_API void calculateBounds(const Transform &t, const Vec3d &minWS, const Vec3d &maxWS, Vec3d &minIS, Vec3d &maxIS)
Calculate an axis-aligned bounding box in index space from an axis-aligned bounding box in world spac...
bool isNegative(const Type &x)
Return true if x is less than zero.
Definition Math.h:367
Vec3< double > Vec3d
Definition Vec3.h:665
Definition PointDataGrid.h:170
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
@ GRID_LEVEL_SET
Definition Types.h:455
@ GRID_UNKNOWN
Definition Types.h:454
math::BBox< Vec3d > BBoxd
Definition Types.h:84
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
#define OPENVDB_VOLUME_TREE_INSTANTIATE(Function)
Definition version.h.in:165
#define OPENVDB_ALL_TREE_INSTANTIATE(Function)
Definition version.h.in:166