Logo Search packages:      
Sourcecode: blender version File versions

Mathutils.c

/* 
 * $Id: Mathutils.c,v 1.5 2004/10/12 23:58:03 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.
 *
 * This is a new part of Blender.
 *
 * Contributor(s): Joseph Gilbert
 *
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
 */

#include <Python.h>
#include <BKE_main.h>
#include <BKE_global.h>
#include <BKE_library.h>
#include <BKE_utildefines.h>
#include <BLI_blenlib.h>
#include <BLI_arithb.h>
#include <PIL_time.h>
#include <BLI_rand.h>
#include <math.h>
#include "vector.h"
#include "euler.h"
#include "quat.h"
#include "matrix.h"
#include "blendef.h"
#include "mydevice.h"
#include "constant.h"
#include "gen_utils.h"
#include "Mathutils.h"


/*****************************************************************************/
// Python API function prototypes for the Mathutils module.  
/*****************************************************************************/
static PyObject *M_Mathutils_Rand( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_Vector( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_CrossVecs( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_DotVecs( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_AngleBetweenVecs( PyObject * self,
                                     PyObject * args );
static PyObject *M_Mathutils_MidpointVecs( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_VecMultMat( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_ProjectVecs( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_CopyVec( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_Matrix( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_RotationMatrix( PyObject * self,
                                   PyObject * args );
static PyObject *M_Mathutils_ScaleMatrix( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_OrthoProjectionMatrix( PyObject * self,
                                        PyObject * args );
static PyObject *M_Mathutils_ShearMatrix( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_TranslationMatrix( PyObject * self,
                                    PyObject * args );
static PyObject *M_Mathutils_MatMultVec( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_CopyMat( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_Quaternion( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_CrossQuats( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_DotQuats( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_CopyQuat( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_DifferenceQuats( PyObject * self,
                                    PyObject * args );
static PyObject *M_Mathutils_Slerp( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_Euler( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_CopyEuler( PyObject * self, PyObject * args );
static PyObject *M_Mathutils_RotateEuler( PyObject * self, PyObject * args );

/*****************************************************************************/
// The following string definitions are used for documentation strings.      
// In Python these will be written to the console when doing a                 
// Blender.Mathutils.__doc__           
/*  Mathutils Module strings                   */
/****************************************************************************/
static char M_Mathutils_doc[] = "The Blender Mathutils module\n\n";
static char M_Mathutils_Vector_doc[] =
      "() - create a new vector object from a list of floats";
static char M_Mathutils_Matrix_doc[] =
      "() - create a new matrix object from a list of floats";
static char M_Mathutils_Quaternion_doc[] =
      "() - create a quaternion from a list or an axis of rotation and an angle";
static char M_Mathutils_Euler_doc[] =
      "() - create and return a new euler object";
static char M_Mathutils_Rand_doc[] = "() - return a random number";
static char M_Mathutils_CrossVecs_doc[] =
      "() - returns a vector perpedicular to the 2 vectors crossed";
static char M_Mathutils_CopyVec_doc[] = "() - create a copy of vector";
static char M_Mathutils_DotVecs_doc[] =
      "() - return the dot product of two vectors";
static char M_Mathutils_AngleBetweenVecs_doc[] =
      "() - returns the angle between two vectors in degrees";
static char M_Mathutils_MidpointVecs_doc[] =
      "() - return the vector to the midpoint between two vectors";
static char M_Mathutils_MatMultVec_doc[] =
      "() - multiplies a matrix by a column vector";
static char M_Mathutils_VecMultMat_doc[] =
      "() - multiplies a row vector by a matrix";
static char M_Mathutils_ProjectVecs_doc[] =
      "() - returns the projection vector from the projection of vecA onto vecB";
static char M_Mathutils_RotationMatrix_doc[] =
      "() - construct a rotation matrix from an angle and axis of rotation";
static char M_Mathutils_ScaleMatrix_doc[] =
      "() - construct a scaling matrix from a scaling factor";
static char M_Mathutils_OrthoProjectionMatrix_doc[] =
      "() - construct a orthographic projection matrix from a selected plane";
static char M_Mathutils_ShearMatrix_doc[] =
      "() - construct a shearing matrix from a plane of shear and a shear factor";
static char M_Mathutils_CopyMat_doc[] = "() - create a copy of a matrix";
static char M_Mathutils_TranslationMatrix_doc[] =
      "() - create a translation matrix from a vector";
static char M_Mathutils_CopyQuat_doc[] = "() - copy quatB to quatA";
static char M_Mathutils_CopyEuler_doc[] = "() - copy eulB to eultA";
static char M_Mathutils_CrossQuats_doc[] =
      "() - return the mutliplication of two quaternions";
static char M_Mathutils_DotQuats_doc[] =
      "() - return the dot product of two quaternions";
static char M_Mathutils_Slerp_doc[] =
      "() - returns the interpolation between two quaternions";
static char M_Mathutils_DifferenceQuats_doc[] =
      "() - return the angular displacment difference between two quats";
static char M_Mathutils_RotateEuler_doc[] =
      "() - rotate euler by an axis and angle";


/****************************************************************************/
// Python method structure definition for Blender.Mathutils module:     
/****************************************************************************/
struct PyMethodDef M_Mathutils_methods[] = {
      {"Rand", ( PyCFunction ) M_Mathutils_Rand, METH_VARARGS,
       M_Mathutils_Rand_doc},
      {"Vector", ( PyCFunction ) M_Mathutils_Vector, METH_VARARGS,
       M_Mathutils_Vector_doc},
      {"CrossVecs", ( PyCFunction ) M_Mathutils_CrossVecs, METH_VARARGS,
       M_Mathutils_CrossVecs_doc},
      {"DotVecs", ( PyCFunction ) M_Mathutils_DotVecs, METH_VARARGS,
       M_Mathutils_DotVecs_doc},
      {"AngleBetweenVecs", ( PyCFunction ) M_Mathutils_AngleBetweenVecs,
       METH_VARARGS,
       M_Mathutils_AngleBetweenVecs_doc},
      {"MidpointVecs", ( PyCFunction ) M_Mathutils_MidpointVecs,
       METH_VARARGS,
       M_Mathutils_MidpointVecs_doc},
      {"VecMultMat", ( PyCFunction ) M_Mathutils_VecMultMat, METH_VARARGS,
       M_Mathutils_VecMultMat_doc},
      {"ProjectVecs", ( PyCFunction ) M_Mathutils_ProjectVecs, METH_VARARGS,
       M_Mathutils_ProjectVecs_doc},
      {"CopyVec", ( PyCFunction ) M_Mathutils_CopyVec, METH_VARARGS,
       M_Mathutils_CopyVec_doc},
      {"Matrix", ( PyCFunction ) M_Mathutils_Matrix, METH_VARARGS,
       M_Mathutils_Matrix_doc},
      {"RotationMatrix", ( PyCFunction ) M_Mathutils_RotationMatrix,
       METH_VARARGS,
       M_Mathutils_RotationMatrix_doc},
      {"ScaleMatrix", ( PyCFunction ) M_Mathutils_ScaleMatrix, METH_VARARGS,
       M_Mathutils_ScaleMatrix_doc},
      {"ShearMatrix", ( PyCFunction ) M_Mathutils_ShearMatrix, METH_VARARGS,
       M_Mathutils_ShearMatrix_doc},
      {"TranslationMatrix", ( PyCFunction ) M_Mathutils_TranslationMatrix,
       METH_VARARGS,
       M_Mathutils_TranslationMatrix_doc},
      {"CopyMat", ( PyCFunction ) M_Mathutils_CopyMat, METH_VARARGS,
       M_Mathutils_CopyMat_doc},
      {"OrthoProjectionMatrix",
       ( PyCFunction ) M_Mathutils_OrthoProjectionMatrix, METH_VARARGS,
       M_Mathutils_OrthoProjectionMatrix_doc},
      {"MatMultVec", ( PyCFunction ) M_Mathutils_MatMultVec, METH_VARARGS,
       M_Mathutils_MatMultVec_doc},
      {"Quaternion", ( PyCFunction ) M_Mathutils_Quaternion, METH_VARARGS,
       M_Mathutils_Quaternion_doc},
      {"CopyQuat", ( PyCFunction ) M_Mathutils_CopyQuat, METH_VARARGS,
       M_Mathutils_CopyQuat_doc},
      {"CrossQuats", ( PyCFunction ) M_Mathutils_CrossQuats, METH_VARARGS,
       M_Mathutils_CrossQuats_doc},
      {"DotQuats", ( PyCFunction ) M_Mathutils_DotQuats, METH_VARARGS,
       M_Mathutils_DotQuats_doc},
      {"DifferenceQuats", ( PyCFunction ) M_Mathutils_DifferenceQuats,
       METH_VARARGS,
       M_Mathutils_DifferenceQuats_doc},
      {"Slerp", ( PyCFunction ) M_Mathutils_Slerp, METH_VARARGS,
       M_Mathutils_Slerp_doc},
      {"Euler", ( PyCFunction ) M_Mathutils_Euler, METH_VARARGS,
       M_Mathutils_Euler_doc},
      {"CopyEuler", ( PyCFunction ) M_Mathutils_CopyEuler, METH_VARARGS,
       M_Mathutils_CopyEuler_doc},
      {"RotateEuler", ( PyCFunction ) M_Mathutils_RotateEuler, METH_VARARGS,
       M_Mathutils_RotateEuler_doc},
      {NULL, NULL, 0, NULL}
};


//***************************************************************************
// Function:             M_Mathutils_Rand            
//***************************************************************************
static PyObject *M_Mathutils_Rand( PyObject * self, PyObject * args )
{

      float high, low, range;
      double rand;
      high = 1.0;
      low = 0.0;

      if( !PyArg_ParseTuple( args, "|ff", &low, &high ) )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "expected optional float & float\n" ) );

      if( ( high < low ) || ( high < 0 && low > 0 ) )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "high value should be larger than low value\n" ) );

      //seed the generator
      BLI_srand( ( unsigned int ) ( PIL_check_seconds_timer(  ) *
                              0x7FFFFFFF ) );

      //get the random number 0 - 1
      rand = BLI_drand(  );

      //set it to range
      range = high - low;
      rand = rand * range;
      rand = rand + low;

      return PyFloat_FromDouble( ( double ) rand );
}

//***************************************************************************
// Function:             M_Mathutils_Vector               
// Python equivalent:     Blender.Mathutils.Vector        
// Supports 2D, 3D, and 4D vector objects both int and float values
// accepted. Mixed float and int values accepted. Ints are parsed to float  
//***************************************************************************
static PyObject *M_Mathutils_Vector( PyObject * self, PyObject * args )
{
      PyObject *listObject = NULL;
      PyObject *checkOb = NULL;
      PyObject *retval = NULL;
      int x;
      float *vec;

      if( !PyArg_ParseTuple( args, "|O!", &PyList_Type, &listObject ) )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "0 or 1 list expected" ) );

      if( !listObject )
            return ( PyObject * ) newVectorObject( NULL, 3 );

      //2D 3D 4D supported
      if( PyList_Size( listObject ) != 2 && PyList_Size( listObject ) != 3
          && PyList_Size( listObject ) != 4 )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "2D, 3D and 4D vectors supported\n" ) );

      for( x = 0; x < PyList_Size( listObject ); x++ ) {
            checkOb = PyList_GetItem( listObject, x );  /* borrowed refernce */
            if( !PyInt_Check( checkOb ) && !PyFloat_Check( checkOb ) )
                  return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                          "expected list of numbers\n" ) );
      }

      //allocate memory
      vec = PyMem_Malloc( PyList_Size( listObject ) * sizeof( float ) );

      //parse it all as floats
      for( x = 0; x < PyList_Size( listObject ); x++ ) {
            if( !PyArg_Parse
                ( PyList_GetItem( listObject, x ), "f", &vec[x] ) ) {
                  return EXPP_ReturnPyObjError( PyExc_TypeError,
                                          "python list not parseable\n" );
            }
      }

      retval =  ( PyObject * ) newVectorObject( vec,
                                      PyList_Size( listObject ) );
      PyMem_Free( vec );
      return retval;
}

//***************************************************************************
//Begin Vector Utils

static PyObject *M_Mathutils_CopyVec( PyObject * self, PyObject * args )
{
      VectorObject *vector;
      float *vec;
      int x;
      PyObject *retval;

      if( !PyArg_ParseTuple( args, "O!", &vector_Type, &vector ) )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "expected vector type\n" ) );

      vec = PyMem_Malloc( vector->size * sizeof( float ) );
      for( x = 0; x < vector->size; x++ ) {
            vec[x] = vector->vec[x];
      }

      retval =  ( PyObject * ) newVectorObject( vec, vector->size );
      
      PyMem_Free( vec );
      return retval;
}

//finds perpendicular vector - only 3D is supported
static PyObject *M_Mathutils_CrossVecs( PyObject * self, PyObject * args )
{
      PyObject *vecCross;
      VectorObject *vec1;
      VectorObject *vec2;

      if( !PyArg_ParseTuple
          ( args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2 ) )
            return ( EXPP_ReturnPyObjError
                   ( PyExc_TypeError, "expected 2 vector types\n" ) );
      if( vec1->size != 3 || vec2->size != 3 )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "only 3D vectors are supported\n" ) );

      vecCross = newVectorObject( NULL, 3 );
      Crossf( ( ( VectorObject * ) vecCross )->vec, vec1->vec, vec2->vec );

      return vecCross;
}

static PyObject *M_Mathutils_DotVecs( PyObject * self, PyObject * args )
{
      VectorObject *vec1;
      VectorObject *vec2;
      float dot;
      int x;

      dot = 0;
      if( !PyArg_ParseTuple
          ( args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2 ) )
            return ( EXPP_ReturnPyObjError
                   ( PyExc_TypeError, "expected vector types\n" ) );
      if( vec1->size != vec2->size )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "vectors must be of the same size\n" ) );

      for( x = 0; x < vec1->size; x++ ) {
            dot += vec1->vec[x] * vec2->vec[x];
      }

      return PyFloat_FromDouble( ( double ) dot );
}

static PyObject *M_Mathutils_AngleBetweenVecs( PyObject * self,
                                     PyObject * args )
{
      VectorObject *vec1;
      VectorObject *vec2;
      float dot, angleRads, norm;
      int x;

      dot = 0;
      if( !PyArg_ParseTuple
          ( args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2 ) )
            return ( EXPP_ReturnPyObjError
                   ( PyExc_TypeError, "expected 2 vector types\n" ) );
      if( vec1->size != vec2->size )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "vectors must be of the same size\n" ) );
      if( vec1->size > 3 || vec2->size > 3 )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "only 2D,3D vectors are supported\n" ) );

      //normalize vec1
      norm = 0.0f;
      for( x = 0; x < vec1->size; x++ ) {
            norm += vec1->vec[x] * vec1->vec[x];
      }
      norm = ( float ) sqrt( norm );
      for( x = 0; x < vec1->size; x++ ) {
            vec1->vec[x] /= norm;
      }

      //normalize vec2
      norm = 0.0f;
      for( x = 0; x < vec2->size; x++ ) {
            norm += vec2->vec[x] * vec2->vec[x];
      }
      norm = ( float ) sqrt( norm );
      for( x = 0; x < vec2->size; x++ ) {
            vec2->vec[x] /= norm;
      }

      //dot product
      for( x = 0; x < vec1->size; x++ ) {
            dot += vec1->vec[x] * vec2->vec[x];
      }

      //I believe saacos checks to see if the vectors are normalized
      angleRads = saacos( dot );

      return PyFloat_FromDouble( ( double )
                           ( angleRads * ( 180 / Py_PI ) ) );
}

static PyObject *M_Mathutils_MidpointVecs( PyObject * self, PyObject * args )
{

      VectorObject *vec1;
      VectorObject *vec2;
      float *vec;
      int x;
      PyObject *retval;

      if( !PyArg_ParseTuple
          ( args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2 ) )
            return ( EXPP_ReturnPyObjError
                   ( PyExc_TypeError, "expected vector types\n" ) );
      if( vec1->size != vec2->size )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "vectors must be of the same size\n" ) );

      vec = PyMem_Malloc( vec1->size * sizeof( float ) );

      for( x = 0; x < vec1->size; x++ ) {
            vec[x] = 0.5f * ( vec1->vec[x] + vec2->vec[x] );
      }
      retval = ( PyObject * ) newVectorObject( vec, vec1->size );
      
      PyMem_Free( vec );
      return retval;
}

//row vector multiplication
static PyObject *M_Mathutils_VecMultMat( PyObject * self, PyObject * args )
{
      PyObject *ob1 = NULL;
      PyObject *ob2 = NULL;
      MatrixObject *mat;
      VectorObject *vec;
      PyObject *retval;
      float *vecNew;
      int x, y;
      int z = 0;
      float dot = 0.0f;

      //get pyObjects
      if( !PyArg_ParseTuple
          ( args, "O!O!", &vector_Type, &ob1, &matrix_Type, &ob2 ) )
            return ( EXPP_ReturnPyObjError
                   ( PyExc_TypeError,
                     "vector and matrix object expected - in that order\n" ) );

      mat = ( MatrixObject * ) ob2;
      vec = ( VectorObject * ) ob1;
      if( mat->colSize != vec->size )
            return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
                                    "matrix col size and vector size must be the same\n" ) );

      vecNew = PyMem_Malloc( vec->size * sizeof( float ) );

      for( x = 0; x < mat->colSize; x++ ) {
            for( y = 0; y < mat->rowSize; y++ ) {
                  dot += mat->matrix[y][x] * vec->vec[y];
            }
            vecNew[z] = dot;
            z++;
            dot = 0;
      }

      retval =  ( PyObject * ) newVectorObject( vecNew, vec->size );

      PyMem_Free( vecNew );
      return retval;
}

static PyObject *M_Mathutils_ProjectVecs( PyObject * self, PyObject * args )
{
      VectorObject *vec1;
      VectorObject *vec2;
      PyObject *retval;
      float *vec;
      float dot = 0.0f;
      float dot2 = 0.0f;
      int x;

      if( !PyArg_ParseTuple
          ( args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2 ) )
            return ( EXPP_ReturnPyObjError
                   ( PyExc_TypeError, "expected vector types\n" ) );
      if( vec1->size != vec2->size )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "vectors must be of the same size\n" ) );

      vec = PyMem_Malloc( vec1->size * sizeof( float ) );

      //dot of vec1 & vec2
      for( x = 0; x < vec1->size; x++ ) {
            dot += vec1->vec[x] * vec2->vec[x];
      }
      //dot of vec2 & vec2
      for( x = 0; x < vec2->size; x++ ) {
            dot2 += vec2->vec[x] * vec2->vec[x];
      }
      dot /= dot2;
      for( x = 0; x < vec1->size; x++ ) {
            vec[x] = dot * vec2->vec[x];
      }

      retval = ( PyObject * ) newVectorObject( vec, vec1->size );
      PyMem_Free( vec );
      return retval;
}

//End Vector Utils

//***************************************************************************
// Function:      M_Mathutils_Matrix                                           // Python equivalent:      Blender.Mathutils.Matrix                          
//***************************************************************************
//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
static PyObject *M_Mathutils_Matrix( PyObject * self, PyObject * args )
{

      PyObject *rowA = NULL;
      PyObject *rowB = NULL;
      PyObject *rowC = NULL;
      PyObject *rowD = NULL;
      PyObject *checkOb = NULL;
      PyObject *retval = NULL;
      int x, rowSize, colSize;
      float *mat;
      int OK;

      if( !PyArg_ParseTuple( args, "|O!O!O!O!", &PyList_Type, &rowA,
                         &PyList_Type, &rowB,
                         &PyList_Type, &rowC, &PyList_Type, &rowD ) ) {
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "expected 0, 2,3 or 4 lists\n" ) );
      }

      if( !rowA )
            return newMatrixObject( NULL, 4, 4 );

      if( !rowB )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "expected 0, 2,3 or 4 lists\n" ) );

      //get rowSize
      if( rowC ) {
            if( rowD ) {
                  rowSize = 4;
            } else {
                  rowSize = 3;
            }
      } else {
            rowSize = 2;
      }

      //check size and get colSize
      OK = 0;
      if( ( PyList_Size( rowA ) == PyList_Size( rowB ) ) ) {
            if( rowC ) {
                  if( ( PyList_Size( rowA ) == PyList_Size( rowC ) ) ) {
                        if( rowD ) {
                              if( ( PyList_Size( rowA ) ==
                                    PyList_Size( rowD ) ) ) {
                                    OK = 1;
                              }
                        }
                        OK = 1;
                  }
            } else
                  OK = 1;
      }

      if( !OK )
            return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                    "each row of vector must contain the same number of parameters\n" );
      colSize = PyList_Size( rowA );

      //check for numeric types
      /* PyList_GetItem() returns borrowed ref */
      for( x = 0; x < colSize; x++ ) {
            checkOb = PyList_GetItem( rowA, x );  
            if( !PyInt_Check( checkOb ) && !PyFloat_Check( checkOb ) )
                  return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                          "1st list - expected list of numbers\n" ) );
            checkOb = PyList_GetItem( rowB, x );
            if( !PyInt_Check( checkOb ) && !PyFloat_Check( checkOb ) )
                  return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                          "2nd list - expected list of numbers\n" ) );
            if( rowC ) {
                  checkOb = PyList_GetItem( rowC, x );
                  if( !PyInt_Check( checkOb )
                      && !PyFloat_Check( checkOb ) )
                        return ( EXPP_ReturnPyObjError
                               ( PyExc_TypeError,
                                 "3rd list - expected list of numbers\n" ) );
            }
            if( rowD ) {
                  checkOb = PyList_GetItem( rowD, x );
                  if( !PyInt_Check( checkOb )
                      && !PyFloat_Check( checkOb ) )
                        return ( EXPP_ReturnPyObjError
                               ( PyExc_TypeError,
                                 "4th list - expected list of numbers\n" ) );
            }
      }

      //allocate space for 1D array
      mat = PyMem_Malloc( rowSize * colSize * sizeof( float ) );

      //parse rows
      for( x = 0; x < colSize; x++ ) {
            if( !PyArg_Parse( PyList_GetItem( rowA, x ), "f", &mat[x] ) )
                  return EXPP_ReturnPyObjError( PyExc_TypeError,
                                          "rowA - python list not parseable\n" );
      }
      for( x = 0; x < colSize; x++ ) {
            if( !PyArg_Parse
                ( PyList_GetItem( rowB, x ), "f", &mat[( colSize + x )] ) )
                  return EXPP_ReturnPyObjError( PyExc_TypeError,
                                          "rowB - python list not parseable\n" );
      }
      if( rowC ) {
            for( x = 0; x < colSize; x++ ) {
                  if( !PyArg_Parse
                      ( PyList_GetItem( rowC, x ), "f",
                        &mat[( ( 2 * colSize ) + x )] ) )
                        return EXPP_ReturnPyObjError( PyExc_TypeError,
                                                "rowC - python list not parseable\n" );
            }
      }
      if( rowD ) {
            for( x = 0; x < colSize; x++ ) {
                  if( !PyArg_Parse
                      ( PyList_GetItem( rowD, x ), "f",
                        &mat[( ( 3 * colSize ) + x )] ) )
                        return EXPP_ReturnPyObjError( PyExc_TypeError,
                                                "rowD - python list not parseable\n" );
            }
      }
      //pass to matrix creation
      retval =  newMatrixObject( mat, rowSize, colSize );

      PyMem_Free( mat);
      return retval;
}

//***************************************************************************
// Function:      M_Mathutils_RotationMatrix                                  
// Python equivalent:    Blender.Mathutils.RotationMatrix  
//***************************************************************************
//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
static PyObject *M_Mathutils_RotationMatrix( PyObject * self, PyObject * args )
{
      PyObject *retval;
      float *mat;
      float angle = 0.0f;
      char *axis = NULL;
      VectorObject *vec = NULL;
      int matSize;
      float norm = 0.0f;
      float cosAngle = 0.0f;
      float sinAngle = 0.0f;

      if( !PyArg_ParseTuple
          ( args, "fi|sO!", &angle, &matSize, &axis, &vector_Type, &vec ) ) {
            return ( EXPP_ReturnPyObjError
                   ( PyExc_TypeError,
                     "expected float int and optional string and vector\n" ) );
      }
      if( angle < -360.0f || angle > 360.0f )
            return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                    "angle size not appropriate\n" );
      if( matSize != 2 && matSize != 3 && matSize != 4 )
            return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                    "can only return a 2x2 3x3 or 4x4 matrix\n" );
      if( matSize == 2 && ( axis != NULL || vec != NULL ) )
            return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                    "cannot create a 2x2 rotation matrix around arbitrary axis\n" );
      if( ( matSize == 3 || matSize == 4 ) && axis == NULL )
            return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                    "please choose an axis of rotation\n" );
      if( axis ) {
            if( ( ( strcmp( axis, "r" ) == 0 ) ||
                  ( strcmp( axis, "R" ) == 0 ) ) && vec == NULL )
                  return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                          "please define the arbitrary axis of rotation\n" );
      }
      if( vec ) {
            if( vec->size != 3 )
                  return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                          "the arbitrary axis must be a 3D vector\n" );
      }

      mat = PyMem_Malloc( matSize * matSize * sizeof( float ) );

      //convert to radians
      angle = angle * ( float ) ( Py_PI / 180 );

      if( axis == NULL && matSize == 2 ) {
            //2D rotation matrix
            mat[0] = ( ( float ) cos( ( double ) ( angle ) ) );
            mat[1] = ( ( float ) sin( ( double ) ( angle ) ) );
            mat[2] = ( -( ( float ) sin( ( double ) ( angle ) ) ) );
            mat[3] = ( ( float ) cos( ( double ) ( angle ) ) );
      } else if( ( strcmp( axis, "x" ) == 0 ) ||
               ( strcmp( axis, "X" ) == 0 ) ) {
            //rotation around X
            mat[0] = 1.0f;
            mat[1] = 0.0f;
            mat[2] = 0.0f;
            mat[3] = 0.0f;
            mat[4] = ( ( float ) cos( ( double ) ( angle ) ) );
            mat[5] = ( ( float ) sin( ( double ) ( angle ) ) );
            mat[6] = 0.0f;
            mat[7] = ( -( ( float ) sin( ( double ) ( angle ) ) ) );
            mat[8] = ( ( float ) cos( ( double ) ( angle ) ) );
      } else if( ( strcmp( axis, "y" ) == 0 ) ||
               ( strcmp( axis, "Y" ) == 0 ) ) {
            //rotation around Y
            mat[0] = ( ( float ) cos( ( double ) ( angle ) ) );
            mat[1] = 0.0f;
            mat[2] = ( -( ( float ) sin( ( double ) ( angle ) ) ) );
            mat[3] = 0.0f;
            mat[4] = 1.0f;
            mat[5] = 0.0f;
            mat[6] = ( ( float ) sin( ( double ) ( angle ) ) );
            mat[7] = 0.0f;
            mat[8] = ( ( float ) cos( ( double ) ( angle ) ) );
      } else if( ( strcmp( axis, "z" ) == 0 ) ||
               ( strcmp( axis, "Z" ) == 0 ) ) {
            //rotation around Z
            mat[0] = ( ( float ) cos( ( double ) ( angle ) ) );
            mat[1] = ( ( float ) sin( ( double ) ( angle ) ) );
            mat[2] = 0.0f;
            mat[3] = ( -( ( float ) sin( ( double ) ( angle ) ) ) );
            mat[4] = ( ( float ) cos( ( double ) ( angle ) ) );
            mat[5] = 0.0f;
            mat[6] = 0.0f;
            mat[7] = 0.0f;
            mat[8] = 1.0f;
      } else if( ( strcmp( axis, "r" ) == 0 ) ||
               ( strcmp( axis, "R" ) == 0 ) ) {
            //arbitrary rotation
            //normalize arbitrary axis
            norm = ( float ) sqrt( vec->vec[0] * vec->vec[0] +
                               vec->vec[1] * vec->vec[1] +
                               vec->vec[2] * vec->vec[2] );
            vec->vec[0] /= norm;
            vec->vec[1] /= norm;
            vec->vec[2] /= norm;

            //create matrix
            cosAngle = ( ( float ) cos( ( double ) ( angle ) ) );
            sinAngle = ( ( float ) sin( ( double ) ( angle ) ) );
            mat[0] = ( ( vec->vec[0] * vec->vec[0] ) * ( 1 - cosAngle ) ) +
                  cosAngle;
            mat[1] = ( ( vec->vec[0] * vec->vec[1] ) * ( 1 - cosAngle ) ) +
                  ( vec->vec[2] * sinAngle );
            mat[2] = ( ( vec->vec[0] * vec->vec[2] ) * ( 1 - cosAngle ) ) -
                  ( vec->vec[1] * sinAngle );
            mat[3] = ( ( vec->vec[0] * vec->vec[1] ) * ( 1 - cosAngle ) ) -
                  ( vec->vec[2] * sinAngle );
            mat[4] = ( ( vec->vec[1] * vec->vec[1] ) * ( 1 - cosAngle ) ) +
                  cosAngle;
            mat[5] = ( ( vec->vec[1] * vec->vec[2] ) * ( 1 - cosAngle ) ) +
                  ( vec->vec[0] * sinAngle );
            mat[6] = ( ( vec->vec[0] * vec->vec[2] ) * ( 1 - cosAngle ) ) +
                  ( vec->vec[1] * sinAngle );
            mat[7] = ( ( vec->vec[1] * vec->vec[2] ) * ( 1 - cosAngle ) ) -
                  ( vec->vec[0] * sinAngle );
            mat[8] = ( ( vec->vec[2] * vec->vec[2] ) * ( 1 - cosAngle ) ) +
                  cosAngle;
      } else {
            return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                    "unrecognizable axis of rotation type - expected x,y,z or r\n" );
      }
      if( matSize == 4 ) {
            //resize matrix
            mat[15] = 1.0f;
            mat[14] = 0.0f;
            mat[13] = 0.0f;
            mat[12] = 0.0f;
            mat[11] = 0.0f;
            mat[10] = mat[8];
            mat[9] = mat[7];
            mat[8] = mat[6];
            mat[7] = 0.0f;
            mat[6] = mat[5];
            mat[5] = mat[4];
            mat[4] = mat[3];
            mat[3] = 0.0f;
      }
      //pass to matrix creation
      retval = newMatrixObject( mat, matSize, matSize );

      PyMem_Free( mat );
      return retval;
}

//***************************************************************************
// Function:      M_Mathutils_TranslationMatrix 
// Python equivalent:       Blender.Mathutils.TranslationMatrix 
//***************************************************************************
static PyObject *M_Mathutils_TranslationMatrix( PyObject * self,
                                    PyObject * args )
{
      VectorObject *vec;
      PyObject *retval;
      float *mat;

      if( !PyArg_ParseTuple( args, "O!", &vector_Type, &vec ) ) {
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "expected vector\n" ) );
      }
      if( vec->size != 3 && vec->size != 4 ) {
            return EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "vector must be 3D or 4D\n" );
      }

      mat = PyMem_Malloc( 4 * 4 * sizeof( float ) );
      Mat4One( ( float ( * )[4] ) mat );

      mat[12] = vec->vec[0];
      mat[13] = vec->vec[1];
      mat[14] = vec->vec[2];

      retval = newMatrixObject( mat, 4, 4 );

      PyMem_Free( mat );
      return retval;
}


//***************************************************************************
// Function:   M_Mathutils_ScaleMatrix  
// Python equivalent:       Blender.Mathutils.ScaleMatrix 
//***************************************************************************
//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
static PyObject *M_Mathutils_ScaleMatrix( PyObject * self, PyObject * args )
{
      float factor;
      int matSize;
      VectorObject *vec = NULL;
      float *mat;
      float norm = 0.0f;
      int x;
      PyObject *retval;

      if( !PyArg_ParseTuple
          ( args, "fi|O!", &factor, &matSize, &vector_Type, &vec ) ) {
            return ( EXPP_ReturnPyObjError
                   ( PyExc_TypeError,
                     "expected float int and optional vector\n" ) );
      }
      if( matSize != 2 && matSize != 3 && matSize != 4 )
            return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                    "can only return a 2x2 3x3 or 4x4 matrix\n" );
      if( vec ) {
            if( vec->size > 2 && matSize == 2 )
                  return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                          "please use 2D vectors when scaling in 2D\n" );
      }
      mat = PyMem_Malloc( matSize * matSize * sizeof( float ) );

      if( vec == NULL ) {     //scaling along axis
            if( matSize == 2 ) {
                  mat[0] = factor;
                  mat[1] = 0.0f;
                  mat[2] = 0.0f;
                  mat[3] = factor;
            } else {
                  mat[0] = factor;
                  mat[1] = 0.0f;
                  mat[2] = 0.0f;
                  mat[3] = 0.0f;
                  mat[4] = factor;
                  mat[5] = 0.0f;
                  mat[6] = 0.0f;
                  mat[7] = 0.0f;
                  mat[8] = factor;
            }
      } else {          //scaling in arbitrary direction

            //normalize arbitrary axis
            for( x = 0; x < vec->size; x++ ) {
                  norm += vec->vec[x] * vec->vec[x];
            }
            norm = ( float ) sqrt( norm );
            for( x = 0; x < vec->size; x++ ) {
                  vec->vec[x] /= norm;
            }
            if( matSize == 2 ) {
                  mat[0] = 1 +
                        ( ( factor -
                            1 ) * ( vec->vec[0] * vec->vec[0] ) );
                  mat[1] = ( ( factor -
                             1 ) * ( vec->vec[0] * vec->vec[1] ) );
                  mat[2] = ( ( factor -
                             1 ) * ( vec->vec[0] * vec->vec[1] ) );
                  mat[3] = 1 +
                        ( ( factor -
                            1 ) * ( vec->vec[1] * vec->vec[1] ) );
            } else {
                  mat[0] = 1 +
                        ( ( factor -
                            1 ) * ( vec->vec[0] * vec->vec[0] ) );
                  mat[1] = ( ( factor -
                             1 ) * ( vec->vec[0] * vec->vec[1] ) );
                  mat[2] = ( ( factor -
                             1 ) * ( vec->vec[0] * vec->vec[2] ) );
                  mat[3] = ( ( factor -
                             1 ) * ( vec->vec[0] * vec->vec[1] ) );
                  mat[4] = 1 +
                        ( ( factor -
                            1 ) * ( vec->vec[1] * vec->vec[1] ) );
                  mat[5] = ( ( factor -
                             1 ) * ( vec->vec[1] * vec->vec[2] ) );
                  mat[6] = ( ( factor -
                             1 ) * ( vec->vec[0] * vec->vec[2] ) );
                  mat[7] = ( ( factor -
                             1 ) * ( vec->vec[1] * vec->vec[2] ) );
                  mat[8] = 1 +
                        ( ( factor -
                            1 ) * ( vec->vec[2] * vec->vec[2] ) );
            }
      }
      if( matSize == 4 ) {
            //resize matrix
            mat[15] = 1.0f;
            mat[14] = 0.0f;
            mat[13] = 0.0f;
            mat[12] = 0.0f;
            mat[11] = 0.0f;
            mat[10] = mat[8];
            mat[9] = mat[7];
            mat[8] = mat[6];
            mat[7] = 0.0f;
            mat[6] = mat[5];
            mat[5] = mat[4];
            mat[4] = mat[3];
            mat[3] = 0.0f;
      }
      //pass to matrix creation
      retval = newMatrixObject( mat, matSize, matSize );

      PyMem_Free( mat );
      return retval;
}

//***************************************************************************
// Function:     M_Mathutils_OrthoProjectionMatrix  
// Python equivalent:        Blender.Mathutils.OrthoProjectionMatrix 
//***************************************************************************
//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
static PyObject *M_Mathutils_OrthoProjectionMatrix( PyObject * self,
                                        PyObject * args )
{
      char *plane;
      int matSize;
      float *mat;
      VectorObject *vec = NULL;
      float norm = 0.0f;
      int x;
      PyObject *retval;

      if( !PyArg_ParseTuple
          ( args, "si|O!", &plane, &matSize, &vector_Type, &vec ) ) {
            return ( EXPP_ReturnPyObjError
                   ( PyExc_TypeError,
                     "expected string and int and optional vector\n" ) );
      }
      if( matSize != 2 && matSize != 3 && matSize != 4 )
            return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                    "can only return a 2x2 3x3 or 4x4 matrix\n" );
      if( vec ) {
            if( vec->size > 2 && matSize == 2 )
                  return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                          "please use 2D vectors when scaling in 2D\n" );
      }
      if( vec == NULL ) {     //ortho projection onto cardinal plane
            if( ( ( strcmp( plane, "x" ) == 0 )
                  || ( strcmp( plane, "X" ) == 0 ) ) && matSize == 2 ) {
                  mat = PyMem_Malloc( matSize * matSize *
                                  sizeof( float ) );
                  mat[0] = 1.0f;
                  mat[1] = 0.0f;
                  mat[2] = 0.0f;
                  mat[3] = 0.0f;
            } else if( ( ( strcmp( plane, "y" ) == 0 )
                       || ( strcmp( plane, "Y" ) == 0 ) )
                     && matSize == 2 ) {
                  mat = PyMem_Malloc( matSize * matSize *
                                  sizeof( float ) );
                  mat[0] = 0.0f;
                  mat[1] = 0.0f;
                  mat[2] = 0.0f;
                  mat[3] = 1.0f;
            } else if( ( ( strcmp( plane, "xy" ) == 0 )
                       || ( strcmp( plane, "XY" ) == 0 ) )
                     && matSize > 2 ) {
                  mat = PyMem_Malloc( matSize * matSize *
                                  sizeof( float ) );
                  mat[0] = 1.0f;
                  mat[1] = 0.0f;
                  mat[2] = 0.0f;
                  mat[3] = 0.0f;
                  mat[4] = 1.0f;
                  mat[5] = 0.0f;
                  mat[6] = 0.0f;
                  mat[7] = 0.0f;
                  mat[8] = 0.0f;
            } else if( ( ( strcmp( plane, "xz" ) == 0 )
                       || ( strcmp( plane, "XZ" ) == 0 ) )
                     && matSize > 2 ) {
                  mat = PyMem_Malloc( matSize * matSize *
                                  sizeof( float ) );
                  mat[0] = 1.0f;
                  mat[1] = 0.0f;
                  mat[2] = 0.0f;
                  mat[3] = 0.0f;
                  mat[4] = 0.0f;
                  mat[5] = 0.0f;
                  mat[6] = 0.0f;
                  mat[7] = 0.0f;
                  mat[8] = 1.0f;
            } else if( ( ( strcmp( plane, "yz" ) == 0 )
                       || ( strcmp( plane, "YZ" ) == 0 ) )
                     && matSize > 2 ) {
                  mat = PyMem_Malloc( matSize * matSize *
                                  sizeof( float ) );
                  mat[0] = 0.0f;
                  mat[1] = 0.0f;
                  mat[2] = 0.0f;
                  mat[3] = 0.0f;
                  mat[4] = 1.0f;
                  mat[5] = 0.0f;
                  mat[6] = 0.0f;
                  mat[7] = 0.0f;
                  mat[8] = 1.0f;
            } else {
                  return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                          "unknown plane - expected: x, y, xy, xz, yz\n" );
            }
      } else {          //arbitrary plane
            //normalize arbitrary axis
            for( x = 0; x < vec->size; x++ ) {
                  norm += vec->vec[x] * vec->vec[x];
            }
            norm = ( float ) sqrt( norm );

            for( x = 0; x < vec->size; x++ ) {
                  vec->vec[x] /= norm;
            }

            if( ( ( strcmp( plane, "r" ) == 0 )
                  || ( strcmp( plane, "R" ) == 0 ) ) && matSize == 2 ) {
                  mat = PyMem_Malloc( matSize * matSize *
                                  sizeof( float ) );
                  mat[0] = 1 - ( vec->vec[0] * vec->vec[0] );
                  mat[1] = -( vec->vec[0] * vec->vec[1] );
                  mat[2] = -( vec->vec[0] * vec->vec[1] );
                  mat[3] = 1 - ( vec->vec[1] * vec->vec[1] );
            } else if( ( ( strcmp( plane, "r" ) == 0 )
                       || ( strcmp( plane, "R" ) == 0 ) )
                     && matSize > 2 ) {
                  mat = PyMem_Malloc( matSize * matSize *
                                  sizeof( float ) );
                  mat[0] = 1 - ( vec->vec[0] * vec->vec[0] );
                  mat[1] = -( vec->vec[0] * vec->vec[1] );
                  mat[2] = -( vec->vec[0] * vec->vec[2] );
                  mat[3] = -( vec->vec[0] * vec->vec[1] );
                  mat[4] = 1 - ( vec->vec[1] * vec->vec[1] );
                  mat[5] = -( vec->vec[1] * vec->vec[2] );
                  mat[6] = -( vec->vec[0] * vec->vec[2] );
                  mat[7] = -( vec->vec[1] * vec->vec[2] );
                  mat[8] = 1 - ( vec->vec[2] * vec->vec[2] );
            } else {
                  return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                          "unknown plane - expected: 'r' expected for axis designation\n" );
            }
      }

      if( matSize == 4 ) {
            //resize matrix
            mat[15] = 1.0f;
            mat[14] = 0.0f;
            mat[13] = 0.0f;
            mat[12] = 0.0f;
            mat[11] = 0.0f;
            mat[10] = mat[8];
            mat[9] = mat[7];
            mat[8] = mat[6];
            mat[7] = 0.0f;
            mat[6] = mat[5];
            mat[5] = mat[4];
            mat[4] = mat[3];
            mat[3] = 0.0f;
      }
      //pass to matrix creation
      retval =  newMatrixObject( mat, matSize, matSize );
      
      PyMem_Free( mat );
      return retval;
}

//***************************************************************************
// Function:      M_Mathutils_ShearMatrix  
// Python equivalent:       Blender.Mathutils.ShearMatrix 
//***************************************************************************
static PyObject *M_Mathutils_ShearMatrix( PyObject * self, PyObject * args )
{
      float factor;
      int matSize;
      char *plane;
      float *mat;
      PyObject *retval;

      if( !PyArg_ParseTuple( args, "sfi", &plane, &factor, &matSize ) ) {
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "expected string float and int\n" ) );
      }

      if( matSize != 2 && matSize != 3 && matSize != 4 )
            return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                    "can only return a 2x2 3x3 or 4x4 matrix\n" );

      if( ( ( strcmp( plane, "x" ) == 0 ) || ( strcmp( plane, "X" ) == 0 ) )
          && matSize == 2 ) {
            mat = PyMem_Malloc( matSize * matSize * sizeof( float ) );
            mat[0] = 1.0f;
            mat[1] = 0.0f;
            mat[2] = factor;
            mat[3] = 1.0f;
      } else if( ( ( strcmp( plane, "y" ) == 0 )
                 || ( strcmp( plane, "Y" ) == 0 ) ) && matSize == 2 ) {
            mat = PyMem_Malloc( matSize * matSize * sizeof( float ) );
            mat[0] = 1.0f;
            mat[1] = factor;
            mat[2] = 0.0f;
            mat[3] = 1.0f;
      } else if( ( ( strcmp( plane, "xy" ) == 0 )
                 || ( strcmp( plane, "XY" ) == 0 ) ) && matSize > 2 ) {
            mat = PyMem_Malloc( matSize * matSize * sizeof( float ) );
            mat[0] = 1.0f;
            mat[1] = 0.0f;
            mat[2] = 0.0f;
            mat[3] = 0.0f;
            mat[4] = 1.0f;
            mat[5] = 0.0f;
            mat[6] = factor;
            mat[7] = factor;
            mat[8] = 0.0f;
      } else if( ( ( strcmp( plane, "xz" ) == 0 )
                 || ( strcmp( plane, "XZ" ) == 0 ) ) && matSize > 2 ) {
            mat = PyMem_Malloc( matSize * matSize * sizeof( float ) );
            mat[0] = 1.0f;
            mat[1] = 0.0f;
            mat[2] = 0.0f;
            mat[3] = factor;
            mat[4] = 1.0f;
            mat[5] = factor;
            mat[6] = 0.0f;
            mat[7] = 0.0f;
            mat[8] = 1.0f;
      } else if( ( ( strcmp( plane, "yz" ) == 0 )
                 || ( strcmp( plane, "YZ" ) == 0 ) ) && matSize > 2 ) {
            mat = PyMem_Malloc( matSize * matSize * sizeof( float ) );
            mat[0] = 1.0f;
            mat[1] = factor;
            mat[2] = factor;
            mat[3] = 0.0f;
            mat[4] = 1.0f;
            mat[5] = 0.0f;
            mat[6] = 0.0f;
            mat[7] = 0.0f;
            mat[8] = 1.0f;
      } else {
            return EXPP_ReturnPyObjError( PyExc_AttributeError,
                                    "expected: x, y, xy, xz, yz or wrong matrix size for shearing plane\n" );
      }

      if( matSize == 4 ) {
            //resize matrix
            mat[15] = 1.0f;
            mat[14] = 0.0f;
            mat[13] = 0.0f;
            mat[12] = 0.0f;
            mat[11] = 0.0f;
            mat[10] = mat[8];
            mat[9] = mat[7];
            mat[8] = mat[6];
            mat[7] = 0.0f;
            mat[6] = mat[5];
            mat[5] = mat[4];
            mat[4] = mat[3];
            mat[3] = 0.0f;
      }
      //pass to matrix creation
      retval = newMatrixObject( mat, matSize, matSize );

      PyMem_Free( mat );
      return retval;
}

//***************************************************************************
//Begin Matrix Utils

static PyObject *M_Mathutils_CopyMat( PyObject * self, PyObject * args )
{
      MatrixObject *matrix;
      float *mat;
      int x, y, z;
      PyObject *retval;

      if( !PyArg_ParseTuple( args, "O!", &matrix_Type, &matrix ) )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "expected matrix\n" ) );

      mat = PyMem_Malloc( matrix->rowSize * matrix->colSize *
                      sizeof( float ) );

      z = 0;
      for( x = 0; x < matrix->rowSize; x++ ) {
            for( y = 0; y < matrix->colSize; y++ ) {
                  mat[z] = matrix->matrix[x][y];
                  z++;
            }
      }

      retval =  ( PyObject * ) newMatrixObject( mat, matrix->rowSize,
                                      matrix->colSize );
      PyMem_Free( mat );
      return retval;
}

static PyObject *M_Mathutils_MatMultVec( PyObject * self, PyObject * args )
{

      PyObject *ob1 = NULL;
      PyObject *ob2 = NULL;
      MatrixObject *mat;
      VectorObject *vec;
      PyObject *retval;
      float *vecNew;
      int x, y;
      int z = 0;
      float dot = 0.0f;

      //get pyObjects
      if( !PyArg_ParseTuple
          ( args, "O!O!", &matrix_Type, &ob1, &vector_Type, &ob2 ) )
            return ( EXPP_ReturnPyObjError
                   ( PyExc_TypeError,
                     "matrix and vector object expected - in that order\n" ) );

      mat = ( MatrixObject * ) ob1;
      vec = ( VectorObject * ) ob2;

      if( mat->rowSize != vec->size )
            return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
                                    "matrix row size and vector size must be the same\n" ) );

      vecNew = PyMem_Malloc( vec->size * sizeof( float ) );

      for( x = 0; x < mat->rowSize; x++ ) {
            for( y = 0; y < mat->colSize; y++ ) {
                  dot += mat->matrix[x][y] * vec->vec[y];
            }
            vecNew[z] = dot;
            z++;
            dot = 0;
      }

      retval =  ( PyObject * ) newVectorObject( vecNew, vec->size );

      PyMem_Free( vecNew );
      return retval;
}

//***************************************************************************
// Function:     M_Mathutils_Quaternion   
// Python equivalent:       Blender.Mathutils.Quaternion   
//***************************************************************************
static PyObject *M_Mathutils_Quaternion( PyObject * self, PyObject * args )
{
      PyObject *listObject;
      float *vec = NULL;
      float *quat = NULL;
      float angle = 0.0f;
      int x;
      float norm;
      PyObject *retval;

      if( !PyArg_ParseTuple
          ( args, "O!|f", &PyList_Type, &listObject, &angle ) )
            return ( EXPP_ReturnPyObjError
                   ( PyExc_TypeError,
                     "expected list and optional float\n" ) );

      if( PyList_Size( listObject ) != 4 && PyList_Size( listObject ) != 3 )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "3 or 4 expected floats for the quaternion\n" ) );

      vec = PyMem_Malloc( PyList_Size( listObject ) * sizeof( float ) );
      for( x = 0; x < PyList_Size( listObject ); x++ ) {
            if( !PyArg_Parse
                ( PyList_GetItem( listObject, x ), "f", &vec[x] ) )
                  return EXPP_ReturnPyObjError( PyExc_TypeError,
                                          "python list not parseable\n" );
      }

      if( PyList_Size( listObject ) == 3 ) {    //an axis of rotation
            norm = ( float ) sqrt( vec[0] * vec[0] + vec[1] * vec[1] +
                               vec[2] * vec[2] );

            vec[0] /= norm;
            vec[1] /= norm;
            vec[2] /= norm;

            angle = angle * ( float ) ( Py_PI / 180 );
            quat = PyMem_Malloc( 4 * sizeof( float ) );
            quat[0] = ( float ) ( cos( ( double ) ( angle ) / 2 ) );
            quat[1] =
                  ( float ) ( sin( ( double ) ( angle ) / 2 ) ) * vec[0];
            quat[2] =
                  ( float ) ( sin( ( double ) ( angle ) / 2 ) ) * vec[1];
            quat[3] =
                  ( float ) ( sin( ( double ) ( angle ) / 2 ) ) * vec[2];

            retval = newQuaternionObject( quat );
      } else
            retval = newQuaternionObject( vec );

      /* freeing a NULL ptr is ok */
      PyMem_Free( vec );
      PyMem_Free( quat );
      
      return retval;
}

//***************************************************************************
//Begin Quaternion Utils

static PyObject *M_Mathutils_CopyQuat( PyObject * self, PyObject * args )
{
      QuaternionObject *quatU;
      float *quat = NULL;
      PyObject *retval;

      if( !PyArg_ParseTuple( args, "O!", &quaternion_Type, &quatU ) )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "expected Quaternion type" ) );

      quat = PyMem_Malloc( 4 * sizeof( float ) );
      quat[0] = quatU->quat[0];
      quat[1] = quatU->quat[1];
      quat[2] = quatU->quat[2];
      quat[3] = quatU->quat[3];

      retval = ( PyObject * ) newQuaternionObject( quat );
      PyMem_Free( quat );
      return retval;
}

static PyObject *M_Mathutils_CrossQuats( PyObject * self, PyObject * args )
{
      QuaternionObject *quatU;
      QuaternionObject *quatV;
      float *quat = NULL;
      PyObject *retval;

      if( !PyArg_ParseTuple( args, "O!O!", &quaternion_Type, &quatU,
                         &quaternion_Type, &quatV ) )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "expected Quaternion types" ) );
      quat = PyMem_Malloc( 4 * sizeof( float ) );
      QuatMul( quat, quatU->quat, quatV->quat );

      retval = ( PyObject * ) newQuaternionObject( quat );
      PyMem_Free( quat );
      return retval;
}

static PyObject *M_Mathutils_DotQuats( PyObject * self, PyObject * args )
{
      QuaternionObject *quatU;
      QuaternionObject *quatV;
      int x;
      float dot = 0.0f;

      if( !PyArg_ParseTuple( args, "O!O!", &quaternion_Type, &quatU,
                         &quaternion_Type, &quatV ) )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "expected Quaternion types" ) );

      for( x = 0; x < 4; x++ ) {
            dot += quatU->quat[x] * quatV->quat[x];
      }

      return PyFloat_FromDouble( ( double ) ( dot ) );
}

static PyObject *M_Mathutils_DifferenceQuats( PyObject * self,
                                    PyObject * args )
{
      QuaternionObject *quatU;
      QuaternionObject *quatV;
      float *quat = NULL;
      float *tempQuat = NULL;
      PyObject *retval;
      int x;
      float dot = 0.0f;

      if( !PyArg_ParseTuple( args, "O!O!", &quaternion_Type,
                         &quatU, &quaternion_Type, &quatV ) )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "expected Quaternion types" ) );

      quat = PyMem_Malloc( 4 * sizeof( float ) );
      tempQuat = PyMem_Malloc( 4 * sizeof( float ) );

      tempQuat[0] = quatU->quat[0];
      tempQuat[1] = -quatU->quat[1];
      tempQuat[2] = -quatU->quat[2];
      tempQuat[3] = -quatU->quat[3];

      dot = ( float ) sqrt( ( double ) tempQuat[0] * ( double ) tempQuat[0] +
                        ( double ) tempQuat[1] * ( double ) tempQuat[1] +
                        ( double ) tempQuat[2] * ( double ) tempQuat[2] +
                        ( double ) tempQuat[3] *
                        ( double ) tempQuat[3] );

      for( x = 0; x < 4; x++ ) {
            tempQuat[x] /= ( dot * dot );
      }
      QuatMul( quat, tempQuat, quatV->quat );

      retval = ( PyObject * ) newQuaternionObject( quat );

      PyMem_Free( quat );
      PyMem_Free( tempQuat );
      return retval;
}

static PyObject *M_Mathutils_Slerp( PyObject * self, PyObject * args )
{
      QuaternionObject *quatU;
      QuaternionObject *quatV;
      float *quat = NULL;
      PyObject *retval;
      float param, x, y, cosD, sinD, deltaD, IsinD, val;
      int flag, z;

      if( !PyArg_ParseTuple( args, "O!O!f", &quaternion_Type,
                         &quatU, &quaternion_Type, &quatV, &param ) )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "expected Quaternion types and float" ) );

      quat = PyMem_Malloc( 4 * sizeof( float ) );

      cosD = quatU->quat[0] * quatV->quat[0] +
            quatU->quat[1] * quatV->quat[1] +
            quatU->quat[2] * quatV->quat[2] +
            quatU->quat[3] * quatV->quat[3];

      flag = 0;
      if( cosD < 0.0f ) {
            flag = 1;
            cosD = -cosD;
      }
      if( cosD > .99999f ) {
            x = 1.0f - param;
            y = param;
      } else {
            sinD = ( float ) sqrt( 1.0f - cosD * cosD );
            deltaD = ( float ) atan2( sinD, cosD );
            IsinD = 1.0f / sinD;
            x = ( float ) sin( ( 1.0f - param ) * deltaD ) * IsinD;
            y = ( float ) sin( param * deltaD ) * IsinD;
      }
      for( z = 0; z < 4; z++ ) {
            val = quatV->quat[z];
            if( val )
                  val = -val;
            quat[z] = ( quatU->quat[z] * x ) + ( val * y );
      }
      retval = ( PyObject * ) newQuaternionObject( quat );
      PyMem_Free( quat );
      return retval;
}

//***************************************************************************
// Function:     M_Mathutils_Euler        
// Python equivalent:      Blender.Mathutils.Euler    
//***************************************************************************
static PyObject *M_Mathutils_Euler( PyObject * self, PyObject * args )
{
      PyObject *listObject;
      float *vec = NULL;
      PyObject *retval;
      int x;

      if( !PyArg_ParseTuple( args, "O!", &PyList_Type, &listObject ) )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "expected list\n" ) );

      if( PyList_Size( listObject ) != 3 )
            return EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "only 3d eulers are supported\n" );

      vec = PyMem_Malloc( 3 * sizeof( float ) );
      for( x = 0; x < 3; x++ ) {
            if( !PyArg_Parse
                ( PyList_GetItem( listObject, x ), "f", &vec[x] ) )
                  return EXPP_ReturnPyObjError( PyExc_TypeError,
                                          "python list not parseable\n" );
      }

      retval = ( PyObject * ) newEulerObject( vec );

      PyMem_Free( vec );
      return retval;
}


//***************************************************************************
//Begin Euler Util

static PyObject *M_Mathutils_CopyEuler( PyObject * self, PyObject * args )
{
      EulerObject *eulU;
      float *eul = NULL;
      PyObject *retval;

      if( !PyArg_ParseTuple( args, "O!", &euler_Type, &eulU ) )
            return ( EXPP_ReturnPyObjError( PyExc_TypeError,
                                    "expected Euler types" ) );

      eul = PyMem_Malloc( 3 * sizeof( float ) );
      eul[0] = eulU->eul[0];
      eul[1] = eulU->eul[1];
      eul[2] = eulU->eul[2];

      retval = ( PyObject * ) newEulerObject( eul );
      PyMem_Free( eul );
      return retval;
}

static PyObject *M_Mathutils_RotateEuler( PyObject * self, PyObject * args )
{
      EulerObject *Eul;
      float angle;
      char *axis;
      int x;

      if( !PyArg_ParseTuple
          ( args, "O!fs", &euler_Type, &Eul, &angle, &axis ) )
            return ( EXPP_ReturnPyObjError
                   ( PyExc_TypeError,
                     "expected euler type & float & string" ) );

      angle *= ( float ) ( Py_PI / 180 );
      for( x = 0; x < 3; x++ ) {
            Eul->eul[x] *= ( float ) ( Py_PI / 180 );
      }
      euler_rot( Eul->eul, angle, *axis );
      for( x = 0; x < 3; x++ ) {
            Eul->eul[x] *= ( float ) ( 180 / Py_PI );
      }

      return EXPP_incr_ret( Py_None );
}

//***************************************************************************
// Function:      Mathutils_Init     
//***************************************************************************
PyObject *Mathutils_Init( void )
{
      PyObject *mod =
            Py_InitModule3( "Blender.Mathutils", M_Mathutils_methods,
                        M_Mathutils_doc );
      return ( mod );
}

Generated by  Doxygen 1.6.0   Back to index