34 #ifndef OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
35 #define OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
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>
46 #include <openvdb/util/NullInterrupter.h>
78 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
80 resampleToMatch(
const GridType& inGrid, GridType& outGrid, Interrupter& interrupter);
103 template<
typename Sampler,
typename Gr
idType>
116 template<
typename Sampler,
typename TreeT>
120 typedef typename TreeT::ValueType
ValueT;
126 mBBox(b.
min().asVec3d(), b.
max().asVec3d()), mVal(tileVal), mActive(on), mEmpty(false)
128 mBBox.expand(-this->radius());
129 mEmpty = mBBox.empty();
134 if (!mEmpty && mBBox.isInside(inCoord)) { result = mVal;
return mActive; }
135 return Sampler::sample(inTree, inCoord, result);
147 template<
typename TreeT>
149 TileSampler(
const CoordBBox&,
const typename TreeT::ValueType&,
bool) {}
154 template<
typename TreeT>
156 TileSampler(
const CoordBBox&,
const typename TreeT::ValueType&,
bool) {}
185 typedef boost::shared_ptr<GridResampler>
Ptr;
203 template<
typename InterrupterType>
void setInterrupter(InterrupterType&);
205 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
206 void transformGrid(
const Transformer&,
207 const GridT& inGrid, GridT& outGrid)
const;
210 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
211 void applyTransform(
const Transformer&,
const GridT& inGrid, GridT& outGrid)
const;
213 bool interrupt()
const {
return mInterrupt && mInterrupt(); }
216 template<
typename Sampler,
typename InTreeT,
typename OutTreeT,
typename Transformer>
217 static void transformBBox(
const Transformer&,
const CoordBBox& inBBox,
218 const InTreeT& inTree, OutTreeT& outTree,
const InterruptFunc&,
219 const Sampler& = Sampler());
221 template<
typename Sampler,
typename TreeT,
typename Transformer>
222 class RangeProcessor;
224 bool mThreaded, mTransformTiles;
225 InterruptFunc mInterrupt;
253 typedef boost::shared_ptr<GridTransformer>
Ptr;
260 const Vec3R& translate,
261 const std::string& xformOrder =
"tsr",
262 const std::string& rotationOrder =
"zyx");
267 template<
class Sampler,
class Gr
idT>
268 void transformGrid(
const GridT& inGrid, GridT& outGrid)
const;
271 struct MatrixTransform;
275 const std::string& xformOrder,
const std::string& rotOrder);
279 Mat4R mTransform, mPreScaleTransform, mPostScaleTransform;
286 namespace local_util {
308 temp *= math::scale<math::Mat3<T> >(
scale).inverse();
358 mIsAffine(mAXform.isLinear() && mBXform.isLinear()),
359 mIsIdentity(mIsAffine && mAXform == mBXform)
368 return mBXform.worldToIndex(mAXform.indexToWorld(pos));
373 return mAXform.worldToIndex(mBXform.indexToWorld(pos));
381 const bool mIsAffine;
382 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 Interrupter,
typename Gr
idType>
432 if (inGrid.constTransform() == outGrid.constTransform()) {
435 outGrid.setTree(inGrid.tree().copy());
441 typedef typename GridType::ValueType ValueT;
443 ? ValueT(outGrid.background() * (1.0 / outGrid.voxelSize()[0]))
444 : ValueT(inGrid.background() * (1.0 / inGrid.voxelSize()[0])));
446 typename GridType::Ptr tempGrid;
449 halfWidth, halfWidth,
450 &outGrid.constTransform(), &interrupter);
458 outGrid.setTree(tempGrid->treePtr());
464 doResampleToMatch<Sampler>(inGrid, outGrid, interrupter);
468 template<
typename Sampler,
typename Gr
idType>
473 resampleToMatch<Sampler>(inGrid, outGrid, interrupter);
481 GridTransformer::GridTransformer(
const Mat4R& xform):
485 mPreScaleTransform(
Mat4R::identity()),
486 mPostScaleTransform(
Mat4R::identity())
492 init(mPivot, scale, rotate, translate,
"srt",
"zyx");
501 const std::string& xformOrder,
const std::string& rotOrder):
504 mPreScaleTransform(
Mat4R::identity()),
505 mPostScaleTransform(
Mat4R::identity())
507 init(pivot, scale, rotate, translate, xformOrder, rotOrder);
515 GridTransformer::init(
518 const std::string& xformOrder,
const std::string& rotOrder)
520 if (xformOrder.size() != 3) {
523 if (rotOrder.size() != 3) {
533 for (
int i = 0; i < 3; ++i) {
534 double s = std::fabs(
scale(i));
536 mMipLevels(i) = int(std::floor(-std::log(s)/std::log(2.0)));
537 scaleRemainder(i) =
scale(i) * (1 << mMipLevels(i));
546 mTransform = mPreScaleTransform = mPostScaleTransform =
Mat4R::identity();
547 Mat4R* remainder = &mPostScaleTransform;
548 int rpos, spos, tpos;
549 rpos = spos = tpos = 3;
550 for (
int ix = 2; ix >= 0; --ix) {
551 switch (xformOrder[ix]) {
556 remainder->preTranslate(pivot);
558 int xpos, ypos, zpos;
559 xpos = ypos = zpos = 3;
560 for (
int ir = 2; ir >= 0; --ir) {
561 switch (rotOrder[ir]) {
581 if (xpos > 2 || ypos > 2 || zpos > 2) {
582 OPENVDB_THROW(ValueError,
"invalid rotation order (" + rotOrder +
")");
586 remainder->preTranslate(-pivot);
595 remainder->preTranslate(pivot);
596 remainder->preScale(scaleRemainder);
597 remainder->preTranslate(-pivot);
598 remainder = &mPreScaleTransform;
604 remainder->preTranslate(translate);
610 if (tpos > 2 || rpos > 2 || spos > 2) {
611 OPENVDB_THROW(ValueError,
"invalid transform order (" + xformOrder +
")");
619 template<
typename InterrupterType>
628 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
631 const GridT& inGrid, GridT& outGrid)
const
633 outGrid.setBackground(inGrid.background());
634 applyTransform<Sampler>(xform, inGrid, outGrid);
638 template<
class Sampler,
class Gr
idT>
642 outGrid.setBackground(inGrid.background());
644 if (!Sampler::mipmap() || mMipLevels == Vec3i::zero()) {
647 applyTransform<Sampler>(xform, inGrid, outGrid);
650 bool firstPass =
true;
651 const typename GridT::ValueType background = inGrid.background();
652 typename GridT::Ptr tempGrid = GridT::create(background);
659 applyTransform<Sampler>(xform, inGrid, *tempGrid);
664 Vec3i count = mMipLevels;
665 while (count != Vec3i::zero()) {
669 count.x() ? .5 : 1, count.y() ? .5 : 1, count.z() ? .5 : 1));
676 applyTransform<Sampler>(xform, inGrid, *tempGrid);
680 typename GridT::Ptr destGrid = GridT::create(background);
681 applyTransform<Sampler>(xform, *tempGrid, *destGrid);
682 tempGrid.swap(destGrid);
691 applyTransform<Sampler>(xform, *tempGrid, outGrid);
693 outGrid.setTree(tempGrid->treePtr());
702 template<
class Sampler,
class TreeT,
typename Transformer>
703 class GridResampler::RangeProcessor
706 typedef typename TreeT::LeafCIter LeafIterT;
707 typedef typename TreeT::ValueAllCIter TileIterT;
713 RangeProcessor(
const Transformer& xform,
const CoordBBox& b,
const TreeT& inT, TreeT& outT):
714 mIsRoot(true), mXform(xform), mBBox(b),
715 mInTree(inT), mOutTree(&outT), mInAcc(mInTree), mOutAcc(*mOutTree)
718 RangeProcessor(
const Transformer& xform,
const CoordBBox& b,
const TreeT& inTree):
719 mIsRoot(false), mXform(xform), mBBox(b),
720 mInTree(inTree), mOutTree(new TreeT(inTree.background())),
721 mInAcc(mInTree), mOutAcc(*mOutTree)
724 ~RangeProcessor() {
if (!mIsRoot)
delete mOutTree; }
727 RangeProcessor(RangeProcessor& other, tbb::split):
729 mXform(other.mXform),
731 mInTree(other.mInTree),
732 mOutTree(new TreeT(mInTree.background())),
735 mInterrupt(other.mInterrupt)
738 void setInterrupt(
const InterruptFunc& f) { mInterrupt = f; }
741 void operator()(LeafRange& r)
745 LeafIterT i = r.iterator();
746 CoordBBox bbox(i->origin(), i->origin() + Coord(i->dim()));
747 if (!mBBox.empty()) {
754 transformBBox<Sampler>(mXform, bbox, mInAcc, mOutAcc, mInterrupt);
760 void operator()(TileRange& r)
765 TileIterT i = r.iterator();
767 if (!i.isTileValue())
continue;
771 i.getBoundingBox(bbox);
772 if (!mBBox.empty()) {
783 internal::TileSampler<Sampler, InTreeAccessor>
784 sampler(bbox, i.getValue(), i.isValueOn());
785 transformBBox(mXform, bbox, mInAcc, mOutAcc, mInterrupt, sampler);
791 void join(RangeProcessor& other)
793 if (!
interrupt()) mOutTree->merge(*other.mOutTree);
797 bool interrupt()
const {
return mInterrupt && mInterrupt(); }
802 const TreeT& mInTree;
804 InTreeAccessor mInAcc;
805 OutTreeAccessor mOutAcc;
813 template<
class Sampler,
class Gr
idT,
typename Transformer>
816 const GridT& inGrid, GridT& outGrid)
const
818 typedef typename GridT::TreeType TreeT;
819 const TreeT& inTree = inGrid.tree();
820 TreeT& outTree = outGrid.tree();
822 typedef RangeProcessor<Sampler, TreeT, Transformer> RangeProc;
824 const GridClass gridClass = inGrid.getGridClass();
831 RangeProc proc(xform, CoordBBox(), inTree, outTree);
832 proc.setInterrupt(mInterrupt);
834 typename RangeProc::TileIterT tileIter = inTree.cbeginValueAll();
835 tileIter.setMaxDepth(tileIter.getLeafDepth() - 1);
836 typename RangeProc::TileRange tileRange(tileIter);
839 tbb::parallel_reduce(tileRange, proc);
849 clipBBox = inGrid.evalActiveVoxelBoundingBox();
854 RangeProc proc(xform, clipBBox, inTree, outTree);
855 proc.setInterrupt(mInterrupt);
857 typename RangeProc::LeafRange leafRange(inTree.cbeginLeaf());
860 tbb::parallel_reduce(leafRange, proc);
867 outTree.pruneInactive();
868 outTree.signedFloodFill();
877 template<
class Sampler,
class InTreeT,
class OutTreeT,
class Transformer>
879 GridResampler::transformBBox(
880 const Transformer& xform,
881 const CoordBBox& bbox,
882 const InTreeT& inTree,
884 const InterruptFunc& interrupt,
885 const Sampler& sampler)
887 typedef typename OutTreeT::ValueType ValueT;
892 inRMin(bbox.min().x(), bbox.min().y(), bbox.min().z()),
893 inRMax(bbox.max().x(), bbox.max().y(), bbox.max().z()),
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;
945 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
OPENVDB_API Hermite min(const Hermite &, const Hermite &)
min and max operations done directly on the compressed data.
Vec2< T > maxComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise maximum of the two vectors.
Definition: Vec2.h:506
math::Vec3< Real > Vec3R
Definition: Types.h:75
Mat3< T > getMat3() const
Definition: Mat4.h:302
const Vec3< T > & init(T x=0, T y=0, T z=0)
Definition: Vec3.h:114
T & z()
Definition: Vec3.h:96
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:97
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:52
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76
3x3 matrix class.
Definition: Mat3.h:54
Mat4 inverse(T tolerance=0) const
Definition: Mat4.h:490
static const Mat4< Real > & identity()
Predefined constant for identity matrix.
Definition: Mat4.h:147
void preTranslate(const Vec3< T0 > &tr)
Left multiples by the specified translation, i.e. Trans * (*this)
Definition: Mat4.h:715
Definition: Exceptions.h:88
Vec3< T > getTranslation() const
Return the translation component.
Definition: Mat4.h:314
T & y()
Definition: Vec3.h:95
GridClass
Definition: Types.h:168
Vec3< typename MatType::value_type > eulerAngles(const MatType &mat, RotationOrder rotationOrder, typename MatType::value_type eps=1.0e-8)
Return the Euler angles composing the given rotation matrix.
Definition: Mat.h:313
math::Mat4< Real > Mat4R
Definition: Types.h:100
void setTranslation(const Vec3< T > &t)
Definition: Mat4.h:319
Definition: Exceptions.h:87
#define OPENVDB_VERSION_NAME
Definition: version.h:45
Definition: TreeIterator.h:1322
bool isAffine(const Mat4< T > &m)
Definition: Mat4.h:1335
OPENVDB_API Hermite max(const Hermite &, const Hermite &)
min and max operations done directly on the compressed data.
Vec2< T > minComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise minimum of the two vectors.
Definition: Vec2.h:497
Vec3< int32_t > Vec3i
Definition: Vec3.h:622
MatType scale(const Vec3< typename MatType::value_type > &s)
Return a matrix that scales by s.
Definition: Mat.h:593
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:141
bool isApproxEqual(const Hermite &lhs, const Hermite &rhs)
Definition: Hermite.h:470
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:67
void preScale(const Vec3< T0 > &v)
Definition: Mat4.h:748
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
Definition: Vec3.h:94
void preRotate(Axis axis, T angle)
Left multiplies by a rotation clock-wiseabout the given axis into this matrix.
Definition: Mat4.h:810
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