OpenVDB  3.1.0
GridTransformer.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2015 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 //
33 
34 #ifndef OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
35 #define OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
36 
37 #include <cmath>
38 #include <boost/bind.hpp>
39 #include <boost/function.hpp>
40 #include <boost/shared_ptr.hpp>
41 #include <tbb/blocked_range.h>
42 #include <tbb/parallel_reduce.h>
43 #include <openvdb/Grid.h>
44 #include <openvdb/Types.h>
45 #include <openvdb/math/Math.h> // for isApproxEqual()
47 #include "ChangeBackground.h"
48 #include "Interpolation.h"
49 #include "LevelSetRebuild.h" // for doLevelSetRebuild()
50 #include "SignedFloodFill.h" // for signedFloodFill
51 #include "Prune.h" // for pruneLevelSet
52 
53 namespace openvdb {
55 namespace OPENVDB_VERSION_NAME {
56 namespace tools {
57 
81 template<typename Sampler, typename Interrupter, typename GridType>
82 inline void
83 resampleToMatch(const GridType& inGrid, GridType& outGrid, Interrupter& interrupter);
84 
106 template<typename Sampler, typename GridType>
107 inline void
108 resampleToMatch(const GridType& inGrid, GridType& outGrid);
109 
110 
112 
113 
114 namespace internal {
115 
119 template<typename Sampler, typename TreeT>
120 class TileSampler: public Sampler
121 {
122 public:
123  typedef typename TreeT::ValueType ValueT;
124 
128  TileSampler(const CoordBBox& b, const ValueT& tileVal, bool on):
129  mBBox(b.min().asVec3d(), b.max().asVec3d()), mVal(tileVal), mActive(on), mEmpty(false)
130  {
131  mBBox.expand(-this->radius()); // shrink the bounding box by the sample radius
132  mEmpty = mBBox.empty();
133  }
134 
135  bool sample(const TreeT& inTree, const Vec3R& inCoord, ValueT& result) const
136  {
137  if (!mEmpty && mBBox.isInside(inCoord)) { result = mVal; return mActive; }
138  return Sampler::sample(inTree, inCoord, result);
139  }
140 
141 protected:
143  ValueT mVal;
144  bool mActive, mEmpty;
145 };
146 
147 
150 template<typename TreeT>
151 class TileSampler<PointSampler, TreeT>: public PointSampler {
152 public:
153  TileSampler(const CoordBBox&, const typename TreeT::ValueType&, bool) {}
154 };
155 
158 template<typename TreeT>
160 public:
161  TileSampler(const CoordBBox&, const typename TreeT::ValueType&, bool) {}
162 };
163 
164 } // namespace internal
165 
166 
168 
169 
188 {
189 public:
190  typedef boost::shared_ptr<GridResampler> Ptr;
191  typedef boost::function<bool (void)> InterruptFunc;
192 
193  GridResampler(): mThreaded(true), mTransformTiles(true) {}
194  virtual ~GridResampler() {}
195 
197  void setThreaded(bool b) { mThreaded = b; }
199  bool threaded() const { return mThreaded; }
201  void setTransformTiles(bool b) { mTransformTiles = b; }
203  bool transformTiles() const { return mTransformTiles; }
204 
208  template<typename InterrupterType> void setInterrupter(InterrupterType&);
209 
210  template<typename Sampler, typename GridT, typename Transformer>
211  void transformGrid(const Transformer&,
212  const GridT& inGrid, GridT& outGrid) const;
213 
214 protected:
215  template<typename Sampler, typename GridT, typename Transformer>
216  void applyTransform(const Transformer&, const GridT& inGrid, GridT& outGrid) const;
217 
218  bool interrupt() const { return mInterrupt && mInterrupt(); }
219 
220 private:
221  template<typename Sampler, typename InTreeT, typename OutTreeT, typename Transformer>
222  static void transformBBox(const Transformer&, const CoordBBox& inBBox,
223  const InTreeT& inTree, OutTreeT& outTree, const InterruptFunc&,
224  const Sampler& = Sampler());
225 
226  template<typename Sampler, typename TreeT, typename Transformer>
227  class RangeProcessor;
228 
229  bool mThreaded, mTransformTiles;
230  InterruptFunc mInterrupt;
231 };
232 
233 
235 
236 
256 {
257 public:
258  typedef boost::shared_ptr<GridTransformer> Ptr;
259 
260  GridTransformer(const Mat4R& xform);
262  const Vec3R& pivot,
263  const Vec3R& scale,
264  const Vec3R& rotate,
265  const Vec3R& translate,
266  const std::string& xformOrder = "tsr",
267  const std::string& rotationOrder = "zyx");
268  virtual ~GridTransformer() {}
269 
270  const Mat4R& getTransform() const { return mTransform; }
271 
272  template<class Sampler, class GridT>
273  void transformGrid(const GridT& inGrid, GridT& outGrid) const;
274 
275 private:
276  struct MatrixTransform;
277 
278  inline void init(const Vec3R& pivot, const Vec3R& scale,
279  const Vec3R& rotate, const Vec3R& translate,
280  const std::string& xformOrder, const std::string& rotOrder);
281 
282  Vec3R mPivot;
283  Vec3i mMipLevels;
284  Mat4R mTransform, mPreScaleTransform, mPostScaleTransform;
285 };
286 
287 
289 
290 
291 namespace local_util {
292 
296 template<typename T>
297 inline bool
299  math::Vec3<T>& rotate, math::Vec3<T>& translate)
300 {
301  if (!math::isAffine(m)) return false;
302 
303  // this is the translation in world space
304  translate = m.getTranslation();
305  // Extract translation.
306  math::Mat3<T> temp = m.getMat3();
307 
308  scale.init(
309  (math::Vec3<T>(1, 0, 0) * temp).length(),
310  (math::Vec3<T>(0, 1, 0) * temp).length(),
311  (math::Vec3<T>(0, 0, 1) * temp).length());
312  // Extract scale.
313  temp *= math::scale<math::Mat3<T> >(scale).inverse();
314 
315  rotate = math::eulerAngles(temp, math::XYZ_ROTATION);
316 
317  if (!rotate.eq(math::Vec3<T>::zero()) && !scale.eq(math::Vec3<T>(scale[0]))) {
318  // No unique decomposition if scale is nonuniform and rotation is nonzero.
319  return false;
320  }
321  return true;
322 }
323 
324 } // namespace local_util
325 
326 
328 
329 
334 {
335  MatrixTransform(): mat(Mat4R::identity()), invMat(Mat4R::identity()) {}
336  MatrixTransform(const Mat4R& xform): mat(xform), invMat(xform.inverse()) {}
337 
338  bool isAffine() const { return math::isAffine(mat); }
339 
340  Vec3R transform(const Vec3R& pos) const { return mat.transformH(pos); }
341 
342  Vec3R invTransform(const Vec3R& pos) const { return invMat.transformH(pos); }
343 
344  Mat4R mat, invMat;
345 };
346 
347 
349 
350 
356 {
357 public:
360  ABTransform(const math::Transform& aXform, const math::Transform& bXform):
361  mAXform(aXform),
362  mBXform(bXform),
363  mIsAffine(mAXform.isLinear() && mBXform.isLinear()),
364  mIsIdentity(mIsAffine && mAXform == mBXform)
365  {}
366 
367  bool isAffine() const { return mIsAffine; }
368 
369  bool isIdentity() const { return mIsIdentity; }
370 
372  {
373  return mBXform.worldToIndex(mAXform.indexToWorld(pos));
374  }
375 
377  {
378  return mAXform.worldToIndex(mBXform.indexToWorld(pos));
379  }
380 
381  const math::Transform& getA() const { return mAXform; }
382  const math::Transform& getB() const { return mBXform; }
383 
384 private:
385  const math::Transform &mAXform, &mBXform;
386  const bool mIsAffine;
387  const bool mIsIdentity;
388 };
389 
390 
397 template<typename Sampler, typename Interrupter, typename GridType>
398 inline void
399 doResampleToMatch(const GridType& inGrid, GridType& outGrid, Interrupter& interrupter)
400 {
401  ABTransform xform(inGrid.transform(), outGrid.transform());
402 
403  if (Sampler::consistent() && xform.isIdentity()) {
404  // If the transforms of the input and output are identical, the
405  // output tree is simply a deep copy of the input tree.
406  outGrid.setTree(inGrid.tree().copy());
407  } else if (xform.isAffine()) {
408  // If the input and output transforms are both affine, create an
409  // input to output transform (in:index-to-world * out:world-to-index)
410  // and use the fast GridTransformer API.
411  Mat4R mat = xform.getA().baseMap()->getAffineMap()->getMat4() *
412  ( xform.getB().baseMap()->getAffineMap()->getMat4().inverse() );
413 
414  GridTransformer transformer(mat);
415  transformer.setInterrupter(interrupter);
416 
417  // Transform the input grid and store the result in the output grid.
418  transformer.transformGrid<Sampler>(inGrid, outGrid);
419  } else {
420  // If either the input or the output transform is non-affine,
421  // use the slower GridResampler API.
422  GridResampler resampler;
423  resampler.setInterrupter(interrupter);
424 
425  resampler.transformGrid<Sampler>(xform, inGrid, outGrid);
426  }
427 }
428 
429 
430 template<typename Sampler, typename Interrupter, typename GridType>
431 inline void
432 resampleToMatch(const GridType& inGrid, GridType& outGrid, Interrupter& interrupter)
433 {
434  if (inGrid.getGridClass() == GRID_LEVEL_SET) {
435  // If the input grid is a level set, resample it using the level set rebuild tool.
436 
437  if (inGrid.constTransform() == outGrid.constTransform()) {
438  // If the transforms of the input and output grids are identical,
439  // the output tree is simply a deep copy of the input tree.
440  outGrid.setTree(inGrid.tree().copy());
441  return;
442  }
443 
444  // If the output grid is a level set, resample the input grid to have the output grid's
445  // background value. Otherwise, preserve the input grid's background value.
446  typedef typename GridType::ValueType ValueT;
447  const ValueT halfWidth = ((outGrid.getGridClass() == openvdb::GRID_LEVEL_SET)
448  ? ValueT(outGrid.background() * (1.0 / outGrid.voxelSize()[0]))
449  : ValueT(inGrid.background() * (1.0 / inGrid.voxelSize()[0])));
450 
451  typename GridType::Ptr tempGrid;
452  try {
453  tempGrid = doLevelSetRebuild(inGrid, /*iso=*/zeroVal<ValueT>(),
454  /*exWidth=*/halfWidth, /*inWidth=*/halfWidth,
455  &outGrid.constTransform(), &interrupter);
456  } catch (TypeError&) {
457  // The input grid is classified as a level set, but it has a value type
458  // that is not supported by the level set rebuild tool. Fall back to
459  // using the generic resampler.
460  tempGrid.reset();
461  }
462  if (tempGrid) {
463  outGrid.setTree(tempGrid->treePtr());
464  return;
465  }
466  }
467 
468  // If the input grid is not a level set, use the generic resampler.
469  doResampleToMatch<Sampler>(inGrid, outGrid, interrupter);
470 }
471 
472 
473 template<typename Sampler, typename GridType>
474 inline void
475 resampleToMatch(const GridType& inGrid, GridType& outGrid)
476 {
477  util::NullInterrupter interrupter;
478  resampleToMatch<Sampler>(inGrid, outGrid, interrupter);
479 }
480 
481 
483 
484 
485 inline
486 GridTransformer::GridTransformer(const Mat4R& xform):
487  mPivot(0, 0, 0),
488  mMipLevels(0, 0, 0),
489  mTransform(xform),
490  mPreScaleTransform(Mat4R::identity()),
491  mPostScaleTransform(Mat4R::identity())
492 {
493  Vec3R scale, rotate, translate;
494  if (local_util::decompose(mTransform, scale, rotate, translate)) {
495  // If the transform can be decomposed into affine components,
496  // use them to set up a mipmapping-like scheme for downsampling.
497  init(mPivot, scale, rotate, translate, "srt", "zyx");
498  }
499 }
500 
501 
502 inline
504  const Vec3R& pivot, const Vec3R& scale,
505  const Vec3R& rotate, const Vec3R& translate,
506  const std::string& xformOrder, const std::string& rotOrder):
507  mPivot(0, 0, 0),
508  mMipLevels(0, 0, 0),
509  mPreScaleTransform(Mat4R::identity()),
510  mPostScaleTransform(Mat4R::identity())
511 {
512  init(pivot, scale, rotate, translate, xformOrder, rotOrder);
513 }
514 
515 
517 
518 
519 inline void
520 GridTransformer::init(
521  const Vec3R& pivot, const Vec3R& scale,
522  const Vec3R& rotate, const Vec3R& translate,
523  const std::string& xformOrder, const std::string& rotOrder)
524 {
525  if (xformOrder.size() != 3) {
526  OPENVDB_THROW(ValueError, "invalid transform order (" + xformOrder + ")");
527  }
528  if (rotOrder.size() != 3) {
529  OPENVDB_THROW(ValueError, "invalid rotation order (" + rotOrder + ")");
530  }
531 
532  mPivot = pivot;
533 
534  // Scaling is handled via a mipmapping-like scheme of successive
535  // halvings of the tree resolution, until the remaining scale
536  // factor is greater than or equal to 1/2.
537  Vec3R scaleRemainder = scale;
538  for (int i = 0; i < 3; ++i) {
539  double s = std::fabs(scale(i));
540  if (s < 0.5) {
541  mMipLevels(i) = int(std::floor(-std::log(s)/std::log(2.0)));
542  scaleRemainder(i) = scale(i) * (1 << mMipLevels(i));
543  }
544  }
545 
546  // Build pre-scale and post-scale transform matrices based on
547  // the user-specified order of operations.
548  // Note that we iterate over the transform order string in reverse order
549  // (e.g., "t", "r", "s", given "srt"). This is because math::Mat matrices
550  // postmultiply row vectors rather than premultiplying column vectors.
551  mTransform = mPreScaleTransform = mPostScaleTransform = Mat4R::identity();
552  Mat4R* remainder = &mPostScaleTransform;
553  int rpos, spos, tpos;
554  rpos = spos = tpos = 3;
555  for (int ix = 2; ix >= 0; --ix) { // reverse iteration
556  switch (xformOrder[ix]) {
557 
558  case 'r':
559  rpos = ix;
560  mTransform.preTranslate(pivot);
561  remainder->preTranslate(pivot);
562 
563  int xpos, ypos, zpos;
564  xpos = ypos = zpos = 3;
565  for (int ir = 2; ir >= 0; --ir) {
566  switch (rotOrder[ir]) {
567  case 'x':
568  xpos = ir;
569  mTransform.preRotate(math::X_AXIS, rotate.x());
570  remainder->preRotate(math::X_AXIS, rotate.x());
571  break;
572  case 'y':
573  ypos = ir;
574  mTransform.preRotate(math::Y_AXIS, rotate.y());
575  remainder->preRotate(math::Y_AXIS, rotate.y());
576  break;
577  case 'z':
578  zpos = ir;
579  mTransform.preRotate(math::Z_AXIS, rotate.z());
580  remainder->preRotate(math::Z_AXIS, rotate.z());
581  break;
582  }
583  }
584  // Reject rotation order strings that don't contain exactly one
585  // instance of "x", "y" and "z".
586  if (xpos > 2 || ypos > 2 || zpos > 2) {
587  OPENVDB_THROW(ValueError, "invalid rotation order (" + rotOrder + ")");
588  }
589 
590  mTransform.preTranslate(-pivot);
591  remainder->preTranslate(-pivot);
592  break;
593 
594  case 's':
595  spos = ix;
596  mTransform.preTranslate(pivot);
597  mTransform.preScale(scale);
598  mTransform.preTranslate(-pivot);
599 
600  remainder->preTranslate(pivot);
601  remainder->preScale(scaleRemainder);
602  remainder->preTranslate(-pivot);
603  remainder = &mPreScaleTransform;
604  break;
605 
606  case 't':
607  tpos = ix;
608  mTransform.preTranslate(translate);
609  remainder->preTranslate(translate);
610  break;
611  }
612  }
613  // Reject transform order strings that don't contain exactly one
614  // instance of "t", "r" and "s".
615  if (tpos > 2 || rpos > 2 || spos > 2) {
616  OPENVDB_THROW(ValueError, "invalid transform order (" + xformOrder + ")");
617  }
618 }
619 
620 
622 
623 
624 template<typename InterrupterType>
625 void
626 GridResampler::setInterrupter(InterrupterType& interrupter)
627 {
628  mInterrupt = boost::bind(&InterrupterType::wasInterrupted,
629  /*this=*/&interrupter, /*percent=*/-1);
630 }
631 
632 
633 template<typename Sampler, typename GridT, typename Transformer>
634 void
635 GridResampler::transformGrid(const Transformer& xform,
636  const GridT& inGrid, GridT& outGrid) const
637 {
638  tools::changeBackground(outGrid.tree(), inGrid.background());
639  applyTransform<Sampler>(xform, inGrid, outGrid);
640 }
641 
642 
643 template<class Sampler, class GridT>
644 void
645 GridTransformer::transformGrid(const GridT& inGrid, GridT& outGrid) const
646 {
647  tools::changeBackground(outGrid.tree(), inGrid.background());
648 
649  if (!Sampler::mipmap() || mMipLevels == Vec3i::zero()) {
650  // Skip the mipmapping step.
651  const MatrixTransform xform(mTransform);
652  applyTransform<Sampler>(xform, inGrid, outGrid);
653 
654  } else {
655  bool firstPass = true;
656  const typename GridT::ValueType background = inGrid.background();
657  typename GridT::Ptr tempGrid = GridT::create(background);
658 
659  if (!mPreScaleTransform.eq(Mat4R::identity())) {
660  firstPass = false;
661  // Apply the pre-scale transform to the input grid
662  // and store the result in a temporary grid.
663  const MatrixTransform xform(mPreScaleTransform);
664  applyTransform<Sampler>(xform, inGrid, *tempGrid);
665  }
666 
667  // While the scale factor along one or more axes is less than 1/2,
668  // scale the grid by half along those axes.
669  Vec3i count = mMipLevels; // # of halvings remaining per axis
670  while (count != Vec3i::zero()) {
671  MatrixTransform xform;
672  xform.mat.setTranslation(mPivot);
673  xform.mat.preScale(Vec3R(
674  count.x() ? .5 : 1, count.y() ? .5 : 1, count.z() ? .5 : 1));
675  xform.mat.preTranslate(-mPivot);
676  xform.invMat = xform.mat.inverse();
677 
678  if (firstPass) {
679  firstPass = false;
680  // Scale the input grid and store the result in a temporary grid.
681  applyTransform<Sampler>(xform, inGrid, *tempGrid);
682  } else {
683  // Scale the temporary grid and store the result in a transient grid,
684  // then swap the two and discard the transient grid.
685  typename GridT::Ptr destGrid = GridT::create(background);
686  applyTransform<Sampler>(xform, *tempGrid, *destGrid);
687  tempGrid.swap(destGrid);
688  }
689  // (3, 2, 1) -> (2, 1, 0) -> (1, 0, 0) -> (0, 0, 0), etc.
690  count = math::maxComponent(count - 1, Vec3i::zero());
691  }
692 
693  // Apply the post-scale transform and store the result in the output grid.
694  if (!mPostScaleTransform.eq(Mat4R::identity())) {
695  const MatrixTransform xform(mPostScaleTransform);
696  applyTransform<Sampler>(xform, *tempGrid, outGrid);
697  } else {
698  outGrid.setTree(tempGrid->treePtr());
699  }
700  }
701 }
702 
703 
705 
706 
707 template<class Sampler, class TreeT, typename Transformer>
708 class GridResampler::RangeProcessor
709 {
710 public:
711  typedef typename TreeT::LeafCIter LeafIterT;
712  typedef typename TreeT::ValueAllCIter TileIterT;
713  typedef typename tree::IteratorRange<LeafIterT> LeafRange;
714  typedef typename tree::IteratorRange<TileIterT> TileRange;
715  typedef typename tree::ValueAccessor<const TreeT> InTreeAccessor;
716  typedef typename tree::ValueAccessor<TreeT> OutTreeAccessor;
717 
718  RangeProcessor(const Transformer& xform, const CoordBBox& b, const TreeT& inT, TreeT& outT):
719  mIsRoot(true), mXform(xform), mBBox(b),
720  mInTree(inT), mOutTree(&outT), mInAcc(mInTree), mOutAcc(*mOutTree)
721  {}
722 
723  RangeProcessor(const Transformer& xform, const CoordBBox& b, const TreeT& inTree):
724  mIsRoot(false), mXform(xform), mBBox(b),
725  mInTree(inTree), mOutTree(new TreeT(inTree.background())),
726  mInAcc(mInTree), mOutAcc(*mOutTree)
727  {}
728 
729  ~RangeProcessor() { if (!mIsRoot) delete mOutTree; }
730 
732  RangeProcessor(RangeProcessor& other, tbb::split):
733  mIsRoot(false),
734  mXform(other.mXform),
735  mBBox(other.mBBox),
736  mInTree(other.mInTree),
737  mOutTree(new TreeT(mInTree.background())),
738  mInAcc(mInTree),
739  mOutAcc(*mOutTree),
740  mInterrupt(other.mInterrupt)
741  {}
742 
743  void setInterrupt(const InterruptFunc& f) { mInterrupt = f; }
744 
746  void operator()(LeafRange& r)
747  {
748  for ( ; r; ++r) {
749  if (interrupt()) break;
750  LeafIterT i = r.iterator();
751  CoordBBox bbox(i->origin(), i->origin() + Coord(i->dim()));
752  if (!mBBox.empty()) {
753  // Intersect the leaf node's bounding box with mBBox.
754  bbox = CoordBBox(
755  Coord::maxComponent(bbox.min(), mBBox.min()),
756  Coord::minComponent(bbox.max(), mBBox.max()));
757  }
758  if (!bbox.empty()) {
759  transformBBox<Sampler>(mXform, bbox, mInAcc, mOutAcc, mInterrupt);
760  }
761  }
762  }
763 
765  void operator()(TileRange& r)
766  {
767  for ( ; r; ++r) {
768  if (interrupt()) break;
769 
770  TileIterT i = r.iterator();
771  // Skip voxels and background tiles.
772  if (!i.isTileValue()) continue;
773  if (!i.isValueOn() && math::isApproxEqual(*i, mOutTree->background())) continue;
774 
775  CoordBBox bbox;
776  i.getBoundingBox(bbox);
777  if (!mBBox.empty()) {
778  // Intersect the tile's bounding box with mBBox.
779  bbox = CoordBBox(
780  Coord::maxComponent(bbox.min(), mBBox.min()),
781  Coord::minComponent(bbox.max(), mBBox.max()));
782  }
783  if (!bbox.empty()) {
788  internal::TileSampler<Sampler, InTreeAccessor>
789  sampler(bbox, i.getValue(), i.isValueOn());
790  transformBBox(mXform, bbox, mInAcc, mOutAcc, mInterrupt, sampler);
791  }
792  }
793  }
794 
796  void join(RangeProcessor& other)
797  {
798  if (!interrupt()) mOutTree->merge(*other.mOutTree);
799  }
800 
801 private:
802  bool interrupt() const { return mInterrupt && mInterrupt(); }
803 
804  const bool mIsRoot; // true if mOutTree is the top-level tree
805  Transformer mXform;
806  CoordBBox mBBox;
807  const TreeT& mInTree;
808  TreeT* mOutTree;
809  InTreeAccessor mInAcc;
810  OutTreeAccessor mOutAcc;
811  InterruptFunc mInterrupt;
812 };
813 
814 
816 
817 
818 template<class Sampler, class GridT, typename Transformer>
819 void
820 GridResampler::applyTransform(const Transformer& xform,
821  const GridT& inGrid, GridT& outGrid) const
822 {
823  typedef typename GridT::TreeType TreeT;
824  const TreeT& inTree = inGrid.tree();
825  TreeT& outTree = outGrid.tree();
826 
827  typedef RangeProcessor<Sampler, TreeT, Transformer> RangeProc;
828 
829  const GridClass gridClass = inGrid.getGridClass();
830 
831  if (gridClass != GRID_LEVEL_SET && mTransformTiles) {
832  // Independently transform the tiles of the input grid.
833  // Note: Tiles in level sets can only be background tiles, and they
834  // are handled more efficiently with a signed flood fill (see below).
835 
836  RangeProc proc(xform, CoordBBox(), inTree, outTree);
837  proc.setInterrupt(mInterrupt);
838 
839  typename RangeProc::TileIterT tileIter = inTree.cbeginValueAll();
840  tileIter.setMaxDepth(tileIter.getLeafDepth() - 1); // skip leaf nodes
841  typename RangeProc::TileRange tileRange(tileIter);
842 
843  if (mThreaded) {
844  tbb::parallel_reduce(tileRange, proc);
845  } else {
846  proc(tileRange);
847  }
848  }
849 
850  CoordBBox clipBBox;
851  if (gridClass == GRID_LEVEL_SET) {
852  // Inactive voxels in level sets can only be background voxels, and they
853  // are handled more efficiently with a signed flood fill (see below).
854  clipBBox = inGrid.evalActiveVoxelBoundingBox();
855  }
856 
857  // Independently transform the leaf nodes of the input grid.
858 
859  RangeProc proc(xform, clipBBox, inTree, outTree);
860  proc.setInterrupt(mInterrupt);
861 
862  typename RangeProc::LeafRange leafRange(inTree.cbeginLeaf());
863 
864  if (mThreaded) {
865  tbb::parallel_reduce(leafRange, proc);
866  } else {
867  proc(leafRange);
868  }
869 
870  // If the grid is a level set, mark inactive voxels as inside or outside.
871  if (gridClass == GRID_LEVEL_SET) {
872  tools::pruneLevelSet(outTree);
873  tools::signedFloodFill(outTree);
874  }
875 }
876 
877 
879 
880 
881 //static
882 template<class Sampler, class InTreeT, class OutTreeT, class Transformer>
883 void
884 GridResampler::transformBBox(
885  const Transformer& xform,
886  const CoordBBox& bbox,
887  const InTreeT& inTree,
888  OutTreeT& outTree,
889  const InterruptFunc& interrupt,
890  const Sampler& sampler)
891 {
892  typedef typename OutTreeT::ValueType ValueT;
893 
894  // Transform the corners of the input tree's bounding box
895  // and compute the enclosing bounding box in the output tree.
896  Vec3R
897  inRMin(bbox.min().x(), bbox.min().y(), bbox.min().z()),
898  inRMax(bbox.max().x(), bbox.max().y(), bbox.max().z()),
899  outRMin = math::minComponent(xform.transform(inRMin), xform.transform(inRMax)),
900  outRMax = math::maxComponent(xform.transform(inRMin), xform.transform(inRMax));
901  for (int i = 0; i < 8; ++i) {
902  Vec3R corner(
903  i & 1 ? inRMax.x() : inRMin.x(),
904  i & 2 ? inRMax.y() : inRMin.y(),
905  i & 4 ? inRMax.z() : inRMin.z());
906  outRMin = math::minComponent(outRMin, xform.transform(corner));
907  outRMax = math::maxComponent(outRMax, xform.transform(corner));
908  }
909  Vec3i
910  outMin = local_util::floorVec3(outRMin) - Sampler::radius(),
911  outMax = local_util::ceilVec3(outRMax) + Sampler::radius();
912 
913  if (!xform.isAffine()) {
914  // If the transform is not affine, back-project each output voxel
915  // into the input tree.
916  Vec3R xyz, inXYZ;
917  Coord outXYZ;
918  int &x = outXYZ.x(), &y = outXYZ.y(), &z = outXYZ.z();
919  for (x = outMin.x(); x <= outMax.x(); ++x) {
920  if (interrupt && interrupt()) break;
921  xyz.x() = x;
922  for (y = outMin.y(); y <= outMax.y(); ++y) {
923  if (interrupt && interrupt()) break;
924  xyz.y() = y;
925  for (z = outMin.z(); z <= outMax.z(); ++z) {
926  xyz.z() = z;
927  inXYZ = xform.invTransform(xyz);
928  ValueT result;
929  if (sampler.sample(inTree, inXYZ, result)) {
930  outTree.setValueOn(outXYZ, result);
931  } else {
932  // Note: Don't overwrite existing active values with inactive values.
933  if (!outTree.isValueOn(outXYZ)) {
934  outTree.setValueOff(outXYZ, result);
935  }
936  }
937  }
938  }
939  }
940  } else { // affine
941  // Compute step sizes in the input tree that correspond to
942  // unit steps in x, y and z in the output tree.
943  const Vec3R
944  translation = xform.invTransform(Vec3R(0, 0, 0)),
945  deltaX = xform.invTransform(Vec3R(1, 0, 0)) - translation,
946  deltaY = xform.invTransform(Vec3R(0, 1, 0)) - translation,
947  deltaZ = xform.invTransform(Vec3R(0, 0, 1)) - translation;
948 
949 #if defined(__ICC)
950  const Vec3R dummy = deltaX;
954 #endif
955 
956  // Step by whole voxels through the output tree, sampling the
957  // corresponding fractional voxels of the input tree.
958  Vec3R inStartX = xform.invTransform(Vec3R(outMin));
959  Coord outXYZ;
960  int &x = outXYZ.x(), &y = outXYZ.y(), &z = outXYZ.z();
961  for (x = outMin.x(); x <= outMax.x(); ++x, inStartX += deltaX) {
962  if (interrupt && interrupt()) break;
963  Vec3R inStartY = inStartX;
964  for (y = outMin.y(); y <= outMax.y(); ++y, inStartY += deltaY) {
965  if (interrupt && interrupt()) break;
966  Vec3R inXYZ = inStartY;
967  for (z = outMin.z(); z <= outMax.z(); ++z, inXYZ += deltaZ) {
968  ValueT result;
969  if (sampler.sample(inTree, inXYZ, result)) {
970  outTree.setValueOn(outXYZ, result);
971  } else {
972  // Note: Don't overwrite existing active values with inactive values.
973  if (!outTree.isValueOn(outXYZ)) {
974  outTree.setValueOff(outXYZ, result);
975  }
976  }
977  }
978  }
979  }
980  }
981 } // GridResampler::transformBBox()
982 
983 } // namespace tools
984 } // namespace OPENVDB_VERSION_NAME
985 } // namespace openvdb
986 
987 #endif // OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
988 
989 // Copyright (c) 2012-2015 DreamWorks Animation LLC
990 // All rights reserved. This software is distributed under the
991 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
3x3 matrix class.
Definition: Mat3.h:54
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76
virtual ~GridTransformer()
Definition: GridTransformer.h:268
ValueT mVal
Definition: GridTransformer.h:143
BBoxd mBBox
Definition: GridTransformer.h:142
MatrixTransform(const Mat4R &xform)
Definition: GridTransformer.h:336
Mat4 inverse(T tolerance=0) const
Definition: Mat4.h:490
Definition: TreeIterator.h:1339
Definition: Interpolation.h:223
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
void setThreaded(bool b)
Enable or disable threading. (Threading is enabled by default.)
Definition: GridTransformer.h:197
This class implements the Transformer functor interface (specifically, the isAffine(), transform() and invTransform() methods) for a transform that maps an A grid into a B grid's index space such that, after resampling, A's index space and transform match B's index space and transform.
Definition: GridTransformer.h:355
Definition: Exceptions.h:88
bool isAffine() const
Definition: GridTransformer.h:367
Definition: Interpolation.h:123
Definition: Math.h:841
GridTransformer(const Mat4R &xform)
Definition: GridTransformer.h:486
Mat3< T > getMat3() const
Definition: Mat4.h:302
math::Vec3< Real > Vec3R
Definition: Types.h:76
bool isIdentity() const
Definition: GridTransformer.h:369
virtual ~GridResampler()
Definition: GridTransformer.h:194
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:97
boost::function< bool(void)> InterruptFunc
Definition: GridTransformer.h:191
Efficient multi-threaded replacement of the background values in tree.
Vec3i floorVec3(const Vec3R &v)
Definition: Interpolation.h:610
Vec2< T > maxComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise maximum of the two vectors.
Definition: Vec2.h:520
const Vec3< T > & init(T x=0, T y=0, T z=0)
Definition: Vec3.h:117
bool threaded() const
Return true if threading is enabled.
Definition: GridTransformer.h:199
Vec3R invTransform(const Vec3R &pos) const
Definition: GridTransformer.h:342
Vec3< T > getTranslation() const
Return the translation component.
Definition: Mat4.h:314
Vec3i ceilVec3(const Vec3R &v)
Definition: Interpolation.h:617
T & y()
Definition: Vec3.h:98
math::Mat4< Real > Mat4R
Definition: Types.h:101
void resampleToMatch(const GridType &inGrid, GridType &outGrid)
Resample an input grid into an output grid of the same type such that, after resampling, the input and output grids coincide (apart from sampling artifacts), but the output grid's transform is unchanged.
Definition: GridTransformer.h:475
void setTransformTiles(bool b)
Enable or disable processing of tiles. (Enabled by default, except for level set grids.)
Definition: GridTransformer.h:201
bool isApproxEqual(const Type &a, const Type &b)
Return true if a is equal to b to within the default floating-point comparison tolerance.
Definition: Math.h:370
void setInterrupter(InterrupterType &)
Allow processing to be aborted by providing an interrupter object. The interrupter will be queried pe...
Definition: GridTransformer.h:626
void changeBackground(TreeOrLeafManagerT &tree, const typename TreeOrLeafManagerT::ValueType &background, bool threaded=true, size_t grainSize=32)
Replace the background value in all the nodes of a tree.
Definition: ChangeBackground.h:230
Vec3< typename MatType::value_type > eulerAngles(const MatType &mat, RotationOrder rotationOrder, typename MatType::value_type eps=static_cast< typename MatType::value_type >(1.0e-8))
Return the Euler angles composing the given rotation matrix.
Definition: Mat.h:314
Vec3R transform(const Vec3R &pos) const
Definition: GridTransformer.h:340
const boost::disable_if_c< VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:105
Vec3< int32_t > Vec3i
Definition: Vec3.h:640
void preTranslate(const Vec3< T0 > &tr)
Left multiples by the specified translation, i.e. Trans * (*this)
Definition: Mat4.h:715
GridResampler()
Definition: GridTransformer.h:193
MatrixTransform()
Definition: GridTransformer.h:335
Defined various multi-threaded utility functions for trees.
Vec2< T > minComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise minimum of the two vectors.
Definition: Vec2.h:511
static const Mat4< Real > & identity()
Predefined constant for identity matrix.
Definition: Mat4.h:147
GridClass
Definition: Types.h:204
void transformGrid(const Transformer &, const GridT &inGrid, GridT &outGrid) const
Definition: GridTransformer.h:635
void setTranslation(const Vec3< T > &t)
Definition: Mat4.h:319
void applyTransform(const Transformer &, const GridT &inGrid, GridT &outGrid) const
Definition: GridTransformer.h:820
boost::enable_if< boost::is_floating_point< typename GridType::ValueType >, typename GridType::Ptr >::type doLevelSetRebuild(const GridType &grid, typename GridType::ValueType iso, typename GridType::ValueType exWidth, typename GridType::ValueType inWidth, const math::Transform *xform, InterruptT *interrupter)
Definition: LevelSetRebuild.h:229
TileSampler(const CoordBBox &b, const ValueT &tileVal, bool on)
Definition: GridTransformer.h:128
#define OPENVDB_VERSION_NAME
Definition: version.h:43
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:52
bool decompose(const math::Mat4< T > &m, math::Vec3< T > &scale, math::Vec3< T > &rotate, math::Vec3< T > &translate)
Decompose an affine transform into scale, rotation and translation components.
Definition: GridTransformer.h:298
const math::Transform & getA() const
Definition: GridTransformer.h:381
A GridTransformer applies a geometric transformation to an input grid using one of several sampling s...
Definition: GridTransformer.h:255
Propagates the sign of distance values from the active voxels in the narrow band to the inactive valu...
openvdb::Vec3R invTransform(const openvdb::Vec3R &pos) const
Definition: GridTransformer.h:376
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:402
ABTransform(const math::Transform &aXform, const math::Transform &bXform)
Definition: GridTransformer.h:360
Definition: Exceptions.h:39
bool interrupt() const
Definition: GridTransformer.h:218
Mat4R mat
Definition: GridTransformer.h:344
openvdb::Vec3R transform(const openvdb::Vec3R &pos) const
Definition: GridTransformer.h:371
Definition: Math.h:840
void doResampleToMatch(const GridType &inGrid, GridType &outGrid, Interrupter &interrupter)
Definition: GridTransformer.h:399
T & z()
Definition: Vec3.h:99
Definition: Types.h:206
bool isAffine(const Mat4< T > &m)
Definition: Mat4.h:1336
bool sample(const TreeT &inTree, const Vec3R &inCoord, ValueT &result) const
Definition: GridTransformer.h:135
TreeT::ValueType ValueT
Definition: GridTransformer.h:123
TileSampler(const CoordBBox &, const typename TreeT::ValueType &, bool)
Definition: GridTransformer.h:153
Mat4R invMat
Definition: GridTransformer.h:344
void signedFloodFill(TreeOrLeafManagerT &tree, bool threaded=true, size_t grainSize=1)
Set the values of all inactive voxels and tiles of a narrow-band level set from the signs of the acti...
Definition: SignedFloodFill.h:280
Calculate an axis-aligned bounding box in index space from a bounding sphere in world space...
Definition: Transform.h:66
const boost::disable_if_c< VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:109
bool mEmpty
Definition: GridTransformer.h:144
A TileSampler wraps a grid sampler of another type (BoxSampler, QuadraticSampler, etc...
Definition: GridTransformer.h:120
TileSampler(const CoordBBox &, const typename TreeT::ValueType &, bool)
Definition: GridTransformer.h:161
Definition: GridTransformer.h:187
bool eq(const Vec3< T > &v, T eps=static_cast< T >(1.0e-7)) const
Test if "this" vector is equivalent to vector v with tolerance of eps.
Definition: Vec3.h:145
void transformGrid(const GridT &inGrid, GridT &outGrid) const
Definition: GridTransformer.h:645
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
void preScale(const Vec3< T0 > &v)
Definition: Mat4.h:748
bool isAffine() const
Definition: GridTransformer.h:338
Provises a unified interface for sampling, i.e. interpolation.
Definition: Interpolation.h:90
MatType scale(const Vec3< typename MatType::value_type > &s)
Return a matrix that scales by s.
Definition: Mat.h:594
Definition: Exceptions.h:87
boost::shared_ptr< GridTransformer > Ptr
Definition: GridTransformer.h:258
static bool sample(const TreeT &inTree, const Vec3R &inCoord, typename TreeT::ValueType &result)
Sample inTree at the floating-point index coordinate inCoord and store the result in result...
Definition: Math.h:839
const math::Transform & getB() const
Definition: GridTransformer.h:382
const Mat4R & getTransform() const
Definition: GridTransformer.h:270
void preRotate(Axis axis, T angle)
Left multiplies by a rotation clock-wiseabout the given axis into this matrix.
Definition: Mat4.h:810
boost::shared_ptr< GridResampler > Ptr
Definition: GridTransformer.h:190
bool transformTiles() const
Return true if tile processing is enabled.
Definition: GridTransformer.h:203
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
Definition: Vec3.h:97
bool eq(const Mat4 &m, T eps=1.0e-8) const
Test if "this" is equivalent to m with tolerance of eps value.
Definition: Mat4.h:338