34 #ifndef OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED 35 #define OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED 46 #include <tbb/blocked_range.h> 47 #include <tbb/parallel_reduce.h> 79 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
81 resampleToMatch(
const GridType& inGrid, GridType& outGrid, Interrupter& interrupter);
104 template<
typename Sampler,
typename Gr
idType>
117 template<
typename Sampler,
typename TreeT>
121 using ValueT =
typename TreeT::ValueType;
127 mBBox(b.
min().asVec3d(), b.
max().asVec3d()), mVal(tileVal), mActive(on), mEmpty(false)
129 mBBox.expand(-this->radius());
130 mEmpty = mBBox.empty();
135 if (!mEmpty && mBBox.isInside(inCoord)) { result = mVal;
return mActive; }
136 return Sampler::sample(inTree, inCoord, result);
148 template<
typename TreeT>
156 template<
typename TreeT>
209 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&,
227 template<
typename Sampler,
typename TreeT,
typename Transformer>
228 class RangeProcessor;
230 bool mThreaded, mTransformTiles;
231 InterruptFunc mInterrupt;
266 const Vec3R& translate,
267 const std::string& xformOrder =
"tsr",
268 const std::string& rotationOrder =
"zyx");
276 template<
class Sampler,
class Gr
idT>
277 void transformGrid(
const GridT& inGrid, GridT& outGrid)
const;
280 struct MatrixTransform;
284 const std::string& xformOrder,
const std::string& rotOrder);
288 Mat4R mTransform, mPreScaleTransform, mPostScaleTransform;
295 namespace local_util {
316 const bool hasUniformScale = unsignedScale.
eq(
math::Vec3<T>(unsignedScale[0]));
318 bool hasRotation =
false;
319 bool validDecomposition =
false;
326 for (
size_t n = 0; n < 8; ++n) {
329 n & 0x1 ? -unsignedScale.
x() : unsignedScale.
x(),
330 n & 0x2 ? -unsignedScale.
y() : unsignedScale.
y(),
331 n & 0x4 ? -unsignedScale.
z() : unsignedScale.
z());
334 const math::Mat3<T> mat = xform * math::scale<math::Mat3<T> >(signedScale).inverse();
335 if (mat.det() < T(0.0))
continue;
340 math::rotation<math::Mat3<T> >(
math::Vec3<T>(1, 0, 0), tmpAngle.
x()) *
345 if (xform.
eq(rebuild)) {
347 const T maxAngle =
std::max(std::abs(tmpAngle[0]),
348 std::max(std::abs(tmpAngle[1]), std::abs(tmpAngle[2])));
350 if (!(minAngle < maxAngle)) {
357 validDecomposition =
true;
359 if (hasUniformScale || !hasRotation) {
367 if (!validDecomposition || (hasRotation && !hasUniformScale)) {
415 mIsAffine(mAXform.isLinear() && mBXform.isLinear()),
416 mIsIdentity(mIsAffine && mAXform == mBXform)
425 return mBXform.worldToIndex(mAXform.indexToWorld(pos));
430 return mAXform.worldToIndex(mBXform.indexToWorld(pos));
438 const bool mIsAffine;
439 const bool mIsIdentity;
449 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
453 ABTransform xform(inGrid.transform(), outGrid.transform());
455 if (Sampler::consistent() && xform.isIdentity()) {
458 outGrid.setTree(inGrid.tree().copy());
459 }
else if (xform.isAffine()) {
463 Mat4R mat = xform.getA().baseMap()->getAffineMap()->getMat4() *
464 ( xform.getB().baseMap()->getAffineMap()->getMat4().inverse() );
482 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
489 if (inGrid.constTransform() == outGrid.constTransform()) {
492 outGrid.setTree(inGrid.tree().copy());
498 using ValueT =
typename GridType::ValueType;
500 ? ValueT(outGrid.background() * (1.0 / outGrid.voxelSize()[0]))
501 : ValueT(inGrid.background() * (1.0 / inGrid.voxelSize()[0])));
503 typename GridType::Ptr tempGrid;
505 tempGrid = doLevelSetRebuild(inGrid, zeroVal<ValueT>(),
506 halfWidth, halfWidth,
507 &outGrid.constTransform(), &interrupter);
515 outGrid.setTree(tempGrid->treePtr());
521 doResampleToMatch<Sampler>(inGrid, outGrid, interrupter);
525 template<
typename Sampler,
typename Gr
idType>
530 resampleToMatch<Sampler>(inGrid, outGrid, interrupter);
538 GridTransformer::GridTransformer(
const Mat4R& xform):
542 mPreScaleTransform(
Mat4R::identity()),
543 mPostScaleTransform(
Mat4R::identity())
549 init(mPivot,
scale, rotate, translate,
"srt",
"zyx");
558 const std::string& xformOrder,
const std::string& rotOrder):
561 mPreScaleTransform(
Mat4R::identity()),
562 mPostScaleTransform(
Mat4R::identity())
564 init(
pivot,
scale, rotate, translate, xformOrder, rotOrder);
572 GridTransformer::init(
575 const std::string& xformOrder,
const std::string& rotOrder)
577 if (xformOrder.size() != 3) {
580 if (rotOrder.size() != 3) {
590 for (
int i = 0; i < 3; ++i) {
591 double s = std::fabs(
scale(i));
593 mMipLevels(i) = int(std::floor(-std::log(s)/std::log(2.0)));
594 scaleRemainder(i) =
scale(i) * (1 << mMipLevels(i));
603 mTransform = mPreScaleTransform = mPostScaleTransform =
Mat4R::identity();
604 Mat4R* remainder = &mPostScaleTransform;
605 int rpos, spos, tpos;
606 rpos = spos = tpos = 3;
607 for (
int ix = 2; ix >= 0; --ix) {
608 switch (xformOrder[ix]) {
613 remainder->preTranslate(
pivot);
615 int xpos, ypos, zpos;
616 xpos = ypos = zpos = 3;
617 for (
int ir = 2; ir >= 0; --ir) {
618 switch (rotOrder[ir]) {
638 if (xpos > 2 || ypos > 2 || zpos > 2) {
639 OPENVDB_THROW(ValueError,
"invalid rotation order (" + rotOrder +
")");
643 remainder->preTranslate(-
pivot);
652 remainder->preTranslate(
pivot);
653 remainder->preScale(scaleRemainder);
654 remainder->preTranslate(-
pivot);
655 remainder = &mPreScaleTransform;
661 remainder->preTranslate(translate);
667 if (tpos > 2 || rpos > 2 || spos > 2) {
668 OPENVDB_THROW(ValueError,
"invalid transform order (" + xformOrder +
")");
676 template<
typename InterrupterType>
685 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
688 const GridT& inGrid, GridT& outGrid)
const 691 applyTransform<Sampler>(xform, inGrid, outGrid);
695 template<
class Sampler,
class Gr
idT>
704 applyTransform<Sampler>(xform, inGrid, outGrid);
707 bool firstPass =
true;
708 const typename GridT::ValueType background = inGrid.background();
709 typename GridT::Ptr tempGrid = GridT::create(background);
716 applyTransform<Sampler>(xform, inGrid, *tempGrid);
721 Vec3i count = mMipLevels;
722 while (count != Vec3i::zero()) {
726 count.x() ? .5 : 1, count.y() ? .5 : 1, count.z() ? .5 : 1));
733 applyTransform<Sampler>(xform, inGrid, *tempGrid);
737 typename GridT::Ptr destGrid = GridT::create(background);
738 applyTransform<Sampler>(xform, *tempGrid, *destGrid);
739 tempGrid.swap(destGrid);
748 applyTransform<Sampler>(xform, *tempGrid, outGrid);
750 outGrid.setTree(tempGrid->treePtr());
759 template<
class Sampler,
class TreeT,
typename Transformer>
760 class GridResampler::RangeProcessor
763 using LeafIterT =
typename TreeT::LeafCIter;
764 using TileIterT =
typename TreeT::ValueAllCIter;
770 RangeProcessor(
const Transformer& xform,
const CoordBBox& b,
const TreeT& inT, TreeT& outT):
771 mIsRoot(true), mXform(xform), mBBox(b),
772 mInTree(inT), mOutTree(&outT), mInAcc(mInTree), mOutAcc(*mOutTree)
775 RangeProcessor(
const Transformer& xform,
const CoordBBox& b,
const TreeT& inTree):
776 mIsRoot(false), mXform(xform), mBBox(b),
777 mInTree(inTree), mOutTree(new TreeT(inTree.background())),
778 mInAcc(mInTree), mOutAcc(*mOutTree)
781 ~RangeProcessor() {
if (!mIsRoot)
delete mOutTree; }
784 RangeProcessor(RangeProcessor& other, tbb::split):
786 mXform(other.mXform),
788 mInTree(other.mInTree),
789 mOutTree(new TreeT(mInTree.background())),
792 mInterrupt(other.mInterrupt)
795 void setInterrupt(
const InterruptFunc& f) { mInterrupt = f; }
798 void operator()(LeafRange& r)
802 LeafIterT i = r.iterator();
803 CoordBBox bbox(i->origin(), i->origin() + Coord(i->dim()));
804 if (!mBBox.empty()) {
811 transformBBox<Sampler>(mXform, bbox, mInAcc, mOutAcc, mInterrupt);
817 void operator()(TileRange& r)
822 TileIterT i = r.iterator();
824 if (!i.isTileValue())
continue;
828 i.getBoundingBox(bbox);
829 if (!mBBox.empty()) {
840 internal::TileSampler<Sampler, InTreeAccessor>
841 sampler(bbox, i.getValue(), i.isValueOn());
842 transformBBox(mXform, bbox, mInAcc, mOutAcc, mInterrupt, sampler);
848 void join(RangeProcessor& other)
850 if (!
interrupt()) mOutTree->merge(*other.mOutTree);
854 bool interrupt()
const {
return mInterrupt && mInterrupt(); }
859 const TreeT& mInTree;
861 InTreeAccessor mInAcc;
862 OutTreeAccessor mOutAcc;
870 template<
class Sampler,
class Gr
idT,
typename Transformer>
873 const GridT& inGrid, GridT& outGrid)
const 875 using TreeT =
typename GridT::TreeType;
876 const TreeT& inTree = inGrid.tree();
877 TreeT& outTree = outGrid.tree();
879 using RangeProc = RangeProcessor<Sampler, TreeT, Transformer>;
881 const GridClass gridClass = inGrid.getGridClass();
888 RangeProc proc(xform,
CoordBBox(), inTree, outTree);
889 proc.setInterrupt(mInterrupt);
891 typename RangeProc::TileIterT tileIter = inTree.cbeginValueAll();
892 tileIter.setMaxDepth(tileIter.getLeafDepth() - 1);
893 typename RangeProc::TileRange tileRange(tileIter);
896 tbb::parallel_reduce(tileRange, proc);
906 clipBBox = inGrid.evalActiveVoxelBoundingBox();
911 RangeProc proc(xform, clipBBox, inTree, outTree);
912 proc.setInterrupt(mInterrupt);
914 typename RangeProc::LeafRange leafRange(inTree.cbeginLeaf());
917 tbb::parallel_reduce(leafRange, proc);
934 template<
class Sampler,
class InTreeT,
class OutTreeT,
class Transformer>
936 GridResampler::transformBBox(
937 const Transformer& xform,
939 const InTreeT& inTree,
941 const InterruptFunc& interrupt,
944 using ValueT =
typename OutTreeT::ValueType;
950 inRMax(bbox.
max().
x()+1, bbox.
max().
y()+1, bbox.
max().
z()+1),
953 for (
int i = 0; i < 8; ++i) {
955 i & 1 ? inRMax.x() : inRMin.x(),
956 i & 2 ? inRMax.y() : inRMin.y(),
957 i & 4 ? inRMax.z() : inRMin.z());
965 if (!xform.isAffine()) {
970 int &x = outXYZ.
x(), &y = outXYZ.
y(), &z = outXYZ.
z();
971 for (x = outMin.x(); x <= outMax.x(); ++x) {
974 for (y = outMin.y(); y <= outMax.y(); ++y) {
977 for (z = outMin.z(); z <= outMax.z(); ++z) {
979 inXYZ = xform.invTransform(xyz);
981 if (sampler.
sample(inTree, inXYZ, result)) {
982 outTree.setValueOn(outXYZ, result);
985 if (!outTree.isValueOn(outXYZ)) {
986 outTree.setValueOff(outXYZ, result);
996 translation = xform.invTransform(
Vec3R(0, 0, 0)),
997 deltaX = xform.invTransform(
Vec3R(1, 0, 0)) - translation,
998 deltaY = xform.invTransform(
Vec3R(0, 1, 0)) - translation,
999 deltaZ = xform.invTransform(
Vec3R(0, 0, 1)) - translation;
1002 const Vec3R dummy = deltaX;
1010 Vec3R inStartX = xform.invTransform(
Vec3R(outMin));
1012 int &x = outXYZ.
x(), &y = outXYZ.y(), &z = outXYZ.z();
1013 for (x = outMin.x(); x <= outMax.x(); ++x, inStartX += deltaX) {
1015 Vec3R inStartY = inStartX;
1016 for (y = outMin.y(); y <= outMax.y(); ++y, inStartY += deltaY) {
1018 Vec3R inXYZ = inStartY;
1019 for (z = outMin.z(); z <= outMax.z(); ++z, inXYZ += deltaZ) {
1021 if (sampler.
sample(inTree, inXYZ, result)) {
1022 outTree.setValueOn(outXYZ, result);
1025 if (!outTree.isValueOn(outXYZ)) {
1026 outTree.setValueOff(outXYZ, result);
1039 #endif // OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED math::Mat4< Real > Mat4R
Definition: Types.h:108
math::Vec3< Real > Vec3R
Definition: Types.h:79
Vec3< int32_t > Vec3i
Definition: Vec3.h:676
Definition: TreeIterator.h:1351
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Mat3< T > getMat3() const
Definition: Mat4.h:343
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
Int32 z() const
Definition: Coord.h:159
Efficient multi-threaded replacement of the background values in tree.
const Coord & max() const
Definition: Coord.h:338
bool eq(const Mat4 &m, T eps=1.0e-8) const
Return true if this matrix is equivalent to m within a tolerance of eps.
Definition: Mat4.h:379
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76
3x3 matrix class.
Definition: Mat3.h:55
Vec2< T > minComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise minimum of the two vectors.
Definition: Vec2.h:530
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:51
Vec3< T > getTranslation() const
Return the translation component.
Definition: Mat4.h:355
Int32 x() const
Definition: Coord.h:157
static const Mat4< Real > & identity()
Predefined constant for identity matrix.
Definition: Mat4.h:152
Defined various multi-threaded utility functions for trees.
Definition: Exceptions.h:91
bool eq(const Mat3 &m, T eps=1.0e-8) const
Return true if this matrix is equivalent to m within a tolerance of eps.
Definition: Mat3.h:349
GridClass
Definition: Types.h:275
Vec2< T > maxComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise maximum of the two vectors.
Definition: Vec2.h:539
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:158
void preTranslate(const Vec3< T0 > &tr)
Left multiples by the specified translation, i.e. Trans * (*this)
Definition: Mat4.h:749
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:136
bool isAffine(const Mat4< T > &m)
Definition: Mat4.h:1350
void preScale(const Vec3< T0 > &v)
Definition: Mat4.h:782
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
T & z()
Definition: Vec3.h:112
const Coord & min() const
Definition: Coord.h:337
T & y()
Definition: Vec3.h:111
Definition: Exceptions.h:40
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:264
void maxComponent(const Coord &other)
Perform a component-wise maximum with the other Coord.
Definition: Coord.h:210
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:358
MatType scale(const Vec3< typename MatType::value_type > &s)
Return a matrix that scales by s.
Definition: Mat.h:647
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:52
Int32 y() const
Definition: Coord.h:158
void preRotate(Axis axis, T angle)
Left multiplies by a rotation clock-wiseabout the given axis into this matrix.
Definition: Mat4.h:844
void pivot(int i, int j, Mat3< T > &S, Vec3< T > &D, Mat3< T > &Q)
Definition: Mat3.h:716
std::shared_ptr< T > SharedPtr
Definition: Types.h:139
Definition: Exceptions.h:92
void setTranslation(const Vec3< T > &t)
Definition: Mat4.h:360
Mat4 inverse(T tolerance=0) const
Definition: Mat4.h:531
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:188
void minComponent(const Coord &other)
Perform a component-wise minimum with the other Coord.
Definition: Coord.h:202
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:365
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:204
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
Definition: Vec3.h:110