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).
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() ------------------*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user