2.5 - More work on Axis-Angle Rotations
authorJoshua Leung <aligorith@gmail.com>
Sat, 12 Sep 2009 05:06:28 +0000 (05:06 +0000)
committerJoshua Leung <aligorith@gmail.com>
Sat, 12 Sep 2009 05:06:28 +0000 (05:06 +0000)
* Added a few new methods for axis-angle conversions, and used these instead of manually performing those steps elsewhere
* Axis-angles to other representations now get their axes normalised to make sure that odd scaling doesn't occur.
* Made a few more tools work with axis-angles properly

source/blender/blenkernel/intern/armature.c
source/blender/blenlib/BLI_arithb.h
source/blender/blenlib/intern/arithb.c
source/blender/editors/animation/keyingsets.c
source/blender/editors/armature/editarmature.c
source/blender/editors/armature/poseobject.c
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform_conversions.c
source/blender/makesrna/intern/rna_pose.c

index 0c18817f8be9170437bb252d2af29c24555626b4..c880925aa94643f6a44c9e743b560d6bc4dd89fc 100644 (file)
@@ -1993,7 +1993,7 @@ void chan_calc_mat(bPoseChannel *chan)
        }
        else if (chan->rotmode == PCHAN_ROT_AXISANGLE) {
                /* axis-angle - stored in quaternion data, but not really that great for 3D-changing orientations */
-               VecRotToMat3(&chan->quat[1], chan->quat[0], rmat);
+               AxisAngleToMat3(&chan->quat[1], chan->quat[0], rmat);
        }
        else {
                /* quats are normalised before use to eliminate scaling issues */
index 71604758b80b36a733a071f13fd5d9640ce28525..8eb4d5972e3991f9646504273419e752d3e50a18 100644 (file)
@@ -342,8 +342,6 @@ void Mat4AddMat4(float m1[][4], float m2[][4], float m3[][4]);
 
 void VecUpMat3old(float *vec, float mat[][3], short axis);
 void VecUpMat3(float *vec, float mat[][3], short axis);
-void VecRotToMat3(float *vec, float phi, float mat[][3]);
-void VecRotToMat4(float *vec, float phi, float mat[][4]);
 
 void VecCopyf(float *v1, float *v2);
 int VecLen(int *v1, int *v2);
@@ -376,10 +374,23 @@ void Vec2Subf(float *v, float *v1, float *v2);
 void Vec2Copyf(float *v1, float *v2);
 void Vec2Lerpf(float *target, float *a, float *b, float t);
 
-void AxisAngleToQuat(float *q, float *axis, float angle);
-void QuatToAxisAngle(float *q, float *axis, float *angle);
+void AxisAngleToQuat(float q[4], float axis[3], float angle);
+void QuatToAxisAngle(float q[4], float axis[3], float *angle);
+void AxisAngleToEulO(float axis[3], float angle, float eul[3], short order);
+void EulOToAxisAngle(float eul[3], short order, float axis[3], float *angle);
+void AxisAngleToMat3(float axis[3], float angle, float mat[3][3]);
+void AxisAngleToMat4(float axis[3], float angle, float mat[4][4]);
+void Mat3ToAxisAngle(float mat[3][3], float axis[3], float *angle);
+void Mat4ToAxisAngle(float mat[4][4], float axis[3], float *angle);
+
+void Mat3ToVecRot(float mat[3][3], float axis[3], float *angle);
+void Mat4ToVecRot(float mat[4][4], float axis[3], float *angle);
+void VecRotToMat3(float *vec, float phi, float mat[][3]);
+void VecRotToMat4(float *vec, float phi, float mat[][4]);
+
 void RotationBetweenVectorsToQuat(float *q, float v1[3], float v2[3]);
 void vectoquat(float *vec, short axis, short upflag, float *q);
+void Mat3ToQuat_is_ok(float wmat[][3], float *q);
 
 void VecReflect(float *out, float *v1, float *v2);
 void VecBisect3(float *v, float *v1, float *v2, float *v3);
@@ -460,8 +471,6 @@ void VecStar(float mat[][3],float *vec);
 
 short EenheidsMat(float mat[][3]);
 
-void Mat3ToQuat_is_ok(float wmat[][3], float *q);
-
 void i_ortho(float left, float right, float bottom, float top, float nearClip, float farClip, float matrix[][4]);
 void i_polarview(float dist, float azimuth, float incidence, float twist, float Vm[][4]);
 void i_translate(float Tx, float Ty, float Tz, float mat[][4]);
index 96056ba77830a648cdc6f4d3554bdaddffbe8378..1839380f953383fa4f022c099ae8be5d9b0b17e5 100644 (file)
@@ -3278,7 +3278,7 @@ void Mat3ToCompatibleEul(float mat[][3], float *eul, float *oldrot)
 /* ************ AXIS ANGLE *************** */
 
 /* Axis angle to Quaternions */
-void AxisAngleToQuat(float *q, float *axis, float angle)
+void AxisAngleToQuat(float q[4], float axis[3], float angle)
 {
        float nor[3];
        float si;
@@ -3315,6 +3315,90 @@ void QuatToAxisAngle(float q[4], float axis[3], float *angle)
        axis[2]= q[3] / si;
 }
 
+/* Axis Angle to Euler Rotation */
+void AxisAngleToEulO(float axis[3], float angle, float eul[3], short order)
+{
+       float q[4];
+       
+       /* use quaternions as intermediate representation for now... */
+       AxisAngleToQuat(q, axis, angle);
+       QuatToEulO(q, eul, order);
+}
+
+/* Euler Rotation to Axis Angle */
+void EulOToAxisAngle(float eul[3], short order, float axis[3], float *angle)
+{
+       float q[4];
+       
+       /* use quaternions as intermediate representation for now... */
+       EulOToQuat(eul, order, q);
+       QuatToAxisAngle(q, axis, angle);
+}
+
+/* axis angle to 3x3 matrix - safer version (normalisation of axis performed) */
+void AxisAngleToMat3(float axis[3], float angle, float mat[3][3])
+{
+       float nor[3];
+       
+       /* normalise the axis first (to remove unwanted scaling) */
+       VecCopyf(nor, axis);
+       Normalize(nor);
+       
+       /* now convert this to a 3x3 matrix */
+       VecRotToMat3(nor, angle, mat);
+}
+
+/* axis angle to 4x4 matrix - safer version (normalisation of axis performed) */
+void AxisAngleToMat4(float axis[3], float angle, float mat[4][4])
+{
+       float nor[3];
+       
+       /* normalise the axis first (to remove unwanted scaling) */
+       VecCopyf(nor, axis);
+       Normalize(nor);
+       
+       /* now convert this to a 4x4 matrix */
+       VecRotToMat4(nor, angle, mat);
+}
+
+/* 3x3 matrix to axis angle (alias around the other call) */
+void Mat3ToAxisAngle(float mat[3][3], float axis[3], float *angle)
+{
+       /* note different order of calling args... */
+       Mat3ToVecRot(axis, angle, mat);
+}
+
+/* 4x4 matrix to axis angle (alias around the other call) */
+void Mat4ToAxisAngle(float mat[4][4], float axis[3], float *angle)
+{
+       /* note different order of calling args... */
+       Mat4ToVecRot(axis, angle, mat);
+}
+
+/* ************ AXIS ANGLE (unchecked) *************** */
+
+/* 3x3 matrix to axis angle */
+void Mat3ToVecRot(float mat[3][3], float axis[3], float *angle)
+{
+       float q[4];
+       
+       /* use quaternions as intermediate representation */
+       // TODO: it would be nicer to go straight there...
+       Mat3ToQuat(mat, q);
+       QuatToAxisAngle(q, axis, angle);
+}
+
+/* 4x4 matrix to axis angle */
+void Mat4ToVecRot(float mat[4][4], float axis[3], float *angle)
+{
+       float q[4];
+       
+       /* use quaternions as intermediate representation */
+       // TODO: it would be nicer to go straight there...
+       Mat4ToQuat(mat, q);
+       QuatToAxisAngle(q, axis, angle);
+}
+
 /* axis angle to 3x3 matrix */
 void VecRotToMat3(float *vec, float phi, float mat[][3])
 {
@@ -3339,7 +3423,6 @@ void VecRotToMat3(float *vec, float phi, float mat[][3])
        mat[2][0]= vz*vx*(1.0f-co)+vy*si;
        mat[2][1]= vy*vz*(1.0f-co)-vx*si;
        mat[2][2]= vz2+co*(1.0f-vz2);
-       
 }
 
 /* axis angle to 4x4 matrix */
@@ -3374,6 +3457,8 @@ void VecRotToQuat(float *vec, float phi, float *quat)
        }
 }
 
+/* ************ VECTORS *************** */
+
 /* Returns a vector bisecting the angle at v2 formed by v1, v2 and v3 */
 void VecBisect3(float *out, float *v1, float *v2, float *v3)
 {
index 2639d49b5bef014e021ea7e1cb75cc1d3fc963ce..60efcce4e73b35bb58ee4d8197370030381aeda9 100644 (file)
@@ -1177,7 +1177,7 @@ int modify_keyframes (bContext *C, ListBase *dsources, bAction *act, KeyingSet *
                                                /* if this path is exactly "rotation", and the rotation mode is set to eulers,
                                                 * use "euler_rotation" instead so that rotations will be keyed correctly
                                                 */
-                                               if (strcmp(ksp->rna_path, "rotation")==0 && (cks->pchan->rotmode))
+                                               if (strcmp(ksp->rna_path, "rotation")==0 && (cks->pchan->rotmode > 0))
                                                        BLI_dynstr_append(pathds, "euler_rotation");
                                                else
                                                        BLI_dynstr_append(pathds, ksp->rna_path);
index 3b6c9e9d13df409deb1d7ba121a5a77853d5c3ac..e2293b658788d941d5b459389bc33dff5f2f9f6c 100644 (file)
@@ -4865,6 +4865,7 @@ static int pose_clear_rot_exec(bContext *C, wmOperator *op)
                        
                        eul[0]= eul[1]= eul[2]= 0.0f;
                        
+                       // TODO: for 4 channel rotations, we need special flags for those too...
                        if (pchan->protectflag & OB_LOCK_ROTX)
                                eul[0]= oldeul[0];
                        if (pchan->protectflag & OB_LOCK_ROTY)
index 9a404e24e12e285fde114afb0cf8ed0cf44ef2bf..b473b9ee2266bb7f7be3b14a386cd54df5eadb0d 100644 (file)
@@ -1009,12 +1009,25 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
                                        }
                                }
                                else if (pchan->rotmode > 0) {
-                                       /* quat to euler */
-                                       QuatToEulO(chan->quat, pchan->eul, pchan->rotmode);
+                                       /* quat/axis-angle to euler */
+                                       if (chan->rotmode == PCHAN_ROT_AXISANGLE)
+                                               AxisAngleToEulO(&chan->quat[1], chan->quat[0], pchan->eul, pchan->rotmode);
+                                       else
+                                               QuatToEulO(chan->quat, pchan->eul, pchan->rotmode);
+                               }
+                               else if (pchan->rotmode == PCHAN_ROT_AXISANGLE) {
+                                       /* quat/euler to axis angle */
+                                       if (chan->rotmode > 0)
+                                               EulOToAxisAngle(chan->eul, chan->rotmode, &pchan->quat[1], &pchan->quat[0]);
+                                       else    
+                                               QuatToAxisAngle(chan->quat, &pchan->quat[1], &pchan->quat[0]);
                                }
                                else {
-                                       /* euler to quat */
-                                       EulOToQuat(chan->eul, chan->rotmode, pchan->quat);
+                                       /* euler/axis-angle to quat */
+                                       if (chan->rotmode > 0)
+                                               EulOToQuat(chan->eul, chan->rotmode, pchan->quat);
+                                       else
+                                               AxisAngleToQuat(pchan->quat, &chan->quat[1], chan->quat[0]);
                                }
                                
                                /* paste flipped pose? */
@@ -1026,6 +1039,14 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
                                                pchan->eul[1] *= -1;
                                                pchan->eul[2] *= -1;
                                        }
+                                       else if (pchan->rotmode == PCHAN_ROT_AXISANGLE) {
+                                               float eul[3];
+                                               
+                                               AxisAngleToEulO(&pchan->quat[1], pchan->quat[0], eul, EULER_ORDER_DEFAULT);
+                                               eul[1]*= -1;
+                                               eul[2]*= -1;
+                                               EulOToAxisAngle(eul, EULER_ORDER_DEFAULT, &pchan->quat[1], &pchan->quat[0]);
+                                       }
                                        else {
                                                float eul[3];
                                                
index 6405e87c4c0d371be053dfbc3c860c0880ebd334..467f5c59e3d38bfeecbad8a12c3046c9aeff3590 100644 (file)
@@ -1614,7 +1614,8 @@ static void protectedQuaternionBits(short protectflag, float *quat, float *oldqu
 {
        /* quaternions get limited with euler... */
        /* this function only does the delta rotation */
-
+       
+       // FIXME: need special checks for quality here...
        if(protectflag) {
                float eul[3], oldeul[3], quat1[4];
 
@@ -2686,12 +2687,13 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
                                
                                QuatMul(td->ext->quat, quat, iquat);
                                
-                               /* this function works on end result */
-                               protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
-                               
                                /* make temp copy (since stored in same place) */
-                               QuatCopy(quat, td->ext->quat);
+                               QuatCopy(quat, td->ext->quat); // this is just a 4d vector copying function
                                QuatToAxisAngle(quat, &td->ext->quat[1], &td->ext->quat[0]); 
+                               
+                               /* this function works on end result */
+                               // TODO: we really need a specialised version of this for axis-angle that doesn't try to do quats...
+                               protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
                        }
                        else { 
                                float eulmat[3][3];
index e0d058f160f77594f8f73dddfc9a48dc6c23ef13..6386c0d4eb72d399e299652a6fb999e31ac73396 100644 (file)
@@ -509,6 +509,8 @@ static short apply_targetless_ik(Object *ob)
                                        /* rotation */
                                        if (parchan->rotmode > 0) 
                                                Mat3ToEulO(rmat3, parchan->eul, parchan->rotmode);
+                                       else if (parchan->rotmode == PCHAN_ROT_AXISANGLE)
+                                               Mat3ToAxisAngle(rmat3, &parchan->quat[1], &parchan->quat[0]);
                                        else
                                                Mat3ToQuat(rmat3, parchan->quat);
                                        
@@ -517,6 +519,8 @@ static short apply_targetless_ik(Object *ob)
                                        if (data->flag & CONSTRAINT_IK_STRETCH) {
                                                if (parchan->rotmode > 0)
                                                        EulOToMat3(parchan->eul, parchan->rotmode, qrmat);
+                                               else if (parchan->rotmode == PCHAN_ROT_AXISANGLE)
+                                                       AxisAngleToMat3(&parchan->quat[1], parchan->quat[0], qrmat);
                                                else
                                                        QuatToMat3(parchan->quat, qrmat);
                                                
index 0a88b0843070fe2c22a5907e6fa6091bc645ee27..d143c94ebb19e5399a32b97b92f5c261fbb5627e 100644 (file)
@@ -115,14 +115,9 @@ static void rna_PoseChannel_euler_rotation_get(PointerRNA *ptr, float *value)
 {
        bPoseChannel *pchan= ptr->data;
        
-       if(pchan->rotmode == PCHAN_ROT_AXISANGLE) {
-               float m[3][3];
-               
-               /* go through a 3x3 matrix */
-               VecRotToMat3(&pchan->quat[1], pchan->quat[0], m);
-               Mat3ToEul(m, value);
-       }
-       else if(pchan->rotmode == PCHAN_ROT_QUAT) /* default XYZ eulers when using axis-angle... */
+       if(pchan->rotmode == PCHAN_ROT_AXISANGLE) /* default XYZ eulers */
+               AxisAngleToEulO(&pchan->quat[1], pchan->quat[0], value, EULER_ORDER_DEFAULT);
+       else if(pchan->rotmode == PCHAN_ROT_QUAT) /* default XYZ eulers  */
                QuatToEul(pchan->quat, value);
        else
                VECCOPY(value, pchan->eul);
@@ -133,14 +128,9 @@ static void rna_PoseChannel_euler_rotation_set(PointerRNA *ptr, const float *val
 {
        bPoseChannel *pchan= ptr->data;
        
-       if(pchan->rotmode == PCHAN_ROT_AXISANGLE) { /* default XYZ eulers when using axis-angle... */
-               float q[4];
-               
-               /* convert to temp quat, then to axis angle (since stored in same var) */
-               EulToQuat((float *)value, q);
-               QuatToAxisAngle(q, &pchan->quat[1], &pchan->quat[0]);
-       }
-       else if(pchan->rotmode == PCHAN_ROT_QUAT) /* default XYZ eulers when using quats... */
+       if(pchan->rotmode == PCHAN_ROT_AXISANGLE) /* default XYZ eulers */
+               EulOToAxisAngle((float *)value, EULER_ORDER_DEFAULT, &pchan->quat[1], &pchan->quat[0]);
+       else if(pchan->rotmode == PCHAN_ROT_QUAT) /* default XYZ eulers */
                EulToQuat((float*)value, pchan->quat);
        else
                VECCOPY(pchan->eul, value);
@@ -177,13 +167,7 @@ static void rna_PoseChannel_rotation_mode_set(PointerRNA *ptr, int value)
        if (value > 0) { /* to euler */
                if (pchan->rotmode == PCHAN_ROT_AXISANGLE) {
                        /* axis-angle to euler */
-                       float m[3][3];
-                       
-                       /* convert to 3x3 matrix, then to euler 
-                        *      - axis angle is stored in quats
-                        */
-                       VecRotToMat3(&pchan->quat[1], pchan->quat[0], m);
-                       Mat3ToEulO(m, pchan->eul, value);
+                       AxisAngleToEulO(&pchan->quat[1], pchan->quat[0], pchan->eul, value);
                }
                else if (pchan->rotmode == PCHAN_ROT_QUAT) {
                        /* quat to euler */
@@ -209,11 +193,7 @@ static void rna_PoseChannel_rotation_mode_set(PointerRNA *ptr, int value)
        else { /* to axis-angle */
                if (pchan->rotmode > 0) {
                        /* euler to axis angle */
-                       float q[4];
-                       
-                       /* convert to temp quat, then to axis angle (since stored in same var) */
-                       EulOToQuat(pchan->eul, pchan->rotmode, q);
-                       QuatToAxisAngle(q, &pchan->quat[1], &pchan->quat[0]);
+                       EulOToAxisAngle(pchan->eul, pchan->rotmode, &pchan->quat[1], &pchan->quat[0]);
                }
                else if (pchan->rotmode == PCHAN_ROT_QUAT) {
                        /* quat to axis angle */