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