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> 81 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
83 resampleToMatch(
const GridType& inGrid, GridType& outGrid, Interrupter& interrupter);
106 template<
typename Sampler,
typename Gr
idType>
119 template<
typename Sampler,
typename TreeT>
123 typedef typename TreeT::ValueType
ValueT;
129 mBBox(b.
min().asVec3d(), b.
max().asVec3d()), mVal(tileVal), mActive(on), mEmpty(false)
131 mBBox.expand(-this->radius());
132 mEmpty = mBBox.empty();
135 bool sample(
const TreeT& inTree,
const Vec3R& inCoord, ValueT& result)
const 137 if (!mEmpty && mBBox.isInside(inCoord)) { result = mVal;
return mActive; }
138 return Sampler::sample(inTree, inCoord, result);
150 template<
typename TreeT>
153 TileSampler(
const CoordBBox&,
const typename TreeT::ValueType&,
bool) {}
158 template<
typename TreeT>
161 TileSampler(
const CoordBBox&,
const typename TreeT::ValueType&,
bool) {}
190 typedef boost::shared_ptr<GridResampler>
Ptr;
208 template<
typename InterrupterType>
void setInterrupter(InterrupterType&);
210 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
211 void transformGrid(
const Transformer&,
212 const GridT& inGrid, GridT& outGrid)
const;
215 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
216 void applyTransform(
const Transformer&,
const GridT& inGrid, GridT& outGrid)
const;
218 bool interrupt()
const {
return mInterrupt && mInterrupt(); }
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&,
226 template<
typename Sampler,
typename TreeT,
typename Transformer>
227 class RangeProcessor;
229 bool mThreaded, mTransformTiles;
230 InterruptFunc mInterrupt;
258 typedef boost::shared_ptr<GridTransformer>
Ptr;
265 const Vec3R& translate,
266 const std::string& xformOrder =
"tsr",
267 const std::string& rotationOrder =
"zyx");
272 template<
class Sampler,
class Gr
idT>
273 void transformGrid(
const GridT& inGrid, GridT& outGrid)
const;
280 const std::string& xformOrder,
const std::string& rotOrder);
284 Mat4R mTransform, mPreScaleTransform, mPostScaleTransform;
291 namespace local_util {
312 const bool hasUniformScale = unsignedScale.
eq(
math::Vec3<T>(unsignedScale[0]));
314 bool hasRotation =
false;
315 bool validDecomposition =
false;
322 for (
size_t n = 0; n < 8; ++n) {
325 n & 0x1 ? -unsignedScale.
x() : unsignedScale.
x(),
326 n & 0x2 ? -unsignedScale.
y() : unsignedScale.
y(),
327 n & 0x4 ? -unsignedScale.
z() : unsignedScale.
z());
330 const math::Mat3<T> mat = xform * math::scale<math::Mat3<T> >(signedScale).inverse();
331 if (mat.det() < T(0.0))
continue;
336 math::rotation<math::Mat3<T> >(
math::Vec3<T>(1, 0, 0), tmpAngle.
x()) *
341 if (xform.
eq(rebuild)) {
343 const T maxAngle =
std::max(std::abs(tmpAngle[0]),
344 std::max(std::abs(tmpAngle[1]), std::abs(tmpAngle[2])));
346 if (!(minAngle < maxAngle)) {
353 validDecomposition =
true;
355 if (hasUniformScale || !hasRotation) {
363 if (!validDecomposition || (hasRotation && !hasUniformScale)) {
411 mIsAffine(mAXform.isLinear() && mBXform.isLinear()),
412 mIsIdentity(mIsAffine && mAXform == mBXform)
421 return mBXform.worldToIndex(mAXform.indexToWorld(pos));
426 return mAXform.worldToIndex(mBXform.indexToWorld(pos));
434 const bool mIsAffine;
435 const bool mIsIdentity;
445 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
449 ABTransform xform(inGrid.transform(), outGrid.transform());
451 if (Sampler::consistent() && xform.isIdentity()) {
454 outGrid.setTree(inGrid.tree().copy());
455 }
else if (xform.isAffine()) {
459 Mat4R mat = xform.getA().baseMap()->getAffineMap()->getMat4() *
460 ( xform.getB().baseMap()->getAffineMap()->getMat4().inverse() );
478 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
485 if (inGrid.constTransform() == outGrid.constTransform()) {
488 outGrid.setTree(inGrid.tree().copy());
494 typedef typename GridType::ValueType ValueT;
496 ? ValueT(outGrid.background() * (1.0 / outGrid.voxelSize()[0]))
497 : ValueT(inGrid.background() * (1.0 / inGrid.voxelSize()[0])));
499 typename GridType::Ptr tempGrid;
502 halfWidth, halfWidth,
503 &outGrid.constTransform(), &interrupter);
511 outGrid.setTree(tempGrid->treePtr());
517 doResampleToMatch<Sampler>(inGrid, outGrid, interrupter);
521 template<
typename Sampler,
typename Gr
idType>
526 resampleToMatch<Sampler>(inGrid, outGrid, interrupter);
534 GridTransformer::GridTransformer(
const Mat4R& xform):
538 mPreScaleTransform(
Mat4R::identity()),
539 mPostScaleTransform(
Mat4R::identity())
545 init(mPivot, scale, rotate, translate,
"srt",
"zyx");
554 const std::string& xformOrder,
const std::string& rotOrder):
557 mPreScaleTransform(
Mat4R::identity()),
558 mPostScaleTransform(
Mat4R::identity())
560 init(pivot, scale, rotate, translate, xformOrder, rotOrder);
568 GridTransformer::init(
571 const std::string& xformOrder,
const std::string& rotOrder)
573 if (xformOrder.size() != 3) {
576 if (rotOrder.size() != 3) {
586 for (
int i = 0; i < 3; ++i) {
587 double s = std::fabs(
scale(i));
589 mMipLevels(i) = int(std::floor(-std::log(s)/std::log(2.0)));
590 scaleRemainder(i) =
scale(i) * (1 << mMipLevels(i));
599 mTransform = mPreScaleTransform = mPostScaleTransform =
Mat4R::identity();
600 Mat4R* remainder = &mPostScaleTransform;
601 int rpos, spos, tpos;
602 rpos = spos = tpos = 3;
603 for (
int ix = 2; ix >= 0; --ix) {
604 switch (xformOrder[ix]) {
611 int xpos, ypos, zpos;
612 xpos = ypos = zpos = 3;
613 for (
int ir = 2; ir >= 0; --ir) {
614 switch (rotOrder[ir]) {
634 if (xpos > 2 || ypos > 2 || zpos > 2) {
649 remainder->
preScale(scaleRemainder);
651 remainder = &mPreScaleTransform;
663 if (tpos > 2 || rpos > 2 || spos > 2) {
672 template<
typename InterrupterType>
681 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
684 const GridT& inGrid, GridT& outGrid)
const 687 applyTransform<Sampler>(xform, inGrid, outGrid);
691 template<
class Sampler,
class Gr
idT>
700 applyTransform<Sampler>(xform, inGrid, outGrid);
703 bool firstPass =
true;
704 const typename GridT::ValueType background = inGrid.background();
705 typename GridT::Ptr tempGrid = GridT::create(background);
712 applyTransform<Sampler>(xform, inGrid, *tempGrid);
717 Vec3i count = mMipLevels;
718 while (count != Vec3i::zero()) {
722 count.x() ? .5 : 1, count.y() ? .5 : 1, count.z() ? .5 : 1));
729 applyTransform<Sampler>(xform, inGrid, *tempGrid);
733 typename GridT::Ptr destGrid = GridT::create(background);
734 applyTransform<Sampler>(xform, *tempGrid, *destGrid);
735 tempGrid.swap(destGrid);
744 applyTransform<Sampler>(xform, *tempGrid, outGrid);
746 outGrid.setTree(tempGrid->treePtr());
755 template<
class Sampler,
class TreeT,
typename Transformer>
756 class GridResampler::RangeProcessor
759 typedef typename TreeT::LeafCIter LeafIterT;
760 typedef typename TreeT::ValueAllCIter TileIterT;
766 RangeProcessor(
const Transformer& xform,
const CoordBBox& b,
const TreeT& inT, TreeT& outT):
767 mIsRoot(
true), mXform(xform), mBBox(b),
768 mInTree(inT), mOutTree(&outT), mInAcc(mInTree), mOutAcc(*mOutTree)
771 RangeProcessor(
const Transformer& xform,
const CoordBBox& b,
const TreeT& inTree):
772 mIsRoot(
false), mXform(xform), mBBox(b),
773 mInTree(inTree), mOutTree(
new TreeT(inTree.background())),
774 mInAcc(mInTree), mOutAcc(*mOutTree)
777 ~RangeProcessor() {
if (!mIsRoot)
delete mOutTree; }
780 RangeProcessor(RangeProcessor& other, tbb::split):
782 mXform(other.mXform),
784 mInTree(other.mInTree),
785 mOutTree(
new TreeT(mInTree.background())),
788 mInterrupt(other.mInterrupt)
791 void setInterrupt(
const InterruptFunc& f) { mInterrupt = f; }
794 void operator()(LeafRange& r)
798 LeafIterT i = r.iterator();
799 CoordBBox bbox(i->origin(), i->origin() + Coord(i->dim()));
800 if (!mBBox.empty()) {
807 transformBBox<Sampler>(mXform, bbox, mInAcc, mOutAcc, mInterrupt);
813 void operator()(TileRange& r)
818 TileIterT i = r.iterator();
820 if (!i.isTileValue())
continue;
824 i.getBoundingBox(bbox);
825 if (!mBBox.empty()) {
837 sampler(bbox, i.getValue(), i.isValueOn());
838 transformBBox(mXform, bbox, mInAcc, mOutAcc, mInterrupt, sampler);
844 void join(RangeProcessor& other)
846 if (!
interrupt()) mOutTree->merge(*other.mOutTree);
850 bool interrupt()
const {
return mInterrupt && mInterrupt(); }
855 const TreeT& mInTree;
857 InTreeAccessor mInAcc;
858 OutTreeAccessor mOutAcc;
866 template<
class Sampler,
class Gr
idT,
typename Transformer>
869 const GridT& inGrid, GridT& outGrid)
const 871 typedef typename GridT::TreeType TreeT;
872 const TreeT& inTree = inGrid.tree();
873 TreeT& outTree = outGrid.tree();
875 typedef RangeProcessor<Sampler, TreeT, Transformer> RangeProc;
877 const GridClass gridClass = inGrid.getGridClass();
884 RangeProc proc(xform, CoordBBox(), inTree, outTree);
885 proc.setInterrupt(mInterrupt);
887 typename RangeProc::TileIterT tileIter = inTree.cbeginValueAll();
888 tileIter.setMaxDepth(tileIter.getLeafDepth() - 1);
889 typename RangeProc::TileRange tileRange(tileIter);
892 tbb::parallel_reduce(tileRange, proc);
902 clipBBox = inGrid.evalActiveVoxelBoundingBox();
907 RangeProc proc(xform, clipBBox, inTree, outTree);
908 proc.setInterrupt(mInterrupt);
910 typename RangeProc::LeafRange leafRange(inTree.cbeginLeaf());
913 tbb::parallel_reduce(leafRange, proc);
930 template<
class Sampler,
class InTreeT,
class OutTreeT,
class Transformer>
932 GridResampler::transformBBox(
933 const Transformer& xform,
934 const CoordBBox& bbox,
935 const InTreeT& inTree,
940 typedef typename OutTreeT::ValueType ValueT;
945 inRMin(bbox.min().x(), bbox.min().y(), bbox.min().z()),
946 inRMax(bbox.max().x(), bbox.max().y(), bbox.max().z()),
949 for (
int i = 0; i < 8; ++i) {
951 i & 1 ? inRMax.x() : inRMin.x(),
952 i & 2 ? inRMax.y() : inRMin.y(),
953 i & 4 ? inRMax.z() : inRMin.z());
961 if (!xform.isAffine()) {
966 int &x = outXYZ.
x(), &y = outXYZ.y(), &z = outXYZ.z();
967 for (x = outMin.x(); x <= outMax.x(); ++x) {
970 for (y = outMin.y(); y <= outMax.y(); ++y) {
973 for (z = outMin.z(); z <= outMax.z(); ++z) {
975 inXYZ = xform.invTransform(xyz);
977 if (sampler.
sample(inTree, inXYZ, result)) {
978 outTree.setValueOn(outXYZ, result);
981 if (!outTree.isValueOn(outXYZ)) {
982 outTree.setValueOff(outXYZ, result);
992 translation = xform.invTransform(
Vec3R(0, 0, 0)),
993 deltaX = xform.invTransform(
Vec3R(1, 0, 0)) - translation,
994 deltaY = xform.invTransform(
Vec3R(0, 1, 0)) - translation,
995 deltaZ = xform.invTransform(
Vec3R(0, 0, 1)) - translation;
998 const Vec3R dummy = deltaX;
1006 Vec3R inStartX = xform.invTransform(
Vec3R(outMin));
1008 int &x = outXYZ.
x(), &y = outXYZ.y(), &z = outXYZ.z();
1009 for (x = outMin.x(); x <= outMax.x(); ++x, inStartX += deltaX) {
1011 Vec3R inStartY = inStartX;
1012 for (y = outMin.y(); y <= outMax.y(); ++y, inStartY += deltaY) {
1014 Vec3R inXYZ = inStartY;
1015 for (z = outMin.z(); z <= outMax.z(); ++z, inXYZ += deltaZ) {
1017 if (sampler.
sample(inTree, inXYZ, result)) {
1018 outTree.setValueOn(outXYZ, result);
1021 if (!outTree.isValueOn(outXYZ)) {
1022 outTree.setValueOff(outXYZ, result);
1035 #endif // OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
Mat3< T > getMat3() const
Definition: Mat4.h:339
GridClass
Definition: Types.h:211
T & z()
Definition: Vec3.h:99
Vec2< T > minComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise minimum of the two vectors.
Definition: Vec2.h:519
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:52
static const Mat4< Real > & identity()
Predefined constant for identity matrix.
Definition: Mat4.h:152
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:97
MatType rotation(const Quat< typename MatType::value_type > &q, typename MatType::value_type eps=static_cast< typename MatType::value_type >(1.0e-8))
Return the rotation matrix specified by the given quaternion.
Definition: Mat.h:153
Efficient multi-threaded replacement of the background values in tree.
Mat4 inverse(T tolerance=0) const
Definition: Mat4.h:527
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
Vec3< T > getTranslation() const
Return the translation component.
Definition: Mat4.h:351
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:375
void preRotate(Axis axis, T angle)
Left multiplies by a rotation clock-wiseabout the given axis into this matrix.
Definition: Mat4.h:840
Vec3< int32_t > Vec3i
Definition: Vec3.h:648
Defined various multi-threaded utility functions for trees.
void preTranslate(const Vec3< T0 > &tr)
Left multiples by the specified translation, i.e. Trans * (*this)
Definition: Mat4.h:745
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
#define OPENVDB_VERSION_NAME
Definition: version.h:43
Propagates the sign of distance values from the active voxels in the narrow band to the inactive valu...
Definition: TreeIterator.h:1339
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
Definition: Vec3.h:97
bool isAffine(const Mat4< T > &m)
Definition: Mat4.h:1366
Definition: Exceptions.h:39
MatType scale(const Vec3< typename MatType::value_type > &s)
Return a matrix that scales by s.
Definition: Mat.h:594
3x3 matrix class.
Definition: Mat3.h:54
void setTranslation(const Vec3< T > &t)
Definition: Mat4.h:356
Definition: Exceptions.h:87
T & y()
Definition: Vec3.h:98
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
Definition: Exceptions.h:88
math::Vec3< Real > Vec3R
Definition: Types.h:76
bool eq(const Mat3 &m, T eps=1.0e-8) const
Test if "this" is equivalent to m with tolerance of eps value.
Definition: Mat3.h:345
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
Vec2< T > maxComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise maximum of the two vectors.
Definition: Vec2.h:528
void preScale(const Vec3< T0 > &v)
Definition: Mat4.h:778
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76