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