From 4b914c7f75faa65a7d2a991b7904c18051d13a13 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 25 Jun 2009 20:47:41 +0000 Subject: Made Mathutils use radians rather then degrees. defining USE_MATHUTILS_DEG for testing existing scripts. 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 | 17 ++++++++++-- source/blender/python/generic/Mathutils.h | 2 ++ source/blender/python/generic/euler.c | 34 +++++++++++++++++++---- source/blender/python/generic/matrix.c | 8 +++++- source/blender/python/generic/quat.c | 29 ++++++++++++------- source/blender/python/generic/vector.c | 2 +- source/gameengine/Converter/BL_ActionActuator.cpp | 6 ++-- source/gameengine/Ketsji/KX_PyMath.cpp | 26 ++++++++++++++++- source/gameengine/Ketsji/KX_PyMath.h | 20 +++++++++++++ 9 files changed, 120 insertions(+), 24 deletions(-) diff --git a/source/blender/python/generic/Mathutils.c b/source/blender/python/generic/Mathutils.c index d7330ac46c0..ec94a48ddbd 100644 --- a/source/blender/python/generic/Mathutils.c +++ b/source/blender/python/generic/Mathutils.c @@ -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); diff --git a/source/blender/python/generic/Mathutils.h b/source/blender/python/generic/Mathutils.h index d234ebf1452..6a4e28d6068 100644 --- a/source/blender/python/generic/Mathutils.h +++ b/source/blender/python/generic/Mathutils.h @@ -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 { diff --git a/source/blender/python/generic/euler.c b/source/blender/python/generic/euler.c index eb9358774e1..9041eb84a3d 100644 --- a/source/blender/python/generic/euler.c +++ b/source/blender/python/generic/euler.c @@ -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; diff --git a/source/blender/python/generic/matrix.c b/source/blender/python/generic/matrix.c index ef4f7280cdc..b546aa1226c 100644 --- a/source/blender/python/generic/matrix.c +++ b/source/blender/python/generic/matrix.c @@ -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() ------------------*/ diff --git a/source/blender/python/generic/quat.c b/source/blender/python/generic/quat.c index b1e9f4a1d31..e7413d38ee5 100644 --- a/source/blender/python/generic/quat.c +++ b/source/blender/python/generic/quat.c @@ -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); } diff --git a/source/blender/python/generic/vector.c b/source/blender/python/generic/vector.c index d68d3f41370..9ce0a7ca2f9 100644 --- a/source/blender/python/generic/vector.c +++ b/source/blender/python/generic/vector.c @@ -1771,7 +1771,7 @@ PyTypeObject vector_Type = { 0, /* ob_size */ #endif /* For printing, in format "." */ - "Blender Vector", /* char *tp_name; */ + "vector", /* char *tp_name; */ sizeof( VectorObject ), /* int tp_basicsize; */ 0, /* tp_itemsize; For allocation */ diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp index c0d28d28bda..ce4311f57bf 100644 --- a/source/gameengine/Converter/BL_ActionActuator.cpp +++ b/source/gameengine/Converter/BL_ActionActuator.cpp @@ -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; diff --git a/source/gameengine/Ketsji/KX_PyMath.cpp b/source/gameengine/Ketsji/KX_PyMath.cpp index ee9fed5d30a..76cfb0e572d 100644 --- a/source/gameengine/Ketsji/KX_PyMath.cpp +++ b/source/gameengine/Ketsji/KX_PyMath.cpp @@ -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 diff --git a/source/gameengine/Ketsji/KX_PyMath.h b/source/gameengine/Ketsji/KX_PyMath.h index 90a13425aa0..f37925bb0ab 100644 --- a/source/gameengine/Ketsji/KX_PyMath.h +++ b/source/gameengine/Ketsji/KX_PyMath.h @@ -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. */ -- cgit v1.2.3