diff options
Diffstat (limited to 'source/blender/python/api2_2x/matrix.c')
-rw-r--r-- | source/blender/python/api2_2x/matrix.c | 1470 |
1 files changed, 838 insertions, 632 deletions
diff --git a/source/blender/python/api2_2x/matrix.c b/source/blender/python/api2_2x/matrix.c index abea09b5f12..b50df287061 100644 --- a/source/blender/python/api2_2x/matrix.c +++ b/source/blender/python/api2_2x/matrix.c @@ -28,804 +28,1010 @@ * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ -#include <BKE_utildefines.h> -#include <BLI_arithb.h> -#include "Mathutils.h" -#include "gen_utils.h" +#include "matrix.h" -//-------------------------DOC STRINGS --------------------------- +//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_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_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"; -//-----------------------METHOD DEFINITIONS ---------------------- + +//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}, + {"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} }; -//-----------------------------METHODS---------------------------- -//---------------------------Matrix.toQuat() --------------------- -PyObject *Matrix_toQuat(MatrixObject * self) + +/*****************************/ +// Matrix Python Object +/*****************************/ + +PyObject *Matrix_toQuat( MatrixObject * self ) { - float quat[4]; - - //must be 3-4 cols, 3-4 rows, square matrix - if(self->colSize < 3 || self->rowSize < 3 || (self->colSize != self->rowSize)) { - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix.toQuat(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n"); - } - if(self->colSize == 3){ - Mat3ToQuat((float (*)[3])*self->matrix, quat); - }else{ - Mat4ToQuat((float (*)[4])*self->matrix, quat); + 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 ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating matrix\n\n" ) ); + } + 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]; } - - if(self->data.blend_data) - return (PyObject *) newQuaternionObject(quat, Py_WRAP); - else - return (PyObject *) newQuaternionObject(quat, Py_NEW); + quat = PyMem_Malloc( 4 * sizeof( float ) ); + if( quat == NULL ) { + PyMem_Free( mat ); + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating quat\n\n" ) ); + } + Mat3ToQuat( ( float ( * )[3] ) mat, quat ); + + return ( PyObject * ) newQuaternionObject( quat ); } -//---------------------------Matrix.toEuler() -------------------- -PyObject *Matrix_toEuler(MatrixObject * self) + + +PyObject *Matrix_toEuler( MatrixObject * self ) { - float eul[3]; + float *eul, *mat; int x; - //must be 3-4 cols, 3-4 rows, square matrix - if(self->colSize !=3 || self->rowSize != 3) { - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix.toQuat(): inappropriate matrix size - expects 3x3 matrix\n"); - } - Mat3ToEul((float (*)[3])*self->matrix, eul); - //have to convert to degrees - for(x = 0; x < 3; x++) { - eul[x] *= (float) (180 / Py_PI); - } - if(self->data.blend_data) - return (PyObject *) newEulerObject(eul, Py_WRAP); - else - return (PyObject *) newEulerObject(eul, Py_NEW); + 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 ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + 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 ) ); + if( eul == NULL ) { + PyMem_Free( mat ); + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating eul\n\n" ) ); + } + Mat3ToEul( ( float ( * )[3] ) mat, eul ); + + for( x = 0; x < 3; x++ ) { + eul[x] *= ( float ) ( 180 / Py_PI ); + } + + return ( PyObject * ) newEulerObject( eul ); } -//---------------------------Matrix.resize4x4() ------------------ -PyObject *Matrix_Resize4x4(MatrixObject * self) + +PyObject *Matrix_Resize4x4( MatrixObject * self ) { - int x, first_row_elem, curr_pos, new_pos, blank_columns, blank_rows; + float *mat; + int x, row, col; + + if( self->colSize == 4 && self->rowSize == 4 ) + return EXPP_incr_ret( Py_None ); - if(self->data.blend_data){ - return EXPP_ReturnPyObjError(PyExc_TypeError, - "cannot resize wrapped data - only python matrices\n"); + mat = PyMem_Malloc( 4 * 4 * sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + for( x = 0; x < 16; x++ ) { + mat[x] = 0.0f; } - self->data.py_data = PyMem_Realloc(self->data.py_data, (sizeof(float) * 16)); - if(self->data.py_data == NULL) { - return EXPP_ReturnPyObjError(PyExc_MemoryError, - "matrix.resize4x4(): problem allocating pointer space\n\n"); + 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; } - self->contigPtr = self->data.py_data; //force - self->matrix = PyMem_Realloc(self->matrix, (sizeof(float) * 4)); - if(self->matrix == NULL) { - return EXPP_ReturnPyObjError(PyExc_MemoryError, - "matrix.resize4x4(): problem allocating pointer space\n\n"); + + PyMem_Free( self->matrix ); + PyMem_Free( self->contigPtr ); + self->contigPtr = PyMem_Malloc( 4 * 4 * sizeof( float ) ); + if( self->contigPtr == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating array space\n\n" ) ); } - //set row pointers - for(x = 0; x < 4; x++) { - self->matrix[x] = self->contigPtr + (x * 4); + self->matrix = PyMem_Malloc( 4 * sizeof( float * ) ); + if( self->matrix == NULL ) { + PyMem_Free( self->contigPtr ); + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating pointer space\n\n" ) ); } - //move data to new spot in array + clean - for(blank_rows = (4 - self->rowSize); blank_rows > 0; blank_rows--){ - for(x = 0; x < 4; x++){ - self->contigPtr[(4 * (self->rowSize + (blank_rows - 1))) + x] = 0.0f; - } + for( x = 0; x < 4; x++ ) { + self->matrix[x] = self->contigPtr + ( x * 4 ); } - for(x = 1; x <= self->rowSize; x++){ - first_row_elem = (self->colSize * (self->rowSize - x)); - curr_pos = (first_row_elem + (self->colSize -1)); - new_pos = (4 * (self->rowSize - x )) + (curr_pos - first_row_elem); - for(blank_columns = (4 - self->colSize); blank_columns > 0; blank_columns--){ - self->contigPtr[new_pos + blank_columns] = 0.0f; - } - for(curr_pos; curr_pos >= first_row_elem; curr_pos--){ - self->contigPtr[new_pos] = self->contigPtr[curr_pos]; - new_pos--; + + for( row = 0; row < 4; row++ ) { + for( col = 0; col < 4; col++ ) { + self->matrix[row][col] = mat[( row * 4 ) + col]; } } - self->rowSize = 4; + PyMem_Free( mat ); + self->colSize = 4; - return (PyObject*)self; + self->rowSize = 4; + + return EXPP_incr_ret( Py_None ); } -//---------------------------Matrix.translationPart() ------------ -PyObject *Matrix_TranslationPart(MatrixObject * self) + +PyObject *Matrix_TranslationPart( MatrixObject * self ) { - float vec[4]; + float *vec = NULL; + PyObject *retval; - if(self->colSize < 3 && self->rowSize < 4){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix.translationPart: inappropriate matrix size\n"); - } + 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[0] = self->matrix[3][0]; - vec[1] = self->matrix[3][1]; - vec[2] = self->matrix[3][2]; + vec = PyMem_Malloc( 3 * sizeof( float ) ); + if( vec == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating vec\n\n" ) ); + } + vec[0] = self->matrix[3][0]; + vec[1] = self->matrix[3][1]; + vec[2] = self->matrix[3][2]; + } - return newVectorObject(vec, 3, Py_NEW); + retval = ( PyObject * ) newVectorObject( vec, 3 ); + PyMem_Free( vec ); + return retval; } -//---------------------------Matrix.rotationPart() --------------- -PyObject *Matrix_RotationPart(MatrixObject * self) + +PyObject *Matrix_RotationPart( MatrixObject * self ) { - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + float *mat; - if(self->colSize < 3 && self->rowSize < 3){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix.rotationPart: inappropriate matrix size\n"); - } + 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[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]; + mat = PyMem_Malloc( 3 * 3 * sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + 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 newMatrixObject(mat, 3, 3, Py_NEW); + return ( PyObject * ) newMatrixObject( mat, 3, 3 ); } -//---------------------------Matrix.invert() --------------------- -PyObject *Matrix_Invert(MatrixObject * self) + +PyObject *Matrix_Invert( MatrixObject * self ) { - - int x, y, z = 0; - float det = 0.0f; - PyObject *f = NULL; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + float det; + int x, y, z; + float *mat = NULL; + float t; - if(self->rowSize != self->colSize){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix.invert: only square matrices are supported\n"); - } + if( self->rowSize != self->colSize ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "only square matrices are supported\n" ); //calculate the determinant - f = Matrix_Determinant(self); - det = PyFloat_AS_DOUBLE(f); + 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( (float ( * )[4]) *self->matrix ); + } else { + return EXPP_ReturnPyObjError( PyExc_StandardError, + "error calculating determinant for inverse()\n" ); + } + + if( det != 0 ) { - if(det != 0) { //calculate the classical adjoint - if(self->rowSize == 2) { + if( self->rowSize == 2 ) { + mat = PyMem_Malloc( self->rowSize * self->colSize * + sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } 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) { - Mat3Adj((float (*)[3]) mat,(float (*)[3]) *self->matrix); - } else if(self->rowSize == 4) { - Mat4Adj((float (*)[4]) mat, (float (*)[4]) *self->matrix); + } else if( self->rowSize == 3 ) { + mat = PyMem_Malloc( self->rowSize * self->colSize * + sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + Mat3Adj( ( float ( * )[3] ) mat,( float ( * )[3] ) *self->matrix ); + } else if( self->rowSize == 4 ) { + mat = PyMem_Malloc( self->rowSize * self->colSize * + sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError + ( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + Mat4Adj( ( float ( * )[4] ) mat, ( float ( * )[4] ) *self->matrix ); } //divide by determinate - for(x = 0; x < (self->rowSize * self->colSize); x++) { + for( x = 0; x < ( self->rowSize * self->colSize ); x++ ) { mat[x] /= det; } + //set values - for(x = 0; x < self->rowSize; x++) { - for(y = 0; y < self->colSize; y++) { + z = 0; + for( x = 0; x < self->rowSize; x++ ) { + for( y = 0; y < self->colSize; y++ ) { self->matrix[x][y] = mat[z]; z++; } } + //transpose - Matrix_Transpose(self); + if( self->rowSize == 2 ) { + t = self->matrix[1][0]; + self->matrix[1][0] = self->matrix[0][1]; + self->matrix[0][1] = t; + +/* + Note: is the code below correct? + transposing mat and not copying into self->matrix? + s. swaney 11-oct-2004 +*/ + } else if( self->rowSize == 3 ) { + Mat3Transp( ( float ( * )[3] ) mat ); + } else if( self->rowSize == 4 ) { + Mat4Transp( ( float ( * )[4] ) mat ); + } } else { - printf("Matrix.invert: matrix does not have an inverse\n"); + printf( "matrix does not have an inverse - none attempted\n" ); } - return (PyObject*)self; + PyMem_Free( mat ); + return EXPP_incr_ret( Py_None ); } -//---------------------------Matrix.determinant() ---------------- -PyObject *Matrix_Determinant(MatrixObject * self) + + +PyObject *Matrix_Determinant( MatrixObject * self ) { - float det = 0.0f; - - if(self->rowSize != self->colSize){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix.determinant: 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]); + 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( (float ( * )[4]) *self->matrix ); } else { - det = Det4x4((float (*)[4]) *self->matrix); + return EXPP_ReturnPyObjError( PyExc_StandardError, + "error in determinant()\n" ); } return PyFloat_FromDouble( (double) det ); } //---------------------------Matrix.transpose() ------------------ -PyObject *Matrix_Transpose(MatrixObject * self) + +PyObject *Matrix_Transpose( MatrixObject * self ) + { - float t = 0.0f; + float t; - if(self->rowSize != self->colSize){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix.transpose: only square matrices are supported\n"); - } + if( self->rowSize != self->colSize ) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "only square matrices are supported\n" ); - if(self->rowSize == 2) { + 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])*self->matrix); - } else { - Mat4Transp((float (*)[4])*self->matrix); - } + } else if( self->rowSize == 3 ) { + Mat3Transp( (float ( * )[3])*self->matrix ); + } else if( self->rowSize == 4 ) { + Mat4Transp( (float ( * )[4])*self->matrix ); + } else + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "unable to transpose matrix\n" ) ); - return (PyObject*)self; + return EXPP_incr_ret( Py_None ); } -//---------------------------Matrix.zero() ----------------------- -PyObject *Matrix_Zero(MatrixObject * self) + +PyObject *Matrix_Zero( MatrixObject * self ) { int row, col; - for(row = 0; row < self->rowSize; row++) { - for(col = 0; col < self->colSize; col++) { + for( row = 0; row < self->rowSize; row++ ) { + for( col = 0; col < self->colSize; col++ ) { self->matrix[row][col] = 0.0f; } } - return (PyObject*)self; + return EXPP_incr_ret( Py_None ); } -//---------------------------Matrix.identity(() ------------------ -PyObject *Matrix_Identity(MatrixObject * self) + +PyObject *Matrix_Identity( MatrixObject * self ) { - if(self->rowSize != self->colSize){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix.identity: only square matrices are supported\n"); - } + if( self->rowSize != self->colSize ) + return ( EXPP_ReturnPyObjError( PyExc_AttributeError, + "only square matrices supported\n" ) ); - if(self->rowSize == 2) { + 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((float (*)[3]) *self->matrix); - } else { - Mat4One((float (*)[4]) *self->matrix); - } + } else if( self->rowSize == 3 ) { + Mat3One( ( float ( * )[3] ) *self->matrix ); + } else if( self->rowSize == 4 ) { + Mat4One( ( float ( * )[4] ) *self->matrix ); + } else + return ( EXPP_ReturnPyObjError( PyExc_TypeError, + "unable to create identity matrix\n" ) ); - return (PyObject*)self; + return EXPP_incr_ret( Py_None ); } -//----------------------------dealloc()(internal) ---------------- -//free the py_object -static void Matrix_dealloc(MatrixObject * self) + +static void Matrix_dealloc( MatrixObject * self ) { - Py_XDECREF(self->coerced_object); - PyMem_Free(self->matrix); - //only free py_data - if(self->data.py_data){ - PyMem_Free(self->data.py_data); - } - PyObject_DEL(self); + PyMem_Free( self->contigPtr ); + PyMem_Free( self->matrix ); + + PyObject_DEL( self ); } -//----------------------------getattr()(internal) ---------------- -//object.attribute access (get) -static PyObject *Matrix_getattr(MatrixObject * self, char *name) + +static PyObject *Matrix_getattr( MatrixObject * self, char *name ) { - if(STREQ(name, "rowSize")) { - return PyInt_FromLong((long) self->rowSize); - } else if(STREQ(name, "colSize")) { - return PyInt_FromLong((long) self->colSize); + 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); + return Py_FindMethod( Matrix_methods, ( PyObject * ) self, name ); } -//----------------------------setattr()(internal) ---------------- -//object.attribute access (set) -static int Matrix_setattr(MatrixObject * self, char *name, PyObject * v) + +static int Matrix_setattr( MatrixObject * self, char *name, PyObject * v ) { /* This is not supported. */ - return (-1); + return ( -1 ); } -//----------------------------print object (internal)------------- -//print the object to screen -static PyObject *Matrix_repr(MatrixObject * self) + +static PyObject *Matrix_repr( MatrixObject * self ) { + PyObject *repr, *str; int x, y; - char buffer[48], str[1024]; - - BLI_strncpy(str,"",1024); - for(x = 0; x < self->rowSize; x++){ - sprintf(buffer, "[", x); - strcat(str,buffer); - for(y = 0; y < (self->colSize - 1); y++) { - sprintf(buffer, "%.6f, ", self->matrix[x][y]); - strcat(str,buffer); - } - if(x < (self->rowSize-1)){ - sprintf(buffer, "%.6f](matrix [row %d])\n", self->matrix[x][y], x); - strcat(str,buffer); - }else{ - sprintf(buffer, "%.6f](matrix [row %d])", self->matrix[x][y], x); - strcat(str,buffer); + 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 EXPP_incr_ret(PyString_FromString(str)); + return repr; } -//---------------------SEQUENCE PROTOCOLS------------------------ -//----------------------------len(object)------------------------ -//sequence length -static int Matrix_len(MatrixObject * self) -{ - return (self->colSize * self->rowSize); -} -//----------------------------object[]--------------------------- -//sequence accessor (get) -//the wrapped vector gives direct access to the matrix data -static PyObject *Matrix_item(MatrixObject * self, int i) +//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 ) { - if(i < 0 || i >= self->rowSize) - return EXPP_ReturnPyObjError(PyExc_IndexError, - "matrix[attribute]: array index out of range\n"); + float *vec = NULL; + PyObject *retval; + 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 ) ); + if( vec == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating vec\n\n" ) ); + } + for( x = 0; x < self->colSize; x++ ) { + vec[x] = self->matrix[i][x]; + } - return newVectorObject(self->matrix[i], self->colSize, Py_WRAP); + retval =( PyObject * ) newVectorObject( vec, self->colSize ); + PyMem_Free( vec ); + return retval; } -//----------------------------object[]------------------------- -//sequence accessor (set) -static int Matrix_ass_item(MatrixObject * self, int i, PyObject * ob) + +static PyObject *Matrix_slice( MatrixObject * self, int begin, int end ) { - int y, x, size = 0; - float vec[4]; + PyObject *list; + int count, maxsize, x, y; - if(i > self->rowSize || i < 0){ - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[attribute] = x: bad row\n"); - } + maxsize = self->colSize * self->rowSize; + if( begin < 0 ) + begin = 0; + if( end > maxsize ) + end = maxsize; + if( begin > end ) + begin = end; - if(PySequence_Check(ob)){ - size = PySequence_Length(ob); - if(size != self->colSize){ - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[attribute] = x: bad sequence size\n"); - } - for (x = 0; x < size; x++) { - PyObject *m, *f; + list = PyList_New( end - begin ); - m = PySequence_GetItem(ob, x); - if (m == NULL) { // Failed to read sequence - return EXPP_ReturnIntError(PyExc_RuntimeError, - "matrix[attribute] = x: unable to read sequence\n"); - } - f = PyNumber_Float(m); - if(f == NULL) { // parsed item not a number - Py_DECREF(m); - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[attribute] = x: sequence argument not a number\n"); - } - vec[x] = PyFloat_AS_DOUBLE(f); - EXPP_decr2(m, f); - } - //parsed well - now set in matrix - for(y = 0; y < size; y++){ - self->matrix[i][y] = vec[y]; - } - return 0; - }else{ - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[attribute] = x: expects a sequence of column size\n"); + 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; } -//----------------------------object[z:y]------------------------ -//sequence slice (get) -static PyObject *Matrix_slice(MatrixObject * self, int begin, int end) -{ - PyObject *list = NULL; - int count; +static int Matrix_ass_item( MatrixObject * self, int i, PyObject * ob ) +{ + int maxsize, x, y; - CLAMP(begin, 0, self->rowSize); - CLAMP(end, 0, self->rowSize); - begin = MIN2(begin,end); + 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" ); - list = PyList_New(end - begin); - for(count = begin; count < end; count++) { - PyList_SetItem(list, count - begin, - newVectorObject(self->matrix[count], self->colSize, Py_WRAP)); - } + x = ( int ) floor( ( double ) ( i / self->colSize ) ); + y = i % self->colSize; + self->matrix[x][y] = ( float ) PyFloat_AsDouble( ob ); - return EXPP_incr_ret(list); + return 0; } -//----------------------------object[z:y]------------------------ -//sequence slice (set) -static int Matrix_ass_slice(MatrixObject * self, int begin, int end, - PyObject * seq) + +static int Matrix_ass_slice( MatrixObject * self, int begin, int end, + PyObject * seq ) { - int i, x, y, size, sub_size; - float mat[16]; - - CLAMP(begin, 0, self->rowSize); - CLAMP(end, 0, self->rowSize); - begin = MIN2(begin,end); - - if(PySequence_Check(seq)){ - size = PySequence_Length(seq); - if(size != (end - begin)){ - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[begin:end] = []: size mismatch in slice assignment\n"); - } - //parse sub items - for (i = 0; i < size; i++) { - //parse each sub sequence - PyObject *subseq; - subseq = PySequence_GetItem(seq, i); - if (subseq == NULL) { // Failed to read sequence - return EXPP_ReturnIntError(PyExc_RuntimeError, - "matrix[begin:end] = []: unable to read sequence\n"); - } - if(PySequence_Check(subseq)){ - //subsequence is also a sequence - sub_size = PySequence_Length(subseq); - if(sub_size != self->colSize){ - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[begin:end] = []: size mismatch in slice assignment\n"); - } - for (y = 0; y < sub_size; y++) { - PyObject *m, *f; - m = PySequence_GetItem(subseq, y); - if (m == NULL) { // Failed to read sequence - return EXPP_ReturnIntError(PyExc_RuntimeError, - "matrix[begin:end] = []: unable to read sequence\n"); - } - f = PyNumber_Float(m); - if(f == NULL) { // parsed item not a number - Py_DECREF(m); - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[begin:end] = []: sequence argument not a number\n"); - } - mat[(i * self->colSize) + y] = PyFloat_AS_DOUBLE(f); - EXPP_decr2(f, m); - } - }else{ - Py_DECREF(subseq); - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[begin:end] = []: illegal argument type for built-in operation\n"); - } - } - //parsed well - now set in matrix - for(x = 0; x < (size * sub_size); x++){ - self->matrix[begin + (int)floor(x / self->colSize)][x % self->colSize] = mat[x]; + 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; - }else{ - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix[begin:end] = []: illegal argument type for built-in operation\n"); } + return 0; } -//------------------------NUMERIC PROTOCOLS---------------------- -//------------------------obj + obj------------------------------ -static PyObject *Matrix_add(PyObject * m1, PyObject * m2) + +static int Matrix_len( MatrixObject * self ) { - int x, y; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - MatrixObject *mat1 = NULL, *mat2 = NULL; + return ( self->colSize * self->rowSize ); +} - EXPP_incr2(m1, m2); - mat1 = (MatrixObject*)m1; - mat2 = (MatrixObject*)m2; +static PyObject *Matrix_add( PyObject * m1, PyObject * m2 ) +{ + float *mat; + int matSize, rowSize, colSize, x, y; - if(mat1->coerced_object || mat2->coerced_object){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix addition: arguments not valid for this operation....\n"); - } - if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){ - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix addition: matrices must have the same dimensions for this operation\n"); - } + 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" ); - for(x = 0; x < mat1->rowSize; x++) { - for(y = 0; y < mat1->colSize; y++) { - mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] + mat2->matrix[x][y]; + 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 ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + 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]; } } - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW); + return newMatrixObject( mat, rowSize, colSize ); } -//------------------------obj - obj------------------------------ -//subtraction -static PyObject *Matrix_sub(PyObject * m1, PyObject * m2) + +static PyObject *Matrix_sub( PyObject * m1, PyObject * m2 ) { - int x, y; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - MatrixObject *mat1 = NULL, *mat2 = NULL; + float *mat; + int matSize, rowSize, colSize, x, y; - EXPP_incr2(m1, m2); - mat1 = (MatrixObject*)m1; - mat2 = (MatrixObject*)m2; + if( ( !Matrix_CheckPyObject( m1 ) ) + || ( !Matrix_CheckPyObject( m2 ) ) ) + return EXPP_ReturnPyObjError( PyExc_TypeError, + "unsupported type for this operation\n" ); - if(mat1->coerced_object || mat2->coerced_object){ - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix addition: arguments not valid for this operation....\n"); - } - if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){ - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix addition: matrices must have the same dimensions 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; - for(x = 0; x < mat1->rowSize; x++) { - for(y = 0; y < mat1->colSize; y++) { - mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] - mat2->matrix[x][y]; + mat = PyMem_Malloc( matSize * sizeof( float ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + 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]; } } - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW); + return newMatrixObject( mat, rowSize, colSize ); } -//------------------------obj * obj------------------------------ -//mulplication -static PyObject *Matrix_mul(PyObject * m1, PyObject * m2) + +static PyObject *Matrix_mul( PyObject * m1, PyObject * m2 ) { - int x, y, z; - float scalar; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - double dot = 0.0f; - MatrixObject *mat1 = NULL, *mat2 = NULL; - PyObject *f = NULL, *retObj = NULL; - VectorObject *vec = NULL; - - EXPP_incr2(m1, m2); - mat1 = (MatrixObject*)m1; - mat2 = (MatrixObject*)m2; - - if(mat1->coerced_object){ - if (PyFloat_Check(mat1->coerced_object) || - PyInt_Check(mat1->coerced_object)){ // FLOAT/INT * MATRIX - f = PyNumber_Float(mat1->coerced_object); - if(f == NULL) { // parsed item not a number - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Matrix multiplication: arguments not acceptable for this operation\n"); - } - scalar = PyFloat_AS_DOUBLE(f); - for(x = 0; x < mat2->rowSize; x++) { - for(y = 0; y < mat2->colSize; y++) { - mat[((x * mat2->colSize) + y)] = scalar * mat2->matrix[x][y]; - } - } - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return newMatrixObject(mat, mat2->rowSize, mat2->colSize, Py_NEW); + PyObject *retval; + int matSizeV, rowSizeV, colSizeV, rowSizeW, colSizeW, matSizeW, x, y,z; + MatrixObject *matV; + MatrixObject *matW; + float *mat = NULL; + float dot = 0; + + + 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 ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); } - }else{ - if(mat2->coerced_object){ - if(VectorObject_Check(mat2->coerced_object)){ //MATRIX * VECTOR - vec = (VectorObject*)EXPP_incr_ret(mat2->coerced_object); - retObj = column_vector_multiplication(mat1, vec); - EXPP_decr3((PyObject*)mat1, (PyObject*)mat2, (PyObject*)vec); - return retObj; - }else if (PyFloat_Check(mat2->coerced_object) || - PyInt_Check(mat2->coerced_object)){ // MATRIX * FLOAT/INT - f = PyNumber_Float(mat2->coerced_object); - if(f == NULL) { // parsed item not a number - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Matrix multiplication: arguments not acceptable for this operation\n"); - } - scalar = PyFloat_AS_DOUBLE(f); - for(x = 0; x < mat1->rowSize; x++) { - for(y = 0; y < mat1->colSize; y++) { - mat[((x * mat1->colSize) + y)] = scalar * mat1->matrix[x][y]; - } - } - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW); - } - }else{ //MATRIX * MATRIX - if(mat1->colSize != mat2->rowSize){ - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return EXPP_ReturnPyObjError(PyExc_AttributeError, - "Matrix multiplication: matrix A rowsize must equal matrix B colsize\n"); + for( x = 0; x < rowSizeV; x++ ) { + for( y = 0; y < colSizeV; y++ ) { + mat[( ( x * rowSizeV ) + y )] = + matV->matrix[x][y] * + matW->matrix[x][y]; } - for(x = 0; x < mat1->rowSize; x++) { - for(y = 0; y < mat2->colSize; y++) { - for(z = 0; z < mat1->colSize; z++) { - dot += (mat1->matrix[x][z] * mat2->matrix[z][y]); - } - mat[((x * mat1->rowSize) + y)] = dot; - dot = 0.0f; + } + retval = ( PyObject* ) newMatrixObject( mat, rowSizeV, colSizeV ); + PyMem_Free( mat ); + return retval; + } 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 ) ); + if( mat == NULL ) { + return ( EXPP_ReturnPyObjError( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + 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, mat1->rowSize, mat2->colSize, Py_NEW); } - } - - EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); - return EXPP_ReturnPyObjError(PyExc_TypeError, - "Matrix multiplication: arguments not acceptable for this operation\n"); + retval = ( PyObject* ) newMatrixObject( mat, rowSizeV, colSizeW ); + PyMem_Free( mat ); + return retval; + } else + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "Error in matrix_mul...\n" ); } -//------------------------coerce(obj, obj)----------------------- + //coercion of unknown types to type MatrixObject for numeric protocols -/*Coercion() is called whenever a math operation has 2 operands that - it doesn't understand how to evaluate. 2+Matrix for example. We want to - evaluate some of these operations like: (vector * 2), however, for math - to proceed, the unknown operand must be cast to a type that python math will - understand. (e.g. in the case above case, 2 must be cast to a vector and - then call vector.multiply(vector, scalar_cast_as_vector)*/ -static int Matrix_coerce(PyObject ** m1, PyObject ** m2) +static int Matrix_coerce( PyObject ** m1, PyObject ** m2 ) { - int x; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - PyObject *coerced = NULL; - - if(!MatrixObject_Check(*m2)) { - if(VectorObject_Check(*m2) || PyFloat_Check(*m2) || PyInt_Check(*m2)) { - coerced = EXPP_incr_ret(*m2); - *m2 = newMatrixObject(NULL,3,3,Py_NEW); - ((MatrixObject*)*m2)->coerced_object = coerced; - }else{ - return EXPP_ReturnIntError(PyExc_TypeError, - "matrix.coerce(): unknown operand - can't coerce for numeric protocols\n"); + 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 ) ); + if( tempI == NULL ) { + return ( EXPP_ReturnIntError + ( PyExc_MemoryError, + "problem allocating tempI\n\n" ) ); + } + *tempI = PyInt_AsLong( *m2 ); + mat = PyMem_Malloc( matSize * + sizeof( float ) ); + if( mat == NULL ) { + PyMem_Free( tempI ); + return ( EXPP_ReturnIntError + ( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + 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 ) ); + if( tempF == NULL ) { + return ( EXPP_ReturnIntError + ( PyExc_MemoryError, + "problem allocating tempF\n\n" ) ); + } + *tempF = PyFloat_AsDouble( *m2 ); + mat = PyMem_Malloc( matSize * + sizeof( float ) ); + if( mat == NULL ) { + PyMem_Free( tempF ); + return ( EXPP_ReturnIntError + ( PyExc_MemoryError, + "problem allocating mat\n\n" ) ); + } + 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 } - Py_INCREF(*m2); - Py_INCREF(*m1); - return 0; + return -1; } -//-----------------PROTCOL DECLARATIONS-------------------------- + +//****************************************************************** +// 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 */ + ( 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__ */ + ( 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__ */ }; -//------------------PY_OBECT DEFINITION-------------------------- + PyTypeObject matrix_Type = { - PyObject_HEAD_INIT(NULL) /* required python macro */ - 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 */ + PyObject_HEAD_INIT( NULL ) /* required python macro */ + 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 */ }; -//------------------------newMatrixObject (internal)------------- -//creates a new matrix object -//self->matrix self->contiguous_ptr (reference to data.xxx) -// [0]------------->[0] -// [1] -// [2] -// [1]------------->[3] -// [4] -// [5] -// .... -//self->matrix[1][1] = self->contiguous_ptr[4] = self->data.xxx_data[4] -/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER - (i.e. it was allocated elsewhere by MEM_mallocN()) - pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON - (i.e. it must be created here with PyMEM_malloc())*/ -PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type) + +//****************************************************************** +//Function: newMatrixObject +//****************************************************************** +PyObject *newMatrixObject( float *mat, int rowSize, int colSize ) { MatrixObject *self; - int x, row, col; + int row, col, x; - //matrix objects can be any 2-4row x 2-4col matrix - if(rowSize < 2 || rowSize > 4 || colSize < 2 || colSize > 4){ - return EXPP_ReturnPyObjError(PyExc_RuntimeError, - "matrix(): row and column sizes must be between 2 and 4\n"); + 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 + self->contigPtr = PyMem_Malloc( rowSize * colSize * sizeof( float ) ); + if( self->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 ) { + PyMem_Free( self->contigPtr ); + 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] = self->contigPtr + ( x * colSize ); } - matrix_Type.ob_type = &PyType_Type; - self = PyObject_NEW(MatrixObject, &matrix_Type); - self->data.blend_data = NULL; - self->data.py_data = NULL; - self->rowSize = rowSize; - self->colSize = colSize; - self->coerced_object = NULL; - - if(type == Py_WRAP){ - self->data.blend_data = mat; - self->contigPtr = self->data.blend_data; - //create pointer array - self->matrix = PyMem_Malloc(rowSize * sizeof(float *)); - if(self->matrix == NULL) { //allocation failure - return EXPP_ReturnPyObjError( PyExc_MemoryError, - "matrix(): problem allocating pointer space\n"); - } - //pointer array points to contigous memory - for(x = 0; x < rowSize; x++) { - self->matrix[x] = self->contigPtr + (x * colSize); - } - }else if (type == Py_NEW){ - self->data.py_data = PyMem_Malloc(rowSize * colSize * sizeof(float)); - if(self->data.py_data == NULL) { //allocation failure - return EXPP_ReturnPyObjError( PyExc_MemoryError, - "matrix(): problem allocating pointer space\n"); - } - self->contigPtr = self->data.py_data; - //create pointer array - self->matrix = PyMem_Malloc(rowSize * sizeof(float *)); - if(self->matrix == NULL) { //allocation failure - PyMem_Free(self->data.py_data); - return EXPP_ReturnPyObjError( PyExc_MemoryError, - "matrix(): problem allocating pointer space\n"); - } - //pointer array points to contigous memory - for(x = 0; x < rowSize; x++) { - self->matrix[x] = self->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]; + } } - //parse - 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; } - } else { //or if no arguments are passed return identity matrix - Matrix_Identity(self); } - }else{ //bad type - return NULL; } - return (PyObject *) EXPP_incr_ret((PyObject *)self); + + //set size vars of matrix + self->rowSize = rowSize; + self->colSize = colSize; + + //set coercion flag + self->flag = 0; + + return ( ( PyObject * ) self ); } |