OpenVDB  6.2.0
Composite.h
Go to the documentation of this file.
1 //
3 // Copyright (c) DreamWorks Animation LLC
4 //
5 // All rights reserved. This software is distributed under the
6 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
7 //
8 // Redistributions of source code must retain the above copyright
9 // and license notice and the following restrictions and disclaimer.
10 //
11 // * Neither the name of DreamWorks Animation nor the names of
12 // its contributors may be used to endorse or promote products derived
13 // from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
27 // LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
28 //
30 //
36 
37 #ifndef OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
38 #define OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
39 
40 #include <openvdb/Platform.h>
41 #include <openvdb/Exceptions.h>
42 #include <openvdb/Types.h>
43 #include <openvdb/Grid.h>
44 #include <openvdb/math/Math.h> // for isExactlyEqual()
45 #include "ValueTransformer.h" // for transformValues()
46 #include "Prune.h"// for prune
47 #include "SignedFloodFill.h" // for signedFloodFill()
48 
49 #include <tbb/blocked_range.h>
50 #include <tbb/parallel_for.h>
51 #include <tbb/parallel_reduce.h>
52 #include <tbb/task_group.h>
53 #include <tbb/task_scheduler_init.h>
54 
55 #include <type_traits>
56 #include <functional>
57 
58 namespace openvdb {
60 namespace OPENVDB_VERSION_NAME {
61 namespace tools {
62 
66 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
67 inline void csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
71 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
72 inline void csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
76 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
77 inline void csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
78 
82 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
83 inline typename GridOrTreeT::Ptr csgUnionCopy(const GridOrTreeT& a, const GridOrTreeT& b);
87 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
88 inline typename GridOrTreeT::Ptr csgIntersectionCopy(const GridOrTreeT& a, const GridOrTreeT& b);
92 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
93 inline typename GridOrTreeT::Ptr csgDifferenceCopy(const GridOrTreeT& a, const GridOrTreeT& b);
94 
97 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
98 inline void compMax(GridOrTreeT& a, GridOrTreeT& b);
101 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
102 inline void compMin(GridOrTreeT& a, GridOrTreeT& b);
105 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
106 inline void compSum(GridOrTreeT& a, GridOrTreeT& b);
109 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
110 inline void compMul(GridOrTreeT& a, GridOrTreeT& b);
113 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
114 inline void compDiv(GridOrTreeT& a, GridOrTreeT& b);
115 
117 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
118 inline void compReplace(GridOrTreeT& a, const GridOrTreeT& b);
119 
120 
122 
123 
124 namespace composite {
125 
126 // composite::min() and composite::max() for non-vector types compare with operator<().
127 template<typename T> inline
128 const typename std::enable_if<!VecTraits<T>::IsVec, T>::type& // = T if T is not a vector type
129 min(const T& a, const T& b) { return std::min(a, b); }
130 
131 template<typename T> inline
132 const typename std::enable_if<!VecTraits<T>::IsVec, T>::type&
133 max(const T& a, const T& b) { return std::max(a, b); }
134 
135 
136 // composite::min() and composite::max() for OpenVDB vector types compare by magnitude.
137 template<typename T> inline
138 const typename std::enable_if<VecTraits<T>::IsVec, T>::type& // = T if T is a vector type
139 min(const T& a, const T& b)
140 {
141  const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
142  return (aMag < bMag ? a : (bMag < aMag ? b : std::min(a, b)));
143 }
144 
145 template<typename T> inline
146 const typename std::enable_if<VecTraits<T>::IsVec, T>::type&
147 max(const T& a, const T& b)
148 {
149  const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
150  return (aMag < bMag ? b : (bMag < aMag ? a : std::max(a, b)));
151 }
152 
153 
154 template<typename T> inline
155 typename std::enable_if<!std::is_integral<T>::value, T>::type // = T if T is not an integer type
156 divide(const T& a, const T& b) { return a / b; }
157 
158 template<typename T> inline
159 typename std::enable_if<std::is_integral<T>::value, T>::type // = T if T is an integer type
160 divide(const T& a, const T& b)
161 {
162  const T zero(0);
163  if (b != zero) return a / b;
164  if (a == zero) return 0;
166 }
167 
168 // If b is true, return a / 1 = a.
169 // If b is false and a is true, return 1 / 0 = inf = MAX_BOOL = 1 = a.
170 // If b is false and a is false, return 0 / 0 = NaN = 0 = a.
171 inline bool divide(bool a, bool /*b*/) { return a; }
172 
173 
175 
176 template<typename TreeType, CSGOperation Operation>
178 {
179  using ValueType = typename TreeType::ValueType;
180  using TreePtrType = typename TreeType::Ptr;
181  using LeafNodeType = typename TreeType::LeafNodeType;
182  using NodeMaskType = typename LeafNodeType::NodeMaskType;
183  using RootNodeType = typename TreeType::RootNodeType;
184  using NodeChainType = typename RootNodeType::NodeChainType;
185  using InternalNodeType = typename boost::mpl::at<NodeChainType, boost::mpl::int_<1> >::type;
186 
187  BuildPrimarySegment(const TreeType& lhs, const TreeType& rhs)
188  : mSegment(new TreeType(lhs.background()))
189  , mLhsTree(&lhs)
190  , mRhsTree(&rhs)
191  {
192  }
193 
194  void operator()() const
195  {
196  std::vector<const LeafNodeType*> leafNodes;
197 
198  {
199  std::vector<const InternalNodeType*> internalNodes;
200  mLhsTree->getNodes(internalNodes);
201 
202  ProcessInternalNodes op(internalNodes, *mRhsTree, *mSegment, leafNodes);
203  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
204  }
205 
206  ProcessLeafNodes op(leafNodes, *mRhsTree, *mSegment);
207  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
208  }
209 
210  TreePtrType& segment() { return mSegment; }
211 
212 private:
213 
214  struct ProcessInternalNodes {
215 
216  ProcessInternalNodes(std::vector<const InternalNodeType*>& lhsNodes,
217  const TreeType& rhsTree, TreeType& outputTree,
218  std::vector<const LeafNodeType*>& outputLeafNodes)
219  : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front())
220  , mRhsTree(&rhsTree)
221  , mLocalTree(mRhsTree->background())
222  , mOutputTree(&outputTree)
223  , mLocalLeafNodes()
224  , mOutputLeafNodes(&outputLeafNodes)
225  {
226  }
227 
228  ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
229  : mLhsNodes(other.mLhsNodes)
230  , mRhsTree(other.mRhsTree)
231  , mLocalTree(mRhsTree->background())
232  , mOutputTree(&mLocalTree)
233  , mLocalLeafNodes()
234  , mOutputLeafNodes(&mLocalLeafNodes)
235  {
236  }
237 
238  void join(ProcessInternalNodes& other)
239  {
240  mOutputTree->merge(*other.mOutputTree);
241  mOutputLeafNodes->insert(mOutputLeafNodes->end(),
242  other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
243  }
244 
245  void operator()(const tbb::blocked_range<size_t>& range)
246  {
247  tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
248  tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
249 
250  std::vector<const LeafNodeType*> tmpLeafNodes;
251 
252  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
253 
254  const InternalNodeType& lhsNode = *mLhsNodes[n];
255  const Coord& ijk = lhsNode.origin();
256  const InternalNodeType * rhsNode =
257  rhsAcc.template probeConstNode<InternalNodeType>(ijk);
258 
259  if (rhsNode) {
260  lhsNode.getNodes(*mOutputLeafNodes);
261  } else {
262  if (Operation == CSG_INTERSECTION) {
263  if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
264  tmpLeafNodes.clear();
265  lhsNode.getNodes(tmpLeafNodes);
266  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
267  outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
268  }
269  }
270  } else { // Union & Difference
271  if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
272  tmpLeafNodes.clear();
273  lhsNode.getNodes(tmpLeafNodes);
274  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
275  outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
276  }
277  }
278  }
279  }
280  } // end range loop
281  }
282 
283  InternalNodeType const * const * const mLhsNodes;
284  TreeType const * const mRhsTree;
285  TreeType mLocalTree;
286  TreeType * const mOutputTree;
287 
288  std::vector<const LeafNodeType*> mLocalLeafNodes;
289  std::vector<const LeafNodeType*> * const mOutputLeafNodes;
290  }; // struct ProcessInternalNodes
291 
292  struct ProcessLeafNodes {
293 
294  ProcessLeafNodes(std::vector<const LeafNodeType*>& lhsNodes,
295  const TreeType& rhsTree, TreeType& output)
296  : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front())
297  , mRhsTree(&rhsTree)
298  , mLocalTree(mRhsTree->background())
299  , mOutputTree(&output)
300  {
301  }
302 
303  ProcessLeafNodes(ProcessLeafNodes& other, tbb::split)
304  : mLhsNodes(other.mLhsNodes)
305  , mRhsTree(other.mRhsTree)
306  , mLocalTree(mRhsTree->background())
307  , mOutputTree(&mLocalTree)
308  {
309  }
310 
311  void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
312 
313  void operator()(const tbb::blocked_range<size_t>& range)
314  {
315  tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
316  tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
317 
318  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
319 
320  const LeafNodeType& lhsNode = *mLhsNodes[n];
321  const Coord& ijk = lhsNode.origin();
322 
323  const LeafNodeType* rhsNodePt = rhsAcc.probeConstLeaf(ijk);
324 
325  if (rhsNodePt) { // combine overlapping nodes
326 
327  LeafNodeType* outputNode = outputAcc.touchLeaf(ijk);
328  ValueType * outputData = outputNode->buffer().data();
329  NodeMaskType& outputMask = outputNode->getValueMask();
330 
331  const ValueType * lhsData = lhsNode.buffer().data();
332  const NodeMaskType& lhsMask = lhsNode.getValueMask();
333 
334  const ValueType * rhsData = rhsNodePt->buffer().data();
335  const NodeMaskType& rhsMask = rhsNodePt->getValueMask();
336 
337  if (Operation == CSG_INTERSECTION) {
338  for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
339  const bool fromRhs = lhsData[pos] < rhsData[pos];
340  outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
341  outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
342  }
343  } else if (Operation == CSG_DIFFERENCE){
344  for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
345  const ValueType rhsVal = math::negative(rhsData[pos]);
346  const bool fromRhs = lhsData[pos] < rhsVal;
347  outputData[pos] = fromRhs ? rhsVal : lhsData[pos];
348  outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
349  }
350  } else { // Union
351  for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
352  const bool fromRhs = lhsData[pos] > rhsData[pos];
353  outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
354  outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
355  }
356  }
357 
358  } else {
359  if (Operation == CSG_INTERSECTION) {
360  if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
361  outputAcc.addLeaf(new LeafNodeType(lhsNode));
362  }
363  } else { // Union & Difference
364  if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
365  outputAcc.addLeaf(new LeafNodeType(lhsNode));
366  }
367  }
368  }
369  } // end range loop
370  }
371 
372  LeafNodeType const * const * const mLhsNodes;
373  TreeType const * const mRhsTree;
374  TreeType mLocalTree;
375  TreeType * const mOutputTree;
376  }; // struct ProcessLeafNodes
377 
378  TreePtrType mSegment;
379  TreeType const * const mLhsTree;
380  TreeType const * const mRhsTree;
381 }; // struct BuildPrimarySegment
382 
383 
384 template<typename TreeType, CSGOperation Operation>
386 {
387  using ValueType = typename TreeType::ValueType;
388  using TreePtrType = typename TreeType::Ptr;
389  using LeafNodeType = typename TreeType::LeafNodeType;
390  using NodeMaskType = typename LeafNodeType::NodeMaskType;
391  using RootNodeType = typename TreeType::RootNodeType;
392  using NodeChainType = typename RootNodeType::NodeChainType;
393  using InternalNodeType = typename boost::mpl::at<NodeChainType, boost::mpl::int_<1> >::type;
394 
395  BuildSecondarySegment(const TreeType& lhs, const TreeType& rhs)
396  : mSegment(new TreeType(lhs.background()))
397  , mLhsTree(&lhs)
398  , mRhsTree(&rhs)
399  {
400  }
401 
402  void operator()() const
403  {
404  std::vector<const LeafNodeType*> leafNodes;
405 
406  {
407  std::vector<const InternalNodeType*> internalNodes;
408  mRhsTree->getNodes(internalNodes);
409 
410  ProcessInternalNodes op(internalNodes, *mLhsTree, *mSegment, leafNodes);
411  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
412  }
413 
414  ProcessLeafNodes op(leafNodes, *mLhsTree, *mSegment);
415  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
416  }
417 
418  TreePtrType& segment() { return mSegment; }
419 
420 private:
421 
422  struct ProcessInternalNodes {
423 
424  ProcessInternalNodes(std::vector<const InternalNodeType*>& rhsNodes,
425  const TreeType& lhsTree, TreeType& outputTree,
426  std::vector<const LeafNodeType*>& outputLeafNodes)
427  : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front())
428  , mLhsTree(&lhsTree)
429  , mLocalTree(mLhsTree->background())
430  , mOutputTree(&outputTree)
431  , mLocalLeafNodes()
432  , mOutputLeafNodes(&outputLeafNodes)
433  {
434  }
435 
436  ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
437  : mRhsNodes(other.mRhsNodes)
438  , mLhsTree(other.mLhsTree)
439  , mLocalTree(mLhsTree->background())
440  , mOutputTree(&mLocalTree)
441  , mLocalLeafNodes()
442  , mOutputLeafNodes(&mLocalLeafNodes)
443  {
444  }
445 
446  void join(ProcessInternalNodes& other)
447  {
448  mOutputTree->merge(*other.mOutputTree);
449  mOutputLeafNodes->insert(mOutputLeafNodes->end(),
450  other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
451  }
452 
453  void operator()(const tbb::blocked_range<size_t>& range)
454  {
455  tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
456  tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
457 
458  std::vector<const LeafNodeType*> tmpLeafNodes;
459 
460  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
461 
462  const InternalNodeType& rhsNode = *mRhsNodes[n];
463  const Coord& ijk = rhsNode.origin();
464  const InternalNodeType * lhsNode =
465  lhsAcc.template probeConstNode<InternalNodeType>(ijk);
466 
467  if (lhsNode) {
468  rhsNode.getNodes(*mOutputLeafNodes);
469  } else {
470  if (Operation == CSG_INTERSECTION) {
471  if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
472  tmpLeafNodes.clear();
473  rhsNode.getNodes(tmpLeafNodes);
474  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
475  outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
476  }
477  }
478  } else if (Operation == CSG_DIFFERENCE) {
479  if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
480  tmpLeafNodes.clear();
481  rhsNode.getNodes(tmpLeafNodes);
482  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
483  LeafNodeType* outputNode = new LeafNodeType(*tmpLeafNodes[i]);
484  outputNode->negate();
485  outputAcc.addLeaf(outputNode);
486  }
487  }
488  } else { // Union
489  if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
490  tmpLeafNodes.clear();
491  rhsNode.getNodes(tmpLeafNodes);
492  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
493  outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
494  }
495  }
496  }
497  }
498  } // end range loop
499  }
500 
501  InternalNodeType const * const * const mRhsNodes;
502  TreeType const * const mLhsTree;
503  TreeType mLocalTree;
504  TreeType * const mOutputTree;
505 
506  std::vector<const LeafNodeType*> mLocalLeafNodes;
507  std::vector<const LeafNodeType*> * const mOutputLeafNodes;
508  }; // struct ProcessInternalNodes
509 
510  struct ProcessLeafNodes {
511 
512  ProcessLeafNodes(std::vector<const LeafNodeType*>& rhsNodes,
513  const TreeType& lhsTree, TreeType& output)
514  : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front())
515  , mLhsTree(&lhsTree)
516  , mLocalTree(mLhsTree->background())
517  , mOutputTree(&output)
518  {
519  }
520 
521  ProcessLeafNodes(ProcessLeafNodes& rhs, tbb::split)
522  : mRhsNodes(rhs.mRhsNodes)
523  , mLhsTree(rhs.mLhsTree)
524  , mLocalTree(mLhsTree->background())
525  , mOutputTree(&mLocalTree)
526  {
527  }
528 
529  void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
530 
531  void operator()(const tbb::blocked_range<size_t>& range)
532  {
533  tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
534  tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
535 
536  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
537 
538  const LeafNodeType& rhsNode = *mRhsNodes[n];
539  const Coord& ijk = rhsNode.origin();
540 
541  const LeafNodeType* lhsNode = lhsAcc.probeConstLeaf(ijk);
542 
543  if (!lhsNode) {
544  if (Operation == CSG_INTERSECTION) {
545  if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
546  outputAcc.addLeaf(new LeafNodeType(rhsNode));
547  }
548  } else if (Operation == CSG_DIFFERENCE) {
549  if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
550  LeafNodeType* outputNode = new LeafNodeType(rhsNode);
551  outputNode->negate();
552  outputAcc.addLeaf(outputNode);
553  }
554  } else { // Union
555  if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
556  outputAcc.addLeaf(new LeafNodeType(rhsNode));
557  }
558  }
559  }
560  } // end range loop
561  }
562 
563  LeafNodeType const * const * const mRhsNodes;
564  TreeType const * const mLhsTree;
565  TreeType mLocalTree;
566  TreeType * const mOutputTree;
567  }; // struct ProcessLeafNodes
568 
569  TreePtrType mSegment;
570  TreeType const * const mLhsTree;
571  TreeType const * const mRhsTree;
572 }; // struct BuildSecondarySegment
573 
574 
575 template<CSGOperation Operation, typename TreeType>
576 inline typename TreeType::Ptr
577 doCSGCopy(const TreeType& lhs, const TreeType& rhs)
578 {
580  BuildSecondarySegment<TreeType, Operation> secondary(lhs, rhs);
581 
582  // Exploiting nested parallelism
583  tbb::task_group tasks;
584  tasks.run(primary);
585  tasks.run(secondary);
586  tasks.wait();
587 
588  primary.segment()->merge(*secondary.segment());
589 
590  // The leafnode (level = 0) sign is set in the segment construction.
591  tools::signedFloodFill(*primary.segment(), /*threaded=*/true, /*grainSize=*/1, /*minLevel=*/1);
592 
593  return primary.segment();
594 }
595 
596 
598 
599 
600 template<typename TreeType>
602 {
603  using TreeTypePtr = typename TreeType::Ptr;
604  static TreeTypePtr construct(const TreeType&, TreeTypePtr& tree) { return tree; }
605 };
606 
607 
608 template<typename TreeType>
609 struct GridOrTreeConstructor<Grid<TreeType> >
610 {
613  using TreeTypePtr = typename TreeType::Ptr;
614 
615  static GridTypePtr construct(const GridType& grid, TreeTypePtr& tree) {
616  GridTypePtr maskGrid(GridType::create(tree));
617  maskGrid->setTransform(grid.transform().copy());
618  maskGrid->insertMeta(grid);
619  return maskGrid;
620  }
621 };
622 
623 
625 
628 template <typename LeafT>
629 using LeafPairList = std::vector<std::pair<LeafT*, LeafT*>>;
631 
637 template <typename TreeT>
638 inline void transferLeafNodes(TreeT &srcTree, TreeT &dstTree,
639  LeafPairList<typename TreeT::LeafNodeType> &overlapping)
640 {
641  using LeafT = typename TreeT::LeafNodeType;
642  tree::ValueAccessor<TreeT> acc(dstTree);//destination
643  std::vector<LeafT*> srcLeafNodes;
644  srcLeafNodes.reserve(srcTree.leafCount());
645  srcTree.stealNodes(srcLeafNodes);
646  srcTree.clear();
647  for (LeafT *srcLeaf : srcLeafNodes) {
648  LeafT *dstLeaf = acc.probeLeaf(srcLeaf->origin());
649  if (dstLeaf) {
650  overlapping.emplace_back(dstLeaf, srcLeaf);//dst, src
651  } else {
652  acc.addLeaf(srcLeaf);
653  }
654  }
655 }
657 
660 template <typename TreeT, typename OpT>
661 inline
662 typename std::enable_if<
663  !std::is_same<typename TreeT::ValueType, bool>::value &&
664  !std::is_same<typename TreeT::BuildType, ValueMask>::value &&
665  std::is_same<typename TreeT::LeafNodeType::Buffer::ValueType,
666  typename TreeT::LeafNodeType::Buffer::StorageType>::value>::type
667 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
668 {
669  using LeafT = typename TreeT::LeafNodeType;
670  LeafPairList<LeafT> overlapping;//dst, src
671  transferLeafNodes(srcTree, dstTree, overlapping);
672 
673  using RangeT = tbb::blocked_range<size_t>;
674  tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](const RangeT& r) {
675  for (auto i = r.begin(); i != r.end(); ++i) {
676  LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
677  dstLeaf->getValueMask() |= srcLeaf->getValueMask();
678  auto *ptr = dstLeaf->buffer().data();
679  for (auto v = srcLeaf->cbeginValueOn(); v; ++v) op(ptr[v.pos()], *v);
680  delete srcLeaf;
681  }
682  });
683 }
685 
688 template <typename TreeT, typename OpT>
689 inline
690 typename std::enable_if<
691  std::is_same<typename TreeT::BuildType, ValueMask>::value &&
692  std::is_same<typename TreeT::ValueType, bool>::value>::type
693 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT)
694 {
695  using LeafT = typename TreeT::LeafNodeType;
696  LeafPairList<LeafT> overlapping;//dst, src
697  transferLeafNodes(srcTree, dstTree, overlapping);
698 
699  using RangeT = tbb::blocked_range<size_t>;
700  tbb::parallel_for(RangeT(0, overlapping.size()), [&overlapping](const RangeT& r) {
701  for (auto i = r.begin(); i != r.end(); ++i) {
702  overlapping[i].first->getValueMask() |= overlapping[i].second->getValueMask();
703  delete overlapping[i].second;
704  }
705  });
706 }
707 
710 template <typename TreeT, typename OpT>
711 inline
712 typename std::enable_if<
713  std::is_same<typename TreeT::ValueType, bool>::value &&
714  !std::is_same<typename TreeT::BuildType, ValueMask>::value>::type
715 doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
716 {
717  using LeafT = typename TreeT::LeafNodeType;
718  LeafPairList<LeafT> overlapping;//dst, src
719  transferLeafNodes(srcTree, dstTree, overlapping);
720 
721  using RangeT = tbb::blocked_range<size_t>;
722  using WordT = typename LeafT::Buffer::WordType;
723  tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](const RangeT& r) {
724  for (auto i = r.begin(); i != r.end(); ++i) {
725  LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
726  WordT *w1 = dstLeaf->buffer().data();
727  const WordT *w2 = srcLeaf->buffer().data();
728  const WordT *w3 = &(srcLeaf->getValueMask().template getWord<WordT>(0));
729  for (Index32 n = LeafT::Buffer::WORD_COUNT; n--; ++w1) {
730  WordT tmp = *w1, state = *w3++;
731  op (tmp, *w2++);
732  *w1 = (state & tmp) | (~state & *w1);//inactive values are unchanged
733  }
734  dstLeaf->getValueMask() |= srcLeaf->getValueMask();
735  delete srcLeaf;
736  }
737  });
738 }
740 
743 template <typename TreeT>
744 struct CopyOp
745 {
746  using ValueT = typename TreeT::ValueType;
747  CopyOp() = default;
748  void operator()(ValueT& dst, const ValueT& src) const { dst = src; }
749 };
751 
752 } // namespace composite
753 
754 
755 template<typename GridOrTreeT>
757 compMax(GridOrTreeT& aTree, GridOrTreeT& bTree)
758 {
759  using Adapter = TreeAdapter<GridOrTreeT>;
760  using TreeT = typename Adapter::TreeType;
761  using ValueT = typename TreeT::ValueType;
762  struct Local {
763  static inline void op(CombineArgs<ValueT>& args) {
764  args.setResult(composite::max(args.a(), args.b()));
765  }
766  };
767  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
768 }
769 
770 
771 template<typename GridOrTreeT>
773 compMin(GridOrTreeT& aTree, GridOrTreeT& bTree)
774 {
775  using Adapter = TreeAdapter<GridOrTreeT>;
776  using TreeT = typename Adapter::TreeType;
777  using ValueT = typename TreeT::ValueType;
778  struct Local {
779  static inline void op(CombineArgs<ValueT>& args) {
780  args.setResult(composite::min(args.a(), args.b()));
781  }
782  };
783  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
784 }
785 
786 
787 template<typename GridOrTreeT>
789 compSum(GridOrTreeT& aTree, GridOrTreeT& bTree)
790 {
791  using Adapter = TreeAdapter<GridOrTreeT>;
792  using TreeT = typename Adapter::TreeType;
793  struct Local {
794  static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
795  args.setResult(args.a() + args.b());
796  }
797  };
798  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
799 }
800 
801 
802 template<typename GridOrTreeT>
804 compMul(GridOrTreeT& aTree, GridOrTreeT& bTree)
805 {
806  using Adapter = TreeAdapter<GridOrTreeT>;
807  using TreeT = typename Adapter::TreeType;
808  struct Local {
809  static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
810  args.setResult(args.a() * args.b());
811  }
812  };
813  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
814 }
815 
816 
817 template<typename GridOrTreeT>
819 compDiv(GridOrTreeT& aTree, GridOrTreeT& bTree)
820 {
821  using Adapter = TreeAdapter<GridOrTreeT>;
822  using TreeT = typename Adapter::TreeType;
823  struct Local {
824  static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
825  args.setResult(composite::divide(args.a(), args.b()));
826  }
827  };
828  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
829 }
830 
831 
833 
834 
835 template<typename TreeT>
837 {
838  TreeT* const aTree;
839 
840  CompReplaceOp(TreeT& _aTree): aTree(&_aTree) {}
841 
843  void operator()(const typename TreeT::ValueOnCIter& iter) const
844  {
845  CoordBBox bbox;
846  iter.getBoundingBox(bbox);
847  aTree->fill(bbox, *iter);
848  }
849 
850  void operator()(const typename TreeT::LeafCIter& leafIter) const
851  {
852  tree::ValueAccessor<TreeT> acc(*aTree);
853  for (typename TreeT::LeafCIter::LeafNodeT::ValueOnCIter iter =
854  leafIter->cbeginValueOn(); iter; ++iter)
855  {
856  acc.setValue(iter.getCoord(), *iter);
857  }
858  }
859 };
860 
861 
862 template<typename GridOrTreeT>
864 compReplace(GridOrTreeT& aTree, const GridOrTreeT& bTree)
865 {
866  using Adapter = TreeAdapter<GridOrTreeT>;
867  using TreeT = typename Adapter::TreeType;
868  using ValueOnCIterT = typename TreeT::ValueOnCIter;
869 
870  // Copy active states (but not values) from B to A.
871  Adapter::tree(aTree).topologyUnion(Adapter::tree(bTree));
872 
873  CompReplaceOp<TreeT> op(Adapter::tree(aTree));
874 
875  // Copy all active tile values from B to A.
876  ValueOnCIterT iter = bTree.cbeginValueOn();
877  iter.setMaxDepth(iter.getLeafDepth() - 1); // don't descend into leaf nodes
878  foreach(iter, op, /*threaded=*/false);
879 
880  // Copy all active voxel values from B to A.
881  foreach(Adapter::tree(bTree).cbeginLeaf(), op);
882 }
883 
884 
886 
887 
890 template<typename TreeType>
892 {
893 public:
894  using TreeT = TreeType;
895  using ValueT = typename TreeT::ValueType;
896  using ChildIterT = typename TreeT::LeafNodeType::ChildAllIter;
897 
898  enum { STOP = 3 };
899 
900  CsgVisitorBase(const TreeT& aTree, const TreeT& bTree):
901  mAOutside(aTree.background()),
902  mAInside(math::negative(mAOutside)),
903  mBOutside(bTree.background()),
904  mBInside(math::negative(mBOutside))
905  {
906  const ValueT zero = zeroVal<ValueT>();
907  if (!(mAOutside > zero)) {
909  "expected grid A outside value > 0, got " << mAOutside);
910  }
911  if (!(mAInside < zero)) {
913  "expected grid A inside value < 0, got " << mAInside);
914  }
915  if (!(mBOutside > zero)) {
917  "expected grid B outside value > 0, got " << mBOutside);
918  }
919  if (!(mBInside < zero)) {
921  "expected grid B outside value < 0, got " << mBOutside);
922  }
923  }
924 
925 protected:
926  ValueT mAOutside, mAInside, mBOutside, mBInside;
927 };
928 
929 
931 
932 
933 template<typename TreeType>
934 struct CsgUnionVisitor: public CsgVisitorBase<TreeType>
935 {
936  using TreeT = TreeType;
937  using ValueT = typename TreeT::ValueType;
938  using ChildIterT = typename TreeT::LeafNodeType::ChildAllIter;
939 
941 
942  CsgUnionVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase<TreeT>(a, b) {}
943 
945  template<typename AIterT, typename BIterT>
946  inline int operator()(AIterT&, BIterT&) { return 0; }
947 
949  template<typename IterT>
950  inline int operator()(IterT& aIter, IterT& bIter)
951  {
952  ValueT aValue = zeroVal<ValueT>();
953  typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue);
954  if (!aChild && aValue < zeroVal<ValueT>()) {
955  // A is an inside tile. Leave it alone and stop traversing this branch.
956  return STOP;
957  }
958 
959  ValueT bValue = zeroVal<ValueT>();
960  typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue);
961  if (!bChild && bValue < zeroVal<ValueT>()) {
962  // B is an inside tile. Make A an inside tile and stop traversing this branch.
963  aIter.setValue(this->mAInside);
964  aIter.setValueOn(bIter.isValueOn());
965  delete aChild;
966  return STOP;
967  }
968 
969  if (!aChild && aValue > zeroVal<ValueT>()) {
970  // A is an outside tile. If B has a child, transfer it to A,
971  // otherwise leave A alone.
972  if (bChild) {
973  bIter.setValue(this->mBOutside);
974  bIter.setValueOff();
975  bChild->resetBackground(this->mBOutside, this->mAOutside);
976  aIter.setChild(bChild); // transfer child
977  delete aChild;
978  }
979  return STOP;
980  }
981 
982  // If A has a child and B is an outside tile, stop traversing this branch.
983  // Continue traversal only if A and B both have children.
984  return (aChild && bChild) ? 0 : STOP;
985  }
986 
988  inline int operator()(ChildIterT& aIter, ChildIterT& bIter)
989  {
990  ValueT aValue, bValue;
991  aIter.probeValue(aValue);
992  bIter.probeValue(bValue);
993  if (aValue > bValue) { // a = min(a, b)
994  aIter.setValue(bValue);
995  aIter.setValueOn(bIter.isValueOn());
996  }
997  return 0;
998  }
999 };
1000 
1001 
1002 
1004 
1005 
1006 template<typename TreeType>
1007 struct CsgIntersectVisitor: public CsgVisitorBase<TreeType>
1008 {
1009  using TreeT = TreeType;
1010  using ValueT = typename TreeT::ValueType;
1011  using ChildIterT = typename TreeT::LeafNodeType::ChildAllIter;
1012 
1014 
1015  CsgIntersectVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase<TreeT>(a, b) {}
1016 
1018  template<typename AIterT, typename BIterT>
1019  inline int operator()(AIterT&, BIterT&) { return 0; }
1020 
1022  template<typename IterT>
1023  inline int operator()(IterT& aIter, IterT& bIter)
1024  {
1025  ValueT aValue = zeroVal<ValueT>();
1026  typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue);
1027  if (!aChild && !(aValue < zeroVal<ValueT>())) {
1028  // A is an outside tile. Leave it alone and stop traversing this branch.
1029  return STOP;
1030  }
1031 
1032  ValueT bValue = zeroVal<ValueT>();
1033  typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue);
1034  if (!bChild && !(bValue < zeroVal<ValueT>())) {
1035  // B is an outside tile. Make A an outside tile and stop traversing this branch.
1036  aIter.setValue(this->mAOutside);
1037  aIter.setValueOn(bIter.isValueOn());
1038  delete aChild;
1039  return STOP;
1040  }
1041 
1042  if (!aChild && aValue < zeroVal<ValueT>()) {
1043  // A is an inside tile. If B has a child, transfer it to A,
1044  // otherwise leave A alone.
1045  if (bChild) {
1046  bIter.setValue(this->mBOutside);
1047  bIter.setValueOff();
1048  bChild->resetBackground(this->mBOutside, this->mAOutside);
1049  aIter.setChild(bChild); // transfer child
1050  delete aChild;
1051  }
1052  return STOP;
1053  }
1054 
1055  // If A has a child and B is an outside tile, stop traversing this branch.
1056  // Continue traversal only if A and B both have children.
1057  return (aChild && bChild) ? 0 : STOP;
1058  }
1059 
1061  inline int operator()(ChildIterT& aIter, ChildIterT& bIter)
1062  {
1063  ValueT aValue, bValue;
1064  aIter.probeValue(aValue);
1065  bIter.probeValue(bValue);
1066  if (aValue < bValue) { // a = max(a, b)
1067  aIter.setValue(bValue);
1068  aIter.setValueOn(bIter.isValueOn());
1069  }
1070  return 0;
1071  }
1072 };
1073 
1074 
1076 
1077 
1078 template<typename TreeType>
1079 struct CsgDiffVisitor: public CsgVisitorBase<TreeType>
1080 {
1081  using TreeT = TreeType;
1082  using ValueT = typename TreeT::ValueType;
1083  using ChildIterT = typename TreeT::LeafNodeType::ChildAllIter;
1084 
1086 
1087  CsgDiffVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase<TreeT>(a, b) {}
1088 
1090  template<typename AIterT, typename BIterT>
1091  inline int operator()(AIterT&, BIterT&) { return 0; }
1092 
1094  template<typename IterT>
1095  inline int operator()(IterT& aIter, IterT& bIter)
1096  {
1097  ValueT aValue = zeroVal<ValueT>();
1098  typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue);
1099  if (!aChild && !(aValue < zeroVal<ValueT>())) {
1100  // A is an outside tile. Leave it alone and stop traversing this branch.
1101  return STOP;
1102  }
1103 
1104  ValueT bValue = zeroVal<ValueT>();
1105  typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue);
1106  if (!bChild && bValue < zeroVal<ValueT>()) {
1107  // B is an inside tile. Make A an inside tile and stop traversing this branch.
1108  aIter.setValue(this->mAOutside);
1109  aIter.setValueOn(bIter.isValueOn());
1110  delete aChild;
1111  return STOP;
1112  }
1113 
1114  if (!aChild && aValue < zeroVal<ValueT>()) {
1115  // A is an inside tile. If B has a child, transfer it to A,
1116  // otherwise leave A alone.
1117  if (bChild) {
1118  bIter.setValue(this->mBOutside);
1119  bIter.setValueOff();
1120  bChild->resetBackground(this->mBOutside, this->mAOutside);
1121  aIter.setChild(bChild); // transfer child
1122  bChild->negate();
1123  delete aChild;
1124  }
1125  return STOP;
1126  }
1127 
1128  // If A has a child and B is an outside tile, stop traversing this branch.
1129  // Continue traversal only if A and B both have children.
1130  return (aChild && bChild) ? 0 : STOP;
1131  }
1132 
1134  inline int operator()(ChildIterT& aIter, ChildIterT& bIter)
1135  {
1136  ValueT aValue, bValue;
1137  aIter.probeValue(aValue);
1138  bIter.probeValue(bValue);
1139  bValue = math::negative(bValue);
1140  if (aValue < bValue) { // a = max(a, -b)
1141  aIter.setValue(bValue);
1142  aIter.setValueOn(bIter.isValueOn());
1143  }
1144  return 0;
1145  }
1146 };
1147 
1148 
1150 
1151 
1152 template<typename GridOrTreeT>
1154 csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune)
1155 {
1156  using Adapter = TreeAdapter<GridOrTreeT>;
1157  using TreeT = typename Adapter::TreeType;
1158  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
1159  CsgUnionVisitor<TreeT> visitor(aTree, bTree);
1160  aTree.visit2(bTree, visitor);
1161  if (prune) tools::pruneLevelSet(aTree);
1162 }
1163 
1164 template<typename GridOrTreeT>
1166 csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune)
1167 {
1168  using Adapter = TreeAdapter<GridOrTreeT>;
1169  using TreeT = typename Adapter::TreeType;
1170  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
1171  CsgIntersectVisitor<TreeT> visitor(aTree, bTree);
1172  aTree.visit2(bTree, visitor);
1173  if (prune) tools::pruneLevelSet(aTree);
1174 }
1175 
1176 template<typename GridOrTreeT>
1178 csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune)
1179 {
1180  using Adapter = TreeAdapter<GridOrTreeT>;
1181  using TreeT = typename Adapter::TreeType;
1182  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
1183  CsgDiffVisitor<TreeT> visitor(aTree, bTree);
1184  aTree.visit2(bTree, visitor);
1185  if (prune) tools::pruneLevelSet(aTree);
1186 }
1187 
1188 
1189 template<typename GridOrTreeT>
1190 OPENVDB_STATIC_SPECIALIZATION inline typename GridOrTreeT::Ptr
1191 csgUnionCopy(const GridOrTreeT& a, const GridOrTreeT& b)
1192 {
1193  using Adapter = TreeAdapter<GridOrTreeT>;
1194  using TreePtrT = typename Adapter::TreeType::Ptr;
1195 
1196  TreePtrT output = composite::doCSGCopy<composite::CSG_UNION>(
1197  Adapter::tree(a), Adapter::tree(b));
1198 
1200 }
1201 
1202 
1203 template<typename GridOrTreeT>
1204 OPENVDB_STATIC_SPECIALIZATION inline typename GridOrTreeT::Ptr
1205 csgIntersectionCopy(const GridOrTreeT& a, const GridOrTreeT& b)
1206 {
1207  using Adapter = TreeAdapter<GridOrTreeT>;
1208  using TreePtrT = typename Adapter::TreeType::Ptr;
1209 
1210  TreePtrT output = composite::doCSGCopy<composite::CSG_INTERSECTION>(
1211  Adapter::tree(a), Adapter::tree(b));
1212 
1214 }
1215 
1216 
1217 template<typename GridOrTreeT>
1218 OPENVDB_STATIC_SPECIALIZATION inline typename GridOrTreeT::Ptr
1219 csgDifferenceCopy(const GridOrTreeT& a, const GridOrTreeT& b)
1220 {
1221  using Adapter = TreeAdapter<GridOrTreeT>;
1222  using TreePtrT = typename Adapter::TreeType::Ptr;
1223 
1224  TreePtrT output = composite::doCSGCopy<composite::CSG_DIFFERENCE>(
1225  Adapter::tree(a), Adapter::tree(b));
1226 
1228 }
1229 
1231 
1253 template<typename TreeT, typename OpT = composite::CopyOp<TreeT> >
1254 inline void
1255 compActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op = composite::CopyOp<TreeT>())
1256 {
1257  composite::doCompActiveLeafVoxels<TreeT, OpT>(srcTree, dstTree, op);
1258 }
1259 
1260 
1261 } // namespace tools
1262 } // namespace OPENVDB_VERSION_NAME
1263 } // namespace openvdb
1264 
1265 #endif // OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
1266 
1267 // Copyright (c) DreamWorks Animation LLC
1268 // All rights reserved. This software is distributed under the
1269 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:108
BuildSecondarySegment(const TreeType &lhs, const TreeType &rhs)
Definition: Composite.h:395
Ptr copy() const
Definition: Transform.h:77
TreePtrType & segment()
Definition: Composite.h:418
typename boost::mpl::at< NodeChainType, boost::mpl::int_< 1 > >::type InternalNodeType
Definition: Composite.h:393
CSGOperation
Definition: Composite.h:174
ValueT mBOutside
Definition: Composite.h:926
static TreeTypePtr construct(const TreeType &, TreeTypePtr &tree)
Definition: Composite.h:604
int operator()(AIterT &, BIterT &)
Don&#39;t process nodes that are at different tree levels.
Definition: Composite.h:1091
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
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:819
typename TreeType::Ptr TreeTypePtr
Definition: Composite.h:613
typename TreeType::RootNodeType RootNodeType
Definition: Composite.h:183
int operator()(ChildIterT &aIter, ChildIterT &bIter)
Process leaf node values.
Definition: Composite.h:1061
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:367
const std::enable_if< VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:147
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
TreeT *const aTree
Definition: Composite.h:838
TreeType::Ptr doCSGCopy(const TreeType &lhs, const TreeType &rhs)
Definition: Composite.h:577
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:361
Definition: Composite.h:891
TreeType TreeT
Definition: Composite.h:894
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:386
typename boost::mpl::at< NodeChainType, boost::mpl::int_< 1 > >::type InternalNodeType
Definition: Composite.h:185
typename RootNodeType::NodeChainType NodeChainType
Definition: Composite.h:392
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:789
typename RootNodeType::NodeChainType NodeChainType
Definition: Composite.h:184
const BValueType & b() const
Get the B input value.
Definition: Types.h:659
Index32 Index
Definition: Types.h:61
void operator()(const typename TreeT::ValueOnCIter &iter) const
Definition: Composite.h:843
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:55
int operator()(IterT &aIter, IterT &bIter)
Process root and internal nodes.
Definition: Composite.h:1095
Defined various multi-threaded utility functions for trees.
typename TreeType::RootNodeType RootNodeType
Definition: Composite.h:391
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:1255
CombineArgs & setResult(const AValueType &val)
Set the output value.
Definition: Types.h:667
int operator()(AIterT &, BIterT &)
Don&#39;t process nodes that are at different tree levels.
Definition: Composite.h:946
int operator()(ChildIterT &aIter, ChildIterT &bIter)
Process leaf node values.
Definition: Composite.h:988
void operator()() const
Definition: Composite.h:402
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:128
int operator()(ChildIterT &aIter, ChildIterT &bIter)
Process leaf node values.
Definition: Composite.h:1134
Definition: Composite.h:836
typename TreeType::Ptr TreePtrType
Definition: Composite.h:388
math::Transform & transform()
Return a reference to this grid&#39;s transform, which might be shared with other grids.
Definition: Grid.h:429
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
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:416
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:417
CsgVisitorBase(const TreeT &aTree, const TreeT &bTree)
Definition: Composite.h:900
typename TreeT::ValueType ValueT
Definition: Composite.h:895
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:804
void compReplace(GridOrTreeT &a, const GridOrTreeT &b)
Copy the active voxels of B into A.
Definition: Composite.h:864
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:288
Definition: Exceptions.h:40
CsgUnionVisitor(const TreeT &a, const TreeT &b)
Definition: Composite.h:942
typename TreeT::LeafNodeType::ChildAllIter ChildIterT
Definition: Composite.h:896
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:1191
typename LeafNodeType::NodeMaskType NodeMaskType
Definition: Composite.h:390
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:1219
TreePtrType & segment()
Definition: Composite.h:210
BuildPrimarySegment(const TreeType &lhs, const TreeType &rhs)
Definition: Composite.h:187
typename Grid< TreeType >::Ptr GridTypePtr
Definition: Composite.h:612
SharedPtr< Grid > Ptr
Definition: Grid.h:596
CsgIntersectVisitor(const TreeT &a, const TreeT &b)
Definition: Composite.h:1015
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:1166
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:422
const std::enable_if< VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:139
int operator()(IterT &aIter, IterT &bIter)
Process root and internal nodes.
Definition: Composite.h:1023
typename TreeType::ValueType ValueType
Definition: Composite.h:179
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:617
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:1178
typename TreeType::ValueType ValueType
Definition: Composite.h:387
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:1154
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:757
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:773
int operator()(AIterT &, BIterT &)
Don&#39;t process nodes that are at different tree levels.
Definition: Composite.h:1019
typename TreeType::LeafNodeType LeafNodeType
Definition: Composite.h:181
const AValueType & a() const
Get the A input value.
Definition: Types.h:657
typename TreeType::Ptr TreePtrType
Definition: Composite.h:180
#define OPENVDB_STATIC_SPECIALIZATION
Macro for determining if there are sufficient C++0x/C++11 features.
Definition: Platform.h:111
void operator()(const typename TreeT::LeafCIter &leafIter) const
Definition: Composite.h:850
CompReplaceOp(TreeT &_aTree)
Definition: Composite.h:840
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:294
typename TreeType::Ptr TreeTypePtr
Definition: Composite.h:603
Definition: Exceptions.h:92
This adapter allows code that is templated on a Tree type to accept either a Tree type or a Grid type...
Definition: Grid.h:1076
bool divide(bool a, bool)
Definition: Composite.h:171
Definition: Composite.h:934
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:180
typename TreeType::LeafNodeType LeafNodeType
Definition: Composite.h:389
int operator()(IterT &aIter, IterT &bIter)
Process root and internal nodes.
Definition: Composite.h:950
typename LeafNodeType::NodeMaskType NodeMaskType
Definition: Composite.h:182
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:257
void clear() override
Remove all nodes from this cache, then reinsert the root node.
Definition: ValueAccessor.h:431
uint32_t Index32
Definition: Types.h:59
CsgDiffVisitor(const TreeT &a, const TreeT &b)
Definition: Composite.h:1087
Definition: Composite.h:1007
Definition: Composite.h:1079
static GridTypePtr construct(const GridType &grid, TreeTypePtr &tree)
Definition: Composite.h:615
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:1205
void operator()() const
Definition: Composite.h:194