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