7 #ifndef OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
8 #define OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
19 #include <tbb/blocked_range.h>
20 #include <tbb/parallel_reduce.h>
52 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
54 resampleToMatch(
const GridType& inGrid, GridType& outGrid, Interrupter& interrupter);
77 template<
typename Sampler,
typename Gr
idType>
91 template<
typename Sampler,
typename TreeT>
92 class TileSampler:
public Sampler
95 using ValueT =
typename TreeT::ValueType;
100 TileSampler(
const CoordBBox&
b,
const ValueT& tileVal,
bool on):
101 mBBox(b.
min().asVec3d(), b.
max().asVec3d()), mVal(tileVal), mActive(on), mEmpty(false)
103 mBBox.expand(-this->radius());
104 mEmpty = mBBox.empty();
107 bool sample(
const TreeT& inTree,
const Vec3R& inCoord, ValueT&
result)
const
109 if (!mEmpty && mBBox.isInside(inCoord)) { result = mVal;
return mActive; }
116 bool mActive, mEmpty;
122 template<
typename TreeT>
123 class TileSampler<PointSampler, TreeT>:
public PointSampler {
125 TileSampler(
const CoordBBox&,
const typename TreeT::ValueType&,
bool) {}
130 template<
typename TreeT>
131 class TileSampler<StaggeredPointSampler, TreeT>:
public StaggeredPointSampler {
133 TileSampler(
const CoordBBox&,
const typename TreeT::ValueType&,
bool) {}
185 template<
typename InterrupterType>
void setInterrupter(InterrupterType&);
187 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
189 const GridT& inGrid, GridT& outGrid)
const;
192 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
193 void applyTransform(
const Transformer&,
const GridT& inGrid, GridT& outGrid)
const;
195 bool interrupt()
const {
return mInterrupt && mInterrupt(); }
198 template<
typename Sampler,
typename InTreeT,
typename OutTreeT,
typename Transformer>
199 static void transformBBox(
const Transformer&,
const CoordBBox& inBBox,
200 const InTreeT& inTree, OutTreeT& outTree,
const InterruptFunc&,
203 template<
typename Sampler,
typename TreeT,
typename Transformer>
204 class RangeProcessor;
206 bool mThreaded, mTransformTiles;
252 template<
class Sampler,
class Gr
idT>
253 void transformGrid(
const GridT& inGrid, GridT& outGrid)
const;
264 Mat4R mTransform, mPreScaleTransform, mPostScaleTransform;
271 namespace local_util {
297 const bool hasUniformScale = unsignedScale.
eq(
math::Vec3<T>(unsignedScale[0]));
299 bool hasRotation =
false;
300 bool validDecomposition =
false;
306 for (
size_t n = 0;
n < 8; ++
n) {
308 n & 0
x1 ? -unsignedScale.
x() : unsignedScale.
x(),
309 n & 0x2 ? -unsignedScale.
y() : unsignedScale.
y(),
310 n & 0x4 ? -unsignedScale.
z() : unsignedScale.
z());
313 const math::Mat3<T> mat = xform * math::scale<math::Mat3<T> >(signedScale).inverse();
314 if (mat.det() <
T(0.0))
continue;
319 math::rotation<math::Mat3<T> >(
math::Vec3<T>(0, 0, 1), tmpAngle.
z()) *
324 if (xform.
eq(rebuild)) {
329 if (!(minAngle < maxAngle)) {
336 validDecomposition =
true;
338 if (hasUniformScale || !hasRotation) {
346 if (!validDecomposition) {
350 if (hasRotation && !hasUniformScale) {
396 mIsAffine(mAXform.isLinear() && mBXform.isLinear()),
397 mIsIdentity(mIsAffine && mAXform == mBXform)
419 const bool mIsAffine;
420 const bool mIsIdentity;
430 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
434 ABTransform xform(inGrid.transform(), outGrid.transform());
439 outGrid.setTree(inGrid.tree().copy());
440 }
else if (xform.isAffine()) {
444 Mat4R mat = xform.getA().baseMap()->getAffineMap()->getMat4() *
445 ( xform.getB().baseMap()->getAffineMap()->getMat4().inverse() );
463 template<
typename ValueType>
465 static ValueType
eval(
const ValueType& background,
const Vec3d& voxelSize)
468 ValueType
result(background * (1.0 / voxelSize[0]));
483 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
490 if (inGrid.constTransform() == outGrid.constTransform()) {
493 outGrid.setTree(inGrid.tree().copy());
499 using ValueT =
typename GridType::ValueType;
502 const ValueT halfWidth = outIsLevelSet
506 typename GridType::Ptr tempGrid;
508 tempGrid = doLevelSetRebuild(inGrid, zeroVal<ValueT>(),
509 halfWidth, halfWidth,
510 &outGrid.constTransform(), &interrupter);
511 }
catch (TypeError&) {
518 outGrid.setTree(tempGrid->treePtr());
524 doResampleToMatch<Sampler>(inGrid, outGrid, interrupter);
528 template<
typename Sampler,
typename Gr
idType>
533 resampleToMatch<Sampler>(inGrid, outGrid, interrupter);
545 mPreScaleTransform(
Mat4R::identity()),
546 mPostScaleTransform(
Mat4R::identity())
552 init(mPivot, scale, rotate, translate,
"rst",
"zyx");
564 mPreScaleTransform(
Mat4R::identity()),
565 mPostScaleTransform(
Mat4R::identity())
567 init(pivot, scale, rotate, translate, xformOrder, rotOrder);
575 GridTransformer::init(
580 if (xformOrder.size() != 3) {
581 OPENVDB_THROW(ValueError,
"invalid transform order (" + xformOrder +
")");
583 if (rotOrder.size() != 3) {
584 OPENVDB_THROW(ValueError,
"invalid rotation order (" + rotOrder +
")");
593 for (
int i = 0; i < 3; ++i) {
594 double s = std::fabs(
scale(i));
597 scaleRemainder(i) =
scale(i) * (1 << mMipLevels(i));
606 mTransform = mPreScaleTransform = mPostScaleTransform =
Mat4R::identity();
608 int rpos, spos, tpos;
609 rpos = spos = tpos = 3;
610 for (
int ix = 2; ix >= 0; --ix) {
611 switch (xformOrder[ix]) {
616 remainder->preTranslate(pivot);
618 int xpos, ypos, zpos;
619 xpos = ypos = zpos = 3;
620 for (
int ir = 2; ir >= 0; --ir) {
621 switch (rotOrder[ir]) {
641 if (xpos > 2 || ypos > 2 || zpos > 2) {
642 OPENVDB_THROW(ValueError,
"invalid rotation order (" + rotOrder +
")");
646 remainder->preTranslate(-pivot);
655 remainder->preTranslate(pivot);
656 remainder->preScale(scaleRemainder);
657 remainder->preTranslate(-pivot);
658 remainder = &mPreScaleTransform;
664 remainder->preTranslate(translate);
670 if (tpos > 2 || rpos > 2 || spos > 2) {
671 OPENVDB_THROW(ValueError,
"invalid transform order (" + xformOrder +
")");
679 template<
typename InterrupterType>
688 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
691 const GridT& inGrid, GridT& outGrid)
const
694 applyTransform<Sampler>(xform, inGrid, outGrid);
698 template<
class Sampler,
class Gr
idT>
707 applyTransform<Sampler>(xform, inGrid, outGrid);
710 bool firstPass =
true;
711 const typename GridT::ValueType background = inGrid.background();
712 typename GridT::Ptr tempGrid = GridT::create(background);
719 applyTransform<Sampler>(xform, inGrid, *tempGrid);
729 count.x() ? .5 : 1, count.y() ? .5 : 1, count.z() ? .5 : 1));
736 applyTransform<Sampler>(xform, inGrid, *tempGrid);
740 typename GridT::Ptr destGrid = GridT::create(background);
741 applyTransform<Sampler>(xform, *tempGrid, *destGrid);
742 tempGrid.swap(destGrid);
751 applyTransform<Sampler>(xform, *tempGrid, outGrid);
753 outGrid.setTree(tempGrid->treePtr());
762 template<
class Sampler,
class TreeT,
typename Transformer>
763 class GridResampler::RangeProcessor
766 using LeafIterT =
typename TreeT::LeafCIter;
767 using TileIterT =
typename TreeT::ValueAllCIter;
773 RangeProcessor(
const Transformer& xform,
const CoordBBox& b,
const TreeT& inT, TreeT& outT):
774 mIsRoot(true), mXform(xform), mBBox(b),
775 mInTree(inT), mOutTree(&outT), mInAcc(mInTree), mOutAcc(*mOutTree)
778 RangeProcessor(
const Transformer& xform,
const CoordBBox& b,
const TreeT& inTree):
779 mIsRoot(false), mXform(xform), mBBox(b),
780 mInTree(inTree), mOutTree(new TreeT(inTree.background())),
781 mInAcc(mInTree), mOutAcc(*mOutTree)
784 ~RangeProcessor() {
if (!mIsRoot)
delete mOutTree; }
787 RangeProcessor(RangeProcessor& other,
tbb::split):
789 mXform(other.mXform),
791 mInTree(other.mInTree),
792 mOutTree(new TreeT(mInTree.background())),
795 mInterrupt(other.mInterrupt)
801 void operator()(LeafRange&
r)
805 LeafIterT i = r.iterator();
806 CoordBBox bbox(i->origin(), i->origin() + Coord(i->dim()));
807 if (!mBBox.empty()) {
814 transformBBox<Sampler>(mXform, bbox, mInAcc, mOutAcc, mInterrupt);
820 void operator()(TileRange& r)
825 TileIterT i = r.iterator();
827 if (!i.isTileValue())
continue;
831 i.getBoundingBox(bbox);
832 if (!mBBox.empty()) {
843 internal::TileSampler<Sampler, InTreeAccessor>
844 sampler(bbox, i.getValue(), i.isValueOn());
845 transformBBox(mXform, bbox, mInAcc, mOutAcc, mInterrupt,
sampler);
851 void join(RangeProcessor& other)
853 if (!
interrupt()) mOutTree->merge(*other.mOutTree);
857 bool interrupt()
const {
return mInterrupt && mInterrupt(); }
862 const TreeT& mInTree;
864 InTreeAccessor mInAcc;
865 OutTreeAccessor mOutAcc;
873 template<
class Sampler,
class Gr
idT,
typename Transformer>
876 const GridT& inGrid, GridT& outGrid)
const
878 using TreeT =
typename GridT::TreeType;
879 const TreeT& inTree = inGrid.tree();
880 TreeT& outTree = outGrid.tree();
882 using RangeProc = RangeProcessor<Sampler, TreeT, Transformer>;
884 const GridClass gridClass = inGrid.getGridClass();
891 RangeProc proc(xform, CoordBBox(), inTree, outTree);
892 proc.setInterrupt(mInterrupt);
894 typename RangeProc::TileIterT tileIter = inTree.cbeginValueAll();
895 tileIter.setMaxDepth(tileIter.getLeafDepth() - 1);
896 typename RangeProc::TileRange tileRange(tileIter);
899 tbb::parallel_reduce(tileRange, proc);
909 clipBBox = inGrid.evalActiveVoxelBoundingBox();
914 RangeProc proc(xform, clipBBox, inTree, outTree);
915 proc.setInterrupt(mInterrupt);
917 typename RangeProc::LeafRange leafRange(inTree.cbeginLeaf());
920 tbb::parallel_reduce(leafRange, proc);
937 template<
class Sampler,
class InTreeT,
class OutTreeT,
class Transformer>
939 GridResampler::transformBBox(
940 const Transformer& xform,
941 const CoordBBox& bbox,
942 const InTreeT& inTree,
944 const InterruptFunc& interrupt,
947 using ValueT =
typename OutTreeT::ValueType;
952 inRMin(bbox.min().x(), bbox.min().y(), bbox.min().z()),
953 inRMax(bbox.max().x()+1, bbox.max().y()+1, bbox.max().z()+1),
956 for (
int i = 0; i < 8; ++i) {
958 i & 1 ? inRMax.x() : inRMin.x(),
959 i & 2 ? inRMax.y() : inRMin.y(),
960 i & 4 ? inRMax.z() : inRMin.z());
968 if (!xform.isAffine()) {
973 int &
x = outXYZ.
x(), &
y = outXYZ.y(), &
z = outXYZ.z();
974 for (x = outMin.x(); x <= outMax.x(); ++
x) {
977 for (
y = outMin.y();
y <= outMax.y(); ++
y) {
980 for (
z = outMin.z();
z <= outMax.z(); ++
z) {
982 inXYZ = xform.invTransform(xyz);
984 if (sampler.
sample(inTree, inXYZ, result)) {
985 outTree.setValueOn(outXYZ, result);
988 if (!outTree.isValueOn(outXYZ)) {
989 outTree.setValueOff(outXYZ, result);
999 translation = xform.invTransform(
Vec3R(0, 0, 0)),
1000 deltaX = xform.invTransform(
Vec3R(1, 0, 0)) - translation,
1001 deltaY = xform.invTransform(
Vec3R(0, 1, 0)) - translation,
1002 deltaZ = xform.invTransform(
Vec3R(0, 0, 1)) - translation;
1008 const Vec3R dummy = deltaX;
1013 Vec3R inStartX = xform.invTransform(
Vec3R(outMin));
1015 int &x = outXYZ.
x(), &
y = outXYZ.y(), &
z = outXYZ.z();
1016 for (x = outMin.x(); x <= outMax.x(); ++
x, inStartX += deltaX) {
1018 Vec3R inStartY = inStartX;
1019 for (
y = outMin.y();
y <= outMax.y(); ++
y, inStartY += deltaY) {
1021 Vec3R inXYZ = inStartY;
1022 for (
z = outMin.z();
z <= outMax.z(); ++
z, inXYZ += deltaZ) {
1024 if (sampler.
sample(inTree, inXYZ, result)) {
1025 outTree.setValueOn(outXYZ, result);
1028 if (!outTree.isValueOn(outXYZ)) {
1029 outTree.setValueOff(outXYZ, result);
1042 #endif // OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
Vec2< T > minComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise minimum of the two vectors.
GLboolean GLboolean GLboolean b
GLenum GLenum GLenum GLenum GLenum scale
Vec3< T0 > transformH(const Vec3< T0 > &p) const
Transform a Vec3 by post-multiplication, doing homogenous divison.
Mat3< T > getMat3() const
#define OPENVDB_USE_VERSION_NAMESPACE
Dummy NOOP interrupter class defining interface.
void setTranslation(const Vec3< T > &t)
void preRotate(Axis axis, T angle)
Left multiplies by a rotation clock-wiseabout the given axis into this matrix.
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.
std::shared_ptr< T > SharedPtr
void OIIO_API split(string_view str, std::vector< string_view > &result, string_view sep=string_view(), int maxsplit=-1)
bool isApproxEqual(const Type &a, const Type &b, const Type &tolerance)
Return true if a is equal to b to within the given tolerance.
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
IMATH_INTERNAL_NAMESPACE_HEADER_ENTER T abs(T a)
GLuint GLfloat GLfloat GLfloat x1
void preScale(const Vec3< T0 > &v)
Vec3< T > getTranslation() const
Return the translation component.
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Efficient multi-threaded replacement of the background values in tree.
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.
GLsizei const GLchar *const * string
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
Defined various multi-threaded utility functions for trees.
GLdouble GLdouble GLdouble z
void preTranslate(const Vec3< T0 > &tr)
Left multiples by the specified translation, i.e. Trans * (*this)
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
class OCIOEXPORT MatrixTransform
ImageBuf OIIO_API rotate(const ImageBuf &src, float angle, string_view filtername=string_view(), float filterwidth=0.0f, bool recompute_roi=false, ROI roi={}, int nthreads=0)
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
GLuint GLsizei GLsizei * length
MatType scale(const Vec3< typename MatType::value_type > &s)
Return a matrix that scales by s.
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.
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.
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
math::BBox< Vec3d > BBoxd
Vec2< T > maxComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise maximum of the two vectors.
static const Mat4< Real > & identity()
Predefined constant for identity matrix.
GA_API const UT_StringHolder pivot
INT64 INT64 INT64 remainder
PUGI__FN char_t * translate(char_t *buffer, const char_t *from, const char_t *to, size_t to_length)
bool wasInterrupted(T *i, int percent=-1)
ImageBuf OIIO_API zero(ROI roi, int nthreads=0)
bool isAffine(const Mat4< T > &m)
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Mat4 inverse(T tolerance=0) const
#define OPENVDB_THROW(exception, message)
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.