Blender  V2.59
mathutils_Matrix.c
Go to the documentation of this file.
00001 /*
00002  * $Id: mathutils_Matrix.c 38674 2011-07-25 01:44:19Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * Contributor(s): Michel Selten & Joseph Gilbert
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include <Python.h>
00034 
00035 #include "mathutils.h"
00036 
00037 #include "BLI_math.h"
00038 #include "BLI_utildefines.h"
00039 
00040 static PyObject *Matrix_copy(MatrixObject *self);
00041 static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value);
00042 static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self);
00043 
00044 /* matrix vector callbacks */
00045 int mathutils_matrix_vector_cb_index= -1;
00046 
00047 static int mathutils_matrix_vector_check(BaseMathObject *bmo)
00048 {
00049         MatrixObject *self= (MatrixObject *)bmo->cb_user;
00050         return BaseMath_ReadCallback(self);
00051 }
00052 
00053 static int mathutils_matrix_vector_get(BaseMathObject *bmo, int subtype)
00054 {
00055         MatrixObject *self= (MatrixObject *)bmo->cb_user;
00056         int i;
00057 
00058         if(BaseMath_ReadCallback(self) == -1)
00059                 return -1;
00060 
00061         for(i=0; i < self->col_size; i++)
00062                 bmo->data[i]= self->matrix[subtype][i];
00063 
00064         return 0;
00065 }
00066 
00067 static int mathutils_matrix_vector_set(BaseMathObject *bmo, int subtype)
00068 {
00069         MatrixObject *self= (MatrixObject *)bmo->cb_user;
00070         int i;
00071 
00072         if(BaseMath_ReadCallback(self) == -1)
00073                 return -1;
00074 
00075         for(i=0; i < self->col_size; i++)
00076                 self->matrix[subtype][i]= bmo->data[i];
00077 
00078         (void)BaseMath_WriteCallback(self);
00079         return 0;
00080 }
00081 
00082 static int mathutils_matrix_vector_get_index(BaseMathObject *bmo, int subtype, int index)
00083 {
00084         MatrixObject *self= (MatrixObject *)bmo->cb_user;
00085 
00086         if(BaseMath_ReadCallback(self) == -1)
00087                 return -1;
00088 
00089         bmo->data[index]= self->matrix[subtype][index];
00090         return 0;
00091 }
00092 
00093 static int mathutils_matrix_vector_set_index(BaseMathObject *bmo, int subtype, int index)
00094 {
00095         MatrixObject *self= (MatrixObject *)bmo->cb_user;
00096 
00097         if(BaseMath_ReadCallback(self) == -1)
00098                 return -1;
00099 
00100         self->matrix[subtype][index]= bmo->data[index];
00101 
00102         (void)BaseMath_WriteCallback(self);
00103         return 0;
00104 }
00105 
00106 Mathutils_Callback mathutils_matrix_vector_cb = {
00107         mathutils_matrix_vector_check,
00108         mathutils_matrix_vector_get,
00109         mathutils_matrix_vector_set,
00110         mathutils_matrix_vector_get_index,
00111         mathutils_matrix_vector_set_index
00112 };
00113 /* matrix vector callbacks, this is so you can do matrix[i][j] = val  */
00114 
00115 //----------------------------------mathutils.Matrix() -----------------
00116 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc.
00117 //create a new matrix type
00118 static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
00119 {
00120         if(kwds && PyDict_Size(kwds)) {
00121                 PyErr_SetString(PyExc_TypeError,
00122                                 "mathutils.Matrix(): "
00123                                 "takes no keyword args");
00124                 return NULL;
00125         }
00126 
00127         switch(PyTuple_GET_SIZE(args)) {
00128                 case 0:
00129                         return (PyObject *) newMatrixObject(NULL, 4, 4, Py_NEW, type);
00130                 case 1:
00131                 {
00132                         PyObject *arg= PyTuple_GET_ITEM(args, 0);
00133 
00134                         /* -1 is an error, size checks will accunt for this */
00135                         const unsigned short row_size= PySequence_Size(arg);
00136 
00137                         if(row_size >= 2 && row_size <= 4) {
00138                                 PyObject *item= PySequence_GetItem(arg, 0);
00139                                 const unsigned short col_size= PySequence_Size(item);
00140                                 Py_XDECREF(item);
00141 
00142                                 if(col_size >= 2 && col_size <= 4) {
00143                                         /* sane row & col size, new matrix and assign as slice  */
00144                                         PyObject *matrix= newMatrixObject(NULL, row_size, col_size, Py_NEW, type);
00145                                         if(Matrix_ass_slice((MatrixObject *)matrix, 0, INT_MAX, arg) == 0) {
00146                                                 return matrix;
00147                                         }
00148                                         else { /* matrix ok, slice assignment not */
00149                                                 Py_DECREF(matrix);
00150                                         }
00151                                 }
00152                         }
00153                 }
00154         }
00155 
00156         /* will overwrite error */
00157         PyErr_SetString(PyExc_TypeError,
00158                         "mathutils.Matrix(): "
00159                         "expects no args or 2-4 numeric sequences");
00160         return NULL;
00161 }
00162 
00163 static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self)
00164 {
00165         PyObject *ret= Matrix_copy(self);
00166         PyObject *ret_dummy= matrix_func(ret);
00167         if(ret_dummy) {
00168                 Py_DECREF(ret_dummy);
00169                 return (PyObject *)ret;
00170         }
00171         else { /* error */
00172                 Py_DECREF(ret);
00173                 return NULL;
00174         }
00175 }
00176 
00177 /* when a matrix is 4x4 size but initialized as a 3x3, re-assign values for 4x4 */
00178 static void matrix_3x3_as_4x4(float mat[16])
00179 {
00180         mat[10] = mat[8];
00181         mat[9] = mat[7];
00182         mat[8] = mat[6];
00183         mat[7] = 0.0f;
00184         mat[6] = mat[5];
00185         mat[5] = mat[4];
00186         mat[4] = mat[3];
00187         mat[3] = 0.0f;
00188 }
00189 
00190 /*-----------------------CLASS-METHODS----------------------------*/
00191 
00192 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc.
00193 PyDoc_STRVAR(C_Matrix_Rotation_doc,
00194 ".. classmethod:: Rotation(angle, size, axis)\n"
00195 "\n"
00196 "   Create a matrix representing a rotation.\n"
00197 "\n"
00198 "   :arg angle: The angle of rotation desired, in radians.\n"
00199 "   :type angle: float\n"
00200 "   :arg size: The size of the rotation matrix to construct [2, 4].\n"
00201 "   :type size: int\n"
00202 "   :arg axis: a string in ['X', 'Y', 'Z'] or a 3D Vector Object\n"
00203 "      (optional when size is 2).\n"
00204 "   :type axis: string or :class:`Vector`\n"
00205 "   :return: A new rotation matrix.\n"
00206 "   :rtype: :class:`Matrix`\n"
00207 );
00208 static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
00209 {
00210         PyObject *vec= NULL;
00211         const char *axis= NULL;
00212         int matSize;
00213         double angle; /* use double because of precision problems at high values */
00214         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
00215                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
00216 
00217         if(!PyArg_ParseTuple(args, "di|O", &angle, &matSize, &vec)) {
00218                 PyErr_SetString(PyExc_TypeError,
00219                                 "mathutils.RotationMatrix(angle, size, axis): "
00220                                 "expected float int and a string or vector");
00221                 return NULL;
00222         }
00223 
00224         if(vec && PyUnicode_Check(vec)) {
00225                 axis= _PyUnicode_AsString((PyObject *)vec);
00226                 if(axis==NULL || axis[0]=='\0' || axis[1]!='\0' || axis[0] < 'X' || axis[0] > 'Z') {
00227                         PyErr_SetString(PyExc_ValueError,
00228                                         "mathutils.RotationMatrix(): "
00229                                         "3rd argument axis value must be a 3D vector "
00230                                         "or a string in 'X', 'Y', 'Z'");
00231                         return NULL;
00232                 }
00233                 else {
00234                         /* use the string */
00235                         vec= NULL;
00236                 }
00237         }
00238 
00239         angle= angle_wrap_rad(angle);
00240 
00241         if(matSize != 2 && matSize != 3 && matSize != 4) {
00242                 PyErr_SetString(PyExc_ValueError,
00243                                 "mathutils.RotationMatrix(): "
00244                                 "can only return a 2x2 3x3 or 4x4 matrix");
00245                 return NULL;
00246         }
00247         if(matSize == 2 && (vec != NULL)) {
00248                 PyErr_SetString(PyExc_ValueError,
00249                                 "mathutils.RotationMatrix(): "
00250                                 "cannot create a 2x2 rotation matrix around arbitrary axis");
00251                 return NULL;
00252         }
00253         if((matSize == 3 || matSize == 4) && (axis == NULL) && (vec == NULL)) {
00254                 PyErr_SetString(PyExc_ValueError,
00255                                 "mathutils.RotationMatrix(): "
00256                                 "axis of rotation for 3d and 4d matrices is required");
00257                 return NULL;
00258         }
00259 
00260         /* check for valid vector/axis above */
00261         if(vec) {
00262                 float tvec[3];
00263 
00264                 if (mathutils_array_parse(tvec, 3, 3, vec, "mathutils.RotationMatrix(angle, size, axis), invalid 'axis' arg") == -1)
00265                         return NULL;
00266 
00267                 axis_angle_to_mat3((float (*)[3])mat, tvec, angle);
00268         }
00269         else if(matSize == 2) {
00270                 //2D rotation matrix
00271                 mat[0] = (float) cos (angle);
00272                 mat[1] = (float) sin (angle);
00273                 mat[2] = -((float) sin(angle));
00274                 mat[3] = (float) cos(angle);
00275         }
00276         else if(strcmp(axis, "X") == 0) {
00277                 //rotation around X
00278                 mat[0] = 1.0f;
00279                 mat[4] = (float) cos(angle);
00280                 mat[5] = (float) sin(angle);
00281                 mat[7] = -((float) sin(angle));
00282                 mat[8] = (float) cos(angle);
00283         }
00284         else if(strcmp(axis, "Y") == 0) {
00285                 //rotation around Y
00286                 mat[0] = (float) cos(angle);
00287                 mat[2] = -((float) sin(angle));
00288                 mat[4] = 1.0f;
00289                 mat[6] = (float) sin(angle);
00290                 mat[8] = (float) cos(angle);
00291         }
00292         else if(strcmp(axis, "Z") == 0) {
00293                 //rotation around Z
00294                 mat[0] = (float) cos(angle);
00295                 mat[1] = (float) sin(angle);
00296                 mat[3] = -((float) sin(angle));
00297                 mat[4] = (float) cos(angle);
00298                 mat[8] = 1.0f;
00299         }
00300         else {
00301                 /* should never get here */
00302                 PyErr_SetString(PyExc_ValueError,
00303                                 "mathutils.RotationMatrix(): unknown error");
00304                 return NULL;
00305         }
00306 
00307         if(matSize == 4) {
00308                 matrix_3x3_as_4x4(mat);
00309         }
00310         //pass to matrix creation
00311         return newMatrixObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
00312 }
00313 
00314 
00315 PyDoc_STRVAR(C_Matrix_Translation_doc,
00316 ".. classmethod:: Translation(vector)\n"
00317 "\n"
00318 "   Create a matrix representing a translation.\n"
00319 "\n"
00320 "   :arg vector: The translation vector.\n"
00321 "   :type vector: :class:`Vector`\n"
00322 "   :return: An identity matrix with a translation.\n"
00323 "   :rtype: :class:`Matrix`\n"
00324 );
00325 static PyObject *C_Matrix_Translation(PyObject *cls, PyObject *value)
00326 {
00327         float mat[16], tvec[3];
00328 
00329         if (mathutils_array_parse(tvec, 3, 4, value, "mathutils.Matrix.Translation(vector), invalid vector arg") == -1)
00330                 return NULL;
00331 
00332         /* create a identity matrix and add translation */
00333         unit_m4((float(*)[4]) mat);
00334         copy_v3_v3(mat + 12, tvec); /* 12, 13, 14 */
00335         return newMatrixObject(mat, 4, 4, Py_NEW, (PyTypeObject *)cls);
00336 }
00337 //----------------------------------mathutils.Matrix.Scale() -------------
00338 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc.
00339 PyDoc_STRVAR(C_Matrix_Scale_doc,
00340 ".. classmethod:: Scale(factor, size, axis)\n"
00341 "\n"
00342 "   Create a matrix representing a scaling.\n"
00343 "\n"
00344 "   :arg factor: The factor of scaling to apply.\n"
00345 "   :type factor: float\n"
00346 "   :arg size: The size of the scale matrix to construct [2, 4].\n"
00347 "   :type size: int\n"
00348 "   :arg axis: Direction to influence scale. (optional).\n"
00349 "   :type axis: :class:`Vector`\n"
00350 "   :return: A new scale matrix.\n"
00351 "   :rtype: :class:`Matrix`\n"
00352 );
00353 static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
00354 {
00355         PyObject *vec= NULL;
00356         int vec_size;
00357         float tvec[3];
00358         float factor;
00359         int matSize;
00360         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
00361                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
00362 
00363         if(!PyArg_ParseTuple(args, "fi|O:Matrix.Scale", &factor, &matSize, &vec)) {
00364                 return NULL;
00365         }
00366         if(matSize != 2 && matSize != 3 && matSize != 4) {
00367                 PyErr_SetString(PyExc_ValueError,
00368                                 "Matrix.Scale(): "
00369                                 "can only return a 2x2 3x3 or 4x4 matrix");
00370                 return NULL;
00371         }
00372         if(vec) {
00373                 vec_size= (matSize == 2 ? 2 : 3);
00374                 if(mathutils_array_parse(tvec, vec_size, vec_size, vec, "Matrix.Scale(factor, size, axis), invalid 'axis' arg") == -1) {
00375                         return NULL;
00376                 }
00377         }
00378         if(vec == NULL) {       //scaling along axis
00379                 if(matSize == 2) {
00380                         mat[0] = factor;
00381                         mat[3] = factor;
00382                 }
00383                 else {
00384                         mat[0] = factor;
00385                         mat[4] = factor;
00386                         mat[8] = factor;
00387                 }
00388         }
00389         else { //scaling in arbitrary direction
00390                 //normalize arbitrary axis
00391                 float norm = 0.0f;
00392                 int x;
00393                 for(x = 0; x < vec_size; x++) {
00394                         norm += tvec[x] * tvec[x];
00395                 }
00396                 norm = (float) sqrt(norm);
00397                 for(x = 0; x < vec_size; x++) {
00398                         tvec[x] /= norm;
00399                 }
00400                 if(matSize == 2) {
00401                         mat[0] = 1 + ((factor - 1) *(tvec[0] * tvec[0]));
00402                         mat[1] =     ((factor - 1) *(tvec[0] * tvec[1]));
00403                         mat[2] =     ((factor - 1) *(tvec[0] * tvec[1]));
00404                         mat[3] = 1 + ((factor - 1) *(tvec[1] * tvec[1]));
00405                 }
00406                 else {
00407                         mat[0] = 1 + ((factor - 1) *(tvec[0] * tvec[0]));
00408                         mat[1] =     ((factor - 1) *(tvec[0] * tvec[1]));
00409                         mat[2] =     ((factor - 1) *(tvec[0] * tvec[2]));
00410                         mat[3] =     ((factor - 1) *(tvec[0] * tvec[1]));
00411                         mat[4] = 1 + ((factor - 1) *(tvec[1] * tvec[1]));
00412                         mat[5] =     ((factor - 1) *(tvec[1] * tvec[2]));
00413                         mat[6] =     ((factor - 1) *(tvec[0] * tvec[2]));
00414                         mat[7] =     ((factor - 1) *(tvec[1] * tvec[2]));
00415                         mat[8] = 1 + ((factor - 1) *(tvec[2] * tvec[2]));
00416                 }
00417         }
00418         if(matSize == 4) {
00419                 matrix_3x3_as_4x4(mat);
00420         }
00421         //pass to matrix creation
00422         return newMatrixObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
00423 }
00424 //----------------------------------mathutils.Matrix.OrthoProjection() ---
00425 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc.
00426 PyDoc_STRVAR(C_Matrix_OrthoProjection_doc,
00427 ".. classmethod:: OrthoProjection(axis, size)\n"
00428 "\n"
00429 "   Create a matrix to represent an orthographic projection.\n"
00430 "\n"
00431 "   :arg axis: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'],\n"
00432 "      where a single axis is for a 2D matrix.\n"
00433 "      Or a vector for an arbitrary axis\n"
00434 "   :type axis: string or :class:`Vector`\n"
00435 "   :arg size: The size of the projection matrix to construct [2, 4].\n"
00436 "   :type size: int\n"
00437 "   :return: A new projection matrix.\n"
00438 "   :rtype: :class:`Matrix`\n"
00439 );
00440 static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
00441 {
00442         PyObject *axis;
00443 
00444         int matSize, x;
00445         float norm = 0.0f;
00446         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
00447                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
00448 
00449         if(!PyArg_ParseTuple(args, "Oi:Matrix.OrthoProjection", &axis, &matSize)) {
00450                 return NULL;
00451         }
00452         if(matSize != 2 && matSize != 3 && matSize != 4) {
00453                 PyErr_SetString(PyExc_ValueError,
00454                                 "mathutils.Matrix.OrthoProjection(): "
00455                                 "can only return a 2x2 3x3 or 4x4 matrix");
00456                 return NULL;
00457         }
00458 
00459         if(PyUnicode_Check(axis)) {     //ortho projection onto cardinal plane
00460                 Py_ssize_t plane_len;
00461                 const char *plane= _PyUnicode_AsStringAndSize(axis, &plane_len);
00462                 if(matSize == 2) {
00463                         if(plane_len == 1 && plane[0]=='X') {
00464                                 mat[0]= 1.0f;
00465                         }
00466                         else if (plane_len == 1 && plane[0]=='Y') {
00467                                 mat[3]= 1.0f;
00468                         }
00469                         else {
00470                                 PyErr_Format(PyExc_ValueError,
00471                                              "mathutils.Matrix.OrthoProjection(): "
00472                                              "unknown plane, expected: X, Y, not '%.200s'",
00473                                              plane);
00474                                 return NULL;
00475                         }
00476                 }
00477                 else {
00478                         if(plane_len == 2 && plane[0]=='X' && plane[1]=='Y') {
00479                                 mat[0]= 1.0f;
00480                                 mat[4]= 1.0f;
00481                         }
00482                         else if (plane_len == 2 && plane[0]=='X' && plane[1]=='Z') {
00483                                 mat[0]= 1.0f;
00484                                 mat[8]= 1.0f;
00485                         }
00486                         else if (plane_len == 2 && plane[0]=='Y' && plane[1]=='Z') {
00487                                 mat[4]= 1.0f;
00488                                 mat[8]= 1.0f;
00489                         }
00490                         else {
00491                                 PyErr_Format(PyExc_ValueError,
00492                                              "mathutils.Matrix.OrthoProjection(): "
00493                                              "unknown plane, expected: XY, XZ, YZ, not '%.200s'",
00494                                              plane);
00495                                 return NULL;
00496                         }
00497                 }
00498         }
00499         else {
00500                 //arbitrary plane
00501 
00502                 int vec_size= (matSize == 2 ? 2 : 3);
00503                 float tvec[4];
00504 
00505                 if(mathutils_array_parse(tvec, vec_size, vec_size, axis, "Matrix.OrthoProjection(axis, size), invalid 'axis' arg") == -1) {
00506                         return NULL;
00507                 }
00508 
00509                 //normalize arbitrary axis
00510                 for(x = 0; x < vec_size; x++) {
00511                         norm += tvec[x] * tvec[x];
00512                 }
00513                 norm = (float) sqrt(norm);
00514                 for(x = 0; x < vec_size; x++) {
00515                         tvec[x] /= norm;
00516                 }
00517                 if(matSize == 2) {
00518                         mat[0] = 1 - (tvec[0] * tvec[0]);
00519                         mat[1] = -(tvec[0] * tvec[1]);
00520                         mat[2] = -(tvec[0] * tvec[1]);
00521                         mat[3] = 1 - (tvec[1] * tvec[1]);
00522                 }
00523                 else if(matSize > 2) {
00524                         mat[0] = 1 - (tvec[0] * tvec[0]);
00525                         mat[1] = -(tvec[0] * tvec[1]);
00526                         mat[2] = -(tvec[0] * tvec[2]);
00527                         mat[3] = -(tvec[0] * tvec[1]);
00528                         mat[4] = 1 - (tvec[1] * tvec[1]);
00529                         mat[5] = -(tvec[1] * tvec[2]);
00530                         mat[6] = -(tvec[0] * tvec[2]);
00531                         mat[7] = -(tvec[1] * tvec[2]);
00532                         mat[8] = 1 - (tvec[2] * tvec[2]);
00533                 }
00534         }
00535         if(matSize == 4) {
00536                 matrix_3x3_as_4x4(mat);
00537         }
00538         //pass to matrix creation
00539         return newMatrixObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
00540 }
00541 
00542 PyDoc_STRVAR(C_Matrix_Shear_doc,
00543 ".. classmethod:: Shear(plane, size, factor)\n"
00544 "\n"
00545 "   Create a matrix to represent an shear transformation.\n"
00546 "\n"
00547 "   :arg plane: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'],\n"
00548 "      where a single axis is for a 2D matrix only.\n"
00549 "   :type plane: string\n"
00550 "   :arg size: The size of the shear matrix to construct [2, 4].\n"
00551 "   :type size: int\n"
00552 "   :arg factor: The factor of shear to apply. For a 3 or 4 *size* matrix\n"
00553 "      pass a pair of floats corrasponding with the *plane* axis.\n"
00554 "   :type factor: float or float pair\n"
00555 "   :return: A new shear matrix.\n"
00556 "   :rtype: :class:`Matrix`\n"
00557 );
00558 static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args)
00559 {
00560         int matSize;
00561         const char *plane;
00562         PyObject *fac;
00563         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
00564                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
00565 
00566         if(!PyArg_ParseTuple(args, "siO:Matrix.Shear", &plane, &matSize, &fac)) {
00567                 return NULL;
00568         }
00569         if(matSize != 2 && matSize != 3 && matSize != 4) {
00570                 PyErr_SetString(PyExc_ValueError,
00571                                 "mathutils.Matrix.Shear(): "
00572                                 "can only return a 2x2 3x3 or 4x4 matrix");
00573                 return NULL;
00574         }
00575 
00576         if(matSize == 2) {
00577                 float const factor= PyFloat_AsDouble(fac);
00578 
00579                 if(factor==-1.0f && PyErr_Occurred()) {
00580                         PyErr_SetString(PyExc_TypeError,
00581                                         "mathutils.Matrix.Shear(): "
00582                                         "the factor to be a float");
00583                         return NULL;
00584                 }
00585 
00586                 /* unit */
00587                 mat[0] = 1.0f;
00588                 mat[3] = 1.0f;
00589 
00590                 if(strcmp(plane, "X") == 0) {
00591                         mat[2] = factor;
00592                 }
00593                 else if(strcmp(plane, "Y") == 0) {
00594                         mat[1] = factor;
00595                 }
00596                 else {
00597                         PyErr_SetString(PyExc_ValueError,
00598                                         "Matrix.Shear(): "
00599                                         "expected: X, Y or wrong matrix size for shearing plane");
00600                         return NULL;
00601                 }
00602         }
00603         else {
00604                 /* 3 or 4, apply as 3x3, resize later if needed */
00605                 float factor[2];
00606 
00607                 if(mathutils_array_parse(factor, 2, 2, fac, "Matrix.Shear()") < 0) {
00608                         return NULL;
00609                 }
00610 
00611                 /* unit */
00612                 mat[0] = 1.0f;
00613                 mat[4] = 1.0f;
00614                 mat[8] = 1.0f;
00615 
00616                 if(strcmp(plane, "XY") == 0) {
00617                         mat[6] = factor[0];
00618                         mat[7] = factor[1];
00619                 }
00620                 else if(strcmp(plane, "XZ") == 0) {
00621                         mat[3] = factor[0];
00622                         mat[5] = factor[1];
00623                 }
00624                 else if(strcmp(plane, "YZ") == 0) {
00625                         mat[1] = factor[0];
00626                         mat[2] = factor[1];
00627                 }
00628                 else {
00629                         PyErr_SetString(PyExc_ValueError,
00630                                         "mathutils.Matrix.Shear(): "
00631                                         "expected: X, Y, XY, XZ, YZ");
00632                         return NULL;
00633                 }
00634         }
00635 
00636         if(matSize == 4) {
00637                 matrix_3x3_as_4x4(mat);
00638         }
00639         //pass to matrix creation
00640         return newMatrixObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
00641 }
00642 
00643 void matrix_as_3x3(float mat[3][3], MatrixObject *self)
00644 {
00645         copy_v3_v3(mat[0], self->matrix[0]);
00646         copy_v3_v3(mat[1], self->matrix[1]);
00647         copy_v3_v3(mat[2], self->matrix[2]);
00648 }
00649 
00650 /* assumes rowsize == colsize is checked and the read callback has run */
00651 static float matrix_determinant_internal(MatrixObject *self)
00652 {
00653         if(self->row_size == 2) {
00654                 return determinant_m2(self->matrix[0][0], self->matrix[0][1],
00655                                          self->matrix[1][0], self->matrix[1][1]);
00656         }
00657         else if(self->row_size == 3) {
00658                 return determinant_m3(self->matrix[0][0], self->matrix[0][1],
00659                                          self->matrix[0][2], self->matrix[1][0],
00660                                          self->matrix[1][1], self->matrix[1][2],
00661                                          self->matrix[2][0], self->matrix[2][1],
00662                                          self->matrix[2][2]);
00663         }
00664         else {
00665                 return determinant_m4((float (*)[4])self->contigPtr);
00666         }
00667 }
00668 
00669 
00670 /*-----------------------------METHODS----------------------------*/
00671 PyDoc_STRVAR(Matrix_to_quaternion_doc,
00672 ".. method:: to_quaternion()\n"
00673 "\n"
00674 "   Return a quaternion representation of the rotation matrix.\n"
00675 "\n"
00676 "   :return: Quaternion representation of the rotation matrix.\n"
00677 "   :rtype: :class:`Quaternion`\n"
00678 );
00679 static PyObject *Matrix_to_quaternion(MatrixObject *self)
00680 {
00681         float quat[4];
00682 
00683         if(BaseMath_ReadCallback(self) == -1)
00684                 return NULL;
00685 
00686         /*must be 3-4 cols, 3-4 rows, square matrix*/
00687         if((self->col_size < 3) || (self->row_size < 3) || (self->col_size != self->row_size)) {
00688                 PyErr_SetString(PyExc_ValueError,
00689                                 "matrix.to_quat(): "
00690                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
00691                 return NULL;
00692         }
00693         if(self->col_size == 3){
00694                 mat3_to_quat(quat, (float (*)[3])self->contigPtr);
00695         }
00696         else {
00697                 mat4_to_quat(quat, (float (*)[4])self->contigPtr);
00698         }
00699 
00700         return newQuaternionObject(quat, Py_NEW, NULL);
00701 }
00702 
00703 /*---------------------------matrix.toEuler() --------------------*/
00704 PyDoc_STRVAR(Matrix_to_euler_doc,
00705 ".. method:: to_euler(order, euler_compat)\n"
00706 "\n"
00707 "   Return an Euler representation of the rotation matrix\n"
00708 "   (3x3 or 4x4 matrix only).\n"
00709 "\n"
00710 "   :arg order: Optional rotation order argument in\n"
00711 "      ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n"
00712 "   :type order: string\n"
00713 "   :arg euler_compat: Optional euler argument the new euler will be made\n"
00714 "      compatible with (no axis flipping between them).\n"
00715 "      Useful for converting a series of matrices to animation curves.\n"
00716 "   :type euler_compat: :class:`Euler`\n"
00717 "   :return: Euler representation of the matrix.\n"
00718 "   :rtype: :class:`Euler`\n"
00719 );
00720 static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
00721 {
00722         const char *order_str= NULL;
00723         short order= EULER_ORDER_XYZ;
00724         float eul[3], eul_compatf[3];
00725         EulerObject *eul_compat = NULL;
00726 
00727         float tmat[3][3];
00728         float (*mat)[3];
00729 
00730         if(BaseMath_ReadCallback(self) == -1)
00731                 return NULL;
00732 
00733         if(!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat))
00734                 return NULL;
00735 
00736         if(eul_compat) {
00737                 if(BaseMath_ReadCallback(eul_compat) == -1)
00738                         return NULL;
00739 
00740                 copy_v3_v3(eul_compatf, eul_compat->eul);
00741         }
00742 
00743         /*must be 3-4 cols, 3-4 rows, square matrix*/
00744         if(self->col_size ==3 && self->row_size ==3) {
00745                 mat= (float (*)[3])self->contigPtr;
00746         }
00747         else if (self->col_size ==4 && self->row_size ==4) {
00748                 copy_m3_m4(tmat, (float (*)[4])self->contigPtr);
00749                 mat= tmat;
00750         }
00751         else {
00752                 PyErr_SetString(PyExc_ValueError,
00753                                 "matrix.to_euler(): "
00754                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
00755                 return NULL;
00756         }
00757 
00758         if(order_str) {
00759                 order= euler_order_from_string(order_str, "matrix.to_euler()");
00760 
00761                 if(order == -1)
00762                         return NULL;
00763         }
00764 
00765         if(eul_compat) {
00766                 if(order == 1)  mat3_to_compatible_eul(eul, eul_compatf, mat);
00767                 else                    mat3_to_compatible_eulO(eul, eul_compatf, order, mat);
00768         }
00769         else {
00770                 if(order == 1)  mat3_to_eul(eul, mat);
00771                 else                    mat3_to_eulO(eul, order, mat);
00772         }
00773 
00774         return newEulerObject(eul, order, Py_NEW, NULL);
00775 }
00776 
00777 PyDoc_STRVAR(Matrix_resize_4x4_doc,
00778 ".. method:: resize_4x4()\n"
00779 "\n"
00780 "   Resize the matrix to 4x4.\n"
00781 );
00782 static PyObject *Matrix_resize_4x4(MatrixObject *self)
00783 {
00784         int x, first_row_elem, curr_pos, new_pos, blank_columns, blank_rows, index;
00785 
00786         if(self->wrapped==Py_WRAP){
00787                 PyErr_SetString(PyExc_TypeError,
00788                                 "cannot resize wrapped data - make a copy and resize that");
00789                 return NULL;
00790         }
00791         if(self->cb_user){
00792                 PyErr_SetString(PyExc_TypeError,
00793                                 "cannot resize owned data - make a copy and resize that");
00794                 return NULL;
00795         }
00796 
00797         self->contigPtr = PyMem_Realloc(self->contigPtr, (sizeof(float) * 16));
00798         if(self->contigPtr == NULL) {
00799                 PyErr_SetString(PyExc_MemoryError,
00800                                 "matrix.resize_4x4(): problem allocating pointer space");
00801                 return NULL;
00802         }
00803         /*set row pointers*/
00804         for(x = 0; x < 4; x++) {
00805                 self->matrix[x] = self->contigPtr + (x * 4);
00806         }
00807         /*move data to new spot in array + clean*/
00808         for(blank_rows = (4 - self->row_size); blank_rows > 0; blank_rows--){
00809                 for(x = 0; x < 4; x++){
00810                         index = (4 * (self->row_size + (blank_rows - 1))) + x;
00811                         if (index == 10 || index == 15){
00812                                 self->contigPtr[index] = 1.0f;
00813                         }
00814                         else {
00815                                 self->contigPtr[index] = 0.0f;
00816                         }
00817                 }
00818         }
00819         for(x = 1; x <= self->row_size; x++){
00820                 first_row_elem = (self->col_size * (self->row_size - x));
00821                 curr_pos = (first_row_elem + (self->col_size -1));
00822                 new_pos = (4 * (self->row_size - x)) + (curr_pos - first_row_elem);
00823                 for(blank_columns = (4 - self->col_size); blank_columns > 0; blank_columns--){
00824                         self->contigPtr[new_pos + blank_columns] = 0.0f;
00825                 }
00826                 for( ; curr_pos >= first_row_elem; curr_pos--){
00827                         self->contigPtr[new_pos] = self->contigPtr[curr_pos];
00828                         new_pos--;
00829                 }
00830         }
00831         self->row_size = 4;
00832         self->col_size = 4;
00833 
00834         Py_RETURN_NONE;
00835 }
00836 
00837 PyDoc_STRVAR(Matrix_to_4x4_doc,
00838 ".. method:: to_4x4()\n"
00839 "\n"
00840 "   Return a 4x4 copy of this matrix.\n"
00841 "\n"
00842 "   :return: a new matrix.\n"
00843 "   :rtype: :class:`Matrix`\n"
00844 );
00845 static PyObject *Matrix_to_4x4(MatrixObject *self)
00846 {
00847         if(BaseMath_ReadCallback(self) == -1)
00848                 return NULL;
00849 
00850         if(self->col_size==4 && self->row_size==4) {
00851                 return (PyObject *)newMatrixObject(self->contigPtr, 4, 4, Py_NEW, Py_TYPE(self));
00852         }
00853         else if(self->col_size==3 && self->row_size==3) {
00854                 float mat[4][4];
00855                 copy_m4_m3(mat, (float (*)[3])self->contigPtr);
00856                 return (PyObject *)newMatrixObject((float *)mat, 4, 4, Py_NEW, Py_TYPE(self));
00857         }
00858         /* TODO, 2x2 matrix */
00859 
00860         PyErr_SetString(PyExc_TypeError,
00861                         "matrix.to_4x4(): inappropriate matrix size");
00862         return NULL;
00863 }
00864 
00865 PyDoc_STRVAR(Matrix_to_3x3_doc,
00866 ".. method:: to_3x3()\n"
00867 "\n"
00868 "   Return a 3x3 copy of this matrix.\n"
00869 "\n"
00870 "   :return: a new matrix.\n"
00871 "   :rtype: :class:`Matrix`\n"
00872 );
00873 static PyObject *Matrix_to_3x3(MatrixObject *self)
00874 {
00875         float mat[3][3];
00876 
00877         if(BaseMath_ReadCallback(self) == -1)
00878                 return NULL;
00879 
00880         if((self->col_size < 3) || (self->row_size < 3)) {
00881                 PyErr_SetString(PyExc_TypeError,
00882                                 "matrix.to_3x3(): inappropriate matrix size");
00883                 return NULL;
00884         }
00885 
00886         matrix_as_3x3(mat, self);
00887 
00888         return newMatrixObject((float *)mat, 3, 3, Py_NEW, Py_TYPE(self));
00889 }
00890 
00891 PyDoc_STRVAR(Matrix_to_translation_doc,
00892 ".. method:: to_translation()\n"
00893 "\n"
00894 "   Return a the translation part of a 4 row matrix.\n"
00895 "\n"
00896 "   :return: Return a the translation of a matrix.\n"
00897 "   :rtype: :class:`Vector`\n"
00898 );
00899 static PyObject *Matrix_to_translation(MatrixObject *self)
00900 {
00901         if(BaseMath_ReadCallback(self) == -1)
00902                 return NULL;
00903 
00904         if((self->col_size < 3) || self->row_size < 4){
00905                 PyErr_SetString(PyExc_TypeError,
00906                                 "matrix.to_translation(): "
00907                                 "inappropriate matrix size");
00908                 return NULL;
00909         }
00910 
00911         return newVectorObject(self->matrix[3], 3, Py_NEW, NULL);
00912 }
00913 
00914 PyDoc_STRVAR(Matrix_to_scale_doc,
00915 ".. method:: to_scale()\n"
00916 "\n"
00917 "   Return a the scale part of a 3x3 or 4x4 matrix.\n"
00918 "\n"
00919 "   :return: Return a the scale of a matrix.\n"
00920 "   :rtype: :class:`Vector`\n"
00921 "\n"
00922 "   .. note:: This method does not return negative a scale on any axis because it is not possible to obtain this data from the matrix alone.\n"
00923 );
00924 static PyObject *Matrix_to_scale(MatrixObject *self)
00925 {
00926         float rot[3][3];
00927         float mat[3][3];
00928         float size[3];
00929 
00930         if(BaseMath_ReadCallback(self) == -1)
00931                 return NULL;
00932 
00933         /*must be 3-4 cols, 3-4 rows, square matrix*/
00934         if((self->col_size < 3) || (self->row_size < 3)) {
00935                 PyErr_SetString(PyExc_TypeError,
00936                                 "matrix.to_scale(): "
00937                                 "inappropriate matrix size, 3x3 minimum size");
00938                 return NULL;
00939         }
00940 
00941         matrix_as_3x3(mat, self);
00942 
00943         /* compatible mat4_to_loc_rot_size */
00944         mat3_to_rot_size(rot, size, mat);
00945 
00946         return newVectorObject(size, 3, Py_NEW, NULL);
00947 }
00948 
00949 /*---------------------------matrix.invert() ---------------------*/
00950 PyDoc_STRVAR(Matrix_invert_doc,
00951 ".. method:: invert()\n"
00952 "\n"
00953 "   Set the matrix to its inverse.\n"
00954 "\n"
00955 "   .. note:: :exc:`ValueError` exception is raised.\n"
00956 "\n"
00957 "   .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n"
00958 );
00959 static PyObject *Matrix_invert(MatrixObject *self)
00960 {
00961 
00962         int x, y, z = 0;
00963         float det = 0.0f;
00964         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
00965                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
00966 
00967         if(BaseMath_ReadCallback(self) == -1)
00968                 return NULL;
00969 
00970         if(self->row_size != self->col_size){
00971                 PyErr_SetString(PyExc_TypeError,
00972                                 "matrix.invert(ed): "
00973                                 "only square matrices are supported");
00974                 return NULL;
00975         }
00976 
00977         /*calculate the determinant*/
00978         det = matrix_determinant_internal(self);
00979 
00980         if(det != 0) {
00981                 /*calculate the classical adjoint*/
00982                 if(self->row_size == 2) {
00983                         mat[0] = self->matrix[1][1];
00984                         mat[1] = -self->matrix[0][1];
00985                         mat[2] = -self->matrix[1][0];
00986                         mat[3] = self->matrix[0][0];
00987                 } else if(self->row_size == 3) {
00988                         adjoint_m3_m3((float (*)[3]) mat,(float (*)[3])self->contigPtr);
00989                 } else if(self->row_size == 4) {
00990                         adjoint_m4_m4((float (*)[4]) mat, (float (*)[4])self->contigPtr);
00991                 }
00992                 /*divide by determinate*/
00993                 for(x = 0; x < (self->row_size * self->col_size); x++) {
00994                         mat[x] /= det;
00995                 }
00996                 /*set values*/
00997                 for(x = 0; x < self->row_size; x++) {
00998                         for(y = 0; y < self->col_size; y++) {
00999                                 self->matrix[x][y] = mat[z];
01000                                 z++;
01001                         }
01002                 }
01003                 /*transpose
01004                 Matrix_transpose(self);*/
01005         }
01006         else {
01007                 PyErr_SetString(PyExc_ValueError,
01008                                 "matrix does not have an inverse");
01009                 return NULL;
01010         }
01011 
01012         (void)BaseMath_WriteCallback(self);
01013         Py_RETURN_NONE;
01014 }
01015 
01016 PyDoc_STRVAR(Matrix_inverted_doc,
01017 ".. method:: inverted()\n"
01018 "\n"
01019 "   Return an inverted copy of the matrix.\n"
01020 "\n"
01021 "   :return: the  inverted matrix.\n"
01022 "   :rtype: :class:`Matrix`\n"
01023 "\n"
01024 "   .. note:: :exc:`ValueError` exception is raised.\n"
01025 );
01026 static PyObject *Matrix_inverted(MatrixObject *self)
01027 {
01028         return matrix__apply_to_copy((PyNoArgsFunction)Matrix_invert, self);
01029 }
01030 
01031 PyDoc_STRVAR(Matrix_rotate_doc,
01032 ".. method:: rotate(other)\n"
01033 "\n"
01034 "   Rotates the matrix a by another mathutils value.\n"
01035 "\n"
01036 "   :arg other: rotation component of mathutils value\n"
01037 "   :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n"
01038 "\n"
01039 "   .. note:: If any of the columns are not unit length this may not have desired results.\n"
01040 );
01041 static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value)
01042 {
01043         float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
01044 
01045         if(BaseMath_ReadCallback(self) == -1)
01046                 return NULL;
01047 
01048         if(mathutils_any_to_rotmat(other_rmat, value, "matrix.rotate(value)") == -1)
01049                 return NULL;
01050 
01051         if(self->col_size != 3 || self->row_size != 3) {
01052                 PyErr_SetString(PyExc_TypeError,
01053                                 "Matrix must have 3x3 dimensions");
01054                 return NULL;
01055         }
01056 
01057         matrix_as_3x3(self_rmat, self);
01058         mul_m3_m3m3(rmat, self_rmat, other_rmat);
01059 
01060         copy_m3_m3((float (*)[3])(self->contigPtr), rmat);
01061 
01062         (void)BaseMath_WriteCallback(self);
01063         Py_RETURN_NONE;
01064 }
01065 
01066 /*---------------------------matrix.decompose() ---------------------*/
01067 PyDoc_STRVAR(Matrix_decompose_doc,
01068 ".. method:: decompose()\n"
01069 "\n"
01070 "   Return the location, rotaion and scale components of this matrix.\n"
01071 "\n"
01072 "   :return: loc, rot, scale triple.\n"
01073 "   :rtype: (:class:`Vector`, :class:`Quaternion`, :class:`Vector`)"
01074 );
01075 static PyObject *Matrix_decompose(MatrixObject *self)
01076 {
01077         PyObject *ret;
01078         float loc[3];
01079         float rot[3][3];
01080         float quat[4];
01081         float size[3];
01082 
01083         if(self->col_size != 4 || self->row_size != 4) {
01084                 PyErr_SetString(PyExc_TypeError,
01085                                 "matrix.decompose(): "
01086                                 "inappropriate matrix size - expects 4x4 matrix");
01087                 return NULL;
01088         }
01089 
01090         if(BaseMath_ReadCallback(self) == -1)
01091                 return NULL;
01092 
01093         mat4_to_loc_rot_size(loc, rot, size, (float (*)[4])self->contigPtr);
01094         mat3_to_quat(quat, rot);
01095 
01096         ret= PyTuple_New(3);
01097         PyTuple_SET_ITEM(ret, 0, newVectorObject(loc, 3, Py_NEW, NULL));
01098         PyTuple_SET_ITEM(ret, 1, newQuaternionObject(quat, Py_NEW, NULL));
01099         PyTuple_SET_ITEM(ret, 2, newVectorObject(size, 3, Py_NEW, NULL));
01100 
01101         return ret;
01102 }
01103 
01104 
01105 
01106 PyDoc_STRVAR(Matrix_lerp_doc,
01107 ".. function:: lerp(other, factor)\n"
01108 "\n"
01109 "   Returns the interpolation of two matricies.\n"
01110 "\n"
01111 "   :arg other: value to interpolate with.\n"
01112 "   :type other: :class:`Matrix`\n"
01113 "   :arg factor: The interpolation value in [0.0, 1.0].\n"
01114 "   :type factor: float\n"
01115 "   :return: The interpolated rotation.\n"
01116 "   :rtype: :class:`Matrix`\n"
01117 );
01118 static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
01119 {
01120         MatrixObject *mat2 = NULL;
01121         float fac, mat[MATRIX_MAX_DIM*MATRIX_MAX_DIM];
01122 
01123         if(!PyArg_ParseTuple(args, "O!f:lerp", &matrix_Type, &mat2, &fac))
01124                 return NULL;
01125 
01126         if(self->row_size != mat2->row_size || self->col_size != mat2->col_size) {
01127                 PyErr_SetString(PyExc_ValueError,
01128                                 "matrix.lerp(): "
01129                                 "expects both matrix objects of the same dimensions");
01130                 return NULL;
01131         }
01132 
01133         if(BaseMath_ReadCallback(self) == -1 || BaseMath_ReadCallback(mat2) == -1)
01134                 return NULL;
01135 
01136         /* TODO, different sized matrix */
01137         if(self->row_size==4 && self->col_size==4) {
01138                 blend_m4_m4m4((float (*)[4])mat, (float (*)[4])self->contigPtr, (float (*)[4])mat2->contigPtr, fac);
01139         }
01140         else if (self->row_size==3 && self->col_size==3) {
01141                 blend_m3_m3m3((float (*)[3])mat, (float (*)[3])self->contigPtr, (float (*)[3])mat2->contigPtr, fac);
01142         }
01143         else {
01144                 PyErr_SetString(PyExc_ValueError,
01145                                 "matrix.lerp(): "
01146                                 "only 3x3 and 4x4 matrices supported");
01147                 return NULL;
01148         }
01149 
01150         return (PyObject*)newMatrixObject(mat, self->row_size, self->col_size, Py_NEW, Py_TYPE(self));
01151 }
01152 
01153 /*---------------------------matrix.determinant() ----------------*/
01154 PyDoc_STRVAR(Matrix_determinant_doc,
01155 ".. method:: determinant()\n"
01156 "\n"
01157 "   Return the determinant of a matrix.\n"
01158 "\n"
01159 "   :return: Return a the determinant of a matrix.\n"
01160 "   :rtype: float\n"
01161 "\n"
01162 "   .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n"
01163 );
01164 static PyObject *Matrix_determinant(MatrixObject *self)
01165 {
01166         if(BaseMath_ReadCallback(self) == -1)
01167                 return NULL;
01168 
01169         if(self->row_size != self->col_size){
01170                 PyErr_SetString(PyExc_TypeError,
01171                                 "matrix.determinant: "
01172                                 "only square matrices are supported");
01173                 return NULL;
01174         }
01175 
01176         return PyFloat_FromDouble((double)matrix_determinant_internal(self));
01177 }
01178 /*---------------------------matrix.transpose() ------------------*/
01179 PyDoc_STRVAR(Matrix_transpose_doc,
01180 ".. method:: transpose()\n"
01181 "\n"
01182 "   Set the matrix to its transpose.\n"
01183 "\n"
01184 "   .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n"
01185 );
01186 static PyObject *Matrix_transpose(MatrixObject *self)
01187 {
01188         float t = 0.0f;
01189 
01190         if(BaseMath_ReadCallback(self) == -1)
01191                 return NULL;
01192 
01193         if(self->row_size != self->col_size){
01194                 PyErr_SetString(PyExc_TypeError,
01195                                 "matrix.transpose(d): "
01196                                 "only square matrices are supported");
01197                 return NULL;
01198         }
01199 
01200         if(self->row_size == 2) {
01201                 t = self->matrix[1][0];
01202                 self->matrix[1][0] = self->matrix[0][1];
01203                 self->matrix[0][1] = t;
01204         } else if(self->row_size == 3) {
01205                 transpose_m3((float (*)[3])self->contigPtr);
01206         }
01207         else {
01208                 transpose_m4((float (*)[4])self->contigPtr);
01209         }
01210 
01211         (void)BaseMath_WriteCallback(self);
01212         Py_RETURN_NONE;
01213 }
01214 
01215 PyDoc_STRVAR(Matrix_transposed_doc,
01216 ".. method:: transposed()\n"
01217 "\n"
01218 "   Return a new, transposed matrix.\n"
01219 "\n"
01220 "   :return: a transposed matrix\n"
01221 "   :rtype: :class:`Matrix`\n"
01222 );
01223 static PyObject *Matrix_transposed(MatrixObject *self)
01224 {
01225         return matrix__apply_to_copy((PyNoArgsFunction)Matrix_transpose, self);
01226 }
01227 
01228 /*---------------------------matrix.zero() -----------------------*/
01229 PyDoc_STRVAR(Matrix_zero_doc,
01230 ".. method:: zero()\n"
01231 "\n"
01232 "   Set all the matrix values to zero.\n"
01233 "\n"
01234 "   :return: an instance of itself\n"
01235 "   :rtype: :class:`Matrix`\n"
01236 );
01237 static PyObject *Matrix_zero(MatrixObject *self)
01238 {
01239         fill_vn(self->contigPtr, self->row_size * self->col_size, 0.0f);
01240 
01241         if(BaseMath_WriteCallback(self) == -1)
01242                 return NULL;
01243 
01244         Py_RETURN_NONE;
01245 }
01246 /*---------------------------matrix.identity(() ------------------*/
01247 PyDoc_STRVAR(Matrix_identity_doc,
01248 ".. method:: identity()\n"
01249 "\n"
01250 "   Set the matrix to the identity matrix.\n"
01251 "\n"
01252 "   .. note:: An object with zero location and rotation, a scale of one,\n"
01253 "      will have an identity matrix.\n"
01254 "\n"
01255 "   .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n"
01256 );
01257 static PyObject *Matrix_identity(MatrixObject *self)
01258 {
01259         if(BaseMath_ReadCallback(self) == -1)
01260                 return NULL;
01261 
01262         if(self->row_size != self->col_size){
01263                 PyErr_SetString(PyExc_TypeError,
01264                                 "matrix.identity: "
01265                                 "only square matrices are supported");
01266                 return NULL;
01267         }
01268 
01269         if(self->row_size == 2) {
01270                 self->matrix[0][0] = 1.0f;
01271                 self->matrix[0][1] = 0.0f;
01272                 self->matrix[1][0] = 0.0f;
01273                 self->matrix[1][1] = 1.0f;
01274         } else if(self->row_size == 3) {
01275                 unit_m3((float (*)[3])self->contigPtr);
01276         }
01277         else {
01278                 unit_m4((float (*)[4])self->contigPtr);
01279         }
01280 
01281         if(BaseMath_WriteCallback(self) == -1)
01282                 return NULL;
01283 
01284         Py_RETURN_NONE;
01285 }
01286 
01287 /*---------------------------Matrix.copy() ------------------*/
01288 PyDoc_STRVAR(Matrix_copy_doc,
01289 ".. method:: copy()\n"
01290 "\n"
01291 "   Returns a copy of this matrix.\n"
01292 "\n"
01293 "   :return: an instance of itself\n"
01294 "   :rtype: :class:`Matrix`\n"
01295 );
01296 static PyObject *Matrix_copy(MatrixObject *self)
01297 {
01298         if(BaseMath_ReadCallback(self) == -1)
01299                 return NULL;
01300 
01301         return (PyObject*)newMatrixObject((float (*))self->contigPtr, self->row_size, self->col_size, Py_NEW, Py_TYPE(self));
01302 }
01303 
01304 /*----------------------------print object (internal)-------------*/
01305 /*print the object to screen*/
01306 static PyObject *Matrix_repr(MatrixObject *self)
01307 {
01308         int x, y;
01309         PyObject *rows[MATRIX_MAX_DIM]= {NULL};
01310 
01311         if(BaseMath_ReadCallback(self) == -1)
01312                 return NULL;
01313 
01314         for(x = 0; x < self->row_size; x++){
01315                 rows[x]= PyTuple_New(self->col_size);
01316                 for(y = 0; y < self->col_size; y++) {
01317                         PyTuple_SET_ITEM(rows[x], y, PyFloat_FromDouble(self->matrix[x][y]));
01318                 }
01319         }
01320         switch(self->row_size) {
01321         case 2: return PyUnicode_FromFormat("Matrix((%R,\n"
01322                                                                                 "        %R))", rows[0], rows[1]);
01323 
01324         case 3: return PyUnicode_FromFormat("Matrix((%R,\n"
01325                                                                                 "        %R,\n"
01326                                                                                 "        %R))", rows[0], rows[1], rows[2]);
01327 
01328         case 4: return PyUnicode_FromFormat("Matrix((%R,\n"
01329                                                                                 "        %R,\n"
01330                                                                                 "        %R,\n"
01331                                                                                 "        %R))", rows[0], rows[1], rows[2], rows[3]);
01332         }
01333 
01334         Py_FatalError("Matrix(): invalid row size!");
01335         return NULL;
01336 }
01337 
01338 static PyObject* Matrix_richcmpr(PyObject *a, PyObject *b, int op)
01339 {
01340         PyObject *res;
01341         int ok= -1; /* zero is true */
01342 
01343         if (MatrixObject_Check(a) && MatrixObject_Check(b)) {
01344                 MatrixObject *matA= (MatrixObject*)a;
01345                 MatrixObject *matB= (MatrixObject*)b;
01346 
01347                 if(BaseMath_ReadCallback(matA) == -1 || BaseMath_ReadCallback(matB) == -1)
01348                         return NULL;
01349 
01350                 ok=     (       (matA->col_size == matB->col_size) &&
01351                                 (matA->row_size == matB->row_size) &&
01352                                 EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr, (matA->row_size * matA->col_size), 1)
01353                         ) ? 0 : -1;
01354         }
01355 
01356         switch (op) {
01357         case Py_NE:
01358                 ok = !ok; /* pass through */
01359         case Py_EQ:
01360                 res = ok ? Py_False : Py_True;
01361                 break;
01362 
01363         case Py_LT:
01364         case Py_LE:
01365         case Py_GT:
01366         case Py_GE:
01367                 res = Py_NotImplemented;
01368                 break;
01369         default:
01370                 PyErr_BadArgument();
01371                 return NULL;
01372         }
01373 
01374         return Py_INCREF(res), res;
01375 }
01376 
01377 /*---------------------SEQUENCE PROTOCOLS------------------------
01378   ----------------------------len(object)------------------------
01379   sequence length*/
01380 static int Matrix_len(MatrixObject *self)
01381 {
01382         return (self->row_size);
01383 }
01384 /*----------------------------object[]---------------------------
01385   sequence accessor (get)
01386   the wrapped vector gives direct access to the matrix data*/
01387 static PyObject *Matrix_item(MatrixObject *self, int i)
01388 {
01389         if(BaseMath_ReadCallback(self) == -1)
01390                 return NULL;
01391 
01392         if(i < 0 || i >= self->row_size) {
01393                 PyErr_SetString(PyExc_IndexError,
01394                                 "matrix[attribute]: "
01395                                 "array index out of range");
01396                 return NULL;
01397         }
01398         return newVectorObject_cb((PyObject *)self, self->col_size, mathutils_matrix_vector_cb_index, i);
01399 }
01400 /*----------------------------object[]-------------------------
01401   sequence accessor (set) */
01402 
01403 static int Matrix_ass_item(MatrixObject *self, int i, PyObject *value)
01404 {
01405         float vec[4];
01406         if(BaseMath_ReadCallback(self) == -1)
01407                 return -1;
01408 
01409         if(i >= self->row_size || i < 0){
01410                 PyErr_SetString(PyExc_IndexError,
01411                                 "matrix[attribute] = x: bad column");
01412                 return -1;
01413         }
01414 
01415         if(mathutils_array_parse(vec, self->col_size, self->col_size, value, "matrix[i] = value assignment") < 0) {
01416                 return -1;
01417         }
01418 
01419         memcpy(self->matrix[i], vec, self->col_size *sizeof(float));
01420 
01421         (void)BaseMath_WriteCallback(self);
01422         return 0;
01423 }
01424 
01425 /*----------------------------object[z:y]------------------------
01426   sequence slice (get)*/
01427 static PyObject *Matrix_slice(MatrixObject *self, int begin, int end)
01428 {
01429 
01430         PyObject *tuple;
01431         int count;
01432 
01433         if(BaseMath_ReadCallback(self) == -1)
01434                 return NULL;
01435 
01436         CLAMP(begin, 0, self->row_size);
01437         CLAMP(end, 0, self->row_size);
01438         begin= MIN2(begin, end);
01439 
01440         tuple= PyTuple_New(end - begin);
01441         for(count= begin; count < end; count++) {
01442                 PyTuple_SET_ITEM(tuple, count - begin,
01443                                 newVectorObject_cb((PyObject *)self, self->col_size, mathutils_matrix_vector_cb_index, count));
01444 
01445         }
01446 
01447         return tuple;
01448 }
01449 /*----------------------------object[z:y]------------------------
01450   sequence slice (set)*/
01451 static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value)
01452 {
01453         PyObject *value_fast= NULL;
01454 
01455         if(BaseMath_ReadCallback(self) == -1)
01456                 return -1;
01457 
01458         CLAMP(begin, 0, self->row_size);
01459         CLAMP(end, 0, self->row_size);
01460         begin = MIN2(begin, end);
01461 
01462         /* non list/tuple cases */
01463         if(!(value_fast=PySequence_Fast(value, "matrix[begin:end] = value"))) {
01464                 /* PySequence_Fast sets the error */
01465                 return -1;
01466         }
01467         else {
01468                 const int size= end - begin;
01469                 int i;
01470                 float mat[16];
01471 
01472                 if(PySequence_Fast_GET_SIZE(value_fast) != size) {
01473                         Py_DECREF(value_fast);
01474                         PyErr_SetString(PyExc_ValueError,
01475                                         "matrix[begin:end] = []: "
01476                                         "size mismatch in slice assignment");
01477                         return -1;
01478                 }
01479 
01480                 /*parse sub items*/
01481                 for (i = 0; i < size; i++) {
01482                         /*parse each sub sequence*/
01483                         PyObject *item= PySequence_Fast_GET_ITEM(value_fast, i);
01484 
01485                         if(mathutils_array_parse(&mat[i * self->col_size], self->col_size, self->col_size, item, "matrix[begin:end] = value assignment") < 0) {
01486                                 return -1;
01487                         }
01488                 }
01489 
01490                 Py_DECREF(value_fast);
01491 
01492                 /*parsed well - now set in matrix*/
01493                 memcpy(self->contigPtr + (begin * self->col_size), mat, sizeof(float) * (size * self->col_size));
01494 
01495                 (void)BaseMath_WriteCallback(self);
01496                 return 0;
01497         }
01498 }
01499 /*------------------------NUMERIC PROTOCOLS----------------------
01500   ------------------------obj + obj------------------------------*/
01501 static PyObject *Matrix_add(PyObject *m1, PyObject *m2)
01502 {
01503         float mat[16];
01504         MatrixObject *mat1 = NULL, *mat2 = NULL;
01505 
01506         mat1 = (MatrixObject*)m1;
01507         mat2 = (MatrixObject*)m2;
01508 
01509         if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
01510                 PyErr_SetString(PyExc_TypeError,
01511                                 "Matrix addition: "
01512                                 "arguments not valid for this operation");
01513                 return NULL;
01514         }
01515 
01516         if(BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1)
01517                 return NULL;
01518 
01519         if(mat1->row_size != mat2->row_size || mat1->col_size != mat2->col_size){
01520                 PyErr_SetString(PyExc_TypeError,
01521                                 "Matrix addition: "
01522                                 "matrices must have the same dimensions for this operation");
01523                 return NULL;
01524         }
01525 
01526         add_vn_vnvn(mat, mat1->contigPtr, mat2->contigPtr, mat1->row_size * mat1->col_size);
01527 
01528         return newMatrixObject(mat, mat1->row_size, mat1->col_size, Py_NEW, Py_TYPE(mat1));
01529 }
01530 /*------------------------obj - obj------------------------------
01531   subtraction*/
01532 static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
01533 {
01534         float mat[16];
01535         MatrixObject *mat1 = NULL, *mat2 = NULL;
01536 
01537         mat1 = (MatrixObject*)m1;
01538         mat2 = (MatrixObject*)m2;
01539 
01540         if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
01541                 PyErr_SetString(PyExc_TypeError,
01542                                 "Matrix addition: "
01543                                 "arguments not valid for this operation");
01544                 return NULL;
01545         }
01546 
01547         if(BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1)
01548                 return NULL;
01549 
01550         if(mat1->row_size != mat2->row_size || mat1->col_size != mat2->col_size){
01551                 PyErr_SetString(PyExc_TypeError,
01552                                 "Matrix addition: "
01553                                 "matrices must have the same dimensions for this operation");
01554                 return NULL;
01555         }
01556 
01557         sub_vn_vnvn(mat, mat1->contigPtr, mat2->contigPtr, mat1->row_size * mat1->col_size);
01558 
01559         return newMatrixObject(mat, mat1->row_size, mat1->col_size, Py_NEW, Py_TYPE(mat1));
01560 }
01561 /*------------------------obj * obj------------------------------
01562   mulplication*/
01563 static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
01564 {
01565         float tmat[16];
01566         mul_vn_vn_fl(tmat, mat->contigPtr, mat->row_size * mat->col_size, scalar);
01567         return newMatrixObject(tmat, mat->row_size, mat->col_size, Py_NEW, Py_TYPE(mat));
01568 }
01569 
01570 static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
01571 {
01572         float scalar;
01573 
01574         MatrixObject *mat1 = NULL, *mat2 = NULL;
01575 
01576         if(MatrixObject_Check(m1)) {
01577                 mat1 = (MatrixObject*)m1;
01578                 if(BaseMath_ReadCallback(mat1) == -1)
01579                         return NULL;
01580         }
01581         if(MatrixObject_Check(m2)) {
01582                 mat2 = (MatrixObject*)m2;
01583                 if(BaseMath_ReadCallback(mat2) == -1)
01584                         return NULL;
01585         }
01586 
01587         if(mat1 && mat2) {
01588                 /*MATRIX * MATRIX*/
01589                 float mat[16]= {0.0f, 0.0f, 0.0f, 0.0f,
01590                                                 0.0f, 0.0f, 0.0f, 0.0f,
01591                                                 0.0f, 0.0f, 0.0f, 0.0f,
01592                                                 0.0f, 0.0f, 0.0f, 1.0f};
01593                 double dot = 0.0f;
01594                 int x, y, z;
01595 
01596                 for(x = 0; x < mat2->row_size; x++) {
01597                         for(y = 0; y < mat1->col_size; y++) {
01598                                 for(z = 0; z < mat1->row_size; z++) {
01599                                         dot += (mat1->matrix[z][y] * mat2->matrix[x][z]);
01600                                 }
01601                                 mat[((x * mat1->col_size) + y)] = (float)dot;
01602                                 dot = 0.0f;
01603                         }
01604                 }
01605 
01606                 return newMatrixObject(mat, mat2->row_size, mat1->col_size, Py_NEW, Py_TYPE(mat1));
01607         }
01608         else if(mat2) {
01609                 /*FLOAT/INT * MATRIX */
01610                 if (((scalar= PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred())==0) {
01611                         return matrix_mul_float(mat2, scalar);
01612                 }
01613         }
01614         else if(mat1) {
01615                 /*VEC * MATRIX */
01616                 if(VectorObject_Check(m2)) {
01617                         VectorObject *vec2= (VectorObject *)m2;
01618                         float tvec[4];
01619                         if(BaseMath_ReadCallback(vec2) == -1)
01620                                 return NULL;
01621                         if(column_vector_multiplication(tvec, vec2, mat1) == -1) {
01622                                 return NULL;
01623                         }
01624 
01625                         return newVectorObject(tvec, vec2->size, Py_NEW, Py_TYPE(m2));
01626                 }
01627                 /*FLOAT/INT * MATRIX */
01628                 else if (((scalar= PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred())==0) {
01629                         return matrix_mul_float(mat1, scalar);
01630                 }
01631         }
01632         else {
01633                 BLI_assert(!"internal error");
01634         }
01635 
01636         PyErr_Format(PyExc_TypeError,
01637                      "Matrix multiplication: "
01638                      "not supported between '%.200s' and '%.200s' types",
01639                      Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
01640         return NULL;
01641 }
01642 static PyObject* Matrix_inv(MatrixObject *self)
01643 {
01644         if(BaseMath_ReadCallback(self) == -1)
01645                 return NULL;
01646 
01647         return Matrix_invert(self);
01648 }
01649 
01650 /*-----------------PROTOCOL DECLARATIONS--------------------------*/
01651 static PySequenceMethods Matrix_SeqMethods = {
01652         (lenfunc) Matrix_len,                                           /* sq_length */
01653         (binaryfunc) NULL,                                                      /* sq_concat */
01654         (ssizeargfunc) NULL,                                            /* sq_repeat */
01655         (ssizeargfunc) Matrix_item,                                     /* sq_item */
01656         (ssizessizeargfunc) NULL,                                       /* sq_slice, deprecated */
01657         (ssizeobjargproc) Matrix_ass_item,                      /* sq_ass_item */
01658         (ssizessizeobjargproc) NULL,                            /* sq_ass_slice, deprecated */
01659         (objobjproc) NULL,                                                      /* sq_contains */
01660         (binaryfunc) NULL,                                                      /* sq_inplace_concat */
01661         (ssizeargfunc) NULL,                                            /* sq_inplace_repeat */
01662 };
01663 
01664 
01665 static PyObject *Matrix_subscript(MatrixObject* self, PyObject* item)
01666 {
01667         if (PyIndex_Check(item)) {
01668                 Py_ssize_t i;
01669                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
01670                 if (i == -1 && PyErr_Occurred())
01671                         return NULL;
01672                 if (i < 0)
01673                         i += self->row_size;
01674                 return Matrix_item(self, i);
01675         } else if (PySlice_Check(item)) {
01676                 Py_ssize_t start, stop, step, slicelength;
01677 
01678                 if (PySlice_GetIndicesEx((void *)item, self->row_size, &start, &stop, &step, &slicelength) < 0)
01679                         return NULL;
01680 
01681                 if (slicelength <= 0) {
01682                         return PyTuple_New(0);
01683                 }
01684                 else if (step == 1) {
01685                         return Matrix_slice(self, start, stop);
01686                 }
01687                 else {
01688                         PyErr_SetString(PyExc_IndexError,
01689                                         "slice steps not supported with matricies");
01690                         return NULL;
01691                 }
01692         }
01693         else {
01694                 PyErr_Format(PyExc_TypeError,
01695                              "matrix indices must be integers, not %.200s",
01696                              Py_TYPE(item)->tp_name);
01697                 return NULL;
01698         }
01699 }
01700 
01701 static int Matrix_ass_subscript(MatrixObject* self, PyObject* item, PyObject* value)
01702 {
01703         if (PyIndex_Check(item)) {
01704                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
01705                 if (i == -1 && PyErr_Occurred())
01706                         return -1;
01707                 if (i < 0)
01708                         i += self->row_size;
01709                 return Matrix_ass_item(self, i, value);
01710         }
01711         else if (PySlice_Check(item)) {
01712                 Py_ssize_t start, stop, step, slicelength;
01713 
01714                 if (PySlice_GetIndicesEx((void *)item, self->row_size, &start, &stop, &step, &slicelength) < 0)
01715                         return -1;
01716 
01717                 if (step == 1)
01718                         return Matrix_ass_slice(self, start, stop, value);
01719                 else {
01720                         PyErr_SetString(PyExc_IndexError,
01721                                         "slice steps not supported with matricies");
01722                         return -1;
01723                 }
01724         }
01725         else {
01726                 PyErr_Format(PyExc_TypeError,
01727                              "matrix indices must be integers, not %.200s",
01728                              Py_TYPE(item)->tp_name);
01729                 return -1;
01730         }
01731 }
01732 
01733 static PyMappingMethods Matrix_AsMapping = {
01734         (lenfunc)Matrix_len,
01735         (binaryfunc)Matrix_subscript,
01736         (objobjargproc)Matrix_ass_subscript
01737 };
01738 
01739 
01740 static PyNumberMethods Matrix_NumMethods = {
01741                 (binaryfunc)    Matrix_add,     /*nb_add*/
01742                 (binaryfunc)    Matrix_sub,     /*nb_subtract*/
01743                 (binaryfunc)    Matrix_mul,     /*nb_multiply*/
01744                 NULL,                                                   /*nb_remainder*/
01745                 NULL,                                                   /*nb_divmod*/
01746                 NULL,                                                   /*nb_power*/
01747                 (unaryfunc)     0,      /*nb_negative*/
01748                 (unaryfunc)     0,      /*tp_positive*/
01749                 (unaryfunc)     0,      /*tp_absolute*/
01750                 (inquiry)       0,      /*tp_bool*/
01751                 (unaryfunc)     Matrix_inv,     /*nb_invert*/
01752                 NULL,                           /*nb_lshift*/
01753                 (binaryfunc)0,  /*nb_rshift*/
01754                 NULL,                           /*nb_and*/
01755                 NULL,                           /*nb_xor*/
01756                 NULL,                           /*nb_or*/
01757                 NULL,                           /*nb_int*/
01758                 NULL,                           /*nb_reserved*/
01759                 NULL,                           /*nb_float*/
01760                 NULL,                           /* nb_inplace_add */
01761                 NULL,                           /* nb_inplace_subtract */
01762                 NULL,                           /* nb_inplace_multiply */
01763                 NULL,                           /* nb_inplace_remainder */
01764                 NULL,                           /* nb_inplace_power */
01765                 NULL,                           /* nb_inplace_lshift */
01766                 NULL,                           /* nb_inplace_rshift */
01767                 NULL,                           /* nb_inplace_and */
01768                 NULL,                           /* nb_inplace_xor */
01769                 NULL,                           /* nb_inplace_or */
01770                 NULL,                           /* nb_floor_divide */
01771                 NULL,                           /* nb_true_divide */
01772                 NULL,                           /* nb_inplace_floor_divide */
01773                 NULL,                           /* nb_inplace_true_divide */
01774                 NULL,                           /* nb_index */
01775 };
01776 
01777 static PyObject *Matrix_getRowSize(MatrixObject *self, void *UNUSED(closure))
01778 {
01779         return PyLong_FromLong((long) self->row_size);
01780 }
01781 
01782 static PyObject *Matrix_getColSize(MatrixObject *self, void *UNUSED(closure))
01783 {
01784         return PyLong_FromLong((long) self->col_size);
01785 }
01786 
01787 static PyObject *Matrix_median_scale_get(MatrixObject *self, void *UNUSED(closure))
01788 {
01789         float mat[3][3];
01790 
01791         if(BaseMath_ReadCallback(self) == -1)
01792                 return NULL;
01793 
01794         /*must be 3-4 cols, 3-4 rows, square matrix*/
01795         if((self->col_size < 3) || (self->row_size < 3)) {
01796                 PyErr_SetString(PyExc_AttributeError,
01797                                 "matrix.median_scale: "
01798                                 "inappropriate matrix size, 3x3 minimum");
01799                 return NULL;
01800         }
01801 
01802         matrix_as_3x3(mat, self);
01803 
01804         return PyFloat_FromDouble(mat3_to_scale(mat));
01805 }
01806 
01807 static PyObject *Matrix_is_negative_get(MatrixObject *self, void *UNUSED(closure))
01808 {
01809         if(BaseMath_ReadCallback(self) == -1)
01810                 return NULL;
01811 
01812         /*must be 3-4 cols, 3-4 rows, square matrix*/
01813         if(self->col_size == 4 && self->row_size == 4)
01814                 return PyBool_FromLong(is_negative_m4((float (*)[4])self->contigPtr));
01815         else if(self->col_size == 3 && self->row_size == 3)
01816                 return PyBool_FromLong(is_negative_m3((float (*)[3])self->contigPtr));
01817         else {
01818                 PyErr_SetString(PyExc_AttributeError,
01819                                 "matrix.is_negative: "
01820                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
01821                 return NULL;
01822         }
01823 }
01824 
01825 static PyObject *Matrix_is_orthogonal_get(MatrixObject *self, void *UNUSED(closure))
01826 {
01827         if(BaseMath_ReadCallback(self) == -1)
01828                 return NULL;
01829 
01830         /*must be 3-4 cols, 3-4 rows, square matrix*/
01831         if(self->col_size == 4 && self->row_size == 4)
01832                 return PyBool_FromLong(is_orthogonal_m4((float (*)[4])self->contigPtr));
01833         else if(self->col_size == 3 && self->row_size == 3)
01834                 return PyBool_FromLong(is_orthogonal_m3((float (*)[3])self->contigPtr));
01835         else {
01836                 PyErr_SetString(PyExc_AttributeError,
01837                                 "matrix.is_orthogonal: "
01838                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
01839                 return NULL;
01840         }
01841 }
01842 
01843 /*****************************************************************************/
01844 /* Python attributes get/set structure:                                      */
01845 /*****************************************************************************/
01846 static PyGetSetDef Matrix_getseters[] = {
01847         {(char *)"row_size", (getter)Matrix_getRowSize, (setter)NULL, (char *)"The row size of the matrix (readonly).\n\n:type: int", NULL},
01848         {(char *)"col_size", (getter)Matrix_getColSize, (setter)NULL, (char *)"The column size of the matrix (readonly).\n\n:type: int", NULL},
01849         {(char *)"median_scale", (getter)Matrix_median_scale_get, (setter)NULL, (char *)"The average scale applied to each axis (readonly).\n\n:type: float", NULL},
01850         {(char *)"is_negative", (getter)Matrix_is_negative_get, (setter)NULL, (char *)"True if this matrix results in a negative scale, 3x3 and 4x4 only, (readonly).\n\n:type: bool", NULL},
01851         {(char *)"is_orthogonal", (getter)Matrix_is_orthogonal_get, (setter)NULL, (char *)"True if this matrix is orthogonal, 3x3 and 4x4 only, (readonly).\n\n:type: bool", NULL},
01852         {(char *)"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, (char *)BaseMathObject_Wrapped_doc, NULL},
01853         {(char *)"owner",(getter)BaseMathObject_getOwner, (setter)NULL, (char *)BaseMathObject_Owner_doc, NULL},
01854         {NULL, NULL, NULL, NULL, NULL}  /* Sentinel */
01855 };
01856 
01857 /*-----------------------METHOD DEFINITIONS ----------------------*/
01858 static struct PyMethodDef Matrix_methods[] = {
01859         /* derived values */
01860         {"determinant", (PyCFunction) Matrix_determinant, METH_NOARGS, Matrix_determinant_doc},
01861         {"decompose", (PyCFunction) Matrix_decompose, METH_NOARGS, Matrix_decompose_doc},
01862 
01863         /* in place only */
01864         {"zero", (PyCFunction) Matrix_zero, METH_NOARGS, Matrix_zero_doc},
01865         {"identity", (PyCFunction) Matrix_identity, METH_NOARGS, Matrix_identity_doc},
01866 
01867         /* operate on original or copy */
01868         {"transpose", (PyCFunction) Matrix_transpose, METH_NOARGS, Matrix_transpose_doc},
01869         {"transposed", (PyCFunction) Matrix_transposed, METH_NOARGS, Matrix_transposed_doc},
01870         {"invert", (PyCFunction) Matrix_invert, METH_NOARGS, Matrix_invert_doc},
01871         {"inverted", (PyCFunction) Matrix_inverted, METH_NOARGS, Matrix_inverted_doc},
01872         {"to_3x3", (PyCFunction) Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc},
01873         // TODO. {"resize_3x3", (PyCFunction) Matrix_resize3x3, METH_NOARGS, Matrix_resize3x3_doc},
01874         {"to_4x4", (PyCFunction) Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc},
01875         {"resize_4x4", (PyCFunction) Matrix_resize_4x4, METH_NOARGS, Matrix_resize_4x4_doc},
01876         {"rotate", (PyCFunction) Matrix_rotate, METH_O, Matrix_rotate_doc},
01877 
01878         /* return converted representation */
01879         {"to_euler", (PyCFunction) Matrix_to_euler, METH_VARARGS, Matrix_to_euler_doc},
01880         {"to_quaternion", (PyCFunction) Matrix_to_quaternion, METH_NOARGS, Matrix_to_quaternion_doc},
01881         {"to_scale", (PyCFunction) Matrix_to_scale, METH_NOARGS, Matrix_to_scale_doc},
01882         {"to_translation", (PyCFunction) Matrix_to_translation, METH_NOARGS, Matrix_to_translation_doc},
01883 
01884         /* operation between 2 or more types  */
01885         {"lerp", (PyCFunction) Matrix_lerp, METH_VARARGS, Matrix_lerp_doc},
01886         {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
01887         {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
01888 
01889         /* class methods */
01890         {"Rotation", (PyCFunction) C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc},
01891         {"Scale", (PyCFunction) C_Matrix_Scale, METH_VARARGS | METH_CLASS, C_Matrix_Scale_doc},
01892         {"Shear", (PyCFunction) C_Matrix_Shear, METH_VARARGS | METH_CLASS, C_Matrix_Shear_doc},
01893         {"Translation", (PyCFunction) C_Matrix_Translation, METH_O | METH_CLASS, C_Matrix_Translation_doc},
01894         {"OrthoProjection", (PyCFunction) C_Matrix_OrthoProjection,  METH_VARARGS | METH_CLASS, C_Matrix_OrthoProjection_doc},
01895         {NULL, NULL, 0, NULL}
01896 };
01897 
01898 /*------------------PY_OBECT DEFINITION--------------------------*/
01899 PyDoc_STRVAR(matrix_doc,
01900 "This object gives access to Matrices in Blender."
01901 );
01902 PyTypeObject matrix_Type = {
01903         PyVarObject_HEAD_INIT(NULL, 0)
01904         "mathutils.Matrix",                                     /*tp_name*/
01905         sizeof(MatrixObject),                           /*tp_basicsize*/
01906         0,                                                                      /*tp_itemsize*/
01907         (destructor)BaseMathObject_dealloc,     /*tp_dealloc*/
01908         NULL,                                                           /*tp_print*/
01909         NULL,                                                           /*tp_getattr*/
01910         NULL,                                                           /*tp_setattr*/
01911         NULL,                                                           /*tp_compare*/
01912         (reprfunc) Matrix_repr,                         /*tp_repr*/
01913         &Matrix_NumMethods,                                     /*tp_as_number*/
01914         &Matrix_SeqMethods,                                     /*tp_as_sequence*/
01915         &Matrix_AsMapping,                                      /*tp_as_mapping*/
01916         NULL,                                                           /*tp_hash*/
01917         NULL,                                                           /*tp_call*/
01918         NULL,                                                           /*tp_str*/
01919         NULL,                                                           /*tp_getattro*/
01920         NULL,                                                           /*tp_setattro*/
01921         NULL,                                                           /*tp_as_buffer*/
01922         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
01923         matrix_doc,                                                     /*tp_doc*/
01924         (traverseproc)BaseMathObject_traverse,  //tp_traverse
01925         (inquiry)BaseMathObject_clear,  //tp_clear
01926         (richcmpfunc)Matrix_richcmpr,           /*tp_richcompare*/
01927         0,                                                                      /*tp_weaklistoffset*/
01928         NULL,                                                           /*tp_iter*/
01929         NULL,                                                           /*tp_iternext*/
01930         Matrix_methods,                                         /*tp_methods*/
01931         NULL,                                                           /*tp_members*/
01932         Matrix_getseters,                                       /*tp_getset*/
01933         NULL,                                                           /*tp_base*/
01934         NULL,                                                           /*tp_dict*/
01935         NULL,                                                           /*tp_descr_get*/
01936         NULL,                                                           /*tp_descr_set*/
01937         0,                                                                      /*tp_dictoffset*/
01938         NULL,                                                           /*tp_init*/
01939         NULL,                                                           /*tp_alloc*/
01940         Matrix_new,                                                     /*tp_new*/
01941         NULL,                                                           /*tp_free*/
01942         NULL,                                                           /*tp_is_gc*/
01943         NULL,                                                           /*tp_bases*/
01944         NULL,                                                           /*tp_mro*/
01945         NULL,                                                           /*tp_cache*/
01946         NULL,                                                           /*tp_subclasses*/
01947         NULL,                                                           /*tp_weaklist*/
01948         NULL                                                            /*tp_del*/
01949 };
01950 
01951 /*------------------------newMatrixObject (internal)-------------
01952 creates a new matrix object
01953 self->matrix     self->contiguous_ptr (reference to data.xxx)
01954            [0]------------->[0]
01955                                                 [1]
01956                                                 [2]
01957            [1]------------->[3]
01958                                                 [4]
01959                                                 [5]
01960 
01961 self->matrix[1][1] = self->contigPtr[4] */
01962 
01963 /*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
01964  (i.e. it was allocated elsewhere by MEM_mallocN())
01965   pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
01966  (i.e. it must be created here with PyMEM_malloc())*/
01967 PyObject *newMatrixObject(float *mat, const unsigned short rowSize, const unsigned short colSize, int type, PyTypeObject *base_type)
01968 {
01969         MatrixObject *self;
01970         int x, row, col;
01971 
01972         /*matrix objects can be any 2-4row x 2-4col matrix*/
01973         if(rowSize < 2 || rowSize > 4 || colSize < 2 || colSize > 4) {
01974                 PyErr_SetString(PyExc_RuntimeError,
01975                                 "Matrix(): "
01976                                 "row and column sizes must be between 2 and 4");
01977                 return NULL;
01978         }
01979 
01980         self= base_type ?       (MatrixObject *)base_type->tp_alloc(base_type, 0) :
01981                                                 (MatrixObject *)PyObject_GC_New(MatrixObject, &matrix_Type);
01982 
01983         if(self) {
01984                 self->row_size = rowSize;
01985                 self->col_size = colSize;
01986 
01987                 /* init callbacks as NULL */
01988                 self->cb_user= NULL;
01989                 self->cb_type= self->cb_subtype= 0;
01990 
01991                 if(type == Py_WRAP){
01992                         self->contigPtr = mat;
01993                         /*pointer array points to contigous memory*/
01994                         for(x = 0; x < rowSize; x++) {
01995                                 self->matrix[x] = self->contigPtr + (x * colSize);
01996                         }
01997                         self->wrapped = Py_WRAP;
01998                 }
01999                 else if (type == Py_NEW){
02000                         self->contigPtr = PyMem_Malloc(rowSize * colSize * sizeof(float));
02001                         if(self->contigPtr == NULL) { /*allocation failure*/
02002                                 PyErr_SetString(PyExc_MemoryError,
02003                                                 "Matrix(): "
02004                                                 "problem allocating pointer space");
02005                                 return NULL;
02006                         }
02007                         /*pointer array points to contigous memory*/
02008                         for(x = 0; x < rowSize; x++) {
02009                                 self->matrix[x] = self->contigPtr + (x * colSize);
02010                         }
02011                         /*parse*/
02012                         if(mat) {       /*if a float array passed*/
02013                                 for(row = 0; row < rowSize; row++) {
02014                                         for(col = 0; col < colSize; col++) {
02015                                                 self->matrix[row][col] = mat[(row * colSize) + col];
02016                                         }
02017                                 }
02018                         }
02019                         else if (rowSize == colSize) { /*or if no arguments are passed return identity matrix for square matrices */
02020                                 PyObject *ret_dummy= Matrix_identity(self);
02021                                 Py_DECREF(ret_dummy);
02022                         }
02023                         self->wrapped = Py_NEW;
02024                 }
02025                 else {
02026                         Py_FatalError("Matrix(): invalid type!");
02027                         return NULL;
02028                 }
02029         }
02030         return (PyObject *) self;
02031 }
02032 
02033 PyObject *newMatrixObject_cb(PyObject *cb_user, int rowSize, int colSize, int cb_type, int cb_subtype)
02034 {
02035         MatrixObject *self= (MatrixObject *)newMatrixObject(NULL, rowSize, colSize, Py_NEW, NULL);
02036         if(self) {
02037                 Py_INCREF(cb_user);
02038                 self->cb_user=                  cb_user;
02039                 self->cb_type=                  (unsigned char)cb_type;
02040                 self->cb_subtype=               (unsigned char)cb_subtype;
02041                 PyObject_GC_Track(self);
02042         }
02043         return (PyObject *) self;
02044 }