HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 "ValueTransformer.h" // for transformValues()
19 #include "Prune.h"// for prune
20 #include "SignedFloodFill.h" // for signedFloodFill()
21 
22 #include <tbb/blocked_range.h>
23 #include <tbb/parallel_for.h>
24 #include <tbb/parallel_reduce.h>
25 #include <tbb/task_group.h>
26 #include <tbb/task_scheduler_init.h>
27 
28 #include <type_traits>
29 #include <functional>
30 
31 namespace openvdb {
33 namespace OPENVDB_VERSION_NAME {
34 namespace tools {
35 
36 /// @brief Given two level set grids, replace the A grid with the union of A and B.
37 /// @throw ValueError if the background value of either grid is not greater than zero.
38 /// @note This operation always leaves the B grid empty.
39 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
40 inline void csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
41 /// @brief Given two level set grids, replace the A grid with the intersection of A and B.
42 /// @throw ValueError if the background value of either grid is not greater than zero.
43 /// @note This operation always leaves the B grid empty.
44 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
45 inline void csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
46 /// @brief Given two level set grids, replace the A grid with the difference A / B.
47 /// @throw ValueError if the background value of either grid is not greater than zero.
48 /// @note This operation always leaves the B grid empty.
49 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
50 inline void csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
51 
52 /// @brief Threaded CSG union operation that produces a new grid or tree from
53 /// immutable inputs.
54 /// @return The CSG union of the @a and @b level set inputs.
55 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
56 inline typename GridOrTreeT::Ptr csgUnionCopy(const GridOrTreeT& a, const GridOrTreeT& b);
57 /// @brief Threaded CSG intersection operation that produces a new grid or tree from
58 /// immutable inputs.
59 /// @return The CSG intersection of the @a and @b level set inputs.
60 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
61 inline typename GridOrTreeT::Ptr csgIntersectionCopy(const GridOrTreeT& a, const GridOrTreeT& b);
62 /// @brief Threaded CSG difference operation that produces a new grid or tree from
63 /// immutable inputs.
64 /// @return The CSG difference of the @a and @b level set inputs.
65 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
66 inline typename GridOrTreeT::Ptr csgDifferenceCopy(const GridOrTreeT& a, const GridOrTreeT& b);
67 
68 /// @brief Given grids A and B, compute max(a, b) per voxel (using sparse traversal).
69 /// Store the result in the A grid and leave the B grid empty.
70 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
71 inline void compMax(GridOrTreeT& a, GridOrTreeT& b);
72 /// @brief Given grids A and B, compute min(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> OPENVDB_STATIC_SPECIALIZATION
75 inline void compMin(GridOrTreeT& a, GridOrTreeT& b);
76 /// @brief Given grids A and B, compute 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> OPENVDB_STATIC_SPECIALIZATION
79 inline void compSum(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> OPENVDB_STATIC_SPECIALIZATION
83 inline void compMul(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> OPENVDB_STATIC_SPECIALIZATION
87 inline void compDiv(GridOrTreeT& a, GridOrTreeT& b);
88 
89 /// Copy the active voxels of B into A.
90 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
91 inline void compReplace(GridOrTreeT& a, const GridOrTreeT& b);
92 
93 
94 ////////////////////////////////////////
95 
96 
97 namespace composite {
98 
99 // composite::min() and composite::max() for non-vector types compare with operator<().
100 template<typename T> inline
101 const typename std::enable_if<!VecTraits<T>::IsVec, T>::type& // = T if T is not a vector type
102 min(const T& a, const T& b) { return std::min(a, b); }
103 
104 template<typename T> inline
105 const typename std::enable_if<!VecTraits<T>::IsVec, T>::type&
106 max(const T& a, const T& b) { return std::max(a, b); }
107 
108 
109 // composite::min() and composite::max() for OpenVDB vector types compare by magnitude.
110 template<typename T> inline
111 const typename std::enable_if<VecTraits<T>::IsVec, T>::type& // = T if T is a vector type
112 min(const T& a, const T& b)
113 {
114  const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
115  return (aMag < bMag ? a : (bMag < aMag ? b : std::min(a, b)));
116 }
117 
118 template<typename T> inline
119 const typename std::enable_if<VecTraits<T>::IsVec, T>::type&
120 max(const T& a, const T& b)
121 {
122  const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
123  return (aMag < bMag ? b : (bMag < aMag ? a : std::max(a, b)));
124 }
125 
126 
127 template<typename T> inline
128 typename std::enable_if<!std::is_integral<T>::value, T>::type // = T if T is not an integer type
129 divide(const T& a, const T& b) { return a / b; }
130 
131 template<typename T> inline
132 typename std::enable_if<std::is_integral<T>::value, T>::type // = T if T is an integer type
133 divide(const T& a, const T& b)
134 {
135  const T zero(0);
136  if (b != zero) return a / b;
137  if (a == zero) return 0;
139 }
140 
141 // If b is true, return a / 1 = a.
142 // If b is false and a is true, return 1 / 0 = inf = MAX_BOOL = 1 = a.
143 // If b is false and a is false, return 0 / 0 = NaN = 0 = a.
144 inline bool divide(bool a, bool /*b*/) { return a; }
145 
146 
148 
149 template<typename TreeType, CSGOperation Operation>
151 {
152  using ValueType = typename TreeType::ValueType;
153  using TreePtrType = typename TreeType::Ptr;
154  using LeafNodeType = typename TreeType::LeafNodeType;
155  using NodeMaskType = typename LeafNodeType::NodeMaskType;
156  using RootNodeType = typename TreeType::RootNodeType;
157  using NodeChainType = typename RootNodeType::NodeChainType;
158  using InternalNodeType = typename NodeChainType::template Get<1>;
159 
160  BuildPrimarySegment(const TreeType& lhs, const TreeType& rhs)
161  : mSegment(new TreeType(lhs.background()))
162  , mLhsTree(&lhs)
163  , mRhsTree(&rhs)
164  {
165  }
166 
167  void operator()() const
168  {
169  std::vector<const LeafNodeType*> leafNodes;
170 
171  {
172  std::vector<const InternalNodeType*> internalNodes;
173  mLhsTree->getNodes(internalNodes);
174 
175  ProcessInternalNodes op(internalNodes, *mRhsTree, *mSegment, leafNodes);
176  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
177  }
178 
179  ProcessLeafNodes op(leafNodes, *mRhsTree, *mSegment);
180  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
181  }
182 
183  TreePtrType& segment() { return mSegment; }
184 
185 private:
186 
187  struct ProcessInternalNodes {
188 
189  ProcessInternalNodes(std::vector<const InternalNodeType*>& lhsNodes,
190  const TreeType& rhsTree, TreeType& outputTree,
191  std::vector<const LeafNodeType*>& outputLeafNodes)
192  : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front())
193  , mRhsTree(&rhsTree)
194  , mLocalTree(mRhsTree->background())
195  , mOutputTree(&outputTree)
196  , mLocalLeafNodes()
197  , mOutputLeafNodes(&outputLeafNodes)
198  {
199  }
200 
201  ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
202  : mLhsNodes(other.mLhsNodes)
203  , mRhsTree(other.mRhsTree)
204  , mLocalTree(mRhsTree->background())
205  , mOutputTree(&mLocalTree)
206  , mLocalLeafNodes()
207  , mOutputLeafNodes(&mLocalLeafNodes)
208  {
209  }
210 
211  void join(ProcessInternalNodes& other)
212  {
213  mOutputTree->merge(*other.mOutputTree);
214  mOutputLeafNodes->insert(mOutputLeafNodes->end(),
215  other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
216  }
217 
218  void operator()(const tbb::blocked_range<size_t>& range)
219  {
220  tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
221  tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
222 
223  std::vector<const LeafNodeType*> tmpLeafNodes;
224 
225  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
226 
227  const InternalNodeType& lhsNode = *mLhsNodes[n];
228  const Coord& ijk = lhsNode.origin();
229  const InternalNodeType * rhsNode =
230  rhsAcc.template probeConstNode<InternalNodeType>(ijk);
231 
232  if (rhsNode) {
233  lhsNode.getNodes(*mOutputLeafNodes);
234  } else {
235  if (Operation == CSG_INTERSECTION) {
236  if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
237  tmpLeafNodes.clear();
238  lhsNode.getNodes(tmpLeafNodes);
239  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
240  outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
241  }
242  }
243  } else { // Union & Difference
244  if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
245  tmpLeafNodes.clear();
246  lhsNode.getNodes(tmpLeafNodes);
247  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
248  outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
249  }
250  }
251  }
252  }
253  } // end range loop
254  }
255 
256  InternalNodeType const * const * const mLhsNodes;
257  TreeType const * const mRhsTree;
258  TreeType mLocalTree;
259  TreeType * const mOutputTree;
260 
261  std::vector<const LeafNodeType*> mLocalLeafNodes;
262  std::vector<const LeafNodeType*> * const mOutputLeafNodes;
263  }; // struct ProcessInternalNodes
264 
265  struct ProcessLeafNodes {
266 
267  ProcessLeafNodes(std::vector<const LeafNodeType*>& lhsNodes,
268  const TreeType& rhsTree, TreeType& output)
269  : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front())
270  , mRhsTree(&rhsTree)
271  , mLocalTree(mRhsTree->background())
272  , mOutputTree(&output)
273  {
274  }
275 
276  ProcessLeafNodes(ProcessLeafNodes& other, tbb::split)
277  : mLhsNodes(other.mLhsNodes)
278  , mRhsTree(other.mRhsTree)
279  , mLocalTree(mRhsTree->background())
280  , mOutputTree(&mLocalTree)
281  {
282  }
283 
284  void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
285 
286  void operator()(const tbb::blocked_range<size_t>& range)
287  {
288  tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
289  tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
290 
291  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
292 
293  const LeafNodeType& lhsNode = *mLhsNodes[n];
294  const Coord& ijk = lhsNode.origin();
295 
296  const LeafNodeType* rhsNodePt = rhsAcc.probeConstLeaf(ijk);
297 
298  if (rhsNodePt) { // combine overlapping nodes
299 
300  LeafNodeType* outputNode = outputAcc.touchLeaf(ijk);
301  ValueType * outputData = outputNode->buffer().data();
302  NodeMaskType& outputMask = outputNode->getValueMask();
303 
304  const ValueType * lhsData = lhsNode.buffer().data();
305  const NodeMaskType& lhsMask = lhsNode.getValueMask();
306 
307  const ValueType * rhsData = rhsNodePt->buffer().data();
308  const NodeMaskType& rhsMask = rhsNodePt->getValueMask();
309 
310  if (Operation == CSG_INTERSECTION) {
311  for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
312  const bool fromRhs = lhsData[pos] < rhsData[pos];
313  outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
314  outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
315  }
316  } else if (Operation == CSG_DIFFERENCE){
317  for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
318  const ValueType rhsVal = math::negative(rhsData[pos]);
319  const bool fromRhs = lhsData[pos] < rhsVal;
320  outputData[pos] = fromRhs ? rhsVal : lhsData[pos];
321  outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
322  }
323  } else { // Union
324  for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
325  const bool fromRhs = lhsData[pos] > rhsData[pos];
326  outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
327  outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
328  }
329  }
330 
331  } else {
332  if (Operation == CSG_INTERSECTION) {
333  if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
334  outputAcc.addLeaf(new LeafNodeType(lhsNode));
335  }
336  } else { // Union & Difference
337  if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
338  outputAcc.addLeaf(new LeafNodeType(lhsNode));
339  }
340  }
341  }
342  } // end range loop
343  }
344 
345  LeafNodeType const * const * const mLhsNodes;
346  TreeType const * const mRhsTree;
347  TreeType mLocalTree;
348  TreeType * const mOutputTree;
349  }; // struct ProcessLeafNodes
350 
351  TreePtrType mSegment;
352  TreeType const * const mLhsTree;
353  TreeType const * const mRhsTree;
354 }; // struct BuildPrimarySegment
355 
356 
357 template<typename TreeType, CSGOperation Operation>
359 {
360  using ValueType = typename TreeType::ValueType;
361  using TreePtrType = typename TreeType::Ptr;
362  using LeafNodeType = typename TreeType::LeafNodeType;
363  using NodeMaskType = typename LeafNodeType::NodeMaskType;
364  using RootNodeType = typename TreeType::RootNodeType;
365  using NodeChainType = typename RootNodeType::NodeChainType;
366  using InternalNodeType = typename NodeChainType::template Get<1>;
367 
368  BuildSecondarySegment(const TreeType& lhs, const TreeType& rhs)
369  : mSegment(new TreeType(lhs.background()))
370  , mLhsTree(&lhs)
371  , mRhsTree(&rhs)
372  {
373  }
374 
375  void operator()() const
376  {
377  std::vector<const LeafNodeType*> leafNodes;
378 
379  {
380  std::vector<const InternalNodeType*> internalNodes;
381  mRhsTree->getNodes(internalNodes);
382 
383  ProcessInternalNodes op(internalNodes, *mLhsTree, *mSegment, leafNodes);
384  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
385  }
386 
387  ProcessLeafNodes op(leafNodes, *mLhsTree, *mSegment);
388  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
389  }
390 
391  TreePtrType& segment() { return mSegment; }
392 
393 private:
394 
395  struct ProcessInternalNodes {
396 
397  ProcessInternalNodes(std::vector<const InternalNodeType*>& rhsNodes,
398  const TreeType& lhsTree, TreeType& outputTree,
399  std::vector<const LeafNodeType*>& outputLeafNodes)
400  : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front())
401  , mLhsTree(&lhsTree)
402  , mLocalTree(mLhsTree->background())
403  , mOutputTree(&outputTree)
404  , mLocalLeafNodes()
405  , mOutputLeafNodes(&outputLeafNodes)
406  {
407  }
408 
409  ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
410  : mRhsNodes(other.mRhsNodes)
411  , mLhsTree(other.mLhsTree)
412  , mLocalTree(mLhsTree->background())
413  , mOutputTree(&mLocalTree)
414  , mLocalLeafNodes()
415  , mOutputLeafNodes(&mLocalLeafNodes)
416  {
417  }
418 
419  void join(ProcessInternalNodes& other)
420  {
421  mOutputTree->merge(*other.mOutputTree);
422  mOutputLeafNodes->insert(mOutputLeafNodes->end(),
423  other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
424  }
425 
426  void operator()(const tbb::blocked_range<size_t>& range)
427  {
428  tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
429  tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
430 
431  std::vector<const LeafNodeType*> tmpLeafNodes;
432 
433  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
434 
435  const InternalNodeType& rhsNode = *mRhsNodes[n];
436  const Coord& ijk = rhsNode.origin();
437  const InternalNodeType * lhsNode =
438  lhsAcc.template probeConstNode<InternalNodeType>(ijk);
439 
440  if (lhsNode) {
441  rhsNode.getNodes(*mOutputLeafNodes);
442  } else {
443  if (Operation == CSG_INTERSECTION) {
444  if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
445  tmpLeafNodes.clear();
446  rhsNode.getNodes(tmpLeafNodes);
447  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
448  outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
449  }
450  }
451  } else if (Operation == CSG_DIFFERENCE) {
452  if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
453  tmpLeafNodes.clear();
454  rhsNode.getNodes(tmpLeafNodes);
455  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
456  LeafNodeType* outputNode = new LeafNodeType(*tmpLeafNodes[i]);
457  outputNode->negate();
458  outputAcc.addLeaf(outputNode);
459  }
460  }
461  } else { // Union
462  if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
463  tmpLeafNodes.clear();
464  rhsNode.getNodes(tmpLeafNodes);
465  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
466  outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
467  }
468  }
469  }
470  }
471  } // end range loop
472  }
473 
474  InternalNodeType const * const * const mRhsNodes;
475  TreeType const * const mLhsTree;
476  TreeType mLocalTree;
477  TreeType * const mOutputTree;
478 
479  std::vector<const LeafNodeType*> mLocalLeafNodes;
480  std::vector<const LeafNodeType*> * const mOutputLeafNodes;
481  }; // struct ProcessInternalNodes
482 
483  struct ProcessLeafNodes {
484 
485  ProcessLeafNodes(std::vector<const LeafNodeType*>& rhsNodes,
486  const TreeType& lhsTree, TreeType& output)
487  : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front())
488  , mLhsTree(&lhsTree)
489  , mLocalTree(mLhsTree->background())
490  , mOutputTree(&output)
491  {
492  }
493 
494  ProcessLeafNodes(ProcessLeafNodes& rhs, tbb::split)
495  : mRhsNodes(rhs.mRhsNodes)
496  , mLhsTree(rhs.mLhsTree)
497  , mLocalTree(mLhsTree->background())
498  , mOutputTree(&mLocalTree)
499  {
500  }
501 
502  void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
503 
504  void operator()(const tbb::blocked_range<size_t>& range)
505  {
506  tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
507  tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
508 
509  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
510 
511  const LeafNodeType& rhsNode = *mRhsNodes[n];
512  const Coord& ijk = rhsNode.origin();
513 
514  const LeafNodeType* lhsNode = lhsAcc.probeConstLeaf(ijk);
515 
516  if (!lhsNode) {
517  if (Operation == CSG_INTERSECTION) {
518  if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
519  outputAcc.addLeaf(new LeafNodeType(rhsNode));
520  }
521  } else if (Operation == CSG_DIFFERENCE) {
522  if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
523  LeafNodeType* outputNode = new LeafNodeType(rhsNode);
524  outputNode->negate();
525  outputAcc.addLeaf(outputNode);
526  }
527  } else { // Union
528  if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
529  outputAcc.addLeaf(new LeafNodeType(rhsNode));
530  }
531  }
532  }
533  } // end range loop
534  }
535 
536  LeafNodeType const * const * const mRhsNodes;
537  TreeType const * const mLhsTree;
538  TreeType mLocalTree;
539  TreeType * const mOutputTree;
540  }; // struct ProcessLeafNodes
541 
542  TreePtrType mSegment;
543  TreeType const * const mLhsTree;
544  TreeType const * const mRhsTree;
545 }; // struct BuildSecondarySegment
546 
547 
548 template<CSGOperation Operation, typename TreeType>
549 inline typename TreeType::Ptr
550 doCSGCopy(const TreeType& lhs, const TreeType& rhs)
551 {
553  BuildSecondarySegment<TreeType, Operation> secondary(lhs, rhs);
554 
555  // Exploiting nested parallelism
556  tbb::task_group tasks;
557  tasks.run(primary);
558  tasks.run(secondary);
559  tasks.wait();
560 
561  primary.segment()->merge(*secondary.segment());
562 
563  // The leafnode (level = 0) sign is set in the segment construction.
564  tools::signedFloodFill(*primary.segment(), /*threaded=*/true, /*grainSize=*/1, /*minLevel=*/1);
565 
566  return primary.segment();
567 }
568 
569 
570 ////////////////////////////////////////
571 
572 
573 template<typename TreeType>
575 {
576  using TreeTypePtr = typename TreeType::Ptr;
577  static TreeTypePtr construct(const TreeType&, TreeTypePtr& tree) { return tree; }
578 };
579 
580 
581 template<typename TreeType>
582 struct GridOrTreeConstructor<Grid<TreeType> >
583 {
586  using TreeTypePtr = typename TreeType::Ptr;
587 
588  static GridTypePtr construct(const GridType& grid, TreeTypePtr& tree) {
589  GridTypePtr maskGrid(GridType::create(tree));
590  maskGrid->setTransform(grid.transform().copy());
591  maskGrid->insertMeta(grid);
592  return maskGrid;
593  }
594 };
595 
596 
597 ////////////////////////////////////////
598 
599 /// @cond COMPOSITE_INTERNAL
600 /// List of pairs of leaf node pointers
601 template <typename LeafT>
602 using LeafPairList = std::vector<std::pair<LeafT*, LeafT*>>;
603 /// @endcond
604 
605 /// @cond COMPOSITE_INTERNAL
606 /// Transfers leaf nodes from a source tree into a
607 /// desitnation tree, unless it already exists in the destination tree
608 /// in which case pointers to both leaf nodes are added to a list for
609 /// subsequent compositing operations.
610 template <typename TreeT>
611 inline void transferLeafNodes(TreeT &srcTree, TreeT &dstTree,
612  LeafPairList<typename TreeT::LeafNodeType> &overlapping)
613 {
614  using LeafT = typename TreeT::LeafNodeType;
615  tree::ValueAccessor<TreeT> acc(dstTree);//destination
616  std::vector<LeafT*> srcLeafNodes;
617  srcLeafNodes.reserve(srcTree.leafCount());
618  srcTree.stealNodes(srcLeafNodes);
619  srcTree.clear();
620  for (LeafT *srcLeaf : srcLeafNodes) {
621  LeafT *dstLeaf = acc.probeLeaf(srcLeaf->origin());
622  if (dstLeaf) {
623  overlapping.emplace_back(dstLeaf, srcLeaf);//dst, src
624  } else {
625  acc.addLeaf(srcLeaf);
626  }
627  }
628 }
629 /// @endcond
630 
631 /// @cond COMPOSITE_INTERNAL
632 /// Template specailization of compActiveLeafVoxels
633 template <typename TreeT, typename OpT>
634 inline
635 typename std::enable_if<
638  std::is_same<typename TreeT::LeafNodeType::Buffer::ValueType,
639  typename TreeT::LeafNodeType::Buffer::StorageType>::value>::type
640 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
641 {
642  using LeafT = typename TreeT::LeafNodeType;
643  LeafPairList<LeafT> overlapping;//dst, src
644  transferLeafNodes(srcTree, dstTree, overlapping);
645 
646  using RangeT = tbb::blocked_range<size_t>;
647  tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](const RangeT& r) {
648  for (auto i = r.begin(); i != r.end(); ++i) {
649  LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
650  dstLeaf->getValueMask() |= srcLeaf->getValueMask();
651  auto *ptr = dstLeaf->buffer().data();
652  for (auto v = srcLeaf->cbeginValueOn(); v; ++v) op(ptr[v.pos()], *v);
653  delete srcLeaf;
654  }
655  });
656 }
657 /// @endcond
658 
659 /// @cond COMPOSITE_INTERNAL
660 /// Template specailization of compActiveLeafVoxels
661 template <typename TreeT, typename OpT>
662 inline
663 typename std::enable_if<
666 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT)
667 {
668  using LeafT = typename TreeT::LeafNodeType;
669  LeafPairList<LeafT> overlapping;//dst, src
670  transferLeafNodes(srcTree, dstTree, overlapping);
671 
672  using RangeT = tbb::blocked_range<size_t>;
673  tbb::parallel_for(RangeT(0, overlapping.size()), [&overlapping](const RangeT& r) {
674  for (auto i = r.begin(); i != r.end(); ++i) {
675  overlapping[i].first->getValueMask() |= overlapping[i].second->getValueMask();
676  delete overlapping[i].second;
677  }
678  });
679 }
680 
681 /// @cond COMPOSITE_INTERNAL
682 /// Template specailization of compActiveLeafVoxels
683 template <typename TreeT, typename OpT>
684 inline
685 typename std::enable_if<
688 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
689 {
690  using LeafT = typename TreeT::LeafNodeType;
691  LeafPairList<LeafT> overlapping;//dst, src
692  transferLeafNodes(srcTree, dstTree, overlapping);
693 
694  using RangeT = tbb::blocked_range<size_t>;
695  using WordT = typename LeafT::Buffer::WordType;
696  tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](const RangeT& r) {
697  for (auto i = r.begin(); i != r.end(); ++i) {
698  LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
699  WordT *w1 = dstLeaf->buffer().data();
700  const WordT *w2 = srcLeaf->buffer().data();
701  const WordT *w3 = &(srcLeaf->getValueMask().template getWord<WordT>(0));
702  for (Index32 n = LeafT::Buffer::WORD_COUNT; n--; ++w1) {
703  WordT tmp = *w1, state = *w3++;
704  op (tmp, *w2++);
705  *w1 = (state & tmp) | (~state & *w1);//inactive values are unchanged
706  }
707  dstLeaf->getValueMask() |= srcLeaf->getValueMask();
708  delete srcLeaf;
709  }
710  });
711 }
712 /// @endcond
713 
714 /// @cond COMPOSITE_INTERNAL
715 /// Default functor for compActiveLeafVoxels
716 template <typename TreeT>
717 struct CopyOp
718 {
719  using ValueT = typename TreeT::ValueType;
720  CopyOp() = default;
721  void operator()(ValueT& dst, const ValueT& src) const { dst = src; }
722 };
723 /// @endcond
724 
725 } // namespace composite
726 
727 
728 template<typename GridOrTreeT>
730 compMax(GridOrTreeT& aTree, GridOrTreeT& bTree)
731 {
732  using Adapter = TreeAdapter<GridOrTreeT>;
733  using TreeT = typename Adapter::TreeType;
734  using ValueT = typename TreeT::ValueType;
735  struct Local {
736  static inline void op(CombineArgs<ValueT>& args) {
737  args.setResult(composite::max(args.a(), args.b()));
738  }
739  };
740  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
741 }
742 
743 
744 template<typename GridOrTreeT>
746 compMin(GridOrTreeT& aTree, GridOrTreeT& bTree)
747 {
748  using Adapter = TreeAdapter<GridOrTreeT>;
749  using TreeT = typename Adapter::TreeType;
750  using ValueT = typename TreeT::ValueType;
751  struct Local {
752  static inline void op(CombineArgs<ValueT>& args) {
753  args.setResult(composite::min(args.a(), args.b()));
754  }
755  };
756  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
757 }
758 
759 
760 template<typename GridOrTreeT>
762 compSum(GridOrTreeT& aTree, GridOrTreeT& bTree)
763 {
764  using Adapter = TreeAdapter<GridOrTreeT>;
765  using TreeT = typename Adapter::TreeType;
766  struct Local {
767  static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
768  args.setResult(args.a() + args.b());
769  }
770  };
771  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
772 }
773 
774 
775 template<typename GridOrTreeT>
777 compMul(GridOrTreeT& aTree, GridOrTreeT& bTree)
778 {
779  using Adapter = TreeAdapter<GridOrTreeT>;
780  using TreeT = typename Adapter::TreeType;
781  struct Local {
782  static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
783  args.setResult(args.a() * args.b());
784  }
785  };
786  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
787 }
788 
789 
790 template<typename GridOrTreeT>
792 compDiv(GridOrTreeT& aTree, GridOrTreeT& bTree)
793 {
794  using Adapter = TreeAdapter<GridOrTreeT>;
795  using TreeT = typename Adapter::TreeType;
796  struct Local {
797  static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
798  args.setResult(composite::divide(args.a(), args.b()));
799  }
800  };
801  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
802 }
803 
804 
805 ////////////////////////////////////////
806 
807 
808 template<typename TreeT>
810 {
811  TreeT* const aTree;
812 
813  CompReplaceOp(TreeT& _aTree): aTree(&_aTree) {}
814 
815  /// @note fill operation is not thread safe
816  void operator()(const typename TreeT::ValueOnCIter& iter) const
817  {
818  CoordBBox bbox;
819  iter.getBoundingBox(bbox);
820  aTree->fill(bbox, *iter);
821  }
822 
823  void operator()(const typename TreeT::LeafCIter& leafIter) const
824  {
826  for (typename TreeT::LeafCIter::LeafNodeT::ValueOnCIter iter =
827  leafIter->cbeginValueOn(); iter; ++iter)
828  {
829  acc.setValue(iter.getCoord(), *iter);
830  }
831  }
832 };
833 
834 
835 template<typename GridOrTreeT>
837 compReplace(GridOrTreeT& aTree, const GridOrTreeT& bTree)
838 {
839  using Adapter = TreeAdapter<GridOrTreeT>;
840  using TreeT = typename Adapter::TreeType;
841  using ValueOnCIterT = typename TreeT::ValueOnCIter;
842 
843  // Copy active states (but not values) from B to A.
844  Adapter::tree(aTree).topologyUnion(Adapter::tree(bTree));
845 
846  CompReplaceOp<TreeT> op(Adapter::tree(aTree));
847 
848  // Copy all active tile values from B to A.
849  ValueOnCIterT iter = bTree.cbeginValueOn();
850  iter.setMaxDepth(iter.getLeafDepth() - 1); // don't descend into leaf nodes
851  foreach(iter, op, /*threaded=*/false);
852 
853  // Copy all active voxel values from B to A.
854  foreach(Adapter::tree(bTree).cbeginLeaf(), op);
855 }
856 
857 
858 ////////////////////////////////////////
859 
860 
861 /// Base visitor class for CSG operations
862 /// (not intended to be used polymorphically, so no virtual functions)
863 template<typename TreeType>
865 {
866 public:
867  using TreeT = TreeType;
868  using ValueT = typename TreeT::ValueType;
869  using ChildIterT = typename TreeT::LeafNodeType::ChildAllIter;
870 
871  enum { STOP = 3 };
872 
873  CsgVisitorBase(const TreeT& aTree, const TreeT& bTree):
874  mAOutside(aTree.background()),
875  mAInside(math::negative(mAOutside)),
876  mBOutside(bTree.background()),
877  mBInside(math::negative(mBOutside))
878  {
879  const ValueT zero = zeroVal<ValueT>();
880  if (!(mAOutside > zero)) {
881  OPENVDB_THROW(ValueError,
882  "expected grid A outside value > 0, got " << mAOutside);
883  }
884  if (!(mAInside < zero)) {
885  OPENVDB_THROW(ValueError,
886  "expected grid A inside value < 0, got " << mAInside);
887  }
888  if (!(mBOutside > zero)) {
889  OPENVDB_THROW(ValueError,
890  "expected grid B outside value > 0, got " << mBOutside);
891  }
892  if (!(mBInside < zero)) {
893  OPENVDB_THROW(ValueError,
894  "expected grid B outside value < 0, got " << mBOutside);
895  }
896  }
897 
898 protected:
900 };
901 
902 
903 ////////////////////////////////////////
904 
905 
906 template<typename TreeType>
907 struct CsgUnionVisitor: public CsgVisitorBase<TreeType>
908 {
909  using TreeT = TreeType;
910  using ValueT = typename TreeT::ValueType;
911  using ChildIterT = typename TreeT::LeafNodeType::ChildAllIter;
912 
914 
915  CsgUnionVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase<TreeT>(a, b) {}
916 
917  /// Don't process nodes that are at different tree levels.
918  template<typename AIterT, typename BIterT>
919  inline int operator()(AIterT&, BIterT&) { return 0; }
920 
921  /// Process root and internal nodes.
922  template<typename IterT>
923  inline int operator()(IterT& aIter, IterT& bIter)
924  {
925  ValueT aValue = zeroVal<ValueT>();
926  typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue);
927  if (!aChild && aValue < zeroVal<ValueT>()) {
928  // A is an inside tile. Leave it alone and stop traversing this branch.
929  return STOP;
930  }
931 
932  ValueT bValue = zeroVal<ValueT>();
933  typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue);
934  if (!bChild && bValue < zeroVal<ValueT>()) {
935  // B is an inside tile. Make A an inside tile and stop traversing this branch.
936  aIter.setValue(this->mAInside);
937  aIter.setValueOn(bIter.isValueOn());
938  delete aChild;
939  return STOP;
940  }
941 
942  if (!aChild && aValue > zeroVal<ValueT>()) {
943  // A is an outside tile. If B has a child, transfer it to A,
944  // otherwise leave A alone.
945  if (bChild) {
946  bIter.setValue(this->mBOutside);
947  bIter.setValueOff();
948  bChild->resetBackground(this->mBOutside, this->mAOutside);
949  aIter.setChild(bChild); // transfer child
950  delete aChild;
951  }
952  return STOP;
953  }
954 
955  // If A has a child and B is an outside tile, stop traversing this branch.
956  // Continue traversal only if A and B both have children.
957  return (aChild && bChild) ? 0 : STOP;
958  }
959 
960  /// Process leaf node values.
961  inline int operator()(ChildIterT& aIter, ChildIterT& bIter)
962  {
963  ValueT aValue, bValue;
964  aIter.probeValue(aValue);
965  bIter.probeValue(bValue);
966  if (aValue > bValue) { // a = min(a, b)
967  aIter.setValue(bValue);
968  aIter.setValueOn(bIter.isValueOn());
969  }
970  return 0;
971  }
972 };
973 
974 
975 
976 ////////////////////////////////////////
977 
978 
979 template<typename TreeType>
980 struct CsgIntersectVisitor: public CsgVisitorBase<TreeType>
981 {
982  using TreeT = TreeType;
983  using ValueT = typename TreeT::ValueType;
984  using ChildIterT = typename TreeT::LeafNodeType::ChildAllIter;
985 
987 
988  CsgIntersectVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase<TreeT>(a, b) {}
989 
990  /// Don't process nodes that are at different tree levels.
991  template<typename AIterT, typename BIterT>
992  inline int operator()(AIterT&, BIterT&) { return 0; }
993 
994  /// Process root and internal nodes.
995  template<typename IterT>
996  inline int operator()(IterT& aIter, IterT& bIter)
997  {
998  ValueT aValue = zeroVal<ValueT>();
999  typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue);
1000  if (!aChild && !(aValue < zeroVal<ValueT>())) {
1001  // A is an outside tile. Leave it alone and stop traversing this branch.
1002  return STOP;
1003  }
1004 
1005  ValueT bValue = zeroVal<ValueT>();
1006  typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue);
1007  if (!bChild && !(bValue < zeroVal<ValueT>())) {
1008  // B is an outside tile. Make A an outside tile and stop traversing this branch.
1009  aIter.setValue(this->mAOutside);
1010  aIter.setValueOn(bIter.isValueOn());
1011  delete aChild;
1012  return STOP;
1013  }
1014 
1015  if (!aChild && aValue < zeroVal<ValueT>()) {
1016  // A is an inside tile. If B has a child, transfer it to A,
1017  // otherwise leave A alone.
1018  if (bChild) {
1019  bIter.setValue(this->mBOutside);
1020  bIter.setValueOff();
1021  bChild->resetBackground(this->mBOutside, this->mAOutside);
1022  aIter.setChild(bChild); // transfer child
1023  delete aChild;
1024  }
1025  return STOP;
1026  }
1027 
1028  // If A has a child and B is an outside tile, stop traversing this branch.
1029  // Continue traversal only if A and B both have children.
1030  return (aChild && bChild) ? 0 : STOP;
1031  }
1032 
1033  /// Process leaf node values.
1034  inline int operator()(ChildIterT& aIter, ChildIterT& bIter)
1035  {
1036  ValueT aValue, bValue;
1037  aIter.probeValue(aValue);
1038  bIter.probeValue(bValue);
1039  if (aValue < bValue) { // a = max(a, b)
1040  aIter.setValue(bValue);
1041  aIter.setValueOn(bIter.isValueOn());
1042  }
1043  return 0;
1044  }
1045 };
1046 
1047 
1048 ////////////////////////////////////////
1049 
1050 
1051 template<typename TreeType>
1052 struct CsgDiffVisitor: public CsgVisitorBase<TreeType>
1053 {
1054  using TreeT = TreeType;
1055  using ValueT = typename TreeT::ValueType;
1056  using ChildIterT = typename TreeT::LeafNodeType::ChildAllIter;
1057 
1059 
1060  CsgDiffVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase<TreeT>(a, b) {}
1061 
1062  /// Don't process nodes that are at different tree levels.
1063  template<typename AIterT, typename BIterT>
1064  inline int operator()(AIterT&, BIterT&) { return 0; }
1065 
1066  /// Process root and internal nodes.
1067  template<typename IterT>
1068  inline int operator()(IterT& aIter, IterT& bIter)
1069  {
1070  ValueT aValue = zeroVal<ValueT>();
1071  typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue);
1072  if (!aChild && !(aValue < zeroVal<ValueT>())) {
1073  // A is an outside tile. Leave it alone and stop traversing this branch.
1074  return STOP;
1075  }
1076 
1077  ValueT bValue = zeroVal<ValueT>();
1078  typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue);
1079  if (!bChild && bValue < zeroVal<ValueT>()) {
1080  // B is an inside tile. Make A an inside tile and stop traversing this branch.
1081  aIter.setValue(this->mAOutside);
1082  aIter.setValueOn(bIter.isValueOn());
1083  delete aChild;
1084  return STOP;
1085  }
1086 
1087  if (!aChild && aValue < zeroVal<ValueT>()) {
1088  // A is an inside tile. If B has a child, transfer it to A,
1089  // otherwise leave A alone.
1090  if (bChild) {
1091  bIter.setValue(this->mBOutside);
1092  bIter.setValueOff();
1093  bChild->resetBackground(this->mBOutside, this->mAOutside);
1094  aIter.setChild(bChild); // transfer child
1095  bChild->negate();
1096  delete aChild;
1097  }
1098  return STOP;
1099  }
1100 
1101  // If A has a child and B is an outside tile, stop traversing this branch.
1102  // Continue traversal only if A and B both have children.
1103  return (aChild && bChild) ? 0 : STOP;
1104  }
1105 
1106  /// Process leaf node values.
1107  inline int operator()(ChildIterT& aIter, ChildIterT& bIter)
1108  {
1109  ValueT aValue, bValue;
1110  aIter.probeValue(aValue);
1111  bIter.probeValue(bValue);
1112  bValue = math::negative(bValue);
1113  if (aValue < bValue) { // a = max(a, -b)
1114  aIter.setValue(bValue);
1115  aIter.setValueOn(bIter.isValueOn());
1116  }
1117  return 0;
1118  }
1119 };
1120 
1121 
1122 ////////////////////////////////////////
1123 
1124 
1125 template<typename GridOrTreeT>
1127 csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune)
1128 {
1129  using Adapter = TreeAdapter<GridOrTreeT>;
1130  using TreeT = typename Adapter::TreeType;
1131  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
1132  CsgUnionVisitor<TreeT> visitor(aTree, bTree);
1133  aTree.visit2(bTree, visitor);
1134  if (prune) tools::pruneLevelSet(aTree);
1135 }
1136 
1137 template<typename GridOrTreeT>
1139 csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune)
1140 {
1141  using Adapter = TreeAdapter<GridOrTreeT>;
1142  using TreeT = typename Adapter::TreeType;
1143  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
1144  CsgIntersectVisitor<TreeT> visitor(aTree, bTree);
1145  aTree.visit2(bTree, visitor);
1146  if (prune) tools::pruneLevelSet(aTree);
1147 }
1148 
1149 template<typename GridOrTreeT>
1151 csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune)
1152 {
1153  using Adapter = TreeAdapter<GridOrTreeT>;
1154  using TreeT = typename Adapter::TreeType;
1155  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
1156  CsgDiffVisitor<TreeT> visitor(aTree, bTree);
1157  aTree.visit2(bTree, visitor);
1158  if (prune) tools::pruneLevelSet(aTree);
1159 }
1160 
1161 
1162 template<typename GridOrTreeT>
1163 OPENVDB_STATIC_SPECIALIZATION inline typename GridOrTreeT::Ptr
1164 csgUnionCopy(const GridOrTreeT& a, const GridOrTreeT& b)
1165 {
1166  using Adapter = TreeAdapter<GridOrTreeT>;
1167  using TreePtrT = typename Adapter::TreeType::Ptr;
1168 
1169  TreePtrT output = composite::doCSGCopy<composite::CSG_UNION>(
1170  Adapter::tree(a), Adapter::tree(b));
1171 
1173 }
1174 
1175 
1176 template<typename GridOrTreeT>
1177 OPENVDB_STATIC_SPECIALIZATION inline typename GridOrTreeT::Ptr
1178 csgIntersectionCopy(const GridOrTreeT& a, const GridOrTreeT& b)
1179 {
1180  using Adapter = TreeAdapter<GridOrTreeT>;
1181  using TreePtrT = typename Adapter::TreeType::Ptr;
1182 
1183  TreePtrT output = composite::doCSGCopy<composite::CSG_INTERSECTION>(
1184  Adapter::tree(a), Adapter::tree(b));
1185 
1187 }
1188 
1189 
1190 template<typename GridOrTreeT>
1191 OPENVDB_STATIC_SPECIALIZATION inline typename GridOrTreeT::Ptr
1192 csgDifferenceCopy(const GridOrTreeT& a, const GridOrTreeT& b)
1193 {
1194  using Adapter = TreeAdapter<GridOrTreeT>;
1195  using TreePtrT = typename Adapter::TreeType::Ptr;
1196 
1197  TreePtrT output = composite::doCSGCopy<composite::CSG_DIFFERENCE>(
1198  Adapter::tree(a), Adapter::tree(b));
1199 
1201 }
1202 
1203 ////////////////////////////////////////////////////////
1204 
1205 /// @brief Composite the active values in leaf nodes, i.e. active
1206 /// voxels, of a source tree into a destination tree.
1207 ///
1208 /// @param srcTree source tree from which active voxels are composited.
1209 ///
1210 /// @param dstTree destination tree into which active voxels are composited.
1211 ///
1212 /// @param op a functor of the form <tt>void op(T& dst, const T& src)</tt>,
1213 /// where @c T is the @c ValueType of the tree, that composites
1214 /// a source value into a destination value. By default
1215 /// it copies the value from src to dst.
1216 ///
1217 /// @details All active voxels in the source tree will
1218 /// be active in the destination tree, and their value is
1219 /// determined by a use-defined functor (OpT op) that operates on the
1220 /// source and destination values. The only exception is when
1221 /// the tree type is MaskTree, in which case no functor is
1222 /// needed since by defintion a MaskTree has no values (only topology).
1223 ///
1224 /// @warning This function only operated on leaf node values,
1225 /// i.e. tile values are ignored.
1226 template<typename TreeT, typename OpT = composite::CopyOp<TreeT> >
1227 inline void
1228 compActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op = composite::CopyOp<TreeT>())
1229 {
1230  composite::doCompActiveLeafVoxels<TreeT, OpT>(srcTree, dstTree, op);
1231 }
1232 
1233 
1234 } // namespace tools
1235 } // namespace OPENVDB_VERSION_NAME
1236 } // namespace openvdb
1237 
1238 #endif // OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
void parallel_for(int64_t start, int64_t end, std::function< void(int64_t index)> &&task, parallel_options opt=parallel_options(0, Split_Y, 1))
Definition: parallel.h:153
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
GLenum GLint * range
Definition: glew.h:3500
OPENVDB_STATIC_SPECIALIZATION 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:792
OPENVDB_STATIC_SPECIALIZATION 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:746
CsgIntersectVisitor(const TreeT &a, const TreeT &b)
Definition: Composite.h:988
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:931
GLenum src
Definition: glew.h:2410
#define OPENVDB_STATIC_SPECIALIZATION
Definition: Platform.h:62
typename NodeChainType::template Get< 1 > InternalNodeType
Definition: Composite.h:366
BuildSecondarySegment(const TreeType &lhs, const TreeType &rhs)
Definition: Composite.h:368
const Args & args
Definition: printf.h:628
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:90
typename TreeT::LeafNodeType::ChildAllIter ChildIterT
Definition: Composite.h:869
OPENVDB_STATIC_SPECIALIZATION 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:1164
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:9477
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:166
int operator()(ChildIterT &aIter, ChildIterT &bIter)
Process leaf node values.
Definition: Composite.h:1107
const GLdouble * v
Definition: glew.h:1391
void operator()(const typename TreeT::ValueOnCIter &iter) const
Definition: Composite.h:816
int operator()(AIterT &, BIterT &)
Don't process nodes that are at different tree levels.
Definition: Composite.h:1064
OPENVDB_STATIC_SPECIALIZATION 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:1192
OPENVDB_STATIC_SPECIALIZATION void csgIntersection(GridOrTreeT &a, GridOrTreeT &b, bool prune=true)
Given two level set grids, replace the A grid with the intersection of A and B.
Definition: Composite.h:1139
This adapter allows code that is templated on a Tree type to accept either a Tree type or a Grid type...
Definition: Grid.h:1068
int operator()(IterT &aIter, IterT &bIter)
Process root and internal nodes.
Definition: Composite.h:996
SYS_FORCE_INLINE const_iterator end() const
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:1228
const AValueType & a() const
Get the A input value.
Definition: Types.h:971
static GridTypePtr construct(const GridType &grid, TreeTypePtr &tree)
Definition: Composite.h:588
int operator()(AIterT &, BIterT &)
Don't process nodes that are at different tree levels.
Definition: Composite.h:919
OPENVDB_STATIC_SPECIALIZATION 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:777
int operator()(IterT &aIter, IterT &bIter)
Process root and internal nodes.
Definition: Composite.h:1068
void OIIO_API split(string_view str, std::vector< string_view > &result, string_view sep=string_view(), int maxsplit=-1)
int operator()(ChildIterT &aIter, ChildIterT &bIter)
Process leaf node values.
Definition: Composite.h:961
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:106
CsgDiffVisitor(const TreeT &a, const TreeT &b)
Definition: Composite.h:1060
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
int operator()(AIterT &, BIterT &)
Don't process nodes that are at different tree levels.
Definition: Composite.h:992
const std::enable_if< VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:120
GLsizei n
Definition: glew.h:4040
Defined various multi-threaded utility functions for trees.
GLenum GLenum dst
Definition: glew.h:2410
typename NodeChainType::template Get< 1 > InternalNodeType
Definition: Composite.h:158
void operator()(const typename TreeT::LeafCIter &leafIter) const
Definition: Composite.h:823
const std::enable_if< VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:112
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1253
math::Transform & transform()
Return a reference to this grid's transform, which might be shared with other grids.
Definition: Grid.h:410
CsgVisitorBase(const TreeT &aTree, const TreeT &bTree)
Definition: Composite.h:873
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
int operator()(IterT &aIter, IterT &bIter)
Process root and internal nodes.
Definition: Composite.h:923
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
GLdouble GLdouble GLdouble b
Definition: glew.h:9122
OPENVDB_STATIC_SPECIALIZATION void csgDifference(GridOrTreeT &a, GridOrTreeT &b, bool prune=true)
Given two level set grids, replace the A grid with the difference A / B.
Definition: Composite.h:1151
int operator()(ChildIterT &aIter, ChildIterT &bIter)
Process leaf node values.
Definition: Composite.h:1034
const void * ptr(const T *p)
Definition: format.h:3292
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...
CsgUnionVisitor(const TreeT &a, const TreeT &b)
Definition: Composite.h:915
OPENVDB_STATIC_SPECIALIZATION 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:730
OPENVDB_STATIC_SPECIALIZATION void csgUnion(GridOrTreeT &a, GridOrTreeT &b, bool prune=true)
Given two level set grids, replace the A grid with the union of A and B.
Definition: Composite.h:1127
GLdouble GLdouble GLdouble r
Definition: glew.h:1406
OPENVDB_STATIC_SPECIALIZATION void compReplace(GridOrTreeT &a, const GridOrTreeT &b)
Copy the active voxels of B into A.
Definition: Composite.h:837
GA_API const UT_StringHolder N
arg_join< It, char > join(It begin, It end, string_view sep)
Definition: format.h:3326
static TreeTypePtr construct(const TreeType &, TreeTypePtr &tree)
Definition: Composite.h:577
#define SIZE
Definition: simple.C:40
OPENVDB_STATIC_SPECIALIZATION 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:1178
TreeType::Ptr doCSGCopy(const TreeType &lhs, const TreeType &rhs)
Definition: Composite.h:550
const BValueType & b() const
Get the B input value.
Definition: Types.h:973
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:334
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:389
ImageBuf OIIO_API zero(ROI roi, int nthreads=0)
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:102
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:112
GLsizei const GLfloat * value
Definition: glew.h:1849
CombineArgs & setResult(const AValueType &val)
Set the output value.
Definition: Types.h:981
OPENVDB_STATIC_SPECIALIZATION 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:762
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:82
std::enable_if<!std::is_integral< T >::value, T >::type divide(const T &a, const T &b)
Definition: Composite.h:129
BuildPrimarySegment(const TreeType &lhs, const TreeType &rhs)
Definition: Composite.h:160