5be4fdedff1f12d920073b8bea688334c1542740
[blender.git] / source / blender / python / mathutils / mathutils_Matrix.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Michel Selten & Joseph Gilbert
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/python/mathutils/mathutils_Matrix.c
24  *  \ingroup pymathutils
25  */
26
27
28 #include <Python.h>
29
30 #include "mathutils.h"
31
32 #include "BLI_math.h"
33 #include "BLI_utildefines.h"
34
35 #ifndef MATH_STANDALONE
36 #  include "BLI_string.h"
37 #  include "BLI_dynstr.h"
38 #endif
39
40 typedef enum eMatrixAccess_t {
41         MAT_ACCESS_ROW,
42         MAT_ACCESS_COL
43 } eMatrixAccess_t;
44
45 static PyObject *Matrix_copy_notest(MatrixObject *self, const float *matrix);
46 static PyObject *Matrix_copy(MatrixObject *self);
47 static PyObject *Matrix_deepcopy(MatrixObject *self, PyObject *args);
48 static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value);
49 static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self);
50 static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type);
51
52 static int matrix_row_vector_check(MatrixObject *mat, VectorObject *vec, int row)
53 {
54         if ((vec->size != mat->num_col) || (row >= mat->num_row)) {
55                 PyErr_SetString(PyExc_AttributeError,
56                                 "Matrix(): "
57                                 "owner matrix has been resized since this row vector was created");
58                 return 0;
59         }
60         else {
61                 return 1;
62         }
63 }
64
65 static int matrix_col_vector_check(MatrixObject *mat, VectorObject *vec, int col)
66 {
67         if ((vec->size != mat->num_row) || (col >= mat->num_col)) {
68                 PyErr_SetString(PyExc_AttributeError,
69                                 "Matrix(): "
70                                 "owner matrix has been resized since this column vector was created");
71                 return 0;
72         }
73         else {
74                 return 1;
75         }
76 }
77
78 /* ----------------------------------------------------------------------------
79  * matrix row callbacks
80  * this is so you can do matrix[i][j] = val OR matrix.row[i][j] = val */
81
82 unsigned char mathutils_matrix_row_cb_index = -1;
83
84 static int mathutils_matrix_row_check(BaseMathObject *bmo)
85 {
86         MatrixObject *self = (MatrixObject *)bmo->cb_user;
87         return BaseMath_ReadCallback(self);
88 }
89
90 static int mathutils_matrix_row_get(BaseMathObject *bmo, int row)
91 {
92         MatrixObject *self = (MatrixObject *)bmo->cb_user;
93         int col;
94
95         if (BaseMath_ReadCallback(self) == -1)
96                 return -1;
97         if (!matrix_row_vector_check(self, (VectorObject *)bmo, row))
98                 return -1;
99
100         for (col = 0; col < self->num_col; col++) {
101                 bmo->data[col] = MATRIX_ITEM(self, row, col);
102         }
103
104         return 0;
105 }
106
107 static int mathutils_matrix_row_set(BaseMathObject *bmo, int row)
108 {
109         MatrixObject *self = (MatrixObject *)bmo->cb_user;
110         int col;
111
112         if (BaseMath_ReadCallback(self) == -1)
113                 return -1;
114         if (!matrix_row_vector_check(self, (VectorObject *)bmo, row))
115                 return -1;
116
117         for (col = 0; col < self->num_col; col++) {
118                 MATRIX_ITEM(self, row, col) = bmo->data[col];
119         }
120
121         (void)BaseMath_WriteCallback(self);
122         return 0;
123 }
124
125 static int mathutils_matrix_row_get_index(BaseMathObject *bmo, int row, int col)
126 {
127         MatrixObject *self = (MatrixObject *)bmo->cb_user;
128
129         if (BaseMath_ReadCallback(self) == -1)
130                 return -1;
131         if (!matrix_row_vector_check(self, (VectorObject *)bmo, row))
132                 return -1;
133
134         bmo->data[col] = MATRIX_ITEM(self, row, col);
135         return 0;
136 }
137
138 static int mathutils_matrix_row_set_index(BaseMathObject *bmo, int row, int col)
139 {
140         MatrixObject *self = (MatrixObject *)bmo->cb_user;
141
142         if (BaseMath_ReadCallback(self) == -1)
143                 return -1;
144         if (!matrix_row_vector_check(self, (VectorObject *)bmo, row))
145                 return -1;
146
147         MATRIX_ITEM(self, row, col) = bmo->data[col];
148
149         (void)BaseMath_WriteCallback(self);
150         return 0;
151 }
152
153 Mathutils_Callback mathutils_matrix_row_cb = {
154         mathutils_matrix_row_check,
155         mathutils_matrix_row_get,
156         mathutils_matrix_row_set,
157         mathutils_matrix_row_get_index,
158         mathutils_matrix_row_set_index
159 };
160
161
162 /* ----------------------------------------------------------------------------
163  * matrix row callbacks
164  * this is so you can do matrix.col[i][j] = val */
165
166 unsigned char mathutils_matrix_col_cb_index = -1;
167
168 static int mathutils_matrix_col_check(BaseMathObject *bmo)
169 {
170         MatrixObject *self = (MatrixObject *)bmo->cb_user;
171         return BaseMath_ReadCallback(self);
172 }
173
174 static int mathutils_matrix_col_get(BaseMathObject *bmo, int col)
175 {
176         MatrixObject *self = (MatrixObject *)bmo->cb_user;
177         int num_row;
178         int row;
179
180         if (BaseMath_ReadCallback(self) == -1)
181                 return -1;
182         if (!matrix_col_vector_check(self, (VectorObject *)bmo, col))
183                 return -1;
184
185         /* for 'translation' size will always be '3' even on 4x4 vec */
186         num_row = min_ii(self->num_row, ((VectorObject *)bmo)->size);
187
188         for (row = 0; row < num_row; row++) {
189                 bmo->data[row] = MATRIX_ITEM(self, row, col);
190         }
191
192         return 0;
193 }
194
195 static int mathutils_matrix_col_set(BaseMathObject *bmo, int col)
196 {
197         MatrixObject *self = (MatrixObject *)bmo->cb_user;
198         int num_row;
199         int row;
200
201         if (BaseMath_ReadCallback(self) == -1)
202                 return -1;
203         if (!matrix_col_vector_check(self, (VectorObject *)bmo, col))
204                 return -1;
205
206         /* for 'translation' size will always be '3' even on 4x4 vec */
207         num_row = min_ii(self->num_row, ((VectorObject *)bmo)->size);
208
209         for (row = 0; row < num_row; row++) {
210                 MATRIX_ITEM(self, row, col) = bmo->data[row];
211         }
212
213         (void)BaseMath_WriteCallback(self);
214         return 0;
215 }
216
217 static int mathutils_matrix_col_get_index(BaseMathObject *bmo, int col, int row)
218 {
219         MatrixObject *self = (MatrixObject *)bmo->cb_user;
220
221         if (BaseMath_ReadCallback(self) == -1)
222                 return -1;
223         if (!matrix_col_vector_check(self, (VectorObject *)bmo, col))
224                 return -1;
225
226         bmo->data[row] = MATRIX_ITEM(self, row, col);
227         return 0;
228 }
229
230 static int mathutils_matrix_col_set_index(BaseMathObject *bmo, int col, int row)
231 {
232         MatrixObject *self = (MatrixObject *)bmo->cb_user;
233
234         if (BaseMath_ReadCallback(self) == -1)
235                 return -1;
236         if (!matrix_col_vector_check(self, (VectorObject *)bmo, col))
237                 return -1;
238
239         MATRIX_ITEM(self, row, col) = bmo->data[row];
240
241         (void)BaseMath_WriteCallback(self);
242         return 0;
243 }
244
245 Mathutils_Callback mathutils_matrix_col_cb = {
246         mathutils_matrix_col_check,
247         mathutils_matrix_col_get,
248         mathutils_matrix_col_set,
249         mathutils_matrix_col_get_index,
250         mathutils_matrix_col_set_index
251 };
252
253
254 /* ----------------------------------------------------------------------------
255  * matrix row callbacks
256  * this is so you can do matrix.translation = val
257  * note, this is _exactly like matrix.col except the 4th component is always omitted */
258
259 unsigned char mathutils_matrix_translation_cb_index = -1;
260
261 static int mathutils_matrix_translation_check(BaseMathObject *bmo)
262 {
263         MatrixObject *self = (MatrixObject *)bmo->cb_user;
264         return BaseMath_ReadCallback(self);
265 }
266
267 static int mathutils_matrix_translation_get(BaseMathObject *bmo, int col)
268 {
269         MatrixObject *self = (MatrixObject *)bmo->cb_user;
270         int row;
271
272         if (BaseMath_ReadCallback(self) == -1)
273                 return -1;
274
275         for (row = 0; row < 3; row++) {
276                 bmo->data[row] = MATRIX_ITEM(self, row, col);
277         }
278
279         return 0;
280 }
281
282 static int mathutils_matrix_translation_set(BaseMathObject *bmo, int col)
283 {
284         MatrixObject *self = (MatrixObject *)bmo->cb_user;
285         int row;
286
287         if (BaseMath_ReadCallback(self) == -1)
288                 return -1;
289
290         for (row = 0; row < 3; row++) {
291                 MATRIX_ITEM(self, row, col) = bmo->data[row];
292         }
293
294         (void)BaseMath_WriteCallback(self);
295         return 0;
296 }
297
298 static int mathutils_matrix_translation_get_index(BaseMathObject *bmo, int col, int row)
299 {
300         MatrixObject *self = (MatrixObject *)bmo->cb_user;
301
302         if (BaseMath_ReadCallback(self) == -1)
303                 return -1;
304
305         bmo->data[row] = MATRIX_ITEM(self, row, col);
306         return 0;
307 }
308
309 static int mathutils_matrix_translation_set_index(BaseMathObject *bmo, int col, int row)
310 {
311         MatrixObject *self = (MatrixObject *)bmo->cb_user;
312
313         if (BaseMath_ReadCallback(self) == -1)
314                 return -1;
315
316         MATRIX_ITEM(self, row, col) = bmo->data[row];
317
318         (void)BaseMath_WriteCallback(self);
319         return 0;
320 }
321
322 Mathutils_Callback mathutils_matrix_translation_cb = {
323         mathutils_matrix_translation_check,
324         mathutils_matrix_translation_get,
325         mathutils_matrix_translation_set,
326         mathutils_matrix_translation_get_index,
327         mathutils_matrix_translation_set_index
328 };
329
330
331 /* matrix column callbacks, this is so you can do matrix.translation = Vector()  */
332
333 /* ----------------------------------mathutils.Matrix() ----------------- */
334 /* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
335 /* create a new matrix type */
336 static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
337 {
338         if (kwds && PyDict_Size(kwds)) {
339                 PyErr_SetString(PyExc_TypeError,
340                                 "Matrix(): "
341                                 "takes no keyword args");
342                 return NULL;
343         }
344
345         switch (PyTuple_GET_SIZE(args)) {
346                 case 0:
347                         return Matrix_CreatePyObject(NULL, 4, 4, type);
348                 case 1:
349                 {
350                         PyObject *arg = PyTuple_GET_ITEM(args, 0);
351
352                         /* Input is now as a sequence of rows so length of sequence
353                          * is the number of rows */
354                         /* -1 is an error, size checks will accunt for this */
355                         const unsigned short num_row = PySequence_Size(arg);
356
357                         if (num_row >= 2 && num_row <= 4) {
358                                 PyObject *item = PySequence_GetItem(arg, 0);
359                                 /* Since each item is a row, number of items is the
360                                  * same as the number of columns */
361                                 const unsigned short num_col = PySequence_Size(item);
362                                 Py_XDECREF(item);
363
364                                 if (num_col >= 2 && num_col <= 4) {
365                                         /* sane row & col size, new matrix and assign as slice  */
366                                         PyObject *matrix = Matrix_CreatePyObject(NULL, num_col, num_row, type);
367                                         if (Matrix_ass_slice((MatrixObject *)matrix, 0, INT_MAX, arg) == 0) {
368                                                 return matrix;
369                                         }
370                                         else { /* matrix ok, slice assignment not */
371                                                 Py_DECREF(matrix);
372                                         }
373                                 }
374                         }
375                         break;
376                 }
377         }
378
379         /* will overwrite error */
380         PyErr_SetString(PyExc_TypeError,
381                         "Matrix(): "
382                         "expects no args or a single arg containing 2-4 numeric sequences");
383         return NULL;
384 }
385
386 static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self)
387 {
388         PyObject *ret = Matrix_copy(self);
389         if (ret) {
390                 PyObject *ret_dummy = matrix_func(ret);
391                 if (ret_dummy) {
392                         Py_DECREF(ret_dummy);
393                         return (PyObject *)ret;
394                 }
395                 else { /* error */
396                         Py_DECREF(ret);
397                         return NULL;
398                 }
399         }
400         else {
401                 /* copy may fail if the read callback errors out */
402                 return NULL;
403         }
404 }
405
406 /* when a matrix is 4x4 size but initialized as a 3x3, re-assign values for 4x4 */
407 static void matrix_3x3_as_4x4(float mat[16])
408 {
409         mat[10] = mat[8];
410         mat[9] = mat[7];
411         mat[8] = mat[6];
412         mat[7] = 0.0f;
413         mat[6] = mat[5];
414         mat[5] = mat[4];
415         mat[4] = mat[3];
416         mat[3] = 0.0f;
417 }
418
419 /*-----------------------CLASS-METHODS----------------------------*/
420
421 /* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
422 PyDoc_STRVAR(C_Matrix_Identity_doc,
423 ".. classmethod:: Identity(size)\n"
424 "\n"
425 "   Create an identity matrix.\n"
426 "\n"
427 "   :arg size: The size of the identity matrix to construct [2, 4].\n"
428 "   :type size: int\n"
429 "   :return: A new identity matrix.\n"
430 "   :rtype: :class:`Matrix`\n"
431 );
432 static PyObject *C_Matrix_Identity(PyObject *cls, PyObject *args)
433 {
434         int matSize;
435
436         if (!PyArg_ParseTuple(args, "i:Matrix.Identity", &matSize)) {
437                 return NULL;
438         }
439
440         if (matSize < 2 || matSize > 4) {
441                 PyErr_SetString(PyExc_RuntimeError,
442                                 "Matrix.Identity(): "
443                                 "size must be between 2 and 4");
444                 return NULL;
445         }
446
447         return Matrix_CreatePyObject(NULL, matSize, matSize, (PyTypeObject *)cls);
448 }
449
450 PyDoc_STRVAR(C_Matrix_Rotation_doc,
451 ".. classmethod:: Rotation(angle, size, axis)\n"
452 "\n"
453 "   Create a matrix representing a rotation.\n"
454 "\n"
455 "   :arg angle: The angle of rotation desired, in radians.\n"
456 "   :type angle: float\n"
457 "   :arg size: The size of the rotation matrix to construct [2, 4].\n"
458 "   :type size: int\n"
459 "   :arg axis: a string in ['X', 'Y', 'Z'] or a 3D Vector Object\n"
460 "      (optional when size is 2).\n"
461 "   :type axis: string or :class:`Vector`\n"
462 "   :return: A new rotation matrix.\n"
463 "   :rtype: :class:`Matrix`\n"
464 );
465 static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
466 {
467         PyObject *vec = NULL;
468         const char *axis = NULL;
469         int matSize;
470         double angle; /* use double because of precision problems at high values */
471         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f,
472                              0.0f, 0.0f, 0.0f, 0.0f,
473                              0.0f, 0.0f, 0.0f, 0.0f,
474                              0.0f, 0.0f, 0.0f, 1.0f};
475
476         if (!PyArg_ParseTuple(args, "di|O:Matrix.Rotation", &angle, &matSize, &vec)) {
477                 return NULL;
478         }
479
480         if (vec && PyUnicode_Check(vec)) {
481                 axis = _PyUnicode_AsString((PyObject *)vec);
482                 if (axis == NULL || axis[0] == '\0' || axis[1] != '\0' || axis[0] < 'X' || axis[0] > 'Z') {
483                         PyErr_SetString(PyExc_ValueError,
484                                         "Matrix.Rotation(): "
485                                         "3rd argument axis value must be a 3D vector "
486                                         "or a string in 'X', 'Y', 'Z'");
487                         return NULL;
488                 }
489                 else {
490                         /* use the string */
491                         vec = NULL;
492                 }
493         }
494
495         angle = angle_wrap_rad(angle);
496
497         if (matSize != 2 && matSize != 3 && matSize != 4) {
498                 PyErr_SetString(PyExc_ValueError,
499                                 "Matrix.Rotation(): "
500                                 "can only return a 2x2 3x3 or 4x4 matrix");
501                 return NULL;
502         }
503         if (matSize == 2 && (vec != NULL)) {
504                 PyErr_SetString(PyExc_ValueError,
505                                 "Matrix.Rotation(): "
506                                 "cannot create a 2x2 rotation matrix around arbitrary axis");
507                 return NULL;
508         }
509         if ((matSize == 3 || matSize == 4) && (axis == NULL) && (vec == NULL)) {
510                 PyErr_SetString(PyExc_ValueError,
511                                 "Matrix.Rotation(): "
512                                 "axis of rotation for 3d and 4d matrices is required");
513                 return NULL;
514         }
515
516         /* check for valid vector/axis above */
517         if (vec) {
518                 float tvec[3];
519
520                 if (mathutils_array_parse(tvec, 3, 3, vec, "Matrix.Rotation(angle, size, axis), invalid 'axis' arg") == -1)
521                         return NULL;
522
523                 axis_angle_to_mat3((float (*)[3])mat, tvec, angle);
524         }
525         else if (matSize == 2) {
526                 angle_to_mat2((float (*)[2])mat, angle);
527
528         }
529         else {
530                 /* valid axis checked above */
531                 axis_angle_to_mat3_single((float (*)[3])mat, axis[0], angle);
532         }
533
534         if (matSize == 4) {
535                 matrix_3x3_as_4x4(mat);
536         }
537         /* pass to matrix creation */
538         return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
539 }
540
541
542 PyDoc_STRVAR(C_Matrix_Translation_doc,
543 ".. classmethod:: Translation(vector)\n"
544 "\n"
545 "   Create a matrix representing a translation.\n"
546 "\n"
547 "   :arg vector: The translation vector.\n"
548 "   :type vector: :class:`Vector`\n"
549 "   :return: An identity matrix with a translation.\n"
550 "   :rtype: :class:`Matrix`\n"
551 );
552 static PyObject *C_Matrix_Translation(PyObject *cls, PyObject *value)
553 {
554         float mat[4][4];
555
556         unit_m4(mat);
557
558         if (mathutils_array_parse(mat[3], 3, 4, value, "mathutils.Matrix.Translation(vector), invalid vector arg") == -1)
559                 return NULL;
560
561         return Matrix_CreatePyObject(&mat[0][0], 4, 4, (PyTypeObject *)cls);
562 }
563 /* ----------------------------------mathutils.Matrix.Scale() ------------- */
564 /* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
565 PyDoc_STRVAR(C_Matrix_Scale_doc,
566 ".. classmethod:: Scale(factor, size, axis)\n"
567 "\n"
568 "   Create a matrix representing a scaling.\n"
569 "\n"
570 "   :arg factor: The factor of scaling to apply.\n"
571 "   :type factor: float\n"
572 "   :arg size: The size of the scale matrix to construct [2, 4].\n"
573 "   :type size: int\n"
574 "   :arg axis: Direction to influence scale. (optional).\n"
575 "   :type axis: :class:`Vector`\n"
576 "   :return: A new scale matrix.\n"
577 "   :rtype: :class:`Matrix`\n"
578 );
579 static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
580 {
581         PyObject *vec = NULL;
582         int vec_size;
583         float tvec[3];
584         float factor;
585         int matSize;
586         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f,
587                          0.0f, 0.0f, 0.0f, 0.0f,
588                          0.0f, 0.0f, 0.0f, 0.0f,
589                          0.0f, 0.0f, 0.0f, 1.0f};
590
591         if (!PyArg_ParseTuple(args, "fi|O:Matrix.Scale", &factor, &matSize, &vec)) {
592                 return NULL;
593         }
594         if (matSize != 2 && matSize != 3 && matSize != 4) {
595                 PyErr_SetString(PyExc_ValueError,
596                                 "Matrix.Scale(): "
597                                 "can only return a 2x2 3x3 or 4x4 matrix");
598                 return NULL;
599         }
600         if (vec) {
601                 vec_size = (matSize == 2 ? 2 : 3);
602                 if (mathutils_array_parse(tvec, vec_size, vec_size, vec,
603                                           "Matrix.Scale(factor, size, axis), invalid 'axis' arg") == -1)
604                 {
605                         return NULL;
606                 }
607         }
608         if (vec == NULL) {  /* scaling along axis */
609                 if (matSize == 2) {
610                         mat[0] = factor;
611                         mat[3] = factor;
612                 }
613                 else {
614                         mat[0] = factor;
615                         mat[4] = factor;
616                         mat[8] = factor;
617                 }
618         }
619         else {
620                 /* scaling in arbitrary direction
621                  * normalize arbitrary axis */
622                 float norm = 0.0f;
623                 int x;
624                 for (x = 0; x < vec_size; x++) {
625                         norm += tvec[x] * tvec[x];
626                 }
627                 norm = sqrtf(norm);
628                 for (x = 0; x < vec_size; x++) {
629                         tvec[x] /= norm;
630                 }
631                 if (matSize == 2) {
632                         mat[0] = 1 + ((factor - 1) * (tvec[0] * tvec[0]));
633                         mat[1] =     ((factor - 1) * (tvec[0] * tvec[1]));
634                         mat[2] =     ((factor - 1) * (tvec[0] * tvec[1]));
635                         mat[3] = 1 + ((factor - 1) * (tvec[1] * tvec[1]));
636                 }
637                 else {
638                         mat[0] = 1 + ((factor - 1) * (tvec[0] * tvec[0]));
639                         mat[1] =     ((factor - 1) * (tvec[0] * tvec[1]));
640                         mat[2] =     ((factor - 1) * (tvec[0] * tvec[2]));
641                         mat[3] =     ((factor - 1) * (tvec[0] * tvec[1]));
642                         mat[4] = 1 + ((factor - 1) * (tvec[1] * tvec[1]));
643                         mat[5] =     ((factor - 1) * (tvec[1] * tvec[2]));
644                         mat[6] =     ((factor - 1) * (tvec[0] * tvec[2]));
645                         mat[7] =     ((factor - 1) * (tvec[1] * tvec[2]));
646                         mat[8] = 1 + ((factor - 1) * (tvec[2] * tvec[2]));
647                 }
648         }
649         if (matSize == 4) {
650                 matrix_3x3_as_4x4(mat);
651         }
652         /* pass to matrix creation */
653         return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
654 }
655 /* ----------------------------------mathutils.Matrix.OrthoProjection() --- */
656 /* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */
657 PyDoc_STRVAR(C_Matrix_OrthoProjection_doc,
658 ".. classmethod:: OrthoProjection(axis, size)\n"
659 "\n"
660 "   Create a matrix to represent an orthographic projection.\n"
661 "\n"
662 "   :arg axis: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'],\n"
663 "      where a single axis is for a 2D matrix.\n"
664 "      Or a vector for an arbitrary axis\n"
665 "   :type axis: string or :class:`Vector`\n"
666 "   :arg size: The size of the projection matrix to construct [2, 4].\n"
667 "   :type size: int\n"
668 "   :return: A new projection matrix.\n"
669 "   :rtype: :class:`Matrix`\n"
670 );
671 static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
672 {
673         PyObject *axis;
674
675         int matSize, x;
676         float norm = 0.0f;
677         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f,
678                          0.0f, 0.0f, 0.0f, 0.0f,
679                          0.0f, 0.0f, 0.0f, 0.0f,
680                          0.0f, 0.0f, 0.0f, 1.0f};
681
682         if (!PyArg_ParseTuple(args, "Oi:Matrix.OrthoProjection", &axis, &matSize)) {
683                 return NULL;
684         }
685         if (matSize != 2 && matSize != 3 && matSize != 4) {
686                 PyErr_SetString(PyExc_ValueError,
687                                 "Matrix.OrthoProjection(): "
688                                 "can only return a 2x2 3x3 or 4x4 matrix");
689                 return NULL;
690         }
691
692         if (PyUnicode_Check(axis)) {  /* ortho projection onto cardinal plane */
693                 Py_ssize_t plane_len;
694                 const char *plane = _PyUnicode_AsStringAndSize(axis, &plane_len);
695                 if (matSize == 2) {
696                         if (plane_len == 1 && plane[0] == 'X') {
697                                 mat[0] = 1.0f;
698                         }
699                         else if (plane_len == 1 && plane[0] == 'Y') {
700                                 mat[3] = 1.0f;
701                         }
702                         else {
703                                 PyErr_Format(PyExc_ValueError,
704                                              "Matrix.OrthoProjection(): "
705                                              "unknown plane, expected: X, Y, not '%.200s'",
706                                              plane);
707                                 return NULL;
708                         }
709                 }
710                 else {
711                         if (plane_len == 2 && plane[0] == 'X' && plane[1] == 'Y') {
712                                 mat[0] = 1.0f;
713                                 mat[4] = 1.0f;
714                         }
715                         else if (plane_len == 2 && plane[0] == 'X' && plane[1] == 'Z') {
716                                 mat[0] = 1.0f;
717                                 mat[8] = 1.0f;
718                         }
719                         else if (plane_len == 2 && plane[0] == 'Y' && plane[1] == 'Z') {
720                                 mat[4] = 1.0f;
721                                 mat[8] = 1.0f;
722                         }
723                         else {
724                                 PyErr_Format(PyExc_ValueError,
725                                              "Matrix.OrthoProjection(): "
726                                              "unknown plane, expected: XY, XZ, YZ, not '%.200s'",
727                                              plane);
728                                 return NULL;
729                         }
730                 }
731         }
732         else {
733                 /* arbitrary plane */
734
735                 int vec_size = (matSize == 2 ? 2 : 3);
736                 float tvec[4];
737
738                 if (mathutils_array_parse(tvec, vec_size, vec_size, axis,
739                                           "Matrix.OrthoProjection(axis, size), invalid 'axis' arg") == -1)
740                 {
741                         return NULL;
742                 }
743
744                 /* normalize arbitrary axis */
745                 for (x = 0; x < vec_size; x++) {
746                         norm += tvec[x] * tvec[x];
747                 }
748                 norm = sqrtf(norm);
749                 for (x = 0; x < vec_size; x++) {
750                         tvec[x] /= norm;
751                 }
752                 if (matSize == 2) {
753                         mat[0] = 1 - (tvec[0] * tvec[0]);
754                         mat[1] =   - (tvec[0] * tvec[1]);
755                         mat[2] =   - (tvec[0] * tvec[1]);
756                         mat[3] = 1 - (tvec[1] * tvec[1]);
757                 }
758                 else if (matSize > 2) {
759                         mat[0] = 1 - (tvec[0] * tvec[0]);
760                         mat[1] =   - (tvec[0] * tvec[1]);
761                         mat[2] =   - (tvec[0] * tvec[2]);
762                         mat[3] =   - (tvec[0] * tvec[1]);
763                         mat[4] = 1 - (tvec[1] * tvec[1]);
764                         mat[5] =   - (tvec[1] * tvec[2]);
765                         mat[6] =   - (tvec[0] * tvec[2]);
766                         mat[7] =   - (tvec[1] * tvec[2]);
767                         mat[8] = 1 - (tvec[2] * tvec[2]);
768                 }
769         }
770         if (matSize == 4) {
771                 matrix_3x3_as_4x4(mat);
772         }
773         /* pass to matrix creation */
774         return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
775 }
776
777 PyDoc_STRVAR(C_Matrix_Shear_doc,
778 ".. classmethod:: Shear(plane, size, factor)\n"
779 "\n"
780 "   Create a matrix to represent an shear transformation.\n"
781 "\n"
782 "   :arg plane: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'],\n"
783 "      where a single axis is for a 2D matrix only.\n"
784 "   :type plane: string\n"
785 "   :arg size: The size of the shear matrix to construct [2, 4].\n"
786 "   :type size: int\n"
787 "   :arg factor: The factor of shear to apply. For a 3 or 4 *size* matrix\n"
788 "      pass a pair of floats corresponding with the *plane* axis.\n"
789 "   :type factor: float or float pair\n"
790 "   :return: A new shear matrix.\n"
791 "   :rtype: :class:`Matrix`\n"
792 );
793 static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args)
794 {
795         int matSize;
796         const char *plane;
797         PyObject *fac;
798         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f,
799                          0.0f, 0.0f, 0.0f, 0.0f,
800                          0.0f, 0.0f, 0.0f, 0.0f,
801                          0.0f, 0.0f, 0.0f, 1.0f};
802
803         if (!PyArg_ParseTuple(args, "siO:Matrix.Shear", &plane, &matSize, &fac)) {
804                 return NULL;
805         }
806         if (matSize != 2 && matSize != 3 && matSize != 4) {
807                 PyErr_SetString(PyExc_ValueError,
808                                 "Matrix.Shear(): "
809                                 "can only return a 2x2 3x3 or 4x4 matrix");
810                 return NULL;
811         }
812
813         if (matSize == 2) {
814                 float const factor = PyFloat_AsDouble(fac);
815
816                 if (factor == -1.0f && PyErr_Occurred()) {
817                         PyErr_SetString(PyExc_TypeError,
818                                         "Matrix.Shear(): "
819                                         "the factor to be a float");
820                         return NULL;
821                 }
822
823                 /* unit */
824                 mat[0] = 1.0f;
825                 mat[3] = 1.0f;
826
827                 if (STREQ(plane, "X")) {
828                         mat[2] = factor;
829                 }
830                 else if (STREQ(plane, "Y")) {
831                         mat[1] = factor;
832                 }
833                 else {
834                         PyErr_SetString(PyExc_ValueError,
835                                         "Matrix.Shear(): "
836                                         "expected: X, Y or wrong matrix size for shearing plane");
837                         return NULL;
838                 }
839         }
840         else {
841                 /* 3 or 4, apply as 3x3, resize later if needed */
842                 float factor[2];
843
844                 if (mathutils_array_parse(factor, 2, 2, fac, "Matrix.Shear()") < 0) {
845                         return NULL;
846                 }
847
848                 /* unit */
849                 mat[0] = 1.0f;
850                 mat[4] = 1.0f;
851                 mat[8] = 1.0f;
852
853                 if (STREQ(plane, "XY")) {
854                         mat[6] = factor[0];
855                         mat[7] = factor[1];
856                 }
857                 else if (STREQ(plane, "XZ")) {
858                         mat[3] = factor[0];
859                         mat[5] = factor[1];
860                 }
861                 else if (STREQ(plane, "YZ")) {
862                         mat[1] = factor[0];
863                         mat[2] = factor[1];
864                 }
865                 else {
866                         PyErr_SetString(PyExc_ValueError,
867                                         "Matrix.Shear(): "
868                                         "expected: X, Y, XY, XZ, YZ");
869                         return NULL;
870                 }
871         }
872
873         if (matSize == 4) {
874                 matrix_3x3_as_4x4(mat);
875         }
876         /* pass to matrix creation */
877         return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
878 }
879
880 void matrix_as_3x3(float mat[3][3], MatrixObject *self)
881 {
882         copy_v3_v3(mat[0], MATRIX_COL_PTR(self, 0));
883         copy_v3_v3(mat[1], MATRIX_COL_PTR(self, 1));
884         copy_v3_v3(mat[2], MATRIX_COL_PTR(self, 2));
885 }
886
887 static void matrix_copy(MatrixObject *mat_dst, const MatrixObject *mat_src)
888 {
889         BLI_assert((mat_dst->num_col == mat_src->num_col) &&
890                    (mat_dst->num_row == mat_src->num_row));
891         BLI_assert(mat_dst != mat_src);
892
893         memcpy(mat_dst->matrix, mat_src->matrix, sizeof(float) * (mat_dst->num_col * mat_dst->num_row));
894 }
895
896 /* assumes rowsize == colsize is checked and the read callback has run */
897 static float matrix_determinant_internal(const MatrixObject *self)
898 {
899         if (self->num_col == 2) {
900                 return determinant_m2(MATRIX_ITEM(self, 0, 0), MATRIX_ITEM(self, 0, 1),
901                                       MATRIX_ITEM(self, 1, 0), MATRIX_ITEM(self, 1, 1));
902         }
903         else if (self->num_col == 3) {
904                 return determinant_m3(MATRIX_ITEM(self, 0, 0), MATRIX_ITEM(self, 0, 1), MATRIX_ITEM(self, 0, 2),
905                                       MATRIX_ITEM(self, 1, 0), MATRIX_ITEM(self, 1, 1), MATRIX_ITEM(self, 1, 2),
906                                       MATRIX_ITEM(self, 2, 0), MATRIX_ITEM(self, 2, 1), MATRIX_ITEM(self, 2, 2));
907         }
908         else {
909                 return determinant_m4((float (*)[4])self->matrix);
910         }
911 }
912
913 static void adjoint_matrix_n(float *mat_dst, const float *mat_src, const unsigned short dim)
914 {
915         /* calculate the classical adjoint */
916         switch (dim) {
917                 case 2:
918                 {
919                         adjoint_m2_m2((float (*)[2])mat_dst, (float (*)[2])mat_src);
920                         break;
921                 }
922                 case 3:
923                 {
924                         adjoint_m3_m3((float (*)[3])mat_dst, (float (*)[3])mat_src);
925                         break;
926                 }
927                 case 4:
928                 {
929                         adjoint_m4_m4((float (*)[4])mat_dst, (float (*)[4])mat_src);
930                         break;
931                 }
932                 default:
933                         BLI_assert(0);
934         }
935 }
936
937 static void matrix_invert_with_det_n_internal(float *mat_dst, const float *mat_src, const float det, const unsigned short dim)
938 {
939         float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
940         unsigned short i, j, k;
941
942         BLI_assert(det != 0.0f);
943
944         adjoint_matrix_n(mat, mat_src, dim);
945
946         /* divide by determinant & set values */
947         k = 0;
948         for (i = 0; i < dim; i++) {  /* num_col */
949                 for (j = 0; j < dim; j++) {  /* num_row */
950                         mat_dst[MATRIX_ITEM_INDEX_NUMROW(dim, j, i)] = mat[k++] / det;
951                 }
952         }
953 }
954
955 /**
956  * \param r_mat can be from ``self->matrix`` or not.
957  */
958 static bool matrix_invert_internal(const MatrixObject *self, float *r_mat)
959 {
960         float det;
961         BLI_assert(self->num_col == self->num_row);
962         det = matrix_determinant_internal(self);
963
964         if (det != 0.0f) {
965                 matrix_invert_with_det_n_internal(r_mat, self->matrix, det, self->num_col);
966                 return true;
967         }
968         else {
969                 return false;
970         }
971 }
972
973 /**
974  * Similar to ``matrix_invert_internal`` but should never error.
975  * \param r_mat can be from ``self->matrix`` or not.
976  */
977 static void matrix_invert_safe_internal(const MatrixObject *self, float *r_mat)
978 {
979         float det;
980         float *in_mat = self->matrix;
981         BLI_assert(self->num_col == self->num_row);
982         det = matrix_determinant_internal(self);
983
984         if (det == 0.0f) {
985                 const float eps = PSEUDOINVERSE_EPSILON;
986
987                 /* We will copy self->matrix into r_mat (if needed), and modify it in place to add diagonal epsilon. */
988                 in_mat = r_mat;
989
990                 switch (self->num_col) {
991                         case 2:
992                         {
993                                 float (*mat)[2] = (float (*)[2])in_mat;
994
995                                 if (in_mat != self->matrix) {
996                                         copy_m2_m2(mat, (float (*)[2])self->matrix);
997                                 }
998                                 mat[0][0] += eps;
999                                 mat[1][1] += eps;
1000
1001                                 if (UNLIKELY((det = determinant_m2(mat[0][0], mat[0][1], mat[1][0], mat[1][1])) == 0.0f)) {
1002                                         unit_m2(mat);
1003                                         det = 1.0f;
1004                                 }
1005                                 break;
1006                         }
1007                         case 3:
1008                         {
1009                                 float (*mat)[3] = (float (*)[3])in_mat;
1010
1011                                 if (in_mat != self->matrix) {
1012                                         copy_m3_m3(mat, (float (*)[3])self->matrix);
1013                                 }
1014                                 mat[0][0] += eps;
1015                                 mat[1][1] += eps;
1016                                 mat[2][2] += eps;
1017
1018                                 if (UNLIKELY((det = determinant_m3_array(mat)) == 0.0f)) {
1019                                         unit_m3(mat);
1020                                         det = 1.0f;
1021                                 }
1022                                 break;
1023                         }
1024                         case 4:
1025                         {
1026                                 float (*mat)[4] = (float (*)[4])in_mat;
1027
1028                                 if (in_mat != self->matrix) {
1029                                         copy_m4_m4(mat, (float (*)[4])self->matrix);
1030                                 }
1031                                 mat[0][0] += eps;
1032                                 mat[1][1] += eps;
1033                                 mat[2][2] += eps;
1034                                 mat[3][3] += eps;
1035
1036                                 if (UNLIKELY(det = determinant_m4(mat)) == 0.0f) {
1037                                         unit_m4(mat);
1038                                         det = 1.0f;
1039                                 }
1040                                 break;
1041                         }
1042                         default:
1043                                 BLI_assert(0);
1044                 }
1045         }
1046
1047         matrix_invert_with_det_n_internal(r_mat, in_mat, det, self->num_col);
1048 }
1049
1050
1051 /*-----------------------------METHODS----------------------------*/
1052 PyDoc_STRVAR(Matrix_to_quaternion_doc,
1053 ".. method:: to_quaternion()\n"
1054 "\n"
1055 "   Return a quaternion representation of the rotation matrix.\n"
1056 "\n"
1057 "   :return: Quaternion representation of the rotation matrix.\n"
1058 "   :rtype: :class:`Quaternion`\n"
1059 );
1060 static PyObject *Matrix_to_quaternion(MatrixObject *self)
1061 {
1062         float quat[4];
1063
1064         if (BaseMath_ReadCallback(self) == -1)
1065                 return NULL;
1066
1067         /* must be 3-4 cols, 3-4 rows, square matrix */
1068         if ((self->num_row < 3) || (self->num_col < 3) || (self->num_row != self->num_col)) {
1069                 PyErr_SetString(PyExc_ValueError,
1070                                 "Matrix.to_quat(): "
1071                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
1072                 return NULL;
1073         }
1074         if (self->num_row == 3) {
1075                 mat3_to_quat(quat, (float (*)[3])self->matrix);
1076         }
1077         else {
1078                 mat4_to_quat(quat, (float (*)[4])self->matrix);
1079         }
1080
1081         return Quaternion_CreatePyObject(quat, NULL);
1082 }
1083
1084 /*---------------------------matrix.toEuler() --------------------*/
1085 PyDoc_STRVAR(Matrix_to_euler_doc,
1086 ".. method:: to_euler(order, euler_compat)\n"
1087 "\n"
1088 "   Return an Euler representation of the rotation matrix\n"
1089 "   (3x3 or 4x4 matrix only).\n"
1090 "\n"
1091 "   :arg order: Optional rotation order argument in\n"
1092 "      ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n"
1093 "   :type order: string\n"
1094 "   :arg euler_compat: Optional euler argument the new euler will be made\n"
1095 "      compatible with (no axis flipping between them).\n"
1096 "      Useful for converting a series of matrices to animation curves.\n"
1097 "   :type euler_compat: :class:`Euler`\n"
1098 "   :return: Euler representation of the matrix.\n"
1099 "   :rtype: :class:`Euler`\n"
1100 );
1101 static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
1102 {
1103         const char *order_str = NULL;
1104         short order = EULER_ORDER_XYZ;
1105         float eul[3], eul_compatf[3];
1106         EulerObject *eul_compat = NULL;
1107
1108         float tmat[3][3];
1109         float (*mat)[3];
1110
1111         if (BaseMath_ReadCallback(self) == -1)
1112                 return NULL;
1113
1114         if (!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat))
1115                 return NULL;
1116
1117         if (eul_compat) {
1118                 if (BaseMath_ReadCallback(eul_compat) == -1)
1119                         return NULL;
1120
1121                 copy_v3_v3(eul_compatf, eul_compat->eul);
1122         }
1123
1124         /*must be 3-4 cols, 3-4 rows, square matrix */
1125         if (self->num_row == 3 && self->num_col == 3) {
1126                 mat = (float (*)[3])self->matrix;
1127         }
1128         else if (self->num_row == 4 && self->num_col == 4) {
1129                 copy_m3_m4(tmat, (float (*)[4])self->matrix);
1130                 mat = tmat;
1131         }
1132         else {
1133                 PyErr_SetString(PyExc_ValueError,
1134                                 "Matrix.to_euler(): "
1135                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
1136                 return NULL;
1137         }
1138
1139         if (order_str) {
1140                 order = euler_order_from_string(order_str, "Matrix.to_euler()");
1141
1142                 if (order == -1)
1143                         return NULL;
1144         }
1145
1146         if (eul_compat) {
1147                 if (order == 1) mat3_to_compatible_eul(eul, eul_compatf, mat);
1148                 else            mat3_to_compatible_eulO(eul, eul_compatf, order, mat);
1149         }
1150         else {
1151                 if (order == 1) mat3_to_eul(eul, mat);
1152                 else mat3_to_eulO(eul, order, mat);
1153         }
1154
1155         return Euler_CreatePyObject(eul, order, NULL);
1156 }
1157
1158 PyDoc_STRVAR(Matrix_resize_4x4_doc,
1159 ".. method:: resize_4x4()\n"
1160 "\n"
1161 "   Resize the matrix to 4x4.\n"
1162 );
1163 static PyObject *Matrix_resize_4x4(MatrixObject *self)
1164 {
1165         float mat[4][4];
1166         int col;
1167
1168         if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
1169                 PyErr_SetString(PyExc_ValueError,
1170                                 "Matrix.resize_4x4(): "
1171                                 "cannot resize wrapped data - make a copy and resize that");
1172                 return NULL;
1173         }
1174         if (self->cb_user) {
1175                 PyErr_SetString(PyExc_ValueError,
1176                                 "Matrix.resize_4x4(): "
1177                                 "cannot resize owned data - make a copy and resize that");
1178                 return NULL;
1179         }
1180
1181         self->matrix = PyMem_Realloc(self->matrix, (sizeof(float) * (MATRIX_MAX_DIM * MATRIX_MAX_DIM)));
1182         if (self->matrix == NULL) {
1183                 PyErr_SetString(PyExc_MemoryError,
1184                                 "Matrix.resize_4x4(): "
1185                                 "problem allocating pointer space");
1186                 return NULL;
1187         }
1188
1189         unit_m4(mat);
1190
1191         for (col = 0; col < self->num_col; col++) {
1192                 memcpy(mat[col], MATRIX_COL_PTR(self, col), self->num_row * sizeof(float));
1193         }
1194
1195         copy_m4_m4((float (*)[4])self->matrix, (float (*)[4])mat);
1196
1197         self->num_col = 4;
1198         self->num_row = 4;
1199
1200         Py_RETURN_NONE;
1201 }
1202
1203 PyDoc_STRVAR(Matrix_to_4x4_doc,
1204 ".. method:: to_4x4()\n"
1205 "\n"
1206 "   Return a 4x4 copy of this matrix.\n"
1207 "\n"
1208 "   :return: a new matrix.\n"
1209 "   :rtype: :class:`Matrix`\n"
1210 );
1211 static PyObject *Matrix_to_4x4(MatrixObject *self)
1212 {
1213         if (BaseMath_ReadCallback(self) == -1)
1214                 return NULL;
1215
1216         if (self->num_row == 4 && self->num_col == 4) {
1217                 return Matrix_CreatePyObject(self->matrix, 4, 4, Py_TYPE(self));
1218         }
1219         else if (self->num_row == 3 && self->num_col == 3) {
1220                 float mat[4][4];
1221                 copy_m4_m3(mat, (float (*)[3])self->matrix);
1222                 return Matrix_CreatePyObject((float *)mat, 4, 4, Py_TYPE(self));
1223         }
1224         /* TODO, 2x2 matrix */
1225
1226         PyErr_SetString(PyExc_ValueError,
1227                         "Matrix.to_4x4(): "
1228                         "inappropriate matrix size");
1229         return NULL;
1230 }
1231
1232 PyDoc_STRVAR(Matrix_to_3x3_doc,
1233 ".. method:: to_3x3()\n"
1234 "\n"
1235 "   Return a 3x3 copy of this matrix.\n"
1236 "\n"
1237 "   :return: a new matrix.\n"
1238 "   :rtype: :class:`Matrix`\n"
1239 );
1240 static PyObject *Matrix_to_3x3(MatrixObject *self)
1241 {
1242         float mat[3][3];
1243
1244         if (BaseMath_ReadCallback(self) == -1)
1245                 return NULL;
1246
1247         if ((self->num_row < 3) || (self->num_col < 3)) {
1248                 PyErr_SetString(PyExc_ValueError,
1249                                 "Matrix.to_3x3(): inappropriate matrix size");
1250                 return NULL;
1251         }
1252
1253         matrix_as_3x3(mat, self);
1254
1255         return Matrix_CreatePyObject((float *)mat, 3, 3, Py_TYPE(self));
1256 }
1257
1258 PyDoc_STRVAR(Matrix_to_translation_doc,
1259 ".. method:: to_translation()\n"
1260 "\n"
1261 "   Return the translation part of a 4 row matrix.\n"
1262 "\n"
1263 "   :return: Return the translation of a matrix.\n"
1264 "   :rtype: :class:`Vector`\n"
1265 );
1266 static PyObject *Matrix_to_translation(MatrixObject *self)
1267 {
1268         if (BaseMath_ReadCallback(self) == -1)
1269                 return NULL;
1270
1271         if ((self->num_row < 3) || self->num_col < 4) {
1272                 PyErr_SetString(PyExc_ValueError,
1273                                 "Matrix.to_translation(): "
1274                                 "inappropriate matrix size");
1275                 return NULL;
1276         }
1277
1278         return Vector_CreatePyObject(MATRIX_COL_PTR(self, 3), 3, NULL);
1279 }
1280
1281 PyDoc_STRVAR(Matrix_to_scale_doc,
1282 ".. method:: to_scale()\n"
1283 "\n"
1284 "   Return the scale part of a 3x3 or 4x4 matrix.\n"
1285 "\n"
1286 "   :return: Return the scale of a matrix.\n"
1287 "   :rtype: :class:`Vector`\n"
1288 "\n"
1289 "   .. 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"
1290 );
1291 static PyObject *Matrix_to_scale(MatrixObject *self)
1292 {
1293         float rot[3][3];
1294         float mat[3][3];
1295         float size[3];
1296
1297         if (BaseMath_ReadCallback(self) == -1)
1298                 return NULL;
1299
1300         /*must be 3-4 cols, 3-4 rows, square matrix */
1301         if ((self->num_row < 3) || (self->num_col < 3)) {
1302                 PyErr_SetString(PyExc_ValueError,
1303                                 "Matrix.to_scale(): "
1304                                 "inappropriate matrix size, 3x3 minimum size");
1305                 return NULL;
1306         }
1307
1308         matrix_as_3x3(mat, self);
1309
1310         /* compatible mat4_to_loc_rot_size */
1311         mat3_to_rot_size(rot, size, mat);
1312
1313         return Vector_CreatePyObject(size, 3, NULL);
1314 }
1315
1316 /*---------------------------matrix.invert() ---------------------*/
1317
1318 /* re-usable checks for invert */
1319 static bool matrix_invert_is_compat(const MatrixObject *self)
1320 {
1321         if (self->num_col != self->num_row) {
1322                 PyErr_SetString(PyExc_ValueError,
1323                                 "Matrix.invert(ed): "
1324                                 "only square matrices are supported");
1325                 return false;
1326         }
1327         else {
1328                 return true;
1329         }
1330 }
1331
1332 static bool matrix_invert_args_check(const MatrixObject *self, PyObject *args, bool check_type)
1333 {
1334         switch (PyTuple_GET_SIZE(args)) {
1335                 case 0:
1336                         return true;
1337                 case 1:
1338                         if (check_type) {
1339                                 const MatrixObject *fallback = (MatrixObject *)PyTuple_GET_ITEM(args, 0);
1340                                 if (!MatrixObject_Check(fallback)) {
1341                                         PyErr_SetString(PyExc_TypeError,
1342                                                         "Matrix.invert: "
1343                                                         "expects a matrix argument or nothing");
1344                                         return false;
1345                                 }
1346
1347                                 if ((self->num_col != fallback->num_col) ||
1348                                     (self->num_row != fallback->num_row))
1349                                 {
1350                                         PyErr_SetString(PyExc_TypeError,
1351                                                         "Matrix.invert: "
1352                                                         "matrix argument has different dimensions");
1353                                         return false;
1354                                 }
1355                         }
1356
1357                         return true;
1358                 default:
1359                         PyErr_SetString(PyExc_ValueError,
1360                                         "Matrix.invert(ed): "
1361                                         "takes at most one argument");
1362                         return false;
1363         }
1364 }
1365
1366 static void matrix_invert_raise_degenerate(void)
1367 {
1368         PyErr_SetString(PyExc_ValueError,
1369                         "Matrix.invert(ed): "
1370                         "matrix does not have an inverse");
1371 }
1372
1373 PyDoc_STRVAR(Matrix_invert_doc,
1374 ".. method:: invert(fallback=None)\n"
1375 "\n"
1376 "   Set the matrix to its inverse.\n"
1377 "\n"
1378 "   :arg fallback: Set the matrix to this value when the inverse can't be calculated\n"
1379 "      (instead of raising a :exc:`ValueError` exception).\n"
1380 "   :type fallback: :class:`Matrix`\n"
1381 "\n"
1382 "   .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n"
1383 );
1384 static PyObject *Matrix_invert(MatrixObject *self, PyObject *args)
1385 {
1386         if (BaseMath_ReadCallback(self) == -1)
1387                 return NULL;
1388
1389         if (matrix_invert_is_compat(self) == false) {
1390                 return NULL;
1391         }
1392
1393         if (matrix_invert_args_check(self, args, true) == false) {
1394                 return NULL;
1395         }
1396
1397         if (matrix_invert_internal(self, self->matrix)) {
1398                 /* pass */
1399         }
1400         else {
1401                 if (PyTuple_GET_SIZE(args) == 1) {
1402                         MatrixObject *fallback = (MatrixObject *)PyTuple_GET_ITEM(args, 0);
1403
1404                         if (BaseMath_ReadCallback(fallback) == -1)
1405                                 return NULL;
1406
1407                         if (self != fallback) {
1408                                 matrix_copy(self, fallback);
1409                         }
1410                 }
1411                 else {
1412                         matrix_invert_raise_degenerate();
1413                         return NULL;
1414                 }
1415         }
1416
1417         (void)BaseMath_WriteCallback(self);
1418         Py_RETURN_NONE;
1419 }
1420
1421 PyDoc_STRVAR(Matrix_inverted_doc,
1422 ".. method:: inverted(fallback=None)\n"
1423 "\n"
1424 "   Return an inverted copy of the matrix.\n"
1425 "\n"
1426 "   :arg fallback: return this value when the inverse can't be calculated\n"
1427 "      (instead of raising a :exc:`ValueError` exception).\n"
1428 "   :type fallback: any\n"
1429 "   :return: the inverted matrix or fallback when given.\n"
1430 "   :rtype: :class:`Matrix`\n"
1431 );
1432 static PyObject *Matrix_inverted(MatrixObject *self, PyObject *args)
1433 {
1434         float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
1435
1436         if (BaseMath_ReadCallback(self) == -1)
1437                 return NULL;
1438
1439         if (matrix_invert_args_check(self, args, false) == false) {
1440                 return NULL;
1441         }
1442
1443         if (matrix_invert_is_compat(self) == false) {
1444                 return NULL;
1445         }
1446
1447         if (matrix_invert_internal(self, mat)) {
1448                 /* pass */
1449         }
1450         else {
1451                 if (PyTuple_GET_SIZE(args) == 1) {
1452                         PyObject *fallback = PyTuple_GET_ITEM(args, 0);
1453                         Py_INCREF(fallback);
1454                         return fallback;
1455                 }
1456                 else {
1457                         matrix_invert_raise_degenerate();
1458                         return NULL;
1459                 }
1460         }
1461
1462         return Matrix_copy_notest(self, mat);
1463 }
1464
1465 static PyObject *Matrix_inverted_noargs(MatrixObject *self)
1466 {
1467         if (BaseMath_ReadCallback(self) == -1)
1468                 return NULL;
1469
1470         if (matrix_invert_is_compat(self) == false) {
1471                 return NULL;
1472         }
1473
1474         if (matrix_invert_internal(self, self->matrix)) {
1475                 /* pass */
1476         }
1477         else {
1478                 matrix_invert_raise_degenerate();
1479                 return NULL;
1480         }
1481
1482         (void)BaseMath_WriteCallback(self);
1483         Py_RETURN_NONE;
1484 }
1485
1486 PyDoc_STRVAR(Matrix_invert_safe_doc,
1487 ".. method:: invert_safe()\n"
1488 "\n"
1489 "   Set the matrix to its inverse, will never error.\n"
1490 "   If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, to get an invertible one.\n"
1491 "   If tweaked matrix is still degenerated, set to the identity matrix instead.\n"
1492 "\n"
1493 "   .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n"
1494 );
1495 static PyObject *Matrix_invert_safe(MatrixObject *self)
1496 {
1497         if (BaseMath_ReadCallback(self) == -1)
1498                 return NULL;
1499
1500         if (matrix_invert_is_compat(self) == false) {
1501                 return NULL;
1502         }
1503
1504         matrix_invert_safe_internal(self, self->matrix);
1505
1506         (void)BaseMath_WriteCallback(self);
1507         Py_RETURN_NONE;
1508 }
1509
1510 PyDoc_STRVAR(Matrix_inverted_safe_doc,
1511 ".. method:: inverted_safe()\n"
1512 "\n"
1513 "   Return an inverted copy of the matrix, will never error.\n"
1514 "   If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, to get an invertible one.\n"
1515 "   If tweaked matrix is still degenerated, return the identity matrix instead.\n"
1516 "\n"
1517 "   :return: the inverted matrix.\n"
1518 "   :rtype: :class:`Matrix`\n"
1519 );
1520 static PyObject *Matrix_inverted_safe(MatrixObject *self)
1521 {
1522         float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
1523
1524         if (BaseMath_ReadCallback(self) == -1)
1525                 return NULL;
1526
1527         if (matrix_invert_is_compat(self) == false) {
1528                 return NULL;
1529         }
1530
1531         matrix_invert_safe_internal(self, mat);
1532
1533         return Matrix_copy_notest(self, mat);
1534 }
1535
1536 /*---------------------------matrix.adjugate() ---------------------*/
1537 PyDoc_STRVAR(Matrix_adjugate_doc,
1538 ".. method:: adjugate()\n"
1539 "\n"
1540 "   Set the matrix to its adjugate.\n"
1541 "\n"
1542 "   .. note:: When the matrix cant be adjugated a :exc:`ValueError` exception is raised.\n"
1543 "\n"
1544 "   .. seealso:: <http://en.wikipedia.org/wiki/Adjugate_matrix>\n"
1545 );
1546 static PyObject *Matrix_adjugate(MatrixObject *self)
1547 {
1548         if (BaseMath_ReadCallback(self) == -1)
1549                 return NULL;
1550
1551         if (self->num_col != self->num_row) {
1552                 PyErr_SetString(PyExc_ValueError,
1553                                 "Matrix.adjugate(d): "
1554                                 "only square matrices are supported");
1555                 return NULL;
1556         }
1557
1558         /* calculate the classical adjoint */
1559         if (self->num_col <= 4) {
1560                 adjoint_matrix_n(self->matrix, self->matrix, self->num_col);
1561         }
1562         else {
1563                 PyErr_Format(PyExc_ValueError,
1564                              "Matrix adjugate(d): size (%d) unsupported",
1565                              (int)self->num_col);
1566                 return NULL;
1567         }
1568
1569
1570         (void)BaseMath_WriteCallback(self);
1571         Py_RETURN_NONE;
1572 }
1573
1574 PyDoc_STRVAR(Matrix_adjugated_doc,
1575 ".. method:: adjugated()\n"
1576 "\n"
1577 "   Return an adjugated copy of the matrix.\n"
1578 "\n"
1579 "   :return: the adjugated matrix.\n"
1580 "   :rtype: :class:`Matrix`\n"
1581 "\n"
1582 "   .. note:: When the matrix cant be adjugated a :exc:`ValueError` exception is raised.\n"
1583 );
1584 static PyObject *Matrix_adjugated(MatrixObject *self)
1585 {
1586         return matrix__apply_to_copy((PyNoArgsFunction)Matrix_adjugate, self);
1587 }
1588
1589 PyDoc_STRVAR(Matrix_rotate_doc,
1590 ".. method:: rotate(other)\n"
1591 "\n"
1592 "   Rotates the matrix by another mathutils value.\n"
1593 "\n"
1594 "   :arg other: rotation component of mathutils value\n"
1595 "   :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n"
1596 "\n"
1597 "   .. note:: If any of the columns are not unit length this may not have desired results.\n"
1598 );
1599 static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value)
1600 {
1601         float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
1602
1603         if (BaseMath_ReadCallback(self) == -1)
1604                 return NULL;
1605
1606         if (mathutils_any_to_rotmat(other_rmat, value, "matrix.rotate(value)") == -1)
1607                 return NULL;
1608
1609         if (self->num_row != 3 || self->num_col != 3) {
1610                 PyErr_SetString(PyExc_ValueError,
1611                                 "Matrix.rotate(): "
1612                                 "must have 3x3 dimensions");
1613                 return NULL;
1614         }
1615
1616         matrix_as_3x3(self_rmat, self);
1617         mul_m3_m3m3(rmat, other_rmat, self_rmat);
1618
1619         copy_m3_m3((float (*)[3])(self->matrix), rmat);
1620
1621         (void)BaseMath_WriteCallback(self);
1622         Py_RETURN_NONE;
1623 }
1624
1625 /*---------------------------matrix.decompose() ---------------------*/
1626 PyDoc_STRVAR(Matrix_decompose_doc,
1627 ".. method:: decompose()\n"
1628 "\n"
1629 "   Return the location, rotation and scale components of this matrix.\n"
1630 "\n"
1631 "   :return: loc, rot, scale triple.\n"
1632 "   :rtype: (:class:`Vector`, :class:`Quaternion`, :class:`Vector`)"
1633 );
1634 static PyObject *Matrix_decompose(MatrixObject *self)
1635 {
1636         PyObject *ret;
1637         float loc[3];
1638         float rot[3][3];
1639         float quat[4];
1640         float size[3];
1641
1642         if (self->num_row != 4 || self->num_col != 4) {
1643                 PyErr_SetString(PyExc_ValueError,
1644                                 "Matrix.decompose(): "
1645                                 "inappropriate matrix size - expects 4x4 matrix");
1646                 return NULL;
1647         }
1648
1649         if (BaseMath_ReadCallback(self) == -1)
1650                 return NULL;
1651
1652         mat4_to_loc_rot_size(loc, rot, size, (float (*)[4])self->matrix);
1653         mat3_to_quat(quat, rot);
1654
1655         ret = PyTuple_New(3);
1656         PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(loc, 3, NULL));
1657         PyTuple_SET_ITEM(ret, 1, Quaternion_CreatePyObject(quat, NULL));
1658         PyTuple_SET_ITEM(ret, 2, Vector_CreatePyObject(size, 3, NULL));
1659
1660         return ret;
1661 }
1662
1663
1664
1665 PyDoc_STRVAR(Matrix_lerp_doc,
1666 ".. function:: lerp(other, factor)\n"
1667 "\n"
1668 "   Returns the interpolation of two matrices.\n"
1669 "\n"
1670 "   :arg other: value to interpolate with.\n"
1671 "   :type other: :class:`Matrix`\n"
1672 "   :arg factor: The interpolation value in [0.0, 1.0].\n"
1673 "   :type factor: float\n"
1674 "   :return: The interpolated matrix.\n"
1675 "   :rtype: :class:`Matrix`\n"
1676 );
1677 static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
1678 {
1679         MatrixObject *mat2 = NULL;
1680         float fac, mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
1681
1682         if (!PyArg_ParseTuple(args, "O!f:lerp", &matrix_Type, &mat2, &fac))
1683                 return NULL;
1684
1685         if (self->num_col != mat2->num_col || self->num_row != mat2->num_row) {
1686                 PyErr_SetString(PyExc_ValueError,
1687                                 "Matrix.lerp(): "
1688                                 "expects both matrix objects of the same dimensions");
1689                 return NULL;
1690         }
1691
1692         if (BaseMath_ReadCallback(self) == -1 || BaseMath_ReadCallback(mat2) == -1)
1693                 return NULL;
1694
1695         /* TODO, different sized matrix */
1696         if (self->num_col == 4 && self->num_row == 4) {
1697                 blend_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac);
1698         }
1699         else if (self->num_col == 3 && self->num_row == 3) {
1700                 blend_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac);
1701         }
1702         else {
1703                 PyErr_SetString(PyExc_ValueError,
1704                                 "Matrix.lerp(): "
1705                                 "only 3x3 and 4x4 matrices supported");
1706                 return NULL;
1707         }
1708
1709         return Matrix_CreatePyObject(mat, self->num_col, self->num_row, Py_TYPE(self));
1710 }
1711
1712 /*---------------------------matrix.determinant() ----------------*/
1713 PyDoc_STRVAR(Matrix_determinant_doc,
1714 ".. method:: determinant()\n"
1715 "\n"
1716 "   Return the determinant of a matrix.\n"
1717 "\n"
1718 "   :return: Return the determinant of a matrix.\n"
1719 "   :rtype: float\n"
1720 "\n"
1721 "   .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n"
1722 );
1723 static PyObject *Matrix_determinant(MatrixObject *self)
1724 {
1725         if (BaseMath_ReadCallback(self) == -1)
1726                 return NULL;
1727
1728         if (self->num_col != self->num_row) {
1729                 PyErr_SetString(PyExc_ValueError,
1730                                 "Matrix.determinant(): "
1731                                 "only square matrices are supported");
1732                 return NULL;
1733         }
1734
1735         return PyFloat_FromDouble((double)matrix_determinant_internal(self));
1736 }
1737 /*---------------------------matrix.transpose() ------------------*/
1738 PyDoc_STRVAR(Matrix_transpose_doc,
1739 ".. method:: transpose()\n"
1740 "\n"
1741 "   Set the matrix to its transpose.\n"
1742 "\n"
1743 "   .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n"
1744 );
1745 static PyObject *Matrix_transpose(MatrixObject *self)
1746 {
1747         if (BaseMath_ReadCallback(self) == -1)
1748                 return NULL;
1749
1750         if (self->num_col != self->num_row) {
1751                 PyErr_SetString(PyExc_ValueError,
1752                                 "Matrix.transpose(d): "
1753                                 "only square matrices are supported");
1754                 return NULL;
1755         }
1756
1757         if (self->num_col == 2) {
1758                 const float t = MATRIX_ITEM(self, 1, 0);
1759                 MATRIX_ITEM(self, 1, 0) = MATRIX_ITEM(self, 0, 1);
1760                 MATRIX_ITEM(self, 0, 1) = t;
1761         }
1762         else if (self->num_col == 3) {
1763                 transpose_m3((float (*)[3])self->matrix);
1764         }
1765         else {
1766                 transpose_m4((float (*)[4])self->matrix);
1767         }
1768
1769         (void)BaseMath_WriteCallback(self);
1770         Py_RETURN_NONE;
1771 }
1772
1773 PyDoc_STRVAR(Matrix_transposed_doc,
1774 ".. method:: transposed()\n"
1775 "\n"
1776 "   Return a new, transposed matrix.\n"
1777 "\n"
1778 "   :return: a transposed matrix\n"
1779 "   :rtype: :class:`Matrix`\n"
1780 );
1781 static PyObject *Matrix_transposed(MatrixObject *self)
1782 {
1783         return matrix__apply_to_copy((PyNoArgsFunction)Matrix_transpose, self);
1784 }
1785
1786 /*---------------------------matrix.normalize() ------------------*/
1787 PyDoc_STRVAR(Matrix_normalize_doc,
1788 ".. method:: normalize()\n"
1789 "\n"
1790 "   Normalize each of the matrix columns.\n"
1791 );
1792 static PyObject *Matrix_normalize(MatrixObject *self)
1793 {
1794         if (BaseMath_ReadCallback(self) == -1)
1795                 return NULL;
1796
1797         if (self->num_col != self->num_row) {
1798                 PyErr_SetString(PyExc_ValueError,
1799                                 "Matrix.normalize(): "
1800                                 "only square matrices are supported");
1801                 return NULL;
1802         }
1803
1804         if (self->num_col == 3) {
1805                 normalize_m3((float (*)[3])self->matrix);
1806         }
1807         else if (self->num_col == 4) {
1808                 normalize_m4((float (*)[4])self->matrix);
1809         }
1810         else {
1811                 PyErr_SetString(PyExc_ValueError,
1812                                 "Matrix.normalize(): "
1813                                 "can only use a 3x3 or 4x4 matrix");
1814         }
1815
1816         (void)BaseMath_WriteCallback(self);
1817         Py_RETURN_NONE;
1818 }
1819
1820 PyDoc_STRVAR(Matrix_normalized_doc,
1821 ".. method:: normalized()\n"
1822 "\n"
1823 "   Return a column normalized matrix\n"
1824 "\n"
1825 "   :return: a column normalized matrix\n"
1826 "   :rtype: :class:`Matrix`\n"
1827 );
1828 static PyObject *Matrix_normalized(MatrixObject *self)
1829 {
1830         return matrix__apply_to_copy((PyNoArgsFunction)Matrix_normalize, self);
1831 }
1832
1833 /*---------------------------matrix.zero() -----------------------*/
1834 PyDoc_STRVAR(Matrix_zero_doc,
1835 ".. method:: zero()\n"
1836 "\n"
1837 "   Set all the matrix values to zero.\n"
1838 "\n"
1839 "   :rtype: :class:`Matrix`\n"
1840 );
1841 static PyObject *Matrix_zero(MatrixObject *self)
1842 {
1843         fill_vn_fl(self->matrix, self->num_col * self->num_row, 0.0f);
1844
1845         if (BaseMath_WriteCallback(self) == -1)
1846                 return NULL;
1847
1848         Py_RETURN_NONE;
1849
1850 }
1851 /*---------------------------matrix.identity(() ------------------*/
1852 static void matrix_identity_internal(MatrixObject *self)
1853 {
1854         BLI_assert((self->num_col == self->num_row) && (self->num_row <= 4));
1855
1856         if (self->num_col == 2) {
1857                 unit_m2((float (*)[2])self->matrix);
1858         }
1859         else if (self->num_col == 3) {
1860                 unit_m3((float (*)[3])self->matrix);
1861         }
1862         else {
1863                 unit_m4((float (*)[4])self->matrix);
1864         }
1865 }
1866
1867 PyDoc_STRVAR(Matrix_identity_doc,
1868 ".. method:: identity()\n"
1869 "\n"
1870 "   Set the matrix to the identity matrix.\n"
1871 "\n"
1872 "   .. note:: An object with zero location and rotation, a scale of one,\n"
1873 "      will have an identity matrix.\n"
1874 "\n"
1875 "   .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n"
1876 );
1877 static PyObject *Matrix_identity(MatrixObject *self)
1878 {
1879         if (BaseMath_ReadCallback(self) == -1)
1880                 return NULL;
1881
1882         if (self->num_col != self->num_row) {
1883                 PyErr_SetString(PyExc_ValueError,
1884                                 "Matrix.identity(): "
1885                                 "only square matrices are supported");
1886                 return NULL;
1887         }
1888
1889         matrix_identity_internal(self);
1890
1891         if (BaseMath_WriteCallback(self) == -1)
1892                 return NULL;
1893
1894         Py_RETURN_NONE;
1895 }
1896
1897 /*---------------------------Matrix.copy() ------------------*/
1898
1899 static PyObject *Matrix_copy_notest(MatrixObject *self, const float *matrix)
1900 {
1901         return Matrix_CreatePyObject((float *)matrix, self->num_col, self->num_row, Py_TYPE(self));
1902 }
1903
1904 PyDoc_STRVAR(Matrix_copy_doc,
1905 ".. method:: copy()\n"
1906 "\n"
1907 "   Returns a copy of this matrix.\n"
1908 "\n"
1909 "   :return: an instance of itself\n"
1910 "   :rtype: :class:`Matrix`\n"
1911 );
1912 static PyObject *Matrix_copy(MatrixObject *self)
1913 {
1914         if (BaseMath_ReadCallback(self) == -1)
1915                 return NULL;
1916
1917         return Matrix_copy_notest(self, self->matrix);
1918 }
1919 static PyObject *Matrix_deepcopy(MatrixObject *self, PyObject *args)
1920 {
1921         if (!mathutils_deepcopy_args_check(args))
1922                 return NULL;
1923         return Matrix_copy(self);
1924 }
1925
1926 /*----------------------------print object (internal)-------------*/
1927 /* print the object to screen */
1928 static PyObject *Matrix_repr(MatrixObject *self)
1929 {
1930         int col, row;
1931         PyObject *rows[MATRIX_MAX_DIM] = {NULL};
1932
1933         if (BaseMath_ReadCallback(self) == -1)
1934                 return NULL;
1935
1936         for (row = 0; row < self->num_row; row++) {
1937                 rows[row] = PyTuple_New(self->num_col);
1938                 for (col = 0; col < self->num_col; col++) {
1939                         PyTuple_SET_ITEM(rows[row], col, PyFloat_FromDouble(MATRIX_ITEM(self, row, col)));
1940                 }
1941         }
1942         switch (self->num_row) {
1943                 case 2: return PyUnicode_FromFormat("Matrix((%R,\n"
1944                                                     "        %R))", rows[0], rows[1]);
1945
1946                 case 3: return PyUnicode_FromFormat("Matrix((%R,\n"
1947                                                     "        %R,\n"
1948                                                     "        %R))", rows[0], rows[1], rows[2]);
1949
1950                 case 4: return PyUnicode_FromFormat("Matrix((%R,\n"
1951                                                     "        %R,\n"
1952                                                     "        %R,\n"
1953                                                     "        %R))", rows[0], rows[1], rows[2], rows[3]);
1954         }
1955
1956         Py_FatalError("Matrix(): invalid row size!");
1957         return NULL;
1958 }
1959
1960 #ifndef MATH_STANDALONE
1961 static PyObject *Matrix_str(MatrixObject *self)
1962 {
1963         DynStr *ds;
1964
1965         int maxsize[MATRIX_MAX_DIM];
1966         int row, col;
1967
1968         char dummy_buf[64];
1969
1970         if (BaseMath_ReadCallback(self) == -1)
1971                 return NULL;
1972
1973         ds = BLI_dynstr_new();
1974
1975         /* First determine the maximum width for each column */
1976         for (col = 0; col < self->num_col; col++) {
1977                 maxsize[col] = 0;
1978                 for (row = 0; row < self->num_row; row++) {
1979                         int size = BLI_snprintf(dummy_buf, sizeof(dummy_buf), "%.4f", MATRIX_ITEM(self, row, col));
1980                         maxsize[col] = max_ii(maxsize[col], size);
1981                 }
1982         }
1983
1984         /* Now write the unicode string to be printed */
1985         BLI_dynstr_appendf(ds, "<Matrix %dx%d (", self->num_row, self->num_col);
1986         for (row = 0; row < self->num_row; row++) {
1987                 for (col = 0; col < self->num_col; col++) {
1988                         BLI_dynstr_appendf(ds, col ? ", %*.4f" : "%*.4f", maxsize[col], MATRIX_ITEM(self, row, col));
1989                 }
1990                 BLI_dynstr_append(ds, row + 1 != self->num_row ? ")\n            (" : ")");
1991         }
1992         BLI_dynstr_append(ds, ">");
1993
1994         return mathutils_dynstr_to_py(ds); /* frees ds */
1995 }
1996 #endif
1997
1998 static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
1999 {
2000         PyObject *res;
2001         int ok = -1; /* zero is true */
2002
2003         if (MatrixObject_Check(a) && MatrixObject_Check(b)) {
2004                 MatrixObject *matA = (MatrixObject *)a;
2005                 MatrixObject *matB = (MatrixObject *)b;
2006
2007                 if (BaseMath_ReadCallback(matA) == -1 || BaseMath_ReadCallback(matB) == -1)
2008                         return NULL;
2009
2010                 ok = ((matA->num_row == matB->num_row) &&
2011                       (matA->num_col == matB->num_col) &&
2012                       EXPP_VectorsAreEqual(matA->matrix, matB->matrix, (matA->num_col * matA->num_row), 1)
2013                       ) ? 0 : -1;
2014         }
2015
2016         switch (op) {
2017                 case Py_NE:
2018                         ok = !ok;
2019                         /* fall-through */
2020                 case Py_EQ:
2021                         res = ok ? Py_False : Py_True;
2022                         break;
2023
2024                 case Py_LT:
2025                 case Py_LE:
2026                 case Py_GT:
2027                 case Py_GE:
2028                         res = Py_NotImplemented;
2029                         break;
2030                 default:
2031                         PyErr_BadArgument();
2032                         return NULL;
2033         }
2034
2035         return Py_INCREF(res), res;
2036 }
2037
2038 /*---------------------SEQUENCE PROTOCOLS------------------------
2039  * ----------------------------len(object)------------------------
2040  * sequence length */
2041 static int Matrix_len(MatrixObject *self)
2042 {
2043         return self->num_row;
2044 }
2045 /*----------------------------object[]---------------------------
2046  * sequence accessor (get)
2047  * the wrapped vector gives direct access to the matrix data */
2048 static PyObject *Matrix_item_row(MatrixObject *self, int row)
2049 {
2050         if (BaseMath_ReadCallback(self) == -1)
2051                 return NULL;
2052
2053         if (row < 0 || row >= self->num_row) {
2054                 PyErr_SetString(PyExc_IndexError,
2055                                 "matrix[attribute]: "
2056                                 "array index out of range");
2057                 return NULL;
2058         }
2059         return Vector_CreatePyObject_cb((PyObject *)self, self->num_col, mathutils_matrix_row_cb_index, row);
2060 }
2061 /* same but column access */
2062 static PyObject *Matrix_item_col(MatrixObject *self, int col)
2063 {
2064         if (BaseMath_ReadCallback(self) == -1)
2065                 return NULL;
2066
2067         if (col < 0 || col >= self->num_col) {
2068                 PyErr_SetString(PyExc_IndexError,
2069                                 "matrix[attribute]: "
2070                                 "array index out of range");
2071                 return NULL;
2072         }
2073         return Vector_CreatePyObject_cb((PyObject *)self, self->num_row, mathutils_matrix_col_cb_index, col);
2074 }
2075
2076 /*----------------------------object[]-------------------------
2077  * sequence accessor (set) */
2078
2079 static int Matrix_ass_item_row(MatrixObject *self, int row, PyObject *value)
2080 {
2081         int col;
2082         float vec[MATRIX_MAX_DIM];
2083         if (BaseMath_ReadCallback(self) == -1)
2084                 return -1;
2085
2086         if (row >= self->num_row || row < 0) {
2087                 PyErr_SetString(PyExc_IndexError,
2088                                 "matrix[attribute] = x: bad row");
2089                 return -1;
2090         }
2091
2092         if (mathutils_array_parse(vec, self->num_col, self->num_col, value, "matrix[i] = value assignment") < 0) {
2093                 return -1;
2094         }
2095
2096         /* Since we are assigning a row we cannot memcpy */
2097         for (col = 0; col < self->num_col; col++) {
2098                 MATRIX_ITEM(self, row, col) = vec[col];
2099         }
2100
2101         (void)BaseMath_WriteCallback(self);
2102         return 0;
2103 }
2104 static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value)
2105 {
2106         int row;
2107         float vec[MATRIX_MAX_DIM];
2108         if (BaseMath_ReadCallback(self) == -1)
2109                 return -1;
2110
2111         if (col >= self->num_col || col < 0) {
2112                 PyErr_SetString(PyExc_IndexError,
2113                                 "matrix[attribute] = x: bad col");
2114                 return -1;
2115         }
2116
2117         if (mathutils_array_parse(vec, self->num_row, self->num_row, value, "matrix[i] = value assignment") < 0) {
2118                 return -1;
2119         }
2120
2121         /* Since we are assigning a row we cannot memcpy */
2122         for (row = 0; row < self->num_row; row++) {
2123                 MATRIX_ITEM(self, row, col) = vec[row];
2124         }
2125
2126         (void)BaseMath_WriteCallback(self);
2127         return 0;
2128 }
2129
2130
2131 /*----------------------------object[z:y]------------------------
2132  * sequence slice (get)*/
2133 static PyObject *Matrix_slice(MatrixObject *self, int begin, int end)
2134 {
2135
2136         PyObject *tuple;
2137         int count;
2138
2139         if (BaseMath_ReadCallback(self) == -1)
2140                 return NULL;
2141
2142         CLAMP(begin, 0, self->num_row);
2143         CLAMP(end, 0, self->num_row);
2144         begin = MIN2(begin, end);
2145
2146         tuple = PyTuple_New(end - begin);
2147         for (count = begin; count < end; count++) {
2148                 PyTuple_SET_ITEM(tuple, count - begin,
2149                                  Vector_CreatePyObject_cb((PyObject *)self, self->num_col, mathutils_matrix_row_cb_index, count));
2150         }
2151
2152         return tuple;
2153 }
2154 /*----------------------------object[z:y]------------------------
2155  * sequence slice (set)*/
2156 static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value)
2157 {
2158         PyObject *value_fast = NULL;
2159
2160         if (BaseMath_ReadCallback(self) == -1)
2161                 return -1;
2162
2163         CLAMP(begin, 0, self->num_row);
2164         CLAMP(end, 0, self->num_row);
2165         begin = MIN2(begin, end);
2166
2167         /* non list/tuple cases */
2168         if (!(value_fast = PySequence_Fast(value, "matrix[begin:end] = value"))) {
2169                 /* PySequence_Fast sets the error */
2170                 return -1;
2171         }
2172         else {
2173                 const int size = end - begin;
2174                 int row, col;
2175                 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2176                 float vec[4];
2177
2178                 if (PySequence_Fast_GET_SIZE(value_fast) != size) {
2179                         Py_DECREF(value_fast);
2180                         PyErr_SetString(PyExc_ValueError,
2181                                         "matrix[begin:end] = []: "
2182                                         "size mismatch in slice assignment");
2183                         return -1;
2184                 }
2185
2186                 memcpy(mat, self->matrix, self->num_col * self->num_row * sizeof(float));
2187
2188                 /* parse sub items */
2189                 for (row = begin; row < end; row++) {
2190                         /* parse each sub sequence */
2191                         PyObject *item = PySequence_Fast_GET_ITEM(value_fast, row - begin);
2192
2193                         if (mathutils_array_parse(vec, self->num_col, self->num_col, item,
2194                                                   "matrix[begin:end] = value assignment") < 0)
2195                         {
2196                                 return -1;
2197                         }
2198
2199                         for (col = 0; col < self->num_col; col++) {
2200                                 mat[col * self->num_row + row] = vec[col];
2201                         }
2202                 }
2203
2204                 Py_DECREF(value_fast);
2205
2206                 /*parsed well - now set in matrix*/
2207                 memcpy(self->matrix, mat, self->num_col * self->num_row * sizeof(float));
2208
2209                 (void)BaseMath_WriteCallback(self);
2210                 return 0;
2211         }
2212 }
2213 /*------------------------NUMERIC PROTOCOLS----------------------
2214  *------------------------obj + obj------------------------------*/
2215 static PyObject *Matrix_add(PyObject *m1, PyObject *m2)
2216 {
2217         float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2218         MatrixObject *mat1 = NULL, *mat2 = NULL;
2219
2220         mat1 = (MatrixObject *)m1;
2221         mat2 = (MatrixObject *)m2;
2222
2223         if (!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
2224                 PyErr_Format(PyExc_TypeError,
2225                              "Matrix addition: (%s + %s) "
2226                              "invalid type for this operation",
2227                              Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
2228                 return NULL;
2229         }
2230
2231         if (BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1)
2232                 return NULL;
2233
2234         if (mat1->num_col != mat2->num_col || mat1->num_row != mat2->num_row) {
2235                 PyErr_SetString(PyExc_ValueError,
2236                                 "Matrix addition: "
2237                                 "matrices must have the same dimensions for this operation");
2238                 return NULL;
2239         }
2240
2241         add_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
2242
2243         return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_TYPE(mat1));
2244 }
2245 /*------------------------obj - obj------------------------------
2246  * subtraction */
2247 static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
2248 {
2249         float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2250         MatrixObject *mat1 = NULL, *mat2 = NULL;
2251
2252         mat1 = (MatrixObject *)m1;
2253         mat2 = (MatrixObject *)m2;
2254
2255         if (!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
2256                 PyErr_Format(PyExc_TypeError,
2257                              "Matrix subtraction: (%s - %s) "
2258                              "invalid type for this operation",
2259                              Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
2260                 return NULL;
2261         }
2262
2263         if (BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1)
2264                 return NULL;
2265
2266         if (mat1->num_col != mat2->num_col || mat1->num_row != mat2->num_row) {
2267                 PyErr_SetString(PyExc_ValueError,
2268                                 "Matrix addition: "
2269                                 "matrices must have the same dimensions for this operation");
2270                 return NULL;
2271         }
2272
2273         sub_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
2274
2275         return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_TYPE(mat1));
2276 }
2277 /*------------------------obj * obj------------------------------
2278  * multiplication */
2279 static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
2280 {
2281         float tmat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2282         mul_vn_vn_fl(tmat, mat->matrix, mat->num_col * mat->num_row, scalar);
2283         return Matrix_CreatePyObject(tmat, mat->num_col, mat->num_row, Py_TYPE(mat));
2284 }
2285
2286 static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
2287 {
2288         float scalar;
2289         int vec_size;
2290
2291         MatrixObject *mat1 = NULL, *mat2 = NULL;
2292
2293         if (MatrixObject_Check(m1)) {
2294                 mat1 = (MatrixObject *)m1;
2295                 if (BaseMath_ReadCallback(mat1) == -1)
2296                         return NULL;
2297         }
2298         if (MatrixObject_Check(m2)) {
2299                 mat2 = (MatrixObject *)m2;
2300                 if (BaseMath_ReadCallback(mat2) == -1)
2301                         return NULL;
2302         }
2303
2304         if (mat1 && mat2) {
2305                 /* MATRIX * MATRIX */
2306                 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2307
2308                 int col, row, item;
2309
2310                 if (mat1->num_col != mat2->num_row) {
2311                         PyErr_SetString(PyExc_ValueError,
2312                                         "matrix1 * matrix2: matrix1 number of columns "
2313                                         "and the matrix2 number of rows must be the same");
2314                         return NULL;
2315                 }
2316
2317                 for (col = 0; col < mat2->num_col; col++) {
2318                         for (row = 0; row < mat1->num_row; row++) {
2319                                 double dot = 0.0f;
2320                                 for (item = 0; item < mat1->num_col; item++) {
2321                                         dot += (double)(MATRIX_ITEM(mat1, row, item) * MATRIX_ITEM(mat2, item, col));
2322                                 }
2323                                 mat[(col * mat1->num_row) + row] = (float)dot;
2324                         }
2325                 }
2326
2327                 return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_TYPE(mat1));
2328         }
2329         else if (mat2) {
2330                 /*FLOAT/INT * MATRIX */
2331                 if (((scalar = PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred()) == 0) {
2332                         return matrix_mul_float(mat2, scalar);
2333                 }
2334         }
2335         else if (mat1) {
2336                 /* MATRIX * VECTOR */
2337                 if (VectorObject_Check(m2)) {
2338                         VectorObject *vec2 = (VectorObject *)m2;
2339                         float tvec[MATRIX_MAX_DIM];
2340                         if (BaseMath_ReadCallback(vec2) == -1)
2341                                 return NULL;
2342                         if (column_vector_multiplication(tvec, vec2, mat1) == -1) {
2343                                 return NULL;
2344                         }
2345
2346                         if (mat1->num_col == 4 && vec2->size == 3) {
2347                                 vec_size = 3;
2348                         }
2349                         else {
2350                                 vec_size = mat1->num_row;
2351                         }
2352
2353                         return Vector_CreatePyObject(tvec, vec_size, Py_TYPE(m2));
2354                 }
2355                 /*FLOAT/INT * MATRIX */
2356                 else if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) {
2357                         return matrix_mul_float(mat1, scalar);
2358                 }
2359         }
2360         else {
2361                 BLI_assert(!"internal error");
2362         }
2363
2364         PyErr_Format(PyExc_TypeError,
2365                      "Matrix multiplication: "
2366                      "not supported between '%.200s' and '%.200s' types",
2367                      Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
2368         return NULL;
2369 }
2370
2371 /*-----------------PROTOCOL DECLARATIONS--------------------------*/
2372 static PySequenceMethods Matrix_SeqMethods = {
2373         (lenfunc) Matrix_len,                       /* sq_length */
2374         (binaryfunc) NULL,                          /* sq_concat */
2375         (ssizeargfunc) NULL,                        /* sq_repeat */
2376         (ssizeargfunc) Matrix_item_row,             /* sq_item */
2377         (ssizessizeargfunc) NULL,                   /* sq_slice, deprecated */
2378         (ssizeobjargproc) Matrix_ass_item_row,      /* sq_ass_item */
2379         (ssizessizeobjargproc) NULL,                /* sq_ass_slice, deprecated */
2380         (objobjproc) NULL,                          /* sq_contains */
2381         (binaryfunc) NULL,                          /* sq_inplace_concat */
2382         (ssizeargfunc) NULL,                        /* sq_inplace_repeat */
2383 };
2384
2385
2386 static PyObject *Matrix_subscript(MatrixObject *self, PyObject *item)
2387 {
2388         if (PyIndex_Check(item)) {
2389                 Py_ssize_t i;
2390                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2391                 if (i == -1 && PyErr_Occurred())
2392                         return NULL;
2393                 if (i < 0)
2394                         i += self->num_row;
2395                 return Matrix_item_row(self, i);
2396         }
2397         else if (PySlice_Check(item)) {
2398                 Py_ssize_t start, stop, step, slicelength;
2399
2400                 if (PySlice_GetIndicesEx(item, self->num_row, &start, &stop, &step, &slicelength) < 0)
2401                         return NULL;
2402
2403                 if (slicelength <= 0) {
2404                         return PyTuple_New(0);
2405                 }
2406                 else if (step == 1) {
2407                         return Matrix_slice(self, start, stop);
2408                 }
2409                 else {
2410                         PyErr_SetString(PyExc_IndexError,
2411                                         "slice steps not supported with matrices");
2412                         return NULL;
2413                 }
2414         }
2415         else {
2416                 PyErr_Format(PyExc_TypeError,
2417                              "matrix indices must be integers, not %.200s",
2418                              Py_TYPE(item)->tp_name);
2419                 return NULL;
2420         }
2421 }
2422
2423 static int Matrix_ass_subscript(MatrixObject *self, PyObject *item, PyObject *value)
2424 {
2425         if (PyIndex_Check(item)) {
2426                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2427                 if (i == -1 && PyErr_Occurred())
2428                         return -1;
2429                 if (i < 0)
2430                         i += self->num_row;
2431                 return Matrix_ass_item_row(self, i, value);
2432         }
2433         else if (PySlice_Check(item)) {
2434                 Py_ssize_t start, stop, step, slicelength;
2435
2436                 if (PySlice_GetIndicesEx(item, self->num_row, &start, &stop, &step, &slicelength) < 0)
2437                         return -1;
2438
2439                 if (step == 1)
2440                         return Matrix_ass_slice(self, start, stop, value);
2441                 else {
2442                         PyErr_SetString(PyExc_IndexError,
2443                                         "slice steps not supported with matrices");
2444                         return -1;
2445                 }
2446         }
2447         else {
2448                 PyErr_Format(PyExc_TypeError,
2449                              "matrix indices must be integers, not %.200s",
2450                              Py_TYPE(item)->tp_name);
2451                 return -1;
2452         }
2453 }
2454
2455 static PyMappingMethods Matrix_AsMapping = {
2456         (lenfunc)Matrix_len,
2457         (binaryfunc)Matrix_subscript,
2458         (objobjargproc)Matrix_ass_subscript
2459 };
2460
2461
2462 static PyNumberMethods Matrix_NumMethods = {
2463         (binaryfunc)    Matrix_add,     /*nb_add*/
2464         (binaryfunc)    Matrix_sub,     /*nb_subtract*/
2465         (binaryfunc)    Matrix_mul,     /*nb_multiply*/
2466         NULL,                               /*nb_remainder*/
2467         NULL,                               /*nb_divmod*/
2468         NULL,                               /*nb_power*/
2469         (unaryfunc)     0,      /*nb_negative*/
2470         (unaryfunc)     0,      /*tp_positive*/
2471         (unaryfunc)     0,      /*tp_absolute*/
2472         (inquiry)   0,      /*tp_bool*/
2473         (unaryfunc) Matrix_inverted_noargs,        /*nb_invert*/
2474         NULL,                   /*nb_lshift*/
2475         (binaryfunc)0,      /*nb_rshift*/
2476         NULL,                   /*nb_and*/
2477         NULL,                   /*nb_xor*/
2478         NULL,                   /*nb_or*/
2479         NULL,                   /*nb_int*/
2480         NULL,                   /*nb_reserved*/
2481         NULL,                   /*nb_float*/
2482         NULL,                   /* nb_inplace_add */
2483         NULL,                   /* nb_inplace_subtract */
2484         NULL,                   /* nb_inplace_multiply */
2485         NULL,                   /* nb_inplace_remainder */
2486         NULL,                   /* nb_inplace_power */
2487         NULL,                   /* nb_inplace_lshift */
2488         NULL,                   /* nb_inplace_rshift */
2489         NULL,                   /* nb_inplace_and */
2490         NULL,                   /* nb_inplace_xor */
2491         NULL,                   /* nb_inplace_or */
2492         NULL,                   /* nb_floor_divide */
2493         NULL,                   /* nb_true_divide */
2494         NULL,                   /* nb_inplace_floor_divide */
2495         NULL,                   /* nb_inplace_true_divide */
2496         NULL,                   /* nb_index */
2497 };
2498
2499 PyDoc_STRVAR(Matrix_translation_doc,
2500 "The translation component of the matrix.\n\n:type: Vector"
2501 );
2502 static PyObject *Matrix_translation_get(MatrixObject *self, void *UNUSED(closure))
2503 {
2504         PyObject *ret;
2505
2506         if (BaseMath_ReadCallback(self) == -1)
2507                 return NULL;
2508
2509         /*must be 4x4 square matrix*/
2510         if (self->num_row != 4 || self->num_col != 4) {
2511                 PyErr_SetString(PyExc_AttributeError,
2512                                 "Matrix.translation: "
2513                                 "inappropriate matrix size, must be 4x4");
2514                 return NULL;
2515         }
2516
2517         ret = (PyObject *)Vector_CreatePyObject_cb((PyObject *)self, 3, mathutils_matrix_translation_cb_index, 3);
2518
2519         return ret;
2520 }
2521
2522 static int Matrix_translation_set(MatrixObject *self, PyObject *value, void *UNUSED(closure))
2523 {
2524         float tvec[3];
2525
2526         if (BaseMath_ReadCallback(self) == -1)
2527                 return -1;
2528
2529         /*must be 4x4 square matrix*/
2530         if (self->num_row != 4 || self->num_col != 4) {
2531                 PyErr_SetString(PyExc_AttributeError,
2532                                 "Matrix.translation: "
2533                                 "inappropriate matrix size, must be 4x4");
2534                 return -1;
2535         }
2536
2537         if ((mathutils_array_parse(tvec, 3, 3, value, "Matrix.translation")) == -1) {
2538                 return -1;
2539         }
2540
2541         copy_v3_v3(((float (*)[4])self->matrix)[3], tvec);
2542
2543         (void)BaseMath_WriteCallback(self);
2544
2545         return 0;
2546 }
2547
2548 PyDoc_STRVAR(Matrix_row_doc,
2549 "Access the matix by rows (default), (read-only).\n\n:type: Matrix Access"
2550 );
2551 static PyObject *Matrix_row_get(MatrixObject *self, void *UNUSED(closure))
2552 {
2553         return MatrixAccess_CreatePyObject(self, MAT_ACCESS_ROW);
2554 }
2555
2556 PyDoc_STRVAR(Matrix_col_doc,
2557 "Access the matix by colums, 3x3 and 4x4 only, (read-only).\n\n:type: Matrix Access"
2558 );
2559 static PyObject *Matrix_col_get(MatrixObject *self, void *UNUSED(closure))
2560 {
2561         return MatrixAccess_CreatePyObject(self, MAT_ACCESS_COL);
2562 }
2563
2564 PyDoc_STRVAR(Matrix_median_scale_doc,
2565 "The average scale applied to each axis (read-only).\n\n:type: float"
2566 );
2567 static PyObject *Matrix_median_scale_get(MatrixObject *self, void *UNUSED(closure))
2568 {
2569         float mat[3][3];
2570
2571         if (BaseMath_ReadCallback(self) == -1)
2572                 return NULL;
2573
2574         /*must be 3-4 cols, 3-4 rows, square matrix*/
2575         if ((self->num_row < 3) || (self->num_col < 3)) {
2576                 PyErr_SetString(PyExc_AttributeError,
2577                                 "Matrix.median_scale: "
2578                                 "inappropriate matrix size, 3x3 minimum");
2579                 return NULL;
2580         }
2581
2582         matrix_as_3x3(mat, self);
2583
2584         return PyFloat_FromDouble(mat3_to_scale(mat));
2585 }
2586
2587 PyDoc_STRVAR(Matrix_is_negative_doc,
2588 "True if this matrix results in a negative scale, 3x3 and 4x4 only, (read-only).\n\n:type: bool"
2589 );
2590 static PyObject *Matrix_is_negative_get(MatrixObject *self, void *UNUSED(closure))
2591 {
2592         if (BaseMath_ReadCallback(self) == -1)
2593                 return NULL;
2594
2595         /*must be 3-4 cols, 3-4 rows, square matrix*/
2596         if (self->num_row == 4 && self->num_col == 4)
2597                 return PyBool_FromLong(is_negative_m4((float (*)[4])self->matrix));
2598         else if (self->num_row == 3 && self->num_col == 3)
2599                 return PyBool_FromLong(is_negative_m3((float (*)[3])self->matrix));
2600         else {
2601                 PyErr_SetString(PyExc_AttributeError,
2602                                 "Matrix.is_negative: "
2603                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
2604                 return NULL;
2605         }
2606 }
2607
2608 PyDoc_STRVAR(Matrix_is_orthogonal_doc,
2609 "True if this matrix is orthogonal, 3x3 and 4x4 only, (read-only).\n\n:type: bool"
2610 );
2611 static PyObject *Matrix_is_orthogonal_get(MatrixObject *self, void *UNUSED(closure))
2612 {
2613         if (BaseMath_ReadCallback(self) == -1)
2614                 return NULL;
2615
2616         /*must be 3-4 cols, 3-4 rows, square matrix*/
2617         if (self->num_row == 4 && self->num_col == 4)
2618                 return PyBool_FromLong(is_orthonormal_m4((float (*)[4])self->matrix));
2619         else if (self->num_row == 3 && self->num_col == 3)
2620                 return PyBool_FromLong(is_orthonormal_m3((float (*)[3])self->matrix));
2621         else {
2622                 PyErr_SetString(PyExc_AttributeError,
2623                                 "Matrix.is_orthogonal: "
2624                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
2625                 return NULL;
2626         }
2627 }
2628
2629 PyDoc_STRVAR(Matrix_is_orthogonal_axis_vectors_doc,
2630 "True if this matrix has got orthogonal axis vectors, 3x3 and 4x4 only, (read-only).\n\n:type: bool"
2631 );
2632 static PyObject *Matrix_is_orthogonal_axis_vectors_get(MatrixObject *self, void *UNUSED(closure))
2633 {
2634         if (BaseMath_ReadCallback(self) == -1)
2635                 return NULL;
2636
2637         /*must be 3-4 cols, 3-4 rows, square matrix*/
2638         if (self->num_row == 4 && self->num_col == 4)
2639                 return PyBool_FromLong(is_orthogonal_m4((float (*)[4])self->matrix));
2640         else if (self->num_row == 3 && self->num_col == 3)
2641                 return PyBool_FromLong(is_orthogonal_m3((float (*)[3])self->matrix));
2642         else {
2643                 PyErr_SetString(PyExc_AttributeError,
2644                                 "Matrix.is_orthogonal_axis_vectors: "
2645                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
2646                 return NULL;
2647         }
2648 }
2649
2650 /*****************************************************************************/
2651 /* Python attributes get/set structure:                                      */
2652 /*****************************************************************************/
2653 static PyGetSetDef Matrix_getseters[] = {
2654         {(char *)"median_scale", (getter)Matrix_median_scale_get, (setter)NULL, Matrix_median_scale_doc, NULL},
2655         {(char *)"translation", (getter)Matrix_translation_get, (setter)Matrix_translation_set, Matrix_translation_doc, NULL},
2656         {(char *)"row", (getter)Matrix_row_get, (setter)NULL, Matrix_row_doc, NULL},
2657         {(char *)"col", (getter)Matrix_col_get, (setter)NULL, Matrix_col_doc, NULL},
2658         {(char *)"is_negative", (getter)Matrix_is_negative_get, (setter)NULL, Matrix_is_negative_doc, NULL},
2659         {(char *)"is_orthogonal", (getter)Matrix_is_orthogonal_get, (setter)NULL, Matrix_is_orthogonal_doc, NULL},
2660         {(char *)"is_orthogonal_axis_vectors", (getter)Matrix_is_orthogonal_axis_vectors_get, (setter)NULL, Matrix_is_orthogonal_axis_vectors_doc, NULL},
2661         {(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL},
2662         {(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
2663         {NULL, NULL, NULL, NULL, NULL}  /* Sentinel */
2664 };
2665
2666 /*-----------------------METHOD DEFINITIONS ----------------------*/
2667 static struct PyMethodDef Matrix_methods[] = {
2668         /* derived values */
2669         {"determinant", (PyCFunction) Matrix_determinant, METH_NOARGS, Matrix_determinant_doc},
2670         {"decompose", (PyCFunction) Matrix_decompose, METH_NOARGS, Matrix_decompose_doc},
2671
2672         /* in place only */
2673         {"zero", (PyCFunction) Matrix_zero, METH_NOARGS, Matrix_zero_doc},
2674         {"identity", (PyCFunction) Matrix_identity, METH_NOARGS, Matrix_identity_doc},
2675
2676         /* operate on original or copy */
2677         {"transpose", (PyCFunction) Matrix_transpose, METH_NOARGS, Matrix_transpose_doc},
2678         {"transposed", (PyCFunction) Matrix_transposed, METH_NOARGS, Matrix_transposed_doc},
2679         {"normalize", (PyCFunction) Matrix_normalize, METH_NOARGS, Matrix_normalize_doc},
2680         {"normalized", (PyCFunction) Matrix_normalized, METH_NOARGS, Matrix_normalized_doc},
2681         {"invert", (PyCFunction) Matrix_invert, METH_VARARGS, Matrix_invert_doc},
2682         {"inverted", (PyCFunction) Matrix_inverted, METH_VARARGS, Matrix_inverted_doc},
2683         {"invert_safe", (PyCFunction) Matrix_invert_safe, METH_NOARGS, Matrix_invert_safe_doc},
2684         {"inverted_safe", (PyCFunction) Matrix_inverted_safe, METH_NOARGS, Matrix_inverted_safe_doc},
2685         {"adjugate", (PyCFunction) Matrix_adjugate, METH_NOARGS, Matrix_adjugate_doc},
2686         {"adjugated", (PyCFunction) Matrix_adjugated, METH_NOARGS, Matrix_adjugated_doc},
2687         {"to_3x3", (PyCFunction) Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc},
2688         /* TODO. {"resize_3x3", (PyCFunction) Matrix_resize3x3, METH_NOARGS, Matrix_resize3x3_doc}, */
2689         {"to_4x4", (PyCFunction) Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc},
2690         {"resize_4x4", (PyCFunction) Matrix_resize_4x4, METH_NOARGS, Matrix_resize_4x4_doc},
2691         {"rotate", (PyCFunction) Matrix_rotate, METH_O, Matrix_rotate_doc},
2692
2693         /* return converted representation */
2694         {"to_euler", (PyCFunction) Matrix_to_euler, METH_VARARGS, Matrix_to_euler_doc},
2695         {"to_quaternion", (PyCFunction) Matrix_to_quaternion, METH_NOARGS, Matrix_to_quaternion_doc},
2696         {"to_scale", (PyCFunction) Matrix_to_scale, METH_NOARGS, Matrix_to_scale_doc},
2697         {"to_translation", (PyCFunction) Matrix_to_translation, METH_NOARGS, Matrix_to_translation_doc},
2698
2699         /* operation between 2 or more types  */
2700         {"lerp", (PyCFunction) Matrix_lerp, METH_VARARGS, Matrix_lerp_doc},
2701         {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
2702         {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
2703         {"__deepcopy__", (PyCFunction) Matrix_deepcopy, METH_VARARGS, Matrix_copy_doc},
2704
2705         /* class methods */
2706         {"Identity", (PyCFunction) C_Matrix_Identity, METH_VARARGS | METH_CLASS, C_Matrix_Identity_doc},
2707         {"Rotation", (PyCFunction) C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc},
2708         {"Scale", (PyCFunction) C_Matrix_Scale, METH_VARARGS | METH_CLASS, C_Matrix_Scale_doc},
2709         {"Shear", (PyCFunction) C_Matrix_Shear, METH_VARARGS | METH_CLASS, C_Matrix_Shear_doc},
2710         {"Translation", (PyCFunction) C_Matrix_Translation, METH_O | METH_CLASS, C_Matrix_Translation_doc},
2711         {"OrthoProjection", (PyCFunction) C_Matrix_OrthoProjection,  METH_VARARGS | METH_CLASS, C_Matrix_OrthoProjection_doc},
2712         {NULL, NULL, 0, NULL}
2713 };
2714
2715 /*------------------PY_OBECT DEFINITION--------------------------*/
2716 PyDoc_STRVAR(matrix_doc,
2717 "This object gives access to Matrices in Blender."
2718 );
2719 PyTypeObject matrix_Type = {
2720         PyVarObject_HEAD_INIT(NULL, 0)
2721         "Matrix",                           /*tp_name*/
2722         sizeof(MatrixObject),               /*tp_basicsize*/
2723         0,                                  /*tp_itemsize*/
2724         (destructor)BaseMathObject_dealloc, /*tp_dealloc*/
2725         NULL,                               /*tp_print*/
2726         NULL,                               /*tp_getattr*/
2727         NULL,                               /*tp_setattr*/
2728         NULL,                               /*tp_compare*/
2729         (reprfunc) Matrix_repr,             /*tp_repr*/
2730         &Matrix_NumMethods,                 /*tp_as_number*/
2731         &Matrix_SeqMethods,                 /*tp_as_sequence*/
2732         &Matrix_AsMapping,                  /*tp_as_mapping*/
2733         NULL,                               /*tp_hash*/
2734         NULL,                               /*tp_call*/
2735 #ifndef MATH_STANDALONE
2736         (reprfunc) Matrix_str,              /*tp_str*/
2737 #else
2738         NULL,                               /*tp_str*/
2739 #endif
2740         NULL,                               /*tp_getattro*/
2741         NULL,                               /*tp_setattro*/
2742         NULL,                               /*tp_as_buffer*/
2743         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
2744         matrix_doc,                         /*tp_doc*/
2745         (traverseproc)BaseMathObject_traverse,  /* tp_traverse */
2746         (inquiry)BaseMathObject_clear,      /*tp_clear*/
2747         (richcmpfunc)Matrix_richcmpr,       /*tp_richcompare*/
2748         0,                                  /*tp_weaklistoffset*/
2749         NULL,                               /*tp_iter*/
2750         NULL,                               /*tp_iternext*/
2751         Matrix_methods,                     /*tp_methods*/
2752         NULL,                               /*tp_members*/
2753         Matrix_getseters,                   /*tp_getset*/
2754         NULL,                               /*tp_base*/
2755         NULL,                               /*tp_dict*/
2756         NULL,                               /*tp_descr_get*/
2757         NULL,                               /*tp_descr_set*/
2758         0,                                  /*tp_dictoffset*/
2759         NULL,                               /*tp_init*/
2760         NULL,                               /*tp_alloc*/
2761         Matrix_new,                         /*tp_new*/
2762         NULL,                               /*tp_free*/
2763         NULL,                               /*tp_is_gc*/
2764         NULL,                               /*tp_bases*/
2765         NULL,                               /*tp_mro*/
2766         NULL,                               /*tp_cache*/
2767         NULL,                               /*tp_subclasses*/
2768         NULL,                               /*tp_weaklist*/
2769         NULL                                /*tp_del*/
2770 };
2771
2772 PyObject *Matrix_CreatePyObject(
2773         const float *mat,
2774         const unsigned short num_col, const unsigned short num_row,
2775         PyTypeObject *base_type)
2776 {
2777         MatrixObject *self;
2778         float *mat_alloc;
2779
2780         /* matrix objects can be any 2-4row x 2-4col matrix */
2781         if (num_col < 2 || num_col > 4 || num_row < 2 || num_row > 4) {
2782                 PyErr_SetString(PyExc_RuntimeError,
2783                                 "Matrix(): "
2784                                 "row and column sizes must be between 2 and 4");
2785                 return NULL;
2786         }
2787
2788         mat_alloc = PyMem_Malloc(num_col * num_row * sizeof(float));
2789         if (UNLIKELY(mat_alloc == NULL)) {
2790                 PyErr_SetString(PyExc_MemoryError,
2791                                 "Matrix(): "
2792                                 "problem allocating data");
2793                 return NULL;
2794         }
2795
2796         self = BASE_MATH_NEW(MatrixObject, matrix_Type, base_type);
2797         if (self) {
2798                 self->matrix = mat_alloc;
2799                 self->num_col = num_col;
2800                 self->num_row = num_row;
2801
2802                 /* init callbacks as NULL */
2803                 self->cb_user = NULL;
2804                 self->cb_type = self->cb_subtype = 0;
2805
2806                 if (mat) {  /*if a float array passed*/
2807                         memcpy(self->matrix, mat, num_col * num_row * sizeof(float));
2808                 }
2809                 else if (num_col == num_row) {
2810                         /* or if no arguments are passed return identity matrix for square matrices */
2811                         matrix_identity_internal(self);
2812                 }
2813                 else {
2814                         /* otherwise zero everything */
2815                         memset(self->matrix, 0, num_col * num_row * sizeof(float));
2816                 }
2817                 self->flag = BASE_MATH_FLAG_DEFAULT;
2818         }
2819         else {
2820                 PyMem_Free(mat_alloc);
2821         }
2822
2823         return (PyObject *)self;
2824 }
2825
2826 PyObject *Matrix_CreatePyObject_wrap(
2827         float *mat,
2828         const unsigned short num_col, const unsigned short num_row,
2829         PyTypeObject *base_type)
2830 {
2831         MatrixObject *self;
2832
2833         /* matrix objects can be any 2-4row x 2-4col matrix */
2834         if (num_col < 2 || num_col > 4 || num_row < 2 || num_row > 4) {
2835                 PyErr_SetString(PyExc_RuntimeError,
2836                                 "Matrix(): "
2837                                 "row and column sizes must be between 2 and 4");
2838                 return NULL;
2839         }
2840
2841         self = BASE_MATH_NEW(MatrixObject, matrix_Type, base_type);
2842         if (self) {
2843                 self->num_col = num_col;
2844                 self->num_row = num_row;
2845
2846                 /* init callbacks as NULL */
2847                 self->cb_user = NULL;
2848                 self->cb_type = self->cb_subtype = 0;
2849
2850                 self->matrix = mat;
2851                 self->flag = BASE_MATH_FLAG_DEFAULT | BASE_MATH_FLAG_IS_WRAP;
2852         }
2853         return (PyObject *) self;
2854 }
2855
2856 PyObject *Matrix_CreatePyObject_cb(PyObject *cb_user,
2857                                    const unsigned short num_col, const unsigned short num_row,
2858                                    unsigned char cb_type, unsigned char cb_subtype)
2859 {
2860         MatrixObject *self = (MatrixObject *)Matrix_CreatePyObject(NULL, num_col, num_row, NULL);
2861         if (self) {
2862                 Py_INCREF(cb_user);
2863                 self->cb_user         = cb_user;
2864                 self->cb_type         = cb_type;
2865                 self->cb_subtype      = cb_subtype;
2866                 PyObject_GC_Track(self);
2867         }
2868         return (PyObject *) self;
2869 }
2870
2871
2872 /* ----------------------------------------------------------------------------
2873  * special type for alternate access */
2874
2875 typedef struct {
2876         PyObject_HEAD /* required python macro   */
2877         MatrixObject *matrix_user;
2878         eMatrixAccess_t type;
2879 } MatrixAccessObject;
2880
2881 static int MatrixAccess_traverse(MatrixAccessObject *self, visitproc visit, void *arg)
2882 {
2883         Py_VISIT(self->matrix_user);
2884         return 0;
2885 }
2886
2887 static int MatrixAccess_clear(MatrixAccessObject *self)
2888 {
2889         Py_CLEAR(self->matrix_user);
2890         return 0;
2891 }
2892
2893 static void MatrixAccess_dealloc(MatrixAccessObject *self)
2894 {
2895         if (self->matrix_user) {
2896                 PyObject_GC_UnTrack(self);
2897                 MatrixAccess_clear(self);
2898         }
2899
2900         Py_TYPE(self)->tp_free(self);
2901 }
2902
2903 /* sequence access */
2904
2905 static int MatrixAccess_len(MatrixAccessObject *self)
2906 {
2907         return (self->type == MAT_ACCESS_ROW) ?
2908                self->matrix_user->num_row :
2909                self->matrix_user->num_col;
2910 }
2911
2912 static PyObject *MatrixAccess_slice(MatrixAccessObject *self, int begin, int end)
2913 {
2914         PyObject *tuple;
2915         int count;
2916
2917         /* row/col access */
2918         MatrixObject *matrix_user = self->matrix_user;
2919         int matrix_access_len;
2920         PyObject *(*Matrix_item_new)(MatrixObject *, int);
2921
2922         if (self->type == MAT_ACCESS_ROW) {
2923                 matrix_access_len = matrix_user->num_row;
2924                 Matrix_item_new = Matrix_item_row;
2925         }
2926         else { /* MAT_ACCESS_ROW */
2927                 matrix_access_len = matrix_user->num_col;
2928                 Matrix_item_new = Matrix_item_col;
2929         }
2930
2931         CLAMP(begin, 0, matrix_access_len);
2932         if (end < 0) end = (matrix_access_len + 1) + end;
2933         CLAMP(end, 0, matrix_access_len);
2934         begin = MIN2(begin, end);
2935
2936         tuple = PyTuple_New(end - begin);
2937         for (count = begin; count < end; count++) {
2938                 PyTuple_SET_ITEM(tuple, count - begin, Matrix_item_new(matrix_user, count));
2939         }
2940
2941         return tuple;
2942 }
2943
2944 static PyObject *MatrixAccess_subscript(MatrixAccessObject *self, PyObject *item)
2945 {
2946         MatrixObject *matrix_user = self->matrix_user;
2947
2948         if (PyIndex_Check(item)) {
2949                 Py_ssize_t i;
2950                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2951                 if (i == -1 && PyErr_Occurred())
2952                         return NULL;
2953                 if (self->type == MAT_ACCESS_ROW) {
2954                         if (i < 0)
2955                                 i += matrix_user->num_row;
2956                         return Matrix_item_row(matrix_user, i);
2957                 }
2958                 else { /* MAT_ACCESS_ROW */
2959                         if (i < 0)
2960                                 i += matrix_user->num_col;
2961                         return Matrix_item_col(matrix_user, i);
2962                 }
2963         }
2964         else if (PySlice_Check(item)) {
2965                 Py_ssize_t start, stop, step, slicelength;
2966
2967                 if (PySlice_GetIndicesEx(item, MatrixAccess_len(self), &start, &stop, &step, &slicelength) < 0)
2968                         return NULL;
2969
2970                 if (slicelength <= 0) {
2971                         return PyTuple_New(0);
2972                 }
2973                 else if (step == 1) {
2974                         return MatrixAccess_slice(self, start, stop);
2975                 }
2976                 else {
2977                         PyErr_SetString(PyExc_IndexError,
2978                                         "slice steps not supported with matrix accessors");
2979                         return NULL;
2980                 }
2981         }
2982         else {
2983                 PyErr_Format(PyExc_TypeError,
2984                              "matrix indices must be integers, not %.200s",
2985                              Py_TYPE(item)->tp_name);
2986                 return NULL;
2987         }
2988 }
2989
2990 static int MatrixAccess_ass_subscript(MatrixAccessObject *self, PyObject *item, PyObject *value)
2991 {
2992         MatrixObject *matrix_user = self->matrix_user;
2993
2994         if (PyIndex_Check(item)) {
2995                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2996                 if (i == -1 && PyErr_Occurred())
2997                         return -1;
2998
2999                 if (self->type == MAT_ACCESS_ROW) {
3000                         if (i < 0)
3001                                 i += matrix_user->num_row;
3002                         return Matrix_ass_item_row(matrix_user, i, value);
3003                 }
3004                 else { /* MAT_ACCESS_ROW */
3005                         if (i < 0)
3006                                 i += matrix_user->num_col;
3007                         return Matrix_ass_item_col(matrix_user, i, value);
3008                 }
3009
3010         }
3011         /* TODO, slice */
3012         else {
3013                 PyErr_Format(PyExc_TypeError,
3014                              "matrix indices must be integers, not %.200s",
3015                              Py_TYPE(item)->tp_name);
3016                 return -1;
3017         }
3018 }
3019
3020 static PyObject *MatrixAccess_iter(MatrixAccessObject *self)
3021 {
3022         /* Try get values from a collection */
3023         PyObject *ret;
3024         PyObject *iter = NULL;
3025         ret = MatrixAccess_slice(self, 0, MATRIX_MAX_DIM);
3026
3027         /* we know this is a tuple so no need to PyIter_Check
3028          * otherwise it could be NULL (unlikely) if conversion failed */
3029         if (ret) {
3030                 iter = PyObject_GetIter(ret);
3031                 Py_DECREF(ret);
3032         }
3033
3034         return iter;
3035 }
3036
3037 static PyMappingMethods MatrixAccess_AsMapping = {
3038         (lenfunc)MatrixAccess_len,
3039         (binaryfunc)MatrixAccess_subscript,
3040         (objobjargproc) MatrixAccess_ass_subscript
3041 };
3042
3043 PyTypeObject matrix_access_Type = {
3044         PyVarObject_HEAD_INIT(NULL, 0)
3045         "MatrixAccess",                     /*tp_name*/
3046         sizeof(MatrixAccessObject),         /*tp_basicsize*/
3047         0,                                  /*tp_itemsize*/
3048         (destructor)MatrixAccess_dealloc,   /*tp_dealloc*/
3049         NULL,                               /*tp_print*/
3050         NULL,                               /*tp_getattr*/
3051         NULL,                               /*tp_setattr*/
3052         NULL,                               /*tp_compare*/
3053         NULL,                               /*tp_repr*/
3054         NULL,                               /*tp_as_number*/
3055         NULL /*&MatrixAccess_SeqMethods*/ /* TODO */,           /*tp_as_sequence*/
3056         &MatrixAccess_AsMapping,            /*tp_as_mapping*/
3057         NULL,                               /*tp_hash*/
3058         NULL,                               /*tp_call*/
3059         NULL,                               /*tp_str*/
3060         NULL,                               /*tp_getattro*/
3061         NULL,                               /*tp_setattro*/
3062         NULL,                               /*tp_as_buffer*/
3063         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
3064         NULL,                               /*tp_doc*/
3065         (traverseproc)MatrixAccess_traverse,/*tp_traverse*/
3066         (inquiry)MatrixAccess_clear,        /*tp_clear*/
3067         NULL /* (richcmpfunc)MatrixAccess_richcmpr */ /* TODO*/, /*tp_richcompare*/
3068         0,                                  /*tp_weaklistoffset*/
3069         (getiterfunc)MatrixAccess_iter, /* getiterfunc tp_iter; */
3070 };
3071
3072 static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type)
3073 {
3074         MatrixAccessObject *matrix_access = (MatrixAccessObject *)PyObject_GC_New(MatrixObject, &matrix_access_Type);
3075
3076         matrix_access->matrix_user = matrix;
3077         Py_INCREF(matrix);
3078
3079         matrix_access->type = type;
3080
3081         return (PyObject *)matrix_access;
3082 }
3083
3084 /* end special access
3085  * -------------------------------------------------------------------------- */