Blender V2.61 - r43446

math_rotation.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  
00021  * The Original Code is: some of this file.
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  * */
00025 
00032 #include <assert.h>
00033 #include "BLI_math.h"
00034 
00035 /******************************** Quaternions ********************************/
00036 
00037 /* used to test is a quat is not normalized */
00038 #define QUAT_EPSILON 0.0001
00039 
00040 /* convenience, avoids setting Y axis everywhere */
00041 void unit_axis_angle(float axis[3], float *angle)
00042 {
00043     axis[0]= 0.0f;
00044     axis[1]= 1.0f;
00045     axis[2]= 0.0f;
00046     *angle= 0.0f;
00047 }
00048 
00049 
00050 void unit_qt(float q[4])
00051 {
00052     q[0]= 1.0f;
00053     q[1]= q[2]= q[3]= 0.0f;
00054 }
00055 
00056 void copy_qt_qt(float q1[4], const float q2[4])
00057 {
00058     q1[0]= q2[0];
00059     q1[1]= q2[1];
00060     q1[2]= q2[2];
00061     q1[3]= q2[3];
00062 }
00063 
00064 int is_zero_qt(float *q)
00065 {
00066     return (q[0] == 0 && q[1] == 0 && q[2] == 0 && q[3] == 0);
00067 }
00068 
00069 void mul_qt_qtqt(float *q, const float *q1, const float *q2)
00070 {
00071     float t0,t1,t2;
00072 
00073     t0=   q1[0]*q2[0]-q1[1]*q2[1]-q1[2]*q2[2]-q1[3]*q2[3];
00074     t1=   q1[0]*q2[1]+q1[1]*q2[0]+q1[2]*q2[3]-q1[3]*q2[2];
00075     t2=   q1[0]*q2[2]+q1[2]*q2[0]+q1[3]*q2[1]-q1[1]*q2[3];
00076     q[3]= q1[0]*q2[3]+q1[3]*q2[0]+q1[1]*q2[2]-q1[2]*q2[1];
00077     q[0]=t0; 
00078     q[1]=t1; 
00079     q[2]=t2;
00080 }
00081 
00082 /* Assumes a unit quaternion */
00083 void mul_qt_v3(const float *q, float *v)
00084 {
00085     float t0, t1, t2;
00086 
00087     t0=  -q[1]*v[0]-q[2]*v[1]-q[3]*v[2];
00088     t1=   q[0]*v[0]+q[2]*v[2]-q[3]*v[1];
00089     t2=   q[0]*v[1]+q[3]*v[0]-q[1]*v[2];
00090     v[2]= q[0]*v[2]+q[1]*v[1]-q[2]*v[0];
00091     v[0]=t1; 
00092     v[1]=t2;
00093 
00094     t1=   t0*-q[1]+v[0]*q[0]-v[1]*q[3]+v[2]*q[2];
00095     t2=   t0*-q[2]+v[1]*q[0]-v[2]*q[1]+v[0]*q[3];
00096     v[2]= t0*-q[3]+v[2]*q[0]-v[0]*q[2]+v[1]*q[1];
00097     v[0]=t1; 
00098     v[1]=t2;
00099 }
00100 
00101 void conjugate_qt(float *q)
00102 {
00103     q[1] = -q[1];
00104     q[2] = -q[2];
00105     q[3] = -q[3];
00106 }
00107 
00108 float dot_qtqt(const float q1[4], const float q2[4])
00109 {
00110     return q1[0]*q2[0] + q1[1]*q2[1] + q1[2]*q2[2] + q1[3]*q2[3];
00111 }
00112 
00113 void invert_qt(float *q)
00114 {
00115     float f = dot_qtqt(q, q);
00116 
00117     if (f == 0.0f)
00118         return;
00119 
00120     conjugate_qt(q);
00121     mul_qt_fl(q, 1.0f/f);
00122 }
00123 
00124 void invert_qt_qt(float *q1, const float *q2)
00125 {
00126     copy_qt_qt(q1, q2);
00127     invert_qt(q1);
00128 }
00129 
00130 /* simple mult */
00131 void mul_qt_fl(float *q, const float f)
00132 {
00133     q[0] *= f;
00134     q[1] *= f;
00135     q[2] *= f;
00136     q[3] *= f;
00137 }
00138 
00139 void sub_qt_qtqt(float q[4], const float q1[4], const float q2[4])
00140 {
00141     float nq2[4];
00142 
00143     nq2[0]= -q2[0];
00144     nq2[1]=  q2[1];
00145     nq2[2]=  q2[2];
00146     nq2[3]=  q2[3];
00147 
00148     mul_qt_qtqt(q, q1, nq2);
00149 }
00150 
00151 /* angular mult factor */
00152 void mul_fac_qt_fl(float *q, const float fac)
00153 {
00154     float angle= fac*saacos(q[0]);  /* quat[0]= cos(0.5*angle), but now the 0.5 and 2.0 rule out */
00155     
00156     float co= (float)cos(angle);
00157     float si= (float)sin(angle);
00158     q[0]= co;
00159     normalize_v3(q+1);
00160     mul_v3_fl(q+1, si);
00161 }
00162 
00163 /* skip error check, currently only needed by mat3_to_quat_is_ok */
00164 static void quat_to_mat3_no_error(float m[][3], const float q[4])
00165 {
00166     double q0, q1, q2, q3, qda,qdb,qdc,qaa,qab,qac,qbb,qbc,qcc;
00167 
00168     q0= M_SQRT2 * (double)q[0];
00169     q1= M_SQRT2 * (double)q[1];
00170     q2= M_SQRT2 * (double)q[2];
00171     q3= M_SQRT2 * (double)q[3];
00172 
00173     qda= q0*q1;
00174     qdb= q0*q2;
00175     qdc= q0*q3;
00176     qaa= q1*q1;
00177     qab= q1*q2;
00178     qac= q1*q3;
00179     qbb= q2*q2;
00180     qbc= q2*q3;
00181     qcc= q3*q3;
00182 
00183     m[0][0]= (float)(1.0-qbb-qcc);
00184     m[0][1]= (float)(qdc+qab);
00185     m[0][2]= (float)(-qdb+qac);
00186 
00187     m[1][0]= (float)(-qdc+qab);
00188     m[1][1]= (float)(1.0-qaa-qcc);
00189     m[1][2]= (float)(qda+qbc);
00190 
00191     m[2][0]= (float)(qdb+qac);
00192     m[2][1]= (float)(-qda+qbc);
00193     m[2][2]= (float)(1.0-qaa-qbb);
00194 }
00195 
00196 
00197 void quat_to_mat3(float m[][3], const float q[4])
00198 {
00199 #ifdef DEBUG
00200     float f;
00201     if(!((f=dot_qtqt(q, q))==0.0f || (fabsf(f-1.0f) < (float)QUAT_EPSILON))) {
00202         fprintf(stderr, "Warning! quat_to_mat3() called with non-normalized: size %.8f *** report a bug ***\n", f);
00203     }
00204 #endif
00205 
00206     quat_to_mat3_no_error(m, q);
00207 }
00208 
00209 void quat_to_mat4(float m[][4], const float q[4])
00210 {
00211     double q0, q1, q2, q3, qda,qdb,qdc,qaa,qab,qac,qbb,qbc,qcc;
00212 
00213 #ifdef DEBUG
00214     if(!((q0=dot_qtqt(q, q))==0.0f || (fabsf(q0-1.0) < QUAT_EPSILON))) {
00215         fprintf(stderr, "Warning! quat_to_mat4() called with non-normalized: size %.8f *** report a bug ***\n", (float)q0);
00216     }
00217 #endif
00218 
00219     q0= M_SQRT2 * (double)q[0];
00220     q1= M_SQRT2 * (double)q[1];
00221     q2= M_SQRT2 * (double)q[2];
00222     q3= M_SQRT2 * (double)q[3];
00223 
00224     qda= q0*q1;
00225     qdb= q0*q2;
00226     qdc= q0*q3;
00227     qaa= q1*q1;
00228     qab= q1*q2;
00229     qac= q1*q3;
00230     qbb= q2*q2;
00231     qbc= q2*q3;
00232     qcc= q3*q3;
00233 
00234     m[0][0]= (float)(1.0-qbb-qcc);
00235     m[0][1]= (float)(qdc+qab);
00236     m[0][2]= (float)(-qdb+qac);
00237     m[0][3]= 0.0f;
00238 
00239     m[1][0]= (float)(-qdc+qab);
00240     m[1][1]= (float)(1.0-qaa-qcc);
00241     m[1][2]= (float)(qda+qbc);
00242     m[1][3]= 0.0f;
00243 
00244     m[2][0]= (float)(qdb+qac);
00245     m[2][1]= (float)(-qda+qbc);
00246     m[2][2]= (float)(1.0-qaa-qbb);
00247     m[2][3]= 0.0f;
00248     
00249     m[3][0]= m[3][1]= m[3][2]= 0.0f;
00250     m[3][3]= 1.0f;
00251 }
00252 
00253 void mat3_to_quat(float *q, float wmat[][3])
00254 {
00255     double tr, s;
00256     float mat[3][3];
00257 
00258     /* work on a copy */
00259     copy_m3_m3(mat, wmat);
00260     normalize_m3(mat);  /* this is needed AND a 'normalize_qt' in the end */
00261     
00262     tr= 0.25* (double)(1.0f+mat[0][0]+mat[1][1]+mat[2][2]);
00263     
00264     if(tr>(double)FLT_EPSILON) {
00265         s= sqrt(tr);
00266         q[0]= (float)s;
00267         s= 1.0/(4.0*s);
00268         q[1]= (float)((mat[1][2]-mat[2][1])*s);
00269         q[2]= (float)((mat[2][0]-mat[0][2])*s);
00270         q[3]= (float)((mat[0][1]-mat[1][0])*s);
00271     }
00272     else {
00273         if(mat[0][0] > mat[1][1] && mat[0][0] > mat[2][2]) {
00274             s= 2.0f*sqrtf(1.0f + mat[0][0] - mat[1][1] - mat[2][2]);
00275             q[1]= (float)(0.25*s);
00276 
00277             s= 1.0/s;
00278             q[0]= (float)((double)(mat[2][1] - mat[1][2])*s);
00279             q[2]= (float)((double)(mat[1][0] + mat[0][1])*s);
00280             q[3]= (float)((double)(mat[2][0] + mat[0][2])*s);
00281         }
00282         else if(mat[1][1] > mat[2][2]) {
00283             s= 2.0f*sqrtf(1.0f + mat[1][1] - mat[0][0] - mat[2][2]);
00284             q[2]= (float)(0.25*s);
00285 
00286             s= 1.0/s;
00287             q[0]= (float)((double)(mat[2][0] - mat[0][2])*s);
00288             q[1]= (float)((double)(mat[1][0] + mat[0][1])*s);
00289             q[3]= (float)((double)(mat[2][1] + mat[1][2])*s);
00290         }
00291         else {
00292             s= 2.0f*sqrtf(1.0f + mat[2][2] - mat[0][0] - mat[1][1]);
00293             q[3]= (float)(0.25*s);
00294 
00295             s= 1.0/s;
00296             q[0]= (float)((double)(mat[1][0] - mat[0][1])*s);
00297             q[1]= (float)((double)(mat[2][0] + mat[0][2])*s);
00298             q[2]= (float)((double)(mat[2][1] + mat[1][2])*s);
00299         }
00300     }
00301 
00302     normalize_qt(q);
00303 }
00304 
00305 void mat4_to_quat(float *q, float m[][4])
00306 {
00307     float mat[3][3];
00308     
00309     copy_m3_m4(mat, m);
00310     mat3_to_quat(q,mat);
00311 }
00312 
00313 void mat3_to_quat_is_ok(float q[4], float wmat[3][3])
00314 {
00315     float mat[3][3], matr[3][3], matn[3][3], q1[4], q2[4], angle, si, co, nor[3];
00316 
00317     /* work on a copy */
00318     copy_m3_m3(mat, wmat);
00319     normalize_m3(mat);
00320     
00321     /* rotate z-axis of matrix to z-axis */
00322 
00323     nor[0] = mat[2][1];     /* cross product with (0,0,1) */
00324     nor[1] =  -mat[2][0];
00325     nor[2] = 0.0;
00326     normalize_v3(nor);
00327     
00328     co= mat[2][2];
00329     angle= 0.5f*saacos(co);
00330     
00331     co= (float)cos(angle);
00332     si= (float)sin(angle);
00333     q1[0]= co;
00334     q1[1]= -nor[0]*si;      /* negative here, but why? */
00335     q1[2]= -nor[1]*si;
00336     q1[3]= -nor[2]*si;
00337 
00338     /* rotate back x-axis from mat, using inverse q1 */
00339     quat_to_mat3_no_error( matr,q1);
00340     invert_m3_m3(matn, matr);
00341     mul_m3_v3(matn, mat[0]);
00342     
00343     /* and align x-axes */
00344     angle= (float)(0.5*atan2(mat[0][1], mat[0][0]));
00345     
00346     co= (float)cos(angle);
00347     si= (float)sin(angle);
00348     q2[0]= co;
00349     q2[1]= 0.0f;
00350     q2[2]= 0.0f;
00351     q2[3]= si;
00352     
00353     mul_qt_qtqt(q, q1, q2);
00354 }
00355 
00356 
00357 float normalize_qt(float *q)
00358 {
00359     float len;
00360     
00361     len= (float)sqrt(dot_qtqt(q, q));
00362     if(len!=0.0f) {
00363         mul_qt_fl(q, 1.0f/len);
00364     }
00365     else {
00366         q[1]= 1.0f;
00367         q[0]= q[2]= q[3]= 0.0f;         
00368     }
00369 
00370     return len;
00371 }
00372 
00373 float normalize_qt_qt(float r[4], const float q[4])
00374 {
00375     copy_qt_qt(r, q);
00376     return normalize_qt(r);
00377 }
00378 
00379 /* note: expects vectors to be normalized */
00380 void rotation_between_vecs_to_quat(float *q, const float v1[3], const float v2[3])
00381 {
00382     float axis[3];
00383     float angle;
00384     
00385     cross_v3_v3v3(axis, v1, v2);
00386     
00387     angle = angle_normalized_v3v3(v1, v2);
00388     
00389     axis_angle_to_quat(q, axis, angle);
00390 }
00391 
00392 void rotation_between_quats_to_quat(float *q, const float q1[4], const float q2[4])
00393 {
00394     float tquat[4];
00395     double dot = 0.0f;
00396     int x;
00397 
00398     copy_qt_qt(tquat, q1);
00399     conjugate_qt(tquat);
00400     dot = 1.0f / dot_qtqt(tquat, tquat);
00401 
00402     for(x = 0; x < 4; x++)
00403         tquat[x] *= dot;
00404 
00405     mul_qt_qtqt(q, tquat, q2);
00406 }
00407 
00408 
00409 void vec_to_quat(float q[4], const float vec[3], short axis, const short upflag)
00410 {
00411     float q2[4], nor[3], *fp, mat[3][3], angle, si, co, x2, y2, z2, len1;
00412     
00413     assert(axis >= 0 && axis <= 5);
00414     assert(upflag >= 0 && upflag <= 2);
00415     
00416     /* first rotate to axis */
00417     if(axis>2) {    
00418         x2= vec[0] ; y2= vec[1] ; z2= vec[2];
00419         axis-= 3;
00420     }
00421     else {
00422         x2= -vec[0] ; y2= -vec[1] ; z2= -vec[2];
00423     }
00424     
00425     q[0]=1.0; 
00426     q[1]=q[2]=q[3]= 0.0;
00427 
00428     len1= (float)sqrt(x2*x2+y2*y2+z2*z2);
00429     if(len1 == 0.0f) return;
00430 
00431     /* nasty! I need a good routine for this...
00432      * problem is a rotation of an Y axis to the negative Y-axis for example.
00433      */
00434 
00435     if(axis==0) {   /* x-axis */
00436         nor[0]= 0.0;
00437         nor[1]= -z2;
00438         nor[2]= y2;
00439 
00440         if(fabs(y2)+fabs(z2)<0.0001)
00441             nor[1]= 1.0;
00442 
00443         co= x2;
00444     }
00445     else if(axis==1) {  /* y-axis */
00446         nor[0]= z2;
00447         nor[1]= 0.0;
00448         nor[2]= -x2;
00449         
00450         if(fabs(x2)+fabs(z2)<0.0001)
00451             nor[2]= 1.0;
00452         
00453         co= y2;
00454     }
00455     else {          /* z-axis */
00456         nor[0]= -y2;
00457         nor[1]= x2;
00458         nor[2]= 0.0;
00459 
00460         if(fabs(x2)+fabs(y2)<0.0001)
00461             nor[0]= 1.0;
00462 
00463         co= z2;
00464     }
00465     co/= len1;
00466 
00467     normalize_v3(nor);
00468     
00469     angle= 0.5f*saacos(co);
00470     si= (float)sin(angle);
00471     q[0]= (float)cos(angle);
00472     q[1]= nor[0]*si;
00473     q[2]= nor[1]*si;
00474     q[3]= nor[2]*si;
00475     
00476     if(axis!=upflag) {
00477         quat_to_mat3(mat,q);
00478 
00479         fp= mat[2];
00480         if(axis==0) {
00481             if(upflag==1) angle= (float)(0.5*atan2(fp[2], fp[1]));
00482             else angle= (float)(-0.5*atan2(fp[1], fp[2]));
00483         }
00484         else if(axis==1) {
00485             if(upflag==0) angle= (float)(-0.5*atan2(fp[2], fp[0]));
00486             else angle= (float)(0.5*atan2(fp[0], fp[2]));
00487         }
00488         else {
00489             if(upflag==0) angle= (float)(0.5*atan2(-fp[1], -fp[0]));
00490             else angle= (float)(-0.5*atan2(-fp[0], -fp[1]));
00491         }
00492                 
00493         co= cosf(angle);
00494         si= sinf(angle)/len1;
00495         q2[0]= co;
00496         q2[1]= x2*si;
00497         q2[2]= y2*si;
00498         q2[3]= z2*si;
00499             
00500         mul_qt_qtqt(q,q2,q);
00501     }
00502 }
00503 
00504 #if 0
00505 /* A & M Watt, Advanced animation and rendering techniques, 1992 ACM press */
00506 void QuatInterpolW(float *result, float *quat1, float *quat2, float t)
00507 {
00508     float omega, cosom, sinom, sc1, sc2;
00509 
00510     cosom = quat1[0]*quat2[0] + quat1[1]*quat2[1] + quat1[2]*quat2[2] + quat1[3]*quat2[3] ;
00511     
00512     /* rotate around shortest angle */
00513     if ((1.0f + cosom) > 0.0001f) {
00514         
00515         if ((1.0f - cosom) > 0.0001f) {
00516             omega = (float)acos(cosom);
00517             sinom = (float)sin(omega);
00518             sc1 = (float)sin((1.0 - t) * omega) / sinom;
00519             sc2 = (float)sin(t * omega) / sinom;
00520         } 
00521         else {
00522             sc1 = 1.0f - t;
00523             sc2 = t;
00524         }
00525         result[0] = sc1*quat1[0] + sc2*quat2[0];
00526         result[1] = sc1*quat1[1] + sc2*quat2[1];
00527         result[2] = sc1*quat1[2] + sc2*quat2[2];
00528         result[3] = sc1*quat1[3] + sc2*quat2[3];
00529     } 
00530     else {
00531         result[0] = quat2[3];
00532         result[1] = -quat2[2];
00533         result[2] = quat2[1];
00534         result[3] = -quat2[0];
00535         
00536         sc1 = (float)sin((1.0 - t)*M_PI_2);
00537         sc2 = (float)sin(t*M_PI_2);
00538         
00539         result[0] = sc1*quat1[0] + sc2*result[0];
00540         result[1] = sc1*quat1[1] + sc2*result[1];
00541         result[2] = sc1*quat1[2] + sc2*result[2];
00542         result[3] = sc1*quat1[3] + sc2*result[3];
00543     }
00544 }
00545 #endif
00546 
00547 void interp_qt_qtqt(float result[4], const float quat1[4], const float quat2[4], const float t)
00548 {
00549     float quat[4], omega, cosom, sinom, sc1, sc2;
00550 
00551     cosom = quat1[0]*quat2[0] + quat1[1]*quat2[1] + quat1[2]*quat2[2] + quat1[3]*quat2[3] ;
00552     
00553     /* rotate around shortest angle */
00554     if (cosom < 0.0f) {
00555         cosom = -cosom;
00556         quat[0]= -quat1[0];
00557         quat[1]= -quat1[1];
00558         quat[2]= -quat1[2];
00559         quat[3]= -quat1[3];
00560     } 
00561     else {
00562         quat[0]= quat1[0];
00563         quat[1]= quat1[1];
00564         quat[2]= quat1[2];
00565         quat[3]= quat1[3];
00566     }
00567     
00568     if ((1.0f - cosom) > 0.0001f) {
00569         omega = (float)acos(cosom);
00570         sinom = (float)sin(omega);
00571         sc1 = (float)sin((1 - t) * omega) / sinom;
00572         sc2 = (float)sin(t * omega) / sinom;
00573     } else {
00574         sc1= 1.0f - t;
00575         sc2= t;
00576     }
00577     
00578     result[0] = sc1 * quat[0] + sc2 * quat2[0];
00579     result[1] = sc1 * quat[1] + sc2 * quat2[1];
00580     result[2] = sc1 * quat[2] + sc2 * quat2[2];
00581     result[3] = sc1 * quat[3] + sc2 * quat2[3];
00582 }
00583 
00584 void add_qt_qtqt(float result[4], const float quat1[4], const float quat2[4], const float t)
00585 {
00586     result[0]= quat1[0] + t*quat2[0];
00587     result[1]= quat1[1] + t*quat2[1];
00588     result[2]= quat1[2] + t*quat2[2];
00589     result[3]= quat1[3] + t*quat2[3];
00590 }
00591 
00592 void tri_to_quat(float quat[4], const float v1[3], const float v2[3], const float v3[3])
00593 {
00594     /* imaginary x-axis, y-axis triangle is being rotated */
00595     float vec[3], q1[4], q2[4], n[3], si, co, angle, mat[3][3], imat[3][3];
00596     
00597     /* move z-axis to face-normal */
00598     normal_tri_v3(vec,v1, v2, v3);
00599 
00600     n[0]= vec[1];
00601     n[1]= -vec[0];
00602     n[2]= 0.0f;
00603     normalize_v3(n);
00604     
00605     if(n[0]==0.0f && n[1]==0.0f) n[0]= 1.0f;
00606     
00607     angle= -0.5f*(float)saacos(vec[2]);
00608     co= (float)cos(angle);
00609     si= (float)sin(angle);
00610     q1[0]= co;
00611     q1[1]= n[0]*si;
00612     q1[2]= n[1]*si;
00613     q1[3]= 0.0f;
00614     
00615     /* rotate back line v1-v2 */
00616     quat_to_mat3(mat,q1);
00617     invert_m3_m3(imat, mat);
00618     sub_v3_v3v3(vec, v2, v1);
00619     mul_m3_v3(imat, vec);
00620 
00621     /* what angle has this line with x-axis? */
00622     vec[2]= 0.0f;
00623     normalize_v3(vec);
00624 
00625     angle= (float)(0.5*atan2(vec[1], vec[0]));
00626     co= (float)cos(angle);
00627     si= (float)sin(angle);
00628     q2[0]= co;
00629     q2[1]= 0.0f;
00630     q2[2]= 0.0f;
00631     q2[3]= si;
00632 
00633     mul_qt_qtqt(quat, q1, q2);
00634 }
00635 
00636 void print_qt(const char *str,  const float q[4])
00637 {
00638     printf("%s: %.3f %.3f %.3f %.3f\n", str, q[0], q[1], q[2], q[3]);
00639 }
00640 
00641 /******************************** Axis Angle *********************************/
00642 
00643 /* Axis angle to Quaternions */
00644 void axis_angle_to_quat(float q[4], const float axis[3], float angle)
00645 {
00646     float nor[3];
00647     float si;
00648 
00649     if(normalize_v3_v3(nor, axis) == 0.0f) {
00650         unit_qt(q);
00651         return;
00652     }
00653 
00654     angle /= 2;
00655     si = (float)sin(angle);
00656     q[0] = (float)cos(angle);
00657     q[1] = nor[0] * si;
00658     q[2] = nor[1] * si;
00659     q[3] = nor[2] * si; 
00660 }
00661 
00662 /* Quaternions to Axis Angle */
00663 void quat_to_axis_angle(float axis[3], float *angle, const float q[4])
00664 {
00665     float ha, si;
00666 
00667 #ifdef DEBUG
00668     if(!((ha=dot_qtqt(q, q))==0.0f || (fabsf(ha-1.0f) < (float)QUAT_EPSILON))) {
00669         fprintf(stderr, "Warning! quat_to_axis_angle() called with non-normalized: size %.8f *** report a bug ***\n", ha);
00670     }
00671 #endif
00672 
00673     /* calculate angle/2, and sin(angle/2) */
00674     ha= (float)acos(q[0]);
00675     si= (float)sin(ha);
00676     
00677     /* from half-angle to angle */
00678     *angle= ha * 2;
00679     
00680     /* prevent division by zero for axis conversion */
00681     if (fabs(si) < 0.0005)
00682         si= 1.0f;
00683     
00684     axis[0]= q[1] / si;
00685     axis[1]= q[2] / si;
00686     axis[2]= q[3] / si;
00687 }
00688 
00689 /* Axis Angle to Euler Rotation */
00690 void axis_angle_to_eulO(float eul[3], const short order, const float axis[3], const float angle)
00691 {
00692     float q[4];
00693     
00694     /* use quaternions as intermediate representation for now... */
00695     axis_angle_to_quat(q, axis, angle);
00696     quat_to_eulO(eul, order,q);
00697 }
00698 
00699 /* Euler Rotation to Axis Angle */
00700 void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], const short order)
00701 {
00702     float q[4];
00703     
00704     /* use quaternions as intermediate representation for now... */
00705     eulO_to_quat(q,eul, order);
00706     quat_to_axis_angle(axis, angle,q);
00707 }
00708 
00709 /* axis angle to 3x3 matrix - safer version (normalisation of axis performed) */
00710 void axis_angle_to_mat3(float mat[3][3], const float axis[3], const float angle)
00711 {
00712     float nor[3], nsi[3], co, si, ico;
00713     
00714     /* normalise the axis first (to remove unwanted scaling) */
00715     if(normalize_v3_v3(nor, axis) == 0.0f) {
00716         unit_m3(mat);
00717         return;
00718     }
00719     
00720     /* now convert this to a 3x3 matrix */
00721     co= (float)cos(angle);      
00722     si= (float)sin(angle);
00723     
00724     ico= (1.0f - co);
00725     nsi[0]= nor[0]*si;
00726     nsi[1]= nor[1]*si;
00727     nsi[2]= nor[2]*si;
00728     
00729     mat[0][0] = ((nor[0] * nor[0]) * ico) + co;
00730     mat[0][1] = ((nor[0] * nor[1]) * ico) + nsi[2];
00731     mat[0][2] = ((nor[0] * nor[2]) * ico) - nsi[1];
00732     mat[1][0] = ((nor[0] * nor[1]) * ico) - nsi[2];
00733     mat[1][1] = ((nor[1] * nor[1]) * ico) + co;
00734     mat[1][2] = ((nor[1] * nor[2]) * ico) + nsi[0];
00735     mat[2][0] = ((nor[0] * nor[2]) * ico) + nsi[1];
00736     mat[2][1] = ((nor[1] * nor[2]) * ico) - nsi[0];
00737     mat[2][2] = ((nor[2] * nor[2]) * ico) + co;
00738 }
00739 
00740 /* axis angle to 4x4 matrix - safer version (normalisation of axis performed) */
00741 void axis_angle_to_mat4(float mat[4][4], const float axis[3], const float angle)
00742 {
00743     float tmat[3][3];
00744     
00745     axis_angle_to_mat3(tmat,axis, angle);
00746     unit_m4(mat);
00747     copy_m4_m3(mat, tmat);
00748 }
00749 
00750 /* 3x3 matrix to axis angle (see Mat4ToVecRot too) */
00751 void mat3_to_axis_angle(float axis[3], float *angle,float mat[3][3])
00752 {
00753     float q[4];
00754     
00755     /* use quaternions as intermediate representation */
00756     // TODO: it would be nicer to go straight there...
00757     mat3_to_quat(q,mat);
00758     quat_to_axis_angle(axis, angle,q);
00759 }
00760 
00761 /* 4x4 matrix to axis angle (see Mat4ToVecRot too) */
00762 void mat4_to_axis_angle(float axis[3], float *angle,float mat[4][4])
00763 {
00764     float q[4];
00765     
00766     /* use quaternions as intermediate representation */
00767     // TODO: it would be nicer to go straight there...
00768     mat4_to_quat(q,mat);
00769     quat_to_axis_angle(axis, angle,q);
00770 }
00771 
00772 
00773 
00774 void single_axis_angle_to_mat3(float mat[3][3], const char axis, const float angle)
00775 {
00776     const float angle_cos= cosf(angle);
00777     const float angle_sin= sinf(angle);
00778 
00779     switch(axis) {
00780     case 'X': /* rotation around X */
00781         mat[0][0] =  1.0f;
00782         mat[0][1] =  0.0f;
00783         mat[0][2] =  0.0f;
00784         mat[1][0] =  0.0f;
00785         mat[1][1] =  angle_cos;
00786         mat[1][2] =  angle_sin;
00787         mat[2][0] =  0.0f;
00788         mat[2][1] = -angle_sin;
00789         mat[2][2] =  angle_cos;
00790         break;
00791     case 'Y': /* rotation around Y */
00792         mat[0][0] =  angle_cos;
00793         mat[0][1] =  0.0f;
00794         mat[0][2] = -angle_sin;
00795         mat[1][0] =  0.0f;
00796         mat[1][1] =  1.0f;
00797         mat[1][2] =  0.0f;
00798         mat[2][0] =  angle_sin;
00799         mat[2][1] =  0.0f;
00800         mat[2][2] =  angle_cos;
00801         break;
00802     case 'Z': /* rotation around Z */
00803         mat[0][0] =  angle_cos;
00804         mat[0][1] =  angle_sin;
00805         mat[0][2] =  0.0f;
00806         mat[1][0] = -angle_sin;
00807         mat[1][1] =  angle_cos;
00808         mat[1][2] =  0.0f;
00809         mat[2][0] =  0.0f;
00810         mat[2][1] =  0.0f;
00811         mat[2][2] =  1.0f;
00812         break;
00813     default:
00814         assert("invalid axis");
00815     }
00816 }
00817 
00818 /****************************** Vector/Rotation ******************************/
00819 /* TODO: the following calls should probably be depreceated sometime         */
00820 
00821 /* axis angle to 3x3 matrix */
00822 void vec_rot_to_mat3(float mat[][3], const float vec[3], const float phi)
00823 {
00824     /* rotation of phi radials around vec */
00825     float vx, vx2, vy, vy2, vz, vz2, co, si;
00826     
00827     vx= vec[0];
00828     vy= vec[1];
00829     vz= vec[2];
00830     vx2= vx*vx;
00831     vy2= vy*vy;
00832     vz2= vz*vz;
00833     co= (float)cos(phi);
00834     si= (float)sin(phi);
00835     
00836     mat[0][0]= vx2+co*(1.0f-vx2);
00837     mat[0][1]= vx*vy*(1.0f-co)+vz*si;
00838     mat[0][2]= vz*vx*(1.0f-co)-vy*si;
00839     mat[1][0]= vx*vy*(1.0f-co)-vz*si;
00840     mat[1][1]= vy2+co*(1.0f-vy2);
00841     mat[1][2]= vy*vz*(1.0f-co)+vx*si;
00842     mat[2][0]= vz*vx*(1.0f-co)+vy*si;
00843     mat[2][1]= vy*vz*(1.0f-co)-vx*si;
00844     mat[2][2]= vz2+co*(1.0f-vz2);
00845 }
00846 
00847 /* axis angle to 4x4 matrix */
00848 void vec_rot_to_mat4(float mat[][4], const float vec[3], const float phi)
00849 {
00850     float tmat[3][3];
00851     
00852     vec_rot_to_mat3(tmat,vec, phi);
00853     unit_m4(mat);
00854     copy_m4_m3(mat, tmat);
00855 }
00856 
00857 /* axis angle to quaternion */
00858 void vec_rot_to_quat(float *quat, const float vec[3], const float phi)
00859 {
00860     /* rotation of phi radials around vec */
00861     float si;
00862 
00863     quat[1]= vec[0];
00864     quat[2]= vec[1];
00865     quat[3]= vec[2];
00866     
00867     if(normalize_v3(quat+1) == 0.0f) {
00868         unit_qt(quat);
00869     }
00870     else {
00871         quat[0]= (float)cos((double)phi/2.0);
00872         si= (float)sin((double)phi/2.0);
00873         quat[1] *= si;
00874         quat[2] *= si;
00875         quat[3] *= si;
00876     }
00877 }
00878 
00879 /******************************** XYZ Eulers *********************************/
00880 
00881 /* XYZ order */
00882 void eul_to_mat3(float mat[][3], const float eul[3])
00883 {
00884     double ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
00885     
00886     ci = cos(eul[0]); 
00887     cj = cos(eul[1]); 
00888     ch = cos(eul[2]);
00889     si = sin(eul[0]); 
00890     sj = sin(eul[1]); 
00891     sh = sin(eul[2]);
00892     cc = ci*ch; 
00893     cs = ci*sh; 
00894     sc = si*ch; 
00895     ss = si*sh;
00896 
00897     mat[0][0] = (float)(cj*ch); 
00898     mat[1][0] = (float)(sj*sc-cs); 
00899     mat[2][0] = (float)(sj*cc+ss);
00900     mat[0][1] = (float)(cj*sh); 
00901     mat[1][1] = (float)(sj*ss+cc); 
00902     mat[2][1] = (float)(sj*cs-sc);
00903     mat[0][2] = (float)-sj;  
00904     mat[1][2] = (float)(cj*si);    
00905     mat[2][2] = (float)(cj*ci);
00906 
00907 }
00908 
00909 /* XYZ order */
00910 void eul_to_mat4(float mat[][4], const float eul[3])
00911 {
00912     double ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
00913     
00914     ci = cos(eul[0]); 
00915     cj = cos(eul[1]); 
00916     ch = cos(eul[2]);
00917     si = sin(eul[0]); 
00918     sj = sin(eul[1]); 
00919     sh = sin(eul[2]);
00920     cc = ci*ch; 
00921     cs = ci*sh; 
00922     sc = si*ch; 
00923     ss = si*sh;
00924 
00925     mat[0][0] = (float)(cj*ch); 
00926     mat[1][0] = (float)(sj*sc-cs); 
00927     mat[2][0] = (float)(sj*cc+ss);
00928     mat[0][1] = (float)(cj*sh); 
00929     mat[1][1] = (float)(sj*ss+cc); 
00930     mat[2][1] = (float)(sj*cs-sc);
00931     mat[0][2] = (float)-sj;  
00932     mat[1][2] = (float)(cj*si);    
00933     mat[2][2] = (float)(cj*ci);
00934 
00935 
00936     mat[3][0]= mat[3][1]= mat[3][2]= mat[0][3]= mat[1][3]= mat[2][3]= 0.0f;
00937     mat[3][3]= 1.0f;
00938 }
00939 
00940 /* returns two euler calculation methods, so we can pick the best */
00941 /* XYZ order */
00942 static void mat3_to_eul2(float tmat[][3], float eul1[3], float eul2[3])
00943 {
00944     float cy, quat[4], mat[3][3];
00945     
00946     mat3_to_quat(quat,tmat);
00947     quat_to_mat3(mat,quat);
00948     copy_m3_m3(mat, tmat);
00949     normalize_m3(mat);
00950     
00951     cy = (float)sqrt(mat[0][0]*mat[0][0] + mat[0][1]*mat[0][1]);
00952     
00953     if (cy > 16.0f*FLT_EPSILON) {
00954         
00955         eul1[0] = (float)atan2(mat[1][2], mat[2][2]);
00956         eul1[1] = (float)atan2(-mat[0][2], cy);
00957         eul1[2] = (float)atan2(mat[0][1], mat[0][0]);
00958         
00959         eul2[0] = (float)atan2(-mat[1][2], -mat[2][2]);
00960         eul2[1] = (float)atan2(-mat[0][2], -cy);
00961         eul2[2] = (float)atan2(-mat[0][1], -mat[0][0]);
00962         
00963     } else {
00964         eul1[0] = (float)atan2(-mat[2][1], mat[1][1]);
00965         eul1[1] = (float)atan2(-mat[0][2], cy);
00966         eul1[2] = 0.0f;
00967         
00968         copy_v3_v3(eul2, eul1);
00969     }
00970 }
00971 
00972 /* XYZ order */
00973 void mat3_to_eul(float *eul,float tmat[][3])
00974 {
00975     float eul1[3], eul2[3];
00976     
00977     mat3_to_eul2(tmat, eul1, eul2);
00978         
00979     /* return best, which is just the one with lowest values it in */
00980     if(fabs(eul1[0])+fabs(eul1[1])+fabs(eul1[2]) > fabs(eul2[0])+fabs(eul2[1])+fabs(eul2[2])) {
00981         copy_v3_v3(eul, eul2);
00982     }
00983     else {
00984         copy_v3_v3(eul, eul1);
00985     }
00986 }
00987 
00988 /* XYZ order */
00989 void mat4_to_eul(float *eul,float tmat[][4])
00990 {
00991     float tempMat[3][3];
00992 
00993     copy_m3_m4(tempMat, tmat);
00994     normalize_m3(tempMat);
00995     mat3_to_eul(eul,tempMat);
00996 }
00997 
00998 /* XYZ order */
00999 void quat_to_eul(float *eul, const float quat[4])
01000 {
01001     float mat[3][3];
01002 
01003     quat_to_mat3(mat,quat);
01004     mat3_to_eul(eul,mat);
01005 }
01006 
01007 /* XYZ order */
01008 void eul_to_quat(float *quat, const float eul[3])
01009 {
01010     float ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
01011  
01012     ti = eul[0]*0.5f; tj = eul[1]*0.5f; th = eul[2]*0.5f;
01013     ci = (float)cos(ti);  cj = (float)cos(tj);  ch = (float)cos(th);
01014     si = (float)sin(ti);  sj = (float)sin(tj);  sh = (float)sin(th);
01015     cc = ci*ch; cs = ci*sh; sc = si*ch; ss = si*sh;
01016     
01017     quat[0] = cj*cc + sj*ss;
01018     quat[1] = cj*sc - sj*cs;
01019     quat[2] = cj*ss + sj*cc;
01020     quat[3] = cj*cs - sj*sc;
01021 }
01022 
01023 /* XYZ order */
01024 void rotate_eul(float *beul, const char axis, const float ang)
01025 {
01026     float eul[3], mat1[3][3], mat2[3][3], totmat[3][3];
01027 
01028     assert(axis >= 'X' && axis <= 'Z');
01029 
01030     eul[0]= eul[1]= eul[2]= 0.0f;
01031     if(axis=='X') eul[0]= ang;
01032     else if(axis=='Y') eul[1]= ang;
01033     else eul[2]= ang;
01034     
01035     eul_to_mat3(mat1,eul);
01036     eul_to_mat3(mat2,beul);
01037     
01038     mul_m3_m3m3(totmat, mat2, mat1);
01039     
01040     mat3_to_eul(beul,totmat);
01041     
01042 }
01043 
01044 /* exported to transform.c */
01045 /* order independent! */
01046 void compatible_eul(float eul[3], const float oldrot[3])
01047 {
01048     float dx, dy, dz;
01049     
01050     /* correct differences of about 360 degrees first */
01051     dx= eul[0] - oldrot[0];
01052     dy= eul[1] - oldrot[1];
01053     dz= eul[2] - oldrot[2];
01054     
01055     while(fabs(dx) > 5.1) {
01056         if(dx > 0.0f) eul[0] -= 2.0f*(float)M_PI; else eul[0]+= 2.0f*(float)M_PI;
01057         dx= eul[0] - oldrot[0];
01058     }
01059     while(fabs(dy) > 5.1) {
01060         if(dy > 0.0f) eul[1] -= 2.0f*(float)M_PI; else eul[1]+= 2.0f*(float)M_PI;
01061         dy= eul[1] - oldrot[1];
01062     }
01063     while(fabs(dz) > 5.1) {
01064         if(dz > 0.0f) eul[2] -= 2.0f*(float)M_PI; else eul[2]+= 2.0f*(float)M_PI;
01065         dz= eul[2] - oldrot[2];
01066     }
01067     
01068     /* is 1 of the axis rotations larger than 180 degrees and the other small? NO ELSE IF!! */  
01069     if(fabs(dx) > 3.2 && fabs(dy)<1.6 && fabs(dz)<1.6) {
01070         if(dx > 0.0f) eul[0] -= 2.0f*(float)M_PI; else eul[0]+= 2.0f*(float)M_PI;
01071     }
01072     if(fabs(dy) > 3.2 && fabs(dz)<1.6 && fabs(dx)<1.6) {
01073         if(dy > 0.0f) eul[1] -= 2.0f*(float)M_PI; else eul[1]+= 2.0f*(float)M_PI;
01074     }
01075     if(fabs(dz) > 3.2 && fabs(dx)<1.6 && fabs(dy)<1.6) {
01076         if(dz > 0.0f) eul[2] -= 2.0f*(float)M_PI; else eul[2]+= 2.0f*(float)M_PI;
01077     }
01078     
01079     /* the method below was there from ancient days... but why! probably because the code sucks :)
01080         */
01081 #if 0   
01082     /* calc again */
01083     dx= eul[0] - oldrot[0];
01084     dy= eul[1] - oldrot[1];
01085     dz= eul[2] - oldrot[2];
01086     
01087     /* special case, tested for x-z  */
01088     
01089     if((fabs(dx) > 3.1 && fabs(dz) > 1.5) || (fabs(dx) > 1.5 && fabs(dz) > 3.1)) {
01090         if(dx > 0.0) eul[0] -= M_PI; else eul[0]+= M_PI;
01091         if(eul[1] > 0.0) eul[1]= M_PI - eul[1]; else eul[1]= -M_PI - eul[1];
01092         if(dz > 0.0) eul[2] -= M_PI; else eul[2]+= M_PI;
01093         
01094     }
01095     else if((fabs(dx) > 3.1 && fabs(dy) > 1.5) || (fabs(dx) > 1.5 && fabs(dy) > 3.1)) {
01096         if(dx > 0.0) eul[0] -= M_PI; else eul[0]+= M_PI;
01097         if(dy > 0.0) eul[1] -= M_PI; else eul[1]+= M_PI;
01098         if(eul[2] > 0.0) eul[2]= M_PI - eul[2]; else eul[2]= -M_PI - eul[2];
01099     }
01100     else if((fabs(dy) > 3.1 && fabs(dz) > 1.5) || (fabs(dy) > 1.5 && fabs(dz) > 3.1)) {
01101         if(eul[0] > 0.0) eul[0]= M_PI - eul[0]; else eul[0]= -M_PI - eul[0];
01102         if(dy > 0.0) eul[1] -= M_PI; else eul[1]+= M_PI;
01103         if(dz > 0.0) eul[2] -= M_PI; else eul[2]+= M_PI;
01104     }
01105 #endif  
01106 }
01107 
01108 /* uses 2 methods to retrieve eulers, and picks the closest */
01109 /* XYZ order */
01110 void mat3_to_compatible_eul(float eul[3], const float oldrot[3], float mat[][3])
01111 {
01112     float eul1[3], eul2[3];
01113     float d1, d2;
01114     
01115     mat3_to_eul2(mat, eul1, eul2);
01116     
01117     compatible_eul(eul1, oldrot);
01118     compatible_eul(eul2, oldrot);
01119     
01120     d1= (float)fabs(eul1[0]-oldrot[0]) + (float)fabs(eul1[1]-oldrot[1]) + (float)fabs(eul1[2]-oldrot[2]);
01121     d2= (float)fabs(eul2[0]-oldrot[0]) + (float)fabs(eul2[1]-oldrot[1]) + (float)fabs(eul2[2]-oldrot[2]);
01122     
01123     /* return best, which is just the one with lowest difference */
01124     if(d1 > d2) {
01125         copy_v3_v3(eul, eul2);
01126     }
01127     else {
01128         copy_v3_v3(eul, eul1);
01129     }
01130     
01131 }
01132 
01133 /************************** Arbitrary Order Eulers ***************************/
01134 
01135 /* Euler Rotation Order Code:
01136  * was adapted from  
01137           ANSI C code from the article
01138         "Euler Angle Conversion"
01139         by Ken Shoemake, shoemake@graphics.cis.upenn.edu
01140         in "Graphics Gems IV", Academic Press, 1994
01141  * for use in Blender
01142  */
01143 
01144 /* Type for rotation order info - see wiki for derivation details */
01145 typedef struct RotOrderInfo {
01146     short axis[3];
01147     short parity;   /* parity of axis permutation (even=0, odd=1) - 'n' in original code */
01148 } RotOrderInfo;
01149 
01150 /* Array of info for Rotation Order calculations 
01151  * WARNING: must be kept in same order as eEulerRotationOrders
01152  */
01153 static RotOrderInfo rotOrders[]= {
01154     /* i, j, k, n */
01155     {{0, 1, 2}, 0}, // XYZ
01156     {{0, 2, 1}, 1}, // XZY
01157     {{1, 0, 2}, 1}, // YXZ
01158     {{1, 2, 0}, 0}, // YZX
01159     {{2, 0, 1}, 0}, // ZXY
01160     {{2, 1, 0}, 1}  // ZYX
01161 };
01162 
01163 /* Get relevant pointer to rotation order set from the array 
01164  * NOTE: since we start at 1 for the values, but arrays index from 0, 
01165  *       there is -1 factor involved in this process...
01166  */
01167 #define GET_ROTATIONORDER_INFO(order) (assert(order>=0 && order<=6), (order < 1) ? &rotOrders[0] : &rotOrders[(order)-1])
01168 
01169 /* Construct quaternion from Euler angles (in radians). */
01170 void eulO_to_quat(float q[4], const float e[3], const short order)
01171 {
01172     RotOrderInfo *R= GET_ROTATIONORDER_INFO(order); 
01173     short i=R->axis[0],  j=R->axis[1],  k=R->axis[2];
01174     double ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
01175     double a[3];
01176     
01177     ti = e[i] * 0.5f;
01178     tj = e[j] * (R->parity ? -0.5f : 0.5f);
01179     th = e[k] * 0.5f;
01180 
01181     ci = cos(ti);  cj = cos(tj);  ch = cos(th);
01182     si = sin(ti);  sj = sin(tj);  sh = sin(th);
01183     
01184     cc = ci*ch; cs = ci*sh; 
01185     sc = si*ch; ss = si*sh;
01186     
01187     a[i] = cj*sc - sj*cs;
01188     a[j] = cj*ss + sj*cc;
01189     a[k] = cj*cs - sj*sc;
01190     
01191     q[0] = cj*cc + sj*ss;
01192     q[1] = a[0];
01193     q[2] = a[1];
01194     q[3] = a[2];
01195     
01196     if (R->parity) q[j+1] = -q[j+1];
01197 }
01198 
01199 /* Convert quaternion to Euler angles (in radians). */
01200 void quat_to_eulO(float e[3], short const order, const float q[4])
01201 {
01202     float M[3][3];
01203     
01204     quat_to_mat3(M,q);
01205     mat3_to_eulO(e, order,M);
01206 }
01207 
01208 /* Construct 3x3 matrix from Euler angles (in radians). */
01209 void eulO_to_mat3(float M[3][3], const float e[3], const short order)
01210 {
01211     RotOrderInfo *R= GET_ROTATIONORDER_INFO(order); 
01212     short i=R->axis[0],  j=R->axis[1],  k=R->axis[2];
01213     double ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
01214     
01215     if (R->parity) {
01216         ti = -e[i];   tj = -e[j];   th = -e[k];
01217     }
01218     else {
01219         ti = e[i];    tj = e[j];    th = e[k];
01220     }
01221     
01222     ci = cos(ti); cj = cos(tj); ch = cos(th);
01223     si = sin(ti); sj = sin(tj); sh = sin(th);
01224     
01225     cc = ci*ch; cs = ci*sh; 
01226     sc = si*ch; ss = si*sh;
01227     
01228     M[i][i] = cj*ch; M[j][i] = sj*sc-cs; M[k][i] = sj*cc+ss;
01229     M[i][j] = cj*sh; M[j][j] = sj*ss+cc; M[k][j] = sj*cs-sc;
01230     M[i][k] = -sj;   M[j][k] = cj*si;    M[k][k] = cj*ci;
01231 }
01232 
01233 /* returns two euler calculation methods, so we can pick the best */
01234 static void mat3_to_eulo2(float M[3][3], float *e1, float *e2, short order)
01235 {
01236     RotOrderInfo *R= GET_ROTATIONORDER_INFO(order); 
01237     short i=R->axis[0],  j=R->axis[1],  k=R->axis[2];
01238     float m[3][3];
01239     double cy;
01240     
01241     /* process the matrix first */
01242     copy_m3_m3(m, M);
01243     normalize_m3(m);
01244     
01245     cy= sqrt(m[i][i]*m[i][i] + m[i][j]*m[i][j]);
01246     
01247     if (cy > 16.0*(double)FLT_EPSILON) {
01248         e1[i] = atan2(m[j][k], m[k][k]);
01249         e1[j] = atan2(-m[i][k], cy);
01250         e1[k] = atan2(m[i][j], m[i][i]);
01251         
01252         e2[i] = atan2(-m[j][k], -m[k][k]);
01253         e2[j] = atan2(-m[i][k], -cy);
01254         e2[k] = atan2(-m[i][j], -m[i][i]);
01255     } 
01256     else {
01257         e1[i] = atan2(-m[k][j], m[j][j]);
01258         e1[j] = atan2(-m[i][k], cy);
01259         e1[k] = 0;
01260         
01261         copy_v3_v3(e2, e1);
01262     }
01263     
01264     if (R->parity) {
01265         e1[0] = -e1[0]; 
01266         e1[1] = -e1[1]; 
01267         e1[2] = -e1[2];
01268         
01269         e2[0] = -e2[0]; 
01270         e2[1] = -e2[1]; 
01271         e2[2] = -e2[2];
01272     }
01273 }
01274 
01275 /* Construct 4x4 matrix from Euler angles (in radians). */
01276 void eulO_to_mat4(float M[4][4], const float e[3], const short order)
01277 {
01278     float m[3][3];
01279     
01280     /* for now, we'll just do this the slow way (i.e. copying matrices) */
01281     normalize_m3(m);
01282     eulO_to_mat3(m,e, order);
01283     copy_m4_m3(M, m);
01284 }
01285 
01286 
01287 /* Convert 3x3 matrix to Euler angles (in radians). */
01288 void mat3_to_eulO(float eul[3], const short order,float M[3][3])
01289 {
01290     float eul1[3], eul2[3];
01291     
01292     mat3_to_eulo2(M, eul1, eul2, order);
01293         
01294     /* return best, which is just the one with lowest values it in */
01295     if(fabs(eul1[0])+fabs(eul1[1])+fabs(eul1[2]) > fabs(eul2[0])+fabs(eul2[1])+fabs(eul2[2])) {
01296         copy_v3_v3(eul, eul2);
01297     }
01298     else {
01299         copy_v3_v3(eul, eul1);
01300     }
01301 }
01302 
01303 /* Convert 4x4 matrix to Euler angles (in radians). */
01304 void mat4_to_eulO(float e[3], const short order,float M[4][4])
01305 {
01306     float m[3][3];
01307     
01308     /* for now, we'll just do this the slow way (i.e. copying matrices) */
01309     copy_m3_m4(m, M);
01310     normalize_m3(m);
01311     mat3_to_eulO(e, order,m);
01312 }
01313 
01314 /* uses 2 methods to retrieve eulers, and picks the closest */
01315 void mat3_to_compatible_eulO(float eul[3], float oldrot[3], short order,float mat[3][3])
01316 {
01317     float eul1[3], eul2[3];
01318     float d1, d2;
01319     
01320     mat3_to_eulo2(mat, eul1, eul2, order);
01321     
01322     compatible_eul(eul1, oldrot);
01323     compatible_eul(eul2, oldrot);
01324     
01325     d1= fabsf(eul1[0]-oldrot[0]) + fabsf(eul1[1]-oldrot[1]) + fabsf(eul1[2]-oldrot[2]);
01326     d2= fabsf(eul2[0]-oldrot[0]) + fabsf(eul2[1]-oldrot[1]) + fabsf(eul2[2]-oldrot[2]);
01327     
01328     /* return best, which is just the one with lowest difference */
01329     if (d1 > d2)
01330         copy_v3_v3(eul, eul2);
01331     else
01332         copy_v3_v3(eul, eul1);
01333 }
01334 
01335 void mat4_to_compatible_eulO(float eul[3], float oldrot[3], short order,float M[4][4])
01336 {
01337     float m[3][3];
01338     
01339     /* for now, we'll just do this the slow way (i.e. copying matrices) */
01340     copy_m3_m4(m, M);
01341     normalize_m3(m);
01342     mat3_to_compatible_eulO(eul, oldrot, order, m);
01343 }
01344 /* rotate the given euler by the given angle on the specified axis */
01345 // NOTE: is this safe to do with different axis orders?
01346 void rotate_eulO(float beul[3], short order, char axis, float ang)
01347 {
01348     float eul[3], mat1[3][3], mat2[3][3], totmat[3][3];
01349 
01350     assert(axis >= 'X' && axis <= 'Z');
01351 
01352     eul[0]= eul[1]= eul[2]= 0.0f;
01353     if (axis=='X') 
01354         eul[0]= ang;
01355     else if (axis=='Y')
01356         eul[1]= ang;
01357     else 
01358         eul[2]= ang;
01359     
01360     eulO_to_mat3(mat1,eul, order);
01361     eulO_to_mat3(mat2,beul, order);
01362     
01363     mul_m3_m3m3(totmat, mat2, mat1);
01364     
01365     mat3_to_eulO(beul, order,totmat);
01366 }
01367 
01368 /* the matrix is written to as 3 axis vectors */
01369 void eulO_to_gimbal_axis(float gmat[][3], const float eul[3], const short order)
01370 {
01371     RotOrderInfo *R= GET_ROTATIONORDER_INFO(order);
01372 
01373     float mat[3][3];
01374     float teul[3];
01375 
01376     /* first axis is local */
01377     eulO_to_mat3(mat,eul, order);
01378     copy_v3_v3(gmat[R->axis[0]], mat[R->axis[0]]);
01379     
01380     /* second axis is local minus first rotation */
01381     copy_v3_v3(teul, eul);
01382     teul[R->axis[0]] = 0;
01383     eulO_to_mat3(mat,teul, order);
01384     copy_v3_v3(gmat[R->axis[1]], mat[R->axis[1]]);
01385     
01386     
01387     /* Last axis is global */
01388     gmat[R->axis[2]][0] = 0;
01389     gmat[R->axis[2]][1] = 0;
01390     gmat[R->axis[2]][2] = 0;
01391     gmat[R->axis[2]][R->axis[2]] = 1;
01392 }
01393 
01394 /******************************* Dual Quaternions ****************************/
01395 
01396 /*
01397    Conversion routines between (regular quaternion, translation) and
01398    dual quaternion.
01399 
01400    Version 1.0.0, February 7th, 2007
01401 
01402    Copyright (C) 2006-2007 University of Dublin, Trinity College, All Rights 
01403    Reserved
01404 
01405    This software is provided 'as-is', without any express or implied
01406    warranty.  In no event will the author(s) be held liable for any damages
01407    arising from the use of this software.
01408 
01409    Permission is granted to anyone to use this software for any purpose,
01410    including commercial applications, and to alter it and redistribute it
01411    freely, subject to the following restrictions:
01412 
01413    1. The origin of this software must not be misrepresented; you must not
01414       claim that you wrote the original software. If you use this software
01415       in a product, an acknowledgment in the product documentation would be
01416       appreciated but is not required.
01417    2. Altered source versions must be plainly marked as such, and must not be
01418       misrepresented as being the original software.
01419    3. This notice may not be removed or altered from any source distribution.
01420 
01421    Author: Ladislav Kavan, kavanl@cs.tcd.ie
01422 
01423    Changes for Blender:
01424    - renaming, style changes and optimizations
01425    - added support for scaling
01426 */
01427 
01428 void mat4_to_dquat(DualQuat *dq,float basemat[][4], float mat[][4])
01429 {
01430     float *t, *q, dscale[3], scale[3], basequat[4];
01431     float baseRS[4][4], baseinv[4][4], baseR[4][4], baseRinv[4][4];
01432     float R[4][4], S[4][4];
01433 
01434     /* split scaling and rotation, there is probably a faster way to do
01435        this, it's done like this now to correctly get negative scaling */
01436     mult_m4_m4m4(baseRS, mat, basemat);
01437     mat4_to_size(scale,baseRS);
01438 
01439     copy_v3_v3(dscale, scale);
01440     dscale[0] -= 1.0f; dscale[1] -= 1.0f; dscale[2] -= 1.0f;
01441 
01442     if((determinant_m4(mat) < 0.0f) || len_v3(dscale) > 1e-4f) {
01443         /* extract R and S  */
01444         float tmp[4][4];
01445 
01446          /* extra orthogonalize, to avoid flipping with stretched bones */
01447         copy_m4_m4(tmp, baseRS);
01448         orthogonalize_m4(tmp, 1);
01449         mat4_to_quat(basequat, tmp);
01450 
01451         quat_to_mat4(baseR, basequat);
01452         copy_v3_v3(baseR[3], baseRS[3]);
01453 
01454         invert_m4_m4(baseinv, basemat);
01455         mult_m4_m4m4(R, baseR, baseinv);
01456 
01457         invert_m4_m4(baseRinv, baseR);
01458         mult_m4_m4m4(S, baseRinv, baseRS);
01459 
01460         /* set scaling part */
01461         mul_serie_m4(dq->scale, basemat, S, baseinv, NULL, NULL, NULL, NULL, NULL);
01462         dq->scale_weight= 1.0f;
01463     }
01464     else {
01465         /* matrix does not contain scaling */
01466         copy_m4_m4(R, mat);
01467         dq->scale_weight= 0.0f;
01468     }
01469 
01470     /* non-dual part */
01471     mat4_to_quat(dq->quat,R);
01472 
01473     /* dual part */
01474     t= R[3];
01475     q= dq->quat;
01476     dq->trans[0]= -0.5f*(t[0]*q[1] + t[1]*q[2] + t[2]*q[3]);
01477     dq->trans[1]=  0.5f*(t[0]*q[0] + t[1]*q[3] - t[2]*q[2]);
01478     dq->trans[2]=  0.5f*(-t[0]*q[3] + t[1]*q[0] + t[2]*q[1]);
01479     dq->trans[3]=  0.5f*(t[0]*q[2] - t[1]*q[1] + t[2]*q[0]);
01480 }
01481 
01482 void dquat_to_mat4(float mat[][4], DualQuat *dq)
01483 {
01484     float len, *t, q0[4];
01485     
01486     /* regular quaternion */
01487     copy_qt_qt(q0, dq->quat);
01488 
01489     /* normalize */
01490     len= (float)sqrt(dot_qtqt(q0, q0)); 
01491     if(len != 0.0f)
01492         mul_qt_fl(q0, 1.0f/len);
01493     
01494     /* rotation */
01495     quat_to_mat4(mat,q0);
01496 
01497     /* translation */
01498     t= dq->trans;
01499     mat[3][0]= 2.0f*(-t[0]*q0[1] + t[1]*q0[0] - t[2]*q0[3] + t[3]*q0[2]);
01500     mat[3][1]= 2.0f*(-t[0]*q0[2] + t[1]*q0[3] + t[2]*q0[0] - t[3]*q0[1]);
01501     mat[3][2]= 2.0f*(-t[0]*q0[3] - t[1]*q0[2] + t[2]*q0[1] + t[3]*q0[0]);
01502 
01503     /* note: this does not handle scaling */
01504 }   
01505 
01506 void add_weighted_dq_dq(DualQuat *dqsum, DualQuat *dq, float weight)
01507 {
01508     int flipped= 0;
01509 
01510     /* make sure we interpolate quats in the right direction */
01511     if (dot_qtqt(dq->quat, dqsum->quat) < 0) {
01512         flipped= 1;
01513         weight= -weight;
01514     }
01515 
01516     /* interpolate rotation and translation */
01517     dqsum->quat[0] += weight*dq->quat[0];
01518     dqsum->quat[1] += weight*dq->quat[1];
01519     dqsum->quat[2] += weight*dq->quat[2];
01520     dqsum->quat[3] += weight*dq->quat[3];
01521 
01522     dqsum->trans[0] += weight*dq->trans[0];
01523     dqsum->trans[1] += weight*dq->trans[1];
01524     dqsum->trans[2] += weight*dq->trans[2];
01525     dqsum->trans[3] += weight*dq->trans[3];
01526 
01527     /* interpolate scale - but only if needed */
01528     if (dq->scale_weight) {
01529         float wmat[4][4];
01530         
01531         if(flipped) /* we don't want negative weights for scaling */
01532             weight= -weight;
01533         
01534         copy_m4_m4(wmat, dq->scale);
01535         mul_m4_fl(wmat, weight);
01536         add_m4_m4m4(dqsum->scale, dqsum->scale, wmat);
01537         dqsum->scale_weight += weight;
01538     }
01539 }
01540 
01541 void normalize_dq(DualQuat *dq, float totweight)
01542 {
01543     float scale= 1.0f/totweight;
01544 
01545     mul_qt_fl(dq->quat, scale);
01546     mul_qt_fl(dq->trans, scale);
01547     
01548     if(dq->scale_weight) {
01549         float addweight= totweight - dq->scale_weight;
01550         
01551         if(addweight) {
01552             dq->scale[0][0] += addweight;
01553             dq->scale[1][1] += addweight;
01554             dq->scale[2][2] += addweight;
01555             dq->scale[3][3] += addweight;
01556         }
01557 
01558         mul_m4_fl(dq->scale, scale);
01559         dq->scale_weight= 1.0f;
01560     }
01561 }
01562 
01563 void mul_v3m3_dq(float *co, float mat[][3],DualQuat *dq)
01564 {   
01565     float M[3][3], t[3], scalemat[3][3], len2;
01566     float w= dq->quat[0], x= dq->quat[1], y= dq->quat[2], z= dq->quat[3];
01567     float t0= dq->trans[0], t1= dq->trans[1], t2= dq->trans[2], t3= dq->trans[3];
01568     
01569     /* rotation matrix */
01570     M[0][0]= w*w + x*x - y*y - z*z;
01571     M[1][0]= 2*(x*y - w*z);
01572     M[2][0]= 2*(x*z + w*y);
01573 
01574     M[0][1]= 2*(x*y + w*z);
01575     M[1][1]= w*w + y*y - x*x - z*z;
01576     M[2][1]= 2*(y*z - w*x); 
01577 
01578     M[0][2]= 2*(x*z - w*y);
01579     M[1][2]= 2*(y*z + w*x);
01580     M[2][2]= w*w + z*z - x*x - y*y;
01581     
01582     len2= dot_qtqt(dq->quat, dq->quat);
01583     if(len2 > 0.0f)
01584         len2= 1.0f/len2;
01585     
01586     /* translation */
01587     t[0]= 2*(-t0*x + w*t1 - t2*z + y*t3);
01588     t[1]= 2*(-t0*y + t1*z - x*t3 + w*t2);
01589     t[2]= 2*(-t0*z + x*t2 + w*t3 - t1*y);
01590 
01591     /* apply scaling */
01592     if(dq->scale_weight)
01593         mul_m4_v3(dq->scale, co);
01594     
01595     /* apply rotation and translation */
01596     mul_m3_v3(M, co);
01597     co[0]= (co[0] + t[0])*len2;
01598     co[1]= (co[1] + t[1])*len2;
01599     co[2]= (co[2] + t[2])*len2;
01600 
01601     /* compute crazyspace correction mat */
01602     if(mat) {
01603         if(dq->scale_weight) {
01604             copy_m3_m4(scalemat, dq->scale);
01605             mul_m3_m3m3(mat, M, scalemat);
01606         }
01607         else
01608             copy_m3_m3(mat, M);
01609         mul_m3_fl(mat, len2);
01610     }
01611 }
01612 
01613 void copy_dq_dq(DualQuat *dq1, DualQuat *dq2)
01614 {
01615     memcpy(dq1, dq2, sizeof(DualQuat));
01616 }
01617 
01618 /* axis matches eTrackToAxis_Modes */
01619 void quat_apply_track(float quat[4], short axis, short upflag)
01620 {   
01621     /* rotations are hard coded to match vec_to_quat */
01622     const float quat_track[][4]= {{0.70710676908493, 0.0, -0.70710676908493, 0.0},  /* pos-y90 */ 
01623                                   {0.5, 0.5, 0.5, 0.5},  /* Quaternion((1,0,0), radians(90)) * Quaternion((0,1,0), radians(90)) */ 
01624                                   {0.70710676908493, 0.0, 0.0, 0.70710676908493},  /* pos-z90 */ 
01625                                   {0.70710676908493, 0.0, 0.70710676908493, 0.0}, /* neg-y90 */ 
01626                                   {0.5, -0.5, -0.5, 0.5}, /* Quaternion((1,0,0), radians(-90)) * Quaternion((0,1,0), radians(-90)) */ 
01627                                   {-3.0908619663705394e-08, 0.70710676908493, 0.70710676908493, 3.0908619663705394e-08}}; /* no rotation */
01628 
01629     assert(axis >= 0 && axis <= 5);
01630     assert(upflag >= 0 && upflag <= 2);
01631     
01632     mul_qt_qtqt(quat, quat, quat_track[axis]);
01633 
01634     if(axis>2)
01635         axis= axis-3;
01636 
01637     /* there are 2 possible up-axis for each axis used, the 'quat_track' applies so the first
01638      * up axis is used X->Y, Y->X, Z->X, if this first up axis isn used then rotate 90d
01639      * the strange bit shift below just find the low axis {X:Y, Y:X, Z:X} */
01640     if(upflag != (2-axis)>>1) {
01641         float q[4]= {0.70710676908493, 0.0, 0.0, 0.0}; /* assign 90d rotation axis */
01642         q[axis+1] = ((axis==1)) ? 0.70710676908493 : -0.70710676908493; /* flip non Y axis */
01643         mul_qt_qtqt(quat, quat, q);
01644     }
01645 }
01646 
01647 
01648 void vec_apply_track(float vec[3], short axis)
01649 {
01650     float tvec[3];
01651 
01652     assert(axis >= 0 && axis <= 5);
01653     
01654     copy_v3_v3(tvec, vec);
01655 
01656     switch(axis) {
01657     case 0: /* pos-x */
01658         /* vec[0]=  0.0; */
01659         vec[1]=  tvec[2];
01660         vec[2]=  -tvec[1];
01661         break;
01662     case 1: /* pos-y */
01663         /* vec[0]= tvec[0]; */
01664         /* vec[1]=  0.0; */
01665         /* vec[2]= tvec[2]; */ 
01666         break;
01667     case 2: /* pos-z */
01668         /* vec[0]= tvec[0]; */
01669         /* vec[1]= tvec[1]; */
01670         // vec[2]=  0.0; */
01671         break;
01672     case 3: /* neg-x */
01673         /* vec[0]=  0.0; */
01674         vec[1]=  tvec[2];
01675         vec[2]= -tvec[1];
01676         break;
01677     case 4: /* neg-y */
01678         vec[0]= -tvec[2];
01679         /* vec[1]=  0.0; */
01680         vec[2]= tvec[0];
01681         break;
01682     case 5: /* neg-z */
01683         vec[0]= -tvec[0];
01684         vec[1]= -tvec[1];
01685         /* vec[2]=  0.0; */
01686         break;
01687     }
01688 }
01689 
01690 /* lens/angle conversion (radians) */
01691 float focallength_to_fov(float focal_length, float sensor)
01692 {
01693     return 2.0f * atanf((sensor/2.0f) / focal_length);
01694 }
01695 
01696 float fov_to_focallength(float hfov, float sensor)
01697 {
01698     return (sensor/2.0f) / tanf(hfov * 0.5f);
01699 }
01700 
01701 /* 'mod_inline(-3,4)= 1', 'fmod(-3,4)= -3' */
01702 static float mod_inline(float a, float b)
01703 {
01704     return a - (b * floorf(a / b));
01705 }
01706 
01707 float angle_wrap_rad(float angle)
01708 {
01709     return mod_inline(angle + (float)M_PI, (float)M_PI*2.0f) - (float)M_PI;
01710 }
01711 
01712 float angle_wrap_deg(float angle)
01713 {
01714     return mod_inline(angle + 180.0f, 360.0f) - 180.0f;
01715 }