33 #ifndef OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
34 #define OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
37 #include <boost/bind.hpp>
38 #include <boost/function.hpp>
39 #include <boost/shared_ptr.hpp>
40 #include <tbb/blocked_range.h>
41 #include <tbb/parallel_reduce.h>
42 #include <openvdb/Grid.h>
43 #include <openvdb/Platform.h>
44 #include <openvdb/Types.h>
45 #include <openvdb/math/Math.h>
46 #include <openvdb/util/NullInterrupter.h>
77 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
79 resampleToMatch(
const GridType& inGrid, GridType& outGrid, Interrupter& interrupter);
102 template<
typename Sampler,
typename Gr
idType>
115 template<
typename Sampler,
typename TreeT>
119 typedef typename TreeT::ValueType
ValueT;
125 mBBox(b.
min().asVec3d(), b.
max().asVec3d()), mVal(tileVal), mActive(on), mEmpty(false)
127 mBBox.expand(-this->radius());
128 mEmpty = mBBox.empty();
131 bool sample(
const TreeT& inTree,
const Vec3R& inCoord,
ValueT& result)
const
133 if (!mEmpty && mBBox.isInside(inCoord)) { result = mVal;
return mActive; }
134 return Sampler::sample(inTree, inCoord, result);
146 template<
typename TreeT>
153 template<
typename TreeT>
184 typedef boost::shared_ptr<GridResampler>
Ptr;
202 template<
typename InterrupterType>
void setInterrupter(InterrupterType&);
211 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
212 void transformGrid(
const Transformer&,
213 const GridT& inGrid, GridT& outGrid)
const;
216 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
217 void applyTransform(
const Transformer&,
const GridT& inGrid, GridT& outGrid)
const;
219 bool interrupt()
const {
return mInterrupt && mInterrupt(); }
222 template<
typename Sampler,
typename InTreeT,
typename OutTreeT,
typename Transformer>
223 static void transformBBox(
const Transformer&,
const CoordBBox& inBBox,
224 const InTreeT& inTree, OutTreeT& outTree,
const InterruptFunc&,
225 const Sampler& = Sampler());
227 template<
typename Sampler,
typename TreeT,
typename Transformer>
228 class RangeProcessor;
230 bool mThreaded, mTransformTiles;
231 InterruptFunc mInterrupt;
259 typedef boost::shared_ptr<GridTransformer>
Ptr;
266 const Vec3R& translate,
267 const std::string& xformOrder =
"tsr",
268 const std::string& rotationOrder =
"zyx");
273 template<
class Sampler,
class Gr
idT>
274 void transformGrid(
const GridT& inGrid, GridT& outGrid)
const;
277 struct MatrixTransform;
281 const std::string& xformOrder,
const std::string& rotOrder);
285 Mat4R mTransform, mPreScaleTransform, mPostScaleTransform;
292 namespace local_util {
314 temp *= math::scale<math::Mat3<T> >(
scale).inverse();
364 mIsAffine(mAXform.isLinear() && mBXform.isLinear()),
365 mIsIdentity(mIsAffine && mAXform == mBXform)
374 return mBXform.worldToIndex(mAXform.indexToWorld(pos));
379 return mAXform.worldToIndex(mBXform.indexToWorld(pos));
387 const bool mIsAffine;
388 const bool mIsIdentity;
392 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
396 ABTransform xform(inGrid.transform(), outGrid.transform());
398 if (Sampler::consistent() && xform.isIdentity()) {
401 outGrid.setTree(inGrid.tree().copy());
402 }
else if (xform.isAffine()) {
406 Mat4R mat = xform.getA().baseMap()->getAffineMap()->getMat4() *
407 ( xform.getB().baseMap()->getAffineMap()->getMat4().inverse() );
425 template<
typename Sampler,
typename Gr
idType>
430 resampleToMatch<Sampler>(inGrid, outGrid, interrupter);
438 GridTransformer::GridTransformer(
const Mat4R& xform):
442 mPreScaleTransform(
Mat4R::identity()),
443 mPostScaleTransform(
Mat4R::identity())
449 init(mPivot, scale, rotate, translate,
"srt",
"zyx");
458 const std::string& xformOrder,
const std::string& rotOrder):
461 mPreScaleTransform(
Mat4R::identity()),
462 mPostScaleTransform(
Mat4R::identity())
464 init(pivot, scale, rotate, translate, xformOrder, rotOrder);
472 GridTransformer::init(
475 const std::string& xformOrder,
const std::string& rotOrder)
477 if (xformOrder.size() != 3) {
480 if (rotOrder.size() != 3) {
490 for (
int i = 0; i < 3; ++i) {
491 double s = std::fabs(
scale(i));
493 mMipLevels(i) = int(std::floor(-std::log(s)/std::log(2.0)));
494 scaleRemainder(i) =
scale(i) * (1 << mMipLevels(i));
503 mTransform = mPreScaleTransform = mPostScaleTransform =
Mat4R::identity();
504 Mat4R* remainder = &mPostScaleTransform;
505 int rpos, spos, tpos;
506 rpos = spos = tpos = 3;
507 for (
int ix = 2; ix >= 0; --ix) {
508 switch (xformOrder[ix]) {
513 remainder->preTranslate(pivot);
515 int xpos, ypos, zpos;
516 xpos = ypos = zpos = 3;
517 for (
int ir = 2; ir >= 0; --ir) {
518 switch (rotOrder[ir]) {
538 if (xpos > 2 || ypos > 2 || zpos > 2) {
539 OPENVDB_THROW(ValueError,
"invalid rotation order (" + rotOrder +
")");
543 remainder->preTranslate(-pivot);
552 remainder->preTranslate(pivot);
553 remainder->preScale(scaleRemainder);
554 remainder->preTranslate(-pivot);
555 remainder = &mPreScaleTransform;
561 remainder->preTranslate(translate);
567 if (tpos > 2 || rpos > 2 || spos > 2) {
568 OPENVDB_THROW(ValueError,
"invalid transform order (" + xformOrder +
")");
576 template<
typename InterrupterType>
585 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
588 const GridT& inGrid, GridT& outGrid)
const
590 outGrid.setBackground(inGrid.background());
591 applyTransform<Sampler>(xform, inGrid, outGrid);
595 template<
class Sampler,
class Gr
idT>
599 outGrid.setBackground(inGrid.background());
601 if (!Sampler::mipmap() || mMipLevels ==
Vec3i::zero()) {
604 applyTransform<Sampler>(xform, inGrid, outGrid);
607 bool firstPass =
true;
608 const typename GridT::ValueType background = inGrid.background();
609 typename GridT::Ptr tempGrid = GridT::create(background);
616 applyTransform<Sampler>(xform, inGrid, *tempGrid);
621 Vec3i count = mMipLevels;
626 count.
x() ? .5 : 1, count.
y() ? .5 : 1, count.
z() ? .5 : 1));
633 applyTransform<Sampler>(xform, inGrid, *tempGrid);
637 typename GridT::Ptr destGrid = GridT::create(background);
638 applyTransform<Sampler>(xform, *tempGrid, *destGrid);
639 tempGrid.swap(destGrid);
648 applyTransform<Sampler>(xform, *tempGrid, outGrid);
650 outGrid.setTree(tempGrid->treePtr());
659 template<
class Sampler,
class TreeT,
typename Transformer>
660 class GridResampler::RangeProcessor
663 typedef typename TreeT::LeafCIter LeafIterT;
664 typedef typename TreeT::ValueAllCIter TileIterT;
670 RangeProcessor(
const Transformer& xform,
const CoordBBox& b,
const TreeT& inT, TreeT& outT):
671 mIsRoot(true), mXform(xform), mBBox(b),
672 mInTree(inT), mOutTree(&outT), mInAcc(mInTree), mOutAcc(*mOutTree)
675 RangeProcessor(
const Transformer& xform,
const CoordBBox& b,
const TreeT& inTree):
676 mIsRoot(false), mXform(xform), mBBox(b),
677 mInTree(inTree), mOutTree(new TreeT(inTree.getBackground())),
678 mInAcc(mInTree), mOutAcc(*mOutTree)
681 ~RangeProcessor() {
if (!mIsRoot)
delete mOutTree; }
684 RangeProcessor(RangeProcessor& other, tbb::split):
686 mXform(other.mXform),
688 mInTree(other.mInTree),
689 mOutTree(new TreeT(mInTree.getBackground())),
692 mInterrupt(other.mInterrupt)
698 void operator()(LeafRange& r)
702 LeafIterT i = r.iterator();
704 if (!mBBox.empty()) {
711 transformBBox<Sampler>(mXform, bbox, mInAcc, mOutAcc, mInterrupt);
717 void operator()(TileRange& r)
722 TileIterT i = r.iterator();
724 if (!i.isTileValue())
continue;
728 i.getBoundingBox(bbox);
729 if (!mBBox.empty()) {
740 internal::TileSampler<Sampler, InTreeAccessor>
741 sampler(bbox, i.getValue(), i.isValueOn());
742 transformBBox(mXform, bbox, mInAcc, mOutAcc, mInterrupt, sampler);
748 void join(RangeProcessor& other)
750 if (!
interrupt()) mOutTree->merge(*other.mOutTree);
754 bool interrupt()
const {
return mInterrupt && mInterrupt(); }
759 const TreeT& mInTree;
761 InTreeAccessor mInAcc;
762 OutTreeAccessor mOutAcc;
770 template<
class Sampler,
class Gr
idT,
typename Transformer>
773 const GridT& inGrid, GridT& outGrid)
const
775 typedef typename GridT::TreeType TreeT;
776 const TreeT& inTree = inGrid.tree();
777 TreeT& outTree = outGrid.tree();
779 typedef RangeProcessor<Sampler, TreeT, Transformer> RangeProc;
781 const GridClass gridClass = inGrid.getGridClass();
788 RangeProc proc(xform,
CoordBBox(), inTree, outTree);
789 proc.setInterrupt(mInterrupt);
791 typename RangeProc::TileIterT tileIter = inTree.cbeginValueAll();
792 tileIter.setMaxDepth(tileIter.getLeafDepth() - 1);
793 typename RangeProc::TileRange tileRange(tileIter);
796 tbb::parallel_reduce(tileRange, proc);
806 clipBBox = inGrid.evalActiveVoxelBoundingBox();
811 RangeProc proc(xform, clipBBox, inTree, outTree);
812 proc.setInterrupt(mInterrupt);
814 typename RangeProc::LeafRange leafRange(inTree.cbeginLeaf());
817 tbb::parallel_reduce(leafRange, proc);
824 outTree.pruneInactive();
825 outTree.signedFloodFill();
834 template<
class Sampler,
class InTreeT,
class OutTreeT,
class Transformer>
836 GridResampler::transformBBox(
837 const Transformer& xform,
839 const InTreeT& inTree,
842 const Sampler& sampler)
844 typedef typename OutTreeT::ValueType ValueT;
854 for (
int i = 0; i < 8; ++i) {
856 i & 1 ? inRMax.x() : inRMin.x(),
857 i & 2 ? inRMax.y() : inRMin.y(),
858 i & 4 ? inRMax.z() : inRMin.z());
866 if (!xform.isAffine()) {
871 int &x = outXYZ.
x(), &y = outXYZ.
y(), &z = outXYZ.
z();
872 for (x = outMin.
x(); x <= outMax.x(); ++x) {
875 for (y = outMin.
y(); y <= outMax.y(); ++y) {
878 for (z = outMin.
z(); z <= outMax.z(); ++z) {
880 inXYZ = xform.invTransform(xyz);
882 if (sampler.sample(inTree, inXYZ, result)) {
883 outTree.setValueOn(outXYZ, result);
886 if (!outTree.isValueOn(outXYZ)) {
887 outTree.setValueOff(outXYZ, result);
897 translation = xform.invTransform(
Vec3R(0, 0, 0)),
898 deltaX = xform.invTransform(
Vec3R(1, 0, 0)) - translation,
899 deltaY = xform.invTransform(
Vec3R(0, 1, 0)) - translation,
900 deltaZ = xform.invTransform(
Vec3R(0, 0, 1)) - translation;
906 const Vec3R dummy = deltaX;
911 Vec3R inStartX = xform.invTransform(
Vec3R(outMin));
913 int &x = outXYZ.
x(), &y = outXYZ.
y(), &z = outXYZ.
z();
914 for (x = outMin.
x(); x <= outMax.x(); ++x, inStartX += deltaX) {
916 Vec3R inStartY = inStartX;
917 for (y = outMin.
y(); y <= outMax.y(); ++y, inStartY += deltaY) {
919 Vec3R inXYZ = inStartY;
920 for (z = outMin.
z(); z <= outMax.z(); ++z, inXYZ += deltaZ) {
922 if (sampler.sample(inTree, inXYZ, result)) {
923 outTree.setValueOn(outXYZ, result);
926 if (!outTree.isValueOn(outXYZ)) {
927 outTree.setValueOff(outXYZ, result);
940 #endif // OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED