/* * $Id$ * * ***** 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 ) { /* since we own this memory... */ PyMem_Free( self->eul ); 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 ); /* we own the self->eul memory and will free it later. if we received an input arg, copy to our internal array */ self->eul = PyMem_Malloc( 3 * sizeof( float ) ); if( ! self->eul ) return EXPP_ReturnPyObjError( PyExc_MemoryError, "newEulerObject:PyMem_Malloc failed" ); if( !eul ) { for( x = 0; x < 3; x++ ) { self->eul[x] = 0.0f; } } else{ for( x = 0; x < 3; x++){ self->eul[x] = eul[x]; } } return ( PyObject * ) self; }