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/Types.h>
44 #include <openvdb/math/Math.h>
45 #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&);
204 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
205 void transformGrid(
const Transformer&,
206 const GridT& inGrid, GridT& outGrid)
const;
209 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
210 void applyTransform(
const Transformer&,
const GridT& inGrid, GridT& outGrid)
const;
215 template<
typename Sampler,
typename InTreeT,
typename OutTreeT,
typename Transformer>
216 static void transformBBox(
const Transformer&,
const CoordBBox& inBBox,
217 const InTreeT& inTree, OutTreeT& outTree,
const InterruptFunc&,
218 const Sampler& = Sampler());
220 template<
typename Sampler,
typename TreeT,
typename Transformer>
221 class RangeProcessor;
223 bool mThreaded, mTransformTiles;
252 typedef boost::shared_ptr<GridTransformer>
Ptr;
259 const Vec3R& translate,
260 const std::string& xformOrder =
"tsr",
261 const std::string& rotationOrder =
"zyx");
266 template<
class Sampler,
class Gr
idT>
267 void transformGrid(
const GridT& inGrid, GridT& outGrid)
const;
270 struct MatrixTransform;
274 const std::string& xformOrder,
const std::string& rotOrder);
278 Mat4R mTransform, mPreScaleTransform, mPostScaleTransform;
285 namespace local_util {
307 temp *= math::scale<math::Mat3<T> >(
scale).inverse();
357 mIsAffine(mAXform.isLinear() && mBXform.isLinear()),
358 mIsIdentity(mIsAffine && mAXform == mBXform)
367 return mBXform.worldToIndex(mAXform.indexToWorld(pos));
372 return mAXform.worldToIndex(mBXform.indexToWorld(pos));
380 const bool mIsAffine;
381 const bool mIsIdentity;
391 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
395 ABTransform xform(inGrid.transform(), outGrid.transform());
397 if (Sampler::consistent() && xform.isIdentity()) {
400 outGrid.setTree(inGrid.tree().copy());
401 }
else if (xform.isAffine()) {
405 Mat4R mat = xform.getA().baseMap()->getAffineMap()->getMat4() *
406 ( xform.getB().baseMap()->getAffineMap()->getMat4().inverse() );
424 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
431 if (inGrid.constTransform() == outGrid.constTransform()) {
434 outGrid.setTree(inGrid.tree().copy());
440 typedef typename GridType::ValueType ValueT;
442 ? ValueT(outGrid.background() * (1.0 / outGrid.voxelSize()[0]))
443 : ValueT(inGrid.background() * (1.0 / inGrid.voxelSize()[0])));
445 typename GridType::Ptr tempGrid;
448 halfWidth, halfWidth,
449 &outGrid.constTransform(), &interrupter);
457 outGrid.setTree(tempGrid->treePtr());
463 doResampleToMatch<Sampler>(inGrid, outGrid, interrupter);
467 template<
typename Sampler,
typename Gr
idType>
472 resampleToMatch<Sampler>(inGrid, outGrid, interrupter);
480 GridTransformer::GridTransformer(
const Mat4R& xform):
484 mPreScaleTransform(
Mat4R::identity()),
485 mPostScaleTransform(
Mat4R::identity())
491 init(mPivot, scale, rotate, translate,
"srt",
"zyx");
500 const std::string& xformOrder,
const std::string& rotOrder):
503 mPreScaleTransform(
Mat4R::identity()),
504 mPostScaleTransform(
Mat4R::identity())
506 init(pivot, scale, rotate, translate, xformOrder, rotOrder);
514 GridTransformer::init(
517 const std::string& xformOrder,
const std::string& rotOrder)
519 if (xformOrder.size() != 3) {
522 if (rotOrder.size() != 3) {
532 for (
int i = 0; i < 3; ++i) {
533 double s = std::fabs(
scale(i));
535 mMipLevels(i) = int(std::floor(-std::log(s)/std::log(2.0)));
536 scaleRemainder(i) =
scale(i) * (1 << mMipLevels(i));
545 mTransform = mPreScaleTransform = mPostScaleTransform =
Mat4R::identity();
546 Mat4R* remainder = &mPostScaleTransform;
547 int rpos, spos, tpos;
548 rpos = spos = tpos = 3;
549 for (
int ix = 2; ix >= 0; --ix) {
550 switch (xformOrder[ix]) {
555 remainder->preTranslate(pivot);
557 int xpos, ypos, zpos;
558 xpos = ypos = zpos = 3;
559 for (
int ir = 2; ir >= 0; --ir) {
560 switch (rotOrder[ir]) {
580 if (xpos > 2 || ypos > 2 || zpos > 2) {
581 OPENVDB_THROW(ValueError,
"invalid rotation order (" + rotOrder +
")");
585 remainder->preTranslate(-pivot);
594 remainder->preTranslate(pivot);
595 remainder->preScale(scaleRemainder);
596 remainder->preTranslate(-pivot);
597 remainder = &mPreScaleTransform;
603 remainder->preTranslate(translate);
609 if (tpos > 2 || rpos > 2 || spos > 2) {
610 OPENVDB_THROW(ValueError,
"invalid transform order (" + xformOrder +
")");
618 template<
typename InterrupterType>
627 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
630 const GridT& inGrid, GridT& outGrid)
const
632 outGrid.setBackground(inGrid.background());
633 applyTransform<Sampler>(xform, inGrid, outGrid);
637 template<
class Sampler,
class Gr
idT>
641 outGrid.setBackground(inGrid.background());
643 if (!Sampler::mipmap() || mMipLevels ==
Vec3i::zero()) {
646 applyTransform<Sampler>(xform, inGrid, outGrid);
649 bool firstPass =
true;
650 const typename GridT::ValueType background = inGrid.background();
651 typename GridT::Ptr tempGrid = GridT::create(background);
658 applyTransform<Sampler>(xform, inGrid, *tempGrid);
663 Vec3i count = mMipLevels;
668 count.
x() ? .5 : 1, count.
y() ? .5 : 1, count.
z() ? .5 : 1));
675 applyTransform<Sampler>(xform, inGrid, *tempGrid);
679 typename GridT::Ptr destGrid = GridT::create(background);
680 applyTransform<Sampler>(xform, *tempGrid, *destGrid);
681 tempGrid.swap(destGrid);
690 applyTransform<Sampler>(xform, *tempGrid, outGrid);
692 outGrid.setTree(tempGrid->treePtr());
701 template<
class Sampler,
class TreeT,
typename Transformer>
713 mIsRoot(true), mXform(xform), mBBox(b),
714 mInTree(inT), mOutTree(&outT), mInAcc(mInTree), mOutAcc(*mOutTree)
718 mIsRoot(false), mXform(xform), mBBox(b),
719 mInTree(inTree), mOutTree(new TreeT(inTree.background())),
720 mInAcc(mInTree), mOutAcc(*mOutTree)
728 mXform(other.mXform),
730 mInTree(other.mInTree),
731 mOutTree(new TreeT(mInTree.background())),
734 mInterrupt(other.mInterrupt)
743 if (interrupt())
break;
746 if (!mBBox.
empty()) {
753 transformBBox<Sampler>(mXform, bbox, mInAcc, mOutAcc, mInterrupt);
762 if (interrupt())
break;
766 if (!i.isTileValue())
continue;
770 i.getBoundingBox(bbox);
771 if (!mBBox.
empty()) {
783 sampler(bbox, i.getValue(), i.isValueOn());
784 transformBBox(mXform, bbox, mInAcc, mOutAcc, mInterrupt, sampler);
792 if (!interrupt()) mOutTree->merge(*other.mOutTree);
796 bool interrupt()
const {
return mInterrupt && mInterrupt(); }
801 const TreeT& mInTree;
812 template<
class Sampler,
class Gr
idT,
typename Transformer>
815 const GridT& inGrid, GridT& outGrid)
const
817 typedef typename GridT::TreeType TreeT;
818 const TreeT& inTree = inGrid.tree();
819 TreeT& outTree = outGrid.tree();
823 const GridClass gridClass = inGrid.getGridClass();
830 RangeProc proc(xform,
CoordBBox(), inTree, outTree);
831 proc.setInterrupt(mInterrupt);
833 typename RangeProc::TileIterT tileIter = inTree.cbeginValueAll();
834 tileIter.setMaxDepth(tileIter.getLeafDepth() - 1);
835 typename RangeProc::TileRange tileRange(tileIter);
838 tbb::parallel_reduce(tileRange, proc);
848 clipBBox = inGrid.evalActiveVoxelBoundingBox();
853 RangeProc proc(xform, clipBBox, inTree, outTree);
854 proc.setInterrupt(mInterrupt);
856 typename RangeProc::LeafRange leafRange(inTree.cbeginLeaf());
859 tbb::parallel_reduce(leafRange, proc);
866 outTree.pruneInactive();
867 outTree.signedFloodFill();
876 template<
class Sampler,
class InTreeT,
class OutTreeT,
class Transformer>
878 GridResampler::transformBBox(
879 const Transformer& xform,
881 const InTreeT& inTree,
883 const InterruptFunc& interrupt,
884 const Sampler& sampler)
886 typedef typename OutTreeT::ValueType ValueT;
896 for (
int i = 0; i < 8; ++i) {
898 i & 1 ? inRMax.x() : inRMin.x(),
899 i & 2 ? inRMax.y() : inRMin.y(),
900 i & 4 ? inRMax.z() : inRMin.z());
908 if (!xform.isAffine()) {
913 int &x = outXYZ.
x(), &y = outXYZ.
y(), &z = outXYZ.
z();
914 for (x = outMin.
x(); x <= outMax.x(); ++x) {
917 for (y = outMin.
y(); y <= outMax.y(); ++y) {
920 for (z = outMin.
z(); z <= outMax.z(); ++z) {
922 inXYZ = xform.invTransform(xyz);
924 if (sampler.sample(inTree, inXYZ, result)) {
925 outTree.setValueOn(outXYZ, result);
928 if (!outTree.isValueOn(outXYZ)) {
929 outTree.setValueOff(outXYZ, result);
939 translation = xform.invTransform(
Vec3R(0, 0, 0)),
940 deltaX = xform.invTransform(
Vec3R(1, 0, 0)) - translation,
941 deltaY = xform.invTransform(
Vec3R(0, 1, 0)) - translation,
942 deltaZ = xform.invTransform(
Vec3R(0, 0, 1)) - translation;
948 const Vec3R dummy = deltaX;
953 Vec3R inStartX = xform.invTransform(
Vec3R(outMin));
955 int &x = outXYZ.
x(), &y = outXYZ.y(), &z = outXYZ.z();
956 for (x = outMin.
x(); x <= outMax.x(); ++x, inStartX += deltaX) {
958 Vec3R inStartY = inStartX;
959 for (y = outMin.
y(); y <= outMax.y(); ++y, inStartY += deltaY) {
961 Vec3R inXYZ = inStartY;
962 for (z = outMin.
z(); z <= outMax.z(); ++z, inXYZ += deltaZ) {
964 if (sampler.sample(inTree, inXYZ, result)) {
965 outTree.setValueOn(outXYZ, result);
968 if (!outTree.isValueOn(outXYZ)) {
969 outTree.setValueOff(outXYZ, result);
982 #endif // OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED