HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Clip.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @file Clip.h
5 ///
6 /// @brief Functions to clip a grid against a bounding box, a camera frustum,
7 /// or another grid's active voxel topology
8 
9 #ifndef OPENVDB_TOOLS_CLIP_HAS_BEEN_INCLUDED
10 #define OPENVDB_TOOLS_CLIP_HAS_BEEN_INCLUDED
11 
12 #include <openvdb/Grid.h>
13 #include <openvdb/math/Math.h> // for math::isNegative()
14 #include <openvdb/math/Maps.h> // for math::NonlinearFrustumMap
16 #include "GridTransformer.h" // for tools::resampleToMatch()
17 #include "Prune.h"
18 #include <tbb/blocked_range.h>
19 #include <tbb/parallel_reduce.h>
20 #include <type_traits> // for std::enable_if, std::is_same
21 #include <vector>
22 
23 
24 namespace openvdb {
26 namespace OPENVDB_VERSION_NAME {
27 namespace tools {
28 
29 /// @brief Clip the given grid against a world-space bounding box
30 /// and return a new grid containing the result.
31 /// @param grid the grid to be clipped
32 /// @param bbox a world-space bounding box
33 /// @param keepInterior if true, discard voxels that lie outside the bounding box;
34 /// if false, discard voxels that lie inside the bounding box
35 /// @warning Clipping a level set will likely produce a grid that is
36 /// no longer a valid level set.
37 template<typename GridType>
38 inline typename GridType::Ptr
39 clip(const GridType& grid, const BBoxd& bbox, bool keepInterior = true);
40 
41 /// @brief Clip the given grid against a frustum and return a new grid containing the result.
42 /// @param grid the grid to be clipped
43 /// @param frustum a frustum map
44 /// @param keepInterior if true, discard voxels that lie outside the frustum;
45 /// if false, discard voxels that lie inside the frustum
46 /// @warning Clipping a level set will likely produce a grid that is
47 /// no longer a valid level set.
48 template<typename GridType>
49 inline typename GridType::Ptr
50 clip(const GridType& grid, const math::NonlinearFrustumMap& frustum, bool keepInterior = true);
51 
52 /// @brief Clip a grid against the active voxels of another grid
53 /// and return a new grid containing the result.
54 /// @param grid the grid to be clipped
55 /// @param mask a grid whose active voxels form a boolean clipping mask
56 /// @param keepInterior if true, discard voxels that do not intersect the mask;
57 /// if false, discard voxels that intersect the mask
58 /// @details The mask grid need not have the same transform as the source grid.
59 /// Also, if the mask grid is a level set, consider using tools::sdfInteriorMask
60 /// to construct a new mask comprising the interior (rather than the narrow band)
61 /// of the level set.
62 /// @warning Clipping a level set will likely produce a grid that is
63 /// no longer a valid level set.
64 template<typename GridType, typename MaskTreeType>
65 inline typename GridType::Ptr
66 clip(const GridType& grid, const Grid<MaskTreeType>& mask, bool keepInterior = true);
67 
68 
69 ////////////////////////////////////////
70 
71 
72 namespace clip_internal {
73 
74 // Use either MaskGrids or BoolGrids internally.
75 // (MaskGrids have a somewhat lower memory footprint.)
77 //using MaskValueType = bool;
78 
79 
80 template<typename TreeT>
82 {
83 public:
84  using ValueT = typename TreeT::ValueType;
85  using LeafNodeT = typename TreeT::LeafNodeType;
86 
87  MaskInteriorVoxels(const TreeT& tree): mAcc(tree) {}
88 
89  template<typename LeafNodeType>
90  void operator()(LeafNodeType& leaf, size_t /*leafIndex*/) const
91  {
92  const auto* refLeaf = mAcc.probeConstLeaf(leaf.origin());
93  if (refLeaf) {
94  for (auto iter = leaf.beginValueOff(); iter; ++iter) {
95  const auto pos = iter.pos();
96  leaf.setActiveState(pos, math::isNegative(refLeaf->getValue(pos)));
97  }
98  }
99  }
100 
101 private:
103 };
104 
105 
106 ////////////////////////////////////////
107 
108 
109 template<typename TreeT>
111 {
112 public:
113  using MaskTreeT = typename TreeT::template ValueConverter<MaskValueType>::Type;
115 
116  CopyLeafNodes(const TreeT&, const MaskLeafManagerT&);
117 
118  void run(bool threaded = true);
119 
120  typename TreeT::Ptr tree() const { return mNewTree; }
121 
123  void operator()(const tbb::blocked_range<size_t>&);
124  void join(const CopyLeafNodes& rhs) { mNewTree->merge(*rhs.mNewTree); }
125 
126 private:
127  const MaskTreeT* mClipMask;
128  const TreeT* mTree;
129  const MaskLeafManagerT* mLeafNodes;
130  typename TreeT::Ptr mNewTree;
131 };
132 
133 
134 template<typename TreeT>
135 CopyLeafNodes<TreeT>::CopyLeafNodes(const TreeT& tree, const MaskLeafManagerT& leafNodes)
136  : mTree(&tree)
137  , mLeafNodes(&leafNodes)
138  , mNewTree(new TreeT(mTree->background()))
139 {
140 }
141 
142 
143 template<typename TreeT>
145  : mTree(rhs.mTree)
146  , mLeafNodes(rhs.mLeafNodes)
147  , mNewTree(new TreeT(mTree->background()))
148 {
149 }
150 
151 
152 template<typename TreeT>
153 void
155 {
156  if (threaded) tbb::parallel_reduce(mLeafNodes->getRange(), *this);
157  else (*this)(mLeafNodes->getRange());
158 }
159 
160 
161 template<typename TreeT>
162 void
163 CopyLeafNodes<TreeT>::operator()(const tbb::blocked_range<size_t>& range)
164 {
165  tree::ValueAccessor<TreeT> acc(*mNewTree);
166  tree::ValueAccessor<const TreeT> refAcc(*mTree);
167 
168  for (auto n = range.begin(); n != range.end(); ++n) {
169  const auto& maskLeaf = mLeafNodes->leaf(n);
170  const auto& ijk = maskLeaf.origin();
171  const auto* refLeaf = refAcc.probeConstLeaf(ijk);
172 
173  auto* newLeaf = acc.touchLeaf(ijk);
174 
175  if (refLeaf) {
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));
180  }
181  } else {
182  typename TreeT::ValueType value;
183  bool isActive = refAcc.probeValue(ijk, value);
184 
185  for (auto it = maskLeaf.cbeginValueOn(); it; ++it) {
186  const auto pos = it.pos();
187  newLeaf->setValueOnly(pos, value);
188  newLeaf->setActiveState(pos, isActive);
189  }
190  }
191  }
192 }
193 
194 
195 ////////////////////////////////////////
196 
197 
199 {
200  static const char* name() { return "bin"; }
201  static int radius() { return 2; }
202  static bool mipmap() { return false; }
203  static bool consistent() { return true; }
204 
205  template<class TreeT>
206  static bool sample(const TreeT& inTree,
207  const Vec3R& inCoord, typename TreeT::ValueType& result)
208  {
209  return inTree.probeValue(Coord::floor(inCoord), result);
210  }
211 };
212 
213 
214 ////////////////////////////////////////
215 
216 
217 // Convert a grid of one type to a grid of another type
218 template<typename FromGridT, typename ToGridT>
220 {
221  using FromGridCPtrT = typename FromGridT::ConstPtr;
222  using ToGridPtrT = typename ToGridT::Ptr;
223  ToGridPtrT operator()(const FromGridCPtrT& grid) { return ToGridPtrT(new ToGridT(*grid)); }
224 };
225 
226 // Partial specialization that avoids copying when
227 // the input and output grid types are the same
228 template<typename GridT>
229 struct ConvertGrid<GridT, GridT>
230 {
231  using GridCPtrT = typename GridT::ConstPtr;
232  GridCPtrT operator()(const GridCPtrT& grid) { return grid; }
233 };
234 
235 
236 ////////////////////////////////////////
237 
238 
239 // Convert a grid of arbitrary type to a mask grid with the same tree configuration
240 // and return a pointer to the new grid.
241 /// @private
242 template<typename GridT>
244  typename GridT::template ValueConverter<MaskValueType>::Type::Ptr>::type
245 convertToMaskGrid(const GridT& grid)
246 {
247  using MaskGridT = typename GridT::template ValueConverter<MaskValueType>::Type;
248  auto mask = MaskGridT::create(/*background=*/false);
249  mask->topologyUnion(grid);
250  mask->setTransform(grid.constTransform().copy());
251  return mask;
252 }
253 
254 // Overload that avoids any processing if the input grid is already a mask grid
255 /// @private
256 template<typename GridT>
258  typename GridT::ConstPtr>::type
259 convertToMaskGrid(const GridT& grid)
260 {
261  return grid.copy(); // shallow copy
262 }
263 
264 
265 ////////////////////////////////////////
266 
267 
268 /// @private
269 template<typename GridType>
270 inline typename GridType::Ptr
271 doClip(
272  const GridType& grid,
273  const typename GridType::template ValueConverter<MaskValueType>::Type& clipMask,
274  bool keepInterior)
275 {
276  using TreeT = typename GridType::TreeType;
277  using MaskTreeT = typename GridType::TreeType::template ValueConverter<MaskValueType>::Type;
278 
279  const auto gridClass = grid.getGridClass();
280  const auto& tree = grid.tree();
281 
282  MaskTreeT gridMask(false);
283  gridMask.topologyUnion(tree);
284 
285  if (gridClass == GRID_LEVEL_SET) {
286  tree::LeafManager<MaskTreeT> leafNodes(gridMask);
287  leafNodes.foreach(MaskInteriorVoxels<TreeT>(tree));
288 
289  tree::ValueAccessor<const TreeT> acc(tree);
290 
291  typename MaskTreeT::ValueAllIter iter(gridMask);
292  iter.setMaxDepth(MaskTreeT::ValueAllIter::LEAF_DEPTH - 1);
293 
294  for ( ; iter; ++iter) {
295  iter.setActiveState(math::isNegative(acc.getValue(iter.getCoord())));
296  }
297  }
298 
299  if (keepInterior) {
300  gridMask.topologyIntersection(clipMask.constTree());
301  } else {
302  gridMask.topologyDifference(clipMask.constTree());
303  }
304 
305  auto outGrid = grid.copyWithNewTree();
306  {
307  // Copy voxel values and states.
308  tree::LeafManager<const MaskTreeT> leafNodes(gridMask);
309  CopyLeafNodes<TreeT> maskOp(tree, leafNodes);
310  maskOp.run();
311  outGrid->setTree(maskOp.tree());
312  }
313  {
314  // Copy tile values and states.
315  tree::ValueAccessor<const TreeT> refAcc(tree);
316  tree::ValueAccessor<const MaskTreeT> maskAcc(gridMask);
317 
318  typename TreeT::ValueAllIter it(outGrid->tree());
319  it.setMaxDepth(TreeT::ValueAllIter::LEAF_DEPTH - 1);
320  for ( ; it; ++it) {
321  Coord ijk = it.getCoord();
322 
323  if (maskAcc.isValueOn(ijk)) {
324  typename TreeT::ValueType value;
325  bool isActive = refAcc.probeValue(ijk, value);
326 
327  it.setValue(value);
328  if (!isActive) it.setValueOff();
329  }
330  }
331  }
332 
333  outGrid->setTransform(grid.transform().copy());
334  if (gridClass != GRID_LEVEL_SET) outGrid->setGridClass(gridClass);
335 
336  return outGrid;
337 }
338 
339 } // namespace clip_internal
340 
341 
342 ////////////////////////////////////////
343 
344 
345 /// @private
346 template<typename GridType>
347 inline typename GridType::Ptr
348 clip(const GridType& grid, const BBoxd& bbox, bool keepInterior)
349 {
350  using MaskValueT = clip_internal::MaskValueType;
351  using MaskGridT = typename GridType::template ValueConverter<MaskValueT>::Type;
352 
353  // Transform the world-space bounding box into the source grid's index space.
354  Vec3d idxMin, idxMax;
355  math::calculateBounds(grid.constTransform(), bbox.min(), bbox.max(), idxMin, idxMax);
356  CoordBBox region(Coord::floor(idxMin), Coord::floor(idxMax));
357  // Construct a boolean mask grid that is true inside the index-space bounding box
358  // and false everywhere else.
359  MaskGridT clipMask(/*background=*/false);
360  clipMask.fill(region, /*value=*/true, /*active=*/true);
361 
362  return clip_internal::doClip(grid, clipMask, keepInterior);
363 }
364 
365 
366 /// @private
367 template<typename SrcGridType, typename ClipTreeType>
368 inline typename SrcGridType::Ptr
369 clip(const SrcGridType& srcGrid, const Grid<ClipTreeType>& clipGrid, bool keepInterior)
370 {
371  using MaskValueT = clip_internal::MaskValueType;
372  using ClipGridType = Grid<ClipTreeType>;
373  using SrcMaskGridType = typename SrcGridType::template ValueConverter<MaskValueT>::Type;
374  using ClipMaskGridType = typename ClipGridType::template ValueConverter<MaskValueT>::Type;
375 
376  // Convert the clipping grid to a boolean-valued mask grid with the same tree configuration.
377  auto maskGrid = clip_internal::convertToMaskGrid(clipGrid);
378 
379  // Resample the mask grid into the source grid's index space.
380  if (srcGrid.constTransform() != maskGrid->constTransform()) {
381  auto resampledMask = ClipMaskGridType::create(/*background=*/false);
382  resampledMask->setTransform(srcGrid.constTransform().copy());
383  tools::resampleToMatch<clip_internal::BoolSampler>(*maskGrid, *resampledMask);
384  tools::prune(resampledMask->tree());
385  maskGrid = resampledMask;
386  }
387 
388  // Convert the mask grid to a mask grid with the same tree configuration as the source grid.
389  auto clipMask = clip_internal::ConvertGrid<
390  /*from=*/ClipMaskGridType, /*to=*/SrcMaskGridType>()(maskGrid);
391 
392  // Clip the source grid against the mask grid.
393  return clip_internal::doClip(srcGrid, *clipMask, keepInterior);
394 }
395 
396 
397 /// @private
398 template<typename GridType>
399 inline typename GridType::Ptr
400 clip(const GridType& inGrid, const math::NonlinearFrustumMap& frustumMap, bool keepInterior)
401 {
402  using ValueT = typename GridType::ValueType;
403  using TreeT = typename GridType::TreeType;
404  using LeafT = typename TreeT::LeafNodeType;
405 
406  const auto& gridXform = inGrid.transform();
407  const auto frustumIndexBBox = frustumMap.getBBox();
408 
409  // Return true if index-space point (i,j,k) lies inside the frustum.
410  auto frustumContainsCoord = [&](const Coord& ijk) -> bool {
411  auto xyz = gridXform.indexToWorld(ijk);
412  xyz = frustumMap.applyInverseMap(xyz);
413  return frustumIndexBBox.isInside(xyz);
414  };
415 
416  // Return the frustum index-space bounding box of the corners of
417  // the given grid index-space bounding box.
418  auto toFrustumIndexSpace = [&](const CoordBBox& inBBox) -> BBoxd {
419  const Coord bounds[2] = { inBBox.min(), inBBox.max() };
420  Coord ijk;
421  BBoxd outBBox;
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);
427  xyz = frustumMap.applyInverseMap(xyz);
428  outBBox.expand(xyz);
429  }
430  return outBBox;
431  };
432 
433  // Construct an output grid with the same transform and metadata as the input grid.
434  auto outGrid = inGrid.copyWithNewTree();
435  if (outGrid->getGridClass() == GRID_LEVEL_SET) {
436  // After clipping, a level set grid might no longer be a valid SDF.
437  outGrid->setGridClass(GRID_UNKNOWN);
438  }
439 
440  const auto& bg = outGrid->background();
441 
442  auto outAcc = outGrid->getAccessor();
443 
444  // Copy active and inactive tiles that intersect the clipping region
445  // from the input grid to the output grid.
446  // ("Clipping region" refers to either the interior or the exterior
447  // of the frustum, depending on the value of keepInterior.)
448  auto tileIter = inGrid.beginValueAll();
449  tileIter.setMaxDepth(GridType::ValueAllIter::LEAF_DEPTH - 1);
450  CoordBBox tileBBox;
451  for ( ; tileIter; ++tileIter) {
452  const bool tileActive = tileIter.isValueOn();
453  const auto& tileValue = tileIter.getValue();
454 
455  // Skip background tiles.
456  if (!tileActive && math::isApproxEqual(tileValue, bg)) continue;
457 
458  // Transform the tile's bounding box into frustum index space.
459  tileIter.getBoundingBox(tileBBox);
460  const auto tileFrustumBBox = toFrustumIndexSpace(tileBBox);
461 
462  // Determine whether any or all of the tile intersects the clipping region.
463  enum class CopyTile { kNone, kPartial, kFull };
464  auto copyTile = CopyTile::kNone;
465  if (keepInterior) {
466  if (frustumIndexBBox.isInside(tileFrustumBBox)) {
467  copyTile = CopyTile::kFull;
468  } else if (frustumIndexBBox.hasOverlap(tileFrustumBBox)) {
469  copyTile = CopyTile::kPartial;
470  }
471  } else {
472  if (!frustumIndexBBox.hasOverlap(tileFrustumBBox)) {
473  copyTile = CopyTile::kFull;
474  } else if (!frustumIndexBBox.isInside(tileFrustumBBox)) {
475  copyTile = CopyTile::kPartial;
476  }
477  }
478  switch (copyTile) {
479  case CopyTile::kNone:
480  break;
481  case CopyTile::kFull:
482  // Copy the entire tile.
483  outAcc.addTile(tileIter.getLevel(), tileBBox.min(), tileValue, tileActive);
484  break;
485  case CopyTile::kPartial:
486  // Copy only voxels inside the clipping region.
487  for (std::vector<CoordBBox> bboxVec = { tileBBox }; !bboxVec.empty(); ) {
488  // For efficiency, subdivide sufficiently large tiles and discard
489  // subregions based on additional bounding box intersection tests.
490  // The mimimum subregion size is chosen so that cost of the
491  // bounding box test is comparable to testing every voxel.
492  if (bboxVec.back().volume() > 64 && bboxVec.back().is_divisible()) {
493  // Subdivide this region in-place and append the other half to the list.
494  bboxVec.emplace_back(bboxVec.back(), tbb::split{});
495  continue;
496  }
497  auto subBBox = bboxVec.back();
498  bboxVec.pop_back();
499 
500  // Discard the subregion if it lies completely outside the clipping region.
501  if (keepInterior) {
502  if (!frustumIndexBBox.hasOverlap(toFrustumIndexSpace(subBBox))) continue;
503  } else {
504  if (frustumIndexBBox.isInside(toFrustumIndexSpace(subBBox))) continue;
505  }
506 
507  // Test every voxel within the subregion.
508  for (const auto& ijk: subBBox) {
509  if (frustumContainsCoord(ijk) == keepInterior) {
510  if (tileActive) {
511  outAcc.setValueOn(ijk, tileValue);
512  } else {
513  outAcc.setValueOff(ijk, tileValue);
514  }
515  }
516  }
517  }
518  break;
519  }
520  }
521  tools::prune(outGrid->tree());
522 
523  // Ensure that the output grid has the same leaf node topology as the input grid,
524  // with the exception of leaf nodes that lie completely outside the clipping region.
525  // (This operation is serial.)
526  for (auto leafIter = inGrid.constTree().beginLeaf(); leafIter; ++leafIter) {
527  const auto leafBBox = leafIter->getNodeBoundingBox();
528  const auto leafFrustumBBox = toFrustumIndexSpace(leafBBox);
529  if (keepInterior) {
530  if (frustumIndexBBox.hasOverlap(leafFrustumBBox)) {
531  outAcc.touchLeaf(leafBBox.min());
532  }
533  } else {
534  if (!frustumIndexBBox.hasOverlap(leafFrustumBBox)
535  || !frustumIndexBBox.isInside(leafFrustumBBox))
536  {
537  outAcc.touchLeaf(leafBBox.min());
538  }
539  }
540  }
541 
542  // In parallel across output leaf nodes, copy leaf voxels
543  // from the input grid to the output grid.
544  tree::LeafManager<TreeT> outLeafNodes{outGrid->tree()};
545  outLeafNodes.foreach(
546  [&](LeafT& leaf, size_t /*idx*/) {
547  auto inAcc = inGrid.getConstAccessor();
548  ValueT val;
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);
555  }
556  }
557  }
558  );
559 
560  return outGrid;
561 }
562 
563 } // namespace tools
564 } // namespace OPENVDB_VERSION_NAME
565 } // namespace openvdb
566 
567 #endif // OPENVDB_TOOLS_CLIP_HAS_BEEN_INCLUDED
GLenum GLint * range
Definition: glew.h:3500
ToGridPtrT operator()(const FromGridCPtrT &grid)
Definition: Clip.h:223
const BBoxd & getBBox() const
Return the bounding box that defines the frustum in pre-image space.
Definition: Maps.h:2348
GLuint const GLfloat * val
Definition: glew.h:2794
const TreeType & tree() const
Return a const reference to tree associated with this manager.
Definition: LeafManager.h:304
void operator()(LeafNodeType &leaf, size_t) const
Definition: Clip.h:90
static bool sample(const TreeT &inTree, const Vec3R &inCoord, typename TreeT::ValueType &result)
Definition: Clip.h:206
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:1876
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:167
void expand(ElementType padding)
Pad this bounding box.
Definition: BBox.h:321
typename TreeT::template ValueConverter< MaskValueType >::Type MaskTreeT
Definition: Clip.h:113
GLenum GLint GLuint mask
Definition: glew.h:1845
CopyLeafNodes(const TreeT &, const MaskLeafManagerT &)
Definition: Clip.h:135
bool isNegative(const Type &x)
Return true if x is less than zero.
Definition: Math.h:358
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.
Definition: Math.h:397
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.
Definition: BBox.h:62
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...
GLsizei n
Definition: glew.h:4040
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...
Definition: LeafManager.h:84
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1253
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
const Vec3T & max() const
Return a const reference to the maximum point of this bounding box.
Definition: BBox.h:64
int floor(T x)
Definition: ImathFun.h:150
Vec3d applyInverseMap(const Vec3d &in) const override
Return the pre-image of in under the map.
Definition: Maps.h:2088
GridType::Ptr clip(const GridType &grid, const BBoxd &bbox, bool keepInterior=true)
Clip the given grid against a world-space bounding box and return a new grid containing the result...
Definition: Clip.h:348
math::BBox< Vec3d > BBoxd
Definition: Types.h:62
GLuint64EXT * result
Definition: glew.h:14007
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
void prune(TreeT &tree, typename TreeT::ValueType tolerance=zeroVal< typename TreeT::ValueType >(), bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing with tiles any nodes whose values are all the same...
Definition: Prune.h:334
void operator()(const tbb::blocked_range< size_t > &)
Definition: Clip.h:163
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:113
GLsizei const GLfloat * value
Definition: glew.h:1849
bool probeValue(const Coord &xyz, ValueType &value) const
Return the active state of the voxel as well as its value.
tree::LeafManager< const MaskTreeT > MaskLeafManagerT
Definition: Clip.h:114