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