OpenVDB  11.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<
637  !std::is_same<typename TreeT::ValueType, bool>::value &&
638  !std::is_same<typename TreeT::BuildType, ValueMask>::value &&
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<
663  std::is_same<typename TreeT::BuildType, ValueMask>::value &&
664  std::is_same<typename TreeT::ValueType, bool>::value>::type
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<
684  std::is_same<typename TreeT::ValueType, bool>::value &&
685  !std::is_same<typename TreeT::BuildType, ValueMask>::value>::type
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  using ValueT = typename GridOrTreeT::ValueType;
800  struct Local {
801  static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
802  if constexpr(std::is_same<ValueT, bool>::value) {
803  args.setResult(args.a() && args.b());
804  } else {
805  args.setResult(args.a() * args.b());
806  }
807  }
808  };
809  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
810 }
811 
812 
813 template<typename GridOrTreeT>
814 void
815 compDiv(GridOrTreeT& aTree, GridOrTreeT& bTree)
816 {
817  using Adapter = TreeAdapter<GridOrTreeT>;
818  using TreeT = typename Adapter::TreeType;
819  struct Local {
820  static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
821  args.setResult(composite::divide(args.a(), args.b()));
822  }
823  };
824  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
825 }
826 
827 
828 ////////////////////////////////////////
829 
830 
831 template<typename TreeT>
833 {
834  TreeT* const aTree;
835 
836  CompReplaceOp(TreeT& _aTree): aTree(&_aTree) {}
837 
838  /// @note fill operation is not thread safe
839  void operator()(const typename TreeT::ValueOnCIter& iter) const
840  {
841  CoordBBox bbox;
842  iter.getBoundingBox(bbox);
843  aTree->fill(bbox, *iter);
844  }
845 
846  void operator()(const typename TreeT::LeafCIter& leafIter) const
847  {
848  tree::ValueAccessor<TreeT> acc(*aTree);
849  for (typename TreeT::LeafCIter::LeafNodeT::ValueOnCIter iter =
850  leafIter->cbeginValueOn(); iter; ++iter)
851  {
852  acc.setValue(iter.getCoord(), *iter);
853  }
854  }
855 };
856 
857 
858 template<typename GridOrTreeT>
859 void
860 compReplace(GridOrTreeT& aTree, const GridOrTreeT& bTree)
861 {
862  using Adapter = TreeAdapter<GridOrTreeT>;
863  using TreeT = typename Adapter::TreeType;
864  using ValueOnCIterT = typename TreeT::ValueOnCIter;
865 
866  // Copy active states (but not values) from B to A.
867  Adapter::tree(aTree).topologyUnion(Adapter::tree(bTree));
868 
869  CompReplaceOp<TreeT> op(Adapter::tree(aTree));
870 
871  // Copy all active tile values from B to A.
872  ValueOnCIterT iter = bTree.cbeginValueOn();
873  iter.setMaxDepth(iter.getLeafDepth() - 1); // don't descend into leaf nodes
874  foreach(iter, op, /*threaded=*/false);
875 
876  // Copy all active voxel values from B to A.
877  foreach(Adapter::tree(bTree).cbeginLeaf(), op);
878 }
879 
880 
881 ////////////////////////////////////////
882 
883 
884 template<typename GridOrTreeT>
885 void
886 csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune, bool pruneCancelledTiles)
887 {
888  using Adapter = TreeAdapter<GridOrTreeT>;
889  using TreeT = typename Adapter::TreeType;
890  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
891  composite::validateLevelSet(aTree, "A");
892  composite::validateLevelSet(bTree, "B");
893  CsgUnionOp<TreeT> op(bTree, Steal());
894  op.setPruneCancelledTiles(prune && pruneCancelledTiles);
895  tree::DynamicNodeManager<TreeT> nodeManager(aTree);
896  nodeManager.foreachTopDown(op);
897  if (prune) tools::pruneLevelSet(aTree);
898 }
899 
900 template<typename GridOrTreeT>
901 void
902 csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune, bool pruneCancelledTiles)
903 {
904  using Adapter = TreeAdapter<GridOrTreeT>;
905  using TreeT = typename Adapter::TreeType;
906  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
907  composite::validateLevelSet(aTree, "A");
908  composite::validateLevelSet(bTree, "B");
909  CsgIntersectionOp<TreeT> op(bTree, Steal());
910  op.setPruneCancelledTiles(prune && pruneCancelledTiles);
911  tree::DynamicNodeManager<TreeT> nodeManager(aTree);
912  nodeManager.foreachTopDown(op);
913  if (prune) tools::pruneLevelSet(aTree);
914 }
915 
916 template<typename GridOrTreeT>
917 void
918 csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune, bool pruneCancelledTiles)
919 {
920  using Adapter = TreeAdapter<GridOrTreeT>;
921  using TreeT = typename Adapter::TreeType;
922  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
923  composite::validateLevelSet(aTree, "A");
924  composite::validateLevelSet(bTree, "B");
925  CsgDifferenceOp<TreeT> op(bTree, Steal());
926  op.setPruneCancelledTiles(prune && pruneCancelledTiles);
927  tree::DynamicNodeManager<TreeT> nodeManager(aTree);
928  nodeManager.foreachTopDown(op);
929  if (prune) tools::pruneLevelSet(aTree);
930 }
931 
932 
933 template<typename GridOrTreeT>
934 typename GridOrTreeT::Ptr
935 csgUnionCopy(const GridOrTreeT& a, const GridOrTreeT& b)
936 {
937  using Adapter = TreeAdapter<GridOrTreeT>;
938  using TreePtrT = typename Adapter::TreeType::Ptr;
939 
940  TreePtrT output = composite::doCSGCopy<composite::CSG_UNION>(
941  Adapter::tree(a), Adapter::tree(b));
942 
943  return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
944 }
945 
946 
947 template<typename GridOrTreeT>
948 typename GridOrTreeT::Ptr
949 csgIntersectionCopy(const GridOrTreeT& a, const GridOrTreeT& b)
950 {
951  using Adapter = TreeAdapter<GridOrTreeT>;
952  using TreePtrT = typename Adapter::TreeType::Ptr;
953 
954  TreePtrT output = composite::doCSGCopy<composite::CSG_INTERSECTION>(
955  Adapter::tree(a), Adapter::tree(b));
956 
957  return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
958 }
959 
960 
961 template<typename GridOrTreeT>
962 typename GridOrTreeT::Ptr
963 csgDifferenceCopy(const GridOrTreeT& a, const GridOrTreeT& b)
964 {
965  using Adapter = TreeAdapter<GridOrTreeT>;
966  using TreePtrT = typename Adapter::TreeType::Ptr;
967 
968  TreePtrT output = composite::doCSGCopy<composite::CSG_DIFFERENCE>(
969  Adapter::tree(a), Adapter::tree(b));
970 
971  return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
972 }
973 
974 ////////////////////////////////////////////////////////
975 
976 /// @brief Composite the active values in leaf nodes, i.e. active
977 /// voxels, of a source tree into a destination tree.
978 ///
979 /// @param srcTree source tree from which active voxels are composited.
980 ///
981 /// @param dstTree destination tree into which active voxels are composited.
982 ///
983 /// @param op a functor of the form <tt>void op(T& dst, const T& src)</tt>,
984 /// where @c T is the @c ValueType of the tree, that composites
985 /// a source value into a destination value. By default
986 /// it copies the value from src to dst.
987 ///
988 /// @details All active voxels in the source tree will
989 /// be active in the destination tree, and their value is
990 /// determined by a use-defined functor (OpT op) that operates on the
991 /// source and destination values. The only exception is when
992 /// the tree type is MaskTree, in which case no functor is
993 /// needed since by defintion a MaskTree has no values (only topology).
994 ///
995 /// @warning This function only operated on leaf node values,
996 /// i.e. tile values are ignored.
997 template<typename TreeT, typename OpT = composite::CopyOp<TreeT> >
998 void
999 compActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op = composite::CopyOp<TreeT>())
1000 {
1001  composite::doCompActiveLeafVoxels<TreeT, OpT>(srcTree, dstTree, op);
1002 }
1003 
1004 
1005 ////////////////////////////////////////
1006 
1007 
1008 // Explicit Template Instantiation
1009 
1010 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1011 
1012 #ifdef OPENVDB_INSTANTIATE_COMPOSITE
1014 #endif
1015 
1016 #define _FUNCTION(TreeT) \
1017  void csgUnion(TreeT&, TreeT&, bool, bool)
1019 #undef _FUNCTION
1020 
1021 #define _FUNCTION(TreeT) \
1022  void csgUnion(Grid<TreeT>&, Grid<TreeT>&, bool, bool)
1024 #undef _FUNCTION
1025 
1026 #define _FUNCTION(TreeT) \
1027  void csgIntersection(TreeT&, TreeT&, bool, bool)
1029 #undef _FUNCTION
1030 
1031 #define _FUNCTION(TreeT) \
1032  void csgIntersection(Grid<TreeT>&, Grid<TreeT>&, bool, bool)
1034 #undef _FUNCTION
1035 
1036 #define _FUNCTION(TreeT) \
1037  void csgDifference(TreeT&, TreeT&, bool, bool)
1039 #undef _FUNCTION
1040 
1041 #define _FUNCTION(TreeT) \
1042  void csgDifference(Grid<TreeT>&, Grid<TreeT>&, bool, bool)
1044 #undef _FUNCTION
1045 
1046 #define _FUNCTION(TreeT) \
1047  TreeT::Ptr csgUnionCopy(const TreeT&, const TreeT&)
1049 #undef _FUNCTION
1050 
1051 #define _FUNCTION(TreeT) \
1052  Grid<TreeT>::Ptr csgUnionCopy(const Grid<TreeT>&, const Grid<TreeT>&)
1054 #undef _FUNCTION
1055 
1056 #define _FUNCTION(TreeT) \
1057  TreeT::Ptr csgIntersectionCopy(const TreeT&, const TreeT&)
1059 #undef _FUNCTION
1060 
1061 #define _FUNCTION(TreeT) \
1062  Grid<TreeT>::Ptr csgIntersectionCopy(const Grid<TreeT>&, const Grid<TreeT>&)
1064 #undef _FUNCTION
1065 
1066 #define _FUNCTION(TreeT) \
1067  TreeT::Ptr csgDifferenceCopy(const TreeT&, const TreeT&)
1069 #undef _FUNCTION
1070 
1071 #define _FUNCTION(TreeT) \
1072  Grid<TreeT>::Ptr csgDifferenceCopy(const Grid<TreeT>&, const Grid<TreeT>&)
1074 #undef _FUNCTION
1075 
1076 #define _FUNCTION(TreeT) \
1077  void compMax(TreeT&, TreeT&)
1079 #undef _FUNCTION
1080 
1081 #define _FUNCTION(TreeT) \
1082  void compMax(Grid<TreeT>&, Grid<TreeT>&)
1084 #undef _FUNCTION
1085 
1086 #define _FUNCTION(TreeT) \
1087  void compMin(TreeT&, TreeT&)
1089 #undef _FUNCTION
1090 
1091 #define _FUNCTION(TreeT) \
1092  void compMin(Grid<TreeT>&, Grid<TreeT>&)
1094 #undef _FUNCTION
1095 
1096 #define _FUNCTION(TreeT) \
1097  void compSum(TreeT&, TreeT&)
1099 #undef _FUNCTION
1100 
1101 #define _FUNCTION(TreeT) \
1102  void compSum(Grid<TreeT>&, Grid<TreeT>&)
1104 #undef _FUNCTION
1105 
1106 #define _FUNCTION(TreeT) \
1107  void compDiv(TreeT&, TreeT&)
1109 #undef _FUNCTION
1110 
1111 #define _FUNCTION(TreeT) \
1112  void compDiv(Grid<TreeT>&, Grid<TreeT>&)
1114 #undef _FUNCTION
1115 
1116 #define _FUNCTION(TreeT) \
1117  void compReplace(TreeT&, const TreeT&)
1119 #undef _FUNCTION
1120 
1121 #define _FUNCTION(TreeT) \
1122  void compReplace(Grid<TreeT>&, const Grid<TreeT>&)
1124 #undef _FUNCTION
1125 
1126 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
1127 
1128 
1129 } // namespace tools
1130 } // namespace OPENVDB_VERSION_NAME
1131 } // namespace openvdb
1132 
1133 #endif // OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
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:569
CombineArgs & setResult(const AValueType &val)
Set the output value.
Definition: Types.h:618
const AValueType & a() const
Get the A input value.
Definition: Types.h:608
const BValueType & b() const
Get the B input value.
Definition: Types.h:610
SharedPtr< Grid > Ptr
Definition: Grid.h:573
Tag dispatch class that distinguishes constructors that steal.
Definition: Types.h:687
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:251
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
The Value Accessor Implementation and API methods. The majoirty of the API matches the API of a compa...
Definition: ValueAccessor.h:367
void setValue(const Coord &xyz, const ValueType &value)
Set a particular value at the given coordinate and mark the coordinate as active.
Definition: ValueAccessor.h:550
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:317
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:128
void split(ContainerT &out, const std::string &in, const char delim)
Definition: Name.h:43
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
const std::enable_if< VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:116
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:815
void compReplace(GridOrTreeT &a, const GridOrTreeT &b)
Copy the active voxels of B into A.
Definition: Composite.h:860
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:918
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:963
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:935
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:999
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:902
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:949
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:886
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:833
void operator()(const typename TreeT::LeafCIter &leafIter) const
Definition: Composite.h:846
TreeT *const aTree
Definition: Composite.h:834
void operator()(const typename TreeT::ValueOnCIter &iter) const
Definition: Composite.h:839
CompReplaceOp(TreeT &_aTree)
Definition: Composite.h:836
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