typo cleanup, no functional changes.
[blender-staging.git] / source / blender / python / mathutils / mathutils_Matrix.c
1 /*
2  *
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * Contributor(s): Michel Selten & Joseph Gilbert
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/python/mathutils/mathutils_Matrix.c
28  *  \ingroup pymathutils
29  */
30
31
32 #include <Python.h>
33
34 #include "mathutils.h"
35
36 #include "BLI_math.h"
37 #include "BLI_utildefines.h"
38 #include "BLI_string.h"
39 #include "BLI_dynstr.h"
40
41 typedef enum eMatrixAccess_t {
42         MAT_ACCESS_ROW,
43         MAT_ACCESS_COL
44 } eMatrixAccess_t;
45
46 static PyObject *Matrix_copy(MatrixObject *self);
47 static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value);
48 static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self);
49 static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type);
50
51 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 int 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 int 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 int 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 { //scaling in arbitrary direction
616                 //normalize arbitrary axis
617                 float norm = 0.0f;
618                 int x;
619                 for (x = 0; x < vec_size; x++) {
620                         norm += tvec[x] * tvec[x];
621                 }
622                 norm = (float) sqrt(norm);
623                 for (x = 0; x < vec_size; x++) {
624                         tvec[x] /= norm;
625                 }
626                 if (matSize == 2) {
627                         mat[0] = 1 + ((factor - 1) *(tvec[0] * tvec[0]));
628                         mat[1] =     ((factor - 1) *(tvec[0] * tvec[1]));
629                         mat[2] =     ((factor - 1) *(tvec[0] * tvec[1]));
630                         mat[3] = 1 + ((factor - 1) *(tvec[1] * tvec[1]));
631                 }
632                 else {
633                         mat[0] = 1 + ((factor - 1) *(tvec[0] * tvec[0]));
634                         mat[1] =     ((factor - 1) *(tvec[0] * tvec[1]));
635                         mat[2] =     ((factor - 1) *(tvec[0] * tvec[2]));
636                         mat[3] =     ((factor - 1) *(tvec[0] * tvec[1]));
637                         mat[4] = 1 + ((factor - 1) *(tvec[1] * tvec[1]));
638                         mat[5] =     ((factor - 1) *(tvec[1] * tvec[2]));
639                         mat[6] =     ((factor - 1) *(tvec[0] * tvec[2]));
640                         mat[7] =     ((factor - 1) *(tvec[1] * tvec[2]));
641                         mat[8] = 1 + ((factor - 1) *(tvec[2] * tvec[2]));
642                 }
643         }
644         if (matSize == 4) {
645                 matrix_3x3_as_4x4(mat);
646         }
647         //pass to matrix creation
648         return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
649 }
650 //----------------------------------mathutils.Matrix.OrthoProjection() ---
651 //mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc.
652 PyDoc_STRVAR(C_Matrix_OrthoProjection_doc,
653 ".. classmethod:: OrthoProjection(axis, size)\n"
654 "\n"
655 "   Create a matrix to represent an orthographic projection.\n"
656 "\n"
657 "   :arg axis: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'],\n"
658 "      where a single axis is for a 2D matrix.\n"
659 "      Or a vector for an arbitrary axis\n"
660 "   :type axis: string or :class:`Vector`\n"
661 "   :arg size: The size of the projection matrix to construct [2, 4].\n"
662 "   :type size: int\n"
663 "   :return: A new projection matrix.\n"
664 "   :rtype: :class:`Matrix`\n"
665 );
666 static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
667 {
668         PyObject *axis;
669
670         int matSize, x;
671         float norm = 0.0f;
672         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f,
673                          0.0f, 0.0f, 0.0f, 0.0f,
674                          0.0f, 0.0f, 0.0f, 0.0f,
675                          0.0f, 0.0f, 0.0f, 1.0f};
676
677         if (!PyArg_ParseTuple(args, "Oi:Matrix.OrthoProjection", &axis, &matSize)) {
678                 return NULL;
679         }
680         if (matSize != 2 && matSize != 3 && matSize != 4) {
681                 PyErr_SetString(PyExc_ValueError,
682                                 "Matrix.OrthoProjection(): "
683                                 "can only return a 2x2 3x3 or 4x4 matrix");
684                 return NULL;
685         }
686
687         if (PyUnicode_Check(axis)) {    //ortho projection onto cardinal plane
688                 Py_ssize_t plane_len;
689                 const char *plane = _PyUnicode_AsStringAndSize(axis, &plane_len);
690                 if (matSize == 2) {
691                         if (plane_len == 1 && plane[0] == 'X') {
692                                 mat[0] = 1.0f;
693                         }
694                         else if (plane_len == 1 && plane[0] == 'Y') {
695                                 mat[3] = 1.0f;
696                         }
697                         else {
698                                 PyErr_Format(PyExc_ValueError,
699                                              "Matrix.OrthoProjection(): "
700                                              "unknown plane, expected: X, Y, not '%.200s'",
701                                              plane);
702                                 return NULL;
703                         }
704                 }
705                 else {
706                         if (plane_len == 2 && plane[0] == 'X' && plane[1] == 'Y') {
707                                 mat[0] = 1.0f;
708                                 mat[4] = 1.0f;
709                         }
710                         else if (plane_len == 2 && plane[0] == 'X' && plane[1] == 'Z') {
711                                 mat[0] = 1.0f;
712                                 mat[8] = 1.0f;
713                         }
714                         else if (plane_len == 2 && plane[0] == 'Y' && plane[1] == 'Z') {
715                                 mat[4] = 1.0f;
716                                 mat[8] = 1.0f;
717                         }
718                         else {
719                                 PyErr_Format(PyExc_ValueError,
720                                              "Matrix.OrthoProjection(): "
721                                              "unknown plane, expected: XY, XZ, YZ, not '%.200s'",
722                                              plane);
723                                 return NULL;
724                         }
725                 }
726         }
727         else {
728                 //arbitrary plane
729
730                 int vec_size = (matSize == 2 ? 2 : 3);
731                 float tvec[4];
732
733                 if (mathutils_array_parse(tvec, vec_size, vec_size, axis,
734                                           "Matrix.OrthoProjection(axis, size), invalid 'axis' arg") == -1)
735                 {
736                         return NULL;
737                 }
738
739                 //normalize arbitrary axis
740                 for (x = 0; x < vec_size; x++) {
741                         norm += tvec[x] * tvec[x];
742                 }
743                 norm = (float) sqrt(norm);
744                 for (x = 0; x < vec_size; x++) {
745                         tvec[x] /= norm;
746                 }
747                 if (matSize == 2) {
748                         mat[0] = 1 - (tvec[0] * tvec[0]);
749                         mat[1] =   - (tvec[0] * tvec[1]);
750                         mat[2] =   - (tvec[0] * tvec[1]);
751                         mat[3] = 1 - (tvec[1] * tvec[1]);
752                 }
753                 else if (matSize > 2) {
754                         mat[0] = 1 - (tvec[0] * tvec[0]);
755                         mat[1] =   - (tvec[0] * tvec[1]);
756                         mat[2] =   - (tvec[0] * tvec[2]);
757                         mat[3] =   - (tvec[0] * tvec[1]);
758                         mat[4] = 1 - (tvec[1] * tvec[1]);
759                         mat[5] =   - (tvec[1] * tvec[2]);
760                         mat[6] =   - (tvec[0] * tvec[2]);
761                         mat[7] =   - (tvec[1] * tvec[2]);
762                         mat[8] = 1 - (tvec[2] * tvec[2]);
763                 }
764         }
765         if (matSize == 4) {
766                 matrix_3x3_as_4x4(mat);
767         }
768         //pass to matrix creation
769         return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
770 }
771
772 PyDoc_STRVAR(C_Matrix_Shear_doc,
773 ".. classmethod:: Shear(plane, size, factor)\n"
774 "\n"
775 "   Create a matrix to represent an shear transformation.\n"
776 "\n"
777 "   :arg plane: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'],\n"
778 "      where a single axis is for a 2D matrix only.\n"
779 "   :type plane: string\n"
780 "   :arg size: The size of the shear matrix to construct [2, 4].\n"
781 "   :type size: int\n"
782 "   :arg factor: The factor of shear to apply. For a 3 or 4 *size* matrix\n"
783 "      pass a pair of floats corrasponding with the *plane* axis.\n"
784 "   :type factor: float or float pair\n"
785 "   :return: A new shear matrix.\n"
786 "   :rtype: :class:`Matrix`\n"
787 );
788 static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args)
789 {
790         int matSize;
791         const char *plane;
792         PyObject *fac;
793         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f,
794                          0.0f, 0.0f, 0.0f, 0.0f,
795                          0.0f, 0.0f, 0.0f, 0.0f,
796                          0.0f, 0.0f, 0.0f, 1.0f};
797
798         if (!PyArg_ParseTuple(args, "siO:Matrix.Shear", &plane, &matSize, &fac)) {
799                 return NULL;
800         }
801         if (matSize != 2 && matSize != 3 && matSize != 4) {
802                 PyErr_SetString(PyExc_ValueError,
803                                 "Matrix.Shear(): "
804                                 "can only return a 2x2 3x3 or 4x4 matrix");
805                 return NULL;
806         }
807
808         if (matSize == 2) {
809                 float const factor = PyFloat_AsDouble(fac);
810
811                 if (factor == -1.0f && PyErr_Occurred()) {
812                         PyErr_SetString(PyExc_TypeError,
813                                         "Matrix.Shear(): "
814                                         "the factor to be a float");
815                         return NULL;
816                 }
817
818                 /* unit */
819                 mat[0] = 1.0f;
820                 mat[3] = 1.0f;
821
822                 if (strcmp(plane, "X") == 0) {
823                         mat[2] = factor;
824                 }
825                 else if (strcmp(plane, "Y") == 0) {
826                         mat[1] = factor;
827                 }
828                 else {
829                         PyErr_SetString(PyExc_ValueError,
830                                         "Matrix.Shear(): "
831                                         "expected: X, Y or wrong matrix size for shearing plane");
832                         return NULL;
833                 }
834         }
835         else {
836                 /* 3 or 4, apply as 3x3, resize later if needed */
837                 float factor[2];
838
839                 if (mathutils_array_parse(factor, 2, 2, fac, "Matrix.Shear()") < 0) {
840                         return NULL;
841                 }
842
843                 /* unit */
844                 mat[0] = 1.0f;
845                 mat[4] = 1.0f;
846                 mat[8] = 1.0f;
847
848                 if (strcmp(plane, "XY") == 0) {
849                         mat[6] = factor[0];
850                         mat[7] = factor[1];
851                 }
852                 else if (strcmp(plane, "XZ") == 0) {
853                         mat[3] = factor[0];
854                         mat[5] = factor[1];
855                 }
856                 else if (strcmp(plane, "YZ") == 0) {
857                         mat[1] = factor[0];
858                         mat[2] = factor[1];
859                 }
860                 else {
861                         PyErr_SetString(PyExc_ValueError,
862                                         "Matrix.Shear(): "
863                                         "expected: X, Y, XY, XZ, YZ");
864                         return NULL;
865                 }
866         }
867
868         if (matSize == 4) {
869                 matrix_3x3_as_4x4(mat);
870         }
871         //pass to matrix creation
872         return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
873 }
874
875 void matrix_as_3x3(float mat[3][3], MatrixObject *self)
876 {
877         copy_v3_v3(mat[0], MATRIX_COL_PTR(self, 0));
878         copy_v3_v3(mat[1], MATRIX_COL_PTR(self, 1));
879         copy_v3_v3(mat[2], MATRIX_COL_PTR(self, 2));
880 }
881
882 /* assumes rowsize == colsize is checked and the read callback has run */
883 static float matrix_determinant_internal(MatrixObject *self)
884 {
885         if (self->num_col == 2) {
886                 return determinant_m2(MATRIX_ITEM(self, 0, 0), MATRIX_ITEM(self, 0, 1),
887                                       MATRIX_ITEM(self, 1, 0), MATRIX_ITEM(self, 1, 1));
888         }
889         else if (self->num_col == 3) {
890                 return determinant_m3(MATRIX_ITEM(self, 0, 0), MATRIX_ITEM(self, 0, 1), MATRIX_ITEM(self, 0, 2),
891                                       MATRIX_ITEM(self, 1, 0), MATRIX_ITEM(self, 1, 1), MATRIX_ITEM(self, 1, 2),
892                                       MATRIX_ITEM(self, 2, 0), MATRIX_ITEM(self, 2, 1), MATRIX_ITEM(self, 2, 2));
893         }
894         else {
895                 return determinant_m4((float (*)[4])self->matrix);
896         }
897 }
898
899
900 /*-----------------------------METHODS----------------------------*/
901 PyDoc_STRVAR(Matrix_to_quaternion_doc,
902 ".. method:: to_quaternion()\n"
903 "\n"
904 "   Return a quaternion representation of the rotation matrix.\n"
905 "\n"
906 "   :return: Quaternion representation of the rotation matrix.\n"
907 "   :rtype: :class:`Quaternion`\n"
908 );
909 static PyObject *Matrix_to_quaternion(MatrixObject *self)
910 {
911         float quat[4];
912
913         if (BaseMath_ReadCallback(self) == -1)
914                 return NULL;
915
916         /* must be 3-4 cols, 3-4 rows, square matrix */
917         if ((self->num_row < 3) || (self->num_col < 3) || (self->num_row != self->num_col)) {
918                 PyErr_SetString(PyExc_ValueError,
919                                 "Matrix.to_quat(): "
920                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
921                 return NULL;
922         }
923         if (self->num_row == 3) {
924                 mat3_to_quat(quat, (float (*)[3])self->matrix);
925         }
926         else {
927                 mat4_to_quat(quat, (float (*)[4])self->matrix);
928         }
929
930         return Quaternion_CreatePyObject(quat, Py_NEW, NULL);
931 }
932
933 /*---------------------------matrix.toEuler() --------------------*/
934 PyDoc_STRVAR(Matrix_to_euler_doc,
935 ".. method:: to_euler(order, euler_compat)\n"
936 "\n"
937 "   Return an Euler representation of the rotation matrix\n"
938 "   (3x3 or 4x4 matrix only).\n"
939 "\n"
940 "   :arg order: Optional rotation order argument in\n"
941 "      ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n"
942 "   :type order: string\n"
943 "   :arg euler_compat: Optional euler argument the new euler will be made\n"
944 "      compatible with (no axis flipping between them).\n"
945 "      Useful for converting a series of matrices to animation curves.\n"
946 "   :type euler_compat: :class:`Euler`\n"
947 "   :return: Euler representation of the matrix.\n"
948 "   :rtype: :class:`Euler`\n"
949 );
950 static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
951 {
952         const char *order_str = NULL;
953         short order = EULER_ORDER_XYZ;
954         float eul[3], eul_compatf[3];
955         EulerObject *eul_compat = NULL;
956
957         float tmat[3][3];
958         float (*mat)[3];
959
960         if (BaseMath_ReadCallback(self) == -1)
961                 return NULL;
962
963         if (!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat))
964                 return NULL;
965
966         if (eul_compat) {
967                 if (BaseMath_ReadCallback(eul_compat) == -1)
968                         return NULL;
969
970                 copy_v3_v3(eul_compatf, eul_compat->eul);
971         }
972
973         /*must be 3-4 cols, 3-4 rows, square matrix */
974         if (self->num_row ==3 && self->num_col ==3) {
975                 mat = (float (*)[3])self->matrix;
976         }
977         else if (self->num_row ==4 && self->num_col ==4) {
978                 copy_m3_m4(tmat, (float (*)[4])self->matrix);
979                 mat = tmat;
980         }
981         else {
982                 PyErr_SetString(PyExc_ValueError,
983                                 "Matrix.to_euler(): "
984                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
985                 return NULL;
986         }
987
988         if (order_str) {
989                 order = euler_order_from_string(order_str, "Matrix.to_euler()");
990
991                 if (order == -1)
992                         return NULL;
993         }
994
995         if (eul_compat) {
996                 if (order == 1) mat3_to_compatible_eul(eul, eul_compatf, mat);
997                 else                    mat3_to_compatible_eulO(eul, eul_compatf, order, mat);
998         }
999         else {
1000                 if (order == 1) mat3_to_eul(eul, mat);
1001                 else                    mat3_to_eulO(eul, order, mat);
1002         }
1003
1004         return Euler_CreatePyObject(eul, order, Py_NEW, NULL);
1005 }
1006
1007 PyDoc_STRVAR(Matrix_resize_4x4_doc,
1008 ".. method:: resize_4x4()\n"
1009 "\n"
1010 "   Resize the matrix to 4x4.\n"
1011 );
1012 static PyObject *Matrix_resize_4x4(MatrixObject *self)
1013 {
1014         float mat[4][4] = MAT4_UNITY;
1015         int col;
1016
1017         if (self->wrapped == Py_WRAP) {
1018                 PyErr_SetString(PyExc_TypeError,
1019                                 "Matrix.resize_4x4(): "
1020                                 "cannot resize wrapped data - make a copy and resize that");
1021                 return NULL;
1022         }
1023         if (self->cb_user) {
1024                 PyErr_SetString(PyExc_TypeError,
1025                                 "Matrix.resize_4x4(): "
1026                                 "cannot resize owned data - make a copy and resize that");
1027                 return NULL;
1028         }
1029
1030         self->matrix = PyMem_Realloc(self->matrix, (sizeof(float) * 16));
1031         if (self->matrix == NULL) {
1032                 PyErr_SetString(PyExc_MemoryError,
1033                                 "Matrix.resize_4x4(): "
1034                                 "problem allocating pointer space");
1035                 return NULL;
1036         }
1037
1038         for (col = 0; col < self->num_col; col++) {
1039                 memcpy(mat[col], MATRIX_COL_PTR(self, col), self->num_row * sizeof(float));
1040         }
1041
1042         copy_m4_m4((float (*)[4])self->matrix, (float (*)[4])mat);
1043
1044         self->num_col = 4;
1045         self->num_row = 4;
1046
1047         Py_RETURN_NONE;
1048 }
1049
1050 PyDoc_STRVAR(Matrix_to_4x4_doc,
1051 ".. method:: to_4x4()\n"
1052 "\n"
1053 "   Return a 4x4 copy of this matrix.\n"
1054 "\n"
1055 "   :return: a new matrix.\n"
1056 "   :rtype: :class:`Matrix`\n"
1057 );
1058 static PyObject *Matrix_to_4x4(MatrixObject *self)
1059 {
1060         if (BaseMath_ReadCallback(self) == -1)
1061                 return NULL;
1062
1063         if (self->num_row == 4 && self->num_col == 4) {
1064                 return Matrix_CreatePyObject(self->matrix, 4, 4, Py_NEW, Py_TYPE(self));
1065         }
1066         else if (self->num_row == 3 && self->num_col == 3) {
1067                 float mat[4][4];
1068                 copy_m4_m3(mat, (float (*)[3])self->matrix);
1069                 return Matrix_CreatePyObject((float *)mat, 4, 4, Py_NEW, Py_TYPE(self));
1070         }
1071         /* TODO, 2x2 matrix */
1072
1073         PyErr_SetString(PyExc_TypeError,
1074                         "Matrix.to_4x4(): "
1075                         "inappropriate matrix size");
1076         return NULL;
1077 }
1078
1079 PyDoc_STRVAR(Matrix_to_3x3_doc,
1080 ".. method:: to_3x3()\n"
1081 "\n"
1082 "   Return a 3x3 copy of this matrix.\n"
1083 "\n"
1084 "   :return: a new matrix.\n"
1085 "   :rtype: :class:`Matrix`\n"
1086 );
1087 static PyObject *Matrix_to_3x3(MatrixObject *self)
1088 {
1089         float mat[3][3];
1090
1091         if (BaseMath_ReadCallback(self) == -1)
1092                 return NULL;
1093
1094         if ((self->num_row < 3) || (self->num_col < 3)) {
1095                 PyErr_SetString(PyExc_TypeError,
1096                                 "Matrix.to_3x3(): inappropriate matrix size");
1097                 return NULL;
1098         }
1099
1100         matrix_as_3x3(mat, self);
1101
1102         return Matrix_CreatePyObject((float *)mat, 3, 3, Py_NEW, Py_TYPE(self));
1103 }
1104
1105 PyDoc_STRVAR(Matrix_to_translation_doc,
1106 ".. method:: to_translation()\n"
1107 "\n"
1108 "   Return a the translation part of a 4 row matrix.\n"
1109 "\n"
1110 "   :return: Return a the translation of a matrix.\n"
1111 "   :rtype: :class:`Vector`\n"
1112 );
1113 static PyObject *Matrix_to_translation(MatrixObject *self)
1114 {
1115         if (BaseMath_ReadCallback(self) == -1)
1116                 return NULL;
1117
1118         if ((self->num_row < 3) || self->num_col < 4) {
1119                 PyErr_SetString(PyExc_TypeError,
1120                                 "Matrix.to_translation(): "
1121                                 "inappropriate matrix size");
1122                 return NULL;
1123         }
1124
1125         return Vector_CreatePyObject(MATRIX_COL_PTR(self, 3), 3, Py_NEW, NULL);
1126 }
1127
1128 PyDoc_STRVAR(Matrix_to_scale_doc,
1129 ".. method:: to_scale()\n"
1130 "\n"
1131 "   Return a the scale part of a 3x3 or 4x4 matrix.\n"
1132 "\n"
1133 "   :return: Return a the scale of a matrix.\n"
1134 "   :rtype: :class:`Vector`\n"
1135 "\n"
1136 "   .. 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"
1137 );
1138 static PyObject *Matrix_to_scale(MatrixObject *self)
1139 {
1140         float rot[3][3];
1141         float mat[3][3];
1142         float size[3];
1143
1144         if (BaseMath_ReadCallback(self) == -1)
1145                 return NULL;
1146
1147         /*must be 3-4 cols, 3-4 rows, square matrix */
1148         if ((self->num_row < 3) || (self->num_col < 3)) {
1149                 PyErr_SetString(PyExc_TypeError,
1150                                 "Matrix.to_scale(): "
1151                                 "inappropriate matrix size, 3x3 minimum size");
1152                 return NULL;
1153         }
1154
1155         matrix_as_3x3(mat, self);
1156
1157         /* compatible mat4_to_loc_rot_size */
1158         mat3_to_rot_size(rot, size, mat);
1159
1160         return Vector_CreatePyObject(size, 3, Py_NEW, NULL);
1161 }
1162
1163 /*---------------------------matrix.invert() ---------------------*/
1164 PyDoc_STRVAR(Matrix_invert_doc,
1165 ".. method:: invert()\n"
1166 "\n"
1167 "   Set the matrix to its inverse.\n"
1168 "\n"
1169 "   .. note:: When the matrix cant be inverted a :exc:`ValueError` exception is raised.\n"
1170 "\n"
1171 "   .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n"
1172 );
1173 static PyObject *Matrix_invert(MatrixObject *self)
1174 {
1175
1176         int x, y, z = 0;
1177         float det = 0.0f;
1178         float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f,
1179                          0.0f, 0.0f, 0.0f, 0.0f,
1180                          0.0f, 0.0f, 0.0f, 0.0f,
1181                          0.0f, 0.0f, 0.0f, 1.0f};
1182
1183         if (BaseMath_ReadCallback(self) == -1)
1184                 return NULL;
1185
1186         if (self->num_col != self->num_row) {
1187                 PyErr_SetString(PyExc_TypeError,
1188                                 "Matrix.invert(ed): "
1189                                 "only square matrices are supported");
1190                 return NULL;
1191         }
1192
1193         /* calculate the determinant */
1194         det = matrix_determinant_internal(self);
1195
1196         if (det != 0) {
1197                 /* calculate the classical adjoint */
1198                 if (self->num_col == 2) {
1199                         mat[0] =  MATRIX_ITEM(self, 1, 1);
1200                         mat[1] = -MATRIX_ITEM(self, 0, 1);
1201                         mat[2] = -MATRIX_ITEM(self, 1, 0);
1202                         mat[3] =  MATRIX_ITEM(self, 0, 0);
1203                 }
1204                 else if (self->num_col == 3) {
1205                         adjoint_m3_m3((float (*)[3]) mat,(float (*)[3])self->matrix);
1206                 }
1207                 else if (self->num_col == 4) {
1208                         adjoint_m4_m4((float (*)[4]) mat, (float (*)[4])self->matrix);
1209                 }
1210                 /* divide by determinate */
1211                 for (x = 0; x < (self->num_col * self->num_row); x++) {
1212                         mat[x] /= det;
1213                 }
1214                 /* set values */
1215                 for (x = 0; x < self->num_col; x++) {
1216                         for (y = 0; y < self->num_row; y++) {
1217                                 MATRIX_ITEM(self, y, x) = mat[z];
1218                                 z++;
1219                         }
1220                 }
1221                 /*transpose
1222                 Matrix_transpose(self);*/
1223         }
1224         else {
1225                 PyErr_SetString(PyExc_ValueError,
1226                                 "Matrix.invert(ed): "
1227                                 "matrix does not have an inverse");
1228                 return NULL;
1229         }
1230
1231         (void)BaseMath_WriteCallback(self);
1232         Py_RETURN_NONE;
1233 }
1234
1235 PyDoc_STRVAR(Matrix_inverted_doc,
1236 ".. method:: inverted()\n"
1237 "\n"
1238 "   Return an inverted copy of the matrix.\n"
1239 "\n"
1240 "   :return: the  inverted matrix.\n"
1241 "   :rtype: :class:`Matrix`\n"
1242 "\n"
1243 "   .. note:: When the matrix cant be inverted a :exc:`ValueError` exception is raised.\n"
1244 );
1245 static PyObject *Matrix_inverted(MatrixObject *self)
1246 {
1247         return matrix__apply_to_copy((PyNoArgsFunction)Matrix_invert, self);
1248 }
1249
1250 PyDoc_STRVAR(Matrix_rotate_doc,
1251 ".. method:: rotate(other)\n"
1252 "\n"
1253 "   Rotates the matrix a by another mathutils value.\n"
1254 "\n"
1255 "   :arg other: rotation component of mathutils value\n"
1256 "   :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n"
1257 "\n"
1258 "   .. note:: If any of the columns are not unit length this may not have desired results.\n"
1259 );
1260 static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value)
1261 {
1262         float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
1263
1264         if (BaseMath_ReadCallback(self) == -1)
1265                 return NULL;
1266
1267         if (mathutils_any_to_rotmat(other_rmat, value, "matrix.rotate(value)") == -1)
1268                 return NULL;
1269
1270         if (self->num_row != 3 || self->num_col != 3) {
1271                 PyErr_SetString(PyExc_TypeError,
1272                                 "Matrix.rotate(): "
1273                                 "must have 3x3 dimensions");
1274                 return NULL;
1275         }
1276
1277         matrix_as_3x3(self_rmat, self);
1278         mul_m3_m3m3(rmat, other_rmat, self_rmat);
1279
1280         copy_m3_m3((float (*)[3])(self->matrix), rmat);
1281
1282         (void)BaseMath_WriteCallback(self);
1283         Py_RETURN_NONE;
1284 }
1285
1286 /*---------------------------matrix.decompose() ---------------------*/
1287 PyDoc_STRVAR(Matrix_decompose_doc,
1288 ".. method:: decompose()\n"
1289 "\n"
1290 "   Return the location, rotaion and scale components of this matrix.\n"
1291 "\n"
1292 "   :return: loc, rot, scale triple.\n"
1293 "   :rtype: (:class:`Vector`, :class:`Quaternion`, :class:`Vector`)"
1294 );
1295 static PyObject *Matrix_decompose(MatrixObject *self)
1296 {
1297         PyObject *ret;
1298         float loc[3];
1299         float rot[3][3];
1300         float quat[4];
1301         float size[3];
1302
1303         if (self->num_row != 4 || self->num_col != 4) {
1304                 PyErr_SetString(PyExc_TypeError,
1305                                 "Matrix.decompose(): "
1306                                 "inappropriate matrix size - expects 4x4 matrix");
1307                 return NULL;
1308         }
1309
1310         if (BaseMath_ReadCallback(self) == -1)
1311                 return NULL;
1312
1313         mat4_to_loc_rot_size(loc, rot, size, (float (*)[4])self->matrix);
1314         mat3_to_quat(quat, rot);
1315
1316         ret = PyTuple_New(3);
1317         PyTuple_SET_ITEM(ret, 0, Vector_CreatePyObject(loc, 3, Py_NEW, NULL));
1318         PyTuple_SET_ITEM(ret, 1, Quaternion_CreatePyObject(quat, Py_NEW, NULL));
1319         PyTuple_SET_ITEM(ret, 2, Vector_CreatePyObject(size, 3, Py_NEW, NULL));
1320
1321         return ret;
1322 }
1323
1324
1325
1326 PyDoc_STRVAR(Matrix_lerp_doc,
1327 ".. function:: lerp(other, factor)\n"
1328 "\n"
1329 "   Returns the interpolation of two matrices.\n"
1330 "\n"
1331 "   :arg other: value to interpolate with.\n"
1332 "   :type other: :class:`Matrix`\n"
1333 "   :arg factor: The interpolation value in [0.0, 1.0].\n"
1334 "   :type factor: float\n"
1335 "   :return: The interpolated rotation.\n"
1336 "   :rtype: :class:`Matrix`\n"
1337 );
1338 static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
1339 {
1340         MatrixObject *mat2 = NULL;
1341         float fac, mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
1342
1343         if (!PyArg_ParseTuple(args, "O!f:lerp", &matrix_Type, &mat2, &fac))
1344                 return NULL;
1345
1346         if (self->num_col != mat2->num_col || self->num_row != mat2->num_row) {
1347                 PyErr_SetString(PyExc_ValueError,
1348                                 "Matrix.lerp(): "
1349                                 "expects both matrix objects of the same dimensions");
1350                 return NULL;
1351         }
1352
1353         if (BaseMath_ReadCallback(self) == -1 || BaseMath_ReadCallback(mat2) == -1)
1354                 return NULL;
1355
1356         /* TODO, different sized matrix */
1357         if (self->num_col == 4 && self->num_row == 4) {
1358                 blend_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac);
1359         }
1360         else if (self->num_col == 3 && self->num_row == 3) {
1361                 blend_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac);
1362         }
1363         else {
1364                 PyErr_SetString(PyExc_ValueError,
1365                                 "Matrix.lerp(): "
1366                                 "only 3x3 and 4x4 matrices supported");
1367                 return NULL;
1368         }
1369
1370         return Matrix_CreatePyObject(mat, self->num_col, self->num_row, Py_NEW, Py_TYPE(self));
1371 }
1372
1373 /*---------------------------matrix.determinant() ----------------*/
1374 PyDoc_STRVAR(Matrix_determinant_doc,
1375 ".. method:: determinant()\n"
1376 "\n"
1377 "   Return the determinant of a matrix.\n"
1378 "\n"
1379 "   :return: Return a the determinant of a matrix.\n"
1380 "   :rtype: float\n"
1381 "\n"
1382 "   .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n"
1383 );
1384 static PyObject *Matrix_determinant(MatrixObject *self)
1385 {
1386         if (BaseMath_ReadCallback(self) == -1)
1387                 return NULL;
1388
1389         if (self->num_col != self->num_row) {
1390                 PyErr_SetString(PyExc_TypeError,
1391                                 "Matrix.determinant(): "
1392                                 "only square matrices are supported");
1393                 return NULL;
1394         }
1395
1396         return PyFloat_FromDouble((double)matrix_determinant_internal(self));
1397 }
1398 /*---------------------------matrix.transpose() ------------------*/
1399 PyDoc_STRVAR(Matrix_transpose_doc,
1400 ".. method:: transpose()\n"
1401 "\n"
1402 "   Set the matrix to its transpose.\n"
1403 "\n"
1404 "   .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n"
1405 );
1406 static PyObject *Matrix_transpose(MatrixObject *self)
1407 {
1408         if (BaseMath_ReadCallback(self) == -1)
1409                 return NULL;
1410
1411         if (self->num_col != self->num_row) {
1412                 PyErr_SetString(PyExc_TypeError,
1413                                 "Matrix.transpose(d): "
1414                                 "only square matrices are supported");
1415                 return NULL;
1416         }
1417
1418         if (self->num_col == 2) {
1419                 const float t = MATRIX_ITEM(self, 1, 0);
1420                 MATRIX_ITEM(self, 1, 0) = MATRIX_ITEM(self, 0, 1);
1421                 MATRIX_ITEM(self, 0, 1) = t;
1422         }
1423         else if (self->num_col == 3) {
1424                 transpose_m3((float (*)[3])self->matrix);
1425         }
1426         else {
1427                 transpose_m4((float (*)[4])self->matrix);
1428         }
1429
1430         (void)BaseMath_WriteCallback(self);
1431         Py_RETURN_NONE;
1432 }
1433
1434 PyDoc_STRVAR(Matrix_transposed_doc,
1435 ".. method:: transposed()\n"
1436 "\n"
1437 "   Return a new, transposed matrix.\n"
1438 "\n"
1439 "   :return: a transposed matrix\n"
1440 "   :rtype: :class:`Matrix`\n"
1441 );
1442 static PyObject *Matrix_transposed(MatrixObject *self)
1443 {
1444         return matrix__apply_to_copy((PyNoArgsFunction)Matrix_transpose, self);
1445 }
1446
1447 /*---------------------------matrix.zero() -----------------------*/
1448 PyDoc_STRVAR(Matrix_zero_doc,
1449 ".. method:: zero()\n"
1450 "\n"
1451 "   Set all the matrix values to zero.\n"
1452 "\n"
1453 "   :return: an instance of itself\n"
1454 "   :rtype: :class:`Matrix`\n"
1455 );
1456 static PyObject *Matrix_zero(MatrixObject *self)
1457 {
1458         fill_vn_fl(self->matrix, self->num_col * self->num_row, 0.0f);
1459
1460         if (BaseMath_WriteCallback(self) == -1)
1461                 return NULL;
1462
1463         Py_RETURN_NONE;
1464 }
1465 /*---------------------------matrix.identity(() ------------------*/
1466 PyDoc_STRVAR(Matrix_identity_doc,
1467 ".. method:: identity()\n"
1468 "\n"
1469 "   Set the matrix to the identity matrix.\n"
1470 "\n"
1471 "   .. note:: An object with zero location and rotation, a scale of one,\n"
1472 "      will have an identity matrix.\n"
1473 "\n"
1474 "   .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n"
1475 );
1476 static PyObject *Matrix_identity(MatrixObject *self)
1477 {
1478         if (BaseMath_ReadCallback(self) == -1)
1479                 return NULL;
1480
1481         if (self->num_col != self->num_row) {
1482                 PyErr_SetString(PyExc_TypeError,
1483                                 "Matrix.identity(): "
1484                                 "only square matrices are supported");
1485                 return NULL;
1486         }
1487
1488         if (self->num_col == 2) {
1489                 MATRIX_ITEM(self, 0, 0) = 1.0f;
1490                 MATRIX_ITEM(self, 0, 1) = 0.0f;
1491                 MATRIX_ITEM(self, 1, 0) = 0.0f;
1492                 MATRIX_ITEM(self, 1, 1) = 1.0f;
1493         }
1494         else if (self->num_col == 3) {
1495                 unit_m3((float (*)[3])self->matrix);
1496         }
1497         else {
1498                 unit_m4((float (*)[4])self->matrix);
1499         }
1500
1501         if (BaseMath_WriteCallback(self) == -1)
1502                 return NULL;
1503
1504         Py_RETURN_NONE;
1505 }
1506
1507 /*---------------------------Matrix.copy() ------------------*/
1508 PyDoc_STRVAR(Matrix_copy_doc,
1509 ".. method:: copy()\n"
1510 "\n"
1511 "   Returns a copy of this matrix.\n"
1512 "\n"
1513 "   :return: an instance of itself\n"
1514 "   :rtype: :class:`Matrix`\n"
1515 );
1516 static PyObject *Matrix_copy(MatrixObject *self)
1517 {
1518         if (BaseMath_ReadCallback(self) == -1)
1519                 return NULL;
1520
1521         return Matrix_CreatePyObject((float (*))self->matrix, self->num_col, self->num_row, Py_NEW, Py_TYPE(self));
1522 }
1523
1524 /*----------------------------print object (internal)-------------*/
1525 /* print the object to screen */
1526 static PyObject *Matrix_repr(MatrixObject *self)
1527 {
1528         int col, row;
1529         PyObject *rows[MATRIX_MAX_DIM] = {NULL};
1530
1531         if (BaseMath_ReadCallback(self) == -1)
1532                 return NULL;
1533
1534         for (row = 0; row < self->num_row; row++) {
1535                 rows[row] = PyTuple_New(self->num_col);
1536                 for (col = 0; col < self->num_col; col++) {
1537                         PyTuple_SET_ITEM(rows[row], col, PyFloat_FromDouble(MATRIX_ITEM(self, row, col)));
1538                 }
1539         }
1540         switch (self->num_row) {
1541         case 2: return PyUnicode_FromFormat("Matrix((%R,\n"
1542                                                                                 "        %R))", rows[0], rows[1]);
1543
1544         case 3: return PyUnicode_FromFormat("Matrix((%R,\n"
1545                                                                                 "        %R,\n"
1546                                                                                 "        %R))", rows[0], rows[1], rows[2]);
1547
1548         case 4: return PyUnicode_FromFormat("Matrix((%R,\n"
1549                                                                                 "        %R,\n"
1550                                                                                 "        %R,\n"
1551                                                                                 "        %R))", rows[0], rows[1], rows[2], rows[3]);
1552         }
1553
1554         Py_FatalError("Matrix(): invalid row size!");
1555         return NULL;
1556 }
1557
1558 static PyObject *Matrix_str(MatrixObject *self)
1559 {
1560         DynStr *ds;
1561
1562         int maxsize[MATRIX_MAX_DIM];
1563         int row, col;
1564
1565         char dummy_buf[64];
1566
1567         if (BaseMath_ReadCallback(self) == -1)
1568                 return NULL;
1569
1570         ds = BLI_dynstr_new();
1571
1572         /* First determine the maximum width for each column */
1573         for (col = 0; col < self->num_col; col++) {
1574                 maxsize[col] = 0;
1575                 for (row = 0; row < self->num_row; row++) {
1576                         int size = BLI_snprintf(dummy_buf, sizeof(dummy_buf), "%.4f", MATRIX_ITEM(self, row, col));
1577                         maxsize[col] = MAX2(maxsize[col], size);
1578                 }
1579         }
1580
1581         /* Now write the unicode string to be printed */
1582         BLI_dynstr_appendf(ds, "<Matrix %dx%d (", self->num_row, self->num_col);
1583         for (row = 0; row < self->num_row; row++) {
1584                 for (col = 0; col < self->num_col; col++) {
1585                         BLI_dynstr_appendf(ds, col ? ", %*.4f" : "%*.4f", maxsize[col], MATRIX_ITEM(self, row, col));
1586                 }
1587                 BLI_dynstr_append(ds, row + 1 != self->num_row ? ")\n            (" : ")");
1588         }
1589         BLI_dynstr_append(ds, ">");
1590
1591         return mathutils_dynstr_to_py(ds); /* frees ds */
1592 }
1593
1594 static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
1595 {
1596         PyObject *res;
1597         int ok = -1; /* zero is true */
1598
1599         if (MatrixObject_Check(a) && MatrixObject_Check(b)) {
1600                 MatrixObject *matA = (MatrixObject *)a;
1601                 MatrixObject *matB = (MatrixObject *)b;
1602
1603                 if (BaseMath_ReadCallback(matA) == -1 || BaseMath_ReadCallback(matB) == -1)
1604                         return NULL;
1605
1606                 ok = (  (matA->num_row == matB->num_row) &&
1607                         (matA->num_col == matB->num_col) &&
1608                          EXPP_VectorsAreEqual(matA->matrix, matB->matrix, (matA->num_col * matA->num_row), 1)
1609                         ) ? 0 : -1;
1610         }
1611
1612         switch (op) {
1613         case Py_NE:
1614                 ok = !ok; /* pass through */
1615         case Py_EQ:
1616                 res = ok ? Py_False : Py_True;
1617                 break;
1618
1619         case Py_LT:
1620         case Py_LE:
1621         case Py_GT:
1622         case Py_GE:
1623                 res = Py_NotImplemented;
1624                 break;
1625         default:
1626                 PyErr_BadArgument();
1627                 return NULL;
1628         }
1629
1630         return Py_INCREF(res), res;
1631 }
1632
1633 /*---------------------SEQUENCE PROTOCOLS------------------------
1634   ----------------------------len(object)------------------------
1635   sequence length */
1636 static int Matrix_len(MatrixObject *self)
1637 {
1638         return (self->num_row);
1639 }
1640 /*----------------------------object[]---------------------------
1641   sequence accessor (get)
1642   the wrapped vector gives direct access to the matrix data */
1643 static PyObject *Matrix_item_row(MatrixObject *self, int row)
1644 {
1645         if (BaseMath_ReadCallback(self) == -1)
1646                 return NULL;
1647
1648         if (row < 0 || row >= self->num_row) {
1649                 PyErr_SetString(PyExc_IndexError,
1650                                 "matrix[attribute]: "
1651                                 "array index out of range");
1652                 return NULL;
1653         }
1654         return Vector_CreatePyObject_cb((PyObject *)self, self->num_col, mathutils_matrix_row_cb_index, row);
1655 }
1656 /* same but column access */
1657 static PyObject *Matrix_item_col(MatrixObject *self, int col)
1658 {
1659         if (BaseMath_ReadCallback(self) == -1)
1660                 return NULL;
1661
1662         if (col < 0 || col >= self->num_col) {
1663                 PyErr_SetString(PyExc_IndexError,
1664                                 "matrix[attribute]: "
1665                                 "array index out of range");
1666                 return NULL;
1667         }
1668         return Vector_CreatePyObject_cb((PyObject *)self, self->num_row, mathutils_matrix_col_cb_index, col);
1669 }
1670
1671 /*----------------------------object[]-------------------------
1672   sequence accessor (set) */
1673
1674 static int Matrix_ass_item_row(MatrixObject *self, int row, PyObject *value)
1675 {
1676         int col;
1677         float vec[4];
1678         if (BaseMath_ReadCallback(self) == -1)
1679                 return -1;
1680
1681         if (row >= self->num_row || row < 0) {
1682                 PyErr_SetString(PyExc_IndexError,
1683                                 "matrix[attribute] = x: bad row");
1684                 return -1;
1685         }
1686
1687         if (mathutils_array_parse(vec, self->num_col, self->num_col, value, "matrix[i] = value assignment") < 0) {
1688                 return -1;
1689         }
1690
1691         /* Since we are assigning a row we cannot memcpy */
1692         for (col = 0; col < self->num_col; col++) {
1693                 MATRIX_ITEM(self, row, col) = vec[col];
1694         }
1695
1696         (void)BaseMath_WriteCallback(self);
1697         return 0;
1698 }
1699 static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value)
1700 {
1701         int row;
1702         float vec[4];
1703         if (BaseMath_ReadCallback(self) == -1)
1704                 return -1;
1705
1706         if (col >= self->num_col || col < 0) {
1707                 PyErr_SetString(PyExc_IndexError,
1708                                 "matrix[attribute] = x: bad col");
1709                 return -1;
1710         }
1711
1712         if (mathutils_array_parse(vec, self->num_row, self->num_row, value, "matrix[i] = value assignment") < 0) {
1713                 return -1;
1714         }
1715
1716         /* Since we are assigning a row we cannot memcpy */
1717         for (row = 0; row < self->num_row; row++) {
1718                 MATRIX_ITEM(self, row, col) = vec[row];
1719         }
1720
1721         (void)BaseMath_WriteCallback(self);
1722         return 0;
1723 }
1724
1725
1726 /*----------------------------object[z:y]------------------------
1727   sequence slice (get)*/
1728 static PyObject *Matrix_slice(MatrixObject *self, int begin, int end)
1729 {
1730
1731         PyObject *tuple;
1732         int count;
1733
1734         if (BaseMath_ReadCallback(self) == -1)
1735                 return NULL;
1736
1737         CLAMP(begin, 0, self->num_row);
1738         CLAMP(end, 0, self->num_row);
1739         begin = MIN2(begin, end);
1740
1741         tuple = PyTuple_New(end - begin);
1742         for (count = begin; count < end; count++) {
1743                 PyTuple_SET_ITEM(tuple, count - begin,
1744                                 Vector_CreatePyObject_cb((PyObject *)self, self->num_col, mathutils_matrix_row_cb_index, count));
1745
1746         }
1747
1748         return tuple;
1749 }
1750 /*----------------------------object[z:y]------------------------
1751   sequence slice (set)*/
1752 static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value)
1753 {
1754         PyObject *value_fast = NULL;
1755
1756         if (BaseMath_ReadCallback(self) == -1)
1757                 return -1;
1758
1759         CLAMP(begin, 0, self->num_row);
1760         CLAMP(end, 0, self->num_row);
1761         begin = MIN2(begin, end);
1762
1763         /* non list/tuple cases */
1764         if (!(value_fast = PySequence_Fast(value, "matrix[begin:end] = value"))) {
1765                 /* PySequence_Fast sets the error */
1766                 return -1;
1767         }
1768         else {
1769                 const int size = end - begin;
1770                 int row, col;
1771                 float mat[16];
1772                 float vec[4];
1773
1774                 if (PySequence_Fast_GET_SIZE(value_fast) != size) {
1775                         Py_DECREF(value_fast);
1776                         PyErr_SetString(PyExc_ValueError,
1777                                         "matrix[begin:end] = []: "
1778                                         "size mismatch in slice assignment");
1779                         return -1;
1780                 }
1781
1782                 memcpy(mat, self->matrix, self->num_col * self->num_row * sizeof(float));
1783
1784                 /* parse sub items */
1785                 for (row = begin; row < end; row++) {
1786                         /* parse each sub sequence */
1787                         PyObject *item = PySequence_Fast_GET_ITEM(value_fast, row - begin);
1788
1789                         if (mathutils_array_parse(vec, self->num_col, self->num_col, item,
1790                                                   "matrix[begin:end] = value assignment") < 0)
1791                         {
1792                                 return -1;
1793                         }
1794
1795                         for (col = 0; col < self->num_col; col++) {
1796                                 mat[col * self->num_row + row] = vec[col];
1797                         }
1798                 }
1799
1800                 Py_DECREF(value_fast);
1801
1802                 /*parsed well - now set in matrix*/
1803                 memcpy(self->matrix, mat, self->num_col * self->num_row * sizeof(float));
1804
1805                 (void)BaseMath_WriteCallback(self);
1806                 return 0;
1807         }
1808 }
1809 /*------------------------NUMERIC PROTOCOLS----------------------
1810   ------------------------obj + obj------------------------------*/
1811 static PyObject *Matrix_add(PyObject *m1, PyObject *m2)
1812 {
1813         float mat[16];
1814         MatrixObject *mat1 = NULL, *mat2 = NULL;
1815
1816         mat1 = (MatrixObject *)m1;
1817         mat2 = (MatrixObject *)m2;
1818
1819         if (!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
1820                 PyErr_Format(PyExc_TypeError,
1821                              "Matrix addition: (%s + %s) "
1822                              "invalid type for this operation",
1823                              Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
1824                 return NULL;
1825         }
1826
1827         if (BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1)
1828                 return NULL;
1829
1830         if (mat1->num_col != mat2->num_col || mat1->num_row != mat2->num_row) {
1831                 PyErr_SetString(PyExc_TypeError,
1832                                 "Matrix addition: "
1833                                 "matrices must have the same dimensions for this operation");
1834                 return NULL;
1835         }
1836
1837         add_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
1838
1839         return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1));
1840 }
1841 /*------------------------obj - obj------------------------------
1842   subtraction*/
1843 static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
1844 {
1845         float mat[16];
1846         MatrixObject *mat1 = NULL, *mat2 = NULL;
1847
1848         mat1 = (MatrixObject *)m1;
1849         mat2 = (MatrixObject *)m2;
1850
1851         if (!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
1852                 PyErr_Format(PyExc_TypeError,
1853                              "Matrix subtraction: (%s - %s) "
1854                              "invalid type for this operation",
1855                              Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name
1856                              );
1857                 return NULL;
1858         }
1859
1860         if (BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1)
1861                 return NULL;
1862
1863         if (mat1->num_col != mat2->num_col || mat1->num_row != mat2->num_row) {
1864                 PyErr_SetString(PyExc_TypeError,
1865                                 "Matrix addition: "
1866                                 "matrices must have the same dimensions for this operation");
1867                 return NULL;
1868         }
1869
1870         sub_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
1871
1872         return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1));
1873 }
1874 /*------------------------obj * obj------------------------------
1875   mulplication*/
1876 static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
1877 {
1878         float tmat[16];
1879         mul_vn_vn_fl(tmat, mat->matrix, mat->num_col * mat->num_row, scalar);
1880         return Matrix_CreatePyObject(tmat, mat->num_col, mat->num_row, Py_NEW, Py_TYPE(mat));
1881 }
1882
1883 static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
1884 {
1885         float scalar;
1886         int vec_size;
1887
1888         MatrixObject *mat1 = NULL, *mat2 = NULL;
1889
1890         if (MatrixObject_Check(m1)) {
1891                 mat1 = (MatrixObject *)m1;
1892                 if (BaseMath_ReadCallback(mat1) == -1)
1893                         return NULL;
1894         }
1895         if (MatrixObject_Check(m2)) {
1896                 mat2 = (MatrixObject *)m2;
1897                 if (BaseMath_ReadCallback(mat2) == -1)
1898                         return NULL;
1899         }
1900
1901         if (mat1 && mat2) {
1902                 /* MATRIX * MATRIX */
1903                 float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f,
1904                                  0.0f, 0.0f, 0.0f, 0.0f,
1905                                  0.0f, 0.0f, 0.0f, 0.0f,
1906                                  0.0f, 0.0f, 0.0f, 1.0f};
1907
1908                 int col, row, item;
1909
1910                 if (mat1->num_col != mat2->num_row) {
1911                         PyErr_SetString(PyExc_ValueError,
1912                                                         "matrix1 * matrix2: matrix1 number of columns "
1913                                                         "and the matrix2 number of rows must be the same");
1914                         return NULL;
1915                 }
1916
1917                 for (col = 0; col < mat2->num_col; col++) {
1918                         for (row = 0; row < mat1->num_row; row++) {
1919                                 double dot = 0.0f;
1920                                 for (item = 0; item < mat1->num_col; item++) {
1921                                         dot += MATRIX_ITEM(mat1, row, item) * MATRIX_ITEM(mat2, item, col);
1922                                 }
1923                                 mat[(col * mat1->num_row) + row] = (float)dot;
1924                         }
1925                 }
1926
1927                 return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1));
1928         }
1929         else if (mat2) {
1930                 /*FLOAT/INT * MATRIX */
1931                 if (((scalar = PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred()) == 0) {
1932                         return matrix_mul_float(mat2, scalar);
1933                 }
1934         }
1935         else if (mat1) {
1936                 /* MATRIX * VECTOR */
1937                 if (VectorObject_Check(m2)) {
1938                         VectorObject *vec2 = (VectorObject *)m2;
1939                         float tvec[4];
1940                         if (BaseMath_ReadCallback(vec2) == -1)
1941                                 return NULL;
1942                         if (column_vector_multiplication(tvec, vec2, mat1) == -1) {
1943                                 return NULL;
1944                         }
1945
1946                         if (mat1->num_col == 4 && vec2->size == 3) {
1947                                 vec_size = 3;
1948                         }
1949                         else {
1950                                 vec_size = mat1->num_row;
1951                         }
1952
1953                         return Vector_CreatePyObject(tvec, vec_size, Py_NEW, Py_TYPE(m2));
1954                 }
1955                 /*FLOAT/INT * MATRIX */
1956                 else if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) {
1957                         return matrix_mul_float(mat1, scalar);
1958                 }
1959         }
1960         else {
1961                 BLI_assert(!"internal error");
1962         }
1963
1964         PyErr_Format(PyExc_TypeError,
1965                      "Matrix multiplication: "
1966                      "not supported between '%.200s' and '%.200s' types",
1967                      Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
1968         return NULL;
1969 }
1970
1971 /*-----------------PROTOCOL DECLARATIONS--------------------------*/
1972 static PySequenceMethods Matrix_SeqMethods = {
1973         (lenfunc) Matrix_len,                                           /* sq_length */
1974         (binaryfunc) NULL,                                                      /* sq_concat */
1975         (ssizeargfunc) NULL,                                            /* sq_repeat */
1976         (ssizeargfunc) Matrix_item_row,                         /* sq_item */
1977         (ssizessizeargfunc) NULL,                                       /* sq_slice, deprecated */
1978         (ssizeobjargproc) Matrix_ass_item_row,          /* sq_ass_item */
1979         (ssizessizeobjargproc) NULL,                            /* sq_ass_slice, deprecated */
1980         (objobjproc) NULL,                                                      /* sq_contains */
1981         (binaryfunc) NULL,                                                      /* sq_inplace_concat */
1982         (ssizeargfunc) NULL,                                            /* sq_inplace_repeat */
1983 };
1984
1985
1986 static PyObject *Matrix_subscript(MatrixObject *self, PyObject *item)
1987 {
1988         if (PyIndex_Check(item)) {
1989                 Py_ssize_t i;
1990                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1991                 if (i == -1 && PyErr_Occurred())
1992                         return NULL;
1993                 if (i < 0)
1994                         i += self->num_row;
1995                 return Matrix_item_row(self, i);
1996         }
1997         else if (PySlice_Check(item)) {
1998                 Py_ssize_t start, stop, step, slicelength;
1999
2000                 if (PySlice_GetIndicesEx((void *)item, self->num_row, &start, &stop, &step, &slicelength) < 0)
2001                         return NULL;
2002
2003                 if (slicelength <= 0) {
2004                         return PyTuple_New(0);
2005                 }
2006                 else if (step == 1) {
2007                         return Matrix_slice(self, start, stop);
2008                 }
2009                 else {
2010                         PyErr_SetString(PyExc_IndexError,
2011                                         "slice steps not supported with matrices");
2012                         return NULL;
2013                 }
2014         }
2015         else {
2016                 PyErr_Format(PyExc_TypeError,
2017                              "matrix indices must be integers, not %.200s",
2018                              Py_TYPE(item)->tp_name);
2019                 return NULL;
2020         }
2021 }
2022
2023 static int Matrix_ass_subscript(MatrixObject *self, PyObject *item, PyObject *value)
2024 {
2025         if (PyIndex_Check(item)) {
2026                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2027                 if (i == -1 && PyErr_Occurred())
2028                         return -1;
2029                 if (i < 0)
2030                         i += self->num_row;
2031                 return Matrix_ass_item_row(self, i, value);
2032         }
2033         else if (PySlice_Check(item)) {
2034                 Py_ssize_t start, stop, step, slicelength;
2035
2036                 if (PySlice_GetIndicesEx((void *)item, self->num_row, &start, &stop, &step, &slicelength) < 0)
2037                         return -1;
2038
2039                 if (step == 1)
2040                         return Matrix_ass_slice(self, start, stop, value);
2041                 else {
2042                         PyErr_SetString(PyExc_IndexError,
2043                                         "slice steps not supported with matrices");
2044                         return -1;
2045                 }
2046         }
2047         else {
2048                 PyErr_Format(PyExc_TypeError,
2049                              "matrix indices must be integers, not %.200s",
2050                              Py_TYPE(item)->tp_name);
2051                 return -1;
2052         }
2053 }
2054
2055 static PyMappingMethods Matrix_AsMapping = {
2056         (lenfunc)Matrix_len,
2057         (binaryfunc)Matrix_subscript,
2058         (objobjargproc)Matrix_ass_subscript
2059 };
2060
2061
2062 static PyNumberMethods Matrix_NumMethods = {
2063                 (binaryfunc)    Matrix_add,     /*nb_add*/
2064                 (binaryfunc)    Matrix_sub,     /*nb_subtract*/
2065                 (binaryfunc)    Matrix_mul,     /*nb_multiply*/
2066                 NULL,                                                   /*nb_remainder*/
2067                 NULL,                                                   /*nb_divmod*/
2068                 NULL,                                                   /*nb_power*/
2069                 (unaryfunc)     0,      /*nb_negative*/
2070                 (unaryfunc)     0,      /*tp_positive*/
2071                 (unaryfunc)     0,      /*tp_absolute*/
2072                 (inquiry)       0,      /*tp_bool*/
2073                 (unaryfunc)     Matrix_inverted,        /*nb_invert*/
2074                 NULL,                           /*nb_lshift*/
2075                 (binaryfunc)0,  /*nb_rshift*/
2076                 NULL,                           /*nb_and*/
2077                 NULL,                           /*nb_xor*/
2078                 NULL,                           /*nb_or*/
2079                 NULL,                           /*nb_int*/
2080                 NULL,                           /*nb_reserved*/
2081                 NULL,                           /*nb_float*/
2082                 NULL,                           /* nb_inplace_add */
2083                 NULL,                           /* nb_inplace_subtract */
2084                 NULL,                           /* nb_inplace_multiply */
2085                 NULL,                           /* nb_inplace_remainder */
2086                 NULL,                           /* nb_inplace_power */
2087                 NULL,                           /* nb_inplace_lshift */
2088                 NULL,                           /* nb_inplace_rshift */
2089                 NULL,                           /* nb_inplace_and */
2090                 NULL,                           /* nb_inplace_xor */
2091                 NULL,                           /* nb_inplace_or */
2092                 NULL,                           /* nb_floor_divide */
2093                 NULL,                           /* nb_true_divide */
2094                 NULL,                           /* nb_inplace_floor_divide */
2095                 NULL,                           /* nb_inplace_true_divide */
2096                 NULL,                           /* nb_index */
2097 };
2098
2099 PyDoc_STRVAR(Matrix_translation_doc,
2100 "The translation component of the matrix.\n\n:type: Vector"
2101 );
2102 static PyObject *Matrix_translation_get(MatrixObject *self, void *UNUSED(closure))
2103 {
2104         PyObject *ret;
2105
2106         if (BaseMath_ReadCallback(self) == -1)
2107                 return NULL;
2108
2109         /*must be 4x4 square matrix*/
2110         if (self->num_row != 4 || self->num_col != 4) {
2111                 PyErr_SetString(PyExc_AttributeError,
2112                                 "Matrix.translation: "
2113                                 "inappropriate matrix size, must be 4x4");
2114                 return NULL;
2115         }
2116
2117         ret = (PyObject *)Vector_CreatePyObject_cb((PyObject *)self, 3, mathutils_matrix_translation_cb_index, 3);
2118
2119         return ret;
2120 }
2121
2122 static int Matrix_translation_set(MatrixObject *self, PyObject *value, void *UNUSED(closure))
2123 {
2124         float tvec[3];
2125
2126         if (BaseMath_ReadCallback(self) == -1)
2127                 return -1;
2128
2129         /*must be 4x4 square matrix*/
2130         if (self->num_row != 4 || self->num_col != 4) {
2131                 PyErr_SetString(PyExc_AttributeError,
2132                                 "Matrix.translation: "
2133                                 "inappropriate matrix size, must be 4x4");
2134                 return -1;
2135         }
2136
2137         if ((mathutils_array_parse(tvec, 3, 3, value, "Matrix.translation")) == -1) {
2138                 return -1;
2139         }
2140
2141         copy_v3_v3(((float (*)[4])self->matrix)[3], tvec);
2142
2143         (void)BaseMath_WriteCallback(self);
2144
2145         return 0;
2146 }
2147
2148 PyDoc_STRVAR(Matrix_row_doc,
2149 "Access the matix by rows (default), (read-only).\n\n:type: Matrix Access"
2150 );
2151 static PyObject *Matrix_row_get(MatrixObject *self, void *UNUSED(closure))
2152 {
2153         return MatrixAccess_CreatePyObject(self, MAT_ACCESS_ROW);
2154 }
2155
2156 PyDoc_STRVAR(Matrix_col_doc,
2157 "Access the matix by colums, 3x3 and 4x4 only, (read-only).\n\n:type: Matrix Access"
2158 );
2159 static PyObject *Matrix_col_get(MatrixObject *self, void *UNUSED(closure))
2160 {
2161         return MatrixAccess_CreatePyObject(self, MAT_ACCESS_COL);
2162 }
2163
2164 PyDoc_STRVAR(Matrix_median_scale_doc,
2165 "The average scale applied to each axis (read-only).\n\n:type: float"
2166 );
2167 static PyObject *Matrix_median_scale_get(MatrixObject *self, void *UNUSED(closure))
2168 {
2169         float mat[3][3];
2170
2171         if (BaseMath_ReadCallback(self) == -1)
2172                 return NULL;
2173
2174         /*must be 3-4 cols, 3-4 rows, square matrix*/
2175         if ((self->num_row < 3) || (self->num_col < 3)) {
2176                 PyErr_SetString(PyExc_AttributeError,
2177                                 "Matrix.median_scale: "
2178                                 "inappropriate matrix size, 3x3 minimum");
2179                 return NULL;
2180         }
2181
2182         matrix_as_3x3(mat, self);
2183
2184         return PyFloat_FromDouble(mat3_to_scale(mat));
2185 }
2186
2187 PyDoc_STRVAR(Matrix_is_negative_doc,
2188 "True if this matrix results in a negative scale, 3x3 and 4x4 only, (read-only).\n\n:type: bool"
2189 );
2190 static PyObject *Matrix_is_negative_get(MatrixObject *self, void *UNUSED(closure))
2191 {
2192         if (BaseMath_ReadCallback(self) == -1)
2193                 return NULL;
2194
2195         /*must be 3-4 cols, 3-4 rows, square matrix*/
2196         if (self->num_row == 4 && self->num_col == 4)
2197                 return PyBool_FromLong(is_negative_m4((float (*)[4])self->matrix));
2198         else if (self->num_row == 3 && self->num_col == 3)
2199                 return PyBool_FromLong(is_negative_m3((float (*)[3])self->matrix));
2200         else {
2201                 PyErr_SetString(PyExc_AttributeError,
2202                                 "Matrix.is_negative: "
2203                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
2204                 return NULL;
2205         }
2206 }
2207
2208 PyDoc_STRVAR(Matrix_is_orthogonal_doc,
2209 "True if this matrix is orthogonal, 3x3 and 4x4 only, (read-only).\n\n:type: bool"
2210 );
2211 static PyObject *Matrix_is_orthogonal_get(MatrixObject *self, void *UNUSED(closure))
2212 {
2213         if (BaseMath_ReadCallback(self) == -1)
2214                 return NULL;
2215
2216         /*must be 3-4 cols, 3-4 rows, square matrix*/
2217         if (self->num_row == 4 && self->num_col == 4)
2218                 return PyBool_FromLong(is_orthogonal_m4((float (*)[4])self->matrix));
2219         else if (self->num_row == 3 && self->num_col == 3)
2220                 return PyBool_FromLong(is_orthogonal_m3((float (*)[3])self->matrix));
2221         else {
2222                 PyErr_SetString(PyExc_AttributeError,
2223                                 "Matrix.is_orthogonal: "
2224                                 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
2225                 return NULL;
2226         }
2227 }
2228
2229 /*****************************************************************************/
2230 /* Python attributes get/set structure:                                      */
2231 /*****************************************************************************/
2232 static PyGetSetDef Matrix_getseters[] = {
2233         {(char *)"median_scale", (getter)Matrix_median_scale_get, (setter)NULL, Matrix_median_scale_doc, NULL},
2234         {(char *)"translation", (getter)Matrix_translation_get, (setter)Matrix_translation_set, Matrix_translation_doc, NULL},
2235         {(char *)"row", (getter)Matrix_row_get, (setter)NULL, Matrix_row_doc, NULL},
2236         {(char *)"col", (getter)Matrix_col_get, (setter)NULL, Matrix_col_doc, NULL},
2237         {(char *)"is_negative", (getter)Matrix_is_negative_get, (setter)NULL, Matrix_is_negative_doc, NULL},
2238         {(char *)"is_orthogonal", (getter)Matrix_is_orthogonal_get, (setter)NULL, Matrix_is_orthogonal_doc, NULL},
2239         {(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL},
2240         {(char *)"owner",(getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
2241         {NULL, NULL, NULL, NULL, NULL}  /* Sentinel */
2242 };
2243
2244 /*-----------------------METHOD DEFINITIONS ----------------------*/
2245 static struct PyMethodDef Matrix_methods[] = {
2246         /* derived values */
2247         {"determinant", (PyCFunction) Matrix_determinant, METH_NOARGS, Matrix_determinant_doc},
2248         {"decompose", (PyCFunction) Matrix_decompose, METH_NOARGS, Matrix_decompose_doc},
2249
2250         /* in place only */
2251         {"zero", (PyCFunction) Matrix_zero, METH_NOARGS, Matrix_zero_doc},
2252         {"identity", (PyCFunction) Matrix_identity, METH_NOARGS, Matrix_identity_doc},
2253
2254         /* operate on original or copy */
2255         {"transpose", (PyCFunction) Matrix_transpose, METH_NOARGS, Matrix_transpose_doc},
2256         {"transposed", (PyCFunction) Matrix_transposed, METH_NOARGS, Matrix_transposed_doc},
2257         {"invert", (PyCFunction) Matrix_invert, METH_NOARGS, Matrix_invert_doc},
2258         {"inverted", (PyCFunction) Matrix_inverted, METH_NOARGS, Matrix_inverted_doc},
2259         {"to_3x3", (PyCFunction) Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc},
2260         // TODO. {"resize_3x3", (PyCFunction) Matrix_resize3x3, METH_NOARGS, Matrix_resize3x3_doc},
2261         {"to_4x4", (PyCFunction) Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc},
2262         {"resize_4x4", (PyCFunction) Matrix_resize_4x4, METH_NOARGS, Matrix_resize_4x4_doc},
2263         {"rotate", (PyCFunction) Matrix_rotate, METH_O, Matrix_rotate_doc},
2264
2265         /* return converted representation */
2266         {"to_euler", (PyCFunction) Matrix_to_euler, METH_VARARGS, Matrix_to_euler_doc},
2267         {"to_quaternion", (PyCFunction) Matrix_to_quaternion, METH_NOARGS, Matrix_to_quaternion_doc},
2268         {"to_scale", (PyCFunction) Matrix_to_scale, METH_NOARGS, Matrix_to_scale_doc},
2269         {"to_translation", (PyCFunction) Matrix_to_translation, METH_NOARGS, Matrix_to_translation_doc},
2270
2271         /* operation between 2 or more types  */
2272         {"lerp", (PyCFunction) Matrix_lerp, METH_VARARGS, Matrix_lerp_doc},
2273         {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
2274         {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
2275
2276         /* class methods */
2277         {"Identity", (PyCFunction) C_Matrix_Identity, METH_VARARGS | METH_CLASS, C_Matrix_Identity_doc},
2278         {"Rotation", (PyCFunction) C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc},
2279         {"Scale", (PyCFunction) C_Matrix_Scale, METH_VARARGS | METH_CLASS, C_Matrix_Scale_doc},
2280         {"Shear", (PyCFunction) C_Matrix_Shear, METH_VARARGS | METH_CLASS, C_Matrix_Shear_doc},
2281         {"Translation", (PyCFunction) C_Matrix_Translation, METH_O | METH_CLASS, C_Matrix_Translation_doc},
2282         {"OrthoProjection", (PyCFunction) C_Matrix_OrthoProjection,  METH_VARARGS | METH_CLASS, C_Matrix_OrthoProjection_doc},
2283         {NULL, NULL, 0, NULL}
2284 };
2285
2286 /*------------------PY_OBECT DEFINITION--------------------------*/
2287 PyDoc_STRVAR(matrix_doc,
2288 "This object gives access to Matrices in Blender."
2289 );
2290 PyTypeObject matrix_Type = {
2291         PyVarObject_HEAD_INIT(NULL, 0)
2292         "mathutils.Matrix",                                     /*tp_name*/
2293         sizeof(MatrixObject),                           /*tp_basicsize*/
2294         0,                                                                      /*tp_itemsize*/
2295         (destructor)BaseMathObject_dealloc,     /*tp_dealloc*/
2296         NULL,                                                           /*tp_print*/
2297         NULL,                                                           /*tp_getattr*/
2298         NULL,                                                           /*tp_setattr*/
2299         NULL,                                                           /*tp_compare*/
2300         (reprfunc) Matrix_repr,                         /*tp_repr*/
2301         &Matrix_NumMethods,                                     /*tp_as_number*/
2302         &Matrix_SeqMethods,                                     /*tp_as_sequence*/
2303         &Matrix_AsMapping,                                      /*tp_as_mapping*/
2304         NULL,                                                           /*tp_hash*/
2305         NULL,                                                           /*tp_call*/
2306         (reprfunc) Matrix_str,                          /*tp_str*/
2307         NULL,                                                           /*tp_getattro*/
2308         NULL,                                                           /*tp_setattro*/
2309         NULL,                                                           /*tp_as_buffer*/
2310         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
2311         matrix_doc,                                                     /*tp_doc*/
2312         (traverseproc)BaseMathObject_traverse,  //tp_traverse
2313         (inquiry)BaseMathObject_clear,  //tp_clear
2314         (richcmpfunc)Matrix_richcmpr,           /*tp_richcompare*/
2315         0,                                                                      /*tp_weaklistoffset*/
2316         NULL,                                                           /*tp_iter*/
2317         NULL,                                                           /*tp_iternext*/
2318         Matrix_methods,                                         /*tp_methods*/
2319         NULL,                                                           /*tp_members*/
2320         Matrix_getseters,                                       /*tp_getset*/
2321         NULL,                                                           /*tp_base*/
2322         NULL,                                                           /*tp_dict*/
2323         NULL,                                                           /*tp_descr_get*/
2324         NULL,                                                           /*tp_descr_set*/
2325         0,                                                                      /*tp_dictoffset*/
2326         NULL,                                                           /*tp_init*/
2327         NULL,                                                           /*tp_alloc*/
2328         Matrix_new,                                                     /*tp_new*/
2329         NULL,                                                           /*tp_free*/
2330         NULL,                                                           /*tp_is_gc*/
2331         NULL,                                                           /*tp_bases*/
2332         NULL,                                                           /*tp_mro*/
2333         NULL,                                                           /*tp_cache*/
2334         NULL,                                                           /*tp_subclasses*/
2335         NULL,                                                           /*tp_weaklist*/
2336         NULL                                                            /*tp_del*/
2337 };
2338
2339 /* pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
2340  * (i.e. it was allocated elsewhere by MEM_mallocN())
2341  * pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
2342  * (i.e. it must be created here with PyMEM_malloc()) */
2343 PyObject *Matrix_CreatePyObject(float *mat,
2344                                 const unsigned short num_col, const unsigned short num_row,
2345                                 int type, PyTypeObject *base_type)
2346 {
2347         MatrixObject *self;
2348
2349         /* matrix objects can be any 2-4row x 2-4col matrix */
2350         if (num_col < 2 || num_col > 4 || num_row < 2 || num_row > 4) {
2351                 PyErr_SetString(PyExc_RuntimeError,
2352                                 "Matrix(): "
2353                                 "row and column sizes must be between 2 and 4");
2354                 return NULL;
2355         }
2356
2357         self = base_type ? (MatrixObject *)base_type->tp_alloc(base_type, 0) :
2358                            (MatrixObject *)PyObject_GC_New(MatrixObject, &matrix_Type);
2359
2360         if (self) {
2361                 self->num_col = num_col;
2362                 self->num_row = num_row;
2363
2364                 /* init callbacks as NULL */
2365                 self->cb_user = NULL;
2366                 self->cb_type = self->cb_subtype = 0;
2367
2368                 if (type == Py_WRAP) {
2369                         self->matrix = mat;
2370                         self->wrapped = Py_WRAP;
2371                 }
2372                 else if (type == Py_NEW) {
2373                         self->matrix = PyMem_Malloc(num_col * num_row * sizeof(float));
2374                         if (self->matrix == NULL) { /*allocation failure*/
2375                                 PyErr_SetString(PyExc_MemoryError,
2376                                                 "Matrix(): "
2377                                                 "problem allocating pointer space");
2378                                 return NULL;
2379                         }
2380
2381                         if (mat) {      /*if a float array passed*/
2382                                 memcpy(self->matrix, mat, num_col * num_row * sizeof(float));
2383                         }
2384                         else if (num_col == num_row) {
2385                                 /* or if no arguments are passed return identity matrix for square matrices */
2386                                 PyObject *ret_dummy = Matrix_identity(self);
2387                                 Py_DECREF(ret_dummy);
2388                         }
2389                         else {
2390                                 /* otherwise zero everything */
2391                                 memset(self->matrix, 0, num_col * num_row * sizeof(float));
2392                         }
2393                         self->wrapped = Py_NEW;
2394                 }
2395                 else {
2396                         Py_FatalError("Matrix(): invalid type!");
2397                         return NULL;
2398                 }
2399         }
2400         return (PyObject *) self;
2401 }
2402
2403 PyObject *Matrix_CreatePyObject_cb(PyObject *cb_user,
2404                                    const unsigned short num_col, const unsigned short num_row,
2405                                    int cb_type, int cb_subtype)
2406 {
2407         MatrixObject *self = (MatrixObject *)Matrix_CreatePyObject(NULL, num_col, num_row, Py_NEW, NULL);
2408         if (self) {
2409                 Py_INCREF(cb_user);
2410                 self->cb_user =                 cb_user;
2411                 self->cb_type =                 (unsigned char)cb_type;
2412                 self->cb_subtype =              (unsigned char)cb_subtype;
2413                 PyObject_GC_Track(self);
2414         }
2415         return (PyObject *) self;
2416 }
2417
2418
2419 /* ----------------------------------------------------------------------------
2420  * special type for alaternate access */
2421
2422 typedef struct {
2423         PyObject_HEAD /* required python macro   */
2424         MatrixObject *matrix_user;
2425         eMatrixAccess_t type;
2426 } MatrixAccessObject;
2427
2428 static int MatrixAccess_traverse(MatrixAccessObject *self, visitproc visit, void *arg)
2429 {
2430         Py_VISIT(self->matrix_user);
2431         return 0;
2432 }
2433
2434 static int MatrixAccess_clear(MatrixAccessObject *self)
2435 {
2436         Py_CLEAR(self->matrix_user);
2437         return 0;
2438 }
2439
2440 static void MatrixAccess_dealloc(MatrixAccessObject *self)
2441 {
2442         if (self->matrix_user) {
2443                 PyObject_GC_UnTrack(self);
2444                 MatrixAccess_clear(self);
2445         }
2446
2447         Py_TYPE(self)->tp_free(self);
2448 }
2449
2450 /* sequence access */
2451
2452 static int MatrixAccess_len(MatrixAccessObject *self)
2453 {
2454         return (self->type == MAT_ACCESS_ROW) ?
2455                     self->matrix_user->num_row :
2456                     self->matrix_user->num_col;
2457 }
2458
2459 static PyObject *MatrixAccess_slice(MatrixAccessObject *self, int begin, int end)
2460 {
2461         PyObject *tuple;
2462         int count;
2463
2464         /* row/col access */
2465         MatrixObject *matrix_user = self->matrix_user;
2466         int matrix_access_len;
2467         PyObject *(*Matrix_item_new)(MatrixObject *, int);
2468
2469         if (self->type == MAT_ACCESS_ROW) {
2470                 matrix_access_len = matrix_user->num_row;
2471                 Matrix_item_new = Matrix_item_row;
2472         }
2473         else { /* MAT_ACCESS_ROW */
2474                 matrix_access_len = matrix_user->num_col;
2475                 Matrix_item_new = Matrix_item_col;
2476         }
2477
2478         CLAMP(begin, 0, matrix_access_len);
2479         if (end < 0) end = (matrix_access_len + 1) + end;
2480         CLAMP(end, 0, matrix_access_len);
2481         begin = MIN2(begin, end);
2482
2483         tuple = PyTuple_New(end - begin);
2484         for (count = begin; count < end; count++) {
2485                 PyTuple_SET_ITEM(tuple, count - begin, Matrix_item_new(matrix_user, count));
2486         }
2487
2488         return tuple;
2489 }
2490
2491 static PyObject *MatrixAccess_subscript(MatrixAccessObject *self, PyObject *item)
2492 {
2493         MatrixObject *matrix_user = self->matrix_user;
2494
2495         if (PyIndex_Check(item)) {
2496                 Py_ssize_t i;
2497                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2498                 if (i == -1 && PyErr_Occurred())
2499                         return NULL;
2500                 if (self->type == MAT_ACCESS_ROW) {
2501                         if (i < 0)
2502                                 i += matrix_user->num_row;
2503                         return Matrix_item_row(matrix_user, i);
2504                 }
2505                 else { /* MAT_ACCESS_ROW */
2506                         if (i < 0)
2507                                 i += matrix_user->num_col;
2508                         return Matrix_item_col(matrix_user, i);
2509                 }
2510         }
2511         else if (PySlice_Check(item)) {
2512                 Py_ssize_t start, stop, step, slicelength;
2513
2514                 if (PySlice_GetIndicesEx((void *)item, MatrixAccess_len(self), &start, &stop, &step, &slicelength) < 0)
2515                         return NULL;
2516
2517                 if (slicelength <= 0) {
2518                         return PyTuple_New(0);
2519                 }
2520                 else if (step == 1) {
2521                         return MatrixAccess_slice(self, start, stop);
2522                 }
2523                 else {
2524                         PyErr_SetString(PyExc_IndexError,
2525                                         "slice steps not supported with matrix accessors");
2526                         return NULL;
2527                 }
2528         }
2529         else {
2530                 PyErr_Format(PyExc_TypeError,
2531                              "matrix indices must be integers, not %.200s",
2532                              Py_TYPE(item)->tp_name);
2533                 return NULL;
2534         }
2535 }
2536
2537 static int MatrixAccess_ass_subscript(MatrixAccessObject *self, PyObject *item, PyObject *value)
2538 {
2539         MatrixObject *matrix_user = self->matrix_user;
2540
2541         if (PyIndex_Check(item)) {
2542                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2543                 if (i == -1 && PyErr_Occurred())
2544                         return -1;
2545
2546                 if (self->type == MAT_ACCESS_ROW) {
2547                         if (i < 0)
2548                                 i += matrix_user->num_row;
2549                         return Matrix_ass_item_row(matrix_user, i, value);
2550                 }
2551                 else { /* MAT_ACCESS_ROW */
2552                         if (i < 0)
2553                                 i += matrix_user->num_col;
2554                         return Matrix_ass_item_col(matrix_user, i, value);
2555                 }
2556
2557         }
2558         /* TODO, slice */
2559         else {
2560                 PyErr_Format(PyExc_TypeError,
2561                              "matrix indices must be integers, not %.200s",
2562                              Py_TYPE(item)->tp_name);
2563                 return -1;
2564         }
2565 }
2566
2567 static PyObject *MatrixAccess_iter(MatrixAccessObject *self)
2568 {
2569         /* Try get values from a collection */
2570         PyObject *ret;
2571         PyObject *iter = NULL;
2572         ret = MatrixAccess_slice(self, 0, MATRIX_MAX_DIM);
2573
2574         /* we know this is a tuple so no need to PyIter_Check
2575          * otherwise it could be NULL (unlikely) if conversion failed */
2576         if (ret) {
2577                 iter = PyObject_GetIter(ret);
2578                 Py_DECREF(ret);
2579         }
2580
2581         return iter;
2582 }
2583
2584 static PyMappingMethods MatrixAccess_AsMapping = {
2585         (lenfunc)MatrixAccess_len,
2586         (binaryfunc)MatrixAccess_subscript,
2587         (objobjargproc) MatrixAccess_ass_subscript
2588 };
2589
2590 PyTypeObject matrix_access_Type = {
2591         PyVarObject_HEAD_INIT(NULL, 0)
2592         "MatrixAccess",                                         /*tp_name*/
2593         sizeof(MatrixAccessObject),                     /*tp_basicsize*/
2594         0,                                                                      /*tp_itemsize*/
2595         (destructor)MatrixAccess_dealloc,       /*tp_dealloc*/
2596         NULL,                                                           /*tp_print*/
2597         NULL,                                                           /*tp_getattr*/
2598         NULL,                                                           /*tp_setattr*/
2599         NULL,                                                           /*tp_compare*/
2600         NULL,                                                           /*tp_repr*/
2601         NULL,                                                           /*tp_as_number*/
2602         NULL /*&MatrixAccess_SeqMethods*/ /* TODO */,                   /*tp_as_sequence*/
2603         &MatrixAccess_AsMapping,                        /*tp_as_mapping*/
2604         NULL,                                                           /*tp_hash*/
2605         NULL,                                                           /*tp_call*/
2606         NULL,                                                           /*tp_str*/
2607         NULL,                                                           /*tp_getattro*/
2608         NULL,                                                           /*tp_setattro*/
2609         NULL,                                                           /*tp_as_buffer*/
2610         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
2611         NULL,                                                           /*tp_doc*/
2612         (traverseproc)MatrixAccess_traverse,    //tp_traverse
2613         (inquiry)MatrixAccess_clear,    //tp_clear
2614         NULL /* (richcmpfunc)MatrixAccess_richcmpr */ /* TODO*/, /*tp_richcompare*/
2615         0,                                                                      /*tp_weaklistoffset*/
2616         (getiterfunc)MatrixAccess_iter, /* getiterfunc tp_iter; */
2617 };
2618
2619 static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type)
2620 {
2621         MatrixAccessObject *matrix_access = (MatrixAccessObject *)PyObject_GC_New(MatrixObject, &matrix_access_Type);
2622
2623         matrix_access->matrix_user = matrix;
2624         Py_INCREF(matrix);
2625
2626         matrix_access->type = type;
2627
2628         return (PyObject *)matrix_access;
2629 }
2630
2631 /* end special access
2632  * -------------------------------------------------------------------------- */