OpenVDB  9.0.0
Composite.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 Composite.h
5 ///
6 /// @brief Functions to efficiently perform various compositing operations on grids
7 ///
8 /// @authors Peter Cucka, Mihai Alden, Ken Museth
9 
10 #ifndef OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
11 #define OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
12 
13 #include <openvdb/Platform.h>
14 #include <openvdb/Exceptions.h>
15 #include <openvdb/Types.h>
16 #include <openvdb/Grid.h>
17 #include <openvdb/math/Math.h> // for isExactlyEqual()
18 #include <openvdb/openvdb.h>
19 #include "Merge.h"
20 #include "ValueTransformer.h" // for transformValues()
21 #include "Prune.h"// for prune
22 #include "SignedFloodFill.h" // for signedFloodFill()
23 
24 #include <tbb/blocked_range.h>
25 #include <tbb/parallel_for.h>
26 #include <tbb/parallel_reduce.h>
27 #include <tbb/task_group.h>
28 
29 #include <type_traits>
30 #include <functional>
31 
32 namespace openvdb {
34 namespace OPENVDB_VERSION_NAME {
35 namespace tools {
36 
37 /// @brief Given two level set grids, replace the A grid with the union of A and B.
38 /// @throw ValueError if the background value of either grid is not greater than zero.
39 /// @note This operation always leaves the B grid empty.
40 template<typename GridOrTreeT>
41 void csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
42 /// @brief Given two level set grids, replace the A grid with the intersection of A and B.
43 /// @throw ValueError if the background value of either grid is not greater than zero.
44 /// @note This operation always leaves the B grid empty.
45 template<typename GridOrTreeT>
46 void csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
47 /// @brief Given two level set grids, replace the A grid with the difference A / B.
48 /// @throw ValueError if the background value of either grid is not greater than zero.
49 /// @note This operation always leaves the B grid empty.
50 template<typename GridOrTreeT>
51 void csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
52 
53 /// @brief Threaded CSG union operation that produces a new grid or tree from
54 /// immutable inputs.
55 /// @return The CSG union of the @a and @b level set inputs.
56 template<typename GridOrTreeT>
57 typename GridOrTreeT::Ptr csgUnionCopy(const GridOrTreeT& a, const GridOrTreeT& b);
58 /// @brief Threaded CSG intersection operation that produces a new grid or tree from
59 /// immutable inputs.
60 /// @return The CSG intersection of the @a and @b level set inputs.
61 template<typename GridOrTreeT>
62 typename GridOrTreeT::Ptr csgIntersectionCopy(const GridOrTreeT& a, const GridOrTreeT& b);
63 /// @brief Threaded CSG difference operation that produces a new grid or tree from
64 /// immutable inputs.
65 /// @return The CSG difference of the @a and @b level set inputs.
66 template<typename GridOrTreeT>
67 typename GridOrTreeT::Ptr csgDifferenceCopy(const GridOrTreeT& a, const GridOrTreeT& b);
68 
69 /// @brief Given grids A and B, compute max(a, b) per voxel (using sparse traversal).
70 /// Store the result in the A grid and leave the B grid empty.
71 template<typename GridOrTreeT>
72 void compMax(GridOrTreeT& a, GridOrTreeT& b);
73 /// @brief Given grids A and B, compute min(a, b) per voxel (using sparse traversal).
74 /// Store the result in the A grid and leave the B grid empty.
75 template<typename GridOrTreeT>
76 void compMin(GridOrTreeT& a, GridOrTreeT& b);
77 /// @brief Given grids A and B, compute a + b per voxel (using sparse traversal).
78 /// Store the result in the A grid and leave the B grid empty.
79 template<typename GridOrTreeT>
80 void compSum(GridOrTreeT& a, GridOrTreeT& b);
81 /// @brief Given grids A and B, compute a * b per voxel (using sparse traversal).
82 /// Store the result in the A grid and leave the B grid empty.
83 template<typename GridOrTreeT>
84 void compMul(GridOrTreeT& a, GridOrTreeT& b);
85 /// @brief Given grids A and B, compute a / b per voxel (using sparse traversal).
86 /// Store the result in the A grid and leave the B grid empty.
87 template<typename GridOrTreeT>
88 void compDiv(GridOrTreeT& a, GridOrTreeT& b);
89 
90 /// Copy the active voxels of B into A.
91 template<typename GridOrTreeT>
92 void compReplace(GridOrTreeT& a, const GridOrTreeT& b);
93 
94 
95 ////////////////////////////////////////
96 
97 
98 namespace composite {
99 
100 // composite::min() and composite::max() for non-vector types compare with operator<().
101 template<typename T> inline
102 const typename std::enable_if<!VecTraits<T>::IsVec, T>::type& // = T if T is not a vector type
103 min(const T& a, const T& b) { return std::min(a, b); }
104 
105 template<typename T> inline
106 const typename std::enable_if<!VecTraits<T>::IsVec, T>::type&
107 max(const T& a, const T& b) { return std::max(a, b); }
108 
109 
110 // composite::min() and composite::max() for OpenVDB vector types compare by magnitude.
111 template<typename T> inline
112 const typename std::enable_if<VecTraits<T>::IsVec, T>::type& // = T if T is a vector type
113 min(const T& a, const T& b)
114 {
115  const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
116  return (aMag < bMag ? a : (bMag < aMag ? b : std::min(a, b)));
117 }
118 
119 template<typename T> inline
120 const typename std::enable_if<VecTraits<T>::IsVec, T>::type&
121 max(const T& a, const T& b)
122 {
123  const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
124  return (aMag < bMag ? b : (bMag < aMag ? a : std::max(a, b)));
125 }
126 
127 
128 template<typename T> inline
129 typename std::enable_if<!std::is_integral<T>::value, T>::type // = T if T is not an integer type
130 divide(const T& a, const T& b) { return a / b; }
131 
132 template<typename T> inline
133 typename std::enable_if<std::is_integral<T>::value, T>::type // = T if T is an integer type
134 divide(const T& a, const T& b)
135 {
136  const T zero(0);
137  if (b != zero) return a / b;
138  if (a == zero) return 0;
140 }
141 
142 // If b is true, return a / 1 = a.
143 // If b is false and a is true, return 1 / 0 = inf = MAX_BOOL = 1 = a.
144 // If b is false and a is false, return 0 / 0 = NaN = 0 = a.
145 inline bool divide(bool a, bool /*b*/) { return a; }
146 
147 
148 /// @cond OPENVDB_DOCS_INTERNAL
149 
150 enum CSGOperation { CSG_UNION, CSG_INTERSECTION, CSG_DIFFERENCE };
151 
152 template<typename TreeType, CSGOperation Operation>
153 struct BuildPrimarySegment
154 {
155  using ValueType = typename TreeType::ValueType;
156  using TreePtrType = typename TreeType::Ptr;
157  using LeafNodeType = typename TreeType::LeafNodeType;
158  using NodeMaskType = typename LeafNodeType::NodeMaskType;
159  using RootNodeType = typename TreeType::RootNodeType;
160  using NodeChainType = typename RootNodeType::NodeChainType;
161  using InternalNodeType = typename NodeChainType::template Get<1>;
162 
163  BuildPrimarySegment(const TreeType& lhs, const TreeType& rhs)
164  : mSegment(new TreeType(lhs.background()))
165  , mLhsTree(&lhs)
166  , mRhsTree(&rhs)
167  {
168  }
169 
170  void operator()() const
171  {
172  std::vector<const LeafNodeType*> leafNodes;
173 
174  {
175  std::vector<const InternalNodeType*> internalNodes;
176  mLhsTree->getNodes(internalNodes);
177 
178  ProcessInternalNodes op(internalNodes, *mRhsTree, *mSegment, leafNodes);
179  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
180  }
181 
182  ProcessLeafNodes op(leafNodes, *mRhsTree, *mSegment);
183  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
184  }
185 
186  TreePtrType& segment() { return mSegment; }
187 
188 private:
189 
190  struct ProcessInternalNodes {
191 
192  ProcessInternalNodes(std::vector<const InternalNodeType*>& lhsNodes,
193  const TreeType& rhsTree, TreeType& outputTree,
194  std::vector<const LeafNodeType*>& outputLeafNodes)
195  : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front())
196  , mRhsTree(&rhsTree)
197  , mLocalTree(mRhsTree->background())
198  , mOutputTree(&outputTree)
199  , mLocalLeafNodes()
200  , mOutputLeafNodes(&outputLeafNodes)
201  {
202  }
203 
204  ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
205  : mLhsNodes(other.mLhsNodes)
206  , mRhsTree(other.mRhsTree)
207  , mLocalTree(mRhsTree->background())
208  , mOutputTree(&mLocalTree)
209  , mLocalLeafNodes()
210  , mOutputLeafNodes(&mLocalLeafNodes)
211  {
212  }
213 
214  void join(ProcessInternalNodes& other)
215  {
216  mOutputTree->merge(*other.mOutputTree);
217  mOutputLeafNodes->insert(mOutputLeafNodes->end(),
218  other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
219  }
220 
221  void operator()(const tbb::blocked_range<size_t>& range)
222  {
223  tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
224  tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
225 
226  std::vector<const LeafNodeType*> tmpLeafNodes;
227 
228  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
229 
230  const InternalNodeType& lhsNode = *mLhsNodes[n];
231  const Coord& ijk = lhsNode.origin();
232  const InternalNodeType * rhsNode =
233  rhsAcc.template probeConstNode<InternalNodeType>(ijk);
234 
235  if (rhsNode) {
236  lhsNode.getNodes(*mOutputLeafNodes);
237  } else {
238  if (Operation == CSG_INTERSECTION) {
239  if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
240  tmpLeafNodes.clear();
241  lhsNode.getNodes(tmpLeafNodes);
242  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
243  outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
244  }
245  }
246  } else { // Union & Difference
247  if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
248  tmpLeafNodes.clear();
249  lhsNode.getNodes(tmpLeafNodes);
250  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
251  outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
252  }
253  }
254  }
255  }
256  } // end range loop
257  }
258 
259  InternalNodeType const * const * const mLhsNodes;
260  TreeType const * const mRhsTree;
261  TreeType mLocalTree;
262  TreeType * const mOutputTree;
263 
264  std::vector<const LeafNodeType*> mLocalLeafNodes;
265  std::vector<const LeafNodeType*> * const mOutputLeafNodes;
266  }; // struct ProcessInternalNodes
267 
268  struct ProcessLeafNodes {
269 
270  ProcessLeafNodes(std::vector<const LeafNodeType*>& lhsNodes,
271  const TreeType& rhsTree, TreeType& output)
272  : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front())
273  , mRhsTree(&rhsTree)
274  , mLocalTree(mRhsTree->background())
275  , mOutputTree(&output)
276  {
277  }
278 
279  ProcessLeafNodes(ProcessLeafNodes& other, tbb::split)
280  : mLhsNodes(other.mLhsNodes)
281  , mRhsTree(other.mRhsTree)
282  , mLocalTree(mRhsTree->background())
283  , mOutputTree(&mLocalTree)
284  {
285  }
286 
287  void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
288 
289  void operator()(const tbb::blocked_range<size_t>& range)
290  {
291  tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
292  tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
293 
294  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
295 
296  const LeafNodeType& lhsNode = *mLhsNodes[n];
297  const Coord& ijk = lhsNode.origin();
298 
299  const LeafNodeType* rhsNodePt = rhsAcc.probeConstLeaf(ijk);
300 
301  if (rhsNodePt) { // combine overlapping nodes
302 
303  LeafNodeType* outputNode = outputAcc.touchLeaf(ijk);
304  ValueType * outputData = outputNode->buffer().data();
305  NodeMaskType& outputMask = outputNode->getValueMask();
306 
307  const ValueType * lhsData = lhsNode.buffer().data();
308  const NodeMaskType& lhsMask = lhsNode.getValueMask();
309 
310  const ValueType * rhsData = rhsNodePt->buffer().data();
311  const NodeMaskType& rhsMask = rhsNodePt->getValueMask();
312 
313  if (Operation == CSG_INTERSECTION) {
314  for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
315  const bool fromRhs = lhsData[pos] < rhsData[pos];
316  outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
317  outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
318  }
319  } else if (Operation == CSG_DIFFERENCE){
320  for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
321  const ValueType rhsVal = math::negative(rhsData[pos]);
322  const bool fromRhs = lhsData[pos] < rhsVal;
323  outputData[pos] = fromRhs ? rhsVal : lhsData[pos];
324  outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
325  }
326  } else { // Union
327  for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
328  const bool fromRhs = lhsData[pos] > rhsData[pos];
329  outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
330  outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
331  }
332  }
333 
334  } else {
335  if (Operation == CSG_INTERSECTION) {
336  if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
337  outputAcc.addLeaf(new LeafNodeType(lhsNode));
338  }
339  } else { // Union & Difference
340  if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
341  outputAcc.addLeaf(new LeafNodeType(lhsNode));
342  }
343  }
344  }
345  } // end range loop
346  }
347 
348  LeafNodeType const * const * const mLhsNodes;
349  TreeType const * const mRhsTree;
350  TreeType mLocalTree;
351  TreeType * const mOutputTree;
352  }; // struct ProcessLeafNodes
353 
354  TreePtrType mSegment;
355  TreeType const * const mLhsTree;
356  TreeType const * const mRhsTree;
357 }; // struct BuildPrimarySegment
358 
359 
360 template<typename TreeType, CSGOperation Operation>
361 struct BuildSecondarySegment
362 {
363  using ValueType = typename TreeType::ValueType;
364  using TreePtrType = typename TreeType::Ptr;
365  using LeafNodeType = typename TreeType::LeafNodeType;
366  using NodeMaskType = typename LeafNodeType::NodeMaskType;
367  using RootNodeType = typename TreeType::RootNodeType;
368  using NodeChainType = typename RootNodeType::NodeChainType;
369  using InternalNodeType = typename NodeChainType::template Get<1>;
370 
371  BuildSecondarySegment(const TreeType& lhs, const TreeType& rhs)
372  : mSegment(new TreeType(lhs.background()))
373  , mLhsTree(&lhs)
374  , mRhsTree(&rhs)
375  {
376  }
377 
378  void operator()() const
379  {
380  std::vector<const LeafNodeType*> leafNodes;
381 
382  {
383  std::vector<const InternalNodeType*> internalNodes;
384  mRhsTree->getNodes(internalNodes);
385 
386  ProcessInternalNodes op(internalNodes, *mLhsTree, *mSegment, leafNodes);
387  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
388  }
389 
390  ProcessLeafNodes op(leafNodes, *mLhsTree, *mSegment);
391  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
392  }
393 
394  TreePtrType& segment() { return mSegment; }
395 
396 private:
397 
398  struct ProcessInternalNodes {
399 
400  ProcessInternalNodes(std::vector<const InternalNodeType*>& rhsNodes,
401  const TreeType& lhsTree, TreeType& outputTree,
402  std::vector<const LeafNodeType*>& outputLeafNodes)
403  : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front())
404  , mLhsTree(&lhsTree)
405  , mLocalTree(mLhsTree->background())
406  , mOutputTree(&outputTree)
407  , mLocalLeafNodes()
408  , mOutputLeafNodes(&outputLeafNodes)
409  {
410  }
411 
412  ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
413  : mRhsNodes(other.mRhsNodes)
414  , mLhsTree(other.mLhsTree)
415  , mLocalTree(mLhsTree->background())
416  , mOutputTree(&mLocalTree)
417  , mLocalLeafNodes()
418  , mOutputLeafNodes(&mLocalLeafNodes)
419  {
420  }
421 
422  void join(ProcessInternalNodes& other)
423  {
424  mOutputTree->merge(*other.mOutputTree);
425  mOutputLeafNodes->insert(mOutputLeafNodes->end(),
426  other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
427  }
428 
429  void operator()(const tbb::blocked_range<size_t>& range)
430  {
431  tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
432  tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
433 
434  std::vector<const LeafNodeType*> tmpLeafNodes;
435 
436  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
437 
438  const InternalNodeType& rhsNode = *mRhsNodes[n];
439  const Coord& ijk = rhsNode.origin();
440  const InternalNodeType * lhsNode =
441  lhsAcc.template probeConstNode<InternalNodeType>(ijk);
442 
443  if (lhsNode) {
444  rhsNode.getNodes(*mOutputLeafNodes);
445  } else {
446  if (Operation == CSG_INTERSECTION) {
447  if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
448  tmpLeafNodes.clear();
449  rhsNode.getNodes(tmpLeafNodes);
450  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
451  outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
452  }
453  }
454  } else if (Operation == CSG_DIFFERENCE) {
455  if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
456  tmpLeafNodes.clear();
457  rhsNode.getNodes(tmpLeafNodes);
458  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
459  LeafNodeType* outputNode = new LeafNodeType(*tmpLeafNodes[i]);
460  outputNode->negate();
461  outputAcc.addLeaf(outputNode);
462  }
463  }
464  } else { // Union
465  if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
466  tmpLeafNodes.clear();
467  rhsNode.getNodes(tmpLeafNodes);
468  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
469  outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
470  }
471  }
472  }
473  }
474  } // end range loop
475  }
476 
477  InternalNodeType const * const * const mRhsNodes;
478  TreeType const * const mLhsTree;
479  TreeType mLocalTree;
480  TreeType * const mOutputTree;
481 
482  std::vector<const LeafNodeType*> mLocalLeafNodes;
483  std::vector<const LeafNodeType*> * const mOutputLeafNodes;
484  }; // struct ProcessInternalNodes
485 
486  struct ProcessLeafNodes {
487 
488  ProcessLeafNodes(std::vector<const LeafNodeType*>& rhsNodes,
489  const TreeType& lhsTree, TreeType& output)
490  : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front())
491  , mLhsTree(&lhsTree)
492  , mLocalTree(mLhsTree->background())
493  , mOutputTree(&output)
494  {
495  }
496 
497  ProcessLeafNodes(ProcessLeafNodes& rhs, tbb::split)
498  : mRhsNodes(rhs.mRhsNodes)
499  , mLhsTree(rhs.mLhsTree)
500  , mLocalTree(mLhsTree->background())
501  , mOutputTree(&mLocalTree)
502  {
503  }
504 
505  void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
506 
507  void operator()(const tbb::blocked_range<size_t>& range)
508  {
509  tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
510  tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
511 
512  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
513 
514  const LeafNodeType& rhsNode = *mRhsNodes[n];
515  const Coord& ijk = rhsNode.origin();
516 
517  const LeafNodeType* lhsNode = lhsAcc.probeConstLeaf(ijk);
518 
519  if (!lhsNode) {
520  if (Operation == CSG_INTERSECTION) {
521  if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
522  outputAcc.addLeaf(new LeafNodeType(rhsNode));
523  }
524  } else if (Operation == CSG_DIFFERENCE) {
525  if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
526  LeafNodeType* outputNode = new LeafNodeType(rhsNode);
527  outputNode->negate();
528  outputAcc.addLeaf(outputNode);
529  }
530  } else { // Union
531  if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
532  outputAcc.addLeaf(new LeafNodeType(rhsNode));
533  }
534  }
535  }
536  } // end range loop
537  }
538 
539  LeafNodeType const * const * const mRhsNodes;
540  TreeType const * const mLhsTree;
541  TreeType mLocalTree;
542  TreeType * const mOutputTree;
543  }; // struct ProcessLeafNodes
544 
545  TreePtrType mSegment;
546  TreeType const * const mLhsTree;
547  TreeType const * const mRhsTree;
548 }; // struct BuildSecondarySegment
549 
550 
551 template<CSGOperation Operation, typename TreeType>
552 typename TreeType::Ptr
553 doCSGCopy(const TreeType& lhs, const TreeType& rhs)
554 {
555  BuildPrimarySegment<TreeType, Operation> primary(lhs, rhs);
556  BuildSecondarySegment<TreeType, Operation> secondary(lhs, rhs);
557 
558  // Exploiting nested parallelism
559  tbb::task_group tasks;
560  tasks.run(primary);
561  tasks.run(secondary);
562  tasks.wait();
563 
564  primary.segment()->merge(*secondary.segment());
565 
566  // The leafnode (level = 0) sign is set in the segment construction.
567  tools::signedFloodFill(*primary.segment(), /*threaded=*/true, /*grainSize=*/1, /*minLevel=*/1);
568 
569  return primary.segment();
570 }
571 
572 
573 ////////////////////////////////////////
574 
575 
576 template<typename TreeType>
577 struct GridOrTreeConstructor
578 {
579  using TreeTypePtr = typename TreeType::Ptr;
580  static TreeTypePtr construct(const TreeType&, TreeTypePtr& tree) { return tree; }
581 };
582 
583 
584 template<typename TreeType>
585 struct GridOrTreeConstructor<Grid<TreeType> >
586 {
587  using GridType = Grid<TreeType>;
588  using GridTypePtr = typename Grid<TreeType>::Ptr;
589  using TreeTypePtr = typename TreeType::Ptr;
590 
591  static GridTypePtr construct(const GridType& grid, TreeTypePtr& tree) {
592  GridTypePtr maskGrid(GridType::create(tree));
593  maskGrid->setTransform(grid.transform().copy());
594  maskGrid->insertMeta(grid);
595  return maskGrid;
596  }
597 };
598 
599 
600 ////////////////////////////////////////
601 
602 /// List of pairs of leaf node pointers
603 template <typename LeafT>
604 using LeafPairList = std::vector<std::pair<LeafT*, LeafT*>>;
605 
606 /// Transfers leaf nodes from a source tree into a
607 /// destination tree, unless it already exists in the destination tree
608 /// in which case pointers to both leaf nodes are added to a list for
609 /// subsequent compositing operations.
610 template <typename TreeT>
611 void transferLeafNodes(TreeT &srcTree, TreeT &dstTree,
612  LeafPairList<typename TreeT::LeafNodeType> &overlapping)
613 {
614  using LeafT = typename TreeT::LeafNodeType;
615  tree::ValueAccessor<TreeT> acc(dstTree);//destination
616  std::vector<LeafT*> srcLeafNodes;
617  srcLeafNodes.reserve(srcTree.leafCount());
618  srcTree.stealNodes(srcLeafNodes);
619  srcTree.clear();
620  for (LeafT *srcLeaf : srcLeafNodes) {
621  LeafT *dstLeaf = acc.probeLeaf(srcLeaf->origin());
622  if (dstLeaf) {
623  overlapping.emplace_back(dstLeaf, srcLeaf);//dst, src
624  } else {
625  acc.addLeaf(srcLeaf);
626  }
627  }
628 }
629 
630 /// Template specialization of compActiveLeafVoxels
631 template <typename TreeT, typename OpT>
632 inline
633 typename std::enable_if<
636  std::is_same<typename TreeT::LeafNodeType::Buffer::ValueType,
637  typename TreeT::LeafNodeType::Buffer::StorageType>::value>::type
638 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
639 {
640  using LeafT = typename TreeT::LeafNodeType;
641  LeafPairList<LeafT> overlapping;//dst, src
642  transferLeafNodes(srcTree, dstTree, overlapping);
643 
644  using RangeT = tbb::blocked_range<size_t>;
645  tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](const RangeT& r) {
646  for (auto i = r.begin(); i != r.end(); ++i) {
647  LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
648  dstLeaf->getValueMask() |= srcLeaf->getValueMask();
649  auto *ptr = dstLeaf->buffer().data();
650  for (auto v = srcLeaf->cbeginValueOn(); v; ++v) op(ptr[v.pos()], *v);
651  delete srcLeaf;
652  }
653  });
654 }
655 
656 /// Template specialization of compActiveLeafVoxels
657 template <typename TreeT, typename OpT>
658 inline
659 typename std::enable_if<
662 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT)
663 {
664  using LeafT = typename TreeT::LeafNodeType;
665  LeafPairList<LeafT> overlapping;//dst, src
666  transferLeafNodes(srcTree, dstTree, overlapping);
667 
668  using RangeT = tbb::blocked_range<size_t>;
669  tbb::parallel_for(RangeT(0, overlapping.size()), [&overlapping](const RangeT& r) {
670  for (auto i = r.begin(); i != r.end(); ++i) {
671  overlapping[i].first->getValueMask() |= overlapping[i].second->getValueMask();
672  delete overlapping[i].second;
673  }
674  });
675 }
676 
677 /// Template specialization of compActiveLeafVoxels
678 template <typename TreeT, typename OpT>
679 inline
680 typename std::enable_if<
683 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
684 {
685  using LeafT = typename TreeT::LeafNodeType;
686  LeafPairList<LeafT> overlapping;//dst, src
687  transferLeafNodes(srcTree, dstTree, overlapping);
688 
689  using RangeT = tbb::blocked_range<size_t>;
690  using WordT = typename LeafT::Buffer::WordType;
691  tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](const RangeT& r) {
692  for (auto i = r.begin(); i != r.end(); ++i) {
693  LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
694  WordT *w1 = dstLeaf->buffer().data();
695  const WordT *w2 = srcLeaf->buffer().data();
696  const WordT *w3 = &(srcLeaf->getValueMask().template getWord<WordT>(0));
697  for (Index32 n = LeafT::Buffer::WORD_COUNT; n--; ++w1) {
698  WordT tmp = *w1, state = *w3++;
699  op (tmp, *w2++);
700  *w1 = (state & tmp) | (~state & *w1);//inactive values are unchanged
701  }
702  dstLeaf->getValueMask() |= srcLeaf->getValueMask();
703  delete srcLeaf;
704  }
705  });
706 }
707 
708 /// Default functor for compActiveLeafVoxels
709 template <typename TreeT>
710 struct CopyOp
711 {
712  using ValueT = typename TreeT::ValueType;
713  CopyOp() = default;
714  void operator()(ValueT& dst, const ValueT& src) const { dst = src; }
715 };
716 
717 template <typename TreeT>
718 void validateLevelSet(const TreeT& tree, const std::string& gridName = std::string(""))
719 {
720  using ValueT = typename TreeT::ValueType;
721  const ValueT zero = zeroVal<ValueT>();
722  if (!(tree.background() > zero)) {
723  std::stringstream ss;
724  ss << "expected grid ";
725  if (!gridName.empty()) ss << gridName << " ";
726  ss << "outside value > 0, got " << tree.background();
727  OPENVDB_THROW(ValueError, ss.str());
728  }
729  if (!(-tree.background() < zero)) {
730  std::stringstream ss;
731  ss << "expected grid ";
732  if (!gridName.empty()) ss << gridName << " ";
733  ss << "inside value < 0, got " << -tree.background();
734  OPENVDB_THROW(ValueError, ss.str());
735  }
736 }
737 
738 /// @endcond
739 
740 } // namespace composite
741 
742 
743 template<typename GridOrTreeT>
744 void
745 compMax(GridOrTreeT& aTree, GridOrTreeT& bTree)
746 {
747  using Adapter = TreeAdapter<GridOrTreeT>;
748  using TreeT = typename Adapter::TreeType;
749  using ValueT = typename TreeT::ValueType;
750  struct Local {
751  static inline void op(CombineArgs<ValueT>& args) {
752  args.setResult(composite::max(args.a(), args.b()));
753  }
754  };
755  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
756 }
757 
758 
759 template<typename GridOrTreeT>
760 void
761 compMin(GridOrTreeT& aTree, GridOrTreeT& bTree)
762 {
763  using Adapter = TreeAdapter<GridOrTreeT>;
764  using TreeT = typename Adapter::TreeType;
765  using ValueT = typename TreeT::ValueType;
766  struct Local {
767  static inline void op(CombineArgs<ValueT>& args) {
768  args.setResult(composite::min(args.a(), args.b()));
769  }
770  };
771  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
772 }
773 
774 
775 template<typename GridOrTreeT>
776 void
777 compSum(GridOrTreeT& aTree, GridOrTreeT& bTree)
778 {
779  using Adapter = TreeAdapter<GridOrTreeT>;
780  using TreeT = typename Adapter::TreeType;
781  struct Local {
782  static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
783  args.setResult(args.a() + args.b());
784  }
785  };
786  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
787 }
788 
789 
790 template<typename GridOrTreeT>
791 void
792 compMul(GridOrTreeT& aTree, GridOrTreeT& bTree)
793 {
794  using Adapter = TreeAdapter<GridOrTreeT>;
795  using TreeT = typename Adapter::TreeType;
796  struct Local {
797  static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
798  args.setResult(args.a() * args.b());
799  }
800  };
801  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
802 }
803 
804 
805 template<typename GridOrTreeT>
806 void
807 compDiv(GridOrTreeT& aTree, GridOrTreeT& bTree)
808 {
809  using Adapter = TreeAdapter<GridOrTreeT>;
810  using TreeT = typename Adapter::TreeType;
811  struct Local {
812  static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
813  args.setResult(composite::divide(args.a(), args.b()));
814  }
815  };
816  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
817 }
818 
819 
820 ////////////////////////////////////////
821 
822 
823 template<typename TreeT>
825 {
826  TreeT* const aTree;
827 
828  CompReplaceOp(TreeT& _aTree): aTree(&_aTree) {}
829 
830  /// @note fill operation is not thread safe
831  void operator()(const typename TreeT::ValueOnCIter& iter) const
832  {
833  CoordBBox bbox;
834  iter.getBoundingBox(bbox);
835  aTree->fill(bbox, *iter);
836  }
837 
838  void operator()(const typename TreeT::LeafCIter& leafIter) const
839  {
840  tree::ValueAccessor<TreeT> acc(*aTree);
841  for (typename TreeT::LeafCIter::LeafNodeT::ValueOnCIter iter =
842  leafIter->cbeginValueOn(); iter; ++iter)
843  {
844  acc.setValue(iter.getCoord(), *iter);
845  }
846  }
847 };
848 
849 
850 template<typename GridOrTreeT>
851 void
852 compReplace(GridOrTreeT& aTree, const GridOrTreeT& bTree)
853 {
854  using Adapter = TreeAdapter<GridOrTreeT>;
855  using TreeT = typename Adapter::TreeType;
856  using ValueOnCIterT = typename TreeT::ValueOnCIter;
857 
858  // Copy active states (but not values) from B to A.
859  Adapter::tree(aTree).topologyUnion(Adapter::tree(bTree));
860 
861  CompReplaceOp<TreeT> op(Adapter::tree(aTree));
862 
863  // Copy all active tile values from B to A.
864  ValueOnCIterT iter = bTree.cbeginValueOn();
865  iter.setMaxDepth(iter.getLeafDepth() - 1); // don't descend into leaf nodes
866  foreach(iter, op, /*threaded=*/false);
867 
868  // Copy all active voxel values from B to A.
869  foreach(Adapter::tree(bTree).cbeginLeaf(), op);
870 }
871 
872 
873 ////////////////////////////////////////
874 
875 
876 template<typename GridOrTreeT>
877 void
878 csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune)
879 {
880  using Adapter = TreeAdapter<GridOrTreeT>;
881  using TreeT = typename Adapter::TreeType;
882  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
883  composite::validateLevelSet(aTree, "A");
884  composite::validateLevelSet(bTree, "B");
885  CsgUnionOp<TreeT> op(bTree, Steal());
886  tree::DynamicNodeManager<TreeT> nodeManager(aTree);
887  nodeManager.foreachTopDown(op);
888  if (prune) tools::pruneLevelSet(aTree);
889 }
890 
891 template<typename GridOrTreeT>
892 void
893 csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune)
894 {
895  using Adapter = TreeAdapter<GridOrTreeT>;
896  using TreeT = typename Adapter::TreeType;
897  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
898  composite::validateLevelSet(aTree, "A");
899  composite::validateLevelSet(bTree, "B");
900  CsgIntersectionOp<TreeT> op(bTree, Steal());
901  tree::DynamicNodeManager<TreeT> nodeManager(aTree);
902  nodeManager.foreachTopDown(op);
903  if (prune) tools::pruneLevelSet(aTree);
904 }
905 
906 template<typename GridOrTreeT>
907 void
908 csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune)
909 {
910  using Adapter = TreeAdapter<GridOrTreeT>;
911  using TreeT = typename Adapter::TreeType;
912  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
913  composite::validateLevelSet(aTree, "A");
914  composite::validateLevelSet(bTree, "B");
915  CsgDifferenceOp<TreeT> op(bTree, Steal());
916  tree::DynamicNodeManager<TreeT> nodeManager(aTree);
917  nodeManager.foreachTopDown(op);
918  if (prune) tools::pruneLevelSet(aTree);
919 }
920 
921 
922 template<typename GridOrTreeT>
923 typename GridOrTreeT::Ptr
924 csgUnionCopy(const GridOrTreeT& a, const GridOrTreeT& b)
925 {
926  using Adapter = TreeAdapter<GridOrTreeT>;
927  using TreePtrT = typename Adapter::TreeType::Ptr;
928 
929  TreePtrT output = composite::doCSGCopy<composite::CSG_UNION>(
930  Adapter::tree(a), Adapter::tree(b));
931 
932  return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
933 }
934 
935 
936 template<typename GridOrTreeT>
937 typename GridOrTreeT::Ptr
938 csgIntersectionCopy(const GridOrTreeT& a, const GridOrTreeT& b)
939 {
940  using Adapter = TreeAdapter<GridOrTreeT>;
941  using TreePtrT = typename Adapter::TreeType::Ptr;
942 
943  TreePtrT output = composite::doCSGCopy<composite::CSG_INTERSECTION>(
944  Adapter::tree(a), Adapter::tree(b));
945 
946  return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
947 }
948 
949 
950 template<typename GridOrTreeT>
951 typename GridOrTreeT::Ptr
952 csgDifferenceCopy(const GridOrTreeT& a, const GridOrTreeT& b)
953 {
954  using Adapter = TreeAdapter<GridOrTreeT>;
955  using TreePtrT = typename Adapter::TreeType::Ptr;
956 
957  TreePtrT output = composite::doCSGCopy<composite::CSG_DIFFERENCE>(
958  Adapter::tree(a), Adapter::tree(b));
959 
960  return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
961 }
962 
963 ////////////////////////////////////////////////////////
964 
965 /// @brief Composite the active values in leaf nodes, i.e. active
966 /// voxels, of a source tree into a destination tree.
967 ///
968 /// @param srcTree source tree from which active voxels are composited.
969 ///
970 /// @param dstTree destination tree into which active voxels are composited.
971 ///
972 /// @param op a functor of the form <tt>void op(T& dst, const T& src)</tt>,
973 /// where @c T is the @c ValueType of the tree, that composites
974 /// a source value into a destination value. By default
975 /// it copies the value from src to dst.
976 ///
977 /// @details All active voxels in the source tree will
978 /// be active in the destination tree, and their value is
979 /// determined by a use-defined functor (OpT op) that operates on the
980 /// source and destination values. The only exception is when
981 /// the tree type is MaskTree, in which case no functor is
982 /// needed since by defintion a MaskTree has no values (only topology).
983 ///
984 /// @warning This function only operated on leaf node values,
985 /// i.e. tile values are ignored.
986 template<typename TreeT, typename OpT = composite::CopyOp<TreeT> >
987 void
988 compActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op = composite::CopyOp<TreeT>())
989 {
990  composite::doCompActiveLeafVoxels<TreeT, OpT>(srcTree, dstTree, op);
991 }
992 
993 
994 ////////////////////////////////////////
995 
996 
997 // Explicit Template Instantiation
998 
999 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1000 
1001 #ifdef OPENVDB_INSTANTIATE_COMPOSITE
1003 #endif
1004 
1005 #define _FUNCTION(TreeT) \
1006  void csgUnion(TreeT&, TreeT&, bool)
1008 #undef _FUNCTION
1009 
1010 #define _FUNCTION(TreeT) \
1011  void csgUnion(Grid<TreeT>&, Grid<TreeT>&, bool)
1013 #undef _FUNCTION
1014 
1015 #define _FUNCTION(TreeT) \
1016  void csgIntersection(TreeT&, TreeT&, bool)
1018 #undef _FUNCTION
1019 
1020 #define _FUNCTION(TreeT) \
1021  void csgIntersection(Grid<TreeT>&, Grid<TreeT>&, bool)
1023 #undef _FUNCTION
1024 
1025 #define _FUNCTION(TreeT) \
1026  void csgDifference(TreeT&, TreeT&, bool)
1028 #undef _FUNCTION
1029 
1030 #define _FUNCTION(TreeT) \
1031  void csgDifference(Grid<TreeT>&, Grid<TreeT>&, bool)
1033 #undef _FUNCTION
1034 
1035 #define _FUNCTION(TreeT) \
1036  TreeT::Ptr csgUnionCopy(const TreeT&, const TreeT&)
1038 #undef _FUNCTION
1039 
1040 #define _FUNCTION(TreeT) \
1041  Grid<TreeT>::Ptr csgUnionCopy(const Grid<TreeT>&, const Grid<TreeT>&)
1043 #undef _FUNCTION
1044 
1045 #define _FUNCTION(TreeT) \
1046  TreeT::Ptr csgIntersectionCopy(const TreeT&, const TreeT&)
1048 #undef _FUNCTION
1049 
1050 #define _FUNCTION(TreeT) \
1051  Grid<TreeT>::Ptr csgIntersectionCopy(const Grid<TreeT>&, const Grid<TreeT>&)
1053 #undef _FUNCTION
1054 
1055 #define _FUNCTION(TreeT) \
1056  TreeT::Ptr csgDifferenceCopy(const TreeT&, const TreeT&)
1058 #undef _FUNCTION
1059 
1060 #define _FUNCTION(TreeT) \
1061  Grid<TreeT>::Ptr csgDifferenceCopy(const Grid<TreeT>&, const Grid<TreeT>&)
1063 #undef _FUNCTION
1064 
1065 #define _FUNCTION(TreeT) \
1066  void compMax(TreeT&, TreeT&)
1068 #undef _FUNCTION
1069 
1070 #define _FUNCTION(TreeT) \
1071  void compMax(Grid<TreeT>&, Grid<TreeT>&)
1073 #undef _FUNCTION
1074 
1075 #define _FUNCTION(TreeT) \
1076  void compMin(TreeT&, TreeT&)
1078 #undef _FUNCTION
1079 
1080 #define _FUNCTION(TreeT) \
1081  void compMin(Grid<TreeT>&, Grid<TreeT>&)
1083 #undef _FUNCTION
1084 
1085 #define _FUNCTION(TreeT) \
1086  void compSum(TreeT&, TreeT&)
1088 #undef _FUNCTION
1089 
1090 #define _FUNCTION(TreeT) \
1091  void compSum(Grid<TreeT>&, Grid<TreeT>&)
1093 #undef _FUNCTION
1094 
1095 #define _FUNCTION(TreeT) \
1096  void compDiv(TreeT&, TreeT&)
1098 #undef _FUNCTION
1099 
1100 #define _FUNCTION(TreeT) \
1101  void compDiv(Grid<TreeT>&, Grid<TreeT>&)
1103 #undef _FUNCTION
1104 
1105 #define _FUNCTION(TreeT) \
1106  void compReplace(TreeT&, const TreeT&)
1108 #undef _FUNCTION
1109 
1110 #define _FUNCTION(TreeT) \
1111  void compReplace(Grid<TreeT>&, const Grid<TreeT>&)
1113 #undef _FUNCTION
1114 
1115 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
1116 
1117 
1118 } // namespace tools
1119 } // namespace OPENVDB_VERSION_NAME
1120 } // namespace openvdb
1121 
1122 #endif // OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
ValueT value
Definition: GridBuilder.h:1287
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Functions to efficiently merge grids.
Defined various multi-threaded utility functions for trees.
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:451
CombineArgs & setResult(const AValueType &val)
Set the output value.
Definition: Types.h:500
const AValueType & a() const
Get the A input value.
Definition: Types.h:490
const BValueType & b() const
Get the B input value.
Definition: Types.h:492
SharedPtr< Grid > Ptr
Definition: Grid.h:579
Tag dispatch class that distinguishes constructors that steal.
Definition: Types.h:568
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:248
Definition: NodeManager.h:890
void foreachTopDown(const NodeOp &op, bool threaded=true, size_t leafGrainSize=1, size_t nonLeafGrainSize=1)
Threaded method that applies a user-supplied functor to all the nodes in the tree.
Definition: NodeManager.h:976
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active.
Definition: ValueAccessor.h:250
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:216
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:127
const std::enable_if< VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:113
const std::enable_if< VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:121
bool divide(bool a, bool)
Definition: Composite.h:145
void compDiv(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute a / b per voxel (using sparse traversal). Store the result in the A grid...
Definition: Composite.h:807
void csgUnion(GridOrTreeT &a, GridOrTreeT &b, bool prune=true)
Given two level set grids, replace the A grid with the union of A and B.
Definition: Composite.h:878
void compReplace(GridOrTreeT &a, const GridOrTreeT &b)
Copy the active voxels of B into A.
Definition: Composite.h:852
void csgDifference(GridOrTreeT &a, GridOrTreeT &b, bool prune=true)
Given two level set grids, replace the A grid with the difference A / B.
Definition: Composite.h:908
void pruneLevelSet(TreeT &tree, bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing nodes whose values are all inactive with inactive ...
Definition: Prune.h:390
void compActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op=composite::CopyOp< TreeT >())
Composite the active values in leaf nodes, i.e. active voxels, of a source tree into a destination tr...
Definition: Composite.h:988
GridOrTreeT::Ptr csgDifferenceCopy(const GridOrTreeT &a, const GridOrTreeT &b)
Threaded CSG difference operation that produces a new grid or tree from immutable inputs.
Definition: Composite.h:952
void csgIntersection(GridOrTreeT &a, GridOrTreeT &b, bool prune=true)
Given two level set grids, replace the A grid with the intersection of A and B.
Definition: Composite.h:893
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:335
GridOrTreeT::Ptr csgUnionCopy(const GridOrTreeT &a, const GridOrTreeT &b)
Threaded CSG union operation that produces a new grid or tree from immutable inputs.
Definition: Composite.h:924
void compSum(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute a + b per voxel (using sparse traversal). Store the result in the A grid...
Definition: Composite.h:777
void compMax(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute max(a, b) per voxel (using sparse traversal). Store the result in the A ...
Definition: Composite.h:745
void signedFloodFill(TreeOrLeafManagerT &tree, bool threaded=true, size_t grainSize=1, Index minLevel=0)
Set the values of all inactive voxels and tiles of a narrow-band level set from the signs of the acti...
Definition: SignedFloodFill.h:267
void compMul(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute a * b per voxel (using sparse traversal). Store the result in the A grid...
Definition: Composite.h:792
void compMin(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute min(a, b) per voxel (using sparse traversal). Store the result in the A ...
Definition: Composite.h:761
GridOrTreeT::Ptr csgIntersectionCopy(const GridOrTreeT &a, const GridOrTreeT &b)
Threaded CSG intersection operation that produces a new grid or tree from immutable inputs.
Definition: Composite.h:938
Index32 Index
Definition: Types.h:54
openvdb::GridBase Grid
Definition: Utils.h:34
Definition: Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
This adapter allows code that is templated on a Tree type to accept either a Tree type or a Grid type...
Definition: Grid.h:1071
Definition: Composite.h:825
void operator()(const typename TreeT::LeafCIter &leafIter) const
Definition: Composite.h:838
TreeT *const aTree
Definition: Composite.h:826
void operator()(const typename TreeT::ValueOnCIter &iter) const
Definition: Composite.h:831
CompReplaceOp(TreeT &_aTree)
Definition: Composite.h:828
DynamicNodeManager operator to merge two trees using a CSG difference.
Definition: Merge.h:263
DynamicNodeManager operator to merge trees using a CSG union or intersection.
Definition: Merge.h:183
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition: version.h.in:147
#define OPENVDB_VOLUME_TREE_INSTANTIATE(Function)
Definition: version.h.in:150