📄 decompose.c
字号:
/**** Decompose.c ****//* Ken Shoemake, 1993 */#include <math.h>#include "Decompose.h"/******* Matrix Preliminaries *******//** Fill out 3x3 matrix to 4x4 **/#define mat_pad(A) (A[W][X]=A[X][W]=A[W][Y]=A[Y][W]=A[W][Z]=A[Z][W]=0,A[W][W]=1)/** Copy nxn matrix A to C using "gets" for assignment **/#define mat_copy(C,gets,A,n) {int i,j; for(i=0;i<n;i++) for(j=0;j<n;j++)\ C[i][j] gets (A[i][j]);}/** Copy transpose of nxn matrix A to C using "gets" for assignment **/#define mat_tpose(AT,gets,A,n) {int i,j; for(i=0;i<n;i++) for(j=0;j<n;j++)\ AT[i][j] gets (A[j][i]);}/** Assign nxn matrix C the element-wise combination of A and B using "op" **/#define mat_binop(C,gets,A,op,B,n) {int i,j; for(i=0;i<n;i++) for(j=0;j<n;j++)\ C[i][j] gets (A[i][j]) op (B[i][j]);}/** Multiply the upper left 3x3 parts of A and B to get AB **/void mat_mult(HMatrix A, HMatrix B, HMatrix AB){ int i, j; for (i=0; i<3; i++) for (j=0; j<3; j++) AB[i][j] = A[i][0]*B[0][j] + A[i][1]*B[1][j] + A[i][2]*B[2][j];}/** Return dot product of length 3 vectors va and vb **/float vdot(float *va, float *vb){ return (va[0]*vb[0] + va[1]*vb[1] + va[2]*vb[2]);}/** Set v to cross product of length 3 vectors va and vb **/void vcross(float *va, float *vb, float *v){ v[0] = va[1]*vb[2] - va[2]*vb[1]; v[1] = va[2]*vb[0] - va[0]*vb[2]; v[2] = va[0]*vb[1] - va[1]*vb[0];}/** Set MadjT to transpose of inverse of M times determinant of M **/void adjoint_transpose(HMatrix M, HMatrix MadjT){ vcross(M[1], M[2], MadjT[0]); vcross(M[2], M[0], MadjT[1]); vcross(M[0], M[1], MadjT[2]);}/******* Quaternion Preliminaries *******//* Construct a (possibly non-unit) quaternion from real components. */Quat Qt_(float x, float y, float z, float w){ Quat qq; qq.x = x; qq.y = y; qq.z = z; qq.w = w; return (qq);}/* Return conjugate of quaternion. */Quat Qt_Conj(Quat q){ Quat qq; qq.x = -q.x; qq.y = -q.y; qq.z = -q.z; qq.w = q.w; return (qq);}/* Return quaternion product qL * qR. Note: order is important! * To combine rotations, use the product Mul(qSecond, qFirst), * which gives the effect of rotating by qFirst then qSecond. */Quat Qt_Mul(Quat qL, Quat qR){ Quat qq; qq.w = qL.w*qR.w - qL.x*qR.x - qL.y*qR.y - qL.z*qR.z; qq.x = qL.w*qR.x + qL.x*qR.w + qL.y*qR.z - qL.z*qR.y; qq.y = qL.w*qR.y + qL.y*qR.w + qL.z*qR.x - qL.x*qR.z; qq.z = qL.w*qR.z + qL.z*qR.w + qL.x*qR.y - qL.y*qR.x; return (qq);}/* Return product of quaternion q by scalar w. */Quat Qt_Scale(Quat q, float w){ Quat qq; qq.w = q.w*w; qq.x = q.x*w; qq.y = q.y*w; qq.z = q.z*w; return (qq);}/* Construct a unit quaternion from rotation matrix. Assumes matrix is * used to multiply column vector on the left: vnew = mat vold. Works * correctly for right-handed coordinate system and right-handed rotations. * Translation and perspective components ignored. */Quat Qt_FromMatrix(HMatrix mat){ /* 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. */ Quat qu; register double tr, s; tr = mat[X][X] + mat[Y][Y]+ mat[Z][Z]; if (tr >= 0.0) { s = sqrt(tr + mat[W][W]); qu.w = s*0.5; s = 0.5 / s; qu.x = (mat[Z][Y] - mat[Y][Z]) * s; qu.y = (mat[X][Z] - mat[Z][X]) * s; qu.z = (mat[Y][X] - mat[X][Y]) * s; } else { int h = X; if (mat[Y][Y] > mat[X][X]) h = Y; if (mat[Z][Z] > mat[h][h]) h = Z; switch (h) {#define caseMacro(i,j,k,I,J,K) \ case I:\ s = sqrt( (mat[I][I] - (mat[J][J]+mat[K][K])) + mat[W][W] );\ qu.i = s*0.5;\ s = 0.5 / s;\ qu.j = (mat[I][J] + mat[J][I]) * s;\ qu.k = (mat[K][I] + mat[I][K]) * s;\ qu.w = (mat[K][J] - mat[J][K]) * s;\ break caseMacro(x,y,z,X,Y,Z); caseMacro(y,z,x,Y,Z,X); caseMacro(z,x,y,Z,X,Y); } } if (mat[W][W] != 1.0) qu = Qt_Scale(qu, 1/sqrt(mat[W][W])); return (qu);}/******* Decomp Auxiliaries *******/static HMatrix mat_id = {{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}};/** Compute either the 1 or infinity norm of M, depending on tpose **/float mat_norm(HMatrix M, int tpose){ int i; float sum, max; max = 0.0; for (i=0; i<3; i++) { if (tpose) sum = fabs(M[0][i])+fabs(M[1][i])+fabs(M[2][i]); else sum = fabs(M[i][0])+fabs(M[i][1])+fabs(M[i][2]); if (max<sum) max = sum; } return max;}float norm_inf(HMatrix M) {return mat_norm(M, 0);}float norm_one(HMatrix M) {return mat_norm(M, 1);}/** Return index of column of M containing maximum abs entry, or -1 if M=0 **/int find_max_col(HMatrix M){ float abs, max; int i, j, col; max = 0.0; col = -1; for (i=0; i<3; i++) for (j=0; j<3; j++) { abs = M[i][j]; if (abs<0.0) abs = -abs; if (abs>max) {max = abs; col = j;} } return col;}/** Setup u for Household reflection to zero all v components but first **/void make_reflector(float *v, float *u){ float s = sqrt(vdot(v, v)); u[0] = v[0]; u[1] = v[1]; u[2] = v[2] + ((v[2]<0.0) ? -s : s); s = sqrt(2.0/vdot(u, u)); u[0] = u[0]*s; u[1] = u[1]*s; u[2] = u[2]*s;}/** Apply Householder reflection represented by u to column vectors of M **/void reflect_cols(HMatrix M, float *u){ int i, j; for (i=0; i<3; i++) { float s = u[0]*M[0][i] + u[1]*M[1][i] + u[2]*M[2][i]; for (j=0; j<3; j++) M[j][i] -= u[j]*s; }}/** Apply Householder reflection represented by u to row vectors of M **/void reflect_rows(HMatrix M, float *u){ int i, j; for (i=0; i<3; i++) { float s = vdot(u, M[i]); for (j=0; j<3; j++) M[i][j] -= u[j]*s; }}/** Find orthogonal factor Q of rank 1 (or less) M **/void do_rank1(HMatrix M, HMatrix Q){ float v1[3], v2[3], s; int col; mat_copy(Q,=,mat_id,4); /* If rank(M) is 1, we should find a non-zero column in M */ col = find_max_col(M); if (col<0) return; /* Rank is 0 */ v1[0] = M[0][col]; v1[1] = M[1][col]; v1[2] = M[2][col]; make_reflector(v1, v1); reflect_cols(M, v1); v2[0] = M[2][0]; v2[1] = M[2][1]; v2[2] = M[2][2]; make_reflector(v2, v2); reflect_rows(M, v2); s = M[2][2]; if (s<0.0) Q[2][2] = -1.0; reflect_cols(Q, v1); reflect_rows(Q, v2);}/** Find orthogonal factor Q of rank 2 (or less) M using adjoint transpose **/void do_rank2(HMatrix M, HMatrix MadjT, HMatrix Q){ float v1[3], v2[3]; float w, x, y, z, c, s, d; int col; /* If rank(M) is 2, we should find a non-zero column in MadjT */ col = find_max_col(MadjT); if (col<0) {do_rank1(M, Q); return;} /* Rank<2 */ v1[0] = MadjT[0][col]; v1[1] = MadjT[1][col]; v1[2] = MadjT[2][col]; make_reflector(v1, v1); reflect_cols(M, v1); vcross(M[0], M[1], v2); make_reflector(v2, v2); reflect_rows(M, v2); w = M[0][0]; x = M[0][1]; y = M[1][0]; z = M[1][1]; if (w*z>x*y) { c = z+w; s = y-x; d = sqrt(c*c+s*s); c = c/d; s = s/d; Q[0][0] = Q[1][1] = c; Q[0][1] = -(Q[1][0] = s); } else { c = z-w; s = y+x; d = sqrt(c*c+s*s); c = c/d; s = s/d; Q[0][0] = -(Q[1][1] = c); Q[0][1] = Q[1][0] = s; } Q[0][2] = Q[2][0] = Q[1][2] = Q[2][1] = 0.0; Q[2][2] = 1.0; reflect_cols(Q, v1); reflect_rows(Q, v2);}/******* Polar Decomposition *******//* Polar Decomposition of 3x3 matrix in 4x4, * M = QS. See Nicholas Higham and Robert S. Schreiber, * Fast Polar Decomposition of An Arbitrary Matrix, * Technical Report 88-942, October 1988, * Department of Computer Science, Cornell University. */float polar_decomp(HMatrix M, HMatrix Q, HMatrix S)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -