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>
21 #include <type_traits>
38 template<
typename Gr
idType>
39 typename GridType::Ptr
49 template<
typename Gr
idType>
50 typename GridType::Ptr
51 clip(
const GridType& grid,
const math::NonlinearFrustumMap& frustum,
bool keepInterior =
true);
65 template<
typename Gr
idType,
typename MaskTreeType>
66 typename GridType::Ptr
67 clip(
const GridType& grid,
const Grid<MaskTreeType>&
mask,
bool keepInterior =
true);
74 namespace clip_internal {
78 using MaskValueType = ValueMask;
82 template<
typename TreeT>
83 class MaskInteriorVoxels
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;
111 template<
typename TreeT>
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; }
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;
136 template<
typename TreeT>
137 CopyLeafNodes<TreeT>::CopyLeafNodes(
const TreeT& tree,
const MaskLeafManagerT& leafNodes)
139 , mLeafNodes(&leafNodes)
140 , mNewTree(new TreeT(mTree->background()))
145 template<
typename TreeT>
146 CopyLeafNodes<TreeT>::CopyLeafNodes(CopyLeafNodes& rhs,
tbb::split)
148 , mLeafNodes(rhs.mLeafNodes)
149 , mNewTree(new TreeT(mTree->background()))
154 template<
typename TreeT>
156 CopyLeafNodes<TreeT>::run(
bool threaded)
158 if (threaded) tbb::parallel_reduce(mLeafNodes->getRange(), *
this);
159 else (*
this)(mLeafNodes->getRange());
163 template<
typename TreeT>
165 CopyLeafNodes<TreeT>::operator()(
const tbb::blocked_range<size_t>&
range)
167 tree::ValueAccessor<TreeT> acc(*mNewTree);
168 tree::ValueAccessor<const TreeT> refAcc(*mTree);
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));
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,
211 return inTree.probeValue(
Coord::floor(inCoord), result);
220 template<
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)); }
230 template<
typename Gr
idT>
231 struct ConvertGrid<GridT, GridT>
233 using GridCPtrT =
typename GridT::ConstPtr;
234 GridCPtrT operator()(
const GridCPtrT& grid) {
return grid; }
244 template<
typename Gr
idT>
246 typename GridT::template ValueConverter<MaskValueType>::Type::Ptr>
::type
247 convertToMaskGrid(
const GridT& grid)
250 auto mask = MaskGridT::create(
false);
251 mask->topologyUnion(grid);
252 mask->setTransform(grid.constTransform().copy());
258 template<
typename Gr
idT>
260 typename GridT::ConstPtr>
::type
261 convertToMaskGrid(
const GridT& grid)
271 template<
typename Gr
idType>
272 typename GridType::Ptr
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);
288 tree::LeafManager<MaskTreeT> leafNodes(gridMask);
289 leafNodes.foreach(MaskInteriorVoxels<TreeT>(tree));
291 tree::ValueAccessor<const TreeT> acc(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();
310 tree::LeafManager<const MaskTreeT> leafNodes(gridMask);
311 CopyLeafNodes<TreeT> maskOp(tree, leafNodes);
313 outGrid->setTree(maskOp.tree());
317 tree::ValueAccessor<const TreeT> refAcc(tree);
318 tree::ValueAccessor<const MaskTreeT> maskAcc(gridMask);
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)) {
327 bool isActive = refAcc.probeValue(ijk, value);
330 if (!isActive) it.setValueOff();
335 outGrid->setTransform(grid.transform().copy());
336 if (gridClass !=
GRID_LEVEL_SET) outGrid->setGridClass(gridClass);
350 template<
typename Gr
idType>
351 typename GridType::Ptr
354 using MaskValueT = clip_internal::MaskValueType;
358 Vec3d idxMin, idxMax;
363 MaskGridT clipMask(
false);
364 clipMask.fill(region,
true,
true);
366 return clip_internal::doClip(grid, clipMask, keepInterior);
371 template<
typename SrcGr
idType,
typename ClipTreeType>
372 typename SrcGridType::Ptr
375 using MaskValueT = clip_internal::MaskValueType;
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());
387 tools::resampleToMatch<clip_internal::BoolSampler>(*maskGrid, *resampledMask);
389 maskGrid = resampledMask;
393 auto clipMask = clip_internal::ConvertGrid<
394 ClipMaskGridType, SrcMaskGridType>()(maskGrid);
397 return clip_internal::doClip(srcGrid, *clipMask, keepInterior);
402 template<
typename Gr
idType>
403 typename GridType::Ptr
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)) {
472 }
else if (frustumIndexBBox.hasOverlap(tileFrustumBBox)) {
473 copyTile = CopyTile::kPartial;
476 if (!frustumIndexBBox.hasOverlap(tileFrustumBBox)) {
478 }
else if (!frustumIndexBBox.isInside(tileFrustumBBox)) {
479 copyTile = CopyTile::kPartial;
483 case CopyTile::kNone:
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());
549 outLeafNodes.foreach(
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)
594 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
601 #endif // OPENVDB_TOOLS_CLIP_HAS_BEEN_INCLUDED
GridType
List of types that are currently supported by NanoVDB.
IMATH_HOSTDEVICE constexpr int floor(T x) IMATH_NOEXCEPT
const BBoxd & getBBox() const
Return the bounding box that defines the frustum in pre-image space.
GLsizei const GLfloat * value
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.
**But if you need a result
bool isNegative(const Type &x)
Return true if x is less than zero.
#define OPENVDB_ALL_TREE_INSTANTIATE(Function)
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 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.
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
#define OPENVDB_VOLUME_TREE_INSTANTIATE(Function)
GLuint const GLchar * name
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.
that also have some descendant prim *whose name begins with which in turn has a child named baz where *the predicate active
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...
void OIIO_UTIL_API split(string_view str, std::vector< string_view > &result, string_view sep=string_view(), int maxsplit=-1)
IMATH_INTERNAL_NAMESPACE_HEADER_ENTER IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T clip(const T &p, const Box< T > &box) IMATH_NOEXCEPT
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...