36 #ifndef OPENVDB_TOOLS_CLIP_HAS_BEEN_INCLUDED 37 #define OPENVDB_TOOLS_CLIP_HAS_BEEN_INCLUDED 45 #include <tbb/blocked_range.h> 46 #include <tbb/parallel_reduce.h> 47 #include <type_traits> 64 template<
typename Gr
idType>
65 inline typename GridType::Ptr
66 clip(
const GridType& grid,
const BBoxd& bbox,
bool keepInterior =
true);
75 template<
typename Gr
idType>
76 inline typename GridType::Ptr
77 clip(
const GridType& grid,
const math::NonlinearFrustumMap& frustum,
bool keepInterior =
true);
91 template<
typename Gr
idType,
typename MaskTreeType>
92 inline typename GridType::Ptr
93 clip(
const GridType& grid,
const Grid<MaskTreeType>& mask,
bool keepInterior =
true);
99 namespace clip_internal {
107 template<
typename TreeT>
111 using ValueT =
typename TreeT::ValueType;
116 template<
typename LeafNodeType>
119 const auto* refLeaf = mAcc.probeConstLeaf(leaf.origin());
121 for (
auto iter = leaf.beginValueOff(); iter; ++iter) {
122 const auto pos = iter.pos();
136 template<
typename TreeT>
140 using MaskTreeT =
typename TreeT::template ValueConverter<MaskValueType>::Type;
145 void run(
bool threaded =
true);
147 typename TreeT::Ptr
tree()
const {
return mNewTree; }
150 void operator()(
const tbb::blocked_range<size_t>&);
157 typename TreeT::Ptr mNewTree;
161 template<
typename TreeT>
164 , mLeafNodes(&leafNodes)
165 , mNewTree(new TreeT(mTree->background()))
170 template<
typename TreeT>
173 , mLeafNodes(rhs.mLeafNodes)
174 , mNewTree(new TreeT(mTree->background()))
179 template<
typename TreeT>
183 if (threaded) tbb::parallel_reduce(mLeafNodes->
getRange(), *
this);
184 else (*
this)(mLeafNodes->
getRange());
188 template<
typename TreeT>
195 for (
auto n = range.begin(); n != range.end(); ++n) {
196 const auto& maskLeaf = mLeafNodes->
leaf(n);
197 const auto& ijk = maskLeaf.origin();
203 for (
auto it = maskLeaf.cbeginValueOn(); it; ++it) {
204 const auto pos = it.pos();
205 newLeaf->setValueOnly(pos, refLeaf->getValue(pos));
206 newLeaf->setActiveState(pos, refLeaf->isValueOn(pos));
209 typename TreeT::ValueType value;
210 bool isActive = refAcc.
probeValue(ijk, value);
212 for (
auto it = maskLeaf.cbeginValueOn(); it; ++it) {
213 const auto pos = it.pos();
214 newLeaf->setValueOnly(pos, value);
215 newLeaf->setActiveState(pos, isActive);
227 static const char*
name() {
return "bin"; }
232 template<
class TreeT>
234 const Vec3R& inCoord,
typename TreeT::ValueType& result)
236 return inTree.probeValue(
Coord::floor(inCoord), result);
245 template<
typename FromGr
idT,
typename ToGr
idT>
255 template<
typename Gr
idT>
269 template<
typename Gr
idT>
270 inline typename std::enable_if<!std::is_same<MaskValueType, typename GridT::BuildType>::value,
271 typename GridT::template ValueConverter<MaskValueType>::Type::Ptr>::type
272 convertToMaskGrid(
const GridT& grid)
274 using MaskGridT =
typename GridT::template ValueConverter<MaskValueType>::Type;
275 auto mask = MaskGridT::create(
false);
276 mask->topologyUnion(grid);
277 mask->setTransform(grid.constTransform().copy());
283 template<
typename Gr
idT>
284 inline typename std::enable_if<std::is_same<MaskValueType, typename GridT::BuildType>::value,
285 typename GridT::ConstPtr>::type
286 convertToMaskGrid(
const GridT& grid)
296 template<
typename Gr
idType>
297 inline typename GridType::Ptr
299 const GridType& grid,
300 const typename GridType::template ValueConverter<MaskValueType>::Type& clipMask,
303 using TreeT =
typename GridType::TreeType;
304 using MaskTreeT =
typename GridType::TreeType::template ValueConverter<MaskValueType>::Type;
306 const auto gridClass = grid.getGridClass();
307 const auto&
tree = grid.tree();
310 gridMask.topologyUnion(
tree);
318 typename MaskTreeT::ValueAllIter iter(gridMask);
319 iter.setMaxDepth(MaskTreeT::ValueAllIter::LEAF_DEPTH - 1);
321 for ( ; iter; ++iter) {
327 gridMask.topologyIntersection(clipMask.constTree());
329 gridMask.topologyDifference(clipMask.constTree());
332 #if OPENVDB_ABI_VERSION_NUMBER <= 3 333 auto outGrid = grid.copy(CP_NEW);
335 auto outGrid = grid.copyWithNewTree();
342 outGrid->setTree(maskOp.
tree());
349 typename TreeT::ValueAllIter it(outGrid->tree());
350 it.setMaxDepth(TreeT::ValueAllIter::LEAF_DEPTH - 1);
352 Coord ijk = it.getCoord();
355 typename TreeT::ValueType value;
356 bool isActive = refAcc.
probeValue(ijk, value);
359 if (!isActive) it.setValueOff();
364 outGrid->setTransform(grid.transform().copy());
365 if (gridClass !=
GRID_LEVEL_SET) outGrid->setGridClass(gridClass);
377 template<
typename Gr
idType>
378 inline typename GridType::Ptr
379 clip(
const GridType& grid,
const BBoxd& bbox,
bool keepInterior)
382 using MaskGridT =
typename GridType::template ValueConverter<MaskValueT>::Type;
385 Vec3d idxMin, idxMax;
390 MaskGridT clipMask(
false);
391 clipMask.fill(region,
true,
true);
393 return clip_internal::doClip(grid, clipMask, keepInterior);
398 template<
typename SrcGr
idType,
typename ClipTreeType>
399 inline typename SrcGridType::Ptr
404 using SrcMaskGridType =
typename SrcGridType::template ValueConverter<MaskValueT>::Type;
405 using ClipMaskGridType =
typename ClipGridType::template ValueConverter<MaskValueT>::Type;
408 auto maskGrid = clip_internal::convertToMaskGrid(clipGrid);
411 if (srcGrid.constTransform() != maskGrid->constTransform()) {
412 auto resampledMask = ClipMaskGridType::create(
false);
413 resampledMask->setTransform(srcGrid.constTransform().copy());
414 tools::resampleToMatch<clip_internal::BoolSampler>(*maskGrid, *resampledMask);
416 maskGrid = resampledMask;
421 ClipMaskGridType, SrcMaskGridType>()(maskGrid);
424 return clip_internal::doClip(srcGrid, *clipMask, keepInterior);
429 template<
typename Gr
idType>
430 inline typename GridType::Ptr
433 using ValueT =
typename GridType::ValueType;
434 using TreeT =
typename GridType::TreeType;
435 using LeafT =
typename TreeT::LeafNodeType;
437 const auto& gridXform = inGrid.transform();
438 const auto frustumIndexBBox = frustumMap.
getBBox();
441 auto frustumContainsCoord = [&](
const Coord& ijk) ->
bool {
442 auto xyz = gridXform.indexToWorld(ijk);
444 return frustumIndexBBox.isInside(xyz);
449 auto toFrustumIndexSpace = [&](
const CoordBBox& inBBox) ->
BBoxd {
450 const Coord bounds[2] = { inBBox.
min(), inBBox.
max() };
453 for (
int i = 0; i < 8; ++i) {
454 ijk[0] = bounds[(i & 1) >> 0][0];
455 ijk[1] = bounds[(i & 2) >> 1][1];
456 ijk[2] = bounds[(i & 4) >> 2][2];
457 auto xyz = gridXform.indexToWorld(ijk);
465 #if OPENVDB_ABI_VERSION_NUMBER <= 3 466 auto outGrid = inGrid.copy(CP_NEW);
468 auto outGrid = inGrid.copyWithNewTree();
475 const auto& bg = outGrid->background();
477 auto outAcc = outGrid->getAccessor();
483 auto tileIter = inGrid.beginValueAll();
484 tileIter.setMaxDepth(GridType::ValueAllIter::LEAF_DEPTH - 1);
486 for ( ; tileIter; ++tileIter) {
487 const bool tileActive = tileIter.isValueOn();
488 const auto& tileValue = tileIter.getValue();
494 tileIter.getBoundingBox(tileBBox);
495 const auto tileFrustumBBox = toFrustumIndexSpace(tileBBox);
498 enum class CopyTile { kNone, kPartial, kFull };
499 auto copyTile = CopyTile::kNone;
501 if (frustumIndexBBox.isInside(tileFrustumBBox)) {
502 copyTile = CopyTile::kFull;
503 }
else if (frustumIndexBBox.hasOverlap(tileFrustumBBox)) {
504 copyTile = CopyTile::kPartial;
507 if (!frustumIndexBBox.hasOverlap(tileFrustumBBox)) {
508 copyTile = CopyTile::kFull;
509 }
else if (!frustumIndexBBox.isInside(tileFrustumBBox)) {
510 copyTile = CopyTile::kPartial;
514 case CopyTile::kNone:
516 case CopyTile::kFull:
518 outAcc.addTile(tileIter.getLevel(), tileBBox.
min(), tileValue, tileActive);
520 case CopyTile::kPartial:
522 for (std::vector<CoordBBox> bboxVec = { tileBBox }; !bboxVec.
empty(); ) {
527 if (bboxVec.back().volume() > 64 && bboxVec.back().is_divisible()) {
529 bboxVec.emplace_back(bboxVec.back(), tbb::split{});
532 auto subBBox = bboxVec.back();
537 if (!frustumIndexBBox.hasOverlap(toFrustumIndexSpace(subBBox)))
continue;
539 if (frustumIndexBBox.isInside(toFrustumIndexSpace(subBBox)))
continue;
543 for (
const auto& ijk: subBBox) {
544 if (frustumContainsCoord(ijk) == keepInterior) {
546 outAcc.setValueOn(ijk, tileValue);
548 outAcc.setValueOff(ijk, tileValue);
561 for (
auto leafIter = inGrid.constTree().beginLeaf(); leafIter; ++leafIter) {
562 const auto leafBBox = leafIter->getNodeBoundingBox();
563 const auto leafFrustumBBox = toFrustumIndexSpace(leafBBox);
565 if (frustumIndexBBox.hasOverlap(leafFrustumBBox)) {
566 outAcc.touchLeaf(leafBBox.min());
569 if (!frustumIndexBBox.hasOverlap(leafFrustumBBox)
570 || !frustumIndexBBox.isInside(leafFrustumBBox))
572 outAcc.touchLeaf(leafBBox.min());
580 outLeafNodes.foreach(
581 [&](LeafT& leaf,
size_t ) {
582 auto inAcc = inGrid.getConstAccessor();
584 for (
auto voxelIter = leaf.beginValueAll(); voxelIter; ++voxelIter) {
585 const auto ijk = voxelIter.getCoord();
586 if (frustumContainsCoord(ijk) == keepInterior) {
587 const bool active = inAcc.probeValue(ijk, val);
588 voxelIter.setValue(val);
589 voxelIter.setValueOn(active);
602 #endif // OPENVDB_TOOLS_CLIP_HAS_BEEN_INCLUDED
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
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:1905
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Return a pointer to the leaf node that contains voxel (x, y, z), or nullptr if no such node exists...
Definition: ValueAccessor.h:422
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...
static Coord floor(const Vec3< T > &xyz)
Return the largest integer coordinates that are not greater than xyz (node centered conversion)...
Definition: Coord.h:84
const Vec3T & max() const
Return a const reference to the maximum point of this bounding box.
Definition: BBox.h:91
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:52
LeafNodeT * touchLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, create one, but preserve the values and active states of all voxels.
Definition: ValueAccessor.h:386
math::BBox< Vec3d > BBoxd
Definition: Types.h:91
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:55
Vec3< double > Vec3d
Definition: Vec3.h:689
Defined various multi-threaded utility functions for trees.
Vec3d applyInverseMap(const Vec3d &in) const override
Return the pre-image of in under the map.
Definition: Maps.h:2117
void expand(ElementType padding)
Pad this bounding box.
Definition: BBox.h:348
const Coord & min() const
Definition: Coord.h:348
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:128
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:264
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:275
bool isApproxEqual(const Type &a, const Type &b)
Return true if a is equal to b to within the default floating-point comparison tolerance.
Definition: Math.h:378
bool isNegative(const Type &x)
Return true if x is less than zero.
Definition: Math.h:338
Definition: Exceptions.h:40
const BBoxd & getBBox() const
Return the bounding box that defines the frustum in pre-image space.
Definition: Maps.h:2377
LeafType & leaf(size_t leafIdx) const
Return a pointer to the leaf node at index leafIdx in the array.
Definition: LeafManager.h:358
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:257
static Coord min()
Return the smallest possible coordinate.
Definition: Coord.h:71
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
Definition: ValueAccessor.h:267
const TreeType & tree() const
Return a const reference to tree associated with this manager.
Definition: LeafManager.h:342
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:109
const Vec3T & min() const
Return a const reference to the minimum point of this bounding box.
Definition: BBox.h:89
RangeType getRange(size_t grainsize=1) const
Return a tbb::blocked_range of leaf array indices.
Definition: LeafManager.h:382
static Coord max()
Return the largest possible coordinate.
Definition: Coord.h:74
#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
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:523