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