diff options
author | Joseph Gilbert <ascotan@gmail.com> | 2004-02-29 16:20:34 +0300 |
---|---|---|
committer | Joseph Gilbert <ascotan@gmail.com> | 2004-02-29 16:20:34 +0300 |
commit | 8f3a9815baafb6f8fe00659cf6390a8c4092ef8b (patch) | |
tree | 9a69af7bffd6fd0d7da8e998d74a37dc273628a2 /source/blender/python/api2_2x/euler.c | |
parent | 2255ac3b19ec3b2aa0e884ad5960f34c9c0efa23 (diff) |
Mathutils library for the python API
- support for quaternions, euler, vector, matrix operations.
- euler supports unique rotation calculation
- new matrix memory construction and internal functions
- quaternion slerp and diff calculation
- 2d, 3d, 4d vector construction and handling
- full conversion support between types
- update to object/window to reflect to matrix type
- update to types/blender/module to reflect new module
Diffstat (limited to 'source/blender/python/api2_2x/euler.c')
-rw-r--r-- | source/blender/python/api2_2x/euler.c | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/source/blender/python/api2_2x/euler.c b/source/blender/python/api2_2x/euler.c new file mode 100644 index 00000000000..c6c8d61f9f3 --- /dev/null +++ b/source/blender/python/api2_2x/euler.c @@ -0,0 +1,331 @@ +/* + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "euler.h" + +//doc strings +char Euler_Zero_doc[] = +"() - set all values in the euler to 0"; +char Euler_Unique_doc[] = +"() - sets the euler rotation a unique shortest arc rotation - tests for gimbal lock"; +char Euler_ToMatrix_doc[] = +"() - returns a rotation matrix representing the euler rotation"; +char Euler_ToQuat_doc[] = +"() - returns a quaternion representing the euler rotation"; + +//methods table +struct PyMethodDef Euler_methods[] = { + {"zero",(PyCFunction)Euler_Zero, METH_NOARGS, + Euler_Zero_doc}, + {"unique",(PyCFunction)Euler_Unique, METH_NOARGS, + Euler_Unique_doc}, + {"toMatrix",(PyCFunction)Euler_ToMatrix, METH_NOARGS, + Euler_ToMatrix_doc}, + {"toQuat",(PyCFunction)Euler_ToQuat, METH_NOARGS, + Euler_ToQuat_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************/ +// Euler Python Object +/*****************************/ + +//euler methods +PyObject *Euler_ToQuat(EulerObject *self) +{ + float *quat; + int x; + + for(x = 0; x < 3; x++){ + self->eul[x] *= (float)(Py_PI/180); + } + quat = PyMem_Malloc(4*sizeof(float)); + EulToQuat(self->eul, quat); + for(x = 0; x < 3; x++){ + self->eul[x] *= (float)(180/Py_PI); + } + return (PyObject*)newQuaternionObject(quat); +} + +PyObject *Euler_ToMatrix(EulerObject *self) +{ + float *mat; + int x; + + for(x = 0; x < 3; x++){ + self->eul[x] *= (float)(Py_PI/180); + } + mat = PyMem_Malloc(3*3*sizeof(float)); + EulToMat3(self->eul, (float(*)[3])mat); + for(x = 0; x < 3; x++){ + self->eul[x] *= (float)(180/Py_PI); + } + return (PyObject*)newMatrixObject(mat,3,3); +} + +PyObject *Euler_Unique(EulerObject *self) +{ + float heading, pitch, bank; + float pi2 = (float)Py_PI * 2.0f; + float piO2 = (float)Py_PI / 2.0f; + float Opi2 = 1.0f / pi2; + + //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); + + //wrap heading in +180 / -180 + pitch += (float)Py_PI; + pitch -= (float)floor(pitch * Opi2) * pi2; + pitch -= (float)Py_PI; + + + if(pitch < -piO2){ + pitch = (float)-Py_PI - pitch; + heading += (float)Py_PI; + bank += (float)Py_PI; + }else if (pitch > piO2){ + pitch = (float)Py_PI - pitch; + heading += (float)Py_PI; + bank += (float)Py_PI; + } + + //gimbal lock test + if(fabs(pitch) > piO2 - 1e-4){ + heading += bank; + bank = 0.0f; + }else{ + bank += (float)Py_PI; + bank -= (float)(floor(bank * Opi2)) * pi2; + bank -= (float)Py_PI; + } + + heading += (float)Py_PI; + heading -= (float)(floor(heading * Opi2)) * pi2; + heading -= (float)Py_PI; + + //back to degrees + self->eul[0] = heading * (float)(180/Py_PI); + self->eul[1] = pitch * (float)(180/Py_PI); + self->eul[2] = bank * (float)(180/Py_PI); + + return EXPP_incr_ret(Py_None); +} + +PyObject *Euler_Zero(EulerObject *self) +{ + self->eul[0] = 0.0; + self->eul[1] = 0.0; + self->eul[2] = 0.0; + + return EXPP_incr_ret(Py_None); +} + +static void Euler_dealloc(EulerObject *self) +{ + PyObject_DEL (self); +} + +static PyObject *Euler_getattr(EulerObject *self, char *name) +{ + if (ELEM3(name[0], 'x', 'y', 'z') && name[1]==0){ + return PyFloat_FromDouble(self->eul[name[0]-'x']); + } + return Py_FindMethod(Euler_methods, (PyObject*)self, name); +} + +static int Euler_setattr(EulerObject *self, char *name, PyObject *e) +{ + float val; + + if (!PyArg_Parse(e, "f", &val)) + return EXPP_ReturnIntError(PyExc_TypeError, + "unable to parse float argument\n"); + + if (ELEM3(name[0], 'x', 'y', 'z') && name[1]==0){ + self->eul[name[0]-'x']= val; + return 0; + } + else return -1; +} + +/* Eulers Sequence methods */ +static PyObject *Euler_item(EulerObject *self, int i) +{ + if (i < 0 || i >= 3) + return EXPP_ReturnPyObjError (PyExc_IndexError, "array index out of range\n"); + + return Py_BuildValue("f", self->eul[i]); +} + +static PyObject *Euler_slice(EulerObject *self, int begin, int end) +{ + PyObject *list; + int count; + + if (begin < 0) begin= 0; + if (end > 3) end= 3; + if (begin > end) begin= end; + + list= PyList_New(end-begin); + + for (count = begin; count < end; count++){ + PyList_SetItem(list, count-begin, PyFloat_FromDouble(self->eul[count])); + } + return list; +} + +static int Euler_ass_item(EulerObject *self, int i, PyObject *ob) +{ + if (i < 0 || i >= 3) + return EXPP_ReturnIntError(PyExc_IndexError, + "array assignment index out of range\n"); + + if (!PyNumber_Check(ob)) + return EXPP_ReturnIntError(PyExc_IndexError, + "Euler member must be a number\n"); + + if(!PyFloat_Check(ob) && !PyInt_Check(ob)){ + return EXPP_ReturnIntError(PyExc_TypeError,"int or float expected\n"); + }else{ + self->eul[i]= (float)PyFloat_AsDouble(ob); + } + return 0; +} + +static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq) +{ + int count, z; + + if (begin < 0) begin= 0; + if (end > 3) end= 3; + if (begin > end) begin= end; + + if (!PySequence_Check(seq)) + return EXPP_ReturnIntError(PyExc_TypeError, + "illegal argument type for built-in operation\n"); + if (PySequence_Length(seq) != (end - begin)) + return EXPP_ReturnIntError(PyExc_TypeError, + "size mismatch in slice assignment\n"); + + z = 0; + for (count = begin; count < end; count++) { + PyObject *ob = PySequence_GetItem(seq, z); z++; + + if(!PyFloat_Check(ob) && !PyInt_Check(ob)){ + Py_DECREF(ob); + return -1; + }else{ + if (!PyArg_Parse(ob, "f", &self->eul[count])) { + Py_DECREF(ob); + return -1; + } + } + } + return 0; +} + +static PyObject *Euler_repr (EulerObject *self) +{ + int i, maxindex = 3 - 1; + char ftoa[24]; + PyObject *str1, *str2; + + str1 = PyString_FromString ("["); + + for (i = 0; i < maxindex; i++) { + sprintf(ftoa, "%.4f, ", self->eul[i]); + str2 = PyString_FromString (ftoa); + if (!str1 || !str2) goto error; + PyString_ConcatAndDel (&str1, str2); + } + + sprintf(ftoa, "%.4f]\n", self->eul[maxindex]); + str2 = PyString_FromString (ftoa); + if (!str1 || !str2) goto error; + PyString_ConcatAndDel (&str1, str2); + + if (str1) return str1; + +error: + Py_XDECREF (str1); + Py_XDECREF (str2); + return EXPP_ReturnPyObjError (PyExc_MemoryError, + "couldn't create PyString!\n"); +} + +static PySequenceMethods Euler_SeqMethods = +{ + (inquiry) 0, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (intargfunc) 0, /* sq_repeat */ + (intargfunc) Euler_item, /* sq_item */ + (intintargfunc) Euler_slice, /* sq_slice */ + (intobjargproc) Euler_ass_item, /* sq_ass_item */ + (intintobjargproc) Euler_ass_slice, /* sq_ass_slice */ +}; + +PyTypeObject euler_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "euler", /*tp_name*/ + sizeof(EulerObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor) Euler_dealloc, /*tp_dealloc*/ + (printfunc) 0, /*tp_print*/ + (getattrfunc) Euler_getattr, /*tp_getattr*/ + (setattrfunc) Euler_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + (reprfunc) Euler_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + &Euler_SeqMethods, /*tp_as_sequence*/ +}; + +PyObject *newEulerObject(float *eul) +{ + EulerObject *self; + int x; + + euler_Type.ob_type = &PyType_Type; + + self = PyObject_NEW(EulerObject, &euler_Type); + + if(!eul){ + self->eul = PyMem_Malloc (3*sizeof (float)); + for(x = 0; x < 3; x++){ + self->eul[x] = 0.0f; + } + }else self->eul = eul; + + return (PyObject*) self; +} + |