Run everything thru indent to cleanup spaces vs tabs. Clean up some of the comments by hand. BGL.c was not touched due to all that macro wackyness. There are no functional changes to the code. Pre-indent versions of source are tagged with tag bpy-cleanup-20040925 , just in case.
932 lines
27 KiB
C
932 lines
27 KiB
C
/*
|
|
* $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): Michel Selten & Joseph Gilbert
|
|
*
|
|
* ***** END GPL/BL DUAL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#include "matrix.h"
|
|
|
|
//doc strings
|
|
char Matrix_Zero_doc[] = "() - set all values in the matrix to 0";
|
|
char Matrix_Identity_doc[] =
|
|
"() - set the square matrix to it's identity matrix";
|
|
char Matrix_Transpose_doc[] = "() - set the matrix to it's transpose";
|
|
char Matrix_Determinant_doc[] = "() - return the determinant of the matrix";
|
|
char Matrix_Invert_doc[] =
|
|
"() - set the matrix to it's inverse if an inverse is possible";
|
|
char Matrix_TranslationPart_doc[] =
|
|
"() - return a vector encompassing the translation of the matrix";
|
|
char Matrix_RotationPart_doc[] =
|
|
"() - return a vector encompassing the rotation of the matrix";
|
|
char Matrix_Resize4x4_doc[] = "() - resize the matrix to a 4x4 square matrix";
|
|
char Matrix_toEuler_doc[] = "() - convert matrix to a euler angle rotation";
|
|
char Matrix_toQuat_doc[] = "() - convert matrix to a quaternion rotation";
|
|
|
|
//methods table
|
|
struct PyMethodDef Matrix_methods[] = {
|
|
{"zero", ( PyCFunction ) Matrix_Zero, METH_NOARGS,
|
|
Matrix_Zero_doc},
|
|
{"identity", ( PyCFunction ) Matrix_Identity, METH_NOARGS,
|
|
Matrix_Identity_doc},
|
|
{"transpose", ( PyCFunction ) Matrix_Transpose, METH_NOARGS,
|
|
Matrix_Transpose_doc},
|
|
{"determinant", ( PyCFunction ) Matrix_Determinant, METH_NOARGS,
|
|
Matrix_Determinant_doc},
|
|
{"invert", ( PyCFunction ) Matrix_Invert, METH_NOARGS,
|
|
Matrix_Invert_doc},
|
|
{"translationPart", ( PyCFunction ) Matrix_TranslationPart,
|
|
METH_NOARGS,
|
|
Matrix_TranslationPart_doc},
|
|
{"rotationPart", ( PyCFunction ) Matrix_RotationPart, METH_NOARGS,
|
|
Matrix_RotationPart_doc},
|
|
{"resize4x4", ( PyCFunction ) Matrix_Resize4x4, METH_NOARGS,
|
|
Matrix_Resize4x4_doc},
|
|
{"toEuler", ( PyCFunction ) Matrix_toEuler, METH_NOARGS,
|
|
Matrix_toEuler_doc},
|
|
{"toQuat", ( PyCFunction ) Matrix_toQuat, METH_NOARGS,
|
|
Matrix_toQuat_doc},
|
|
{NULL, NULL, 0, NULL}
|
|
};
|
|
|
|
/*****************************/
|
|
// Matrix Python Object
|
|
/*****************************/
|
|
|
|
PyObject *Matrix_toQuat( MatrixObject * self )
|
|
{
|
|
float *quat, *mat;
|
|
|
|
if( self->colSize < 3 ) {
|
|
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"inappropriate matrix size\n" );
|
|
} else if( self->colSize > 2 ) { //3 or 4 col
|
|
if( self->rowSize < 3 ) //3 or 4 row
|
|
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"inappropriate matrix size\n" );
|
|
|
|
mat = PyMem_Malloc( 3 * 3 * sizeof( float ) );
|
|
mat[0] = self->matrix[0][0];
|
|
mat[1] = self->matrix[0][1];
|
|
mat[2] = self->matrix[0][2];
|
|
mat[3] = self->matrix[1][0];
|
|
mat[4] = self->matrix[1][1];
|
|
mat[5] = self->matrix[1][2];
|
|
mat[6] = self->matrix[2][0];
|
|
mat[7] = self->matrix[2][1];
|
|
mat[8] = self->matrix[2][2];
|
|
}
|
|
quat = PyMem_Malloc( 4 * sizeof( float ) );
|
|
Mat3ToQuat( ( float ( * )[3] ) mat, quat );
|
|
|
|
return ( PyObject * ) newQuaternionObject( quat );
|
|
}
|
|
|
|
|
|
PyObject *Matrix_toEuler( MatrixObject * self )
|
|
{
|
|
float *eul, *mat;
|
|
int x;
|
|
|
|
if( self->colSize < 3 ) {
|
|
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"inappropriate matrix size\n" );
|
|
} else if( self->colSize > 2 ) { //3 or 4 col
|
|
if( self->rowSize < 3 ) //3 or 4 row
|
|
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"inappropriate matrix size\n" );
|
|
|
|
mat = PyMem_Malloc( 3 * 3 * sizeof( float ) );
|
|
mat[0] = self->matrix[0][0];
|
|
mat[1] = self->matrix[0][1];
|
|
mat[2] = self->matrix[0][2];
|
|
mat[3] = self->matrix[1][0];
|
|
mat[4] = self->matrix[1][1];
|
|
mat[5] = self->matrix[1][2];
|
|
mat[6] = self->matrix[2][0];
|
|
mat[7] = self->matrix[2][1];
|
|
mat[8] = self->matrix[2][2];
|
|
}
|
|
eul = PyMem_Malloc( 3 * sizeof( float ) );
|
|
Mat3ToEul( ( float ( * )[3] ) mat, eul );
|
|
|
|
for( x = 0; x < 3; x++ ) {
|
|
eul[x] *= ( float ) ( 180 / Py_PI );
|
|
}
|
|
|
|
return ( PyObject * ) newEulerObject( eul );
|
|
}
|
|
|
|
PyObject *Matrix_Resize4x4( MatrixObject * self )
|
|
{
|
|
float *mat;
|
|
float *contigPtr;
|
|
int x, row, col;
|
|
|
|
if( self->colSize == 4 && self->rowSize == 4 )
|
|
return EXPP_incr_ret( Py_None );
|
|
|
|
mat = PyMem_Malloc( 4 * 4 * sizeof( float ) );
|
|
for( x = 0; x < 16; x++ ) {
|
|
mat[x] = 0.0f;
|
|
}
|
|
|
|
if( self->colSize == 2 ) { //2x2, 2x3, 2x4
|
|
mat[0] = self->matrix[0][0];
|
|
mat[1] = self->matrix[0][1];
|
|
mat[4] = self->matrix[1][0];
|
|
mat[5] = self->matrix[1][1];
|
|
if( self->rowSize > 2 ) {
|
|
mat[8] = self->matrix[2][0];
|
|
mat[9] = self->matrix[2][1];
|
|
}
|
|
if( self->rowSize > 3 ) {
|
|
mat[12] = self->matrix[3][0];
|
|
mat[13] = self->matrix[3][1];
|
|
}
|
|
mat[10] = 1.0f;
|
|
mat[15] = 1.0f;
|
|
} else if( self->colSize == 3 ) { //3x2, 3x3, 3x4
|
|
mat[0] = self->matrix[0][0];
|
|
mat[1] = self->matrix[0][1];
|
|
mat[2] = self->matrix[0][2];
|
|
mat[4] = self->matrix[1][0];
|
|
mat[5] = self->matrix[1][1];
|
|
mat[6] = self->matrix[1][2];
|
|
if( self->rowSize > 2 ) {
|
|
mat[8] = self->matrix[2][0];
|
|
mat[9] = self->matrix[2][1];
|
|
mat[10] = self->matrix[2][2];
|
|
}
|
|
if( self->rowSize > 3 ) {
|
|
mat[12] = self->matrix[3][0];
|
|
mat[13] = self->matrix[3][1];
|
|
mat[14] = self->matrix[3][2];
|
|
}
|
|
if( self->rowSize == 2 )
|
|
mat[10] = 1.0f;
|
|
mat[15] = 1.0f;
|
|
} else if( self->colSize == 4 ) { //2x4, 3x4
|
|
mat[0] = self->matrix[0][0];
|
|
mat[1] = self->matrix[0][1];
|
|
mat[2] = self->matrix[0][2];
|
|
mat[3] = self->matrix[0][3];
|
|
mat[4] = self->matrix[1][0];
|
|
mat[5] = self->matrix[1][1];
|
|
mat[6] = self->matrix[1][2];
|
|
mat[7] = self->matrix[1][3];
|
|
if( self->rowSize > 2 ) {
|
|
mat[8] = self->matrix[2][0];
|
|
mat[9] = self->matrix[2][1];
|
|
mat[10] = self->matrix[2][2];
|
|
mat[11] = self->matrix[2][3];
|
|
}
|
|
if( self->rowSize == 2 )
|
|
mat[10] = 1.0f;
|
|
mat[15] = 1.0f;
|
|
}
|
|
|
|
PyMem_Free( *self->matrix );
|
|
contigPtr = PyMem_Malloc( 4 * 4 * sizeof( float ) );
|
|
if( contigPtr == NULL ) {
|
|
return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
|
|
"problem allocating array space\n\n" ) );
|
|
}
|
|
self->matrix = PyMem_Malloc( 4 * sizeof( float * ) );
|
|
if( self->matrix == NULL ) {
|
|
return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
|
|
"problem allocating pointer space\n\n" ) );
|
|
}
|
|
for( x = 0; x < 4; x++ ) {
|
|
self->matrix[x] = contigPtr + ( x * 4 );
|
|
}
|
|
|
|
for( row = 0; row < 4; row++ ) {
|
|
for( col = 0; col < 4; col++ ) {
|
|
self->matrix[row][col] = mat[( row * 4 ) + col];
|
|
}
|
|
}
|
|
PyMem_Free( mat );
|
|
|
|
self->colSize = 4;
|
|
self->rowSize = 4;
|
|
|
|
return EXPP_incr_ret( Py_None );
|
|
}
|
|
|
|
PyObject *Matrix_TranslationPart( MatrixObject * self )
|
|
{
|
|
float *vec;
|
|
|
|
if( self->colSize < 3 ) {
|
|
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"inappropriate matrix size\n" );
|
|
} else if( self->colSize > 2 ) { //3 or 4 columns
|
|
if( self->rowSize < 4 ) //all 4 rows
|
|
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"inappropriate matrix size\n" );
|
|
|
|
vec = PyMem_Malloc( 3 * sizeof( float ) );
|
|
vec[0] = self->matrix[3][0];
|
|
vec[1] = self->matrix[3][1];
|
|
vec[2] = self->matrix[3][2];
|
|
}
|
|
|
|
return ( PyObject * ) newVectorObject( vec, 3 );
|
|
}
|
|
|
|
PyObject *Matrix_RotationPart( MatrixObject * self )
|
|
{
|
|
float *mat;
|
|
|
|
if( self->colSize < 3 ) {
|
|
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"inappropriate matrix size\n" );
|
|
} else if( self->colSize > 2 ) { //3 or 4 col
|
|
if( self->rowSize < 3 ) //3 or 4 row
|
|
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"inappropriate matrix size\n" );
|
|
|
|
mat = PyMem_Malloc( 3 * 3 * sizeof( float ) );
|
|
mat[0] = self->matrix[0][0];
|
|
mat[1] = self->matrix[0][1];
|
|
mat[2] = self->matrix[0][2];
|
|
mat[3] = self->matrix[1][0];
|
|
mat[4] = self->matrix[1][1];
|
|
mat[5] = self->matrix[1][2];
|
|
mat[6] = self->matrix[2][0];
|
|
mat[7] = self->matrix[2][1];
|
|
mat[8] = self->matrix[2][2];
|
|
}
|
|
|
|
return ( PyObject * ) newMatrixObject( mat, 3, 3 );
|
|
}
|
|
|
|
PyObject *Matrix_Invert( MatrixObject * self )
|
|
{
|
|
float det;
|
|
int x, y, z;
|
|
float *mat = NULL;
|
|
float t;
|
|
|
|
if( self->rowSize != self->colSize )
|
|
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"only square matrices are supported\n" );
|
|
|
|
//calculate the determinant
|
|
if( self->rowSize == 2 ) {
|
|
det = Det2x2( self->matrix[0][0], self->matrix[0][1],
|
|
self->matrix[1][0], self->matrix[1][1] );
|
|
} else if( self->rowSize == 3 ) {
|
|
det = Det3x3( self->matrix[0][0], self->matrix[0][1],
|
|
self->matrix[0][2], self->matrix[1][0],
|
|
self->matrix[1][1], self->matrix[1][2],
|
|
self->matrix[2][0], self->matrix[2][1],
|
|
self->matrix[2][2] );
|
|
} else if( self->rowSize == 4 ) {
|
|
det = Det4x4( *self->matrix );
|
|
} else {
|
|
return EXPP_ReturnPyObjError( PyExc_StandardError,
|
|
"error calculating determinant for inverse()\n" );
|
|
}
|
|
|
|
if( det != 0 ) {
|
|
|
|
//calculate the classical adjoint
|
|
if( self->rowSize == 2 ) {
|
|
mat = PyMem_Malloc( self->rowSize * self->colSize *
|
|
sizeof( float ) );
|
|
mat[0] = self->matrix[1][1];
|
|
mat[1] = -self->matrix[1][0];
|
|
mat[2] = -self->matrix[0][1];
|
|
mat[3] = self->matrix[0][0];
|
|
} else if( self->rowSize == 3 ) {
|
|
mat = PyMem_Malloc( self->rowSize * self->colSize *
|
|
sizeof( float ) );
|
|
Mat3Adj( ( float ( * )[3] ) mat, *self->matrix );
|
|
} else if( self->rowSize == 4 ) {
|
|
mat = PyMem_Malloc( self->rowSize * self->colSize *
|
|
sizeof( float ) );
|
|
Mat4Adj( ( float ( * )[4] ) mat, *self->matrix );
|
|
}
|
|
//divide by determinate
|
|
for( x = 0; x < ( self->rowSize * self->colSize ); x++ ) {
|
|
mat[x] /= det;
|
|
}
|
|
|
|
//set values
|
|
z = 0;
|
|
for( x = 0; x < self->rowSize; x++ ) {
|
|
for( y = 0; y < self->colSize; y++ ) {
|
|
self->matrix[x][y] = mat[z];
|
|
z++;
|
|
}
|
|
}
|
|
|
|
//transpose
|
|
if( self->rowSize == 2 ) {
|
|
t = self->matrix[1][0];
|
|
self->matrix[1][0] = self->matrix[0][1];
|
|
self->matrix[0][1] = t;
|
|
} else if( self->rowSize == 3 ) {
|
|
Mat3Transp( ( float ( * )[3] ) mat );
|
|
} else if( self->rowSize == 4 ) {
|
|
Mat4Transp( ( float ( * )[4] ) mat );
|
|
}
|
|
} else {
|
|
printf( "matrix does not have an inverse - none attempted\n" );
|
|
}
|
|
|
|
return EXPP_incr_ret( Py_None );
|
|
}
|
|
|
|
|
|
PyObject *Matrix_Determinant( MatrixObject * self )
|
|
{
|
|
float det;
|
|
|
|
if( self->rowSize != self->colSize )
|
|
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"only square matrices are supported\n" );
|
|
|
|
if( self->rowSize == 2 ) {
|
|
det = Det2x2( self->matrix[0][0], self->matrix[0][1],
|
|
self->matrix[1][0], self->matrix[1][1] );
|
|
} else if( self->rowSize == 3 ) {
|
|
det = Det3x3( self->matrix[0][0], self->matrix[0][1],
|
|
self->matrix[0][2], self->matrix[1][0],
|
|
self->matrix[1][1], self->matrix[1][2],
|
|
self->matrix[2][0], self->matrix[2][1],
|
|
self->matrix[2][2] );
|
|
} else if( self->rowSize == 4 ) {
|
|
det = Det4x4( *self->matrix );
|
|
} else {
|
|
return EXPP_ReturnPyObjError( PyExc_StandardError,
|
|
"error in determinant()\n" );
|
|
}
|
|
return PyFloat_FromDouble( det );
|
|
}
|
|
|
|
PyObject *Matrix_Transpose( MatrixObject * self )
|
|
{
|
|
float t;
|
|
|
|
if( self->rowSize != self->colSize )
|
|
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"only square matrices are supported\n" );
|
|
|
|
if( self->rowSize == 2 ) {
|
|
t = self->matrix[1][0];
|
|
self->matrix[1][0] = self->matrix[0][1];
|
|
self->matrix[0][1] = t;
|
|
} else if( self->rowSize == 3 ) {
|
|
Mat3Transp( *self->matrix );
|
|
} else if( self->rowSize == 4 ) {
|
|
Mat4Transp( *self->matrix );
|
|
} else
|
|
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
|
|
"unable to transpose matrix\n" ) );
|
|
|
|
return EXPP_incr_ret( Py_None );
|
|
}
|
|
|
|
PyObject *Matrix_Zero( MatrixObject * self )
|
|
{
|
|
int row, col;
|
|
|
|
for( row = 0; row < self->rowSize; row++ ) {
|
|
for( col = 0; col < self->colSize; col++ ) {
|
|
self->matrix[row][col] = 0.0f;
|
|
}
|
|
}
|
|
return EXPP_incr_ret( Py_None );
|
|
}
|
|
|
|
PyObject *Matrix_Identity( MatrixObject * self )
|
|
{
|
|
if( self->rowSize != self->colSize )
|
|
return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"only square matrices supported\n" ) );
|
|
|
|
if( self->rowSize == 2 ) {
|
|
self->matrix[0][0] = 1.0f;
|
|
self->matrix[0][1] = 0.0f;
|
|
self->matrix[1][0] = 0.0f;
|
|
self->matrix[1][1] = 1.0f;
|
|
} else if( self->rowSize == 3 ) {
|
|
Mat3One( *self->matrix );
|
|
} else if( self->rowSize == 4 ) {
|
|
Mat4One( *self->matrix );
|
|
} else
|
|
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
|
|
"unable to create identity matrix\n" ) );
|
|
|
|
return EXPP_incr_ret( Py_None );
|
|
}
|
|
|
|
static void Matrix_dealloc( MatrixObject * self )
|
|
{
|
|
PyMem_Free( self->matrix );
|
|
PyMem_DEL( self );
|
|
}
|
|
|
|
static PyObject *Matrix_getattr( MatrixObject * self, char *name )
|
|
{
|
|
if( strcmp( name, "rowSize" ) == 0 ) {
|
|
return PyInt_FromLong( ( long ) self->rowSize );
|
|
} else if( strcmp( name, "colSize" ) == 0 ) {
|
|
return PyInt_FromLong( ( long ) self->colSize );
|
|
}
|
|
|
|
return Py_FindMethod( Matrix_methods, ( PyObject * ) self, name );
|
|
}
|
|
|
|
static int Matrix_setattr( MatrixObject * self, char *name, PyObject * v )
|
|
{
|
|
/* This is not supported. */
|
|
return ( -1 );
|
|
}
|
|
|
|
static PyObject *Matrix_repr( MatrixObject * self )
|
|
{
|
|
PyObject *repr, *str;
|
|
int x, y;
|
|
char ftoa[24];
|
|
|
|
repr = PyString_FromString( "" );
|
|
if( !repr )
|
|
return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"Attribute error in PyMatrix (repr)\n" ) );
|
|
|
|
for( x = 0; x < self->rowSize; x++ ) {
|
|
str = PyString_FromString( "[" );
|
|
PyString_ConcatAndDel( &repr, str );
|
|
|
|
for( y = 0; y < ( self->colSize - 1 ); y++ ) {
|
|
sprintf( ftoa, "%.4f, ", self->matrix[x][y] );
|
|
str = PyString_FromString( ftoa );
|
|
PyString_ConcatAndDel( &repr, str );
|
|
}
|
|
sprintf( ftoa, "%.4f]\n", self->matrix[x][y] );
|
|
str = PyString_FromString( ftoa );
|
|
PyString_ConcatAndDel( &repr, str );
|
|
}
|
|
return repr;
|
|
}
|
|
|
|
//no support for matrix[x][y] so have to return by sequence index
|
|
//will return a row from the matrix to support previous API
|
|
//compatability
|
|
static PyObject *Matrix_item( MatrixObject * self, int i )
|
|
{
|
|
float *vec;
|
|
int x;
|
|
|
|
if( i < 0 || i >= self->rowSize )
|
|
return EXPP_ReturnPyObjError( PyExc_IndexError,
|
|
"matrix row index out of range\n" );
|
|
|
|
vec = PyMem_Malloc( self->colSize * sizeof( float ) );
|
|
for( x = 0; x < self->colSize; x++ ) {
|
|
vec[x] = self->matrix[i][x];
|
|
}
|
|
|
|
return ( PyObject * ) newVectorObject( vec, self->colSize );
|
|
}
|
|
|
|
static PyObject *Matrix_slice( MatrixObject * self, int begin, int end )
|
|
{
|
|
PyObject *list;
|
|
int count, maxsize, x, y;
|
|
|
|
maxsize = self->colSize * self->rowSize;
|
|
if( begin < 0 )
|
|
begin = 0;
|
|
if( end > maxsize )
|
|
end = maxsize;
|
|
if( begin > end )
|
|
begin = end;
|
|
|
|
list = PyList_New( end - begin );
|
|
|
|
for( count = begin; count < end; count++ ) {
|
|
x = ( int ) floor( ( double ) ( count / self->colSize ) );
|
|
y = count % self->colSize;
|
|
PyList_SetItem( list, count - begin,
|
|
PyFloat_FromDouble( self->matrix[x][y] ) );
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
static int Matrix_ass_item( MatrixObject * self, int i, PyObject * ob )
|
|
{
|
|
int maxsize, x, y;
|
|
|
|
maxsize = self->colSize * self->rowSize;
|
|
if( i < 0 || i >= maxsize )
|
|
return EXPP_ReturnIntError( PyExc_IndexError,
|
|
"array assignment index out of range\n" );
|
|
if( !PyInt_Check( ob ) && !PyFloat_Check( ob ) )
|
|
return EXPP_ReturnIntError( PyExc_IndexError,
|
|
"matrix member must be a number\n" );
|
|
|
|
x = ( int ) floor( ( double ) ( i / self->colSize ) );
|
|
y = i % self->colSize;
|
|
self->matrix[x][y] = ( float ) PyFloat_AsDouble( ob );
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int Matrix_ass_slice( MatrixObject * self, int begin, int end,
|
|
PyObject * seq )
|
|
{
|
|
int count, maxsize, x, y, z;
|
|
|
|
maxsize = self->colSize * self->rowSize;
|
|
if( begin < 0 )
|
|
begin = 0;
|
|
if( end > maxsize )
|
|
end = maxsize;
|
|
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( !PyInt_Check( ob ) && !PyFloat_Check( ob ) )
|
|
return EXPP_ReturnIntError( PyExc_IndexError,
|
|
"list member must be a number\n" );
|
|
|
|
x = ( int ) floor( ( double ) ( count / self->colSize ) );
|
|
y = count % self->colSize;
|
|
if( !PyArg_Parse( ob, "f", &self->matrix[x][y] ) ) {
|
|
Py_DECREF( ob );
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int Matrix_len( MatrixObject * self )
|
|
{
|
|
return ( self->colSize * self->rowSize );
|
|
}
|
|
|
|
PyObject *Matrix_add( PyObject * m1, PyObject * m2 )
|
|
{
|
|
float *mat;
|
|
int matSize, rowSize, colSize, x, y;
|
|
|
|
if( ( !Matrix_CheckPyObject( m1 ) )
|
|
|| ( !Matrix_CheckPyObject( m2 ) ) )
|
|
return EXPP_ReturnPyObjError( PyExc_TypeError,
|
|
"unsupported type for this operation\n" );
|
|
|
|
if( ( ( MatrixObject * ) m1 )->flag > 0
|
|
|| ( ( MatrixObject * ) m2 )->flag > 0 )
|
|
return EXPP_ReturnPyObjError( PyExc_ArithmeticError,
|
|
"cannot add scalar to a matrix\n" );
|
|
|
|
if( ( ( MatrixObject * ) m1 )->rowSize !=
|
|
( ( MatrixObject * ) m2 )->rowSize
|
|
|| ( ( MatrixObject * ) m1 )->colSize !=
|
|
( ( MatrixObject * ) m2 )->colSize )
|
|
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"matrices must be the same same for this operation\n" );
|
|
|
|
rowSize = ( ( ( MatrixObject * ) m1 )->rowSize );
|
|
colSize = ( ( ( MatrixObject * ) m1 )->colSize );
|
|
matSize = rowSize * colSize;
|
|
|
|
mat = PyMem_Malloc( matSize * sizeof( float ) );
|
|
|
|
for( x = 0; x < rowSize; x++ ) {
|
|
for( y = 0; y < colSize; y++ ) {
|
|
mat[( ( x * rowSize ) + y )] =
|
|
( ( MatrixObject * ) m1 )->matrix[x][y] +
|
|
( ( MatrixObject * ) m2 )->matrix[x][y];
|
|
}
|
|
}
|
|
|
|
return newMatrixObject( mat, rowSize, colSize );
|
|
}
|
|
|
|
PyObject *Matrix_sub( PyObject * m1, PyObject * m2 )
|
|
{
|
|
float *mat;
|
|
int matSize, rowSize, colSize, x, y;
|
|
|
|
if( ( !Matrix_CheckPyObject( m1 ) )
|
|
|| ( !Matrix_CheckPyObject( m2 ) ) )
|
|
return EXPP_ReturnPyObjError( PyExc_TypeError,
|
|
"unsupported type for this operation\n" );
|
|
|
|
if( ( ( MatrixObject * ) m1 )->flag > 0
|
|
|| ( ( MatrixObject * ) m2 )->flag > 0 )
|
|
return EXPP_ReturnPyObjError( PyExc_ArithmeticError,
|
|
"cannot subtract a scalar from a matrix\n" );
|
|
|
|
if( ( ( MatrixObject * ) m1 )->rowSize !=
|
|
( ( MatrixObject * ) m2 )->rowSize
|
|
|| ( ( MatrixObject * ) m1 )->colSize !=
|
|
( ( MatrixObject * ) m2 )->colSize )
|
|
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"matrices must be the same same for this operation\n" );
|
|
|
|
rowSize = ( ( ( MatrixObject * ) m1 )->rowSize );
|
|
colSize = ( ( ( MatrixObject * ) m1 )->colSize );
|
|
matSize = rowSize * colSize;
|
|
|
|
mat = PyMem_Malloc( matSize * sizeof( float ) );
|
|
|
|
for( x = 0; x < rowSize; x++ ) {
|
|
for( y = 0; y < colSize; y++ ) {
|
|
mat[( ( x * rowSize ) + y )] =
|
|
( ( MatrixObject * ) m1 )->matrix[x][y] -
|
|
( ( MatrixObject * ) m2 )->matrix[x][y];
|
|
}
|
|
}
|
|
|
|
return newMatrixObject( mat, rowSize, colSize );
|
|
}
|
|
|
|
PyObject *Matrix_mul( PyObject * m1, PyObject * m2 )
|
|
{
|
|
float *mat;
|
|
int matSizeV, rowSizeV, colSizeV, rowSizeW, colSizeW, matSizeW, x, y,
|
|
z;
|
|
float dot = 0;
|
|
MatrixObject *matV;
|
|
MatrixObject *matW;
|
|
|
|
if( ( !Matrix_CheckPyObject( m1 ) )
|
|
|| ( !Matrix_CheckPyObject( m2 ) ) )
|
|
return EXPP_ReturnPyObjError( PyExc_TypeError,
|
|
"unsupported type for this operation\n" );
|
|
|
|
//get some vars
|
|
rowSizeV = ( ( ( MatrixObject * ) m1 )->rowSize );
|
|
colSizeV = ( ( ( MatrixObject * ) m1 )->colSize );
|
|
matSizeV = rowSizeV * colSizeV;
|
|
rowSizeW = ( ( ( MatrixObject * ) m2 )->rowSize );
|
|
colSizeW = ( ( ( MatrixObject * ) m2 )->colSize );
|
|
matSizeW = rowSizeW * colSizeW;
|
|
matV = ( ( MatrixObject * ) m1 );
|
|
matW = ( ( MatrixObject * ) m2 );
|
|
|
|
//coerced int or float for scalar multiplication
|
|
if( matW->flag > 1 || matW->flag > 2 ) {
|
|
|
|
if( rowSizeV != rowSizeW && colSizeV != colSizeW )
|
|
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"Matrix dimension error during scalar multiplication\n" );
|
|
|
|
mat = PyMem_Malloc( matSizeV * sizeof( float ) );
|
|
|
|
for( x = 0; x < rowSizeV; x++ ) {
|
|
for( y = 0; y < colSizeV; y++ ) {
|
|
mat[( ( x * rowSizeV ) + y )] =
|
|
matV->matrix[x][y] *
|
|
matW->matrix[x][y];
|
|
}
|
|
}
|
|
return newMatrixObject( mat, rowSizeV, colSizeV );
|
|
} else if( matW->flag == 0 && matV->flag == 0 ) { //true matrix multiplication
|
|
if( colSizeV != rowSizeW ) {
|
|
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"Matrix multiplication undefined...\n" );
|
|
}
|
|
|
|
mat = PyMem_Malloc( ( rowSizeV * colSizeW ) *
|
|
sizeof( float ) );
|
|
|
|
for( x = 0; x < rowSizeV; x++ ) {
|
|
for( y = 0; y < colSizeW; y++ ) {
|
|
for( z = 0; z < colSizeV; z++ ) {
|
|
dot += ( matV->matrix[x][z] *
|
|
matW->matrix[z][y] );
|
|
}
|
|
mat[( ( x * rowSizeV ) + y )] = dot;
|
|
dot = 0;
|
|
}
|
|
}
|
|
return newMatrixObject( mat, rowSizeV, colSizeW );
|
|
} else
|
|
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
|
"Error in matrix_mul...\n" );
|
|
}
|
|
|
|
//coercion of unknown types to type MatrixObject for numeric protocols
|
|
int Matrix_coerce( PyObject ** m1, PyObject ** m2 )
|
|
{
|
|
long *tempI;
|
|
double *tempF;
|
|
float *mat;
|
|
int x, matSize;
|
|
|
|
matSize =
|
|
( ( ( MatrixObject * ) * m1 )->rowSize ) *
|
|
( ( ( MatrixObject * ) * m1 )->rowSize );
|
|
if( Matrix_CheckPyObject( *m1 ) ) {
|
|
if( Matrix_CheckPyObject( *m2 ) ) { //matrix & matrix
|
|
Py_INCREF( *m1 );
|
|
Py_INCREF( *m2 );
|
|
return 0;
|
|
} else {
|
|
if( VectorObject_Check( *m2 ) ) { //matrix & vector?
|
|
printf( "use MatMultVec() for column vector multiplication\n" );
|
|
Py_INCREF( *m1 );
|
|
return 0;
|
|
} else if( PyNumber_Check( *m2 ) ) { //& scalar?
|
|
if( PyInt_Check( *m2 ) ) { //it's a int
|
|
tempI = PyMem_Malloc( 1 *
|
|
sizeof( long ) );
|
|
*tempI = PyInt_AsLong( *m2 );
|
|
mat = PyMem_Malloc( matSize *
|
|
sizeof( float ) );
|
|
for( x = 0; x < matSize; x++ ) {
|
|
mat[x] = ( float ) *tempI;
|
|
}
|
|
PyMem_Free( tempI );
|
|
*m2 = newMatrixObject( mat,
|
|
( ( ( MatrixObject * ) * m1 )->rowSize ), ( ( ( MatrixObject * ) * m1 )->colSize ) );
|
|
( ( MatrixObject * ) * m2 )->flag = 1; //int coercion
|
|
PyMem_Free( mat );
|
|
Py_INCREF( *m1 );
|
|
return 0;
|
|
} else if( PyFloat_Check( *m2 ) ) { //it's a float
|
|
tempF = PyMem_Malloc( 1 *
|
|
sizeof
|
|
( double ) );
|
|
*tempF = PyFloat_AsDouble( *m2 );
|
|
mat = PyMem_Malloc( matSize *
|
|
sizeof( float ) );
|
|
for( x = 0; x < matSize; x++ ) {
|
|
mat[x] = ( float ) *tempF;
|
|
}
|
|
PyMem_Free( tempF );
|
|
*m2 = newMatrixObject( mat,
|
|
( ( ( MatrixObject * ) * m1 )->rowSize ), ( ( ( MatrixObject * ) * m1 )->colSize ) );
|
|
( ( MatrixObject * ) * m2 )->flag = 2; //float coercion
|
|
PyMem_Free( mat );
|
|
Py_INCREF( *m1 );
|
|
return 0;
|
|
}
|
|
}
|
|
//unknom2n type or numeric cast failure
|
|
printf( "attempting matrix operation m2ith unsupported type...\n" );
|
|
Py_INCREF( *m1 );
|
|
return 0; //operation m2ill type check
|
|
}
|
|
} else {
|
|
//1st not Matrix
|
|
printf( "numeric protocol failure...\n" );
|
|
return -1; //this should not occur - fail
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//******************************************************************
|
|
// Matrix definition
|
|
//******************************************************************
|
|
static PySequenceMethods Matrix_SeqMethods = {
|
|
( inquiry ) Matrix_len, /* sq_length */
|
|
( binaryfunc ) 0, /* sq_concat */
|
|
( intargfunc ) 0, /* sq_repeat */
|
|
( intargfunc ) Matrix_item, /* sq_item */
|
|
( intintargfunc ) Matrix_slice, /* sq_slice */
|
|
( intobjargproc ) Matrix_ass_item, /* sq_ass_item */
|
|
( intintobjargproc ) Matrix_ass_slice, /* sq_ass_slice */
|
|
};
|
|
|
|
static PyNumberMethods Matrix_NumMethods = {
|
|
( binaryfunc ) Matrix_add, /* __add__ */
|
|
( binaryfunc ) Matrix_sub, /* __sub__ */
|
|
( binaryfunc ) Matrix_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 ) Matrix_coerce, /* __coerce__ */
|
|
( unaryfunc ) 0, /* __int__ */
|
|
( unaryfunc ) 0, /* __long__ */
|
|
( unaryfunc ) 0, /* __float__ */
|
|
( unaryfunc ) 0, /* __oct__ */
|
|
( unaryfunc ) 0, /* __hex__ */
|
|
};
|
|
|
|
PyTypeObject matrix_Type = {
|
|
PyObject_HEAD_INIT( NULL )
|
|
0, /*ob_size */
|
|
"Matrix", /*tp_name */
|
|
sizeof( MatrixObject ), /*tp_basicsize */
|
|
0, /*tp_itemsize */
|
|
( destructor ) Matrix_dealloc, /*tp_dealloc */
|
|
( printfunc ) 0, /*tp_print */
|
|
( getattrfunc ) Matrix_getattr, /*tp_getattr */
|
|
( setattrfunc ) Matrix_setattr, /*tp_setattr */
|
|
0, /*tp_compare */
|
|
( reprfunc ) Matrix_repr, /*tp_repr */
|
|
&Matrix_NumMethods, /*tp_as_number */
|
|
&Matrix_SeqMethods, /*tp_as_sequence */
|
|
};
|
|
|
|
//******************************************************************
|
|
//Function: newMatrixObject
|
|
//******************************************************************
|
|
PyObject *newMatrixObject( float *mat, int rowSize, int colSize )
|
|
{
|
|
MatrixObject *self;
|
|
float *contigPtr;
|
|
int row, col, x;
|
|
|
|
if( rowSize < 2 || rowSize > 4 || colSize < 2 || colSize > 4 )
|
|
return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
|
"row and column sizes must be between 2 and 4\n" ) );
|
|
|
|
self = PyObject_NEW( MatrixObject, &matrix_Type );
|
|
|
|
//generate contigous memory space
|
|
contigPtr = PyMem_Malloc( rowSize * colSize * sizeof( float ) );
|
|
if( contigPtr == NULL ) {
|
|
return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
|
|
"problem allocating array space\n\n" ) );
|
|
}
|
|
//create pointer array
|
|
self->matrix = PyMem_Malloc( rowSize * sizeof( float * ) );
|
|
if( self->matrix == NULL ) {
|
|
return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
|
|
"problem allocating pointer space\n\n" ) );
|
|
}
|
|
//pointer array points to contigous memory
|
|
for( x = 0; x < rowSize; x++ ) {
|
|
self->matrix[x] = contigPtr + ( x * colSize );
|
|
}
|
|
|
|
if( mat ) { //if a float array passed
|
|
for( row = 0; row < rowSize; row++ ) {
|
|
for( col = 0; col < colSize; col++ ) {
|
|
self->matrix[row][col] =
|
|
mat[( row * colSize ) + col];
|
|
}
|
|
}
|
|
} else { //or if NULL passed
|
|
for( row = 0; row < rowSize; row++ ) {
|
|
for( col = 0; col < colSize; col++ ) {
|
|
self->matrix[row][col] = 0.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
//set size vars of matrix
|
|
self->rowSize = rowSize;
|
|
self->colSize = colSize;
|
|
|
|
//set coercion flag
|
|
self->flag = 0;
|
|
|
|
return ( ( PyObject * ) self );
|
|
}
|