Logo Search packages:      
Sourcecode: blender version File versions

euler.c

/*
 * $Id: euler.c,v 1.4 2004/12/01 23:09:59 stiv Exp $
 *
 * ***** 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;
}

Generated by  Doxygen 1.6.0   Back to index