/* * * ***** 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; }