Mathutils API: Euler support for rotation order.
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
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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[];
|
||||
|
||||
@@ -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;
|
||||
if(self->order==0) eul_to_mat3((float (*)[3])mat, self->eul);
|
||||
else eulO_to_mat3((float (*)[3])mat, self->eul, self->order);
|
||||
|
||||
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
|
||||
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
|
||||
compatible_eul(self->eul, value->eul);
|
||||
|
||||
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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
#endif
|
||||
return newEulerObject(eul, Py_NEW, 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);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
@@ -34,10 +34,12 @@
|
||||
|
||||
//-----------------------------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,14 +48,23 @@ 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];
|
||||
|
||||
@@ -62,34 +73,15 @@ static PyObject *Quaternion_ToEuler(QuaternionObject * self, PyObject *args)
|
||||
|
||||
quat_to_mat3(mat, self->quat);
|
||||
|
||||
#ifdef USE_MATHUTILS_DEG
|
||||
{
|
||||
float eul_compatf[3];
|
||||
int x;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user