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
Definition: Exceptions.h:65
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
#define OPENVDB_VOLUME_TREE_INSTANTIATE(Function)
Definition: version.h.in:160
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
The Value Accessor Implementation and API methods. The majoirty of the API matches the API of a compa...
Definition: ValueAccessor.h:68
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
TreeT *const aTree
Definition: Composite.h:834
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
LeafNodeT * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains the voxel coordinate xyz. If no LeafNode exists...
Definition: ValueAccessor.h:836
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
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
Definition: NodeManager.h:36
This adapter allows code that is templated on a Tree type to accept either a Tree type or a Grid type...
Definition: Grid.h:1059
bool divide(bool a, bool)
Definition: Composite.h:148
void compReplace(GridOrTreeT &a, const GridOrTreeT &b)
Copy the active voxels of B into A.
Definition: Composite.h:860
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
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
const std::enable_if< VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:124
DynamicNodeManager operator to merge trees using a CSG union or intersection.
Definition: Merge.h:192
void setPruneCancelledTiles(bool doprune)
Enables immediate pruning of tiles that cancel each other out.
Definition: Merge.h:300
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:568
DynamicNodeManager operator to merge two trees using a CSG difference.
Definition: Merge.h:279
void operator()(const typename TreeT::ValueOnCIter &iter) const
Definition: Composite.h:839
Tag dispatch class that distinguishes constructors that steal.
Definition: Types.h:687
const std::enable_if< VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:116
Definition: Composite.h:832
Defined various multi-threaded utility functions for trees.
BBox< Coord > CoordBBox
Definition: NanoVDB.h:2535
CombineArgs & setResult(const AValueType &val)
Set the output value.
Definition: Types.h:618
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 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
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
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
const AValueType & a() const
Get the A input value.
Definition: Types.h:608
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:455
const BValueType & b() const
Get the B input value.
Definition: Types.h:610
Definition: Exceptions.h:13
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
LeafNodeT * touchLeaf(const Coord &xyz)
Returns the leaf node that contains voxel (x, y, z) and if it doesn&#39;t exist, create it...
Definition: ValueAccessor.h:715
SharedPtr< Grid > Ptr
Definition: Grid.h:573
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
void clear() override final
Remove all the cached nodes and invalidate the corresponding hash-keys.
Definition: ValueAccessor.h:880
Index32 Index
Definition: Types.h:54
Functions to efficiently merge grids.
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:317
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
const LeafNodeT * probeConstLeaf(const Coord &xyz) const
Return a pointer to the leaf node that contains the voxel coordinate xyz. If no LeafNode exists...
Definition: ValueAccessor.h:838
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
void operator()(const typename TreeT::LeafCIter &leafIter) const
Definition: Composite.h:846
void setPruneCancelledTiles(bool doprune)
Enables immediate pruning of tiles that cancel each other out.
Definition: Merge.h:242
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition: version.h.in:157
void addLeaf(LeafNodeT *leaf)
Add the specified leaf to this tree, possibly creating a child branch in the process. If the leaf node already exists, replace it.
Definition: ValueAccessor.h:729
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
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
void split(ContainerT &out, const std::string &in, const char delim)
Definition: Name.h:43
CompReplaceOp(TreeT &_aTree)
Definition: Composite.h:836
uint32_t Index32
Definition: Types.h:52
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
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:212
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:128
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
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