OpenVDB  0.104.0
Composite.h
Go to the documentation of this file.
1 
2 //
3 // Copyright (c) 2012 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 <boost/utility/enable_if.hpp>
47 
48 
49 namespace openvdb {
51 namespace OPENVDB_VERSION_NAME {
52 namespace tools {
53 
57 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
58 inline void csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
62 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
63 inline void csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
67 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
68 inline void csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
69 
72 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
73 inline void compMax(GridOrTreeT& a, GridOrTreeT& b);
76 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
77 inline void compMin(GridOrTreeT& a, GridOrTreeT& b);
80 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
81 inline void compSum(GridOrTreeT& a, GridOrTreeT& b);
84 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
85 inline void compMul(GridOrTreeT& a, GridOrTreeT& b);
86 
88 template<typename GridOrTreeT> OPENVDB_STATIC_SPECIALIZATION
89 inline void compReplace(GridOrTreeT& a, const GridOrTreeT& b);
90 
91 
93 
94 
95 namespace composite {
96 
97 // composite::min() and composite::max() for non-vector types compare with operator<().
98 template<typename T> inline
99 const typename boost::disable_if_c<VecTraits<T>::IsVec, T>::type& // = T if T is not a vector type
100 min(const T& a, const T& b) { return std::min(a, b); }
101 
102 template<typename T> inline
103 const typename boost::disable_if_c<VecTraits<T>::IsVec, T>::type&
104 max(const T& a, const T& b) { return std::max(a, b); }
105 
106 
107 // composite::min() and composite::max() for OpenVDB vector types compare by magnitude.
108 template<typename T> inline
109 const typename boost::enable_if_c<VecTraits<T>::IsVec, T>::type& // = T if T is a vector type
110 min(const T& a, const T& b)
111 {
112  const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
113  return (aMag < bMag ? a : (bMag < aMag ? b : std::min(a, b)));
114 }
115 
116 template<typename T> inline
117 const typename boost::enable_if_c<VecTraits<T>::IsVec, T>::type&
118 max(const T& a, const T& b)
119 {
120  const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
121  return (aMag < bMag ? b : (bMag < aMag ? a : std::max(a, b)));
122 }
123 
124 } // namespace composite
125 
126 
127 template<typename GridOrTreeT>
129 compMax(GridOrTreeT& aTree, GridOrTreeT& bTree)
130 {
131  typedef TreeAdapter<GridOrTreeT> Adapter;
132  typedef typename Adapter::TreeType TreeT;
133  typedef typename TreeT::ValueType ValueT;
134  struct Local {
135  static inline void op(CombineArgs<ValueT>& args) {
136  args.setResult(composite::max(args.a(), args.b()));
137  }
138  };
139  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
140 }
141 
142 
143 template<typename GridOrTreeT>
145 compMin(GridOrTreeT& aTree, GridOrTreeT& bTree)
146 {
147  typedef TreeAdapter<GridOrTreeT> Adapter;
148  typedef typename Adapter::TreeType TreeT;
149  typedef typename TreeT::ValueType ValueT;
150  struct Local {
151  static inline void op(CombineArgs<ValueT>& args) {
152  args.setResult(composite::min(args.a(), args.b()));
153  }
154  };
155  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
156 }
157 
158 
159 template<typename GridOrTreeT>
161 compSum(GridOrTreeT& aTree, GridOrTreeT& bTree)
162 {
163  typedef TreeAdapter<GridOrTreeT> Adapter;
164  typedef typename Adapter::TreeType TreeT;
165  struct Local {
166  static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
167  args.setResult(args.a() + args.b());
168  }
169  };
170  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
171 }
172 
173 
174 template<typename GridOrTreeT>
176 compMul(GridOrTreeT& aTree, GridOrTreeT& bTree)
177 {
178  typedef TreeAdapter<GridOrTreeT> Adapter;
179  typedef typename Adapter::TreeType TreeT;
180  struct Local {
181  static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
182  args.setResult(args.a() * args.b());
183  }
184  };
185  Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
186 }
187 
188 
190 
191 
192 template<typename TreeT>
194 {
195  TreeT* const aTree;
196 
197  CompReplaceOp(TreeT& _aTree): aTree(&_aTree) {}
198 
199  void operator()(const typename TreeT::ValueOnCIter& iter) const
200  {
201  CoordBBox bbox;
202  iter.getBoundingBox(bbox);
203  aTree->fill(bbox, *iter);
204  }
205 
206  void operator()(const typename TreeT::LeafCIter& leafIter) const
207  {
208  tree::ValueAccessor<TreeT> acc(*aTree);
209  for (typename TreeT::LeafCIter::LeafNodeT::ValueOnCIter iter =
210  leafIter->cbeginValueOn(); iter; ++iter)
211  {
212  acc.setValue(iter.getCoord(), *iter);
213  }
214  }
215 };
216 
217 
218 template<typename GridOrTreeT>
220 compReplace(GridOrTreeT& aTree, const GridOrTreeT& bTree)
221 {
222  typedef TreeAdapter<GridOrTreeT> Adapter;
223  typedef typename Adapter::TreeType TreeT;
224  typedef typename TreeT::ValueOnCIter ValueOnCIterT;
225 
226  // Copy active states (but not values) from B to A.
227  Adapter::tree(aTree).topologyUnion(Adapter::tree(bTree));
228 
229  CompReplaceOp<TreeT> op(Adapter::tree(aTree));
230 
231  // Copy all active tile values from B to A.
232  ValueOnCIterT iter = bTree.cbeginValueOn();
233  iter.setMaxDepth(iter.getLeafDepth() - 1); // don't descend into leaf nodes
234  foreach(iter, op);
235 
236  // Copy all active voxel values from B to A.
237  foreach(Adapter::tree(bTree).cbeginLeaf(), op);
238 }
239 
240 
242 
243 
246 template<typename TreeType>
248 {
249 public:
250  typedef TreeType TreeT;
251  typedef typename TreeT::ValueType ValueT;
252  typedef typename TreeT::LeafNodeType::ChildAllIter ChildIterT;
253 
254  enum { STOP = 3 };
255 
256  CsgVisitorBase(const TreeT& aTree, const TreeT& bTree):
257  mAOutside(aTree.getBackground()),
258  mAInside(negative(mAOutside)),
259  mBOutside(bTree.getBackground()),
260  mBInside(negative(mBOutside))
261  {
262  const ValueT zero = zeroVal<ValueT>();
263  if (!(mAOutside > zero)) {
265  "expected grid A outside value > 0, got " << mAOutside);
266  }
267  if (!(mAInside < zero)) {
269  "expected grid A inside value < 0, got " << mAInside);
270  }
271  if (!(mBOutside > zero)) {
273  "expected grid B outside value > 0, got " << mBOutside);
274  }
275  if (!(mBInside < zero)) {
277  "expected grid B outside value < 0, got " << mBOutside);
278  }
279  }
280 
281 protected:
282  ValueT mAOutside, mAInside, mBOutside, mBInside;
283 };
284 
285 
287 
288 
289 template<typename TreeType>
290 struct CsgUnionVisitor: public CsgVisitorBase<TreeType>
291 {
292  typedef TreeType TreeT;
293  typedef typename TreeT::ValueType ValueT;
294  typedef typename TreeT::LeafNodeType::ChildAllIter ChildIterT;
295 
297 
298  CsgUnionVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase<TreeT>(a, b) {}
299 
301  template<typename AIterT, typename BIterT>
302  inline int operator()(AIterT&, BIterT&) { return 0; }
303 
305  template<typename IterT>
306  inline int operator()(IterT& aIter, IterT& bIter)
307  {
308  ValueT aValue = zeroVal<ValueT>();
309  typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue);
310  if (!aChild && aValue < zeroVal<ValueT>()) {
311  // A is an inside tile. Leave it alone and stop traversing this branch.
312  return STOP;
313  }
314 
315  ValueT bValue = zeroVal<ValueT>();
316  typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue);
317  if (!bChild && bValue < zeroVal<ValueT>()) {
318  // B is an inside tile. Make A an inside tile and stop traversing this branch.
319  aIter.setValue(this->mAInside);
320  aIter.setValueOn(bIter.isValueOn());
321  delete aChild;
322  return STOP;
323  }
324 
325  if (!aChild && aValue > zeroVal<ValueT>()) {
326  // A is an outside tile. If B has a child, transfer it to A,
327  // otherwise leave A alone.
328  if (bChild) {
329  bIter.setValue(this->mBOutside);
330  bIter.setValueOff();
331  bChild->resetBackground(this->mBOutside, this->mAOutside);
332  aIter.setChild(bChild); // transfer child
333  delete aChild;
334  }
335  return STOP;
336  }
337 
338  // If A has a child and B is an outside tile, stop traversing this branch.
339  // Continue traversal only if A and B both have children.
340  return (aChild && bChild) ? 0 : STOP;
341  }
342 
344  inline int operator()(ChildIterT& aIter, ChildIterT& bIter)
345  {
346  ValueT aValue, bValue;
347  aIter.probeValue(aValue);
348  bIter.probeValue(bValue);
349  if (aValue > bValue) { // a = min(a, b)
350  aIter.setValue(bValue);
351  aIter.setValueOn(bIter.isValueOn());
352  }
353  return 0;
354  }
355 };
356 
357 
358 
360 
361 
362 template<typename TreeType>
363 struct CsgIntersectVisitor: public CsgVisitorBase<TreeType>
364 {
365  typedef TreeType TreeT;
366  typedef typename TreeT::ValueType ValueT;
367  typedef typename TreeT::LeafNodeType::ChildAllIter ChildIterT;
368 
370 
371  CsgIntersectVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase<TreeT>(a, b) {}
372 
374  template<typename AIterT, typename BIterT>
375  inline int operator()(AIterT&, BIterT&) { return 0; }
376 
378  template<typename IterT>
379  inline int operator()(IterT& aIter, IterT& bIter)
380  {
381  ValueT aValue = zeroVal<ValueT>();
382  typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue);
383  if (!aChild && !(aValue < zeroVal<ValueT>())) {
384  // A is an outside tile. Leave it alone and stop traversing this branch.
385  return STOP;
386  }
387 
388  ValueT bValue = zeroVal<ValueT>();
389  typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue);
390  if (!bChild && !(bValue < zeroVal<ValueT>())) {
391  // B is an outside tile. Make A an outside tile and stop traversing this branch.
392  aIter.setValue(this->mAOutside);
393  aIter.setValueOn(bIter.isValueOn());
394  delete aChild;
395  return STOP;
396  }
397 
398  if (!aChild && aValue < zeroVal<ValueT>()) {
399  // A is an inside tile. If B has a child, transfer it to A,
400  // otherwise leave A alone.
401  if (bChild) {
402  bIter.setValue(this->mBOutside);
403  bIter.setValueOff();
404  bChild->resetBackground(this->mBOutside, this->mAOutside);
405  aIter.setChild(bChild); // transfer child
406  delete aChild;
407  }
408  return STOP;
409  }
410 
411  // If A has a child and B is an outside tile, stop traversing this branch.
412  // Continue traversal only if A and B both have children.
413  return (aChild && bChild) ? 0 : STOP;
414  }
415 
417  inline int operator()(ChildIterT& aIter, ChildIterT& bIter)
418  {
419  ValueT aValue, bValue;
420  aIter.probeValue(aValue);
421  bIter.probeValue(bValue);
422  if (aValue < bValue) { // a = max(a, b)
423  aIter.setValue(bValue);
424  aIter.setValueOn(bIter.isValueOn());
425  }
426  return 0;
427  }
428 };
429 
430 
432 
433 
434 template<typename TreeType>
435 struct CsgDiffVisitor: public CsgVisitorBase<TreeType>
436 {
437  typedef TreeType TreeT;
438  typedef typename TreeT::ValueType ValueT;
439  typedef typename TreeT::LeafNodeType::ChildAllIter ChildIterT;
440 
442 
443  CsgDiffVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase<TreeT>(a, b) {}
444 
446  template<typename AIterT, typename BIterT>
447  inline int operator()(AIterT&, BIterT&) { return 0; }
448 
450  template<typename IterT>
451  inline int operator()(IterT& aIter, IterT& bIter)
452  {
453  ValueT aValue = zeroVal<ValueT>();
454  typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue);
455  if (!aChild && !(aValue < zeroVal<ValueT>())) {
456  // A is an outside tile. Leave it alone and stop traversing this branch.
457  return STOP;
458  }
459 
460  ValueT bValue = zeroVal<ValueT>();
461  typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue);
462  if (!bChild && bValue < zeroVal<ValueT>()) {
463  // B is an inside tile. Make A an inside tile and stop traversing this branch.
464  aIter.setValue(this->mAOutside);
465  aIter.setValueOn(bIter.isValueOn());
466  delete aChild;
467  return STOP;
468  }
469 
470  if (!aChild && aValue < zeroVal<ValueT>()) {
471  // A is an inside tile. If B has a child, transfer it to A,
472  // otherwise leave A alone.
473  if (bChild) {
474  bIter.setValue(this->mBOutside);
475  bIter.setValueOff();
476  bChild->resetBackground(this->mBOutside, this->mAOutside);
477  aIter.setChild(bChild); // transfer child
478  bChild->negate();
479  delete aChild;
480  }
481  return STOP;
482  }
483 
484  // If A has a child and B is an outside tile, stop traversing this branch.
485  // Continue traversal only if A and B both have children.
486  return (aChild && bChild) ? 0 : STOP;
487  }
488 
490  inline int operator()(ChildIterT& aIter, ChildIterT& bIter)
491  {
492  ValueT aValue, bValue;
493  aIter.probeValue(aValue);
494  bIter.probeValue(bValue);
495  bValue = negative(bValue);
496  if (aValue < bValue) { // a = max(a, -b)
497  aIter.setValue(bValue);
498  aIter.setValueOn(bIter.isValueOn());
499  }
500  return 0;
501  }
502 };
503 
504 
506 
507 
508 template<typename GridOrTreeT>
510 csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune)
511 {
512  typedef TreeAdapter<GridOrTreeT> Adapter;
513  typedef typename Adapter::TreeType TreeT;
514  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
515  CsgUnionVisitor<TreeT> visitor(aTree, bTree);
516  aTree.visit2(bTree, visitor);
517  if (prune) aTree.pruneLevelSet();
518  //if (prune) aTree.prune();
519 }
520 
521 template<typename GridOrTreeT>
523 csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune)
524 {
525  typedef TreeAdapter<GridOrTreeT> Adapter;
526  typedef typename Adapter::TreeType TreeT;
527  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
528  CsgIntersectVisitor<TreeT> visitor(aTree, bTree);
529  aTree.visit2(bTree, visitor);
530  if (prune) aTree.pruneLevelSet();
531  //if (prune) aTree.prune();
532 }
533 
534 template<typename GridOrTreeT>
536 csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune)
537 {
538  typedef TreeAdapter<GridOrTreeT> Adapter;
539  typedef typename Adapter::TreeType TreeT;
540  TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
541  CsgDiffVisitor<TreeT> visitor(aTree, bTree);
542  aTree.visit2(bTree, visitor);
543  if (prune) aTree.pruneLevelSet();
544  //if (prune) aTree.prune();
545 }
546 
547 } // namespace tools
548 } // namespace OPENVDB_VERSION_NAME
549 } // namespace openvdb
550 
551 #endif // OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
552 
553 // Copyright (c) 2012 DreamWorks Animation LLC
554 // All rights reserved. This software is distributed under the
555 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )