7e881fd5dda2df534800b3475033082a07feacdf
[blender.git] / source / blender / python / mathutils / mathutils_Matrix.c
1 /*
2  *
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * Contributor(s): Michel Selten & Joseph Gilbert
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/python/mathutils/mathutils_Matrix.c
28  *  \ingroup pymathutils
29  */
30
31
32 #include <Python.h>
33
34 #include "mathutils.h"
35
36 #include "BLI_math.h"
37 #include "BLI_utildefines.h"
38 #include "BLI_string.h"
39 #include "BLI_dynstr.h"
40
41 typedef enum eMatrixAccess_t {
42         MAT_ACCESS_ROW,
43         MAT_ACCESS_COL
44 } eMatrixAccess_t;
45
46 static PyObject *Matrix_copy(MatrixObject *self);
47 static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value);
48 static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self);
49 static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type);
50
51 /* matrix row callbacks */
52 int mathutils_matrix_row_cb_index = -1;
53
54 static int mathutils_matrix_vector_check(BaseMathObject *bmo)
55 {
56         MatrixObject *self = (MatrixObject *)bmo->cb_user;
57         return BaseMath_ReadCallback(self);
58 }
59
60 static int mathutils_matrix_vector_get(BaseMathObject *bmo, int row)
61 {
62         MatrixObject *self = (MatrixObject *)bmo->cb_user;
63         int col;
64
65         if (BaseMath_ReadCallback(self) == -1)
66                 return -1;
67
68         for (col = 0; col < self->num_col; col++) {
69                 bmo->data[col] = MATRIX_ITEM(self, row, col);
70         }
71
72         return 0;
73 }
74
75 static int mathutils_matrix_vector_set(BaseMathObject *bmo, int row)
76 {
77         MatrixObject *self = (MatrixObject *)bmo->cb_user;
78         int col;
79
80         if (BaseMath_ReadCallback(self) == -1)
81                 return -1;
82
83         for (col = 0; col < self->num_col; col++) {
84                 MATRIX_ITEM(self, row, col) = bmo->data[col];
85         }
86
87         (void)BaseMath_WriteCallback(self);
88         return 0;
89 }
90
91 static int mathutils_matrix_vector_get_index(BaseMathObject *bmo, int row, int col)
92 {
93         MatrixObject *self = (MatrixObject *)bmo->cb_user;
94
95         if (BaseMath_ReadCallback(self) == -1)
96                 return -1;
97
98         bmo->data[col] = MATRIX_ITEM(self, row, col);
99         return 0;
100 }
101
102 static int mathutils_matrix_vector_set_index(BaseMathObject *bmo, int row, int col)
103 {
104         MatrixObject *self = (MatrixObject *)bmo->cb_user;
105
106         if (BaseMath_ReadCallback(self) == -1)
107                 return -1;
108
109         MATRIX_ITEM(self, row, col) = bmo->data[col];
110
111         (void)BaseMath_WriteCallback(self);
112         return 0;
113 }
114
115 Mathutils_Callback mathutils_matrix_row_cb = {
116         mathutils_matrix_vector_check,
117         mathutils_matrix_vector_get,
118         mathutils_matrix_vector_set,
119         mathutils_matrix_vector_get_index,
120         mathutils_matrix_vector_set_index
121 };
122 /* matrix vector callbacks, this is so you can do matrix[i][j] = val  */
123
124 /* matrix row callbacks */
125 int mathutils_matrix_col_cb_index = -1;
126
127 static int mathutils_matrix_column_check(BaseMathObject *bmo)
128 {
129         MatrixObject *self = (MatrixObject *)bmo->cb_user;
130         return BaseMath_ReadCallback(self);
131 }
132
133 static int mathutils_matrix_column_get(BaseMathObject *bmo, int col)
134 {
135         MatrixObject *self = (MatrixObject *)bmo->cb_user;
136         int num_row;
137         int row;
138
139         if (BaseMath_ReadCallback(self) == -1)
140                 return -1;
141
142         /* for 'translation' size will always be '3' even on 4x4 vec */
143         num_row = MIN2(self->num_row, ((VectorObject *)bmo)->size);
144
145         for (row = 0; row < num_row; row++) {
146                 bmo->data[row] = MATRIX_ITEM(self, row, col);
147         }
148
149         return 0;
150 }
151
152 static int mathutils_matrix_column_set(BaseMathObject *bmo, int col)
153 {
154         MatrixObject *self = (MatrixObject *)bmo->cb_user;
155         int num_row;
156         int row;
157
158         if (BaseMath_ReadCallback(self) == -1)
159                 return -1;
160
161         /* for 'translation' size will always be '3' even on 4x4 vec */
162         num_row = MIN2(self->num_row, ((VectorObject *)bmo)->size);
163
164         for (row = 0; row < num_row; row++) {
165                 MATRIX_ITEM(self, row, col) = bmo->data[row];
166         }
167
168         (void)BaseMath_WriteCallback(self);
169         return 0;
170 }
171
172 static int mathutils_matrix_column_get_index(BaseMathObject *bmo, int col, int row)
173 {
174         MatrixObject *self = (MatrixObject *)bmo->cb_user;
175
176         if (BaseMath_ReadCallback(self) == -1)
177                 return -1;
178
179         bmo->data[row] = MATRIX_ITEM(self, row, col);
180         return 0;
181 }
182
183 static int mathutils_matrix_column_set_index(BaseMathObject *bmo, int col, int row)
184 {
185         MatrixObject *self = (MatrixObject *)bmo->cb_user;
186
187         if (BaseMath_ReadCallback(self) == -1)
188                 return -1;
189
190         MATRIX_ITEM(self, row, col) = bmo->data[row];
191
192         (void)BaseMath_WriteCallback(self);
193         return 0;
194 }
195
196 Mathutils_Callback mathutils_matrix_col_cb = {
197         mathutils_matrix_column_check,
198         mathutils_matrix_column_get,
199         mathutils_matrix_column_set,
200         mathutils_matrix_column_get_index,
201         mathutils_matrix_column_set_index
202 };
203 /* matrix column callbacks, this is so you can do matrix.translation = Vector()  */
204
205 //----------------------------------mathutils.Matrix() -----------------
206 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc.
207 //create a new matrix type
208 static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
209 {
210         if (kwds && PyDict_Size(kwds)) {
211                 PyErr_SetString(PyExc_TypeError,
212                                 "Matrix(): "
213                                 "takes no keyword args");
214                 return NULL;
215         }
216
217         switch (PyTuple_GET_SIZE(args)) {
218                 case 0:
219                         return Matrix_CreatePyObject(NULL, 4, 4, Py_NEW, type);
220                 case 1:
221                 {
222                         PyObject *arg = PyTuple_GET_ITEM(args, 0);
223
224                         /* Input is now as a sequence of rows so length of sequence
225                          * is the number of rows */
226                         /* -1 is an error, size checks will accunt for this */
227                         const unsigned short num_row = PySequence_Size(arg);
228
229                         if (num_row >= 2 && num_row <= 4) {
230                                 PyObject *item = PySequence_GetItem(arg, 0);
231                                 /* Since each item is a row, number of items is the
232                                  * same as the number of columns */
233                                 const unsigned short num_col = PySequence_Size(item);
234                                 Py_XDECREF(item);
235
236                                 if (num_col >= 2 && num_col <= 4) {
237                                         /* sane row & col size, new matrix and assign as slice  */
238                                         PyObject *matrix = Matrix_CreatePyObject(NULL, num_col, num_row, Py_NEW, type);
239                                         if (Matrix_ass_slice((MatrixObject *)matrix, 0, INT_MAX, arg) == 0) {
240                                                 return matrix;
241                                         }
242                                         else { /* matrix ok, slice assignment not */
243                                                 Py_DECREF(matrix);
244                                         }
245                                 }
246                         }
247                 }
248         }
249
250         /* will overwrite error */
251         PyErr_SetString(PyExc_TypeError,
252                         "Matrix(): "
253                         "expects no args or 2-4 numeric sequences");
254         return NULL;
255 }
256
257 static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self)
258 {
259         PyObject *ret = Matrix_copy(self);
260         PyObject *ret_dummy = matrix_func(ret);
261         if (ret_dummy) {
262                 Py_DECREF(ret_dummy);
263                 return (PyObject *)ret;
264         }
265         else { /* error */
266                 Py_DECREF(ret);
267                 return NULL;
268         }
269 }
270
271 /* when a matrix is 4x4 size but initialized as a 3x3, re-assign values for 4x4 */
272 static void matrix_3x3_as_4x4(float mat[16])
273 {
274         mat[10] = mat[8];
275         mat[9] = mat[7];
276         mat[8] = mat[6];
277         mat[7] = 0.0f;
278         mat[6] = mat[5];
279         mat[5] = mat[4];
280         mat[4] = mat[3];
281         mat[3] = 0.0f;
282 }
283
284 /*-----------------------CLASS-METHODS----------------------------*/
285
286 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc.
287 PyDoc_STRVAR(C_Matrix_Rotation_doc,
288 ".. classmethod:: Rotation(angle, size, axis)\n"
289 "\n"
290 "   Create a matrix representing a rotation.\n"
291 "\n"
292 "   :arg angle: The angle of rotation desired, in radians.\n"
293 "   :type angle: float\n"
294 "   :arg size: The size of the rotation matrix to construct [2, 4].\n"
295 "   :type size: int\n"
296 "   :arg axis: a string in ['X', 'Y', 'Z'] or a 3D Vector Object\n"
297 "      (optional when size is 2).\n"
298 "   :type axis: string or :class:`Vector`\n"
299 "   :return: A new rotation matrix.\n"
300 "   :rtype: :class:`Matrix`\n"
301 );
302 static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
303 {
304         PyObject *vec = NULL;
305         const char *axis = NULL;
306         int matSize;
307         double angle; /* use double because of precision problems at high values */
308         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
309                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
310
311         if (!PyArg_ParseTuple(args, "di|O", &angle, &matSize, &vec)) {
312                 PyErr_SetString(PyExc_TypeError,
313                                 "Matrix.Rotation(angle, size, axis): "
314                                 "expected float int and a string or vector");
315                 return NULL;
316         }
317
318         if (vec && PyUnicode_Check(vec)) {
319                 axis = _PyUnicode_AsString((PyObject *)vec);
320                 if (axis == NULL || axis[0] == '\0' || axis[1] != '\0' || axis[0] < 'X' || axis[0] > 'Z') {
321                         PyErr_SetString(PyExc_ValueError,
322                                         "Matrix.Rotation(): "
323                                         "3rd argument axis value must be a 3D vector "
324                                         "or a string in 'X', 'Y', 'Z'");
325                         return NULL;
326                 }
327                 else {
328                         /* use the string */
329                         vec = NULL;
330                 }
331         }
332
333         angle = angle_wrap_rad(angle);
334
335         if (matSize != 2 && matSize != 3 && matSize != 4) {
336                 PyErr_SetString(PyExc_ValueError,
337                                 "Matrix.Rotation(): "
338                                 "can only return a 2x2 3x3 or 4x4 matrix");
339                 return NULL;
340         }
341         if (matSize == 2 && (vec != NULL)) {
342                 PyErr_SetString(PyExc_ValueError,
343                                 "Matrix.Rotation(): "
344                                 "cannot create a 2x2 rotation matrix around arbitrary axis");
345                 return NULL;
346         }
347         if ((matSize == 3 || matSize == 4) && (axis == NULL) && (vec == NULL)) {
348                 PyErr_SetString(PyExc_ValueError,
349                                 "Matrix.Rotation(): "
350                                 "axis of rotation for 3d and 4d matrices is required");
351                 return NULL;
352         }
353
354         /* check for valid vector/axis above */
355         if (vec) {
356                 float tvec[3];
357
358                 if (mathutils_array_parse(tvec, 3, 3, vec, "Matrix.Rotation(angle, size, axis), invalid 'axis' arg") == -1)
359                         return NULL;
360
361                 axis_angle_to_mat3((float (*)[3])mat, tvec, angle);
362         }
363         else if (matSize == 2) {
364                 const float angle_cos = cosf(angle);
365                 const float angle_sin = sinf(angle);
366
367                 //2D rotation matrix
368                 mat[0] =  angle_cos;
369                 mat[1] =  angle_sin;
370                 mat[2] = -angle_sin;
371                 mat[3] =  angle_cos;
372         }
373         else {
374                 /* valid axis checked above */
375                 single_axis_angle_to_mat3((float (*)[3])mat, axis[0], angle);
376         }
377
378         if (matSize == 4) {
379                 matrix_3x3_as_4x4(mat);
380         }
381         //pass to matrix creation
382         return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
383 }
384
385
386 PyDoc_STRVAR(C_Matrix_Translation_doc,
387 ".. classmethod:: Translation(vector)\n"
388 "\n"
389 "   Create a matrix representing a translation.\n"
390 "\n"
391 "   :arg vector: The translation vector.\n"
392 "   :type vector: :class:`Vector`\n"
393 "   :return: An identity matrix with a translation.\n"
394 "   :rtype: :class:`Matrix`\n"
395 );
396 static PyObject *C_Matrix_Translation(PyObject *cls, PyObject *value)
397 {
398         float mat[4][4]= MAT4_UNITY;
399
400         if (mathutils_array_parse(mat[3], 3, 4, value, "mathutils.Matrix.Translation(vector), invalid vector arg") == -1)
401                 return NULL;
402
403         return Matrix_CreatePyObject(&mat[0][0], 4, 4, Py_NEW, (PyTypeObject *)cls);
404 }
405 //----------------------------------mathutils.Matrix.Scale() -------------
406 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc.
407 PyDoc_STRVAR(C_Matrix_Scale_doc,
408 ".. classmethod:: Scale(factor, size, axis)\n"
409 "\n"
410 "   Create a matrix representing a scaling.\n"
411 "\n"
412 "   :arg factor: The factor of scaling to apply.\n"
413 "   :type factor: float\n"
414 "   :arg size: The size of the scale matrix to construct [2, 4].\n"
415 "   :type size: int\n"
416 "   :arg axis: Direction to influence scale. (optional).\n"
417 "   :type axis: :class:`Vector`\n"
418 "   :return: A new scale matrix.\n"
419 "   :rtype: :class:`Matrix`\n"
420 );
421 static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
422 {
423         PyObject *vec = NULL;
424         int vec_size;
425         float tvec[3];
426         float factor;
427         int matSize;
428         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
429                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
430
431         if (!PyArg_ParseTuple(args, "fi|O:Matrix.Scale", &factor, &matSize, &vec)) {
432                 return NULL;
433         }
434         if (matSize != 2 && matSize != 3 && matSize != 4) {
435                 PyErr_SetString(PyExc_ValueError,
436                                 "Matrix.Scale(): "
437                                 "can only return a 2x2 3x3 or 4x4 matrix");
438                 return NULL;
439         }
440         if (vec) {
441                 vec_size = (matSize == 2 ? 2 : 3);
442                 if (mathutils_array_parse(tvec, vec_size, vec_size, vec, "Matrix.Scale(factor, size, axis), invalid 'axis' arg") == -1) {
443                         return NULL;
444                 }
445         }
446         if (vec == NULL) {      //scaling along axis
447                 if (matSize == 2) {
448                         mat[0] = factor;
449                         mat[3] = factor;
450                 }
451                 else {
452                         mat[0] = factor;
453                         mat[4] = factor;
454                         mat[8] = factor;
455                 }
456         }
457         else { //scaling in arbitrary direction
458                 //normalize arbitrary axis
459                 float norm = 0.0f;
460                 int x;
461                 for (x = 0; x < vec_size; x++) {
462                         norm += tvec[x] * tvec[x];
463                 }
464                 norm = (float) sqrt(norm);
465                 for (x = 0; x < vec_size; x++) {
466                         tvec[x] /= norm;
467                 }
468                 if (matSize == 2) {
469                         mat[0] = 1 + ((factor - 1) *(tvec[0] * tvec[0]));
470                         mat[1] =     ((factor - 1) *(tvec[0] * tvec[1]));
471                         mat[2] =     ((factor - 1) *(tvec[0] * tvec[1]));
472                         mat[3] = 1 + ((factor - 1) *(tvec[1] * tvec[1]));
473                 }
474                 else {
475                         mat[0] = 1 + ((factor - 1) *(tvec[0] * tvec[0]));
476                         mat[1] =     ((factor - 1) *(tvec[0] * tvec[1]));
477                         mat[2] =     ((factor - 1) *(tvec[0] * tvec[2]));
478                         mat[3] =     ((factor - 1) *(tvec[0] * tvec[1]));
479                         mat[4] = 1 + ((factor - 1) *(tvec[1] * tvec[1]));
480                         mat[5] =     ((factor - 1) *(tvec[1] * tvec[2]));
481                         mat[6] =     ((factor - 1) *(tvec[0] * tvec[2]));
482                         mat[7] =     ((factor - 1) *(tvec[1] * tvec[2]));
483                         mat[8] = 1 + ((factor - 1) *(tvec[2] * tvec[2]));
484                 }
485         }
486         if (matSize == 4) {
487                 matrix_3x3_as_4x4(mat);
488         }
489         //pass to matrix creation
490         return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
491 }
492 //----------------------------------mathutils.Matrix.OrthoProjection() ---
493 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc.
494 PyDoc_STRVAR(C_Matrix_OrthoProjection_doc,
495 ".. classmethod:: OrthoProjection(axis, size)\n"
496 "\n"
497 "   Create a matrix to represent an orthographic projection.\n"
498 "\n"
499 "   :arg axis: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'],\n"
500 "      where a single axis is for a 2D matrix.\n"
501 "      Or a vector for an arbitrary axis\n"
502 "   :type axis: string or :class:`Vector`\n"
503 "   :arg size: The size of the projection matrix to construct [2, 4].\n"
504 "   :type size: int\n"
505 "   :return: A new projection matrix.\n"
506 "   :rtype: :class:`Matrix`\n"
507 );
508 static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
509 {
510         PyObject *axis;
511
512         int matSize, x;
513         float norm = 0.0f;
514         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
515                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
516
517         if (!PyArg_ParseTuple(args, "Oi:Matrix.OrthoProjection", &axis, &matSize)) {
518                 return NULL;
519         }
520         if (matSize != 2 && matSize != 3 && matSize != 4) {
521                 PyErr_SetString(PyExc_ValueError,
522                                 "Matrix.OrthoProjection(): "
523                                 "can only return a 2x2 3x3 or 4x4 matrix");
524                 return NULL;
525         }
526
527         if (PyUnicode_Check(axis)) {    //ortho projection onto cardinal plane
528                 Py_ssize_t plane_len;
529                 const char *plane = _PyUnicode_AsStringAndSize(axis, &plane_len);
530                 if (matSize == 2) {
531                         if (plane_len == 1 && plane[0] == 'X') {
532                                 mat[0] = 1.0f;
533                         }
534                         else if (plane_len == 1 && plane[0] == 'Y') {
535                                 mat[3] = 1.0f;
536                         }
537                         else {
538                                 PyErr_Format(PyExc_ValueError,
539                                              "Matrix.OrthoProjection(): "
540                                              "unknown plane, expected: X, Y, not '%.200s'",
541                                              plane);
542                                 return NULL;
543                         }
544                 }
545                 else {
546                         if (plane_len == 2 && plane[0] == 'X' && plane[1] == 'Y') {
547                                 mat[0] = 1.0f;
548                                 mat[4] = 1.0f;
549                         }
550                         else if (plane_len == 2 && plane[0] == 'X' && plane[1] == 'Z') {
551                                 mat[0] = 1.0f;
552                                 mat[8] = 1.0f;
553                         }
554                         else if (plane_len == 2 && plane[0] == 'Y' && plane[1] == 'Z') {
555                                 mat[4] = 1.0f;
556                                 mat[8] = 1.0f;
557                         }
558                         else {
559                                 PyErr_Format(PyExc_ValueError,
560                                              "Matrix.OrthoProjection(): "
561                                              "unknown plane, expected: XY, XZ, YZ, not '%.200s'",
562                                              plane);
563                                 return NULL;
564                         }
565                 }
566         }
567         else {
568                 //arbitrary plane
569
570                 int vec_size = (matSize == 2 ? 2 : 3);
571                 float tvec[4];
572
573                 if (mathutils_array_parse(tvec, vec_size, vec_size, axis,
574                                           "Matrix.OrthoProjection(axis, size), invalid 'axis' arg") == -1)
575                 {
576                         return NULL;
577                 }
578
579                 //normalize arbitrary axis
580                 for (x = 0; x < vec_size; x++) {
581                         norm += tvec[x] * tvec[x];
582                 }
583                 norm = (float) sqrt(norm);
584                 for (x = 0; x < vec_size; x++) {
585                         tvec[x] /= norm;
586                 }
587                 if (matSize == 2) {
588                         mat[0] = 1 - (tvec[0] * tvec[0]);
589                         mat[1] =   - (tvec[0] * tvec[1]);
590                         mat[2] =   - (tvec[0] * tvec[1]);
591                         mat[3] = 1 - (tvec[1] * tvec[1]);
592                 }
593                 else if (matSize > 2) {
594                         mat[0] = 1 - (tvec[0] * tvec[0]);
595                         mat[1] =   - (tvec[0] * tvec[1]);
596                         mat[2] =   - (tvec[0] * tvec[2]);
597                         mat[3] =   - (tvec[0] * tvec[1]);
598                         mat[4] = 1 - (tvec[1] * tvec[1]);
599                         mat[5] =   - (tvec[1] * tvec[2]);
600                         mat[6] =   - (tvec[0] * tvec[2]);
601                         mat[7] =   - (tvec[1] * tvec[2]);
602                         mat[8] = 1 - (tvec[2] * tvec[2]);
603                 }
604         }
605         if (matSize == 4) {
606                 matrix_3x3_as_4x4(mat);
607         }
608         //pass to matrix creation
609         return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
610 }
611
612 PyDoc_STRVAR(C_Matrix_Shear_doc,
613 ".. classmethod:: Shear(plane, size, factor)\n"
614 "\n"
615 "   Create a matrix to represent an shear transformation.\n"
616 "\n"
617 "   :arg plane: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'],\n"
618 "      where a single axis is for a 2D matrix only.\n"
619 "   :type plane: string\n"
620 "   :arg size: The size of the shear matrix to construct [2, 4].\n"
621 "   :type size: int\n"
622 "   :arg factor: The factor of shear to apply. For a 3 or 4 *size* matrix\n"
623 "      pass a pair of floats corrasponding with the *plane* axis.\n"
624 "   :type factor: float or float pair\n"
625 "   :return: A new shear matrix.\n"
626 "   :rtype: :class:`Matrix`\n"
627 );
628 static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args)
629 {
630         int matSize;
631         const char *plane;
632         PyObject *fac;
633         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
634                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
635
636         if (!PyArg_ParseTuple(args, "siO:Matrix.Shear", &plane, &matSize, &fac)) {
637                 return NULL;
638         }
639         if (matSize != 2 && matSize != 3 && matSize != 4) {
640                 PyErr_SetString(PyExc_ValueError,
641                                 "Matrix.Shear(): "
642                                 "can only return a 2x2 3x3 or 4x4 matrix");
643                 return NULL;
644         }
645
646         if (matSize == 2) {
647                 float const factor = PyFloat_AsDouble(fac);
648
649                 if (factor == -1.0f && PyErr_Occurred()) {
650                         PyErr_SetString(PyExc_TypeError,
651                                         "Matrix.Shear(): "
652                                         "the factor to be a float");
653                         return NULL;
654                 }
655
656                 /* unit */
657                 mat[0] = 1.0f;
658                 mat[3] = 1.0f;
659
660                 if (strcmp(plane, "X") == 0) {
661                         mat[2] = factor;
662                 }
663                 else if (strcmp(plane, "Y") == 0) {
664                         mat[1] = factor;
665                 }
666                 else {
667                         PyErr_SetString(PyExc_ValueError,
668                                         "Matrix.Shear(): "
669                                         "expected: X, Y or wrong matrix size for shearing plane");
670                         return NULL;
671                 }
672         }
673         else {
674                 /* 3 or 4, apply as 3x3, resize later if needed */
675                 float factor[2];
676
677                 if (mathutils_array_parse(factor, 2, 2, fac, "Matrix.Shear()") < 0) {
678                         return NULL;
679                 }
680
681                 /* unit */
682                 mat[0] = 1.0f;
683                 mat[4] = 1.0f;
684                 mat[8] = 1.0f;
685
686                 if (strcmp(plane, "XY") == 0) {
687                         mat[6] = factor[0];
688                         mat[7] = factor[1];
689                 }
690                 else if (strcmp(plane, "XZ") == 0) {
691                         mat[3] = factor[0];
692                         mat[5] = factor[1];
693                 }
694                 else if (strcmp(plane, "YZ") == 0) {
695                         mat[1] = factor[0];
696                         mat[2] = factor[1];
697                 }
698                 else {
699                         PyErr_SetString(PyExc_ValueError,
700                                         "Matrix.Shear(): "
701                                         "expected: X, Y, XY, XZ, YZ");
702                         return NULL;
703                 }
704         }
705
706         if (matSize == 4) {
707                 matrix_3x3_as_4x4(mat);
708         }
709         //pass to matrix creation
710         return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
711 }
712
713 void matrix_as_3x3(float mat[3][3], MatrixObject *self)
714 {
715         copy_v3_v3(mat[0], MATRIX_COL_PTR(self, 0));
716         copy_v3_v3(mat[1], MATRIX_COL_PTR(self, 1));
717         copy_v3_v3(mat[2], MATRIX_COL_PTR(self, 2));
718 }
719
720 /* assumes rowsize == colsize is checked and the read callback has run */
721 static float matrix_determinant_internal(MatrixObject *self)
722 {
723         if (self->num_col == 2) {
724                 return determinant_m2(MATRIX_ITEM(self, 0, 0), MATRIX_ITEM(self, 0, 1),
725                                       MATRIX_ITEM(self, 1, 0), MATRIX_ITEM(self, 1, 1));
726         }
727         else if (self->num_col == 3) {
728                 return determinant_m3(MATRIX_ITEM(self, 0, 0), MATRIX_ITEM(self, 0, 1), MATRIX_ITEM(self, 0, 2),
729                                       MATRIX_ITEM(self, 1, 0), MATRIX_ITEM(self, 1, 1), MATRIX_ITEM(self, 1, 2),
730                                       MATRIX_ITEM(self, 2, 0), MATRIX_ITEM(self, 2, 1), MATRIX_ITEM(self, 2, 2));
731         }
732         else {
733                 return determinant_m4((float (*)[4])self->matrix);
734         }
735 }
736
737
738 /*-----------------------------METHODS----------------------------*/
739 PyDoc_STRVAR(Matrix_to_quaternion_doc,
740 ".. method:: to_quaternion()\n"
741 "\n"
742 "   Return a quaternion representation of the rotation matrix.\n"
743 "\n"
744 "   :return: Quaternion representation of the rotation matrix.\n"
745 "   :rtype: :class:`Quaternion`\n"
746 );
747 static PyObject *Matrix_to_quaternion(MatrixObject *self)
748 {
749         float quat[4];
750
751         if (BaseMath_ReadCallback(self) == -1)
752                 return NULL;
753
754         /* must be 3-4 cols, 3-4 rows, square matrix */
755         if ((self->num_row < 3) || (self->num_col < 3) || (self->num_row != self->num_col)) {
756                 PyErr_SetString(PyExc_ValueError,
757                                 "Matrix.to_quat(): "
758                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
759                 return NULL;
760         }
761         if (self->num_row == 3) {
762                 mat3_to_quat(quat, (float (*)[3])self->matrix);
763         }
764         else {
765                 mat4_to_quat(quat, (float (*)[4])self->matrix);
766         }
767
768         return Quaternion_CreatePyObject(quat, Py_NEW, NULL);
769 }
770
771 /*---------------------------matrix.toEuler() --------------------*/
772 PyDoc_STRVAR(Matrix_to_euler_doc,
773 ".. method:: to_euler(order, euler_compat)\n"
774 "\n"
775 "   Return an Euler representation of the rotation matrix\n"
776 "   (3x3 or 4x4 matrix only).\n"
777 "\n"
778 "   :arg order: Optional rotation order argument in\n"
779 "      ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n"
780 "   :type order: string\n"
781 "   :arg euler_compat: Optional euler argument the new euler will be made\n"
782 "      compatible with (no axis flipping between them).\n"
783 "      Useful for converting a series of matrices to animation curves.\n"
784 "   :type euler_compat: :class:`Euler`\n"
785 "   :return: Euler representation of the matrix.\n"
786 "   :rtype: :class:`Euler`\n"
787 );
788 static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
789 {
790         const char *order_str = NULL;
791         short order = EULER_ORDER_XYZ;
792         float eul[3], eul_compatf[3];
793         EulerObject *eul_compat = NULL;
794
795         float tmat[3][3];
796         float (*mat)[3];
797
798         if (BaseMath_ReadCallback(self) == -1)
799                 return NULL;
800
801         if (!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat))
802                 return NULL;
803
804         if (eul_compat) {
805                 if (BaseMath_ReadCallback(eul_compat) == -1)
806                         return NULL;
807
808                 copy_v3_v3(eul_compatf, eul_compat->eul);
809         }
810
811         /*must be 3-4 cols, 3-4 rows, square matrix */
812         if (self->num_row ==3 && self->num_col ==3) {
813                 mat = (float (*)[3])self->matrix;
814         }
815         else if (self->num_row ==4 && self->num_col ==4) {
816                 copy_m3_m4(tmat, (float (*)[4])self->matrix);
817                 mat = tmat;
818         }
819         else {
820                 PyErr_SetString(PyExc_ValueError,
821                                 "Matrix.to_euler(): "
822                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
823                 return NULL;
824         }
825
826         if (order_str) {
827                 order = euler_order_from_string(order_str, "Matrix.to_euler()");
828
829                 if (order == -1)
830                         return NULL;
831         }
832
833         if (eul_compat) {
834                 if (order == 1) mat3_to_compatible_eul(eul, eul_compatf, mat);
835                 else                    mat3_to_compatible_eulO(eul, eul_compatf, order, mat);
836         }
837         else {
838                 if (order == 1) mat3_to_eul(eul, mat);
839                 else                    mat3_to_eulO(eul, order, mat);
840         }
841
842         return Euler_CreatePyObject(eul, order, Py_NEW, NULL);
843 }
844
845 PyDoc_STRVAR(Matrix_resize_4x4_doc,
846 ".. method:: resize_4x4()\n"
847 "\n"
848 "   Resize the matrix to 4x4.\n"
849 );
850 static PyObject *Matrix_resize_4x4(MatrixObject *self)
851 {
852         float mat[4][4] = MAT4_UNITY;
853         int col;
854
855         if (self->wrapped == Py_WRAP) {
856                 PyErr_SetString(PyExc_TypeError,
857                                 "Matrix.resize_4x4(): "
858                                 "cannot resize wrapped data - make a copy and resize that");
859                 return NULL;
860         }
861         if (self->cb_user) {
862                 PyErr_SetString(PyExc_TypeError,
863                                 "Matrix.resize_4x4(): "
864                                 "cannot resize owned data - make a copy and resize that");
865                 return NULL;
866         }
867
868         self->matrix = PyMem_Realloc(self->matrix, (sizeof(float) * 16));
869         if (self->matrix == NULL) {
870                 PyErr_SetString(PyExc_MemoryError,
871                                 "Matrix.resize_4x4(): "
872                                 "problem allocating pointer space");
873                 return NULL;
874         }
875
876         for (col = 0; col < self->num_col; col++) {
877                 memcpy(mat[col], MATRIX_COL_PTR(self, col), self->num_row * sizeof(float));
878         }
879
880         copy_m4_m4((float (*)[4])self->matrix, (float (*)[4])mat);
881
882         self->num_col = 4;
883         self->num_row = 4;
884
885         Py_RETURN_NONE;
886 }
887
888 PyDoc_STRVAR(Matrix_to_4x4_doc,
889 ".. method:: to_4x4()\n"
890 "\n"
891 "   Return a 4x4 copy of this matrix.\n"
892 "\n"
893 "   :return: a new matrix.\n"
894 "   :rtype: :class:`Matrix`\n"
895 );
896 static PyObject *Matrix_to_4x4(MatrixObject *self)
897 {
898         if (BaseMath_ReadCallback(self) == -1)
899                 return NULL;
900
901         if (self->num_row == 4 && self->num_col == 4) {
902                 return Matrix_CreatePyObject(self->matrix, 4, 4, Py_NEW, Py_TYPE(self));
903         }
904         else if (self->num_row == 3 && self->num_col == 3) {
905                 float mat[4][4];
906                 copy_m4_m3(mat, (float (*)[3])self->matrix);
907                 return Matrix_CreatePyObject((float *)mat, 4, 4, Py_NEW, Py_TYPE(self));
908         }
909         /* TODO, 2x2 matrix */
910
911         PyErr_SetString(PyExc_TypeError,
912                         "Matrix.to_4x4(): "
913                         "inappropriate matrix size");
914         return NULL;
915 }
916
917 PyDoc_STRVAR(Matrix_to_3x3_doc,
918 ".. method:: to_3x3()\n"
919 "\n"
920 "   Return a 3x3 copy of this matrix.\n"
921 "\n"
922 "   :return: a new matrix.\n"
923 "   :rtype: :class:`Matrix`\n"
924 );
925 static PyObject *Matrix_to_3x3(MatrixObject *self)
926 {
927         float mat[3][3];
928
929         if (BaseMath_ReadCallback(self) == -1)
930                 return NULL;
931
932         if ((self->num_row < 3) || (self->num_col < 3)) {
933                 PyErr_SetString(PyExc_TypeError,
934                                 "Matrix.to_3x3(): inappropriate matrix size");
935                 return NULL;
936         }
937
938         matrix_as_3x3(mat, self);
939
940         return Matrix_CreatePyObject((float *)mat, 3, 3, Py_NEW, Py_TYPE(self));
941 }
942
943 PyDoc_STRVAR(Matrix_to_translation_doc,
944 ".. method:: to_translation()\n"
945 "\n"
946 "   Return a the translation part of a 4 row matrix.\n"
947 "\n"
948 "   :return: Return a the translation of a matrix.\n"
949 "   :rtype: :class:`Vector`\n"
950 );
951 static PyObject *Matrix_to_translation(MatrixObject *self)
952 {
953         if (BaseMath_ReadCallback(self) == -1)
954                 return NULL;
955
956         if ((self->num_row < 3) || self->num_col < 4) {
957                 PyErr_SetString(PyExc_TypeError,
958                                 "Matrix.to_translation(): "
959                                 "inappropriate matrix size");
960                 return NULL;
961         }
962
963         return Vector_CreatePyObject(MATRIX_COL_PTR(self, 3), 3, Py_NEW, NULL);
964 }
965
966 PyDoc_STRVAR(Matrix_to_scale_doc,
967 ".. method:: to_scale()\n"
968 "\n"
969 "   Return a the scale part of a 3x3 or 4x4 matrix.\n"
970 "\n"
971 "   :return: Return a the scale of a matrix.\n"
972 "   :rtype: :class:`Vector`\n"
973 "\n"
974 "   .. 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"
975 );
976 static PyObject *Matrix_to_scale(MatrixObject *self)
977 {
978         float rot[3][3];
979         float mat[3][3];
980         float size[3];
981
982         if (BaseMath_ReadCallback(self) == -1)
983                 return NULL;
984
985         /*must be 3-4 cols, 3-4 rows, square matrix */
986         if ((self->num_row < 3) || (self->num_col < 3)) {
987                 PyErr_SetString(PyExc_TypeError,
988                                 "Matrix.to_scale(): "
989                                 "inappropriate matrix size, 3x3 minimum size");
990                 return NULL;
991         }
992
993         matrix_as_3x3(mat, self);
994
995         /* compatible mat4_to_loc_rot_size */
996         mat3_to_rot_size(rot, size, mat);
997
998         return Vector_CreatePyObject(size, 3, Py_NEW, NULL);
999 }
1000
1001 /*---------------------------matrix.invert() ---------------------*/
1002 PyDoc_STRVAR(Matrix_invert_doc,
1003 ".. method:: invert()\n"
1004 "\n"
1005 "   Set the matrix to its inverse.\n"
1006 "\n"
1007 "   .. note:: :exc:`ValueError` exception is raised.\n"
1008 "\n"
1009 "   .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n"
1010 );
1011 static PyObject *Matrix_invert(MatrixObject *self)
1012 {
1013
1014         int x, y, z = 0;
1015         float det = 0.0f;
1016         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f,
1017                          0.0f, 0.0f, 0.0f, 0.0f,
1018                          0.0f, 0.0f, 0.0f, 0.0f,
1019                          0.0f, 0.0f, 0.0f, 1.0f};
1020
1021         if (BaseMath_ReadCallback(self) == -1)
1022                 return NULL;
1023
1024         if (self->num_col != self->num_row) {
1025                 PyErr_SetString(PyExc_TypeError,
1026                                 "Matrix.invert(ed): "
1027                                 "only square matrices are supported");
1028                 return NULL;
1029         }
1030
1031         /* calculate the determinant */
1032         det = matrix_determinant_internal(self);
1033
1034         if (det != 0) {
1035                 /* calculate the classical adjoint */
1036                 if (self->num_col == 2) {
1037                         mat[0] =  MATRIX_ITEM(self, 1, 1);
1038                         mat[1] = -MATRIX_ITEM(self, 0, 1);
1039                         mat[2] = -MATRIX_ITEM(self, 1, 0);
1040                         mat[3] =  MATRIX_ITEM(self, 0, 0);
1041                 }
1042                 else if (self->num_col == 3) {
1043                         adjoint_m3_m3((float (*)[3]) mat,(float (*)[3])self->matrix);
1044                 }
1045                 else if (self->num_col == 4) {
1046                         adjoint_m4_m4((float (*)[4]) mat, (float (*)[4])self->matrix);
1047                 }
1048                 /* divide by determinate */
1049                 for (x = 0; x < (self->num_col * self->num_row); x++) {
1050                         mat[x] /= det;
1051                 }
1052                 /* set values */
1053                 for (x = 0; x < self->num_col; x++) {
1054                         for (y = 0; y < self->num_row; y++) {
1055                                 MATRIX_ITEM(self, y, x) = mat[z];
1056                                 z++;
1057                         }
1058                 }
1059                 /*transpose
1060                 Matrix_transpose(self);*/
1061         }
1062         else {
1063                 PyErr_SetString(PyExc_ValueError,
1064                                 "Matrix.invert(ed): "
1065                                 "matrix does not have an inverse");
1066                 return NULL;
1067         }
1068
1069         (void)BaseMath_WriteCallback(self);
1070         Py_RETURN_NONE;
1071 }
1072
1073 PyDoc_STRVAR(Matrix_inverted_doc,
1074 ".. method:: inverted()\n"
1075 "\n"
1076 "   Return an inverted copy of the matrix.\n"
1077 "\n"
1078 "   :return: the  inverted matrix.\n"
1079 "   :rtype: :class:`Matrix`\n"
1080 "\n"
1081 "   .. note:: :exc:`ValueError` exception is raised.\n"
1082 );
1083 static PyObject *Matrix_inverted(MatrixObject *self)
1084 {
1085         return matrix__apply_to_copy((PyNoArgsFunction)Matrix_invert, self);
1086 }
1087
1088 PyDoc_STRVAR(Matrix_rotate_doc,
1089 ".. method:: rotate(other)\n"
1090 "\n"
1091 "   Rotates the matrix a by another mathutils value.\n"
1092 "\n"
1093 "   :arg other: rotation component of mathutils value\n"
1094 "   :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n"
1095 "\n"
1096 "   .. note:: If any of the columns are not unit length this may not have desired results.\n"
1097 );
1098 static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value)
1099 {
1100         float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
1101
1102         if (BaseMath_ReadCallback(self) == -1)
1103                 return NULL;
1104
1105         if (mathutils_any_to_rotmat(other_rmat, value, "matrix.rotate(value)") == -1)
1106                 return NULL;
1107
1108         if (self->num_row != 3 || self->num_col != 3) {
1109                 PyErr_SetString(PyExc_TypeError,
1110                                 "Matrix.rotate(): "
1111                                 "must have 3x3 dimensions");
1112                 return NULL;
1113         }
1114
1115         matrix_as_3x3(self_rmat, self);
1116         mul_m3_m3m3(rmat, other_rmat, self_rmat);
1117
1118         copy_m3_m3((float (*)[3])(self->matrix), rmat);
1119
1120         (void)BaseMath_WriteCallback(self);
1121         Py_RETURN_NONE;
1122 }
1123
1124 /*---------------------------matrix.decompose() ---------------------*/
1125 PyDoc_STRVAR(Matrix_decompose_doc,
1126 ".. method:: decompose()\n"
1127 "\n"
1128 "   Return the location, rotaion and scale components of this matrix.\n"
1129 "\n"
1130 "   :return: loc, rot, scale triple.\n"
1131 "   :rtype: (:class:`Vector`, :class:`Quaternion`, :class:`Vector`)"
1132 );
1133 static PyObject *Matrix_decompose(MatrixObject *self)
1134 {
1135         PyObject *ret;
1136         float loc[3];
1137         float rot[3][3];
1138         float quat[4];
1139         float size[3];
1140
1141         if (self->num_row != 4 || self->num_col != 4) {
1142                 PyErr_SetString(PyExc_TypeError,
1143                                 "Matrix.decompose(): "
1144                                 "inappropriate matrix size - expects 4x4 matrix");
1145                 return NULL;
1146         }
1147
1148         if (BaseMath_ReadCallback(self) == -1)
1149                 return NULL;
1150
1151         mat4_to_loc_rot_size(loc, rot, size, (float (*)[4])self->matrix);
1152         mat3_to_quat(quat, rot);
1153
1154         ret = PyTuple_New(3);
1155         PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(loc, 3, Py_NEW, NULL));
1156         PyTuple_SET_ITEM(ret, 1, Quaternion_CreatePyObject(quat, Py_NEW, NULL));
1157         PyTuple_SET_ITEM(ret, 2, Vector_CreatePyObject(size, 3, Py_NEW, NULL));
1158
1159         return ret;
1160 }
1161
1162
1163
1164 PyDoc_STRVAR(Matrix_lerp_doc,
1165 ".. function:: lerp(other, factor)\n"
1166 "\n"
1167 "   Returns the interpolation of two matrices.\n"
1168 "\n"
1169 "   :arg other: value to interpolate with.\n"
1170 "   :type other: :class:`Matrix`\n"
1171 "   :arg factor: The interpolation value in [0.0, 1.0].\n"
1172 "   :type factor: float\n"
1173 "   :return: The interpolated rotation.\n"
1174 "   :rtype: :class:`Matrix`\n"
1175 );
1176 static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
1177 {
1178         MatrixObject *mat2 = NULL;
1179         float fac, mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
1180
1181         if (!PyArg_ParseTuple(args, "O!f:lerp", &matrix_Type, &mat2, &fac))
1182                 return NULL;
1183
1184         if (self->num_col != mat2->num_col || self->num_row != mat2->num_row) {
1185                 PyErr_SetString(PyExc_ValueError,
1186                                 "Matrix.lerp(): "
1187                                 "expects both matrix objects of the same dimensions");
1188                 return NULL;
1189         }
1190
1191         if (BaseMath_ReadCallback(self) == -1 || BaseMath_ReadCallback(mat2) == -1)
1192                 return NULL;
1193
1194         /* TODO, different sized matrix */
1195         if (self->num_col == 4 && self->num_row == 4) {
1196                 blend_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac);
1197         }
1198         else if (self->num_col == 3 && self->num_row == 3) {
1199                 blend_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac);
1200         }
1201         else {
1202                 PyErr_SetString(PyExc_ValueError,
1203                                 "Matrix.lerp(): "
1204                                 "only 3x3 and 4x4 matrices supported");
1205                 return NULL;
1206         }
1207
1208         return Matrix_CreatePyObject(mat, self->num_col, self->num_row, Py_NEW, Py_TYPE(self));
1209 }
1210
1211 /*---------------------------matrix.determinant() ----------------*/
1212 PyDoc_STRVAR(Matrix_determinant_doc,
1213 ".. method:: determinant()\n"
1214 "\n"
1215 "   Return the determinant of a matrix.\n"
1216 "\n"
1217 "   :return: Return a the determinant of a matrix.\n"
1218 "   :rtype: float\n"
1219 "\n"
1220 "   .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n"
1221 );
1222 static PyObject *Matrix_determinant(MatrixObject *self)
1223 {
1224         if (BaseMath_ReadCallback(self) == -1)
1225                 return NULL;
1226
1227         if (self->num_col != self->num_row) {
1228                 PyErr_SetString(PyExc_TypeError,
1229                                 "Matrix.determinant(): "
1230                                 "only square matrices are supported");
1231                 return NULL;
1232         }
1233
1234         return PyFloat_FromDouble((double)matrix_determinant_internal(self));
1235 }
1236 /*---------------------------matrix.transpose() ------------------*/
1237 PyDoc_STRVAR(Matrix_transpose_doc,
1238 ".. method:: transpose()\n"
1239 "\n"
1240 "   Set the matrix to its transpose.\n"
1241 "\n"
1242 "   .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n"
1243 );
1244 static PyObject *Matrix_transpose(MatrixObject *self)
1245 {
1246         if (BaseMath_ReadCallback(self) == -1)
1247                 return NULL;
1248
1249         if (self->num_col != self->num_row) {
1250                 PyErr_SetString(PyExc_TypeError,
1251                                 "Matrix.transpose(d): "
1252                                 "only square matrices are supported");
1253                 return NULL;
1254         }
1255
1256         if (self->num_col == 2) {
1257                 const float t = MATRIX_ITEM(self, 1, 0);
1258                 MATRIX_ITEM(self, 1, 0) = MATRIX_ITEM(self, 0, 1);
1259                 MATRIX_ITEM(self, 0, 1) = t;
1260         }
1261         else if (self->num_col == 3) {
1262                 transpose_m3((float (*)[3])self->matrix);
1263         }
1264         else {
1265                 transpose_m4((float (*)[4])self->matrix);
1266         }
1267
1268         (void)BaseMath_WriteCallback(self);
1269         Py_RETURN_NONE;
1270 }
1271
1272 PyDoc_STRVAR(Matrix_transposed_doc,
1273 ".. method:: transposed()\n"
1274 "\n"
1275 "   Return a new, transposed matrix.\n"
1276 "\n"
1277 "   :return: a transposed matrix\n"
1278 "   :rtype: :class:`Matrix`\n"
1279 );
1280 static PyObject *Matrix_transposed(MatrixObject *self)
1281 {
1282         return matrix__apply_to_copy((PyNoArgsFunction)Matrix_transpose, self);
1283 }
1284
1285 /*---------------------------matrix.zero() -----------------------*/
1286 PyDoc_STRVAR(Matrix_zero_doc,
1287 ".. method:: zero()\n"
1288 "\n"
1289 "   Set all the matrix values to zero.\n"
1290 "\n"
1291 "   :return: an instance of itself\n"
1292 "   :rtype: :class:`Matrix`\n"
1293 );
1294 static PyObject *Matrix_zero(MatrixObject *self)
1295 {
1296         fill_vn_fl(self->matrix, self->num_col * self->num_row, 0.0f);
1297
1298         if (BaseMath_WriteCallback(self) == -1)
1299                 return NULL;
1300
1301         Py_RETURN_NONE;
1302 }
1303 /*---------------------------matrix.identity(() ------------------*/
1304 PyDoc_STRVAR(Matrix_identity_doc,
1305 ".. method:: identity()\n"
1306 "\n"
1307 "   Set the matrix to the identity matrix.\n"
1308 "\n"
1309 "   .. note:: An object with zero location and rotation, a scale of one,\n"
1310 "      will have an identity matrix.\n"
1311 "\n"
1312 "   .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n"
1313 );
1314 static PyObject *Matrix_identity(MatrixObject *self)
1315 {
1316         if (BaseMath_ReadCallback(self) == -1)
1317                 return NULL;
1318
1319         if (self->num_col != self->num_row) {
1320                 PyErr_SetString(PyExc_TypeError,
1321                                 "Matrix.identity(): "
1322                                 "only square matrices are supported");
1323                 return NULL;
1324         }
1325
1326         if (self->num_col == 2) {
1327                 MATRIX_ITEM(self, 0, 0) = 1.0f;
1328                 MATRIX_ITEM(self, 0, 1) = 0.0f;
1329                 MATRIX_ITEM(self, 1, 0) = 0.0f;
1330                 MATRIX_ITEM(self, 1, 1) = 1.0f;
1331         }
1332         else if (self->num_col == 3) {
1333                 unit_m3((float (*)[3])self->matrix);
1334         }
1335         else {
1336                 unit_m4((float (*)[4])self->matrix);
1337         }
1338
1339         if (BaseMath_WriteCallback(self) == -1)
1340                 return NULL;
1341
1342         Py_RETURN_NONE;
1343 }
1344
1345 /*---------------------------Matrix.copy() ------------------*/
1346 PyDoc_STRVAR(Matrix_copy_doc,
1347 ".. method:: copy()\n"
1348 "\n"
1349 "   Returns a copy of this matrix.\n"
1350 "\n"
1351 "   :return: an instance of itself\n"
1352 "   :rtype: :class:`Matrix`\n"
1353 );
1354 static PyObject *Matrix_copy(MatrixObject *self)
1355 {
1356         if (BaseMath_ReadCallback(self) == -1)
1357                 return NULL;
1358
1359         return Matrix_CreatePyObject((float (*))self->matrix, self->num_col, self->num_row, Py_NEW, Py_TYPE(self));
1360 }
1361
1362 /*----------------------------print object (internal)-------------*/
1363 /* print the object to screen */
1364 static PyObject *Matrix_repr(MatrixObject *self)
1365 {
1366         int col, row;
1367         PyObject *rows[MATRIX_MAX_DIM] = {NULL};
1368
1369         if (BaseMath_ReadCallback(self) == -1)
1370                 return NULL;
1371
1372         for (row = 0; row < self->num_row; row++) {
1373                 rows[row] = PyTuple_New(self->num_col);
1374                 for (col = 0; col < self->num_col; col++) {
1375                         PyTuple_SET_ITEM(rows[row], col, PyFloat_FromDouble(MATRIX_ITEM(self, row, col)));
1376                 }
1377         }
1378         switch (self->num_row) {
1379         case 2: return PyUnicode_FromFormat("Matrix((%R,\n"
1380                                                                                 "        %R))", rows[0], rows[1]);
1381
1382         case 3: return PyUnicode_FromFormat("Matrix((%R,\n"
1383                                                                                 "        %R,\n"
1384                                                                                 "        %R))", rows[0], rows[1], rows[2]);
1385
1386         case 4: return PyUnicode_FromFormat("Matrix((%R,\n"
1387                                                                                 "        %R,\n"
1388                                                                                 "        %R,\n"
1389                                                                                 "        %R))", rows[0], rows[1], rows[2], rows[3]);
1390         }
1391
1392         Py_FatalError("Matrix(): invalid row size!");
1393         return NULL;
1394 }
1395
1396 static PyObject *Matrix_str(MatrixObject *self)
1397 {
1398         DynStr *ds;
1399
1400         int maxsize[MATRIX_MAX_DIM];
1401         int row, col;
1402
1403         char dummy_buf[1];
1404
1405         if (BaseMath_ReadCallback(self) == -1)
1406                 return NULL;
1407
1408         ds = BLI_dynstr_new();
1409
1410         /* First determine the maximum width for each column */
1411         for (col = 0; col < self->num_col; col++) {
1412                 maxsize[col] = 0;
1413                 for (row = 0; row < self->num_row; row++) {
1414                         int size = BLI_snprintf(dummy_buf, sizeof(dummy_buf), "%.4f", MATRIX_ITEM(self, row, col));
1415                         maxsize[col] = MAX2(maxsize[col], size);
1416                 }
1417         }
1418
1419         /* Now write the unicode string to be printed */
1420         BLI_dynstr_appendf(ds, "<Matrix %dx%d (", self->num_row, self->num_col);
1421         for (row = 0; row < self->num_row; row++) {
1422                 for (col = 0; col < self->num_col; col++) {
1423                         BLI_dynstr_appendf(ds, col ? ", %*.4f" : "%*.4f", maxsize[col], MATRIX_ITEM(self, row, col));
1424                 }
1425                 BLI_dynstr_append(ds, row + 1 != self->num_row ? ")\n             " : ")");
1426         }
1427         BLI_dynstr_append(ds, ">");
1428
1429         return mathutils_dynstr_to_py(ds); /* frees ds */
1430 }
1431
1432 static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
1433 {
1434         PyObject *res;
1435         int ok = -1; /* zero is true */
1436
1437         if (MatrixObject_Check(a) && MatrixObject_Check(b)) {
1438                 MatrixObject *matA = (MatrixObject *)a;
1439                 MatrixObject *matB = (MatrixObject *)b;
1440
1441                 if (BaseMath_ReadCallback(matA) == -1 || BaseMath_ReadCallback(matB) == -1)
1442                         return NULL;
1443
1444                 ok = (  (matA->num_row == matB->num_row) &&
1445                         (matA->num_col == matB->num_col) &&
1446                          EXPP_VectorsAreEqual(matA->matrix, matB->matrix, (matA->num_col * matA->num_row), 1)
1447                         ) ? 0 : -1;
1448         }
1449
1450         switch (op) {
1451         case Py_NE:
1452                 ok = !ok; /* pass through */
1453         case Py_EQ:
1454                 res = ok ? Py_False : Py_True;
1455                 break;
1456
1457         case Py_LT:
1458         case Py_LE:
1459         case Py_GT:
1460         case Py_GE:
1461                 res = Py_NotImplemented;
1462                 break;
1463         default:
1464                 PyErr_BadArgument();
1465                 return NULL;
1466         }
1467
1468         return Py_INCREF(res), res;
1469 }
1470
1471 /*---------------------SEQUENCE PROTOCOLS------------------------
1472   ----------------------------len(object)------------------------
1473   sequence length */
1474 static int Matrix_len(MatrixObject *self)
1475 {
1476         return (self->num_row);
1477 }
1478 /*----------------------------object[]---------------------------
1479   sequence accessor (get)
1480   the wrapped vector gives direct access to the matrix data */
1481 static PyObject *Matrix_item_row(MatrixObject *self, int row)
1482 {
1483         if (BaseMath_ReadCallback(self) == -1)
1484                 return NULL;
1485
1486         if (row < 0 || row >= self->num_row) {
1487                 PyErr_SetString(PyExc_IndexError,
1488                                 "matrix[attribute]: "
1489                                 "array index out of range");
1490                 return NULL;
1491         }
1492         return Vector_CreatePyObject_cb((PyObject *)self, self->num_col, mathutils_matrix_row_cb_index, row);
1493 }
1494 /* same but column access */
1495 static PyObject *Matrix_item_col(MatrixObject *self, int col)
1496 {
1497         if (BaseMath_ReadCallback(self) == -1)
1498                 return NULL;
1499
1500         if (col < 0 || col >= self->num_col) {
1501                 PyErr_SetString(PyExc_IndexError,
1502                                 "matrix[attribute]: "
1503                                 "array index out of range");
1504                 return NULL;
1505         }
1506         return Vector_CreatePyObject_cb((PyObject *)self, self->num_row, mathutils_matrix_col_cb_index, col);
1507 }
1508
1509 /*----------------------------object[]-------------------------
1510   sequence accessor (set) */
1511
1512 static int Matrix_ass_item_row(MatrixObject *self, int row, PyObject *value)
1513 {
1514         int col;
1515         float vec[4];
1516         if (BaseMath_ReadCallback(self) == -1)
1517                 return -1;
1518
1519         if (row >= self->num_row || row < 0) {
1520                 PyErr_SetString(PyExc_IndexError,
1521                                 "matrix[attribute] = x: bad row");
1522                 return -1;
1523         }
1524
1525         if (mathutils_array_parse(vec, self->num_col, self->num_col, value, "matrix[i] = value assignment") < 0) {
1526                 return -1;
1527         }
1528
1529         /* Since we are assigning a row we cannot memcpy */
1530         for (col = 0; col < self->num_col; col++) {
1531                 MATRIX_ITEM(self, row, col) = vec[col];
1532         }
1533
1534         (void)BaseMath_WriteCallback(self);
1535         return 0;
1536 }
1537 static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value)
1538 {
1539         int row;
1540         float vec[4];
1541         if (BaseMath_ReadCallback(self) == -1)
1542                 return -1;
1543
1544         if (col >= self->num_col || col < 0) {
1545                 PyErr_SetString(PyExc_IndexError,
1546                                 "matrix[attribute] = x: bad col");
1547                 return -1;
1548         }
1549
1550         if (mathutils_array_parse(vec, self->num_row, self->num_row, value, "matrix[i] = value assignment") < 0) {
1551                 return -1;
1552         }
1553
1554         /* Since we are assigning a row we cannot memcpy */
1555         for (row = 0; row < self->num_row; row++) {
1556                 MATRIX_ITEM(self, row, col) = vec[row];
1557         }
1558
1559         (void)BaseMath_WriteCallback(self);
1560         return 0;
1561 }
1562
1563
1564 /*----------------------------object[z:y]------------------------
1565   sequence slice (get)*/
1566 static PyObject *Matrix_slice(MatrixObject *self, int begin, int end)
1567 {
1568
1569         PyObject *tuple;
1570         int count;
1571
1572         if (BaseMath_ReadCallback(self) == -1)
1573                 return NULL;
1574
1575         CLAMP(begin, 0, self->num_row);
1576         CLAMP(end, 0, self->num_row);
1577         begin = MIN2(begin, end);
1578
1579         tuple = PyTuple_New(end - begin);
1580         for (count = begin; count < end; count++) {
1581                 PyTuple_SET_ITEM(tuple, count - begin,
1582                                 Vector_CreatePyObject_cb((PyObject *)self, self->num_col, mathutils_matrix_row_cb_index, count));
1583
1584         }
1585
1586         return tuple;
1587 }
1588 /*----------------------------object[z:y]------------------------
1589   sequence slice (set)*/
1590 static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value)
1591 {
1592         PyObject *value_fast = NULL;
1593
1594         if (BaseMath_ReadCallback(self) == -1)
1595                 return -1;
1596
1597         CLAMP(begin, 0, self->num_row);
1598         CLAMP(end, 0, self->num_row);
1599         begin = MIN2(begin, end);
1600
1601         /* non list/tuple cases */
1602         if (!(value_fast = PySequence_Fast(value, "matrix[begin:end] = value"))) {
1603                 /* PySequence_Fast sets the error */
1604                 return -1;
1605         }
1606         else {
1607                 const int size = end - begin;
1608                 int row, col;
1609                 float mat[16];
1610                 float vec[4];
1611
1612                 if (PySequence_Fast_GET_SIZE(value_fast) != size) {
1613                         Py_DECREF(value_fast);
1614                         PyErr_SetString(PyExc_ValueError,
1615                                         "matrix[begin:end] = []: "
1616                                         "size mismatch in slice assignment");
1617                         return -1;
1618                 }
1619
1620                 memcpy(mat, self->matrix, self->num_col * self->num_row * sizeof(float));
1621
1622                 /* parse sub items */
1623                 for (row = begin; row < end; row++) {
1624                         /* parse each sub sequence */
1625                         PyObject *item = PySequence_Fast_GET_ITEM(value_fast, row - begin);
1626
1627                         if (mathutils_array_parse(vec, self->num_col, self->num_col, item, "matrix[begin:end] = value assignment") < 0)
1628                                 return -1;
1629
1630                         for (col = 0; col < self->num_col; col++) {
1631                                 mat[col * self->num_row + row] = vec[col];
1632                         }
1633                 }
1634
1635                 Py_DECREF(value_fast);
1636
1637                 /*parsed well - now set in matrix*/
1638                 memcpy(self->matrix, mat, self->num_col * self->num_row * sizeof(float));
1639
1640                 (void)BaseMath_WriteCallback(self);
1641                 return 0;
1642         }
1643 }
1644 /*------------------------NUMERIC PROTOCOLS----------------------
1645   ------------------------obj + obj------------------------------*/
1646 static PyObject *Matrix_add(PyObject *m1, PyObject *m2)
1647 {
1648         float mat[16];
1649         MatrixObject *mat1 = NULL, *mat2 = NULL;
1650
1651         mat1 = (MatrixObject *)m1;
1652         mat2 = (MatrixObject *)m2;
1653
1654         if (!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
1655                 PyErr_Format(PyExc_TypeError,
1656                              "Matrix addition: (%s + %s) "
1657                              "invalid type for this operation",
1658                              Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
1659                 return NULL;
1660         }
1661
1662         if (BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1)
1663                 return NULL;
1664
1665         if (mat1->num_col != mat2->num_col || mat1->num_row != mat2->num_row) {
1666                 PyErr_SetString(PyExc_TypeError,
1667                                 "Matrix addition: "
1668                                 "matrices must have the same dimensions for this operation");
1669                 return NULL;
1670         }
1671
1672         add_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
1673
1674         return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1));
1675 }
1676 /*------------------------obj - obj------------------------------
1677   subtraction*/
1678 static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
1679 {
1680         float mat[16];
1681         MatrixObject *mat1 = NULL, *mat2 = NULL;
1682
1683         mat1 = (MatrixObject *)m1;
1684         mat2 = (MatrixObject *)m2;
1685
1686         if (!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
1687                 PyErr_Format(PyExc_TypeError,
1688                              "Matrix subtraction: (%s - %s) "
1689                              "invalid type for this operation",
1690                              Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name
1691                              );
1692                 return NULL;
1693         }
1694
1695         if (BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1)
1696                 return NULL;
1697
1698         if (mat1->num_col != mat2->num_col || mat1->num_row != mat2->num_row) {
1699                 PyErr_SetString(PyExc_TypeError,
1700                                 "Matrix addition: "
1701                                 "matrices must have the same dimensions for this operation");
1702                 return NULL;
1703         }
1704
1705         sub_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
1706
1707         return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1));
1708 }
1709 /*------------------------obj * obj------------------------------
1710   mulplication*/
1711 static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
1712 {
1713         float tmat[16];
1714         mul_vn_vn_fl(tmat, mat->matrix, mat->num_col * mat->num_row, scalar);
1715         return Matrix_CreatePyObject(tmat, mat->num_col, mat->num_row, Py_NEW, Py_TYPE(mat));
1716 }
1717
1718 static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
1719 {
1720         float scalar;
1721         int vec_size;
1722
1723         MatrixObject *mat1 = NULL, *mat2 = NULL;
1724
1725         if (MatrixObject_Check(m1)) {
1726                 mat1 = (MatrixObject *)m1;
1727                 if (BaseMath_ReadCallback(mat1) == -1)
1728                         return NULL;
1729         }
1730         if (MatrixObject_Check(m2)) {
1731                 mat2 = (MatrixObject *)m2;
1732                 if (BaseMath_ReadCallback(mat2) == -1)
1733                         return NULL;
1734         }
1735
1736         if (mat1 && mat2) {
1737                 /* MATRIX * MATRIX */
1738                 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f,
1739                                  0.0f, 0.0f, 0.0f, 0.0f,
1740                                  0.0f, 0.0f, 0.0f, 0.0f,
1741                                  0.0f, 0.0f, 0.0f, 1.0f};
1742                 double dot = 0.0f;
1743                 int col, row, item;
1744
1745                 if (mat1->num_col != mat2->num_row) {
1746                         PyErr_SetString(PyExc_ValueError,
1747                                                         "matrix1 * matrix2: matrix1 number of columns "
1748                                                         "and the matrix2 number of rows must be the same");
1749                         return NULL;
1750                 }
1751
1752                 for (col = 0; col < mat2->num_col; col++) {
1753                         for (row = 0; row < mat1->num_row; row++) {
1754                                 for (item = 0; item < mat1->num_col; item++) {
1755                                         dot += MATRIX_ITEM(mat1, row, item) * MATRIX_ITEM(mat2, item, col);
1756                                 }
1757                                 mat[(col * mat1->num_row) + row] = (float)dot;
1758                                 dot = 0.0f;
1759                         }
1760                 }
1761
1762                 return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1));
1763         }
1764         else if (mat2) {
1765                 /*FLOAT/INT * MATRIX */
1766                 if (((scalar = PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred()) == 0) {
1767                         return matrix_mul_float(mat2, scalar);
1768                 }
1769         }
1770         else if (mat1) {
1771                 /* MATRIX * VECTOR */
1772                 if (VectorObject_Check(m2)) {
1773                         VectorObject *vec2 = (VectorObject *)m2;
1774                         float tvec[4];
1775                         if (BaseMath_ReadCallback(vec2) == -1)
1776                                 return NULL;
1777                         if (column_vector_multiplication(tvec, vec2, mat1) == -1) {
1778                                 return NULL;
1779                         }
1780
1781                         if (mat1->num_col == 4 && vec2->size == 3) {
1782                                 vec_size = 3;
1783                         }
1784                         else {
1785                                 vec_size = mat1->num_row;
1786                         }
1787
1788                         return Vector_CreatePyObject(tvec, vec_size, Py_NEW, Py_TYPE(m2));
1789                 }
1790                 /*FLOAT/INT * MATRIX */
1791                 else if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) {
1792                         return matrix_mul_float(mat1, scalar);
1793                 }
1794         }
1795         else {
1796                 BLI_assert(!"internal error");
1797         }
1798
1799         PyErr_Format(PyExc_TypeError,
1800                      "Matrix multiplication: "
1801                      "not supported between '%.200s' and '%.200s' types",
1802                      Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
1803         return NULL;
1804 }
1805 static PyObject *Matrix_inv(MatrixObject *self)
1806 {
1807         if (BaseMath_ReadCallback(self) == -1)
1808                 return NULL;
1809
1810         return Matrix_invert(self);
1811 }
1812
1813 /*-----------------PROTOCOL DECLARATIONS--------------------------*/
1814 static PySequenceMethods Matrix_SeqMethods = {
1815         (lenfunc) Matrix_len,                                           /* sq_length */
1816         (binaryfunc) NULL,                                                      /* sq_concat */
1817         (ssizeargfunc) NULL,                                            /* sq_repeat */
1818         (ssizeargfunc) Matrix_item_row,                         /* sq_item */
1819         (ssizessizeargfunc) NULL,                                       /* sq_slice, deprecated */
1820         (ssizeobjargproc) Matrix_ass_item_row,          /* sq_ass_item */
1821         (ssizessizeobjargproc) NULL,                            /* sq_ass_slice, deprecated */
1822         (objobjproc) NULL,                                                      /* sq_contains */
1823         (binaryfunc) NULL,                                                      /* sq_inplace_concat */
1824         (ssizeargfunc) NULL,                                            /* sq_inplace_repeat */
1825 };
1826
1827
1828 static PyObject *Matrix_subscript(MatrixObject *self, PyObject *item)
1829 {
1830         if (PyIndex_Check(item)) {
1831                 Py_ssize_t i;
1832                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1833                 if (i == -1 && PyErr_Occurred())
1834                         return NULL;
1835                 if (i < 0)
1836                         i += self->num_row;
1837                 return Matrix_item_row(self, i);
1838         }
1839         else if (PySlice_Check(item)) {
1840                 Py_ssize_t start, stop, step, slicelength;
1841
1842                 if (PySlice_GetIndicesEx((void *)item, self->num_row, &start, &stop, &step, &slicelength) < 0)
1843                         return NULL;
1844
1845                 if (slicelength <= 0) {
1846                         return PyTuple_New(0);
1847                 }
1848                 else if (step == 1) {
1849                         return Matrix_slice(self, start, stop);
1850                 }
1851                 else {
1852                         PyErr_SetString(PyExc_IndexError,
1853                                         "slice steps not supported with matrices");
1854                         return NULL;
1855                 }
1856         }
1857         else {
1858                 PyErr_Format(PyExc_TypeError,
1859                              "matrix indices must be integers, not %.200s",
1860                              Py_TYPE(item)->tp_name);
1861                 return NULL;
1862         }
1863 }
1864
1865 static int Matrix_ass_subscript(MatrixObject *self, PyObject *item, PyObject *value)
1866 {
1867         if (PyIndex_Check(item)) {
1868                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1869                 if (i == -1 && PyErr_Occurred())
1870                         return -1;
1871                 if (i < 0)
1872                         i += self->num_row;
1873                 return Matrix_ass_item_row(self, i, value);
1874         }
1875         else if (PySlice_Check(item)) {
1876                 Py_ssize_t start, stop, step, slicelength;
1877
1878                 if (PySlice_GetIndicesEx((void *)item, self->num_row, &start, &stop, &step, &slicelength) < 0)
1879                         return -1;
1880
1881                 if (step == 1)
1882                         return Matrix_ass_slice(self, start, stop, value);
1883                 else {
1884                         PyErr_SetString(PyExc_IndexError,
1885                                         "slice steps not supported with matrices");
1886                         return -1;
1887                 }
1888         }
1889         else {
1890                 PyErr_Format(PyExc_TypeError,
1891                              "matrix indices must be integers, not %.200s",
1892                              Py_TYPE(item)->tp_name);
1893                 return -1;
1894         }
1895 }
1896
1897 static PyMappingMethods Matrix_AsMapping = {
1898         (lenfunc)Matrix_len,
1899         (binaryfunc)Matrix_subscript,
1900         (objobjargproc)Matrix_ass_subscript
1901 };
1902
1903
1904 static PyNumberMethods Matrix_NumMethods = {
1905                 (binaryfunc)    Matrix_add,     /*nb_add*/
1906                 (binaryfunc)    Matrix_sub,     /*nb_subtract*/
1907                 (binaryfunc)    Matrix_mul,     /*nb_multiply*/
1908                 NULL,                                                   /*nb_remainder*/
1909                 NULL,                                                   /*nb_divmod*/
1910                 NULL,                                                   /*nb_power*/
1911                 (unaryfunc)     0,      /*nb_negative*/
1912                 (unaryfunc)     0,      /*tp_positive*/
1913                 (unaryfunc)     0,      /*tp_absolute*/
1914                 (inquiry)       0,      /*tp_bool*/
1915                 (unaryfunc)     Matrix_inv,     /*nb_invert*/
1916                 NULL,                           /*nb_lshift*/
1917                 (binaryfunc)0,  /*nb_rshift*/
1918                 NULL,                           /*nb_and*/
1919                 NULL,                           /*nb_xor*/
1920                 NULL,                           /*nb_or*/
1921                 NULL,                           /*nb_int*/
1922                 NULL,                           /*nb_reserved*/
1923                 NULL,                           /*nb_float*/
1924                 NULL,                           /* nb_inplace_add */
1925                 NULL,                           /* nb_inplace_subtract */
1926                 NULL,                           /* nb_inplace_multiply */
1927                 NULL,                           /* nb_inplace_remainder */
1928                 NULL,                           /* nb_inplace_power */
1929                 NULL,                           /* nb_inplace_lshift */
1930                 NULL,                           /* nb_inplace_rshift */
1931                 NULL,                           /* nb_inplace_and */
1932                 NULL,                           /* nb_inplace_xor */
1933                 NULL,                           /* nb_inplace_or */
1934                 NULL,                           /* nb_floor_divide */
1935                 NULL,                           /* nb_true_divide */
1936                 NULL,                           /* nb_inplace_floor_divide */
1937                 NULL,                           /* nb_inplace_true_divide */
1938                 NULL,                           /* nb_index */
1939 };
1940
1941 PyDoc_STRVAR(Matrix_row_size_doc,
1942 "The row size of the matrix (readonly).\n\n:type: int"
1943 );
1944 static PyObject *Matrix_row_size_get(MatrixObject *self, void *UNUSED(closure))
1945 {
1946         return PyLong_FromLong((long) self->num_col);
1947 }
1948
1949 PyDoc_STRVAR(Matrix_col_size_doc,
1950 "The column size of the matrix (readonly).\n\n:type: int"
1951 );
1952 static PyObject *Matrix_col_size_get(MatrixObject *self, void *UNUSED(closure))
1953 {
1954         return PyLong_FromLong((long) self->num_row);
1955 }
1956
1957 PyDoc_STRVAR(Matrix_translation_doc,
1958 "The translation component of the matrix.\n\n:type: Vector"
1959 );
1960 static PyObject *Matrix_translation_get(MatrixObject *self, void *UNUSED(closure))
1961 {
1962         PyObject *ret;
1963
1964         if (BaseMath_ReadCallback(self) == -1)
1965                 return NULL;
1966
1967         /*must be 4x4 square matrix*/
1968         if (self->num_row != 4 || self->num_col != 4) {
1969                 PyErr_SetString(PyExc_AttributeError,
1970                                 "Matrix.translation: "
1971                                 "inappropriate matrix size, must be 4x4");
1972                 return NULL;
1973         }
1974
1975         ret = (PyObject *)Vector_CreatePyObject_cb((PyObject *)self, 3, mathutils_matrix_col_cb_index, 3);
1976
1977         return ret;
1978 }
1979
1980 static int Matrix_translation_set(MatrixObject *self, PyObject *value, void *UNUSED(closure))
1981 {
1982         float tvec[3];
1983
1984         if (BaseMath_ReadCallback(self) == -1)
1985                 return -1;
1986
1987         /*must be 4x4 square matrix*/
1988         if (self->num_row != 4 || self->num_col != 4) {
1989                 PyErr_SetString(PyExc_AttributeError,
1990                                 "Matrix.translation: "
1991                                 "inappropriate matrix size, must be 4x4");
1992                 return -1;
1993         }
1994
1995         if ((mathutils_array_parse(tvec, 3, 3, value, "Matrix.translation")) == -1)
1996                 return -1;
1997
1998         copy_v3_v3(((float (*)[4])self->matrix)[3], tvec);
1999
2000         (void)BaseMath_WriteCallback(self);
2001
2002         return 0;
2003 }
2004
2005 PyDoc_STRVAR(Matrix_row_doc,
2006 "Access the matix by rows (default), (readonly).\n\n:type: Matrix Access"
2007 );
2008 static PyObject *Matrix_row_get(MatrixObject *self, void *UNUSED(closure))
2009 {
2010         return MatrixAccess_CreatePyObject(self, MAT_ACCESS_ROW);
2011 }
2012
2013 PyDoc_STRVAR(Matrix_col_doc,
2014 "Access the matix by colums, 3x3 and 4x4 only, (readonly).\n\n:type: Matrix Access"
2015 );
2016 static PyObject *Matrix_col_get(MatrixObject *self, void *UNUSED(closure))
2017 {
2018         return MatrixAccess_CreatePyObject(self, MAT_ACCESS_COL);
2019 }
2020
2021 PyDoc_STRVAR(Matrix_median_scale_doc,
2022 "The average scale applied to each axis (readonly).\n\n:type: float"
2023 );
2024 static PyObject *Matrix_median_scale_get(MatrixObject *self, void *UNUSED(closure))
2025 {
2026         float mat[3][3];
2027
2028         if (BaseMath_ReadCallback(self) == -1)
2029                 return NULL;
2030
2031         /*must be 3-4 cols, 3-4 rows, square matrix*/
2032         if ((self->num_row < 3) || (self->num_col < 3)) {
2033                 PyErr_SetString(PyExc_AttributeError,
2034                                 "Matrix.median_scale: "
2035                                 "inappropriate matrix size, 3x3 minimum");
2036                 return NULL;
2037         }
2038
2039         matrix_as_3x3(mat, self);
2040
2041         return PyFloat_FromDouble(mat3_to_scale(mat));
2042 }
2043
2044 PyDoc_STRVAR(Matrix_is_negative_doc,
2045 "True if this matrix results in a negative scale, 3x3 and 4x4 only, (readonly).\n\n:type: bool"
2046 );
2047 static PyObject *Matrix_is_negative_get(MatrixObject *self, void *UNUSED(closure))
2048 {
2049         if (BaseMath_ReadCallback(self) == -1)
2050                 return NULL;
2051
2052         /*must be 3-4 cols, 3-4 rows, square matrix*/
2053         if (self->num_row == 4 && self->num_col == 4)
2054                 return PyBool_FromLong(is_negative_m4((float (*)[4])self->matrix));
2055         else if (self->num_row == 3 && self->num_col == 3)
2056                 return PyBool_FromLong(is_negative_m3((float (*)[3])self->matrix));
2057         else {
2058                 PyErr_SetString(PyExc_AttributeError,
2059                                 "Matrix.is_negative: "
2060                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
2061                 return NULL;
2062         }
2063 }
2064
2065 PyDoc_STRVAR(Matrix_is_orthogonal_doc,
2066 "True if this matrix is orthogonal, 3x3 and 4x4 only, (readonly).\n\n:type: bool"
2067 );
2068 static PyObject *Matrix_is_orthogonal_get(MatrixObject *self, void *UNUSED(closure))
2069 {
2070         if (BaseMath_ReadCallback(self) == -1)
2071                 return NULL;
2072
2073         /*must be 3-4 cols, 3-4 rows, square matrix*/
2074         if (self->num_row == 4 && self->num_col == 4)
2075                 return PyBool_FromLong(is_orthogonal_m4((float (*)[4])self->matrix));
2076         else if (self->num_row == 3 && self->num_col == 3)
2077                 return PyBool_FromLong(is_orthogonal_m3((float (*)[3])self->matrix));
2078         else {
2079                 PyErr_SetString(PyExc_AttributeError,
2080                                 "Matrix.is_orthogonal: "
2081                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
2082                 return NULL;
2083         }
2084 }
2085
2086 /*****************************************************************************/
2087 /* Python attributes get/set structure:                                      */
2088 /*****************************************************************************/
2089 static PyGetSetDef Matrix_getseters[] = {
2090         {(char *)"row_size", (getter)Matrix_row_size_get, (setter)NULL, Matrix_row_size_doc, NULL},
2091         {(char *)"col_size", (getter)Matrix_col_size_get, (setter)NULL, Matrix_col_size_doc, NULL},
2092         {(char *)"median_scale", (getter)Matrix_median_scale_get, (setter)NULL, Matrix_median_scale_doc, NULL},
2093         {(char *)"translation", (getter)Matrix_translation_get, (setter)Matrix_translation_set, Matrix_translation_doc, NULL},
2094         {(char *)"row", (getter)Matrix_row_get, (setter)NULL, Matrix_row_doc, NULL},
2095         {(char *)"col", (getter)Matrix_col_get, (setter)NULL, Matrix_col_doc, NULL},
2096         {(char *)"is_negative", (getter)Matrix_is_negative_get, (setter)NULL, Matrix_is_negative_doc, NULL},
2097         {(char *)"is_orthogonal", (getter)Matrix_is_orthogonal_get, (setter)NULL, Matrix_is_orthogonal_doc, NULL},
2098         {(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL},
2099         {(char *)"owner",(getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
2100         {NULL, NULL, NULL, NULL, NULL}  /* Sentinel */
2101 };
2102
2103 /*-----------------------METHOD DEFINITIONS ----------------------*/
2104 static struct PyMethodDef Matrix_methods[] = {
2105         /* derived values */
2106         {"determinant", (PyCFunction) Matrix_determinant, METH_NOARGS, Matrix_determinant_doc},
2107         {"decompose", (PyCFunction) Matrix_decompose, METH_NOARGS, Matrix_decompose_doc},
2108
2109         /* in place only */
2110         {"zero", (PyCFunction) Matrix_zero, METH_NOARGS, Matrix_zero_doc},
2111         {"identity", (PyCFunction) Matrix_identity, METH_NOARGS, Matrix_identity_doc},
2112
2113         /* operate on original or copy */
2114         {"transpose", (PyCFunction) Matrix_transpose, METH_NOARGS, Matrix_transpose_doc},
2115         {"transposed", (PyCFunction) Matrix_transposed, METH_NOARGS, Matrix_transposed_doc},
2116         {"invert", (PyCFunction) Matrix_invert, METH_NOARGS, Matrix_invert_doc},
2117         {"inverted", (PyCFunction) Matrix_inverted, METH_NOARGS, Matrix_inverted_doc},
2118         {"to_3x3", (PyCFunction) Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc},
2119         // TODO. {"resize_3x3", (PyCFunction) Matrix_resize3x3, METH_NOARGS, Matrix_resize3x3_doc},
2120         {"to_4x4", (PyCFunction) Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc},
2121         {"resize_4x4", (PyCFunction) Matrix_resize_4x4, METH_NOARGS, Matrix_resize_4x4_doc},
2122         {"rotate", (PyCFunction) Matrix_rotate, METH_O, Matrix_rotate_doc},
2123
2124         /* return converted representation */
2125         {"to_euler", (PyCFunction) Matrix_to_euler, METH_VARARGS, Matrix_to_euler_doc},
2126         {"to_quaternion", (PyCFunction) Matrix_to_quaternion, METH_NOARGS, Matrix_to_quaternion_doc},
2127         {"to_scale", (PyCFunction) Matrix_to_scale, METH_NOARGS, Matrix_to_scale_doc},
2128         {"to_translation", (PyCFunction) Matrix_to_translation, METH_NOARGS, Matrix_to_translation_doc},
2129
2130         /* operation between 2 or more types  */
2131         {"lerp", (PyCFunction) Matrix_lerp, METH_VARARGS, Matrix_lerp_doc},
2132         {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
2133         {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
2134
2135         /* class methods */
2136         {"Rotation", (PyCFunction) C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc},
2137         {"Scale", (PyCFunction) C_Matrix_Scale, METH_VARARGS | METH_CLASS, C_Matrix_Scale_doc},
2138         {"Shear", (PyCFunction) C_Matrix_Shear, METH_VARARGS | METH_CLASS, C_Matrix_Shear_doc},
2139         {"Translation", (PyCFunction) C_Matrix_Translation, METH_O | METH_CLASS, C_Matrix_Translation_doc},
2140         {"OrthoProjection", (PyCFunction) C_Matrix_OrthoProjection,  METH_VARARGS | METH_CLASS, C_Matrix_OrthoProjection_doc},
2141         {NULL, NULL, 0, NULL}
2142 };
2143
2144 /*------------------PY_OBECT DEFINITION--------------------------*/
2145 PyDoc_STRVAR(matrix_doc,
2146 "This object gives access to Matrices in Blender."
2147 );
2148 PyTypeObject matrix_Type = {
2149         PyVarObject_HEAD_INIT(NULL, 0)
2150         "mathutils.Matrix",                                     /*tp_name*/
2151         sizeof(MatrixObject),                           /*tp_basicsize*/
2152         0,                                                                      /*tp_itemsize*/
2153         (destructor)BaseMathObject_dealloc,     /*tp_dealloc*/
2154         NULL,                                                           /*tp_print*/
2155         NULL,                                                           /*tp_getattr*/
2156         NULL,                                                           /*tp_setattr*/
2157         NULL,                                                           /*tp_compare*/
2158         (reprfunc) Matrix_repr,                         /*tp_repr*/
2159         &Matrix_NumMethods,                                     /*tp_as_number*/
2160         &Matrix_SeqMethods,                                     /*tp_as_sequence*/
2161         &Matrix_AsMapping,                                      /*tp_as_mapping*/
2162         NULL,                                                           /*tp_hash*/
2163         NULL,                                                           /*tp_call*/
2164         (reprfunc) Matrix_str,                          /*tp_str*/
2165         NULL,                                                           /*tp_getattro*/
2166         NULL,                                                           /*tp_setattro*/
2167         NULL,                                                           /*tp_as_buffer*/
2168         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
2169         matrix_doc,                                                     /*tp_doc*/
2170         (traverseproc)BaseMathObject_traverse,  //tp_traverse
2171         (inquiry)BaseMathObject_clear,  //tp_clear
2172         (richcmpfunc)Matrix_richcmpr,           /*tp_richcompare*/
2173         0,                                                                      /*tp_weaklistoffset*/
2174         NULL,                                                           /*tp_iter*/
2175         NULL,                                                           /*tp_iternext*/
2176         Matrix_methods,                                         /*tp_methods*/
2177         NULL,                                                           /*tp_members*/
2178         Matrix_getseters,                                       /*tp_getset*/
2179         NULL,                                                           /*tp_base*/
2180         NULL,                                                           /*tp_dict*/
2181         NULL,                                                           /*tp_descr_get*/
2182         NULL,                                                           /*tp_descr_set*/
2183         0,                                                                      /*tp_dictoffset*/
2184         NULL,                                                           /*tp_init*/
2185         NULL,                                                           /*tp_alloc*/
2186         Matrix_new,                                                     /*tp_new*/
2187         NULL,                                                           /*tp_free*/
2188         NULL,                                                           /*tp_is_gc*/
2189         NULL,                                                           /*tp_bases*/
2190         NULL,                                                           /*tp_mro*/
2191         NULL,                                                           /*tp_cache*/
2192         NULL,                                                           /*tp_subclasses*/
2193         NULL,                                                           /*tp_weaklist*/
2194         NULL                                                            /*tp_del*/
2195 };
2196
2197 /* pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
2198  * (i.e. it was allocated elsewhere by MEM_mallocN())
2199  * pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
2200  * (i.e. it must be created here with PyMEM_malloc()) */
2201 PyObject *Matrix_CreatePyObject(float *mat,
2202                                 const unsigned short num_col, const unsigned short num_row,
2203                                 int type, PyTypeObject *base_type)
2204 {
2205         MatrixObject *self;
2206
2207         /* matrix objects can be any 2-4row x 2-4col matrix */
2208         if (num_col < 2 || num_col > 4 || num_row < 2 || num_row > 4) {
2209                 PyErr_SetString(PyExc_RuntimeError,
2210                                 "Matrix(): "
2211                                 "row and column sizes must be between 2 and 4");
2212                 return NULL;
2213         }
2214
2215         self = base_type ? (MatrixObject *)base_type->tp_alloc(base_type, 0) :
2216                            (MatrixObject *)PyObject_GC_New(MatrixObject, &matrix_Type);
2217
2218         if (self) {
2219                 self->num_col = num_col;
2220                 self->num_row = num_row;
2221
2222                 /* init callbacks as NULL */
2223                 self->cb_user = NULL;
2224                 self->cb_type = self->cb_subtype = 0;
2225
2226                 if (type == Py_WRAP) {
2227                         self->matrix = mat;
2228                         self->wrapped = Py_WRAP;
2229                 }
2230                 else if (type == Py_NEW) {
2231                         self->matrix = PyMem_Malloc(num_col * num_row * sizeof(float));
2232                         if (self->matrix == NULL) { /*allocation failure*/
2233                                 PyErr_SetString(PyExc_MemoryError,
2234                                                 "Matrix(): "
2235                                                 "problem allocating pointer space");
2236                                 return NULL;
2237                         }
2238
2239                         if (mat) {      /*if a float array passed*/
2240                                 memcpy(self->matrix, mat, num_col * num_row * sizeof(float));
2241                         }
2242                         else if (num_col == num_row) {
2243                                 /* or if no arguments are passed return identity matrix for square matrices */
2244                                 PyObject *ret_dummy = Matrix_identity(self);
2245                                 Py_DECREF(ret_dummy);
2246                         }
2247                         else {
2248                                 /* otherwise zero everything */
2249                                 memset(self->matrix, 0, num_col * num_row * sizeof(float));
2250                         }
2251                         self->wrapped = Py_NEW;
2252                 }
2253                 else {
2254                         Py_FatalError("Matrix(): invalid type!");
2255                         return NULL;
2256                 }
2257         }
2258         return (PyObject *) self;
2259 }
2260
2261 PyObject *Matrix_CreatePyObject_cb(PyObject *cb_user,
2262                                    const unsigned short num_col, const unsigned short num_row,
2263                                    int cb_type, int cb_subtype)
2264 {
2265         MatrixObject *self = (MatrixObject *)Matrix_CreatePyObject(NULL, num_col, num_row, Py_NEW, NULL);
2266         if (self) {
2267                 Py_INCREF(cb_user);
2268                 self->cb_user =                 cb_user;
2269                 self->cb_type =                 (unsigned char)cb_type;
2270                 self->cb_subtype =              (unsigned char)cb_subtype;
2271                 PyObject_GC_Track(self);
2272         }
2273         return (PyObject *) self;
2274 }
2275
2276
2277 /* ----------------------------------------------------------------------------
2278  * special type for alaternate access */
2279
2280 typedef struct {
2281         PyObject_HEAD /* required python macro   */
2282         MatrixObject *matrix_user;
2283         eMatrixAccess_t type;
2284 } MatrixAccessObject;
2285
2286 static int MatrixAccess_traverse(MatrixAccessObject *self, visitproc visit, void *arg)
2287 {
2288         Py_VISIT(self->matrix_user);
2289         return 0;
2290 }
2291
2292 int MatrixAccess_clear(MatrixAccessObject *self)
2293 {
2294         Py_CLEAR(self->matrix_user);
2295         return 0;
2296 }
2297
2298 void MatrixAccess_dealloc(MatrixAccessObject *self)
2299 {
2300         if (self->matrix_user) {
2301                 PyObject_GC_UnTrack(self);
2302                 MatrixAccess_clear(self);
2303         }
2304
2305         Py_TYPE(self)->tp_free(self);
2306 }
2307
2308 /* sequence access */
2309
2310 static int MatrixAccess_len(MatrixAccessObject *self)
2311 {
2312         return (self->type == MAT_ACCESS_ROW) ?
2313                     self->matrix_user->num_row :
2314                     self->matrix_user->num_col;
2315 }
2316
2317 static PyObject *MatrixAccess_subscript(MatrixAccessObject *self, PyObject *item)
2318 {
2319         MatrixObject *matrix_user = self->matrix_user;
2320
2321         if (PyIndex_Check(item)) {
2322                 Py_ssize_t i;
2323                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2324                 if (i == -1 && PyErr_Occurred())
2325                         return NULL;
2326                 if (self->type == MAT_ACCESS_ROW) {
2327                         if (i < 0)
2328                                 i += matrix_user->num_row;
2329                         return Matrix_item_row(matrix_user, i);
2330                 }
2331                 else { /* MAT_ACCESS_ROW */
2332                         if (i < 0)
2333                                 i += matrix_user->num_col;
2334                         return Matrix_item_col(matrix_user, i);
2335                 }
2336         }
2337         /* TODO, slice */
2338         else {
2339                 PyErr_Format(PyExc_TypeError,
2340                              "matrix indices must be integers, not %.200s",
2341                              Py_TYPE(item)->tp_name);
2342                 return NULL;
2343         }
2344 }
2345
2346 static int MatrixAccess_ass_subscript(MatrixAccessObject *self, PyObject *item, PyObject *value)
2347 {
2348         MatrixObject *matrix_user = self->matrix_user;
2349
2350         if (PyIndex_Check(item)) {
2351                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2352                 if (i == -1 && PyErr_Occurred())
2353                         return -1;
2354
2355                 if (self->type == MAT_ACCESS_ROW) {
2356                         if (i < 0)
2357                                 i += matrix_user->num_row;
2358                         return Matrix_ass_item_row(matrix_user, i, value);
2359                 }
2360                 else { /* MAT_ACCESS_ROW */
2361                         if (i < 0)
2362                                 i += matrix_user->num_col;
2363                         return Matrix_ass_item_col(matrix_user, i, value);
2364                 }
2365
2366         }
2367         /* TODO, slice */
2368         else {
2369                 PyErr_Format(PyExc_TypeError,
2370                              "matrix indices must be integers, not %.200s",
2371                              Py_TYPE(item)->tp_name);
2372                 return -1;
2373         }
2374 }
2375
2376
2377 static PyMappingMethods MatrixAccess_AsMapping = {
2378         (lenfunc)MatrixAccess_len,
2379         (binaryfunc)MatrixAccess_subscript,
2380         (objobjargproc) MatrixAccess_ass_subscript
2381 };
2382
2383 PyTypeObject matrix_access_Type = {
2384         PyVarObject_HEAD_INIT(NULL, 0)
2385         "MatrixAccess",                                         /*tp_name*/
2386         sizeof(MatrixAccessObject),                     /*tp_basicsize*/
2387         0,                                                                      /*tp_itemsize*/
2388         (destructor)MatrixAccess_dealloc,       /*tp_dealloc*/
2389         NULL,                                                           /*tp_print*/
2390         NULL,                                                           /*tp_getattr*/
2391         NULL,                                                           /*tp_setattr*/
2392         NULL,                                                           /*tp_compare*/
2393         NULL,                                                           /*tp_repr*/
2394         NULL,                                                           /*tp_as_number*/
2395         NULL /*&MatrixAccess_SeqMethods*/ /* TODO */,                   /*tp_as_sequence*/
2396         &MatrixAccess_AsMapping,                        /*tp_as_mapping*/
2397         NULL,                                                           /*tp_hash*/
2398         NULL,                                                           /*tp_call*/
2399         NULL,                                                           /*tp_str*/
2400         NULL,                                                           /*tp_getattro*/
2401         NULL,                                                           /*tp_setattro*/
2402         NULL,                                                           /*tp_as_buffer*/
2403         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
2404         NULL,                                                           /*tp_doc*/
2405         (traverseproc)MatrixAccess_traverse,    //tp_traverse
2406         (inquiry)MatrixAccess_clear,    //tp_clear
2407         NULL /* (richcmpfunc)MatrixAccess_richcmpr */ /* TODO*/, /*tp_richcompare*/
2408 };
2409
2410 static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type)
2411 {
2412         MatrixAccessObject *matrix_access = (MatrixAccessObject *)PyObject_GC_New(MatrixObject, &matrix_access_Type);
2413
2414         matrix_access->matrix_user = matrix;
2415         Py_INCREF(matrix);
2416
2417         matrix_access->type = type;
2418
2419         return (PyObject *)matrix_access;
2420 }
2421
2422 /* end special access
2423  * -------------------------------------------------------------------------- */