Xform.h
上传用户:kellyonhid
上传日期:2013-10-12
资源大小:932k
文件大小:37k
- ////////////////////////////////////////////////////////////
- // Xform.h
- //
- // A class for doing 3D transformations using 4x4 matrices
- ////////////////////////////////////////////////////////////
- #ifndef _xform_h_
- #define _xform_h_
- #include <assert.h>
- #include <math.h>
- #include <float.h>
- #include <iostream.h>
- #include <iomanip.h>
- #include <algo.h>
- #include "Pnt3.h"
- #ifdef __GNUC__
- // G++ implements the standard for templated friend functions of template
- // classes. This means that the following forward declarations are necessary..
- template <class T>
- class Xform;
- template <class T>
- Xform<T> operator*(const Xform<T> &a, const Xform<T> &b);
- template <class T>
- Xform<T> delta(Xform<T> a, const Xform<T> &b);
- template <class T>
- Xform<T> linear_interp(const Xform<T> &a,
- const Xform<T> &b,
- double t);
- template <class T>
- Xform<T> bilinear_interp(const Xform<T> &u0v0,
- const Xform<T> &u1v0,
- const Xform<T> &u0v1,
- const Xform<T> &u1v1,
- double u, double v);
- template <class T>
- Xform<T> relative_xform(const Xform<T> &a, Xform<T> b);
- template <class T>
- ostream& operator<<(ostream &out, const Xform<T> &xf);
- template <class T>
- istream& operator>>(istream & in, Xform<T> &xf);
- #endif
- // logically Xform is applied to a point: p' = M*p
- // however, the transpose of the M is stored
- // to keep it compatible with OpenGL
- template <class T> // use only with float or double
- class Xform {
- private:
- T m[4][4]; // column major order
- public:
- Xform(void);
- Xform(const double *a); // from OpenGL matrix
- Xform(const float *a); // from OpenGL matrix
- Xform(const T r[3][3], const T t[3]);
- Xform<T> &operator=(const double *a);
- Xform<T> &operator=(const float *a);
- Xform<T> &operator=(const Xform<T> &xf);
- Xform<T> &fromQuaternion(const double q[4], // q == {w,x,y,z}
- double tx = 0.0,
- double ty = 0.0,
- double tz = 0.0);
- Xform<T> &fromQuaternion(const float q[4], // q == {w,x,y,z}
- float tx = 0.0,
- float ty = 0.0,
- float tz = 0.0);
- void toQuaternion(double q[4]) const;
- void toQuaternion(float q[4]) const;
- Xform<T> &addQuaternion(T q0, T q1, T q2, T q3,
- T tx = 0.0, T ty = 0.0, T tz = 0.0);
- Xform<T> &addQuaternion(const float *q, int n = 4); // n == 4,7
- Xform<T> &addQuaternion(const double *q, int n = 4); // n == 4,7
- void fromEuler(const T ea[3], int order);
- void toEuler(T ea[3], int order);
- Xform<T> &fromFrame(const Pnt3 &x,
- const Pnt3 &y,
- const Pnt3 &z,
- const Pnt3 &org);
- Xform<T> &fromRotTrans(const T r[3][3], const T t[3]);
- bool isIdentity (void) const;
- Xform<T> &identity(void); // set to identity
- Xform<T> &fast_invert(void); // assume rot + trans
- Xform<T> &invert(void); // general inversion
- void translate(const double t[3]); // M <- T*M
- void translate(const float t[3]); // M <- T*M
- void translate(T x, T y, T z); // M <- T*M
- void getTranslation(double t[3]) const;
- void getTranslation(float t[3]) const;
- void removeTranslation(void);
- void removeTranslation(double t[3]);
- void removeTranslation(float t[3]);
- void scale(const double t[3]); // M <- S*M
- void scale(const float t[3]); // M <- S*M
- void scale(T x, T y, T z); // M <- S*M
- void get_e(int i, T e[3]) const; // get a basis vector, i=0,1,2
- Xform<T> &rotX(T a); // M <- R*M
- Xform<T> &rotY(T a); // M <- R*M
- Xform<T> &rotZ(T a); // M <- R*M
- Xform<T> &rot(T angle, T ax, T ay, T az); // M <- R*M
- Xform<T> &rot(T angle, T ax, T ay, T az,
- T ox, T oy, T oz); // M <- R*M
- Xform<T> &rotQ(T q0, T q1, T q2, T q3); // M <- R*M
- void get_rot(T &angle, T &ax, T &ay, T &az);
- void apply(const double i[3], double o[3]) const; // o = M*i
- void apply(const float i[3], float o[3]) const; // o = M*i
- void apply_inv(const double i[3], double o[3]) const; // o = M^-1*i
- void apply_inv(const float i[3], float o[3]) const; // o = M^-1*i
- void operator()(double i[3]) const; // i <- M*i
- void operator()(float i[3]) const; // i <- M*i
- // apply to normal vector (no translation, only rotation)
- void apply_nrm(const double i[3], double o[3]) const; // o = M*i
- void apply_nrm(const float i[3], float o[3]) const; // o = M*i
- T& operator()(int i, int j); // indexed access
- T operator()(int i, int j) const; // indexed access
- operator const T *(void) const { return m[0]; } // array access
- operator T *(void) { return m[0]; }
- Pnt3 unproject(float u, float v, float z) const; // all input [-1,1]
- Pnt3 unproject_fast(float u, float v, float z) const;
- Xform<T> &operator*=(const Xform<T> &a); // (*this) = a * (*this)
- // test how close to a rigid transformation the current
- // transformation is, ideally returns 0
- float test_rigidity(void);
- // enforce the rigidity of the xform by setting the projective
- // part to 0 0 0 1 and making sure rotation part is just a rotation
- Xform<T> &enforce_rigidity(void);
- #ifndef __GNUC__
- friend Xform<T> operator*(const Xform<T> &a, // a*b
- const Xform<T> &b);
- friend Xform<T> delta(Xform<T> a, // d * a = b
- const Xform<T> &b);
- friend Xform<T> linear_interp(const Xform<T> &a, // r=t*a+(1-t)*b
- const Xform<T> &b,
- double t);
- friend Xform<T> bilinear_interp(const Xform<T> &u0v0,
- const Xform<T> &u1v0,
- const Xform<T> &u0v1,
- const Xform<T> &u1v1,
- double u, double v);
- friend Xform<T> relative_xform(const Xform<T> &a,
- Xform<T> b); // c = b^-1 * a
- friend ostream& operator<<(ostream &out, const Xform<T> &xf);
- friend istream& operator>>(istream & in, Xform<T> &xf);
- #else
- friend Xform<T> operator*<>(const Xform<T> &a, // a*b
- const Xform<T> &b);
- friend Xform<T> delta<>(Xform<T> a, // d * a = b
- const Xform<T> &b);
- friend Xform<T> linear_interp<>(const Xform<T> &a, // r=t*a+(1-t)*b
- const Xform<T> &b,
- double t);
- friend Xform<T> bilinear_interp<>(const Xform<T> &u0v0,
- const Xform<T> &u1v0,
- const Xform<T> &u0v1,
- const Xform<T> &u1v1,
- double u, double v);
- friend Xform<T> relative_xform<>(const Xform<T> &a,
- Xform<T> b); // c = b^-1 * a
- friend ostream& operator<< <> (ostream &out, const Xform<T> &xf);
- friend istream& operator>> <> (istream & in, Xform<T> &xf);
- #endif
- };
- template <class T> inline
- Xform<T>::Xform(void)
- {
- m[1][0] = m[2][0] = m[3][0] = m[0][1] = m[2][1] = m[3][1] = 0.0;
- m[0][2] = m[1][2] = m[3][2] = m[0][3] = m[1][3] = m[2][3] = 0.0;
- m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0;
- }
- template <class T> inline
- Xform<T>::Xform(const double *a)
- {
- m[0][0] = a[0]; m[0][1] = a[1]; m[0][2] = a[2]; m[0][3] = a[3];
- m[1][0] = a[4]; m[1][1] = a[5]; m[1][2] = a[6]; m[1][3] = a[7];
- m[2][0] = a[8]; m[2][1] = a[9]; m[2][2] = a[10];m[2][3] = a[11];
- m[3][0] = a[12];m[3][1] = a[13];m[3][2] = a[14];m[3][3] = a[15];
- }
- template <class T> inline
- Xform<T>::Xform(const float *a)
- {
- m[0][0] = a[0]; m[0][1] = a[1]; m[0][2] = a[2]; m[0][3] = a[3];
- m[1][0] = a[4]; m[1][1] = a[5]; m[1][2] = a[6]; m[1][3] = a[7];
- m[2][0] = a[8]; m[2][1] = a[9]; m[2][2] = a[10];m[2][3] = a[11];
- m[3][0] = a[12];m[3][1] = a[13];m[3][2] = a[14];m[3][3] = a[15];
- }
- template <class T> inline
- Xform<T>::Xform(const T r[3][3], const T t[3])
- {
- m[0][0] = r[0][0]; m[0][1]=r[1][0]; m[0][2]=r[2][0]; m[0][3]=0.0;
- m[1][0] = r[0][1]; m[1][1]=r[1][1]; m[1][2]=r[2][1]; m[1][3]=0.0;
- m[2][0] = r[0][2]; m[2][1]=r[1][2]; m[2][2]=r[2][2]; m[2][3]=0.0;
- m[3][0] = t[0]; m[3][1] = t[1]; m[3][2] = t[2]; m[3][3] = 1.0;
- }
- template <class T> inline Xform<T> &
- Xform<T>::operator=(const double *a)
- {
- m[0][0] = a[0]; m[0][1] = a[1]; m[0][2] = a[2]; m[0][3] = a[3];
- m[1][0] = a[4]; m[1][1] = a[5]; m[1][2] = a[6]; m[1][3] = a[7];
- m[2][0] = a[8]; m[2][1] = a[9]; m[2][2] = a[10];m[2][3] = a[11];
- m[3][0] = a[12];m[3][1] = a[13];m[3][2] = a[14];m[3][3] = a[15];
- return *this;
- }
- template <class T> inline Xform<T> &
- Xform<T>::operator=(const float *a)
- {
- m[0][0] = a[0]; m[0][1] = a[1]; m[0][2] = a[2]; m[0][3] = a[3];
- m[1][0] = a[4]; m[1][1] = a[5]; m[1][2] = a[6]; m[1][3] = a[7];
- m[2][0] = a[8]; m[2][1] = a[9]; m[2][2] = a[10];m[2][3] = a[11];
- m[3][0] = a[12];m[3][1] = a[13];m[3][2] = a[14];m[3][3] = a[15];
- return *this;
- }
- template <class T> inline Xform<T> &
- Xform<T>::operator=(const Xform<T> &xf)
- {
- return operator=((const T *) xf);
- }
- // see Graphics Gems III p. 465
- // note quaternion order: w,x,y,z
- template <class T> inline Xform<T> &
- Xform<T>::fromQuaternion(const double q[4],
- double tx, double ty, double tz)
- {
- // q doesn't have to be unit
- T norm2 = q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3];
- T s = (norm2 > 0.0) ? 2.0/norm2 : 0.0;
- T xs = q[1]*s, ys = q[2]*s, zs = q[3]*s;
- T wx = q[0]*xs, wy = q[0]*ys, wz = q[0]*zs;
- T xx = q[1]*xs, xy = q[1]*ys, xz = q[1]*zs;
- T yy = q[2]*ys, yz = q[2]*zs, zz = q[3]*zs;
-
- m[0][0] = 1.0 - (yy+zz); m[0][1] = xy + wz; m[0][2] = xz - wy;
- m[1][0] = xy - wz; m[1][1] = 1.0 - (xx+zz); m[1][2] = yz + wx;
- m[2][0] = xz + wy; m[2][1] = yz - wx; m[2][2] = 1.0 - (xx+yy);
-
- m[3][0] = tx; m[3][1] = ty; m[3][2] = tz;
- m[0][3] = m[1][3] = m[2][3] = 0.0;
- m[3][3] = 1.0;
- return *this;
- }
- template <class T> inline Xform<T> &
- Xform<T>::fromQuaternion(const float q[4],
- float tx, float ty, float tz)
- {
- // q doesn't have to be unit
- T norm2 = q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3];
- T s = (norm2 > 0.0) ? 2.0/norm2 : 0.0;
- T xs = q[1]*s, ys = q[2]*s, zs = q[3]*s;
- T wx = q[0]*xs, wy = q[0]*ys, wz = q[0]*zs;
- T xx = q[1]*xs, xy = q[1]*ys, xz = q[1]*zs;
- T yy = q[2]*ys, yz = q[2]*zs, zz = q[3]*zs;
-
- m[0][0] = 1.0 - (yy+zz); m[0][1] = xy + wz; m[0][2] = xz - wy;
- m[1][0] = xy - wz; m[1][1] = 1.0 - (xx+zz); m[1][2] = yz + wx;
- m[2][0] = xz + wy; m[2][1] = yz - wx; m[2][2] = 1.0 - (xx+yy);
- m[3][0] = tx; m[3][1] = ty; m[3][2] = tz;
- m[0][3] = m[1][3] = m[2][3] = 0.0;
- m[3][3] = 1.0;
- return *this;
- }
- // From Graphics Gems IV p. 213
- // note transposed matrix and quaternion order w,x,y,z
- // see also Graphics Gems II pp. 351 - 354
- // Ignore translation and projective parts.
- // This algorithm avoids near-zero divides by looking for a
- // large component - first w, then x, y, or z.
- // When the trace is greater than zero, |w| is greater than 1/2,
- // which is as small as a largest component can be.
- // Otherwise, the largest diagonal entry corresponds to the
- // largest of |x|, |y|, or |z|, one of which must be larger
- // than |w|, and at least 1/2.
- template <class T> inline void
- Xform<T>::toQuaternion(double q[4]) const
- {
- T tr = m[0][0] + m[1][1]+ m[2][2];
- if (tr >= 0.0) {
- T s = sqrt(tr + m[3][3]);
- q[0] = s*0.5;
- s = 0.5 / s;
- q[1] = (m[1][2] - m[2][1]) * s;
- q[2] = (m[2][0] - m[0][2]) * s;
- q[3] = (m[0][1] - m[1][0]) * s;
- } else {
- int i = 0;
- if (m[1][1] > m[0][0]) i = 1;
- if (m[2][2] > m[i][i]) i = 2;
- int j = (i+1)%3;
- int k = (j+1)%3;
- T s = sqrt(m[3][3] + (m[i][i] - (m[j][j] + m[k][k])));
- q[i+1] = s * 0.5;
- s = 0.5 / s;
- q[j+1] = (m[i][j] + m[j][i]) * s;
- q[k+1] = (m[i][k] + m[k][i]) * s;
- q[0] = (m[j][k] - m[k][j]) * s;
- }
- if (m[3][3] != 1.0) {
- T tmp = 1.0/sqrt(m[3][3]);
- q[0]*=tmp; q[1]*=tmp; q[2]*=tmp; q[3]*=tmp;
- }
- }
- template <class T> inline void
- Xform<T>::toQuaternion(float q[4]) const
- {
- T tr = m[0][0] + m[1][1]+ m[2][2];
- if (tr >= 0.0) {
- T s = sqrt(tr + m[3][3]);
- q[0] = s*0.5;
- s = 0.5 / s;
- q[1] = (m[1][2] - m[2][1]) * s;
- q[2] = (m[2][0] - m[0][2]) * s;
- q[3] = (m[0][1] - m[1][0]) * s;
- } else {
- int i = 0;
- if (m[1][1] > m[0][0]) i = 1;
- if (m[2][2] > m[i][i]) i = 2;
- int j = (i+1)%3;
- int k = (j+1)%3;
- T s = sqrt(m[3][3] + (m[i][i] - (m[j][j] + m[k][k])));
- q[i+1] = s * 0.5;
- s = 0.5 / s;
- q[j+1] = (m[i][j] + m[j][i]) * s;
- q[k+1] = (m[i][k] + m[k][i]) * s;
- q[0] = (m[j][k] - m[k][j]) * s;
- }
- if (m[3][3] != 1.0) {
- T tmp = 1.0/sqrt(m[3][3]);
- q[0]*=tmp; q[1]*=tmp; q[2]*=tmp; q[3]*=tmp;
- }
- }
- template <class T> inline Xform<T> &
- Xform<T>::addQuaternion(T q0, T q1, T q2, T q3, T tx, T ty, T tz)
- {
- rotQ(q0,q1,q2,q3);
- translate(tx,ty,tz);
- return *this;
- }
- template <class T> inline Xform<T> &
- Xform<T>::addQuaternion(const float *q, int n)
- {
- rotQ(q[0],q[1],q[2],q[3]);
- if (n == 7)
- translate(q[4],q[5],q[6]);
- return *this;
- }
- template <class T> inline Xform<T> &
- Xform<T>::addQuaternion(const double *q, int n)
- {
- rotQ(q[0],q[1],q[2],q[3]);
- if (n == 7)
- translate(q[4],q[5],q[6]);
- return *this;
- }
- //
- // Euler angle stuff from Graphics Gems IV pp. 222-229
- //
- /*** Order type constants, constructors, extractors ***/
- /* There are 24 possible conventions, designated by: */
- /* o EulAxI = axis used initially */
- /* o EulPar = parity of axis permutation */
- /* o EulRep = repetition of initial axis as last */
- /* o EulFrm = frame from which axes are taken */
- /* Axes I,J,K will be a permutation of X,Y,Z. */
- /* Axis H will be either I or K, depending on EulRep. */
- /* Frame S takes axes from initial static frame. */
- /* If ord = (AxI=X, Par=Even, Rep=No, Frm=S), then */
- /* {a,b,c,ord} means Rz(c)Ry(b)Rx(a), where Rz(c)v */
- /* rotates v around Z by c radians. */
- #define EulFrmS 0
- #define EulFrmR 1
- #define EulFrm(ord) ((unsigned)(ord)&1)
- #define EulRepNo 0
- #define EulRepYes 1
- #define EulRep(ord) (((unsigned)(ord)>>1)&1)
- #define EulParEven 0
- #define EulParOdd 1
- #define EulPar(ord) (((unsigned)(ord)>>2)&1)
- #define EulSafe "