HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Composite.h
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2012-2017 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 //
29 ///////////////////////////////////////////////////////////////////////////
30 //
31 /// @file Composite.h
32 ///
33 /// @brief Functions to efficiently perform various compositing operations on grids
34 ///
35 /// @authors Peter Cucka, Mihai Alden
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 #include <hboost/utility/enable_if.hpp>
49 
50 #include <tbb/blocked_range.h>
51 #include <tbb/parallel_for.h>
52 #include <tbb/parallel_reduce.h>
53 #include <tbb/task_group.h>
54 #include <tbb/task_scheduler_init.h>
55 
56 
57 namespace openvdb {
59 namespace OPENVDB_VERSION_NAME {
60 namespace tools {
61 
62 /// @brief Given two level set grids, replace the A grid with the union of A and B.
63 /// @throw ValueError if the background value of either grid is not greater than zero.
64 /// @note This operation always leaves the B grid empty.
65 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
66 inline void csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
67 /// @brief Given two level set grids, replace the A grid with the intersection of A and B.
68 /// @throw ValueError if the background value of either grid is not greater than zero.
69 /// @note This operation always leaves the B grid empty.
70 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
71 inline void csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
72 /// @brief Given two level set grids, replace the A grid with the difference A / B.
73 /// @throw ValueError if the background value of either grid is not greater than zero.
74 /// @note This operation always leaves the B grid empty.
75 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
76 inline void csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
77 
78 /// @brief Threaded CSG union operation that produces a new grid or tree from
79 /// immutable inputs.
80 /// @return The CSG union of the @a and @b level set inputs.
81 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
82 inline typename GridOrTreeT::Ptr csgUnionCopy(const GridOrTreeT& a, const GridOrTreeT& b);
83 /// @brief Threaded CSG intersection operation that produces a new grid or tree from
84 /// immutable inputs.
85 /// @return The CSG intersection of the @a and @b level set inputs.
86 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
87 inline typename GridOrTreeT::Ptr csgIntersectionCopy(const GridOrTreeT& a, const GridOrTreeT& b);
88 /// @brief Threaded CSG difference operation that produces a new grid or tree from
89 /// immutable inputs.
90 /// @return The CSG difference of the @a and @b level set inputs.
91 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
92 inline typename GridOrTreeT::Ptr csgDifferenceCopy(const GridOrTreeT& a, const GridOrTreeT& b);
93 
94 /// @brief Given grids A and B, compute max(a, b) per voxel (using sparse traversal).
95 /// Store the result in the A grid and leave the B grid empty.
96 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
97 inline void compMax(GridOrTreeT& a, GridOrTreeT& b);
98 /// @brief Given grids A and B, compute min(a, b) per voxel (using sparse traversal).
99 /// Store the result in the A grid and leave the B grid empty.
100 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
101 inline void compMin(GridOrTreeT& a, GridOrTreeT& b);
102 /// @brief Given grids A and B, compute a + b per voxel (using sparse traversal).
103 /// Store the result in the A grid and leave the B grid empty.
104 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
105 inline void compSum(GridOrTreeT& a, GridOrTreeT& b);
106 /// @brief Given grids A and B, compute a * b per voxel (using sparse traversal).
107 /// Store the result in the A grid and leave the B grid empty.
108 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
109 inline void compMul(GridOrTreeT& a, GridOrTreeT& b);
110 /// @brief Given grids A and B, compute a / b per voxel (using sparse traversal).
111 /// Store the result in the A grid and leave the B grid empty.
112 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
113 inline void compDiv(GridOrTreeT& a, GridOrTreeT& b);
114 
115 /// Copy the active voxels of B into A.
116 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
117 inline void compReplace(GridOrTreeT& a, const GridOrTreeT& b);
118 
119 
120 ////////////////////////////////////////
121 
122 
123 namespace composite {
124 
125 // composite::min() and composite::max() for non-vector types compare with operator<().
126 template<typename T> inline
127 const typename hboost::disable_if_c<VecTraits<T>::IsVec, T>::type& // = T if T is not a vector type
128 min(const T& a, const T& b) { return std::min(a, b); }
129 
130 template<typename T> inline
131 const typename hboost::disable_if_c<VecTraits<T>::IsVec, T>::type&
132 max(const T& a, const T& b) { return std::max(a, b); }
133 
134 
135 // composite::min() and composite::max() for OpenVDB vector types compare by magnitude.
136 template<typename T> inline
137 const typename hboost::enable_if_c<VecTraits<T>::IsVec, T>::type& // = T if T is a vector type
138 min(const T& a, const T& b)
139 {
140  const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
141  return (aMag < bMag ? a : (bMag < aMag ? b : std::min(a, b)));
142 }
143 
144 template<typename T> inline
145 const typename hboost::enable_if_c<VecTraits<T>::IsVec, T>::type&
146 max(const T& a, const T& b)
147 {
148  const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
149  return (aMag < bMag ? b : (bMag < aMag ? a : std::max(a, b)));
150 }
151 
152 
153 template<typename T> inline
154 typename hboost::disable_if<hboost::is_integral<T>, T>::type // = T if T is not an integer type
155 divide(const T& a, const T& b) { return a / b; }
156 
157 template<typename T> inline
158 typename hboost::enable_if<hboost::is_integral<T>, T>::type // = T if T is an integer type
159 divide(const T& a, const T& b)
160 {
161  const T zero(0);
162  if (b != zero) return a / b;
163  if (a == zero) return 0;
165 }
166 
167 // If b is true, return a / 1 = a.
168 // If b is false and a is true, return 1 / 0 = inf = MAX_BOOL = 1 = a.
169 // If b is false and a is false, return 0 / 0 = NaN = 0 = a.
170 inline bool divide(bool a, bool /*b*/) { return a; }
171 
172 
174 
175 template<typename TreeType, CSGOperation Operation>
177 {
178  typedef typename TreeType::ValueType ValueType;
179  typedef typename TreeType::Ptr TreePtrType;
180  typedef typename TreeType::LeafNodeType LeafNodeType;
181  typedef typename LeafNodeType::NodeMaskType NodeMaskType;
182  typedef typename TreeType::RootNodeType RootNodeType;
183  typedef typename RootNodeType::NodeChainType NodeChainType;
184  typedef typename hboost::mpl::at<NodeChainType, hboost::mpl::int_<1> >::type InternalNodeType;
185 
186  BuildPrimarySegment(const TreeType& lhs, const TreeType& rhs)
187  : mSegment(new TreeType(lhs.background()))
188  , mLhsTree(&lhs)
189  , mRhsTree(&rhs)
190  {
191  }
192 
193  void operator()() const
194  {
195  std::vector<const LeafNodeType*> leafNodes;
196 
197  {
198  std::vector<const InternalNodeType*> internalNodes;
199  mLhsTree->getNodes(internalNodes);
200 
201  ProcessInternalNodes op(internalNodes, *mRhsTree, *mSegment, leafNodes);
202  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
203  }
204 
205  ProcessLeafNodes op(leafNodes, *mRhsTree, *mSegment);
206  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
207  }
208 
209  TreePtrType& segment() { return mSegment; }
210 
211 private:
212 
213  struct ProcessInternalNodes {
214 
215  ProcessInternalNodes(std::vector<const InternalNodeType*>& lhsNodes, const TreeType& rhsTree,
216  TreeType& outputTree, std::vector<const LeafNodeType*>& outputLeafNodes)
217  : mLhsNodes(lhsNodes.empty() ? NULL : &lhsNodes.front())
218  , mRhsTree(&rhsTree)
219  , mLocalTree(mRhsTree->background())
220  , mOutputTree(&outputTree)
221  , mLocalLeafNodes()
222  , mOutputLeafNodes(&outputLeafNodes)
223  {
224  }
225 
226  ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
227  : mLhsNodes(other.mLhsNodes)
228  , mRhsTree(other.mRhsTree)
229  , mLocalTree(mRhsTree->background())
230  , mOutputTree(&mLocalTree)
231  , mLocalLeafNodes()
232  , mOutputLeafNodes(&mLocalLeafNodes)
233  {
234  }
235 
236  void join(ProcessInternalNodes& other)
237  {
238  mOutputTree->merge(*other.mOutputTree);
239  mOutputLeafNodes->insert(mOutputLeafNodes->end(),
240  other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
241  }
242 
243  void operator()(const tbb::blocked_range<size_t>& range)
244  {
245  tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
246  tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
247 
248  std::vector<const LeafNodeType*> tmpLeafNodes;
249 
250  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
251 
252  const InternalNodeType& lhsNode = *mLhsNodes[n];
253  const Coord& ijk = lhsNode.origin();
254  const InternalNodeType * rhsNode = rhsAcc.template probeConstNode<InternalNodeType>(ijk);
255 
256  if (rhsNode) {
257  lhsNode.getNodes(*mOutputLeafNodes);
258  } else {
259  if (Operation == CSG_INTERSECTION) {
260  if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
261  tmpLeafNodes.clear();
262  lhsNode.getNodes(tmpLeafNodes);
263  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
264  outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
265  }
266  }
267  } else { // Union & Difference
268  if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
269  tmpLeafNodes.clear();
270  lhsNode.getNodes(tmpLeafNodes);
271  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
272  outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
273  }
274  }
275  }
276  }
277  } // end range loop
278  }
279 
280  InternalNodeType const * const * const mLhsNodes;
281  TreeType const * const mRhsTree;
282  TreeType mLocalTree;
283  TreeType * const mOutputTree;
284 
285  std::vector<const LeafNodeType*> mLocalLeafNodes;
286  std::vector<const LeafNodeType*> * const mOutputLeafNodes;
287  }; // struct ProcessInternalNodes
288 
289  struct ProcessLeafNodes {
290 
291  ProcessLeafNodes(std::vector<const LeafNodeType*>& lhsNodes, const TreeType& rhsTree, TreeType& output)
292  : mLhsNodes(lhsNodes.empty() ? NULL : &lhsNodes.front())
293  , mRhsTree(&rhsTree)
294  , mLocalTree(mRhsTree->background())
295  , mOutputTree(&output)
296  {
297  }
298 
299  ProcessLeafNodes(ProcessLeafNodes& other, tbb::split)
300  : mLhsNodes(other.mLhsNodes)
301  , mRhsTree(other.mRhsTree)
302  , mLocalTree(mRhsTree->background())
303  , mOutputTree(&mLocalTree)
304  {
305  }
306 
307  void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
308 
309  void operator()(const tbb::blocked_range<size_t>& range)
310  {
311  tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
312  tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
313 
314  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
315 
316  const LeafNodeType& lhsNode = *mLhsNodes[n];
317  const Coord& ijk = lhsNode.origin();
318 
319  const LeafNodeType* rhsNodePt = rhsAcc.probeConstLeaf(ijk);
320 
321  if (rhsNodePt) { // combine overlapping nodes
322 
323  LeafNodeType* outputNode = outputAcc.touchLeaf(ijk);
324  ValueType * outputData = outputNode->buffer().data();
325  NodeMaskType& outputMask = outputNode->getValueMask();
326 
327  const ValueType * lhsData = lhsNode.buffer().data();
328  const NodeMaskType& lhsMask = lhsNode.getValueMask();
329 
330  const ValueType * rhsData = rhsNodePt->buffer().data();
331  const NodeMaskType& rhsMask = rhsNodePt->getValueMask();
332 
333  if (Operation == CSG_INTERSECTION) {
334  for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
335  const bool fromRhs = lhsData[pos] < rhsData[pos];
336  outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
337  outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
338  }
339  } else if (Operation == CSG_DIFFERENCE){
340  for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
341  const ValueType rhsVal = math::negative(rhsData[pos]);
342  const bool fromRhs = lhsData[pos] < rhsVal;
343  outputData[pos] = fromRhs ? rhsVal : lhsData[pos];
344  outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
345  }
346  } else { // Union
347  for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
348  const bool fromRhs = lhsData[pos] > rhsData[pos];
349  outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
350  outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
351  }
352  }
353 
354  } else {
355  if (Operation == CSG_INTERSECTION) {
356  if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
357  outputAcc.addLeaf(new LeafNodeType(lhsNode));
358  }
359  } else { // Union & Difference
360  if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
361  outputAcc.addLeaf(new LeafNodeType(lhsNode));
362  }
363  }
364  }
365  } // end range loop
366  }
367 
368  LeafNodeType const * const * const mLhsNodes;
369  TreeType const * const mRhsTree;
370  TreeType mLocalTree;
371  TreeType * const mOutputTree;
372  }; // struct ProcessLeafNodes
373 
374  TreePtrType mSegment;
375  TreeType const * const mLhsTree;
376  TreeType const * const mRhsTree;
377 }; // struct BuildPrimarySegment
378 
379 
380 template<typename TreeType, CSGOperation Operation>
382 {
383  typedef typename TreeType::ValueType ValueType;
384  typedef typename TreeType::Ptr TreePtrType;
385  typedef typename TreeType::LeafNodeType LeafNodeType;
386  typedef typename LeafNodeType::NodeMaskType NodeMaskType;
387  typedef typename TreeType::RootNodeType RootNodeType;
388  typedef typename RootNodeType::NodeChainType NodeChainType;
389  typedef typename hboost::mpl::at<NodeChainType, hboost::mpl::int_<1> >::type InternalNodeType;
390 
391  BuildSecondarySegment(const TreeType& lhs, const TreeType& rhs)
392  : mSegment(new TreeType(lhs.background()))
393  , mLhsTree(&lhs)
394  , mRhsTree(&rhs)
395  {
396  }
397 
398  void operator()() const
399  {
400  std::vector<const LeafNodeType*> leafNodes;
401 
402  {
403  std::vector<const InternalNodeType*> internalNodes;
404  mRhsTree->getNodes(internalNodes);
405 
406  ProcessInternalNodes op(internalNodes, *mLhsTree, *mSegment, leafNodes);
407  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
408  }
409 
410  ProcessLeafNodes op(leafNodes, *mLhsTree, *mSegment);
411  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
412  }
413 
414  TreePtrType& segment() { return mSegment; }
415 
416 private:
417 
418  struct ProcessInternalNodes {
419 
420  ProcessInternalNodes(std::vector<const InternalNodeType*>& rhsNodes, const TreeType& lhsTree,
421  TreeType& outputTree, std::vector<const LeafNodeType*>& outputLeafNodes)
422  : mRhsNodes(rhsNodes.empty() ? NULL : &rhsNodes.front())
423  , mLhsTree(&lhsTree)
424  , mLocalTree(mLhsTree->background())
425  , mOutputTree(&outputTree)
426  , mLocalLeafNodes()
427  , mOutputLeafNodes(&outputLeafNodes)
428  {
429  }
430 
431  ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
432  : mRhsNodes(other.mRhsNodes)
433  , mLhsTree(other.mLhsTree)
434  , mLocalTree(mLhsTree->background())
435  , mOutputTree(&mLocalTree)
436  , mLocalLeafNodes()
437  , mOutputLeafNodes(&mLocalLeafNodes)
438  {
439  }
440 
441  void join(ProcessInternalNodes& other)
442  {
443  mOutputTree->merge(*other.mOutputTree);
444  mOutputLeafNodes->insert(mOutputLeafNodes->end(),
445  other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
446  }
447 
448  void operator()(const tbb::blocked_range<size_t>& range)
449  {
450  tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
451  tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
452 
453  std::vector<const LeafNodeType*> tmpLeafNodes;
454 
455  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
456 
457  const InternalNodeType& rhsNode = *mRhsNodes[n];
458  const Coord& ijk = rhsNode.origin();
459  const InternalNodeType * lhsNode = lhsAcc.template probeConstNode<InternalNodeType>(ijk);
460 
461  if (lhsNode) {
462  rhsNode.getNodes(*mOutputLeafNodes);
463  } else {
464  if (Operation == CSG_INTERSECTION) {
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  } else if (Operation == CSG_DIFFERENCE) {
473  if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
474  tmpLeafNodes.clear();
475  rhsNode.getNodes(tmpLeafNodes);
476  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
477  LeafNodeType* outputNode = new LeafNodeType(*tmpLeafNodes[i]);
478  outputNode->negate();
479  outputAcc.addLeaf(outputNode);
480  }
481  }
482  } else { // Union
483  if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
484  tmpLeafNodes.clear();
485  rhsNode.getNodes(tmpLeafNodes);
486  for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
487  outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
488  }
489  }
490  }
491  }
492  } // end range loop
493  }
494 
495  InternalNodeType const * const * const mRhsNodes;
496  TreeType const * const mLhsTree;
497  TreeType mLocalTree;
498  TreeType * const mOutputTree;
499 
500  std::vector<const LeafNodeType*> mLocalLeafNodes;
501  std::vector<const LeafNodeType*> * const mOutputLeafNodes;
502  }; // struct ProcessInternalNodes
503 
504  struct ProcessLeafNodes {
505 
506  ProcessLeafNodes(std::vector<const LeafNodeType*>& rhsNodes, const TreeType& lhsTree, TreeType& output)
507  : mRhsNodes(rhsNodes.empty() ? NULL : &rhsNodes.front())
508  , mLhsTree(&lhsTree)
509  , mLocalTree(mLhsTree->background())
510  , mOutputTree(&output)
511  {
512  }
513 
514  ProcessLeafNodes(ProcessLeafNodes& rhs, tbb::split)
515  : mRhsNodes(rhs.mRhsNodes)
516  , mLhsTree(rhs.mLhsTree)
517  , mLocalTree(mLhsTree->background())
518  , mOutputTree(&mLocalTree)
519  {
520  }
521 
522  void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
523 
524  void operator()(const tbb::blocked_range<size_t>& range)
525  {
526  tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
527  tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
528 
529  for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
530 
531  const LeafNodeType& rhsNode = *mRhsNodes[n];
532  const Coord& ijk = rhsNode.origin();
533 
534  const LeafNodeType* lhsNode = lhsAcc.probeConstLeaf(ijk);
535 
536  if (!lhsNode) {
537  if (Operation == CSG_INTERSECTION) {
538  if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
539  outputAcc.addLeaf(new LeafNodeType(rhsNode));
540  }
541  } else if (Operation == CSG_DIFFERENCE) {
542  if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
543  LeafNodeType* outputNode = new LeafNodeType(rhsNode);
544  outputNode->negate();
545  outputAcc.addLeaf(outputNode);
546  }
547  } else { // Union
548  if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
549  outputAcc.addLeaf(new LeafNodeType(rhsNode));
550  }
551  }
552  }
553  } // end range loop
554  }
555 
556  LeafNodeType const * const * const mRhsNodes;
557  TreeType const * const mLhsTree;
558  TreeType mLocalTree;
559  TreeType * const mOutputTree;
560  }; // struct ProcessLeafNodes
561 
562  TreePtrType mSegment;
563  TreeType const * const mLhsTree;
564  TreeType const * const mRhsTree;
565 }; // struct BuildSecondarySegment
566 
567 
568 template<CSGOperation Operation, typename TreeType>
569 inline typename TreeType::Ptr
570 doCSGCopy(const TreeType& lhs, const TreeType& rhs)
571 {
573  BuildSecondarySegment<TreeType, Operation> secondary(lhs, rhs);
574 
575  // Exploiting nested parallelism
576  tbb::task_group tasks;
577  tasks.run(primary);
578  tasks.run(secondary);
579  tasks.wait();
580 
581  primary.segment()->merge(*secondary.segment());
582 
583  // The leafnode (level = 0) sign is set in the segment construction.
584  tools::signedFloodFill(*primary.segment(), /*threaded=*/true, /*grainSize=*/1, /*minLevel=*/1);
585 
586  return primary.segment();
587 }
588 
589 
590 ////////////////////////////////////////
591 
592 
593 template<typename TreeType>
595 {
596  typedef typename TreeType::Ptr TreeTypePtr;
597  static TreeTypePtr construct(const TreeType&, TreeTypePtr& tree) { return tree; }
598 };
599 
600 
601 template<typename TreeType>
602 struct GridOrTreeConstructor<Grid<TreeType> >
603 {
606  typedef typename TreeType::Ptr TreeTypePtr;
607 
608  static GridTypePtr construct(const GridType& grid, TreeTypePtr& tree) {
609  GridTypePtr maskGrid(GridType::create(tree));
610  maskGrid->setTransform(grid.transform().copy());
611  maskGrid->insertMeta(grid);
612  return maskGrid;
613  }
614 };
615 
616 
617 ////////////////////////////////////////
618 
619 
620 } // namespace composite
621 
622 
623 template<typename GridOrTreeT>
625 compMax(GridOrTreeT& aTree, GridOrTreeT& bTree)
626 {
627  typedef TreeAdapter<GridOrTreeT> Adapter;
628  typedef typename Adapter::TreeType TreeT;
629  typedef typename TreeT::ValueType ValueT;
630  struct Local {
631  static inline void op(CombineArgs<ValueT>& args) {
632  args.setResult(composite::max(args.a(), args.b()));
633  }
634  };
635  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
636 }
637 
638 
639 template<typename GridOrTreeT>
641 compMin(GridOrTreeT& aTree, GridOrTreeT& bTree)
642 {
643  typedef TreeAdapter<GridOrTreeT> Adapter;
644  typedef typename Adapter::TreeType TreeT;
645  typedef typename TreeT::ValueType ValueT;
646  struct Local {
647  static inline void op(CombineArgs<ValueT>& args) {
648  args.setResult(composite::min(args.a(), args.b()));
649  }
650  };
651  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
652 }
653 
654 
655 template<typename GridOrTreeT>
657 compSum(GridOrTreeT& aTree, GridOrTreeT& bTree)
658 {
659  typedef TreeAdapter<GridOrTreeT> Adapter;
660  typedef typename Adapter::TreeType TreeT;
661  struct Local {
662  static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
663  args.setResult(args.a() + args.b());
664  }
665  };
666  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
667 }
668 
669 
670 template<typename GridOrTreeT>
672 compMul(GridOrTreeT& aTree, GridOrTreeT& bTree)
673 {
674  typedef TreeAdapter<GridOrTreeT> Adapter;
675  typedef typename Adapter::TreeType TreeT;
676  struct Local {
677  static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
678  args.setResult(args.a() * args.b());
679  }
680  };
681  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
682 }
683 
684 
685 template<typename GridOrTreeT>
687 compDiv(GridOrTreeT& aTree, GridOrTreeT& bTree)
688 {
689  typedef TreeAdapter<GridOrTreeT> Adapter;
690  typedef typename Adapter::TreeType TreeT;
691  struct Local {
692  static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
693  args.setResult(composite::divide(args.a(), args.b()));
694  }
695  };
696  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
697 }
698 
699 
700 ////////////////////////////////////////
701 
702 
703 template<typename TreeT>
705 {
706  TreeT* const aTree;
707 
708  CompReplaceOp(TreeT& _aTree): aTree(&_aTree) {}
709 
710  /// @note fill operation is not thread safe
711  void operator()(const typename TreeT::ValueOnCIter& iter) const
712  {
713  CoordBBox bbox;
714  iter.getBoundingBox(bbox);
715  aTree->fill(bbox, *iter);
716  }
717 
718  void operator()(const typename TreeT::LeafCIter& leafIter) const
719  {
721  for (typename TreeT::LeafCIter::LeafNodeT::ValueOnCIter iter =
722  leafIter->cbeginValueOn(); iter; ++iter)
723  {
724  acc.setValue(iter.getCoord(), *iter);
725  }
726  }
727 };
728 
729 
730 template<typename GridOrTreeT>
732 compReplace(GridOrTreeT& aTree, const GridOrTreeT& bTree)
733 {
734  typedef TreeAdapter<GridOrTreeT> Adapter;
735  typedef typename Adapter::TreeType TreeT;
736  typedef typename TreeT::ValueOnCIter ValueOnCIterT;
737 
738  // Copy active states (but not values) from B to A.
739  Adapter::tree(aTree).topologyUnion(Adapter::tree(bTree));
740 
741  CompReplaceOp<TreeT> op(Adapter::tree(aTree));
742 
743  // Copy all active tile values from B to A.
744  ValueOnCIterT iter = bTree.cbeginValueOn();
745  iter.setMaxDepth(iter.getLeafDepth() - 1); // don't descend into leaf nodes
746  foreach(iter, op, /*threaded=*/false);
747 
748  // Copy all active voxel values from B to A.
749  foreach(Adapter::tree(bTree).cbeginLeaf(), op);
750 }
751 
752 
753 ////////////////////////////////////////
754 
755 
756 /// Base visitor class for CSG operations
757 /// (not intended to be used polymorphically, so no virtual functions)
758 template<typename TreeType>
760 {
761 public:
762  typedef TreeType TreeT;
763  typedef typename TreeT::ValueType ValueT;
764  typedef typename TreeT::LeafNodeType::ChildAllIter ChildIterT;
765 
766  enum { STOP = 3 };
767 
768  CsgVisitorBase(const TreeT& aTree, const TreeT& bTree):
769  mAOutside(aTree.background()),
770  mAInside(math::negative(mAOutside)),
771  mBOutside(bTree.background()),
772  mBInside(math::negative(mBOutside))
773  {
774  const ValueT zero = zeroVal<ValueT>();
775  if (!(mAOutside > zero)) {
776  OPENVDB_THROW(ValueError,
777  "expected grid A outside value > 0, got " << mAOutside);
778  }
779  if (!(mAInside < zero)) {
780  OPENVDB_THROW(ValueError,
781  "expected grid A inside value < 0, got " << mAInside);
782  }
783  if (!(mBOutside > zero)) {
784  OPENVDB_THROW(ValueError,
785  "expected grid B outside value > 0, got " << mBOutside);
786  }
787  if (!(mBInside < zero)) {
788  OPENVDB_THROW(ValueError,
789  "expected grid B outside value < 0, got " << mBOutside);
790  }
791  }
792 
793 protected:
795 };
796 
797 
798 ////////////////////////////////////////
799 
800 
801 template<typename TreeType>
802 struct CsgUnionVisitor: public CsgVisitorBase<TreeType>
803 {
804  typedef TreeType TreeT;
805  typedef typename TreeT::ValueType ValueT;
806  typedef typename TreeT::LeafNodeType::ChildAllIter ChildIterT;
807 
809 
810  CsgUnionVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase<TreeT>(a, b) {}
811 
812  /// Don't process nodes that are at different tree levels.
813  template<typename AIterT, typename BIterT>
814  inline int operator()(AIterT&, BIterT&) { return 0; }
815 
816  /// Process root and internal nodes.
817  template<typename IterT>
818  inline int operator()(IterT& aIter, IterT& bIter)
819  {
820  ValueT aValue = zeroVal<ValueT>();
821  typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue);
822  if (!aChild && aValue < zeroVal<ValueT>()) {
823  // A is an inside tile. Leave it alone and stop traversing this branch.
824  return STOP;
825  }
826 
827  ValueT bValue = zeroVal<ValueT>();
828  typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue);
829  if (!bChild && bValue < zeroVal<ValueT>()) {
830  // B is an inside tile. Make A an inside tile and stop traversing this branch.
831  aIter.setValue(this->mAInside);
832  aIter.setValueOn(bIter.isValueOn());
833  delete aChild;
834  return STOP;
835  }
836 
837  if (!aChild && aValue > zeroVal<ValueT>()) {
838  // A is an outside tile. If B has a child, transfer it to A,
839  // otherwise leave A alone.
840  if (bChild) {
841  bIter.setValue(this->mBOutside);
842  bIter.setValueOff();
843  bChild->resetBackground(this->mBOutside, this->mAOutside);
844  aIter.setChild(bChild); // transfer child
845  delete aChild;
846  }
847  return STOP;
848  }
849 
850  // If A has a child and B is an outside tile, stop traversing this branch.
851  // Continue traversal only if A and B both have children.
852  return (aChild && bChild) ? 0 : STOP;
853  }
854 
855  /// Process leaf node values.
856  inline int operator()(ChildIterT& aIter, ChildIterT& bIter)
857  {
858  ValueT aValue, bValue;
859  aIter.probeValue(aValue);
860  bIter.probeValue(bValue);
861  if (aValue > bValue) { // a = min(a, b)
862  aIter.setValue(bValue);
863  aIter.setValueOn(bIter.isValueOn());
864  }
865  return 0;
866  }
867 };
868 
869 
870 
871 ////////////////////////////////////////
872 
873 
874 template<typename TreeType>
875 struct CsgIntersectVisitor: public CsgVisitorBase<TreeType>
876 {
877  typedef TreeType TreeT;
878  typedef typename TreeT::ValueType ValueT;
879  typedef typename TreeT::LeafNodeType::ChildAllIter ChildIterT;
880 
882 
883  CsgIntersectVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase<TreeT>(a, b) {}
884 
885  /// Don't process nodes that are at different tree levels.
886  template<typename AIterT, typename BIterT>
887  inline int operator()(AIterT&, BIterT&) { return 0; }
888 
889  /// Process root and internal nodes.
890  template<typename IterT>
891  inline int operator()(IterT& aIter, IterT& bIter)
892  {
893  ValueT aValue = zeroVal<ValueT>();
894  typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue);
895  if (!aChild && !(aValue < zeroVal<ValueT>())) {
896  // A is an outside tile. Leave it alone and stop traversing this branch.
897  return STOP;
898  }
899 
900  ValueT bValue = zeroVal<ValueT>();
901  typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue);
902  if (!bChild && !(bValue < zeroVal<ValueT>())) {
903  // B is an outside tile. Make A an outside tile and stop traversing this branch.
904  aIter.setValue(this->mAOutside);
905  aIter.setValueOn(bIter.isValueOn());
906  delete aChild;
907  return STOP;
908  }
909 
910  if (!aChild && aValue < zeroVal<ValueT>()) {
911  // A is an inside tile. If B has a child, transfer it to A,
912  // otherwise leave A alone.
913  if (bChild) {
914  bIter.setValue(this->mBOutside);
915  bIter.setValueOff();
916  bChild->resetBackground(this->mBOutside, this->mAOutside);
917  aIter.setChild(bChild); // transfer child
918  delete aChild;
919  }
920  return STOP;
921  }
922 
923  // If A has a child and B is an outside tile, stop traversing this branch.
924  // Continue traversal only if A and B both have children.
925  return (aChild && bChild) ? 0 : STOP;
926  }
927 
928  /// Process leaf node values.
929  inline int operator()(ChildIterT& aIter, ChildIterT& bIter)
930  {
931  ValueT aValue, bValue;
932  aIter.probeValue(aValue);
933  bIter.probeValue(bValue);
934  if (aValue < bValue) { // a = max(a, b)
935  aIter.setValue(bValue);
936  aIter.setValueOn(bIter.isValueOn());
937  }
938  return 0;
939  }
940 };
941 
942 
943 ////////////////////////////////////////
944 
945 
946 template<typename TreeType>
947 struct CsgDiffVisitor: public CsgVisitorBase<TreeType>
948 {
949  typedef TreeType TreeT;
950  typedef typename TreeT::ValueType ValueT;
951  typedef typename TreeT::LeafNodeType::ChildAllIter ChildIterT;
952 
954 
955  CsgDiffVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase<TreeT>(a, b) {}
956 
957  /// Don't process nodes that are at different tree levels.
958  template<typename AIterT, typename BIterT>
959  inline int operator()(AIterT&, BIterT&) { return 0; }
960 
961  /// Process root and internal nodes.
962  template<typename IterT>
963  inline int operator()(IterT& aIter, IterT& bIter)
964  {
965  ValueT aValue = zeroVal<ValueT>();
966  typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue);
967  if (!aChild && !(aValue < zeroVal<ValueT>())) {
968  // A is an outside tile. Leave it alone and stop traversing this branch.
969  return STOP;
970  }
971 
972  ValueT bValue = zeroVal<ValueT>();
973  typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue);
974  if (!bChild && bValue < zeroVal<ValueT>()) {
975  // B is an inside tile. Make A an inside tile and stop traversing this branch.
976  aIter.setValue(this->mAOutside);
977  aIter.setValueOn(bIter.isValueOn());
978  delete aChild;
979  return STOP;
980  }
981 
982  if (!aChild && aValue < zeroVal<ValueT>()) {
983  // A is an inside tile. If B has a child, transfer it to A,
984  // otherwise leave A alone.
985  if (bChild) {
986  bIter.setValue(this->mBOutside);
987  bIter.setValueOff();
988  bChild->resetBackground(this->mBOutside, this->mAOutside);
989  aIter.setChild(bChild); // transfer child
990  bChild->negate();
991  delete aChild;
992  }
993  return STOP;
994  }
995 
996  // If A has a child and B is an outside tile, stop traversing this branch.
997  // Continue traversal only if A and B both have children.
998  return (aChild && bChild) ? 0 : STOP;
999  }
1000 
1001  /// Process leaf node values.
1002  inline int operator()(ChildIterT& aIter, ChildIterT& bIter)
1003  {
1004  ValueT aValue, bValue;
1005  aIter.probeValue(aValue);
1006  bIter.probeValue(bValue);
1007  bValue = math::negative(bValue);
1008  if (aValue < bValue) { // a = max(a, -b)
1009  aIter.setValue(bValue);
1010  aIter.setValueOn(bIter.isValueOn());
1011  }
1012  return 0;
1013  }
1014 };
1015 
1016 
1017 ////////////////////////////////////////
1018 
1019 
1020 template<typename GridOrTreeT>
1022 csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune)
1023 {
1024  typedef TreeAdapter<GridOrTreeT> Adapter;
1025  typedef typename Adapter::TreeType TreeT;
1026  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
1027  CsgUnionVisitor<TreeT> visitor(aTree, bTree);
1028  aTree.visit2(bTree, visitor);
1029  if (prune) tools::pruneLevelSet(aTree);
1030 }
1031 
1032 template<typename GridOrTreeT>
1034 csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune)
1035 {
1036  typedef TreeAdapter<GridOrTreeT> Adapter;
1037  typedef typename Adapter::TreeType TreeT;
1038  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
1039  CsgIntersectVisitor<TreeT> visitor(aTree, bTree);
1040  aTree.visit2(bTree, visitor);
1041  if (prune) tools::pruneLevelSet(aTree);
1042 }
1043 
1044 template<typename GridOrTreeT>
1046 csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune)
1047 {
1048  typedef TreeAdapter<GridOrTreeT> Adapter;
1049  typedef typename Adapter::TreeType TreeT;
1050  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
1051  CsgDiffVisitor<TreeT> visitor(aTree, bTree);
1052  aTree.visit2(bTree, visitor);
1053  if (prune) tools::pruneLevelSet(aTree);
1054 }
1055 
1056 
1057 template<typename GridOrTreeT>
1058 OPENVDB_STATIC_SPECIALIZATION inline typename GridOrTreeT::Ptr
1059 csgUnionCopy(const GridOrTreeT& a, const GridOrTreeT& b)
1060 {
1061  typedef TreeAdapter<GridOrTreeT> Adapter;
1062  typedef typename Adapter::TreeType::Ptr TreePtrT;
1063 
1064  TreePtrT output = composite::doCSGCopy<composite::CSG_UNION>(
1065  Adapter::tree(a), Adapter::tree(b));
1066 
1068 }
1069 
1070 
1071 template<typename GridOrTreeT>
1072 OPENVDB_STATIC_SPECIALIZATION inline typename GridOrTreeT::Ptr
1073 csgIntersectionCopy(const GridOrTreeT& a, const GridOrTreeT& b)
1074 {
1075  typedef TreeAdapter<GridOrTreeT> Adapter;
1076  typedef typename Adapter::TreeType::Ptr TreePtrT;
1077 
1078  TreePtrT output = composite::doCSGCopy<composite::CSG_INTERSECTION>(
1079  Adapter::tree(a), Adapter::tree(b));
1080 
1082 }
1083 
1084 
1085 template<typename GridOrTreeT>
1086 OPENVDB_STATIC_SPECIALIZATION inline typename GridOrTreeT::Ptr
1087 csgDifferenceCopy(const GridOrTreeT& a, const GridOrTreeT& b)
1088 {
1089  typedef TreeAdapter<GridOrTreeT> Adapter;
1090  typedef typename Adapter::TreeType::Ptr TreePtrT;
1091 
1092  TreePtrT output = composite::doCSGCopy<composite::CSG_DIFFERENCE>(
1093  Adapter::tree(a), Adapter::tree(b));
1094 
1096 }
1097 
1098 
1099 } // namespace tools
1100 } // namespace OPENVDB_VERSION_NAME
1101 } // namespace openvdb
1102 
1103 #endif // OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
1104 
1105 // Copyright (c) 2012-2017 DreamWorks Animation LLC
1106 // All rights reserved. This software is distributed under the
1107 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
OPENVDB_STATIC_SPECIALIZATION void compDiv(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute a / b per voxel (using sparse traversal). Store the result in the A grid...
Definition: Composite.h:687
OPENVDB_STATIC_SPECIALIZATION void compMin(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute min(a, b) per voxel (using sparse traversal). Store the result in the A ...
Definition: Composite.h:641
CsgIntersectVisitor(const TreeT &a, const TreeT &b)
Definition: Composite.h:883
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:371
GLenum GLint * range
Definition: glcorearb.h:1924
#define OPENVDB_STATIC_SPECIALIZATION
Macro for determining if there are sufficient C++0x/C++11 features.
Definition: Platform.h:91
BuildSecondarySegment(const TreeType &lhs, const TreeType &rhs)
Definition: Composite.h:391
const hboost::disable_if_c< VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:128
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:116
OPENVDB_STATIC_SPECIALIZATION GridOrTreeT::Ptr csgUnionCopy(const GridOrTreeT &a, const GridOrTreeT &b)
Threaded CSG union operation that produces a new grid or tree from immutable inputs.
Definition: Composite.h:1059
const hboost::enable_if_c< VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:146
png_infop png_color_16p * background
Definition: png.h:2326
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1221
int operator()(ChildIterT &aIter, ChildIterT &bIter)
Process leaf node values.
Definition: Composite.h:1002
void operator()(const typename TreeT::ValueOnCIter &iter) const
Definition: Composite.h:711
hboost::mpl::at< NodeChainType, hboost::mpl::int_< 1 > >::type InternalNodeType
Definition: Composite.h:389
int operator()(AIterT &, BIterT &)
Don't process nodes that are at different tree levels.
Definition: Composite.h:959
TreeT::LeafNodeType::ChildAllIter ChildIterT
Definition: Composite.h:764
png_uint_32 i
Definition: png.h:2877
OPENVDB_STATIC_SPECIALIZATION GridOrTreeT::Ptr csgDifferenceCopy(const GridOrTreeT &a, const GridOrTreeT &b)
Threaded CSG difference operation that produces a new grid or tree from immutable inputs...
Definition: Composite.h:1087
OPENVDB_STATIC_SPECIALIZATION void csgIntersection(GridOrTreeT &a, GridOrTreeT &b, bool prune=true)
Given two level set grids, replace the A grid with the intersection of A and B.
Definition: Composite.h:1034
This adapter allows code that is templated on a Tree type to accept either a Tree type or a Grid type...
Definition: Grid.h:937
const hboost::disable_if_c< VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:132
int operator()(IterT &aIter, IterT &bIter)
Process root and internal nodes.
Definition: Composite.h:891
SYS_FORCE_INLINE const_iterator end() const
const AValueType & a() const
Get the A input value.
Definition: Types.h:411
static GridTypePtr construct(const GridType &grid, TreeTypePtr &tree)
Definition: Composite.h:608
int operator()(AIterT &, BIterT &)
Don't process nodes that are at different tree levels.
Definition: Composite.h:814
OPENVDB_STATIC_SPECIALIZATION void compMul(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute a * b per voxel (using sparse traversal). Store the result in the A grid...
Definition: Composite.h:672
int operator()(IterT &aIter, IterT &bIter)
Process root and internal nodes.
Definition: Composite.h:963
GLdouble n
Definition: glcorearb.h:2007
TreeT::LeafNodeType::ChildAllIter ChildIterT
Definition: Composite.h:951
int operator()(ChildIterT &aIter, ChildIterT &bIter)
Process leaf node values.
Definition: Composite.h:856
#define OPENVDB_VERSION_NAME
Definition: version.h:43
const hboost::enable_if_c< VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:138
CsgDiffVisitor(const TreeT &a, const TreeT &b)
Definition: Composite.h:955
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
int operator()(AIterT &, BIterT &)
Don't process nodes that are at different tree levels.
Definition: Composite.h:887
Defined various multi-threaded utility functions for trees.
void operator()(const typename TreeT::LeafCIter &leafIter) const
Definition: Composite.h:718
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1221
hboost::mpl::at< NodeChainType, hboost::mpl::int_< 1 > >::type InternalNodeType
Definition: Composite.h:184
math::Transform & transform()
Return a reference to this grid's transform, which might be shared with other grids.
Definition: Grid.h:346
CsgVisitorBase(const TreeT &aTree, const TreeT &bTree)
Definition: Composite.h:768
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:54
int operator()(IterT &aIter, IterT &bIter)
Process root and internal nodes.
Definition: Composite.h:818
Propagates the sign of distance values from the active voxels in the narrow band to the inactive valu...
OPENVDB_STATIC_SPECIALIZATION void csgDifference(GridOrTreeT &a, GridOrTreeT &b, bool prune=true)
Given two level set grids, replace the A grid with the difference A / B.
Definition: Composite.h:1046
int operator()(ChildIterT &aIter, ChildIterT &bIter)
Process leaf node values.
Definition: Composite.h:929
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...
TreeT::LeafNodeType::ChildAllIter ChildIterT
Definition: Composite.h:806
CsgUnionVisitor(const TreeT &a, const TreeT &b)
Definition: Composite.h:810
OPENVDB_STATIC_SPECIALIZATION void compMax(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute max(a, b) per voxel (using sparse traversal). Store the result in the A ...
Definition: Composite.h:625
OPENVDB_STATIC_SPECIALIZATION void csgUnion(GridOrTreeT &a, GridOrTreeT &b, bool prune=true)
Given two level set grids, replace the A grid with the union of A and B.
Definition: Composite.h:1022
TreeT::LeafNodeType::ChildAllIter ChildIterT
Definition: Composite.h:879
OPENVDB_STATIC_SPECIALIZATION void compReplace(GridOrTreeT &a, const GridOrTreeT &b)
Copy the active voxels of B into A.
Definition: Composite.h:732
GA_API const UT_StringHolder N
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:107
static TreeTypePtr construct(const TreeType &, TreeTypePtr &tree)
Definition: Composite.h:597
#define SIZE
Definition: simple.C:40
OPENVDB_STATIC_SPECIALIZATION GridOrTreeT::Ptr csgIntersectionCopy(const GridOrTreeT &a, const GridOrTreeT &b)
Threaded CSG intersection operation that produces a new grid or tree from immutable inputs...
Definition: Composite.h:1073
TreeType::Ptr doCSGCopy(const TreeType &lhs, const TreeType &rhs)
Definition: Composite.h:570
hboost::disable_if< hboost::is_integral< T >, T >::type divide(const T &a, const T &b)
Definition: Composite.h:155
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
const BValueType & b() const
Get the B input value.
Definition: Types.h:413
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:374
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:429
CombineArgs & setResult(const AValueType &val)
Set the output value.
Definition: Types.h:421
OPENVDB_STATIC_SPECIALIZATION void compSum(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute a + b per voxel (using sparse traversal). Store the result in the A grid...
Definition: Composite.h:657
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:101
BuildPrimarySegment(const TreeType &lhs, const TreeType &rhs)
Definition: Composite.h:186