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
66 clip(
const GridType& grid,
const Grid<MaskTreeType>&
mask,
bool keepInterior =
true);
72 namespace clip_internal {
80 template<
typename TreeT>
84 using ValueT =
typename TreeT::ValueType;
89 template<
typename LeafNodeType>
94 for (
auto iter = leaf.beginValueOff(); iter; ++iter) {
95 const auto pos = iter.pos();
109 template<
typename TreeT>
118 void run(
bool threaded =
true);
120 typename TreeT::Ptr
tree()
const {
return mNewTree; }
123 void operator()(
const tbb::blocked_range<size_t>&);
130 typename TreeT::Ptr mNewTree;
134 template<
typename TreeT>
137 , mLeafNodes(&leafNodes)
138 , mNewTree(new TreeT(mTree->background()))
143 template<
typename TreeT>
146 , mLeafNodes(rhs.mLeafNodes)
147 , mNewTree(new TreeT(mTree->background()))
152 template<
typename TreeT>
156 if (threaded) tbb::parallel_reduce(mLeafNodes->getRange(), *
this);
157 else (*
this)(mLeafNodes->getRange());
161 template<
typename TreeT>
168 for (
auto n = range.begin();
n != range.end(); ++
n) {
169 const auto& maskLeaf = mLeafNodes->leaf(
n);
170 const auto& ijk = maskLeaf.origin();
176 for (
auto it = maskLeaf.cbeginValueOn(); it; ++it) {
177 const auto pos = it.pos();
178 newLeaf->setValueOnly(pos, refLeaf->getValue(pos));
179 newLeaf->setActiveState(pos, refLeaf->isValueOn(pos));
182 typename TreeT::ValueType
value;
183 bool isActive = refAcc.
probeValue(ijk, value);
185 for (
auto it = maskLeaf.cbeginValueOn(); it; ++it) {
186 const auto pos = it.pos();
187 newLeaf->setValueOnly(pos, value);
188 newLeaf->setActiveState(pos, isActive);
200 static const char*
name() {
return "bin"; }
205 template<
class TreeT>
207 const Vec3R& inCoord,
typename TreeT::ValueType&
result)
209 return inTree.probeValue(
Coord::floor(inCoord), result);
218 template<
typename FromGr
idT,
typename ToGr
idT>
228 template<
typename Gr
idT>
242 template<
typename Gr
idT>
244 typename GridT::template ValueConverter<MaskValueType>::Type::Ptr>
::type
245 convertToMaskGrid(
const GridT& grid)
248 auto mask = MaskGridT::create(
false);
249 mask->topologyUnion(grid);
250 mask->setTransform(grid.constTransform().copy());
256 template<
typename Gr
idT>
258 typename GridT::ConstPtr>
::type
259 convertToMaskGrid(
const GridT& grid)
269 template<
typename Gr
idType>
270 inline typename GridType::Ptr
272 const GridType& grid,
273 const typename GridType::template ValueConverter<MaskValueType>::Type& clipMask,
276 using TreeT =
typename GridType::TreeType;
277 using MaskTreeT =
typename GridType::TreeType::template ValueConverter<MaskValueType>::Type;
279 const auto gridClass = grid.getGridClass();
280 const auto& tree = grid.tree();
282 MaskTreeT gridMask(
false);
283 gridMask.topologyUnion(tree);
286 tree::LeafManager<MaskTreeT> leafNodes(gridMask);
287 leafNodes.foreach(MaskInteriorVoxels<TreeT>(tree));
289 tree::ValueAccessor<const TreeT> acc(tree);
291 typename MaskTreeT::ValueAllIter iter(gridMask);
292 iter.setMaxDepth(MaskTreeT::ValueAllIter::LEAF_DEPTH - 1);
294 for ( ; iter; ++iter) {
300 gridMask.topologyIntersection(clipMask.constTree());
302 gridMask.topologyDifference(clipMask.constTree());
305 auto outGrid = grid.copyWithNewTree();
308 tree::LeafManager<const MaskTreeT> leafNodes(gridMask);
309 CopyLeafNodes<TreeT> maskOp(tree, leafNodes);
311 outGrid->setTree(maskOp.tree());
315 tree::ValueAccessor<const TreeT> refAcc(tree);
316 tree::ValueAccessor<const MaskTreeT> maskAcc(gridMask);
318 typename TreeT::ValueAllIter it(outGrid->tree());
319 it.setMaxDepth(TreeT::ValueAllIter::LEAF_DEPTH - 1);
321 Coord ijk = it.getCoord();
323 if (maskAcc.isValueOn(ijk)) {
324 typename TreeT::ValueType
value;
325 bool isActive = refAcc.probeValue(ijk, value);
328 if (!isActive) it.setValueOff();
333 outGrid->setTransform(grid.transform().copy());
334 if (gridClass !=
GRID_LEVEL_SET) outGrid->setGridClass(gridClass);
346 template<
typename Gr
idType>
347 inline typename GridType::Ptr
348 clip(
const GridType& grid,
const BBoxd& bbox,
bool keepInterior)
354 Vec3d idxMin, idxMax;
359 MaskGridT clipMask(
false);
360 clipMask.fill(region,
true,
true);
362 return clip_internal::doClip(grid, clipMask, keepInterior);
367 template<
typename SrcGr
idType,
typename ClipTreeType>
368 inline typename SrcGridType::Ptr
374 using ClipMaskGridType =
typename ClipGridType::template ValueConverter<MaskValueT>::Type;
377 auto maskGrid = clip_internal::convertToMaskGrid(clipGrid);
380 if (srcGrid.constTransform() != maskGrid->constTransform()) {
381 auto resampledMask = ClipMaskGridType::create(
false);
382 resampledMask->setTransform(srcGrid.constTransform().copy());
383 tools::resampleToMatch<clip_internal::BoolSampler>(*maskGrid, *resampledMask);
385 maskGrid = resampledMask;
389 auto clipMask = clip_internal::ConvertGrid<
390 ClipMaskGridType, SrcMaskGridType>()(maskGrid);
393 return clip_internal::doClip(srcGrid, *clipMask, keepInterior);
398 template<
typename Gr
idType>
399 inline typename GridType::Ptr
402 using ValueT =
typename GridType::ValueType;
403 using TreeT =
typename GridType::TreeType;
404 using LeafT =
typename TreeT::LeafNodeType;
406 const auto& gridXform = inGrid.transform();
407 const auto frustumIndexBBox = frustumMap.
getBBox();
410 auto frustumContainsCoord = [&](
const Coord& ijk) ->
bool {
411 auto xyz = gridXform.indexToWorld(ijk);
413 return frustumIndexBBox.isInside(xyz);
418 auto toFrustumIndexSpace = [&](
const CoordBBox& inBBox) ->
BBoxd {
419 const Coord bounds[2] = { inBBox.
min(), inBBox.max() };
422 for (
int i = 0; i < 8; ++i) {
423 ijk[0] = bounds[(i & 1) >> 0][0];
424 ijk[1] = bounds[(i & 2) >> 1][1];
425 ijk[2] = bounds[(i & 4) >> 2][2];
426 auto xyz = gridXform.indexToWorld(ijk);
434 auto outGrid = inGrid.copyWithNewTree();
440 const auto& bg = outGrid->background();
442 auto outAcc = outGrid->getAccessor();
448 auto tileIter = inGrid.beginValueAll();
449 tileIter.setMaxDepth(GridType::ValueAllIter::LEAF_DEPTH - 1);
451 for ( ; tileIter; ++tileIter) {
452 const bool tileActive = tileIter.isValueOn();
453 const auto& tileValue = tileIter.getValue();
459 tileIter.getBoundingBox(tileBBox);
460 const auto tileFrustumBBox = toFrustumIndexSpace(tileBBox);
463 enum class CopyTile { kNone, kPartial,
kFull };
464 auto copyTile = CopyTile::kNone;
466 if (frustumIndexBBox.isInside(tileFrustumBBox)) {
468 }
else if (frustumIndexBBox.hasOverlap(tileFrustumBBox)) {
469 copyTile = CopyTile::kPartial;
472 if (!frustumIndexBBox.hasOverlap(tileFrustumBBox)) {
474 }
else if (!frustumIndexBBox.isInside(tileFrustumBBox)) {
475 copyTile = CopyTile::kPartial;
479 case CopyTile::kNone:
483 outAcc.addTile(tileIter.getLevel(), tileBBox.min(), tileValue, tileActive);
485 case CopyTile::kPartial:
487 for (std::vector<CoordBBox> bboxVec = { tileBBox }; !bboxVec.empty(); ) {
492 if (bboxVec.back().volume() > 64 && bboxVec.back().is_divisible()) {
494 bboxVec.emplace_back(bboxVec.back(),
tbb::split{});
497 auto subBBox = bboxVec.back();
502 if (!frustumIndexBBox.hasOverlap(toFrustumIndexSpace(subBBox)))
continue;
504 if (frustumIndexBBox.isInside(toFrustumIndexSpace(subBBox)))
continue;
508 for (
const auto& ijk: subBBox) {
509 if (frustumContainsCoord(ijk) == keepInterior) {
511 outAcc.setValueOn(ijk, tileValue);
513 outAcc.setValueOff(ijk, tileValue);
526 for (
auto leafIter = inGrid.constTree().beginLeaf(); leafIter; ++leafIter) {
527 const auto leafBBox = leafIter->getNodeBoundingBox();
528 const auto leafFrustumBBox = toFrustumIndexSpace(leafBBox);
530 if (frustumIndexBBox.hasOverlap(leafFrustumBBox)) {
531 outAcc.touchLeaf(leafBBox.min());
534 if (!frustumIndexBBox.hasOverlap(leafFrustumBBox)
535 || !frustumIndexBBox.isInside(leafFrustumBBox))
537 outAcc.touchLeaf(leafBBox.min());
545 outLeafNodes.foreach(
546 [&](LeafT& leaf,
size_t ) {
547 auto inAcc = inGrid.getConstAccessor();
549 for (
auto voxelIter = leaf.beginValueAll(); voxelIter; ++voxelIter) {
550 const auto ijk = voxelIter.getCoord();
551 if (frustumContainsCoord(ijk) == keepInterior) {
552 const bool active = inAcc.probeValue(ijk, val);
553 voxelIter.setValue(val);
554 voxelIter.setValueOn(active);
567 #endif // OPENVDB_TOOLS_CLIP_HAS_BEEN_INCLUDED
const BBoxd & getBBox() const
Return the bounding box that defines the frustum in pre-image space.
GLuint const GLfloat * val
const TreeType & tree() const
Return a const reference to tree associated with this manager.
This map is composed of three steps. First it will take a box of size (Lx X Ly X Lz) defined by a mem...
#define OPENVDB_USE_VERSION_NAMESPACE
void expand(ElementType padding)
Pad this bounding box.
bool isNegative(const Type &x)
Return true if x is less than zero.
void OIIO_API split(string_view str, std::vector< string_view > &result, string_view sep=string_view(), int maxsplit=-1)
bool isApproxEqual(const Type &a, const Type &b, const Type &tolerance)
Return true if a is equal to b to within the given tolerance.
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...
const Vec3T & min() const
Return a const reference to the minimum point of this bounding box.
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
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...
Defined various multi-threaded utility functions for trees.
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.
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
GLuint GLuint GLsizei GLenum type
Container class that associates a tree with a transform and metadata.
const Vec3T & max() const
Return a const reference to the maximum point of this bounding box.
Vec3d applyInverseMap(const Vec3d &in) const override
Return the pre-image of in under the map.
math::BBox< Vec3d > BBoxd
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
GLsizei const GLfloat * value
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.