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/quat.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/quat.c')
-rw-r--r-- | source/blender/python/api2_2x/quat.c | 504 |
1 files changed, 504 insertions, 0 deletions
diff --git a/source/blender/python/api2_2x/quat.c b/source/blender/python/api2_2x/quat.c new file mode 100644 index 00000000000..3d785570027 --- /dev/null +++ b/source/blender/python/api2_2x/quat.c @@ -0,0 +1,504 @@ +/* + * ***** 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 "quat.h" + +//doc strings +char Quaternion_Identity_doc[] = +"() - set the quaternion to it's identity (1, vector)"; +char Quaternion_Negate_doc[] = +"() - set all values in the quaternion to their negative"; +char Quaternion_Conjugate_doc[] = +"() - set the quaternion to it's conjugate"; +char Quaternion_Inverse_doc[] = +"() - set the quaternion to it's inverse"; +char Quaternion_Normalize_doc[] = +"() - normalize the vector portion of the quaternion"; +char Quaternion_ToEuler_doc[] = +"() - return a euler rotation representing the quaternion"; +char Quaternion_ToMatrix_doc[] = +"() - return a rotation matrix representing the quaternion"; + +//methods table +struct PyMethodDef Quaternion_methods[] = { + {"identity",(PyCFunction)Quaternion_Identity, METH_NOARGS, + Quaternion_Identity_doc}, + {"negate",(PyCFunction)Quaternion_Negate, METH_NOARGS, + Quaternion_Negate_doc}, + {"conjugate",(PyCFunction)Quaternion_Conjugate, METH_NOARGS, + Quaternion_Conjugate_doc}, + {"inverse",(PyCFunction)Quaternion_Inverse, METH_NOARGS, + Quaternion_Inverse_doc}, + {"normalize",(PyCFunction)Quaternion_Normalize, METH_NOARGS, + Quaternion_Normalize_doc}, + {"toEuler",(PyCFunction)Quaternion_ToEuler, METH_NOARGS, + Quaternion_ToEuler_doc}, + {"toMatrix",(PyCFunction)Quaternion_ToMatrix, METH_NOARGS, + Quaternion_ToMatrix_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************/ +// Quaternion Python Object +/*****************************/ + +PyObject *Quaternion_ToEuler(QuaternionObject *self) +{ + float *eul; + int x; + + eul = PyMem_Malloc(3*sizeof(float)); + QuatToEul(self->quat, eul); + + for(x = 0; x < 3; x++){ + eul[x] *= (float)(180/Py_PI); + } + return (PyObject*)newEulerObject(eul); +} + +PyObject *Quaternion_ToMatrix(QuaternionObject *self) +{ + float *mat; + + mat = PyMem_Malloc(3*3*sizeof(float)); + QuatToMat3(self->quat, (float(*)[3])mat); + + return (PyObject*)newMatrixObject(mat, 3,3); +} + +//normalize the axis of rotation of [theta,vector] +PyObject *Quaternion_Normalize(QuaternionObject *self) +{ + NormalQuat(self->quat); + return EXPP_incr_ret(Py_None); +} + +PyObject *Quaternion_Inverse(QuaternionObject *self) +{ + float mag = 0.0f; + int x; + + for(x = 1; x < 4; x++){ + self->quat[x] = -self->quat[x]; + } + for(x = 0; x < 4; x++){ + mag += (self->quat[x] * self->quat[x]); + } + mag = (float)sqrt(mag); + for(x = 0; x < 4; x++){ + self->quat[x] /= (mag * mag); + } + + return EXPP_incr_ret(Py_None); +} + +PyObject *Quaternion_Identity(QuaternionObject *self) +{ + self->quat[0] = 1.0; + self->quat[1] = 0.0; self->quat[2] = 0.0; self->quat[3] = 0.0; + + return EXPP_incr_ret(Py_None); +} + +PyObject *Quaternion_Negate(QuaternionObject *self) +{ + int x; + + for(x = 0; x < 4; x++){ + self->quat[x] = -self->quat[x]; + } + return EXPP_incr_ret(Py_None); +} + +PyObject *Quaternion_Conjugate(QuaternionObject *self) +{ + int x; + + for(x = 1; x < 4; x++){ + self->quat[x] = -self->quat[x]; + } + return EXPP_incr_ret(Py_None); +} + +static void Quaternion_dealloc(QuaternionObject *self) +{ + PyObject_DEL (self); +} + +static PyObject *Quaternion_getattr(QuaternionObject *self, char *name) +{ + double mag = 0.0f; + float *vec; + int x; + + if (ELEM4(name[0], 'w', 'x', 'y', 'z') && name[1]==0){ + return PyFloat_FromDouble(self->quat[name[0]-'w']); + } + if(strcmp(name,"magnitude") == 0){ + for(x = 0; x < 4; x++){ + mag += self->quat[x] * self->quat[x]; + } + mag = (float)sqrt(mag); + return PyFloat_FromDouble(mag); + } + if(strcmp(name,"angle") == 0){ + + mag = self->quat[0]; + mag = 2 * (acos(mag)); + mag *= (180/Py_PI); + return PyFloat_FromDouble(mag); + } + if(strcmp(name,"axis") == 0){ + + mag = (double)(self->quat[0] * (Py_PI/180)); + mag = 2 * (acos(mag)); + mag = sin(mag/2); + vec = PyMem_Malloc(3*sizeof(float)); + for(x = 0; x < 3; x++){ + vec[x] = (self->quat[x + 1]/((float)(mag))); + } + Normalise(vec); + return (PyObject*)newVectorObject(vec,3); + } + return Py_FindMethod(Quaternion_methods, (PyObject*)self, name); +} + +static int Quaternion_setattr(QuaternionObject *self, char *name, PyObject *v) +{ + float val; + + if(!PyFloat_Check(v) && !PyInt_Check(v)){ + return EXPP_ReturnIntError(PyExc_TypeError,"int or float expected\n"); + }else{ + if (!PyArg_Parse(v, "f", &val)) + return EXPP_ReturnIntError(PyExc_TypeError, "unable to parse float argument\n"); + } + if (ELEM4(name[0], 'w', 'x', 'y', 'z') && name[1]==0){ + self->quat[name[0]-'w']= val; + }else return -1; + + return 0; +} + +/* Quaternions Sequence methods */ +static PyObject *Quaternion_item(QuaternionObject *self, int i) +{ + if (i < 0 || i >= 4) + return EXPP_ReturnPyObjError (PyExc_IndexError, "array index out of range\n"); + + return Py_BuildValue("f", self->quat[i]); +} + +static PyObject *Quaternion_slice(QuaternionObject *self, int begin, int end) +{ + PyObject *list; + int count; + + if (begin < 0) begin= 0; + if (end > 4) end= 4; + if (begin > end) begin= end; + + list= PyList_New(end-begin); + + for (count = begin; count < end; count++){ + PyList_SetItem(list, count-begin, PyFloat_FromDouble(self->quat[count])); + } + return list; +} + +static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob) +{ + if (i < 0 || i >= 4) + return EXPP_ReturnIntError(PyExc_IndexError, + "array assignment index out of range\n"); + if (!PyNumber_Check(ob)) + return EXPP_ReturnIntError(PyExc_IndexError, + "Quaternion 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->quat[i]= (float)PyFloat_AsDouble(ob); + } + return 0; +} + +static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyObject *seq) +{ + int count, z; + + if (begin < 0) begin= 0; + if (end > 4) end= 4; + 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->quat[count])) { + Py_DECREF(ob); + return -1; + } + } + } + return 0; +} + +static PyObject *Quaternion_repr (QuaternionObject *self) +{ + int i, maxindex = 4 - 1; + char ftoa[24]; + PyObject *str1, *str2; + + str1 = PyString_FromString ("["); + + for (i = 0; i < maxindex; i++) { + sprintf(ftoa, "%.4f, ", self->quat[i]); + str2 = PyString_FromString (ftoa); + if (!str1 || !str2) goto error; + PyString_ConcatAndDel (&str1, str2); + } + + sprintf(ftoa, "%.4f]\n", self->quat[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"); +} + + +PyObject * Quaternion_add(PyObject *q1, PyObject *q2) +{ + float * quat; + int x; + + if((!QuaternionObject_Check(q1)) || (!QuaternionObject_Check(q2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + if(((QuaternionObject*)q1)->flag > 0 || ((QuaternionObject*)q2)->flag > 0) + return EXPP_ReturnPyObjError (PyExc_ArithmeticError, + "cannot add a scalar and a quat\n"); + + quat = PyMem_Malloc (4*sizeof(float)); + for(x = 0; x < 4; x++){ + quat[x] = (((QuaternionObject*)q1)->quat[x]) + (((QuaternionObject*)q2)->quat[x]); + } + + return (PyObject*)newQuaternionObject(quat); +} + +PyObject * Quaternion_sub(PyObject *q1, PyObject *q2) +{ + float * quat; + int x; + + if((!QuaternionObject_Check(q1)) || (!QuaternionObject_Check(q2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + if(((QuaternionObject*)q1)->flag > 0 || ((QuaternionObject*)q2)->flag > 0) + return EXPP_ReturnPyObjError (PyExc_ArithmeticError, + "cannot subtract a scalar and a quat\n"); + + quat = PyMem_Malloc (4*sizeof(float)); + for(x = 0; x < 4; x++){ + quat[x] = (((QuaternionObject*)q1)->quat[x]) - (((QuaternionObject*)q2)->quat[x]); + } + return (PyObject*)newQuaternionObject(quat); +} + +PyObject * Quaternion_mul(PyObject *q1, PyObject * q2) +{ + float * quat; + int x; + + if((!QuaternionObject_Check(q1)) || (!QuaternionObject_Check(q2))) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "unsupported type for this operation\n"); + if(((QuaternionObject*)q1)->flag == 0 && ((QuaternionObject*)q2)->flag == 0) + return EXPP_ReturnPyObjError (PyExc_ArithmeticError, + "please use the dot or cross product to multiply quaternions\n"); + + quat = PyMem_Malloc (4*sizeof(float)); + //scalar mult by quat + for(x = 0; x < 4; x++){ + quat[x] = ((QuaternionObject*)q1)->quat[x] * ((QuaternionObject*)q2)->quat[x]; + } + return (PyObject*)newQuaternionObject(quat); +} + +//coercion of unknown types to type QuaternionObject for numeric protocols +int Quaternion_coerce(PyObject **q1, PyObject **q2) +{ + long *tempI; + double *tempF; + float *quat; + int x; + + if (QuaternionObject_Check(*q1)) { + if (QuaternionObject_Check(*q2)) { //two Quaternions + Py_INCREF(*q1); + Py_INCREF(*q2); + return 0; + }else{ + if(PyNumber_Check(*q2)){ + if(PyInt_Check(*q2)){ //cast scalar to Quaternion + tempI = PyMem_Malloc(1*sizeof(long)); + *tempI = PyInt_AsLong(*q2); + quat = PyMem_Malloc (4*sizeof (float)); + for(x = 0; x < 4; x++){ + quat[x] = (float)*tempI; + } + PyMem_Free(tempI); + *q2 = newQuaternionObject(quat); + ((QuaternionObject*)*q2)->flag = 1; //int coercion + Py_INCREF(*q1); + return 0; + }else if(PyFloat_Check(*q2)){ //cast scalar to Quaternion + tempF = PyMem_Malloc(1*sizeof(double)); + *tempF = PyFloat_AsDouble(*q2); + quat = PyMem_Malloc (4*sizeof (float)); + for(x = 0; x < 4; x++){ + quat[x] = (float)*tempF; + } + PyMem_Free(tempF); + *q2 = newQuaternionObject(quat); + ((QuaternionObject*)*q2)->flag = 2; //float coercion + Py_INCREF(*q1); + return 0; + } + } + //unknown type or numeric cast failure + printf("attempting quaternion operation with unsupported type...\n"); + Py_INCREF(*q1); + return 0; //operation will type check + } + }else{ + printf("numeric protocol failure...\n"); + return -1; //this should not occur - fail + } + return -1; +} + +static PySequenceMethods Quaternion_SeqMethods = +{ + (inquiry) 0, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (intargfunc) 0, /* sq_repeat */ + (intargfunc) Quaternion_item, /* sq_item */ + (intintargfunc) Quaternion_slice, /* sq_slice */ + (intobjargproc) Quaternion_ass_item, /* sq_ass_item */ + (intintobjargproc) Quaternion_ass_slice, /* sq_ass_slice */ +}; + +static PyNumberMethods Quaternion_NumMethods = +{ + (binaryfunc) Quaternion_add, /* __add__ */ + (binaryfunc) Quaternion_sub, /* __sub__ */ + (binaryfunc) Quaternion_mul, /* __mul__ */ + (binaryfunc) 0, /* __div__ */ + (binaryfunc) 0, /* __mod__ */ + (binaryfunc) 0, /* __divmod__ */ + (ternaryfunc) 0, /* __pow__ */ + (unaryfunc) 0, /* __neg__ */ + (unaryfunc) 0, /* __pos__ */ + (unaryfunc) 0, /* __abs__ */ + (inquiry) 0, /* __nonzero__ */ + (unaryfunc) 0, /* __invert__ */ + (binaryfunc) 0, /* __lshift__ */ + (binaryfunc) 0, /* __rshift__ */ + (binaryfunc) 0, /* __and__ */ + (binaryfunc) 0, /* __xor__ */ + (binaryfunc) 0, /* __or__ */ + (coercion) Quaternion_coerce, /* __coerce__ */ + (unaryfunc) 0, /* __int__ */ + (unaryfunc) 0, /* __long__ */ + (unaryfunc) 0, /* __float__ */ + (unaryfunc) 0, /* __oct__ */ + (unaryfunc) 0, /* __hex__ */ + +}; + +PyTypeObject quaternion_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "quaternion", /*tp_name*/ + sizeof(QuaternionObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor) Quaternion_dealloc, /*tp_dealloc*/ + (printfunc) 0, /*tp_print*/ + (getattrfunc) Quaternion_getattr, /*tp_getattr*/ + (setattrfunc) Quaternion_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + (reprfunc) Quaternion_repr, /*tp_repr*/ + &Quaternion_NumMethods, /*tp_as_number*/ + &Quaternion_SeqMethods, /*tp_as_sequence*/ +}; + +PyObject *newQuaternionObject(float *quat) +{ + QuaternionObject *self; + int x; + + quaternion_Type.ob_type = &PyType_Type; + + self = PyObject_NEW(QuaternionObject, &quaternion_Type); + + if(!quat){ + self->quat = PyMem_Malloc (4 *sizeof (float)); + for(x = 0; x < 4; x++){ + self->quat[x] = 0.0f; + } + self->quat[3] = 1.0f; + }else{ + self->quat = quat; + } + self->flag = 0; + + return (PyObject*) self; +} + |