Mathutils API: Euler support for rotation order.
authorCampbell Barton <ideasman42@gmail.com>
Sat, 20 Feb 2010 19:49:04 +0000 (19:49 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sat, 20 Feb 2010 19:49:04 +0000 (19:49 +0000)
Examples.
 euler = Euler(1, 2, 3)
 euler.order = 'ZXY'

 euler = matrix.to_euler('XZY')

Still missing rna support. this still wont give the right order, defaulting to XYZ.
 eul = object.rotation_euler

release/scripts/io/export_fbx.py
source/blender/blenlib/intern/math_rotation.c
source/blender/python/generic/Mathutils.c
source/blender/python/generic/Mathutils.h
source/blender/python/generic/euler.c
source/blender/python/generic/euler.h
source/blender/python/generic/matrix.c
source/blender/python/generic/quat.c
source/blender/python/generic/vector.c
source/blender/python/intern/bpy_rna.c

index 1cad32f32d6b504d081ef1513360b8b3acc3d1da..558c5896397b31eef2142895df3431db1c7f7fdc 100644 (file)
@@ -2876,7 +2876,7 @@ Takes:  {''')
                                 context_bone_anim_vecs = []
                                 prev_eul = None
                                 for mtx in context_bone_anim_mats:
-                                    if prev_eul:       prev_eul = mtx[1].to_euler(prev_eul)
+                                    if prev_eul:       prev_eul = mtx[1].to_euler('XYZ', prev_eul)
                                     else:                      prev_eul = mtx[1].to_euler()
                                     context_bone_anim_vecs.append(eulerRadToDeg(prev_eul))
 #                                                                      context_bone_anim_vecs.append(prev_eul)
index 8d0130a52c233c0a42dfde45042a87f0c4b34d62..8d5684a3ac8a75d1b9fd964d952872dd05152649 100644 (file)
@@ -1052,7 +1052,7 @@ static RotOrderInfo rotOrders[]= {
        {{1, 0, 2}, 1}, // YXZ
        {{1, 2, 0}, 0}, // YZX
        {{2, 0, 1}, 0}, // ZXY
-       {{2, 1, 0}, 1}  // ZYZ
+       {{2, 1, 0}, 1}  // ZYX
 };
 
 /* Get relevant pointer to rotation order set from the array 
index 3675c5946dec29138a3bdeaff8ececd124a52e5e..0ded2b182640a5ee5d69019e5ed174a1562d9ee5 100644 (file)
@@ -170,18 +170,10 @@ static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args)
                }
        }
 
-#ifdef USE_MATHUTILS_DEG
-       /* Clamp to -360:360 */
-       while (angle<-360.0f)
-               angle+=360.0;
-       while (angle>360.0f)
-               angle-=360.0;
-#else
        while (angle<-(Py_PI*2))
                angle+=(Py_PI*2);
        while (angle>(Py_PI*2))
                angle-=(Py_PI*2);
-#endif
        
        if(matSize != 2 && matSize != 3 && matSize != 4) {
                PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
@@ -205,10 +197,6 @@ static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args)
                        return NULL;
                
        }
-#ifdef USE_MATHUTILS_DEG
-       //convert to radians
-       angle = angle * (float) (Py_PI / 180);
-#endif
 
        /* check for valid vector/axis above */
        if(vec) {
index e8b1fc2ed28b904a66e34cbf3bf8892a1a593997..d0b90341cd20f9a9858bc2e48784c731008694b2 100644 (file)
@@ -37,8 +37,6 @@
 #include "quat.h"
 #include "euler.h"
 
-/* #define USE_MATHUTILS_DEG - for backwards compat */
-
 /* Can cast different mathutils types to this, use for generic funcs */
 
 extern char BaseMathObject_Wrapped_doc[];
index bbfd6cb43cf126d9885b3ea24159cfebeb7a8b57..7e5be428868f2ebd2a8af376811c1478c3263d26 100644 (file)
@@ -41,6 +41,7 @@ static PyObject *Euler_new(PyTypeObject * type, PyObject * args, PyObject * kwar
        int size, i;
        float eul[3];
        PyObject *e;
+       short order= 0;  // TODO, add order option
 
        size = PyTuple_GET_SIZE(args);
        if (size == 1) {
@@ -53,7 +54,7 @@ static PyObject *Euler_new(PyTypeObject * type, PyObject * args, PyObject * kwar
                }
        } else if (size == 0) {
                //returns a new empty 3d euler
-               return newEulerObject(NULL, Py_NEW, NULL);
+               return newEulerObject(NULL, order, Py_NEW, NULL);
        } else {
                listObject = args;
        }
@@ -79,7 +80,24 @@ static PyObject *Euler_new(PyTypeObject * type, PyObject * args, PyObject * kwar
                        return NULL;
                }
        }
-       return newEulerObject(eul, Py_NEW, NULL);
+       return newEulerObject(eul, order, Py_NEW, NULL);
+}
+
+short euler_order_from_string(const char *str, const char *error_prefix)
+{
+       if((str[0] && str[1] && str[2] && str[3]=='\0')) {
+               switch(*((int32_t *)str)) {
+                       case 'X'|'Y'<<8|'Z'<<16:        return 0;
+                       case 'X'|'Z'<<8|'Y'<<16:        return 1;
+                       case 'Y'|'X'<<8|'Z'<<16:        return 2;
+                       case 'Y'|'Z'<<8|'X'<<16:        return 3;
+                       case 'Z'|'X'<<8|'Y'<<16:        return 4;
+                       case 'Z'|'Y'<<8|'X'<<16:        return 5;
+               }
+       }
+
+       PyErr_Format(PyExc_TypeError, "%s: invalid euler order '%s'", error_prefix, str);
+       return -1;
 }
 
 //-----------------------------METHODS----------------------------
@@ -97,22 +115,12 @@ static char Euler_ToQuat_doc[] =
 static PyObject *Euler_ToQuat(EulerObject * self)
 {
        float quat[4];
-#ifdef USE_MATHUTILS_DEG
-       float eul[3];
-       int x;
-#endif
 
        if(!BaseMath_ReadCallback(self))
                return NULL;
 
-#ifdef USE_MATHUTILS_DEG
-       for(x = 0; x < 3; x++) {
-               eul[x] = self->eul[x] * ((float)Py_PI / 180);
-       }
-       eul_to_quat( quat,eul);
-#else
-       eul_to_quat( quat,self->eul);
-#endif
+       if(self->order==0)      eul_to_quat(quat, self->eul);
+       else                            eulO_to_quat(quat, self->eul, self->order);
 
        return newQuaternionObject(quat, Py_NEW, NULL);
 }
@@ -133,24 +141,14 @@ static PyObject *Euler_ToMatrix(EulerObject * self)
        if(!BaseMath_ReadCallback(self))
                return NULL;
 
-#ifdef USE_MATHUTILS_DEG
-       {
-               float eul[3];
-               int x;
-               
-               for(x = 0; x < 3; x++) {
-                       eul[x] = self->eul[x] * ((float)Py_PI / 180);
-               }
-               eul_to_mat3( (float (*)[3]) mat,eul);
-       }
-#else
-       eul_to_mat3( (float (*)[3]) mat,self->eul);
-#endif
+       if(self->order==0)      eul_to_mat3((float (*)[3])mat, self->eul);
+       else                            eulO_to_mat3((float (*)[3])mat, self->eul, self->order);
+
        return newMatrixObject(mat, 3, 3 , Py_NEW, NULL);
 }
 //----------------------------Euler.unique()-----------------------
 //sets the x,y,z values to a unique euler rotation
-
+// TODO, check if this works with rotation order!!!
 static char Euler_Unique_doc[] =
 ".. method:: unique()\n"
 "\n"
@@ -170,16 +168,9 @@ static PyObject *Euler_Unique(EulerObject * self)
        if(!BaseMath_ReadCallback(self))
                return NULL;
 
-#ifdef USE_MATHUTILS_DEG
-       //radians
-       heading = self->eul[0] * (float)Py_PI / 180;
-       pitch = self->eul[1] * (float)Py_PI / 180;
-       bank = self->eul[2] * (float)Py_PI / 180;
-#else
        heading = self->eul[0];
        pitch = self->eul[1];
        bank = self->eul[2];
-#endif
 
        //wrap heading in +180 / -180
        pitch += Py_PI;
@@ -210,13 +201,6 @@ static PyObject *Euler_Unique(EulerObject * self)
        heading -= (floor(heading * PI_INV)) * PI_2;
        heading -= Py_PI;
 
-#ifdef USE_MATHUTILS_DEG
-       //back to degrees
-       self->eul[0] = (float)(heading * 180 / (float)Py_PI);
-       self->eul[1] = (float)(pitch * 180 / (float)Py_PI);
-       self->eul[2] = (float)(bank * 180 / (float)Py_PI);
-#endif
-
        BaseMath_WriteCallback(self);
        Py_INCREF(self);
        return (PyObject *)self;
@@ -261,28 +245,8 @@ static PyObject *Euler_Rotate(EulerObject * self, PyObject *args)
        if(!BaseMath_ReadCallback(self))
                return NULL;
 
-#ifdef USE_MATHUTILS_DEG
-       {
-               int x;
-
-               //covert to radians
-               angle *= ((float)Py_PI / 180);
-               for(x = 0; x < 3; x++) {
-                       self->eul[x] *= ((float)Py_PI / 180);
-               }
-       }
-#endif
-       rotate_eul(self->eul, *axis, angle);
-
-#ifdef USE_MATHUTILS_DEG
-       {
-               int x;
-               //convert back from radians
-               for(x = 0; x < 3; x++) {
-                       self->eul[x] *= (180 / (float)Py_PI);
-               }
-       }
-#endif
+       if(self->order == 0)    rotate_eul(self->eul, *axis, angle);
+       else                                    rotate_eulO(self->eul, self->order, *axis, angle);
 
        BaseMath_WriteCallback(self);
        Py_INCREF(self);
@@ -297,40 +261,27 @@ static char Euler_MakeCompatible_doc[] =
 "   :arg other: make compatible with this rotation.\n"
 "   :type other: :class:`Euler`\n"
 "   :return: an instance of itself.\n"
-"   :rtype: :class:`Euler`\n";
+"   :rtype: :class:`Euler`\n"
+"\n"
+"   .. note:: the order of eulers must match or an exception is raised.\n";
 
 static PyObject *Euler_MakeCompatible(EulerObject * self, EulerObject *value)
 {
-#ifdef USE_MATHUTILS_DEG
-       float eul_from_rad[3];
-       int x;
-#endif
-       
        if(!EulerObject_Check(value)) {
-               PyErr_SetString(PyExc_TypeError, "euler.makeCompatible(euler):expected a single euler argument.");
+               PyErr_SetString(PyExc_TypeError, "euler.make_compatible(euler): expected a single euler argument.");
                return NULL;
        }
        
        if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
                return NULL;
 
-#ifdef USE_MATHUTILS_DEG
-       //covert to radians
-       for(x = 0; x < 3; x++) {
-               self->eul[x] = self->eul[x] * ((float)Py_PI / 180);
-               eul_from_rad[x] = value->eul[x] * ((float)Py_PI / 180);
+       if(self->order != value->order) {
+               PyErr_SetString(PyExc_ValueError, "euler.make_compatible(euler): rotation orders don't match\n");
+               return NULL;
        }
-       compatible_eul(self->eul, eul_from_rad);
-#else
+
        compatible_eul(self->eul, value->eul);
-#endif
 
-#ifdef USE_MATHUTILS_DEG
-       //convert back from radians
-       for(x = 0; x < 3; x++) {
-               self->eul[x] *= (180 / (float)Py_PI);
-       }
-#endif
        BaseMath_WriteCallback(self);
        Py_INCREF(self);
        return (PyObject *)self;
@@ -354,7 +305,7 @@ static PyObject *Euler_copy(EulerObject * self, PyObject *args)
        if(!BaseMath_ReadCallback(self))
                return NULL;
 
-       return newEulerObject(self->eul, Py_NEW, Py_TYPE(self));
+       return newEulerObject(self->eul, self->order, Py_NEW, Py_TYPE(self));
 }
 
 //----------------------------print object (internal)--------------
@@ -402,12 +353,7 @@ static PyObject* Euler_richcmpr(PyObject *objectA, PyObject *objectB, int compar
                        result = EXPP_VectorsAreEqual(eulA->eul, eulB->eul, 3, 1);
                        break;
                case Py_NE:
-                       result = EXPP_VectorsAreEqual(eulA->eul, eulB->eul, 3, 1);
-                       if (result == 0){
-                               result = 1;
-                       }else{
-                               result = 0;
-                       }
+                       result = !EXPP_VectorsAreEqual(eulA->eul, eulB->eul, 3, 1);
                        break;
                default:
                        printf("The result of the comparison could not be evaluated");
@@ -563,6 +509,30 @@ static int Euler_setAxis( EulerObject * self, PyObject * value, void * type )
        return Euler_ass_item(self, GET_INT_FROM_POINTER(type), value);
 }
 
+/* rotation order */
+static PyObject *Euler_getOrder(EulerObject *self, void *type)
+{
+       static char order[][4] = {"XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"};
+       return PyUnicode_FromString(order[self->order]);
+}
+
+static int Euler_setOrder( EulerObject * self, PyObject * value, void * type )
+{
+       char *order_str= _PyUnicode_AsString(value);
+       short order= euler_order_from_string(order_str, "euler.order");
+
+       if(order < 0)
+               return -1;
+
+       if(self->cb_user) {
+               PyErr_SetString(PyExc_TypeError, "euler.order: assignment is not allowed on eulers with an owner");
+               return -1;
+       }
+
+       self->order= order;
+       return 0;
+}
+
 /*****************************************************************************/
 /* Python attributes get/set structure:                                      */
 /*****************************************************************************/
@@ -570,6 +540,7 @@ static PyGetSetDef Euler_getseters[] = {
        {"x", (getter)Euler_getAxis, (setter)Euler_setAxis, "Euler X axis in radians. **type** float", (void *)0},
        {"y", (getter)Euler_getAxis, (setter)Euler_setAxis, "Euler Y axis in radians. **type** float", (void *)1},
        {"z", (getter)Euler_getAxis, (setter)Euler_setAxis, "Euler Z axis in radians. **type** float", (void *)2},
+       {"order", (getter)Euler_getOrder, (setter)Euler_setOrder, "Euler rotation order. **type** string in ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX']", (void *)NULL},
 
        {"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, BaseMathObject_Wrapped_doc, NULL},
        {"_owner", (getter)BaseMathObject_getOwner, (setter)NULL, BaseMathObject_Owner_doc, NULL},
@@ -650,7 +621,7 @@ PyTypeObject euler_Type = {
  (i.e. it was allocated elsewhere by MEM_mallocN())
   pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
  (i.e. it must be created here with PyMEM_malloc())*/
-PyObject *newEulerObject(float *eul, int type, PyTypeObject *base_type)
+PyObject *newEulerObject(float *eul, short order, int type, PyTypeObject *base_type)
 {
        EulerObject *self;
        int x;
@@ -678,12 +649,14 @@ PyObject *newEulerObject(float *eul, int type, PyTypeObject *base_type)
        }else{ //bad type
                return NULL;
        }
+
+       self->order= order;
        return (PyObject *)self;
 }
 
-PyObject *newEulerObject_cb(PyObject *cb_user, int cb_type, int cb_subtype)
+PyObject *newEulerObject_cb(PyObject *cb_user, short order, int cb_type, int cb_subtype)
 {
-       EulerObject *self= (EulerObject *)newEulerObject(NULL, Py_NEW, NULL);
+       EulerObject *self= (EulerObject *)newEulerObject(NULL, order, Py_NEW, NULL);
        if(self) {
                Py_INCREF(cb_user);
                self->cb_user=                  cb_user;
index e9826814165e975705e59d43bc0410f02cea7747..994a5f1780e612295921c4ccf2ca7f2879a125d4 100644 (file)
@@ -45,6 +45,8 @@ typedef struct {
        unsigned char wrapped;          /* wrapped data type? */
        /* end BaseMathObject */
 
+       unsigned char order;            /* rotation order */
+
 } EulerObject;
 
 /*struct data contains a pointer to the actual data that the
@@ -53,7 +55,10 @@ be stored in py_data) or be a wrapper for data allocated through
 blender (stored in blend_data). This is an either/or struct not both*/
 
 //prototypes
-PyObject *newEulerObject( float *eul, int type, PyTypeObject *base_type);
-PyObject *newEulerObject_cb(PyObject *cb_user, int cb_type, int cb_subtype);
+PyObject *newEulerObject( float *eul, short order, int type, PyTypeObject *base_type);
+PyObject *newEulerObject_cb(PyObject *cb_user, short order, int cb_type, int cb_subtype);
+
+short euler_order_from_string(const char *str, const char *error_prefix);
+
 
 #endif                         /* EXPP_euler_h */
index 23906161db2cbabca0227035ac3071ed753155f4..71b471c61edac65e3e23f46d8f40ea5f1aa6a502 100644 (file)
@@ -217,7 +217,7 @@ static PyObject *Matrix_toQuat(MatrixObject * self)
        
        /*must be 3-4 cols, 3-4 rows, square matrix*/
        if(self->colSize < 3 || self->rowSize < 3 || (self->colSize != self->rowSize)) {
-               PyErr_SetString(PyExc_AttributeError, "Matrix.toQuat(): inappropriate matrix size - expects 3x3 or 4x4 matrix");
+               PyErr_SetString(PyExc_AttributeError, "Matrix.to_quat(): inappropriate matrix size - expects 3x3 or 4x4 matrix");
                return NULL;
        } 
        if(self->colSize == 3){
@@ -228,12 +228,15 @@ static PyObject *Matrix_toQuat(MatrixObject * self)
        
        return newQuaternionObject(quat, Py_NEW, NULL);
 }
+
 /*---------------------------Matrix.toEuler() --------------------*/
 static char Matrix_toEuler_doc[] =
-".. method:: to_euler(euler_compat)\n"
+".. method:: to_euler(order, euler_compat)\n"
 "\n"
 "   Return an Euler representation of the rotation matrix (3x3 or 4x4 matrix only).\n"
 "\n"
+"   :arg order: Optional rotation order argument in ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n"
+"   :type order: string\n"
 "   :arg euler_compat: Optional euler argument the new euler will be made compatible with (no axis flipping between them). Useful for converting a series of matrices to animation curves.\n"
 "   :type euler_compat: :class:`Euler`\n"
 "   :return: Euler representation of the matrix.\n"
@@ -241,53 +244,55 @@ static char Matrix_toEuler_doc[] =
 
 PyObject *Matrix_toEuler(MatrixObject * self, PyObject *args)
 {
+       char *order_str= NULL;
+       short order= 0;
        float eul[3], eul_compatf[3];
        EulerObject *eul_compat = NULL;
-#ifdef USE_MATHUTILS_DEG
-       int x;
-#endif
+
+       float tmat[3][3];
+       float (*mat)[3];
        
        if(!BaseMath_ReadCallback(self))
                return NULL;
        
-       if(!PyArg_ParseTuple(args, "|O!:toEuler", &euler_Type, &eul_compat))
+       if(!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat))
                return NULL;
        
        if(eul_compat) {
                if(!BaseMath_ReadCallback(eul_compat))
                        return NULL;
 
-#ifdef USE_MATHUTILS_DEG
-               for(x = 0; x < 3; x++) {
-                       eul_compatf[x] = eul_compat->eul[x] * ((float)Py_PI / 180);
-               }
-#else
                VECCOPY(eul_compatf, eul_compat->eul);
-#endif
        }
        
        /*must be 3-4 cols, 3-4 rows, square matrix*/
        if(self->colSize ==3 && self->rowSize ==3) {
-               if(eul_compat)  mat3_to_compatible_eul( eul, eul_compatf,(float (*)[3])*self->matrix);
-               else                    mat3_to_eul( eul,(float (*)[3])*self->matrix);
+               mat= (float (*)[3])self->matrix;
        }else if (self->colSize ==4 && self->rowSize ==4) {
-               float tempmat3[3][3];
-               copy_m3_m4(tempmat3, (float (*)[4])*self->matrix);
-               mat3_to_eul( eul,tempmat3);
-               if(eul_compat)  mat3_to_compatible_eul( eul, eul_compatf,tempmat3);
-               else                    mat3_to_eul( eul,tempmat3);
-               
+               copy_m3_m4(tmat, (float (*)[4])*self->matrix);
+               mat= tmat;
        }else {
-               PyErr_SetString(PyExc_AttributeError, "Matrix.toEuler(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
+               PyErr_SetString(PyExc_AttributeError, "Matrix.to_euler(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
                return NULL;
        }
-#ifdef USE_MATHUTILS_DEG
-       /*have to convert to degrees*/
-       for(x = 0; x < 3; x++) {
-               eul[x] *= (float) (180 / Py_PI);
+
+       if(order_str) {
+               order= euler_order_from_string(order_str, "Matrix.to_euler()");
+
+               if(order < 0)
+                       return NULL;
+       }
+
+       if(eul_compat) {
+               if(order == 0)  mat3_to_compatible_eul( eul, eul_compatf, mat);
+               else                    mat3_to_compatible_eulO(eul, eul_compatf, order, mat);
+       }
+       else {
+               if(order == 0)  mat3_to_eul(eul, mat);
+               else                    mat3_to_eulO(eul, order, mat);
        }
-#endif
-       return newEulerObject(eul, Py_NEW, NULL);
+
+       return newEulerObject(eul, order, Py_NEW, NULL);
 }
 /*---------------------------Matrix.resize4x4() ------------------*/
 static char Matrix_Resize4x4_doc[] =
@@ -367,21 +372,15 @@ static char Matrix_TranslationPart_doc[] =
 
 PyObject *Matrix_TranslationPart(MatrixObject * self)
 {
-       float vec[4];
-       
        if(!BaseMath_ReadCallback(self))
                return NULL;
        
        if(self->colSize < 3 || self->rowSize < 4){
-               PyErr_SetString(PyExc_AttributeError, "Matrix.translationPart: inappropriate matrix size");
+               PyErr_SetString(PyExc_AttributeError, "Matrix.translation_part(): inappropriate matrix size");
                return NULL;
        }
 
-       vec[0] = self->matrix[3][0];
-       vec[1] = self->matrix[3][1];
-       vec[2] = self->matrix[3][2];
-
-       return newVectorObject(vec, 3, Py_NEW, NULL);
+       return newVectorObject(self->matrix[3], 3, Py_NEW, NULL);
 }
 /*---------------------------Matrix.rotationPart() ---------------*/
 static char Matrix_RotationPart_doc[] =
@@ -403,7 +402,7 @@ PyObject *Matrix_RotationPart(MatrixObject * self)
                return NULL;
 
        if(self->colSize < 3 || self->rowSize < 3){
-               PyErr_SetString(PyExc_AttributeError, "Matrix.rotationPart: inappropriate matrix size\n");
+               PyErr_SetString(PyExc_AttributeError, "Matrix.rotation_part(): inappropriate matrix size\n");
                return NULL;
        }
 
@@ -444,7 +443,7 @@ PyObject *Matrix_scalePart(MatrixObject * self)
        else if(self->colSize == 3 && self->rowSize == 3)
                copy_m3_m3(mat, (float (*)[3])*self->matrix);
        else {
-               PyErr_SetString(PyExc_AttributeError, "Matrix.scalePart(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
+               PyErr_SetString(PyExc_AttributeError, "Matrix.scale_part(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
                return NULL;
        }
        /* functionality copied from editobject.c apply_obmat */
index ee9dd6606ac472085aab0e59da335cc799bdb4a1..7a8733c970fd507abaebb049494897d0580196a7 100644 (file)
 
 //-----------------------------METHODS------------------------------
 static char Quaternion_ToEuler_doc[] =
-".. method:: to_euler(euler_compat)\n"
+".. method:: to_euler(order, euler_compat)\n"
 "\n"
 "   Return Euler representation of the quaternion.\n"
 "\n"
+"   :arg order: Optional rotation order argument in ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n"
+"   :type order: string\n"
 "   :arg euler_compat: Optional euler argument the new euler will be made compatible with (no axis flipping between them). Useful for converting a series of matrices to animation curves.\n"
 "   :type euler_compat: :class:`Euler`\n"
 "   :return: Euler representation of the quaternion.\n"
@@ -46,50 +48,40 @@ static char Quaternion_ToEuler_doc[] =
 static PyObject *Quaternion_ToEuler(QuaternionObject * self, PyObject *args)
 {
        float eul[3];
+       char *order_str= NULL;
+       short order= 0;
        EulerObject *eul_compat = NULL;
        
-       if(!PyArg_ParseTuple(args, "|O!:toEuler", &euler_Type, &eul_compat))
+       if(!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat))
                return NULL;
        
        if(!BaseMath_ReadCallback(self))
                return NULL;
 
+       if(order_str) {
+               order= euler_order_from_string(order_str, "Matrix.to_euler()");
+
+               if(order < 0)
+                       return NULL;
+       }
+
        if(eul_compat) {
                float mat[3][3];
                
                if(!BaseMath_ReadCallback(eul_compat))
                        return NULL;
                
-               quat_to_mat3( mat,self->quat);
-
-#ifdef USE_MATHUTILS_DEG
-               {
-                       float  eul_compatf[3];
-                       int x;
+               quat_to_mat3(mat, self->quat);
 
-                       for(x = 0; x < 3; x++) {
-                               eul_compatf[x] = eul_compat->eul[x] * ((float)Py_PI / 180);
-                       }
-                       mat3_to_compatible_eul( eul, eul_compatf,mat);
-               }
-#else
-               mat3_to_compatible_eul( eul, eul_compat->eul,mat);
-#endif
+               if(order == 0)  mat3_to_compatible_eul(eul, eul_compat->eul, mat);
+               else                    mat3_to_compatible_eulO(eul, order, eul_compat->eul, mat);
        }
        else {
-               quat_to_eul( eul,self->quat);
+               if(order == 0)  quat_to_eul(eul, self->quat);
+               else                    quat_to_eulO(eul, order, self->quat);
        }
        
-#ifdef USE_MATHUTILS_DEG
-       {
-               int x;
-
-               for(x = 0; x < 3; x++) {
-                       eul[x] *= (180 / (float)Py_PI);
-               }
-       }
-#endif
-       return newEulerObject(eul, Py_NEW, NULL);
+       return newEulerObject(eul, order, Py_NEW, NULL);
 }
 //----------------------------Quaternion.toMatrix()------------------
 static char Quaternion_ToMatrix_doc[] =
@@ -218,8 +210,8 @@ static PyObject *Quaternion_Slerp(QuaternionObject *self, PyObject *args)
        QuaternionObject *value;
        float quat[4], fac;
 
-       if(!PyArg_ParseTuple(args, "O!f", &quaternion_Type, &value, &fac)) {
-               PyErr_SetString(PyExc_TypeError, "Mathutils.Slerp(): expected Quaternion types and float");
+       if(!PyArg_ParseTuple(args, "O!f:slerp", &quaternion_Type, &value, &fac)) {
+               PyErr_SetString(PyExc_TypeError, "quat.slerp(): expected Quaternion types and float");
                return NULL;
        }
 
@@ -227,7 +219,7 @@ static PyObject *Quaternion_Slerp(QuaternionObject *self, PyObject *args)
                return NULL;
 
        if(fac > 1.0f || fac < 0.0f) {
-               PyErr_SetString(PyExc_AttributeError, "Mathutils.Slerp(): interpolation factor must be between 0.0 and 1.0");
+               PyErr_SetString(PyExc_AttributeError, "quat.slerp(): interpolation factor must be between 0.0 and 1.0");
                return NULL;
        }
 
@@ -698,12 +690,7 @@ static PyObject *Quaternion_getMagnitude( QuaternionObject * self, void *type )
 
 static PyObject *Quaternion_getAngle( QuaternionObject * self, void *type )
 {
-       double ang = self->quat[0];
-       ang = 2 * (saacos(ang));
-#ifdef USE_MATHUTILS_DEG
-       ang *= (180 / Py_PI);
-#endif
-       return PyFloat_FromDouble(ang);
+       return PyFloat_FromDouble(2.0 * (saacos(self->quat[0])));
 }
 
 static PyObject *Quaternion_getAxisVec( QuaternionObject * self, void *type )
@@ -815,11 +802,7 @@ static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kw
        }
 
        if(size == 3) //calculate the quat based on axis/angle
-#ifdef USE_MATHUTILS_DEG
-               axis_angle_to_quat(quat, quat, angle * (Py_PI / 180));
-#else
                axis_angle_to_quat(quat, quat, angle);
-#endif
 
        return newQuaternionObject(quat, Py_NEW, NULL);
 }
index 06e0a0480b47910e36744b0c3c4de476545dd5b3..d5ff44ae5ad6add9193f974b0fb0897b0a373b3f 100644 (file)
@@ -159,17 +159,17 @@ static char Vector_Resize2D_doc[] =
 static PyObject *Vector_Resize2D(VectorObject * self)
 {
        if(self->wrapped==Py_WRAP) {
-               PyErr_SetString(PyExc_TypeError, "vector.resize2d(): cannot resize wrapped data - only python vectors\n");
+               PyErr_SetString(PyExc_TypeError, "vector.resize2D(): cannot resize wrapped data - only python vectors\n");
                return NULL;
        }
        if(self->cb_user) {
-               PyErr_SetString(PyExc_TypeError, "vector.resize2d(): cannot resize a vector that has an owner");
+               PyErr_SetString(PyExc_TypeError, "vector.resize2D(): cannot resize a vector that has an owner");
                return NULL;
        }
        
        self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 2));
        if(self->vec == NULL) {
-               PyErr_SetString(PyExc_MemoryError, "vector.resize2d(): problem allocating pointer space\n\n");
+               PyErr_SetString(PyExc_MemoryError, "vector.resize2D(): problem allocating pointer space\n\n");
                return NULL;
        }
        
@@ -189,17 +189,17 @@ static char Vector_Resize3D_doc[] =
 static PyObject *Vector_Resize3D(VectorObject * self)
 {
        if (self->wrapped==Py_WRAP) {
-               PyErr_SetString(PyExc_TypeError, "vector.resize3d(): cannot resize wrapped data - only python vectors\n");
+               PyErr_SetString(PyExc_TypeError, "vector.resize3D(): cannot resize wrapped data - only python vectors\n");
                return NULL;
        }
        if(self->cb_user) {
-               PyErr_SetString(PyExc_TypeError, "vector.resize3d(): cannot resize a vector that has an owner");
+               PyErr_SetString(PyExc_TypeError, "vector.resize3D(): cannot resize a vector that has an owner");
                return NULL;
        }
        
        self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 3));
        if(self->vec == NULL) {
-               PyErr_SetString(PyExc_MemoryError, "vector.resize3d(): problem allocating pointer space\n\n");
+               PyErr_SetString(PyExc_MemoryError, "vector.resize3D(): problem allocating pointer space\n\n");
                return NULL;
        }
        
@@ -222,17 +222,17 @@ static char Vector_Resize4D_doc[] =
 static PyObject *Vector_Resize4D(VectorObject * self)
 {
        if(self->wrapped==Py_WRAP) {
-               PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize wrapped data - only python vectors");
+               PyErr_SetString(PyExc_TypeError, "vector.resize4D(): cannot resize wrapped data - only python vectors");
                return NULL;
        }
        if(self->cb_user) {
-               PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize a vector that has an owner");
+               PyErr_SetString(PyExc_TypeError, "vector.resize4D(): cannot resize a vector that has an owner");
                return NULL;
        }
        
        self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 4));
        if(self->vec == NULL) {
-               PyErr_SetString(PyExc_MemoryError, "vector.resize4d(): problem allocating pointer space\n\n");
+               PyErr_SetString(PyExc_MemoryError, "vector.resize4D(): problem allocating pointer space\n\n");
                return NULL;
        }
        if(self->size == 2){
@@ -265,7 +265,7 @@ static PyObject *Vector_ToTuple(VectorObject * self, PyObject *value)
        PyObject *ret;
 
        if(ndigits > 22 || ndigits < 0) { /* accounts for non ints */
-               PyErr_SetString(PyExc_TypeError, "vector.key(ndigits): ndigits must be between 0 and 21");
+               PyErr_SetString(PyExc_TypeError, "vector.to_tuple(ndigits): ndigits must be between 0 and 21");
                return NULL;
        }
 
@@ -300,7 +300,7 @@ static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args )
        char *strack, *sup;
        short track = 2, up = 1;
 
-       if( !PyArg_ParseTuple ( args, "|ss", &strack, &sup ) ) {
+       if(!PyArg_ParseTuple( args, "|ss:to_track_quat", &strack, &sup)) {
                PyErr_SetString( PyExc_TypeError, "expected optional two strings\n" );
                return NULL;
        }
@@ -558,11 +558,7 @@ static PyObject *Vector_Angle(VectorObject * self, VectorObject * value)
 
        angleRads = (double)saacos(dot);
 
-#ifdef USE_MATHUTILS_DEG
-       return PyFloat_FromDouble(angleRads * (180/ Py_PI));
-#else
        return PyFloat_FromDouble(angleRads);
-#endif
 }
 
 static char Vector_Difference_doc[] =
@@ -666,12 +662,12 @@ static PyObject *Vector_Lerp(VectorObject * self, PyObject * args)
        float fac, ifac, vec[4];
        int x;
 
-       if(!PyArg_ParseTuple(args, "O!f", &vector_Type, &vec2, &fac)) {
+       if(!PyArg_ParseTuple(args, "O!f:lerp", &vector_Type, &vec2, &fac)) {
                PyErr_SetString(PyExc_TypeError, "vector.lerp(): expects a vector of the same size and float");
                return NULL;
        }
        if(self->size != vec2->size) {
-               PyErr_SetString(PyExc_AttributeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size");
+               PyErr_SetString(PyExc_AttributeError, "vector.lerp(): expects (2) vector objects of the same size");
                return NULL;
        }
 
index 9b754f9e635b3f21c3c3cc478e7d9cb9ddbcdb7a..31c2f548c856b466d27108047aae2b159d2efb0d 100644 (file)
@@ -65,6 +65,11 @@ static Py_ssize_t pyrna_prop_collection_length( BPy_PropertyRNA *self );
 /* bpyrna vector/euler/quat callbacks */
 static int mathutils_rna_array_cb_index= -1; /* index for our callbacks */
 
+/* not used yet but may want to use the subtype below */
+#define MATHUTILS_CB_SUBTYPE_EUL 0
+#define MATHUTILS_CB_SUBTYPE_VEC 1
+#define MATHUTILS_CB_SUBTYPE_QUAT 2
+
 static int mathutils_rna_generic_check(BPy_PropertyRNA *self)
 {
        return self->prop?1:0;
@@ -181,7 +186,7 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
                                        RNA_property_float_get_array(ptr, prop, ((VectorObject *)ret)->vec);
                                }
                                else {
-                                       PyObject *vec_cb= newVectorObject_cb(ret, len, mathutils_rna_array_cb_index, FALSE);
+                                       PyObject *vec_cb= newVectorObject_cb(ret, len, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_VEC);
                                        Py_DECREF(ret); /* the vector owns now */
                                        ret= vec_cb; /* return the vector instead */
                                }
@@ -215,11 +220,11 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
                case PROP_QUATERNION:
                        if(len==3) { /* euler */
                                if(is_thick) {
-                                       ret= newEulerObject(NULL, Py_NEW, NULL);
+                                       ret= newEulerObject(NULL, 0, Py_NEW, NULL); // TODO, get order from RNA
                                        RNA_property_float_get_array(ptr, prop, ((EulerObject *)ret)->eul);
                                }
                                else {
-                                       PyObject *eul_cb= newEulerObject_cb(ret, mathutils_rna_array_cb_index, FALSE);
+                                       PyObject *eul_cb= newEulerObject_cb(ret, 0, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_EUL); // TODO, get order from RNA
                                        Py_DECREF(ret); /* the matrix owns now */
                                        ret= eul_cb; /* return the matrix instead */
                                }
@@ -230,7 +235,7 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
                                        RNA_property_float_get_array(ptr, prop, ((QuaternionObject *)ret)->quat);
                                }
                                else {
-                                       PyObject *quat_cb= newQuaternionObject_cb(ret, mathutils_rna_array_cb_index, FALSE);
+                                       PyObject *quat_cb= newQuaternionObject_cb(ret, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_QUAT);
                                        Py_DECREF(ret); /* the matrix owns now */
                                        ret= quat_cb; /* return the matrix instead */
                                }