Made Mathutils use radians rather then degrees. defining USE_MATHUTILS_DEG for testin...
authorCampbell Barton <ideasman42@gmail.com>
Thu, 25 Jun 2009 20:47:41 +0000 (20:47 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 25 Jun 2009 20:47:41 +0000 (20:47 +0000)
Added conversion for BGE Quaternion WXYZ (Blender/C) -> XYZW (Moto C++).
BGE Python API now uses WXYZ following mathutils (break script warning).

source/blender/python/generic/Mathutils.c
source/blender/python/generic/Mathutils.h
source/blender/python/generic/euler.c
source/blender/python/generic/matrix.c
source/blender/python/generic/quat.c
source/blender/python/generic/vector.c
source/gameengine/Converter/BL_ActionActuator.cpp
source/gameengine/Ketsji/KX_PyMath.cpp
source/gameengine/Ketsji/KX_PyMath.h

index d7330ac46c02d218b60bd3525a19ffa5e8f4b759..ec94a48ddbd4e57bfc1c9fee248bdb1f16534324 100644 (file)
@@ -275,8 +275,11 @@ static PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args)
 
        angleRads = (double)saacos(dot);
 
+#ifdef USE_MATHUTILS_DEG
        return PyFloat_FromDouble(angleRads * (180/ Py_PI));
-
+#else
+       return PyFloat_FromDouble(angleRads);
+#endif
 AttributeError1:
        PyErr_SetString(PyExc_AttributeError, "Mathutils.AngleBetweenVecs(): expects (2) VECTOR objects of the same size\n");
        return NULL;
@@ -364,12 +367,19 @@ static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args)
                PyErr_SetString(PyExc_TypeError, "Mathutils.RotationMatrix(): expected float int and optional string and vector\n");
                return NULL;
        }
-       
+
+#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");
@@ -399,8 +409,11 @@ 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
+
        if(axis == NULL && matSize == 2) {
                //2D rotation matrix
                mat[0] = (float) cos (angle);
index d234ebf1452a223a2fedb73a7d4d6d9c8a4edd35..6a4e28d6068e5e32d6b76b401c84284f484750b2 100644 (file)
@@ -38,6 +38,8 @@
 #include "quat.h"
 #include "euler.h"
 
+/* #define USE_MATHUTILS_DEG - for backwards compat */
+
 /* Can cast different mathutils types to this, use for generic funcs */
 
 typedef struct {
index eb9358774e156cee9042f6dc9dad8cb9f240b612..9041eb84a3d05c9040044c0a3334a0bac2ae66c0 100644 (file)
@@ -70,7 +70,7 @@ static PyObject *Euler_new(PyObject * self, PyObject * args)
 
        PyObject *listObject = NULL;
        int size, i;
-       float eul[3], scalar;
+       float eul[3];
        PyObject *e;
 
        size = PyTuple_GET_SIZE(args);
@@ -102,15 +102,13 @@ static PyObject *Euler_new(PyObject * self, PyObject * args)
                        return NULL;
                }
 
-               scalar= (float)PyFloat_AsDouble(e);
+               eul[i]= (float)PyFloat_AsDouble(e);
                Py_DECREF(e);
                
-               if(scalar==-1 && PyErr_Occurred()) { // parsed item is not a number
+               if(eul[i]==-1 && PyErr_Occurred()) { // parsed item is not a number
                        PyErr_SetString(PyExc_TypeError, "Mathutils.Euler(): 3d numeric sequence expected\n");
                        return NULL;
                }
-
-               eul[i]= scalar;
        }
        return newEulerObject(eul, Py_NEW);
 }
@@ -126,10 +124,15 @@ static PyObject *Euler_ToQuat(EulerObject * self)
        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);
        }
        EulToQuat(eul, quat);
+#else
+       EulToQuat(self->eul, quat);
+#endif
+
        return newQuaternionObject(quat, Py_NEW);
 }
 //----------------------------Euler.toMatrix()---------------------
@@ -143,10 +146,14 @@ static PyObject *Euler_ToMatrix(EulerObject * self)
        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);
        }
        EulToMat3(eul, (float (*)[3]) mat);
+#else
+       EulToMat3(self->eul, (float (*)[3]) mat);
+#endif
        return newMatrixObject(mat, 3, 3 , Py_NEW);
 }
 //----------------------------Euler.unique()-----------------------
@@ -161,10 +168,12 @@ 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;
+#endif
 
        //wrap heading in +180 / -180
        pitch += Py_PI;
@@ -195,10 +204,12 @@ static PyObject *Euler_Unique(EulerObject * self)
        heading -= (floor(heading * Opi2)) * pi2;
        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);
@@ -237,16 +248,21 @@ static PyObject *Euler_Rotate(EulerObject * self, PyObject *args)
        if(!BaseMath_ReadCallback(self))
                return NULL;
 
+#ifdef USE_MATHUTILS_DEG
        //covert to radians
        angle *= ((float)Py_PI / 180);
        for(x = 0; x < 3; x++) {
                self->eul[x] *= ((float)Py_PI / 180);
        }
+#endif
        euler_rot(self->eul, angle, *axis);
+
+#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);
@@ -266,17 +282,23 @@ static PyObject *Euler_MakeCompatible(EulerObject * self, EulerObject *value)
        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);
        }
        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;
index ef4f7280cdc5acec0967398ac3fbdbfd3fc2d2fa..b546aa1226c5ec76e0c3a545bc5668c3f18594cf 100644 (file)
@@ -257,10 +257,14 @@ PyObject *Matrix_toEuler(MatrixObject * self, PyObject *args)
        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*/
@@ -278,10 +282,12 @@ PyObject *Matrix_toEuler(MatrixObject * self, PyObject *args)
                PyErr_SetString(PyExc_AttributeError, "Matrix.toEuler(): 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);
        }
+#endif
        return newEulerObject(eul, Py_NEW);
 }
 /*---------------------------Matrix.resize4x4() ------------------*/
index b1e9f4a1d312760287a89aff6defc8493ad06460..e7413d38ee5a424b33dbca1fefcde35e19118c97 100644 (file)
@@ -77,7 +77,7 @@ static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kw
 {
        PyObject *listObject = NULL, *n, *q;
        int size, i;
-       float quat[4], scalar;
+       float quat[4];
        double angle = 0.0f;
 
        size = PyTuple_GET_SIZE(args);
@@ -151,19 +151,21 @@ static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kw
                        return NULL;
                }
 
-               scalar = PyFloat_AsDouble(q);
+               quat[i] = PyFloat_AsDouble(q);
                Py_DECREF(q);
 
-               if (scalar==-1 && PyErr_Occurred()) {
+               if (quat[i]==-1 && PyErr_Occurred()) {
                        PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
                        return NULL;
                }
-               quat[i] = scalar;
        }
 
        if(size == 3) //calculate the quat based on axis/angle
-               AxisAngleToQuat(quat, quat, angle * (Py_PI / 180)); // TODO - 2.5 use radians, note using quat for src and target is ok here
-
+#ifdef USE_MATHUTILS_DEG
+               AxisAngleToQuat(quat, quat, angle * (Py_PI / 180));
+#else
+               AxisAngleToQuat(quat, quat, angle);
+#endif
 
        return newQuaternionObject(quat, Py_NEW);
 }
@@ -189,28 +191,33 @@ static PyObject *Quaternion_ToEuler(QuaternionObject * self, PyObject *args)
                if(!BaseMath_ReadCallback(eul_compat))
                        return NULL;
                
+               QuatToMat3(self->quat, mat);
+
+#ifdef USE_MATHUTILS_DEG
                for(x = 0; x < 3; x++) {
                        eul_compatf[x] = eul_compat->eul[x] * ((float)Py_PI / 180);
                }
-               
-               QuatToMat3(self->quat, mat);
                Mat3ToCompatibleEul(mat, eul, eul_compatf);
+#else
+               Mat3ToCompatibleEul(mat, eul, eul_compat->eul);
+#endif
        }
        else {
                QuatToEul(self->quat, eul);
        }
        
-       
+#ifdef USE_MATHUTILS_DEG
        for(x = 0; x < 3; x++) {
                eul[x] *= (180 / (float)Py_PI);
        }
+#endif
        return newEulerObject(eul, Py_NEW);
 }
 //----------------------------Quaternion.toMatrix()------------------
 //return the quat as a matrix
 static PyObject *Quaternion_ToMatrix(QuaternionObject * self)
 {
-       float mat[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
+       float mat[9]; /* all values are set */
 
        if(!BaseMath_ReadCallback(self))
                return NULL;
@@ -662,7 +669,9 @@ 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);
 }
 
index d68d3f4137074cfab1bcaa40e84b9c37e0d26ada..9ce0a7ca2f9ee329808f95fc7df11e15c7e1a739 100644 (file)
@@ -1771,7 +1771,7 @@ PyTypeObject vector_Type = {
        0,                          /* ob_size */
 #endif
        /*  For printing, in format "<module>.<name>" */
-       "Blender Vector",             /* char *tp_name; */
+       "vector",             /* char *tp_name; */
        sizeof( VectorObject ),         /* int tp_basicsize; */
        0,                          /* tp_itemsize;  For allocation */
 
index c0d28d28bda4323071f4cb0a2d5b98f25410d23c..ce4311f57bf4ebfb6a8bc5720adf35a252cd3a2e 100644 (file)
@@ -962,9 +962,9 @@ KX_PYMETHODDEF_DOC(BL_ActionActuator, setChannel,
        else {
                MT_Vector3 loc;
                MT_Vector3 size;
-               MT_Vector4 quat;
+               MT_Quaternion quat;
                
-               if (!PyVecTo(pyloc, loc) || !PyVecTo(pysize, size) || !PyVecTo(pyquat, quat))
+               if (!PyVecTo(pyloc, loc) || !PyVecTo(pysize, size) || !PyQuatTo(pyquat, quat))
                        return NULL;
                
                // same as above
@@ -977,7 +977,7 @@ KX_PYMETHODDEF_DOC(BL_ActionActuator, setChannel,
                // for some reason loc.setValue(pchan->loc) fails
                pchan->loc[0]= loc[0]; pchan->loc[1]= loc[1]; pchan->loc[2]= loc[2];
                pchan->size[0]= size[0]; pchan->size[1]= size[1]; pchan->size[2]= size[2];
-               pchan->quat[0]= quat[0]; pchan->quat[1]= quat[1]; pchan->quat[2]= quat[2]; pchan->quat[3]= quat[3];
+               pchan->quat[0]= quat[3]; pchan->quat[1]= quat[0]; pchan->quat[2]= quat[1]; pchan->quat[3]= quat[2]; /* notice xyzw -> wxyz is intentional */
        }
        
        pchan->flag |= POSE_ROT|POSE_LOC|POSE_SIZE;
index ee9fed5d30a4493a37f4d9e6664194869517726b..76cfb0e572d443eaf8b807d9422582b471647db2 100644 (file)
@@ -53,7 +53,7 @@ bool PyOrientationTo(PyObject* pyval, MT_Matrix3x3 &rot, const char *error_prefi
        if (size == 4)
        {
                MT_Quaternion qrot;
-               if (PyVecTo(pyval, qrot))
+               if (PyQuatTo(pyval, qrot))
                {
                        rot.setRotation(qrot);
                        return true;
@@ -79,6 +79,21 @@ bool PyOrientationTo(PyObject* pyval, MT_Matrix3x3 &rot, const char *error_prefi
        return false;
 }
 
+bool PyQuatTo(PyObject* pyval, MT_Quaternion &qrot)
+{
+       if(!PyVecTo(pyval, qrot))
+               return false;
+
+       /* annoying!, Blender/Mathutils have the W axis first! */
+       MT_Scalar w= qrot[0]; /* from python, this is actually the W */
+       qrot[0]= qrot[1];
+       qrot[1]= qrot[2];
+       qrot[2]= qrot[3];
+       qrot[3]= w;
+
+       return true;
+}
+
 PyObject* PyObjectFrom(const MT_Matrix4x4 &mat)
 {
 #ifdef USE_MATHUTILS
@@ -126,6 +141,15 @@ PyObject* PyObjectFrom(const MT_Matrix3x3 &mat)
 #endif
 }
 
+#ifdef USE_MATHUTILS
+PyObject* PyObjectFrom(const MT_Quaternion &qrot)
+{
+       /* NOTE, were re-ordering here for Mathutils compat */
+       float fvec[4]= {qrot[3], qrot[0], qrot[1], qrot[2]};
+       return newQuaternionObject(fvec, Py_WRAP);
+}
+#endif
+
 PyObject* PyObjectFrom(const MT_Tuple4 &vec)
 {
 #ifdef USE_MATHUTILS
index 90a13425aa04a45ae6dcfb9fc82df3e2923193a4..f37925bb0ab9ff298529a481705f7ed0934e9973 100644 (file)
@@ -116,6 +116,16 @@ bool PyVecTo(PyObject* pyval, T& vec)
                vec.getValue((float *) pyvec->vec);
                return true;
        }
+       else if(QuaternionObject_Check(pyval)) {
+               QuaternionObject *pyquat= (QuaternionObject *)pyval;
+               if (4 != Size(vec)) {
+                       PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", 4, Size(vec));
+                       return false;
+               }
+               /* xyzw -> wxyz reordering is done by PyQuatTo */
+               vec.getValue((float *) pyquat->quat);
+               return true;
+       }
        else if(EulerObject_Check(pyval)) {
                EulerObject *pyeul= (EulerObject *)pyval;
                if (3 != Size(vec)) {
@@ -186,6 +196,9 @@ bool PyVecTo(PyObject* pyval, T& vec)
        return false;
 }
 
+
+bool PyQuatTo(PyObject* pyval, MT_Quaternion &qrot);
+
 bool PyOrientationTo(PyObject* pyval, MT_Matrix3x3 &mat, const char *error_prefix);
 
 /**
@@ -208,6 +221,13 @@ PyObject* PyObjectFrom(const MT_Tuple2 &vec);
  */
 PyObject* PyObjectFrom(const MT_Tuple3 &vec);
 
+#ifdef USE_MATHUTILS
+/**
+ * Converts an MT_Quaternion to a python object.
+ */
+PyObject* PyObjectFrom(const MT_Quaternion &qrot);
+#endif
+
 /**
  * Converts an MT_Tuple4 to a python object.
  */