9 #ifndef OPENVDB_TOOLS_CLIP_HAS_BEEN_INCLUDED
10 #define OPENVDB_TOOLS_CLIP_HAS_BEEN_INCLUDED
18 #include <tbb/blocked_range.h>
19 #include <tbb/parallel_reduce.h>
20 #include <type_traits>
37 template<
typename Gr
idType>
38 inline typename GridType::Ptr
39 clip(
const GridType& grid,
const BBoxd& bbox,
bool keepInterior =
true);
48 template<
typename Gr
idType>
49 inline typename GridType::Ptr
50 clip(
const GridType& grid,
const math::NonlinearFrustumMap& frustum,
bool keepInterior =
true);
64 template<
typename Gr
idType,
typename MaskTreeType>
65 inline typename GridType::Ptr
73 namespace clip_internal {
81 template<
typename TreeT>
82 class MaskInteriorVoxels
85 using ValueT =
typename TreeT::ValueType;
86 using LeafNodeT =
typename TreeT::LeafNodeType;
88 MaskInteriorVoxels(
const TreeT& tree): mAcc(tree) {}
90 template<
typename LeafNodeType>
91 void operator()(LeafNodeType& leaf,
size_t )
const
93 const auto* refLeaf = mAcc.probeConstLeaf(leaf.origin());
95 for (
auto iter = leaf.beginValueOff(); iter; ++iter) {
96 const auto pos = iter.pos();
103 tree::ValueAccessor<const TreeT> mAcc;
110 template<
typename TreeT>
114 using MaskTreeT =
typename TreeT::template ValueConverter<MaskValueType>::Type;
115 using MaskLeafManagerT = tree::LeafManager<const MaskTreeT>;
117 CopyLeafNodes(
const TreeT&,
const MaskLeafManagerT&);
119 void run(
bool threaded =
true);
121 typename TreeT::Ptr tree()
const {
return mNewTree; }
123 CopyLeafNodes(CopyLeafNodes&, tbb::split);
124 void operator()(
const tbb::blocked_range<size_t>&);
125 void join(
const CopyLeafNodes& rhs) { mNewTree->merge(*rhs.mNewTree); }
128 const MaskTreeT* mClipMask;
130 const MaskLeafManagerT* mLeafNodes;
131 typename TreeT::Ptr mNewTree;
135 template<
typename TreeT>
136 CopyLeafNodes<TreeT>::CopyLeafNodes(
const TreeT& tree,
const MaskLeafManagerT& leafNodes)
138 , mLeafNodes(&leafNodes)
139 , mNewTree(new TreeT(mTree->background()))
144 template<
typename TreeT>
145 CopyLeafNodes<TreeT>::CopyLeafNodes(CopyLeafNodes& rhs, tbb::split)
147 , mLeafNodes(rhs.mLeafNodes)
148 , mNewTree(new TreeT(mTree->background()))
153 template<
typename TreeT>
157 if (threaded) tbb::parallel_reduce(mLeafNodes->getRange(), *
this);
158 else (*
this)(mLeafNodes->getRange());
162 template<
typename TreeT>
164 CopyLeafNodes<TreeT>::operator()(
const tbb::blocked_range<size_t>& range)
166 tree::ValueAccessor<TreeT> acc(*mNewTree);
167 tree::ValueAccessor<const TreeT> refAcc(*mTree);
169 for (
auto n = range.begin(); n != range.end(); ++n) {
170 const auto& maskLeaf = mLeafNodes->leaf(n);
171 const auto& ijk = maskLeaf.origin();
172 const auto* refLeaf = refAcc.probeConstLeaf(ijk);
174 auto* newLeaf = acc.touchLeaf(ijk);
177 for (
auto it = maskLeaf.cbeginValueOn(); it; ++it) {
178 const auto pos = it.pos();
179 newLeaf->setValueOnly(pos, refLeaf->getValue(pos));
180 newLeaf->setActiveState(pos, refLeaf->isValueOn(pos));
183 typename TreeT::ValueType value;
184 bool isActive = refAcc.probeValue(ijk, value);
186 for (
auto it = maskLeaf.cbeginValueOn(); it; ++it) {
187 const auto pos = it.pos();
188 newLeaf->setValueOnly(pos, value);
189 newLeaf->setActiveState(pos, isActive);
201 static const char* name() {
return "bin"; }
202 static int radius() {
return 2; }
203 static bool mipmap() {
return false; }
204 static bool consistent() {
return true; }
206 template<
class TreeT>
207 static bool sample(
const TreeT& inTree,
208 const Vec3R& inCoord,
typename TreeT::ValueType& result)
210 return inTree.probeValue(
Coord::floor(inCoord), result);
219 template<
typename FromGr
idT,
typename ToGr
idT>
222 using FromGridCPtrT =
typename FromGridT::ConstPtr;
223 using ToGridPtrT =
typename ToGridT::Ptr;
224 ToGridPtrT operator()(
const FromGridCPtrT& grid) {
return ToGridPtrT(
new ToGridT(*grid)); }
229 template<
typename Gr
idT>
230 struct ConvertGrid<GridT, GridT>
232 using GridCPtrT =
typename GridT::ConstPtr;
233 GridCPtrT operator()(
const GridCPtrT& grid) {
return grid; }
243 template<
typename Gr
idT>
244 inline typename std::enable_if<!std::is_same<MaskValueType, typename GridT::BuildType>::value,
245 typename GridT::template ValueConverter<MaskValueType>::Type::Ptr>::type
246 convertToMaskGrid(
const GridT& grid)
248 using MaskGridT =
typename GridT::template ValueConverter<MaskValueType>::Type;
249 auto mask = MaskGridT::create(
false);
250 mask->topologyUnion(grid);
251 mask->setTransform(grid.constTransform().copy());
257 template<
typename Gr
idT>
258 inline typename std::enable_if<std::is_same<MaskValueType, typename GridT::BuildType>::value,
259 typename GridT::ConstPtr>::type
260 convertToMaskGrid(
const GridT& grid)
270 template<
typename Gr
idType>
271 inline typename GridType::Ptr
273 const GridType& grid,
274 const typename GridType::template ValueConverter<MaskValueType>::Type& clipMask,
277 using TreeT =
typename GridType::TreeType;
278 using MaskTreeT =
typename GridType::TreeType::template ValueConverter<MaskValueType>::Type;
280 const auto gridClass = grid.getGridClass();
281 const auto& tree = grid.tree();
283 MaskTreeT gridMask(
false);
284 gridMask.topologyUnion(tree);
287 tree::LeafManager<MaskTreeT> leafNodes(gridMask);
288 leafNodes.foreach(MaskInteriorVoxels<TreeT>(tree));
290 tree::ValueAccessor<const TreeT> acc(tree);
292 typename MaskTreeT::ValueAllIter iter(gridMask);
293 iter.setMaxDepth(MaskTreeT::ValueAllIter::LEAF_DEPTH - 1);
295 for ( ; iter; ++iter) {
301 gridMask.topologyIntersection(clipMask.constTree());
303 gridMask.topologyDifference(clipMask.constTree());
306 auto outGrid = grid.copyWithNewTree();
309 tree::LeafManager<const MaskTreeT> leafNodes(gridMask);
310 CopyLeafNodes<TreeT> maskOp(tree, leafNodes);
312 outGrid->setTree(maskOp.tree());
316 tree::ValueAccessor<const TreeT> refAcc(tree);
317 tree::ValueAccessor<const MaskTreeT> maskAcc(gridMask);
319 typename TreeT::ValueAllIter it(outGrid->tree());
320 it.setMaxDepth(TreeT::ValueAllIter::LEAF_DEPTH - 1);
322 Coord ijk = it.getCoord();
324 if (maskAcc.isValueOn(ijk)) {
325 typename TreeT::ValueType value;
326 bool isActive = refAcc.probeValue(ijk, value);
329 if (!isActive) it.setValueOff();
334 outGrid->setTransform(grid.transform().copy());
335 if (gridClass !=
GRID_LEVEL_SET) outGrid->setGridClass(gridClass);
349 template<
typename Gr
idType>
350 inline typename GridType::Ptr
351 clip(
const GridType& grid,
const BBoxd& bbox,
bool keepInterior)
353 using MaskValueT = clip_internal::MaskValueType;
354 using MaskGridT =
typename GridType::template ValueConverter<MaskValueT>::Type;
357 Vec3d idxMin, idxMax;
362 MaskGridT clipMask(
false);
363 clipMask.fill(region,
true,
true);
365 return clip_internal::doClip(grid, clipMask, keepInterior);
370 template<
typename SrcGr
idType,
typename ClipTreeType>
371 inline typename SrcGridType::Ptr
372 clip(
const SrcGridType& srcGrid,
const Grid<ClipTreeType>& clipGrid,
bool keepInterior)
374 using MaskValueT = clip_internal::MaskValueType;
376 using SrcMaskGridType =
typename SrcGridType::template ValueConverter<MaskValueT>::Type;
377 using ClipMaskGridType =
typename ClipGridType::template ValueConverter<MaskValueT>::Type;
380 auto maskGrid = clip_internal::convertToMaskGrid(clipGrid);
383 if (srcGrid.constTransform() != maskGrid->constTransform()) {
384 auto resampledMask = ClipMaskGridType::create(
false);
385 resampledMask->setTransform(srcGrid.constTransform().copy());
386 tools::resampleToMatch<clip_internal::BoolSampler>(*maskGrid, *resampledMask);
388 maskGrid = resampledMask;
392 auto clipMask = clip_internal::ConvertGrid<
393 ClipMaskGridType, SrcMaskGridType>()(maskGrid);
396 return clip_internal::doClip(srcGrid, *clipMask, keepInterior);
401 template<
typename Gr
idType>
402 inline typename GridType::Ptr
405 using ValueT =
typename GridType::ValueType;
406 using TreeT =
typename GridType::TreeType;
407 using LeafT =
typename TreeT::LeafNodeType;
409 const auto& gridXform = inGrid.transform();
410 const auto frustumIndexBBox = frustumMap.
getBBox();
413 auto frustumContainsCoord = [&](
const Coord& ijk) ->
bool {
414 auto xyz = gridXform.indexToWorld(ijk);
416 return frustumIndexBBox.isInside(xyz);
421 auto toFrustumIndexSpace = [&](
const CoordBBox& inBBox) ->
BBoxd {
422 const Coord bounds[2] = { inBBox.
min(), inBBox.
max() };
425 for (
int i = 0; i < 8; ++i) {
426 ijk[0] = bounds[(i & 1) >> 0][0];
427 ijk[1] = bounds[(i & 2) >> 1][1];
428 ijk[2] = bounds[(i & 4) >> 2][2];
429 auto xyz = gridXform.indexToWorld(ijk);
437 auto outGrid = inGrid.copyWithNewTree();
443 const auto& bg = outGrid->background();
445 auto outAcc = outGrid->getAccessor();
451 auto tileIter = inGrid.beginValueAll();
452 tileIter.setMaxDepth(GridType::ValueAllIter::LEAF_DEPTH - 1);
454 for ( ; tileIter; ++tileIter) {
455 const bool tileActive = tileIter.isValueOn();
456 const auto& tileValue = tileIter.getValue();
462 tileIter.getBoundingBox(tileBBox);
463 const auto tileFrustumBBox = toFrustumIndexSpace(tileBBox);
466 enum class CopyTile { kNone, kPartial, kFull };
467 auto copyTile = CopyTile::kNone;
469 if (frustumIndexBBox.isInside(tileFrustumBBox)) {
470 copyTile = CopyTile::kFull;
471 }
else if (frustumIndexBBox.hasOverlap(tileFrustumBBox)) {
472 copyTile = CopyTile::kPartial;
475 if (!frustumIndexBBox.hasOverlap(tileFrustumBBox)) {
476 copyTile = CopyTile::kFull;
477 }
else if (!frustumIndexBBox.isInside(tileFrustumBBox)) {
478 copyTile = CopyTile::kPartial;
482 case CopyTile::kNone:
484 case CopyTile::kFull:
486 outAcc.addTile(tileIter.getLevel(), tileBBox.
min(), tileValue, tileActive);
488 case CopyTile::kPartial:
490 for (std::vector<CoordBBox> bboxVec = { tileBBox }; !bboxVec.
empty(); ) {
495 if (bboxVec.back().volume() > 64 && bboxVec.back().is_divisible()) {
497 bboxVec.emplace_back(bboxVec.back(), tbb::split{});
500 auto subBBox = bboxVec.back();
505 if (!frustumIndexBBox.hasOverlap(toFrustumIndexSpace(subBBox)))
continue;
507 if (frustumIndexBBox.isInside(toFrustumIndexSpace(subBBox)))
continue;
511 for (
const auto& ijk: subBBox) {
512 if (frustumContainsCoord(ijk) == keepInterior) {
514 outAcc.setValueOn(ijk, tileValue);
516 outAcc.setValueOff(ijk, tileValue);
529 for (
auto leafIter = inGrid.constTree().beginLeaf(); leafIter; ++leafIter) {
530 const auto leafBBox = leafIter->getNodeBoundingBox();
531 const auto leafFrustumBBox = toFrustumIndexSpace(leafBBox);
533 if (frustumIndexBBox.hasOverlap(leafFrustumBBox)) {
534 outAcc.touchLeaf(leafBBox.min());
537 if (!frustumIndexBBox.hasOverlap(leafFrustumBBox)
538 || !frustumIndexBBox.isInside(leafFrustumBBox))
540 outAcc.touchLeaf(leafBBox.min());
548 outLeafNodes.foreach(
549 [&](LeafT& leaf,
size_t ) {
550 auto inAcc = inGrid.getConstAccessor();
552 for (
auto voxelIter = leaf.beginValueAll(); voxelIter; ++voxelIter) {
553 const auto ijk = voxelIter.getCoord();
554 if (frustumContainsCoord(ijk) == keepInterior) {
555 const bool active = inAcc.probeValue(ijk, val);
556 voxelIter.setValue(val);
557 voxelIter.setValueOn(active);
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...
Defined various multi-threaded utility functions for trees.
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:577
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:248
const Coord & min() const
Definition: Coord.h:320
bool empty() const
Return true if this bounding box is empty (i.e., encloses no coordinates).
Definition: Coord.h:355
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:25
static Coord min()
Return the smallest possible coordinate.
Definition: Coord.h:43
static Coord floor(const Vec3< T > &xyz)
Return the largest integer coordinates that are not greater than xyz (node centered conversion).
Definition: Coord.h:56
static Coord max()
Return the largest possible coordinate.
Definition: Coord.h:46
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:1911
Vec3d applyInverseMap(const Vec3d &in) const override
Return the pre-image of in under the map.
Definition: Maps.h:2122
const BBoxd & getBBox() const
Return the bounding box that defines the frustum in pre-image space.
Definition: Maps.h:2382
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:85
const TreeType & tree() const
Return a const reference to tree associated with this manager.
Definition: LeafManager.h:302
void run(const char *ax, openvdb::GridBase &grid)
Run a full AX pipeline (parse, compile and execute) on a single OpenVDB Grid.
bool isNegative(const Type &x)
Return true if x is less than zero.
Definition: Math.h:368
Vec3< double > Vec3d
Definition: Vec3.h:668
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:407
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...
@ GRID_LEVEL_SET
Definition: Types.h:337
@ GRID_UNKNOWN
Definition: Types.h:336
math::BBox< Vec3d > BBoxd
Definition: Types.h:84
math::Vec3< Real > Vec3R
Definition: Types.h:72
Definition: Exceptions.h:13
#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:180