diff options
author | Joseph Gilbert <ascotan@gmail.com> | 2005-07-14 07:34:56 +0400 |
---|---|---|
committer | Joseph Gilbert <ascotan@gmail.com> | 2005-07-14 07:34:56 +0400 |
commit | b89035906daa352ac8eae4c157c3dd6f61b7ad62 (patch) | |
tree | d3e3312fb8e282c327b6cb4f7b1f780ce299afa2 /source/blender/python/api2_2x/matrix.c | |
parent | 1bfd0eae148af20ed97992d44a66f5a6ec34571c (diff) |
Mathutils update
- also included is some fixes for preprocessor inclues and some clean up of the previous commit
-rewrite and bugfixes
----------------------------------
Here's my changelog:
-fixed Rand() so that it doesn't seed everytime and should generate better random numbers
- changed a few error return types to something more appropriate
- clean up of uninitialized variables & removal of unneccessary objects
- NMesh returns wrapped vectors now
- World returns wrapped matrices now
- Object.getEuler() and Object.getBoundingBox() return Wrapped data when data is present
- Object.getMatrix() returns wrapped data if it's worldspace, 'localspace' returns a new matrix
- Vector, Euler, Mat, Quat, call all now internally wrap object without destroying internal datablocks
- Removed memory allocation (unneeded) from all methods
- Vector's resize methods are only applicable to new vectors not wrapped data.
- Matrix(), Quat(), Euler(), Vector() now accepts ANY sequence list, including tuples, list, or a self object to copy - matrices accept multiple sequences
- Fixed Slerp() so that it now works correctly values are clamped between 0 and 1
- Euler.rotate does internal rotation now
- Slice assignment now works better for all types
- Vector * Vector and Quat * Quat are defined and return the DOT product
- Mat * Vec and Vec * Mat are defined now
- Moved #includes to .c file from headers. Also fixed prototypes in mathutils
- Added new helper functions for incref'ing to genutils
- Major cleanup of header files includes - include Mathutils.h for access to math types
- matrix.toQuat() and .toEuler() now fixed take appropriate matrix sizes
- Matrix() with no parameters now returns an identity matrix by default not a zero matrix
- printf() now prints with 6 digits instead of 4
- printf() now prints output with object descriptor
- Matrices now support [x][y] assignment (e.g. matrix[x][y] = 5.4)
- Matrix[index] = value now expectes a sequence not an integer. This will now set a ROW of the matrix through a sequence. index cannot go above the row size of the matrix.
- slice operations on matrices work with sequences now (rows of the matrix) example: mymatrix[0:2] returns a list of 2 wrapped vectors with access to the matrix data.
- slice assignment will no longer modify the data if the assignment operation fails
- fixed error in matrix * scalar multiplication
- euler.toMatrix(), toQuat() no longer causes "creep" from repeated use
- Wrapped data will generate wrapped objects when toEuler(), toQuat(), toMatrix() is used
- Quats can be created with angle/axis, axis/angle
- 4x4 matrices can be multiplied by 3D vectors (by popular demand :))
- vec *quat / quat * vec is now defined
- vec.magnitude alias for vec.length
- all self, internal methods return a pointer to self now so you can do print vector.internalmethod() or vector.internalmethod().nextmethod() (no more print matrix.inverse() returning 'none')
- these methods have been deprecated (still functioning but suggested to use the corrected functionality):
* CopyVec() - replaced by Vector() functionality
* CopyMat() - replaced by Matrix() functionality
* CopyQuat() - replace by Quaternion() functionality
* CopyEuler() - replaced by Euler() functionality
* RotateEuler() - replaced by Euler.rotate() funtionality
* MatMultVec() - replaced by matrix * vector
* VecMultMat() - replaced by vector * matrix
- New struct containers references to python object data or internally allocated blender data for wrapping
* Explaination here: math structs now function as a 'simple wrapper' or a 'py_object' - data that is created on the fly will now be a 'py_object' with its memory managed by python
* otherwise if the data is returned by blender's G.main then the math object is a 'simple wrapper' and data can be accessed directly from the struct just like other python objects.
Diffstat (limited to 'source/blender/python/api2_2x/matrix.c')
-rw-r--r-- | source/blender/python/api2_2x/matrix.c | 1467 |
1 files changed, 629 insertions, 838 deletions
diff --git a/source/blender/python/api2_2x/matrix.c b/source/blender/python/api2_2x/matrix.c index b50df287061..8b0add848a2 100644 --- a/source/blender/python/api2_2x/matrix.c +++ b/source/blender/python/api2_2x/matrix.c @@ -28,1010 +28,801 @@ * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ -#include "matrix.h" +#include "BKE_utildefines.h" +#include "BLI_arithb.h" +#include "Mathutils.h" +#include "gen_utils.h" +#include "BLI_blenlib.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"; - -//methods table +//-----------------------METHOD DEFINITIONS ---------------------- 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} }; - -/*****************************/ -// Matrix Python Object -/*****************************/ - -PyObject *Matrix_toQuat( MatrixObject * self ) +//-----------------------------METHODS---------------------------- +//---------------------------Matrix.toQuat() --------------------- +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 ) ); - 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]; + 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); } - 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 ); + + if(self->data.blend_data) + return (PyObject *) newQuaternionObject(quat, Py_WRAP); + else + return (PyObject *) newQuaternionObject(quat, Py_NEW); } - - -PyObject *Matrix_toEuler( MatrixObject * self ) +//---------------------------Matrix.toEuler() -------------------- +PyObject *Matrix_toEuler(MatrixObject * self) { - float *eul, *mat; + float eul[3]; 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 ) ); - 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 ); + //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); } - -PyObject *Matrix_Resize4x4( MatrixObject * self ) +//---------------------------Matrix.resize4x4() ------------------ +PyObject *Matrix_Resize4x4(MatrixObject * self) { - float *mat; - int x, row, col; - - if( self->colSize == 4 && self->rowSize == 4 ) - return EXPP_incr_ret( Py_None ); + int x, first_row_elem, curr_pos, new_pos, blank_columns, blank_rows; - 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; + if(self->data.blend_data){ + return EXPP_ReturnPyObjError(PyExc_TypeError, + "cannot resize wrapped data - only python matrices\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->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"); } - - 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" ) ); + 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"); } - 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" ) ); + //set row pointers + for(x = 0; x < 4; x++) { + self->matrix[x] = self->contigPtr + (x * 4); } - for( x = 0; x < 4; x++ ) { - self->matrix[x] = self->contigPtr + ( x * 4 ); + //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( row = 0; row < 4; row++ ) { - for( col = 0; col < 4; col++ ) { - self->matrix[row][col] = mat[( row * 4 ) + col]; + 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; curr_pos >= first_row_elem; curr_pos--){ + self->contigPtr[new_pos] = self->contigPtr[curr_pos]; + new_pos--; } } - PyMem_Free( mat ); - - self->colSize = 4; self->rowSize = 4; - - return EXPP_incr_ret( Py_None ); + self->colSize = 4; + return (PyObject*)self; } - -PyObject *Matrix_TranslationPart( MatrixObject * self ) +//---------------------------Matrix.translationPart() ------------ +PyObject *Matrix_TranslationPart(MatrixObject * self) { - float *vec = NULL; - PyObject *retval; + float vec[4]; - 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 ) ); - 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]; + if(self->colSize < 3 && self->rowSize < 4){ + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Matrix.translationPart: inappropriate matrix size\n"); } - retval = ( PyObject * ) newVectorObject( vec, 3 ); - PyMem_Free( vec ); - return retval; -} + vec[0] = self->matrix[3][0]; + vec[1] = self->matrix[3][1]; + vec[2] = self->matrix[3][2]; -PyObject *Matrix_RotationPart( MatrixObject * self ) + return newVectorObject(vec, 3, Py_NEW); +} +//---------------------------Matrix.rotationPart() --------------- +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" ); + 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}; - 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]; + if(self->colSize < 3 && self->rowSize < 3){ + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Matrix.rotationPart: inappropriate matrix size\n"); } - return ( PyObject * ) newMatrixObject( mat, 3, 3 ); -} + 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]; -PyObject *Matrix_Invert( MatrixObject * self ) + return newMatrixObject(mat, 3, 3, Py_NEW); +} +//---------------------------Matrix.invert() --------------------- +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" ); + + 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}; - //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( (float ( * )[4]) *self->matrix ); - } else { - return EXPP_ReturnPyObjError( PyExc_StandardError, - "error calculating determinant for inverse()\n" ); + if(self->rowSize != self->colSize){ + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Matrix.invert: only square matrices are supported\n"); } - if( det != 0 ) { + //calculate the determinant + f = Matrix_Determinant(self); + det = PyFloat_AS_DOUBLE(f); + if(det != 0) { //calculate the classical adjoint - 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" ) ); - } + if(self->rowSize == 2) { 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 ) ); - 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 ); + } 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); } //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 - z = 0; - for( x = 0; x < self->rowSize; x++ ) { - for( y = 0; y < self->colSize; y++ ) { + 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; - -/* - 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 ); - } + Matrix_Transpose(self); } else { - printf( "matrix does not have an inverse - none attempted\n" ); + printf("Matrix.invert: matrix does not have an inverse\n"); } - PyMem_Free( mat ); - return EXPP_incr_ret( Py_None ); + return (PyObject*)self; } - - -PyObject *Matrix_Determinant( MatrixObject * self ) +//---------------------------Matrix.determinant() ---------------- +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( (float ( * )[4]) *self->matrix ); + 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]); } else { - return EXPP_ReturnPyObjError( PyExc_StandardError, - "error in determinant()\n" ); + det = Det4x4((float (*)[4]) *self->matrix); } return PyFloat_FromDouble( (double) det ); } //---------------------------Matrix.transpose() ------------------ - -PyObject *Matrix_Transpose( MatrixObject * self ) - +PyObject *Matrix_Transpose(MatrixObject * self) { - float t; + float t = 0.0f; - if( self->rowSize != self->colSize ) - return EXPP_ReturnPyObjError( PyExc_AttributeError, - "only square matrices are supported\n" ); + if(self->rowSize != self->colSize){ + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Matrix.transpose: 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 if( self->rowSize == 4 ) { - Mat4Transp( (float ( * )[4])*self->matrix ); - } else - return ( EXPP_ReturnPyObjError( PyExc_TypeError, - "unable to transpose matrix\n" ) ); + } else if(self->rowSize == 3) { + Mat3Transp((float (*)[3])*self->matrix); + } else { + Mat4Transp((float (*)[4])*self->matrix); + } - return EXPP_incr_ret( Py_None ); + return (PyObject*)self; } - -PyObject *Matrix_Zero( MatrixObject * self ) +//---------------------------Matrix.zero() ----------------------- +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 EXPP_incr_ret( Py_None ); + return (PyObject*)self; } - -PyObject *Matrix_Identity( MatrixObject * self ) +//---------------------------Matrix.identity(() ------------------ +PyObject *Matrix_Identity(MatrixObject * self) { - if( self->rowSize != self->colSize ) - return ( EXPP_ReturnPyObjError( PyExc_AttributeError, - "only square matrices supported\n" ) ); + if(self->rowSize != self->colSize){ + return EXPP_ReturnPyObjError(PyExc_AttributeError, + "Matrix.identity: only square matrices are 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 if( self->rowSize == 4 ) { - Mat4One( ( float ( * )[4] ) *self->matrix ); - } else - return ( EXPP_ReturnPyObjError( PyExc_TypeError, - "unable to create identity matrix\n" ) ); + } else if(self->rowSize == 3) { + Mat3One((float (*)[3]) *self->matrix); + } else { + Mat4One((float (*)[4]) *self->matrix); + } - return EXPP_incr_ret( Py_None ); + return (PyObject*)self; } - -static void Matrix_dealloc( MatrixObject * self ) +//----------------------------dealloc()(internal) ---------------- +//free the py_object +static void Matrix_dealloc(MatrixObject * self) { - PyMem_Free( self->contigPtr ); - PyMem_Free( self->matrix ); - - PyObject_DEL( 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); } - -static PyObject *Matrix_getattr( MatrixObject * self, char *name ) +//----------------------------getattr()(internal) ---------------- +//object.attribute access (get) +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 ); + if(STREQ(name, "rowSize")) { + return PyInt_FromLong((long) self->rowSize); + } else if(STREQ(name, "colSize")) { + return PyInt_FromLong((long) self->colSize); } - return Py_FindMethod( Matrix_methods, ( PyObject * ) self, name ); + return Py_FindMethod(Matrix_methods, (PyObject *) self, name); } - -static int Matrix_setattr( MatrixObject * self, char *name, PyObject * v ) +//----------------------------setattr()(internal) ---------------- +//object.attribute access (set) +static int Matrix_setattr(MatrixObject * self, char *name, PyObject * v) { /* This is not supported. */ - return ( -1 ); + return (-1); } - -static PyObject *Matrix_repr( MatrixObject * self ) +//----------------------------print object (internal)------------- +//print the object to screen +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 ); + char buffer[48], str[1024]; + + BLI_strncpy(str,"",1024); + for(x = 0; x < self->rowSize; x++){ + sprintf(buffer, "["); + 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); } - sprintf( ftoa, "%.4f]\n", self->matrix[x][y] ); - str = PyString_FromString( ftoa ); - PyString_ConcatAndDel( &repr, str ); } - return repr; + + return EXPP_incr_ret(PyString_FromString(str)); } -//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 ) +//---------------------SEQUENCE PROTOCOLS------------------------ +//----------------------------len(object)------------------------ +//sequence length +static int Matrix_len(MatrixObject * self) { - 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]; - } - - retval =( PyObject * ) newVectorObject( vec, self->colSize ); - PyMem_Free( vec ); - return retval; + return (self->colSize * self->rowSize); } - -static PyObject *Matrix_slice( MatrixObject * self, int begin, int end ) +//----------------------------object[]--------------------------- +//sequence accessor (get) +//the wrapped vector gives direct access to the matrix data +static PyObject *Matrix_item(MatrixObject * self, int i) { - 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; + if(i < 0 || i >= self->rowSize) + return EXPP_ReturnPyObjError(PyExc_IndexError, + "matrix[attribute]: array index out of range\n"); - 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; + return newVectorObject(self->matrix[i], self->colSize, Py_WRAP); } - -static int Matrix_ass_item( MatrixObject * self, int i, PyObject * ob ) +//----------------------------object[]------------------------- +//sequence accessor (set) +static int Matrix_ass_item(MatrixObject * self, int i, PyObject * ob) { - int maxsize, x, y; + int y, x, size = 0; + float vec[4]; - 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" ); + if(i > self->rowSize || i < 0){ + return EXPP_ReturnIntError(PyExc_TypeError, + "matrix[attribute] = x: bad row\n"); + } - x = ( int ) floor( ( double ) ( i / self->colSize ) ); - y = i % self->colSize; - self->matrix[x][y] = ( float ) PyFloat_AsDouble( ob ); + 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; - return 0; + 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"); + } } - -static int Matrix_ass_slice( MatrixObject * self, int begin, int end, - PyObject * seq ) +//----------------------------object[z:y]------------------------ +//sequence slice (get) +static PyObject *Matrix_slice(MatrixObject * self, int begin, int end) { - 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" ); + PyObject *list = NULL; + int count; - 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" ); + CLAMP(begin, 0, self->rowSize); + CLAMP(end, 0, self->rowSize); + begin = MIN2(begin,end); - 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; - } + list = PyList_New(end - begin); + for(count = begin; count < end; count++) { + PyList_SetItem(list, count - begin, + newVectorObject(self->matrix[count], self->colSize, Py_WRAP)); } - return 0; -} -static int Matrix_len( MatrixObject * self ) + return EXPP_incr_ret(list); +} +//----------------------------object[z:y]------------------------ +//sequence slice (set) +static int Matrix_ass_slice(MatrixObject * self, int begin, int end, + PyObject * seq) { - return ( self->colSize * self->rowSize ); + int i, x, y, size, sub_size = 0; + 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]; + } + return 0; + }else{ + return EXPP_ReturnIntError(PyExc_TypeError, + "matrix[begin:end] = []: illegal argument type for built-in operation\n"); + } } - -static PyObject *Matrix_add( PyObject * m1, PyObject * m2 ) +//------------------------NUMERIC PROTOCOLS---------------------- +//------------------------obj + obj------------------------------ +static 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" ); + 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; - rowSize = ( ( ( MatrixObject * ) m1 )->rowSize ); - colSize = ( ( ( MatrixObject * ) m1 )->colSize ); - matSize = rowSize * colSize; + EXPP_incr2(m1, m2); + mat1 = (MatrixObject*)m1; + mat2 = (MatrixObject*)m2; - mat = PyMem_Malloc( matSize * sizeof( float ) ); - if( mat == NULL ) { - return ( EXPP_ReturnPyObjError( PyExc_MemoryError, - "problem allocating mat\n\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"); } - 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]; + + 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]; } } - return newMatrixObject( mat, rowSize, colSize ); + EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); + return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW); } - -static PyObject *Matrix_sub( PyObject * m1, PyObject * m2 ) +//------------------------obj - obj------------------------------ +//subtraction +static 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" ); + 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; - rowSize = ( ( ( MatrixObject * ) m1 )->rowSize ); - colSize = ( ( ( MatrixObject * ) m1 )->colSize ); - matSize = rowSize * colSize; + EXPP_incr2(m1, m2); + mat1 = (MatrixObject*)m1; + mat2 = (MatrixObject*)m2; - mat = PyMem_Malloc( matSize * sizeof( float ) ); - if( mat == NULL ) { - return ( EXPP_ReturnPyObjError( PyExc_MemoryError, - "problem allocating mat\n\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"); } - 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]; + + 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]; } } - return newMatrixObject( mat, rowSize, colSize ); + EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); + return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW); } - -static PyObject *Matrix_mul( PyObject * m1, PyObject * m2 ) +//------------------------obj * obj------------------------------ +//mulplication +static PyObject *Matrix_mul(PyObject * m1, PyObject * m2) { - 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" ) ); - } - for( x = 0; x < rowSizeV; x++ ) { - for( y = 0; y < colSizeV; y++ ) { - mat[( ( x * rowSizeV ) + y )] = - matV->matrix[x][y] * - matW->matrix[x][y]; + 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"); } - } - 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] ); + 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]; } - mat[( ( x * rowSizeV ) + y )] = dot; - dot = 0; } + EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); + return newMatrixObject(mat, mat2->rowSize, mat2->colSize, Py_NEW); } - retval = ( PyObject* ) newMatrixObject( mat, rowSizeV, colSizeW ); - PyMem_Free( mat ); - return retval; - } else - return EXPP_ReturnPyObjError( PyExc_AttributeError, - "Error in matrix_mul...\n" ); -} - -//coercion of unknown types to type MatrixObject for numeric protocols -static 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 ) ); - 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" ) ); + }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]; } - for( x = 0; x < matSize; x++ ) { - mat[x] = ( float ) *tempF; + } + 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 < 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]); } - 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; + mat[((x * mat1->rowSize) + y)] = dot; + dot = 0.0f; } } - //unknom2n type or numeric cast failure - printf( "attempting matrix operation m2ith unsupported type...\n" ); - Py_INCREF( *m1 ); - return 0; //operation m2ill type check + return newMatrixObject(mat, mat1->rowSize, mat2->colSize, Py_NEW); } - } else { - //1st not Matrix - printf( "numeric protocol failure...\n" ); - return -1; //this should not occur - fail } - return -1; -} -//****************************************************************** -// Matrix definition -//****************************************************************** + EXPP_decr2((PyObject*)mat1, (PyObject*)mat2); + return EXPP_ReturnPyObjError(PyExc_TypeError, + "Matrix multiplication: arguments not acceptable for this operation\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) +{ + 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"); + } + } + Py_INCREF(*m2); + Py_INCREF(*m1); + return 0; +} +//-----------------PROTCOL DECLARATIONS-------------------------- 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 */ }; - -//****************************************************************** -//Function: newMatrixObject -//****************************************************************** -PyObject *newMatrixObject( float *mat, int rowSize, int colSize ) +//------------------------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) { MatrixObject *self; - 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 ); + int x, row, col; - //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 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( 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]; - } + 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"); } - } else { //or if NULL passed - for( row = 0; row < rowSize; row++ ) { - for( col = 0; col < colSize; col++ ) { - self->matrix[row][col] = 0.0f; + 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); + } + //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 no arguments are passed return identity matrix + Matrix_Identity(self); } + }else{ //bad type + return NULL; } - - //set size vars of matrix - self->rowSize = rowSize; - self->colSize = colSize; - - //set coercion flag - self->flag = 0; - - return ( ( PyObject * ) self ); + return (PyObject *) EXPP_incr_ret((PyObject *)self); } |