3 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
19 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20 * All rights reserved.
22 * Contributor(s): Michel Selten & Joseph Gilbert
24 * ***** END GPL LICENSE BLOCK *****
27 /** \file blender/python/mathutils/mathutils_Matrix.c
28 * \ingroup pymathutils
34 #include "mathutils.h"
37 #include "BLI_utildefines.h"
38 #include "BLI_string.h"
39 #include "BLI_dynstr.h"
41 typedef enum eMatrixAccess_t {
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);
51 static int matrix_row_vector_check(MatrixObject *mat, VectorObject *vec, int row)
53 if ((vec->size != mat->num_col) || (row >= mat->num_row)) {
54 PyErr_SetString(PyExc_AttributeError,
56 "owner matrix has been resized since this row vector was created");
64 static int matrix_col_vector_check(MatrixObject *mat, VectorObject *vec, int col)
66 if ((vec->size != mat->num_row) || (col >= mat->num_col)) {
67 PyErr_SetString(PyExc_AttributeError,
69 "owner matrix has been resized since this column vector was created");
77 /* ----------------------------------------------------------------------------
78 * matrix row callbacks
79 * this is so you can do matrix[i][j] = val OR matrix.row[i][j] = val */
81 int mathutils_matrix_row_cb_index = -1;
83 static int mathutils_matrix_row_check(BaseMathObject *bmo)
85 MatrixObject *self = (MatrixObject *)bmo->cb_user;
86 return BaseMath_ReadCallback(self);
89 static int mathutils_matrix_row_get(BaseMathObject *bmo, int row)
91 MatrixObject *self = (MatrixObject *)bmo->cb_user;
94 if (BaseMath_ReadCallback(self) == -1)
96 if (!matrix_row_vector_check(self, (VectorObject *)bmo, row))
99 for (col = 0; col < self->num_col; col++) {
100 bmo->data[col] = MATRIX_ITEM(self, row, col);
106 static int mathutils_matrix_row_set(BaseMathObject *bmo, int row)
108 MatrixObject *self = (MatrixObject *)bmo->cb_user;
111 if (BaseMath_ReadCallback(self) == -1)
113 if (!matrix_row_vector_check(self, (VectorObject *)bmo, row))
116 for (col = 0; col < self->num_col; col++) {
117 MATRIX_ITEM(self, row, col) = bmo->data[col];
120 (void)BaseMath_WriteCallback(self);
124 static int mathutils_matrix_row_get_index(BaseMathObject *bmo, int row, int col)
126 MatrixObject *self = (MatrixObject *)bmo->cb_user;
128 if (BaseMath_ReadCallback(self) == -1)
130 if (!matrix_row_vector_check(self, (VectorObject *)bmo, row))
133 bmo->data[col] = MATRIX_ITEM(self, row, col);
137 static int mathutils_matrix_row_set_index(BaseMathObject *bmo, int row, int col)
139 MatrixObject *self = (MatrixObject *)bmo->cb_user;
141 if (BaseMath_ReadCallback(self) == -1)
143 if (!matrix_row_vector_check(self, (VectorObject *)bmo, row))
146 MATRIX_ITEM(self, row, col) = bmo->data[col];
148 (void)BaseMath_WriteCallback(self);
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
161 /* ----------------------------------------------------------------------------
162 * matrix row callbacks
163 * this is so you can do matrix.col[i][j] = val */
165 int mathutils_matrix_col_cb_index = -1;
167 static int mathutils_matrix_col_check(BaseMathObject *bmo)
169 MatrixObject *self = (MatrixObject *)bmo->cb_user;
170 return BaseMath_ReadCallback(self);
173 static int mathutils_matrix_col_get(BaseMathObject *bmo, int col)
175 MatrixObject *self = (MatrixObject *)bmo->cb_user;
179 if (BaseMath_ReadCallback(self) == -1)
181 if (!matrix_col_vector_check(self, (VectorObject *)bmo, col))
184 /* for 'translation' size will always be '3' even on 4x4 vec */
185 num_row = MIN2(self->num_row, ((VectorObject *)bmo)->size);
187 for (row = 0; row < num_row; row++) {
188 bmo->data[row] = MATRIX_ITEM(self, row, col);
194 static int mathutils_matrix_col_set(BaseMathObject *bmo, int col)
196 MatrixObject *self = (MatrixObject *)bmo->cb_user;
200 if (BaseMath_ReadCallback(self) == -1)
202 if (!matrix_col_vector_check(self, (VectorObject *)bmo, col))
205 /* for 'translation' size will always be '3' even on 4x4 vec */
206 num_row = MIN2(self->num_row, ((VectorObject *)bmo)->size);
208 for (row = 0; row < num_row; row++) {
209 MATRIX_ITEM(self, row, col) = bmo->data[row];
212 (void)BaseMath_WriteCallback(self);
216 static int mathutils_matrix_col_get_index(BaseMathObject *bmo, int col, int row)
218 MatrixObject *self = (MatrixObject *)bmo->cb_user;
220 if (BaseMath_ReadCallback(self) == -1)
222 if (!matrix_col_vector_check(self, (VectorObject *)bmo, col))
225 bmo->data[row] = MATRIX_ITEM(self, row, col);
229 static int mathutils_matrix_col_set_index(BaseMathObject *bmo, int col, int row)
231 MatrixObject *self = (MatrixObject *)bmo->cb_user;
233 if (BaseMath_ReadCallback(self) == -1)
235 if (!matrix_col_vector_check(self, (VectorObject *)bmo, col))
238 MATRIX_ITEM(self, row, col) = bmo->data[row];
240 (void)BaseMath_WriteCallback(self);
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
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 */
258 int mathutils_matrix_translation_cb_index = -1;
260 static int mathutils_matrix_translation_check(BaseMathObject *bmo)
262 MatrixObject *self = (MatrixObject *)bmo->cb_user;
263 return BaseMath_ReadCallback(self);
266 static int mathutils_matrix_translation_get(BaseMathObject *bmo, int col)
268 MatrixObject *self = (MatrixObject *)bmo->cb_user;
271 if (BaseMath_ReadCallback(self) == -1)
274 for (row = 0; row < 3; row++) {
275 bmo->data[row] = MATRIX_ITEM(self, row, col);
281 static int mathutils_matrix_translation_set(BaseMathObject *bmo, int col)
283 MatrixObject *self = (MatrixObject *)bmo->cb_user;
286 if (BaseMath_ReadCallback(self) == -1)
289 for (row = 0; row < 3; row++) {
290 MATRIX_ITEM(self, row, col) = bmo->data[row];
293 (void)BaseMath_WriteCallback(self);
297 static int mathutils_matrix_translation_get_index(BaseMathObject *bmo, int col, int row)
299 MatrixObject *self = (MatrixObject *)bmo->cb_user;
301 if (BaseMath_ReadCallback(self) == -1)
304 bmo->data[row] = MATRIX_ITEM(self, row, col);
308 static int mathutils_matrix_translation_set_index(BaseMathObject *bmo, int col, int row)
310 MatrixObject *self = (MatrixObject *)bmo->cb_user;
312 if (BaseMath_ReadCallback(self) == -1)
315 MATRIX_ITEM(self, row, col) = bmo->data[row];
317 (void)BaseMath_WriteCallback(self);
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
330 /* matrix column callbacks, this is so you can do matrix.translation = Vector() */
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)
337 if (kwds && PyDict_Size(kwds)) {
338 PyErr_SetString(PyExc_TypeError,
340 "takes no keyword args");
344 switch (PyTuple_GET_SIZE(args)) {
346 return Matrix_CreatePyObject(NULL, 4, 4, Py_NEW, type);
349 PyObject *arg = PyTuple_GET_ITEM(args, 0);
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);
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);
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) {
369 else { /* matrix ok, slice assignment not */
377 /* will overwrite error */
378 PyErr_SetString(PyExc_TypeError,
380 "expects no args or 2-4 numeric sequences");
384 static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self)
386 PyObject *ret = Matrix_copy(self);
387 PyObject *ret_dummy = matrix_func(ret);
389 Py_DECREF(ret_dummy);
390 return (PyObject *)ret;
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])
411 /*-----------------------CLASS-METHODS----------------------------*/
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"
417 " Create an identity matrix.\n"
419 " :arg size: The size of the identity matrix to construct [2, 4].\n"
421 " :return: A new identity matrix.\n"
422 " :rtype: :class:`Matrix`\n"
424 static PyObject *C_Matrix_Identity(PyObject *cls, PyObject *args)
428 if (!PyArg_ParseTuple(args, "i:Matrix.Identity", &matSize)) {
432 if (matSize < 2 || matSize > 4) {
433 PyErr_SetString(PyExc_RuntimeError,
434 "Matrix.Identity(): "
435 "size must be between 2 and 4");
439 return Matrix_CreatePyObject(NULL, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
442 PyDoc_STRVAR(C_Matrix_Rotation_doc,
443 ".. classmethod:: Rotation(angle, size, axis)\n"
445 " Create a matrix representing a rotation.\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"
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"
457 static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
459 PyObject *vec = NULL;
460 const char *axis = NULL;
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};
468 if (!PyArg_ParseTuple(args, "di|O:Matrix.Rotation", &angle, &matSize, &vec)) {
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'");
487 angle = angle_wrap_rad(angle);
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");
495 if (matSize == 2 && (vec != NULL)) {
496 PyErr_SetString(PyExc_ValueError,
497 "Matrix.Rotation(): "
498 "cannot create a 2x2 rotation matrix around arbitrary axis");
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");
508 /* check for valid vector/axis above */
512 if (mathutils_array_parse(tvec, 3, 3, vec, "Matrix.Rotation(angle, size, axis), invalid 'axis' arg") == -1)
515 axis_angle_to_mat3((float (*)[3])mat, tvec, angle);
517 else if (matSize == 2) {
518 const float angle_cos = cosf(angle);
519 const float angle_sin = sinf(angle);
528 /* valid axis checked above */
529 single_axis_angle_to_mat3((float (*)[3])mat, axis[0], angle);
533 matrix_3x3_as_4x4(mat);
535 //pass to matrix creation
536 return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
540 PyDoc_STRVAR(C_Matrix_Translation_doc,
541 ".. classmethod:: Translation(vector)\n"
543 " Create a matrix representing a translation.\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"
550 static PyObject *C_Matrix_Translation(PyObject *cls, PyObject *value)
552 float mat[4][4]= MAT4_UNITY;
554 if (mathutils_array_parse(mat[3], 3, 4, value, "mathutils.Matrix.Translation(vector), invalid vector arg") == -1)
557 return Matrix_CreatePyObject(&mat[0][0], 4, 4, Py_NEW, (PyTypeObject *)cls);
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"
564 " Create a matrix representing a scaling.\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"
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"
575 static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
577 PyObject *vec = NULL;
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};
587 if (!PyArg_ParseTuple(args, "fi|O:Matrix.Scale", &factor, &matSize, &vec)) {
590 if (matSize != 2 && matSize != 3 && matSize != 4) {
591 PyErr_SetString(PyExc_ValueError,
593 "can only return a 2x2 3x3 or 4x4 matrix");
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)
604 if (vec == NULL) { //scaling along axis
615 else { //scaling in arbitrary direction
616 //normalize arbitrary axis
619 for (x = 0; x < vec_size; x++) {
620 norm += tvec[x] * tvec[x];
622 norm = (float) sqrt(norm);
623 for (x = 0; x < vec_size; x++) {
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]));
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]));
645 matrix_3x3_as_4x4(mat);
647 //pass to matrix creation
648 return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
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"
655 " Create a matrix to represent an orthographic projection.\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"
663 " :return: A new projection matrix.\n"
664 " :rtype: :class:`Matrix`\n"
666 static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
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};
677 if (!PyArg_ParseTuple(args, "Oi:Matrix.OrthoProjection", &axis, &matSize)) {
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");
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);
691 if (plane_len == 1 && plane[0] == 'X') {
694 else if (plane_len == 1 && plane[0] == 'Y') {
698 PyErr_Format(PyExc_ValueError,
699 "Matrix.OrthoProjection(): "
700 "unknown plane, expected: X, Y, not '%.200s'",
706 if (plane_len == 2 && plane[0] == 'X' && plane[1] == 'Y') {
710 else if (plane_len == 2 && plane[0] == 'X' && plane[1] == 'Z') {
714 else if (plane_len == 2 && plane[0] == 'Y' && plane[1] == 'Z') {
719 PyErr_Format(PyExc_ValueError,
720 "Matrix.OrthoProjection(): "
721 "unknown plane, expected: XY, XZ, YZ, not '%.200s'",
730 int vec_size = (matSize == 2 ? 2 : 3);
733 if (mathutils_array_parse(tvec, vec_size, vec_size, axis,
734 "Matrix.OrthoProjection(axis, size), invalid 'axis' arg") == -1)
739 //normalize arbitrary axis
740 for (x = 0; x < vec_size; x++) {
741 norm += tvec[x] * tvec[x];
743 norm = (float) sqrt(norm);
744 for (x = 0; x < vec_size; x++) {
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]);
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]);
766 matrix_3x3_as_4x4(mat);
768 //pass to matrix creation
769 return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
772 PyDoc_STRVAR(C_Matrix_Shear_doc,
773 ".. classmethod:: Shear(plane, size, factor)\n"
775 " Create a matrix to represent an shear transformation.\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"
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"
788 static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args)
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};
798 if (!PyArg_ParseTuple(args, "siO:Matrix.Shear", &plane, &matSize, &fac)) {
801 if (matSize != 2 && matSize != 3 && matSize != 4) {
802 PyErr_SetString(PyExc_ValueError,
804 "can only return a 2x2 3x3 or 4x4 matrix");
809 float const factor = PyFloat_AsDouble(fac);
811 if (factor == -1.0f && PyErr_Occurred()) {
812 PyErr_SetString(PyExc_TypeError,
814 "the factor to be a float");
822 if (strcmp(plane, "X") == 0) {
825 else if (strcmp(plane, "Y") == 0) {
829 PyErr_SetString(PyExc_ValueError,
831 "expected: X, Y or wrong matrix size for shearing plane");
836 /* 3 or 4, apply as 3x3, resize later if needed */
839 if (mathutils_array_parse(factor, 2, 2, fac, "Matrix.Shear()") < 0) {
848 if (strcmp(plane, "XY") == 0) {
852 else if (strcmp(plane, "XZ") == 0) {
856 else if (strcmp(plane, "YZ") == 0) {
861 PyErr_SetString(PyExc_ValueError,
863 "expected: X, Y, XY, XZ, YZ");
869 matrix_3x3_as_4x4(mat);
871 //pass to matrix creation
872 return Matrix_CreatePyObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
875 void matrix_as_3x3(float mat[3][3], MatrixObject *self)
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));
882 /* assumes rowsize == colsize is checked and the read callback has run */
883 static float matrix_determinant_internal(MatrixObject *self)
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));
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));
895 return determinant_m4((float (*)[4])self->matrix);
900 /*-----------------------------METHODS----------------------------*/
901 PyDoc_STRVAR(Matrix_to_quaternion_doc,
902 ".. method:: to_quaternion()\n"
904 " Return a quaternion representation of the rotation matrix.\n"
906 " :return: Quaternion representation of the rotation matrix.\n"
907 " :rtype: :class:`Quaternion`\n"
909 static PyObject *Matrix_to_quaternion(MatrixObject *self)
913 if (BaseMath_ReadCallback(self) == -1)
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,
920 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
923 if (self->num_row == 3) {
924 mat3_to_quat(quat, (float (*)[3])self->matrix);
927 mat4_to_quat(quat, (float (*)[4])self->matrix);
930 return Quaternion_CreatePyObject(quat, Py_NEW, NULL);
933 /*---------------------------matrix.toEuler() --------------------*/
934 PyDoc_STRVAR(Matrix_to_euler_doc,
935 ".. method:: to_euler(order, euler_compat)\n"
937 " Return an Euler representation of the rotation matrix\n"
938 " (3x3 or 4x4 matrix only).\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"
950 static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
952 const char *order_str = NULL;
953 short order = EULER_ORDER_XYZ;
954 float eul[3], eul_compatf[3];
955 EulerObject *eul_compat = NULL;
960 if (BaseMath_ReadCallback(self) == -1)
963 if (!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat))
967 if (BaseMath_ReadCallback(eul_compat) == -1)
970 copy_v3_v3(eul_compatf, eul_compat->eul);
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;
977 else if (self->num_row ==4 && self->num_col ==4) {
978 copy_m3_m4(tmat, (float (*)[4])self->matrix);
982 PyErr_SetString(PyExc_ValueError,
983 "Matrix.to_euler(): "
984 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
989 order = euler_order_from_string(order_str, "Matrix.to_euler()");
996 if (order == 1) mat3_to_compatible_eul(eul, eul_compatf, mat);
997 else mat3_to_compatible_eulO(eul, eul_compatf, order, mat);
1000 if (order == 1) mat3_to_eul(eul, mat);
1001 else mat3_to_eulO(eul, order, mat);
1004 return Euler_CreatePyObject(eul, order, Py_NEW, NULL);
1007 PyDoc_STRVAR(Matrix_resize_4x4_doc,
1008 ".. method:: resize_4x4()\n"
1010 " Resize the matrix to 4x4.\n"
1012 static PyObject *Matrix_resize_4x4(MatrixObject *self)
1014 float mat[4][4] = MAT4_UNITY;
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");
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");
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");
1038 for (col = 0; col < self->num_col; col++) {
1039 memcpy(mat[col], MATRIX_COL_PTR(self, col), self->num_row * sizeof(float));
1042 copy_m4_m4((float (*)[4])self->matrix, (float (*)[4])mat);
1050 PyDoc_STRVAR(Matrix_to_4x4_doc,
1051 ".. method:: to_4x4()\n"
1053 " Return a 4x4 copy of this matrix.\n"
1055 " :return: a new matrix.\n"
1056 " :rtype: :class:`Matrix`\n"
1058 static PyObject *Matrix_to_4x4(MatrixObject *self)
1060 if (BaseMath_ReadCallback(self) == -1)
1063 if (self->num_row == 4 && self->num_col == 4) {
1064 return Matrix_CreatePyObject(self->matrix, 4, 4, Py_NEW, Py_TYPE(self));
1066 else if (self->num_row == 3 && self->num_col == 3) {
1068 copy_m4_m3(mat, (float (*)[3])self->matrix);
1069 return Matrix_CreatePyObject((float *)mat, 4, 4, Py_NEW, Py_TYPE(self));
1071 /* TODO, 2x2 matrix */
1073 PyErr_SetString(PyExc_TypeError,
1075 "inappropriate matrix size");
1079 PyDoc_STRVAR(Matrix_to_3x3_doc,
1080 ".. method:: to_3x3()\n"
1082 " Return a 3x3 copy of this matrix.\n"
1084 " :return: a new matrix.\n"
1085 " :rtype: :class:`Matrix`\n"
1087 static PyObject *Matrix_to_3x3(MatrixObject *self)
1091 if (BaseMath_ReadCallback(self) == -1)
1094 if ((self->num_row < 3) || (self->num_col < 3)) {
1095 PyErr_SetString(PyExc_TypeError,
1096 "Matrix.to_3x3(): inappropriate matrix size");
1100 matrix_as_3x3(mat, self);
1102 return Matrix_CreatePyObject((float *)mat, 3, 3, Py_NEW, Py_TYPE(self));
1105 PyDoc_STRVAR(Matrix_to_translation_doc,
1106 ".. method:: to_translation()\n"
1108 " Return a the translation part of a 4 row matrix.\n"
1110 " :return: Return a the translation of a matrix.\n"
1111 " :rtype: :class:`Vector`\n"
1113 static PyObject *Matrix_to_translation(MatrixObject *self)
1115 if (BaseMath_ReadCallback(self) == -1)
1118 if ((self->num_row < 3) || self->num_col < 4) {
1119 PyErr_SetString(PyExc_TypeError,
1120 "Matrix.to_translation(): "
1121 "inappropriate matrix size");
1125 return Vector_CreatePyObject(MATRIX_COL_PTR(self, 3), 3, Py_NEW, NULL);
1128 PyDoc_STRVAR(Matrix_to_scale_doc,
1129 ".. method:: to_scale()\n"
1131 " Return a the scale part of a 3x3 or 4x4 matrix.\n"
1133 " :return: Return a the scale of a matrix.\n"
1134 " :rtype: :class:`Vector`\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"
1138 static PyObject *Matrix_to_scale(MatrixObject *self)
1144 if (BaseMath_ReadCallback(self) == -1)
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");
1155 matrix_as_3x3(mat, self);
1157 /* compatible mat4_to_loc_rot_size */
1158 mat3_to_rot_size(rot, size, mat);
1160 return Vector_CreatePyObject(size, 3, Py_NEW, NULL);
1163 /*---------------------------matrix.invert() ---------------------*/
1164 PyDoc_STRVAR(Matrix_invert_doc,
1165 ".. method:: invert()\n"
1167 " Set the matrix to its inverse.\n"
1169 " .. note:: When the matrix cant be inverted a :exc:`ValueError` exception is raised.\n"
1171 " .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n"
1173 static PyObject *Matrix_invert(MatrixObject *self)
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};
1183 if (BaseMath_ReadCallback(self) == -1)
1186 if (self->num_col != self->num_row) {
1187 PyErr_SetString(PyExc_TypeError,
1188 "Matrix.invert(ed): "
1189 "only square matrices are supported");
1193 /* calculate the determinant */
1194 det = matrix_determinant_internal(self);
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);
1204 else if (self->num_col == 3) {
1205 adjoint_m3_m3((float (*)[3]) mat,(float (*)[3])self->matrix);
1207 else if (self->num_col == 4) {
1208 adjoint_m4_m4((float (*)[4]) mat, (float (*)[4])self->matrix);
1210 /* divide by determinate */
1211 for (x = 0; x < (self->num_col * self->num_row); x++) {
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];
1222 Matrix_transpose(self);*/
1225 PyErr_SetString(PyExc_ValueError,
1226 "Matrix.invert(ed): "
1227 "matrix does not have an inverse");
1231 (void)BaseMath_WriteCallback(self);
1235 PyDoc_STRVAR(Matrix_inverted_doc,
1236 ".. method:: inverted()\n"
1238 " Return an inverted copy of the matrix.\n"
1240 " :return: the inverted matrix.\n"
1241 " :rtype: :class:`Matrix`\n"
1243 " .. note:: When the matrix cant be inverted a :exc:`ValueError` exception is raised.\n"
1245 static PyObject *Matrix_inverted(MatrixObject *self)
1247 return matrix__apply_to_copy((PyNoArgsFunction)Matrix_invert, self);
1250 PyDoc_STRVAR(Matrix_rotate_doc,
1251 ".. method:: rotate(other)\n"
1253 " Rotates the matrix a by another mathutils value.\n"
1255 " :arg other: rotation component of mathutils value\n"
1256 " :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n"
1258 " .. note:: If any of the columns are not unit length this may not have desired results.\n"
1260 static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value)
1262 float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
1264 if (BaseMath_ReadCallback(self) == -1)
1267 if (mathutils_any_to_rotmat(other_rmat, value, "matrix.rotate(value)") == -1)
1270 if (self->num_row != 3 || self->num_col != 3) {
1271 PyErr_SetString(PyExc_TypeError,
1273 "must have 3x3 dimensions");
1277 matrix_as_3x3(self_rmat, self);
1278 mul_m3_m3m3(rmat, other_rmat, self_rmat);
1280 copy_m3_m3((float (*)[3])(self->matrix), rmat);
1282 (void)BaseMath_WriteCallback(self);
1286 /*---------------------------matrix.decompose() ---------------------*/
1287 PyDoc_STRVAR(Matrix_decompose_doc,
1288 ".. method:: decompose()\n"
1290 " Return the location, rotaion and scale components of this matrix.\n"
1292 " :return: loc, rot, scale triple.\n"
1293 " :rtype: (:class:`Vector`, :class:`Quaternion`, :class:`Vector`)"
1295 static PyObject *Matrix_decompose(MatrixObject *self)
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");
1310 if (BaseMath_ReadCallback(self) == -1)
1313 mat4_to_loc_rot_size(loc, rot, size, (float (*)[4])self->matrix);
1314 mat3_to_quat(quat, rot);
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));
1326 PyDoc_STRVAR(Matrix_lerp_doc,
1327 ".. function:: lerp(other, factor)\n"
1329 " Returns the interpolation of two matrices.\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"
1338 static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
1340 MatrixObject *mat2 = NULL;
1341 float fac, mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
1343 if (!PyArg_ParseTuple(args, "O!f:lerp", &matrix_Type, &mat2, &fac))
1346 if (self->num_col != mat2->num_col || self->num_row != mat2->num_row) {
1347 PyErr_SetString(PyExc_ValueError,
1349 "expects both matrix objects of the same dimensions");
1353 if (BaseMath_ReadCallback(self) == -1 || BaseMath_ReadCallback(mat2) == -1)
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);
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);
1364 PyErr_SetString(PyExc_ValueError,
1366 "only 3x3 and 4x4 matrices supported");
1370 return Matrix_CreatePyObject(mat, self->num_col, self->num_row, Py_NEW, Py_TYPE(self));
1373 /*---------------------------matrix.determinant() ----------------*/
1374 PyDoc_STRVAR(Matrix_determinant_doc,
1375 ".. method:: determinant()\n"
1377 " Return the determinant of a matrix.\n"
1379 " :return: Return a the determinant of a matrix.\n"
1382 " .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n"
1384 static PyObject *Matrix_determinant(MatrixObject *self)
1386 if (BaseMath_ReadCallback(self) == -1)
1389 if (self->num_col != self->num_row) {
1390 PyErr_SetString(PyExc_TypeError,
1391 "Matrix.determinant(): "
1392 "only square matrices are supported");
1396 return PyFloat_FromDouble((double)matrix_determinant_internal(self));
1398 /*---------------------------matrix.transpose() ------------------*/
1399 PyDoc_STRVAR(Matrix_transpose_doc,
1400 ".. method:: transpose()\n"
1402 " Set the matrix to its transpose.\n"
1404 " .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n"
1406 static PyObject *Matrix_transpose(MatrixObject *self)
1408 if (BaseMath_ReadCallback(self) == -1)
1411 if (self->num_col != self->num_row) {
1412 PyErr_SetString(PyExc_TypeError,
1413 "Matrix.transpose(d): "
1414 "only square matrices are supported");
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;
1423 else if (self->num_col == 3) {
1424 transpose_m3((float (*)[3])self->matrix);
1427 transpose_m4((float (*)[4])self->matrix);
1430 (void)BaseMath_WriteCallback(self);
1434 PyDoc_STRVAR(Matrix_transposed_doc,
1435 ".. method:: transposed()\n"
1437 " Return a new, transposed matrix.\n"
1439 " :return: a transposed matrix\n"
1440 " :rtype: :class:`Matrix`\n"
1442 static PyObject *Matrix_transposed(MatrixObject *self)
1444 return matrix__apply_to_copy((PyNoArgsFunction)Matrix_transpose, self);
1447 /*---------------------------matrix.zero() -----------------------*/
1448 PyDoc_STRVAR(Matrix_zero_doc,
1449 ".. method:: zero()\n"
1451 " Set all the matrix values to zero.\n"
1453 " :return: an instance of itself\n"
1454 " :rtype: :class:`Matrix`\n"
1456 static PyObject *Matrix_zero(MatrixObject *self)
1458 fill_vn_fl(self->matrix, self->num_col * self->num_row, 0.0f);
1460 if (BaseMath_WriteCallback(self) == -1)
1465 /*---------------------------matrix.identity(() ------------------*/
1466 PyDoc_STRVAR(Matrix_identity_doc,
1467 ".. method:: identity()\n"
1469 " Set the matrix to the identity matrix.\n"
1471 " .. note:: An object with zero location and rotation, a scale of one,\n"
1472 " will have an identity matrix.\n"
1474 " .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n"
1476 static PyObject *Matrix_identity(MatrixObject *self)
1478 if (BaseMath_ReadCallback(self) == -1)
1481 if (self->num_col != self->num_row) {
1482 PyErr_SetString(PyExc_TypeError,
1483 "Matrix.identity(): "
1484 "only square matrices are supported");
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;
1494 else if (self->num_col == 3) {
1495 unit_m3((float (*)[3])self->matrix);
1498 unit_m4((float (*)[4])self->matrix);
1501 if (BaseMath_WriteCallback(self) == -1)
1507 /*---------------------------Matrix.copy() ------------------*/
1508 PyDoc_STRVAR(Matrix_copy_doc,
1509 ".. method:: copy()\n"
1511 " Returns a copy of this matrix.\n"
1513 " :return: an instance of itself\n"
1514 " :rtype: :class:`Matrix`\n"
1516 static PyObject *Matrix_copy(MatrixObject *self)
1518 if (BaseMath_ReadCallback(self) == -1)
1521 return Matrix_CreatePyObject((float (*))self->matrix, self->num_col, self->num_row, Py_NEW, Py_TYPE(self));
1524 /*----------------------------print object (internal)-------------*/
1525 /* print the object to screen */
1526 static PyObject *Matrix_repr(MatrixObject *self)
1529 PyObject *rows[MATRIX_MAX_DIM] = {NULL};
1531 if (BaseMath_ReadCallback(self) == -1)
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)));
1540 switch (self->num_row) {
1541 case 2: return PyUnicode_FromFormat("Matrix((%R,\n"
1542 " %R))", rows[0], rows[1]);
1544 case 3: return PyUnicode_FromFormat("Matrix((%R,\n"
1546 " %R))", rows[0], rows[1], rows[2]);
1548 case 4: return PyUnicode_FromFormat("Matrix((%R,\n"
1551 " %R))", rows[0], rows[1], rows[2], rows[3]);
1554 Py_FatalError("Matrix(): invalid row size!");
1558 static PyObject *Matrix_str(MatrixObject *self)
1562 int maxsize[MATRIX_MAX_DIM];
1567 if (BaseMath_ReadCallback(self) == -1)
1570 ds = BLI_dynstr_new();
1572 /* First determine the maximum width for each column */
1573 for (col = 0; col < self->num_col; col++) {
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);
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));
1587 BLI_dynstr_append(ds, row + 1 != self->num_row ? ")\n (" : ")");
1589 BLI_dynstr_append(ds, ">");
1591 return mathutils_dynstr_to_py(ds); /* frees ds */
1594 static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
1597 int ok = -1; /* zero is true */
1599 if (MatrixObject_Check(a) && MatrixObject_Check(b)) {
1600 MatrixObject *matA = (MatrixObject *)a;
1601 MatrixObject *matB = (MatrixObject *)b;
1603 if (BaseMath_ReadCallback(matA) == -1 || BaseMath_ReadCallback(matB) == -1)
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)
1614 ok = !ok; /* pass through */
1616 res = ok ? Py_False : Py_True;
1623 res = Py_NotImplemented;
1626 PyErr_BadArgument();
1630 return Py_INCREF(res), res;
1633 /*---------------------SEQUENCE PROTOCOLS------------------------
1634 ----------------------------len(object)------------------------
1636 static int Matrix_len(MatrixObject *self)
1638 return (self->num_row);
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)
1645 if (BaseMath_ReadCallback(self) == -1)
1648 if (row < 0 || row >= self->num_row) {
1649 PyErr_SetString(PyExc_IndexError,
1650 "matrix[attribute]: "
1651 "array index out of range");
1654 return Vector_CreatePyObject_cb((PyObject *)self, self->num_col, mathutils_matrix_row_cb_index, row);
1656 /* same but column access */
1657 static PyObject *Matrix_item_col(MatrixObject *self, int col)
1659 if (BaseMath_ReadCallback(self) == -1)
1662 if (col < 0 || col >= self->num_col) {
1663 PyErr_SetString(PyExc_IndexError,
1664 "matrix[attribute]: "
1665 "array index out of range");
1668 return Vector_CreatePyObject_cb((PyObject *)self, self->num_row, mathutils_matrix_col_cb_index, col);
1671 /*----------------------------object[]-------------------------
1672 sequence accessor (set) */
1674 static int Matrix_ass_item_row(MatrixObject *self, int row, PyObject *value)
1678 if (BaseMath_ReadCallback(self) == -1)
1681 if (row >= self->num_row || row < 0) {
1682 PyErr_SetString(PyExc_IndexError,
1683 "matrix[attribute] = x: bad row");
1687 if (mathutils_array_parse(vec, self->num_col, self->num_col, value, "matrix[i] = value assignment") < 0) {
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];
1696 (void)BaseMath_WriteCallback(self);
1699 static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value)
1703 if (BaseMath_ReadCallback(self) == -1)
1706 if (col >= self->num_col || col < 0) {
1707 PyErr_SetString(PyExc_IndexError,
1708 "matrix[attribute] = x: bad col");
1712 if (mathutils_array_parse(vec, self->num_row, self->num_row, value, "matrix[i] = value assignment") < 0) {
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];
1721 (void)BaseMath_WriteCallback(self);
1726 /*----------------------------object[z:y]------------------------
1727 sequence slice (get)*/
1728 static PyObject *Matrix_slice(MatrixObject *self, int begin, int end)
1734 if (BaseMath_ReadCallback(self) == -1)
1737 CLAMP(begin, 0, self->num_row);
1738 CLAMP(end, 0, self->num_row);
1739 begin = MIN2(begin, end);
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));
1750 /*----------------------------object[z:y]------------------------
1751 sequence slice (set)*/
1752 static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value)
1754 PyObject *value_fast = NULL;
1756 if (BaseMath_ReadCallback(self) == -1)
1759 CLAMP(begin, 0, self->num_row);
1760 CLAMP(end, 0, self->num_row);
1761 begin = MIN2(begin, end);
1763 /* non list/tuple cases */
1764 if (!(value_fast = PySequence_Fast(value, "matrix[begin:end] = value"))) {
1765 /* PySequence_Fast sets the error */
1769 const int size = end - begin;
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");
1782 memcpy(mat, self->matrix, self->num_col * self->num_row * sizeof(float));
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);
1789 if (mathutils_array_parse(vec, self->num_col, self->num_col, item,
1790 "matrix[begin:end] = value assignment") < 0)
1795 for (col = 0; col < self->num_col; col++) {
1796 mat[col * self->num_row + row] = vec[col];
1800 Py_DECREF(value_fast);
1802 /*parsed well - now set in matrix*/
1803 memcpy(self->matrix, mat, self->num_col * self->num_row * sizeof(float));
1805 (void)BaseMath_WriteCallback(self);
1809 /*------------------------NUMERIC PROTOCOLS----------------------
1810 ------------------------obj + obj------------------------------*/
1811 static PyObject *Matrix_add(PyObject *m1, PyObject *m2)
1814 MatrixObject *mat1 = NULL, *mat2 = NULL;
1816 mat1 = (MatrixObject *)m1;
1817 mat2 = (MatrixObject *)m2;
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);
1827 if (BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1)
1830 if (mat1->num_col != mat2->num_col || mat1->num_row != mat2->num_row) {
1831 PyErr_SetString(PyExc_TypeError,
1833 "matrices must have the same dimensions for this operation");
1837 add_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
1839 return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1));
1841 /*------------------------obj - obj------------------------------
1843 static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
1846 MatrixObject *mat1 = NULL, *mat2 = NULL;
1848 mat1 = (MatrixObject *)m1;
1849 mat2 = (MatrixObject *)m2;
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
1860 if (BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1)
1863 if (mat1->num_col != mat2->num_col || mat1->num_row != mat2->num_row) {
1864 PyErr_SetString(PyExc_TypeError,
1866 "matrices must have the same dimensions for this operation");
1870 sub_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
1872 return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1));
1874 /*------------------------obj * obj------------------------------
1876 static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
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));
1883 static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
1888 MatrixObject *mat1 = NULL, *mat2 = NULL;
1890 if (MatrixObject_Check(m1)) {
1891 mat1 = (MatrixObject *)m1;
1892 if (BaseMath_ReadCallback(mat1) == -1)
1895 if (MatrixObject_Check(m2)) {
1896 mat2 = (MatrixObject *)m2;
1897 if (BaseMath_ReadCallback(mat2) == -1)
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};
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");
1917 for (col = 0; col < mat2->num_col; col++) {
1918 for (row = 0; row < mat1->num_row; row++) {
1920 for (item = 0; item < mat1->num_col; item++) {
1921 dot += MATRIX_ITEM(mat1, row, item) * MATRIX_ITEM(mat2, item, col);
1923 mat[(col * mat1->num_row) + row] = (float)dot;
1927 return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_NEW, Py_TYPE(mat1));
1930 /*FLOAT/INT * MATRIX */
1931 if (((scalar = PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred()) == 0) {
1932 return matrix_mul_float(mat2, scalar);
1936 /* MATRIX * VECTOR */
1937 if (VectorObject_Check(m2)) {
1938 VectorObject *vec2 = (VectorObject *)m2;
1940 if (BaseMath_ReadCallback(vec2) == -1)
1942 if (column_vector_multiplication(tvec, vec2, mat1) == -1) {
1946 if (mat1->num_col == 4 && vec2->size == 3) {
1950 vec_size = mat1->num_row;
1953 return Vector_CreatePyObject(tvec, vec_size, Py_NEW, Py_TYPE(m2));
1955 /*FLOAT/INT * MATRIX */
1956 else if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) {
1957 return matrix_mul_float(mat1, scalar);
1961 BLI_assert(!"internal error");
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);
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 */
1986 static PyObject *Matrix_subscript(MatrixObject *self, PyObject *item)
1988 if (PyIndex_Check(item)) {
1990 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1991 if (i == -1 && PyErr_Occurred())
1995 return Matrix_item_row(self, i);
1997 else if (PySlice_Check(item)) {
1998 Py_ssize_t start, stop, step, slicelength;
2000 if (PySlice_GetIndicesEx((void *)item, self->num_row, &start, &stop, &step, &slicelength) < 0)
2003 if (slicelength <= 0) {
2004 return PyTuple_New(0);
2006 else if (step == 1) {
2007 return Matrix_slice(self, start, stop);
2010 PyErr_SetString(PyExc_IndexError,
2011 "slice steps not supported with matrices");
2016 PyErr_Format(PyExc_TypeError,
2017 "matrix indices must be integers, not %.200s",
2018 Py_TYPE(item)->tp_name);
2023 static int Matrix_ass_subscript(MatrixObject *self, PyObject *item, PyObject *value)
2025 if (PyIndex_Check(item)) {
2026 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2027 if (i == -1 && PyErr_Occurred())
2031 return Matrix_ass_item_row(self, i, value);
2033 else if (PySlice_Check(item)) {
2034 Py_ssize_t start, stop, step, slicelength;
2036 if (PySlice_GetIndicesEx((void *)item, self->num_row, &start, &stop, &step, &slicelength) < 0)
2040 return Matrix_ass_slice(self, start, stop, value);
2042 PyErr_SetString(PyExc_IndexError,
2043 "slice steps not supported with matrices");
2048 PyErr_Format(PyExc_TypeError,
2049 "matrix indices must be integers, not %.200s",
2050 Py_TYPE(item)->tp_name);
2055 static PyMappingMethods Matrix_AsMapping = {
2056 (lenfunc)Matrix_len,
2057 (binaryfunc)Matrix_subscript,
2058 (objobjargproc)Matrix_ass_subscript
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*/
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*/
2075 (binaryfunc)0, /*nb_rshift*/
2080 NULL, /*nb_reserved*/
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 */
2099 PyDoc_STRVAR(Matrix_translation_doc,
2100 "The translation component of the matrix.\n\n:type: Vector"
2102 static PyObject *Matrix_translation_get(MatrixObject *self, void *UNUSED(closure))
2106 if (BaseMath_ReadCallback(self) == -1)
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");
2117 ret = (PyObject *)Vector_CreatePyObject_cb((PyObject *)self, 3, mathutils_matrix_translation_cb_index, 3);
2122 static int Matrix_translation_set(MatrixObject *self, PyObject *value, void *UNUSED(closure))
2126 if (BaseMath_ReadCallback(self) == -1)
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");
2137 if ((mathutils_array_parse(tvec, 3, 3, value, "Matrix.translation")) == -1) {
2141 copy_v3_v3(((float (*)[4])self->matrix)[3], tvec);
2143 (void)BaseMath_WriteCallback(self);
2148 PyDoc_STRVAR(Matrix_row_doc,
2149 "Access the matix by rows (default), (read-only).\n\n:type: Matrix Access"
2151 static PyObject *Matrix_row_get(MatrixObject *self, void *UNUSED(closure))
2153 return MatrixAccess_CreatePyObject(self, MAT_ACCESS_ROW);
2156 PyDoc_STRVAR(Matrix_col_doc,
2157 "Access the matix by colums, 3x3 and 4x4 only, (read-only).\n\n:type: Matrix Access"
2159 static PyObject *Matrix_col_get(MatrixObject *self, void *UNUSED(closure))
2161 return MatrixAccess_CreatePyObject(self, MAT_ACCESS_COL);
2164 PyDoc_STRVAR(Matrix_median_scale_doc,
2165 "The average scale applied to each axis (read-only).\n\n:type: float"
2167 static PyObject *Matrix_median_scale_get(MatrixObject *self, void *UNUSED(closure))
2171 if (BaseMath_ReadCallback(self) == -1)
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");
2182 matrix_as_3x3(mat, self);
2184 return PyFloat_FromDouble(mat3_to_scale(mat));
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"
2190 static PyObject *Matrix_is_negative_get(MatrixObject *self, void *UNUSED(closure))
2192 if (BaseMath_ReadCallback(self) == -1)
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));
2201 PyErr_SetString(PyExc_AttributeError,
2202 "Matrix.is_negative: "
2203 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
2208 PyDoc_STRVAR(Matrix_is_orthogonal_doc,
2209 "True if this matrix is orthogonal, 3x3 and 4x4 only, (read-only).\n\n:type: bool"
2211 static PyObject *Matrix_is_orthogonal_get(MatrixObject *self, void *UNUSED(closure))
2213 if (BaseMath_ReadCallback(self) == -1)
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));
2222 PyErr_SetString(PyExc_AttributeError,
2223 "Matrix.is_orthogonal: "
2224 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
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 */
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},
2251 {"zero", (PyCFunction) Matrix_zero, METH_NOARGS, Matrix_zero_doc},
2252 {"identity", (PyCFunction) Matrix_identity, METH_NOARGS, Matrix_identity_doc},
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},
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},
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},
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}
2286 /*------------------PY_OBECT DEFINITION--------------------------*/
2287 PyDoc_STRVAR(matrix_doc,
2288 "This object gives access to Matrices in Blender."
2290 PyTypeObject matrix_Type = {
2291 PyVarObject_HEAD_INIT(NULL, 0)
2292 "mathutils.Matrix", /*tp_name*/
2293 sizeof(MatrixObject), /*tp_basicsize*/
2295 (destructor)BaseMathObject_dealloc, /*tp_dealloc*/
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*/
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*/
2317 NULL, /*tp_iternext*/
2318 Matrix_methods, /*tp_methods*/
2319 NULL, /*tp_members*/
2320 Matrix_getseters, /*tp_getset*/
2323 NULL, /*tp_descr_get*/
2324 NULL, /*tp_descr_set*/
2325 0, /*tp_dictoffset*/
2328 Matrix_new, /*tp_new*/
2334 NULL, /*tp_subclasses*/
2335 NULL, /*tp_weaklist*/
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)
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,
2353 "row and column sizes must be between 2 and 4");
2357 self = base_type ? (MatrixObject *)base_type->tp_alloc(base_type, 0) :
2358 (MatrixObject *)PyObject_GC_New(MatrixObject, &matrix_Type);
2361 self->num_col = num_col;
2362 self->num_row = num_row;
2364 /* init callbacks as NULL */
2365 self->cb_user = NULL;
2366 self->cb_type = self->cb_subtype = 0;
2368 if (type == Py_WRAP) {
2370 self->wrapped = Py_WRAP;
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,
2377 "problem allocating pointer space");
2381 if (mat) { /*if a float array passed*/
2382 memcpy(self->matrix, mat, num_col * num_row * sizeof(float));
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);
2390 /* otherwise zero everything */
2391 memset(self->matrix, 0, num_col * num_row * sizeof(float));
2393 self->wrapped = Py_NEW;
2396 Py_FatalError("Matrix(): invalid type!");
2400 return (PyObject *) self;
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)
2407 MatrixObject *self = (MatrixObject *)Matrix_CreatePyObject(NULL, num_col, num_row, Py_NEW, NULL);
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);
2415 return (PyObject *) self;
2419 /* ----------------------------------------------------------------------------
2420 * special type for alaternate access */
2423 PyObject_HEAD /* required python macro */
2424 MatrixObject *matrix_user;
2425 eMatrixAccess_t type;
2426 } MatrixAccessObject;
2428 static int MatrixAccess_traverse(MatrixAccessObject *self, visitproc visit, void *arg)
2430 Py_VISIT(self->matrix_user);
2434 static int MatrixAccess_clear(MatrixAccessObject *self)
2436 Py_CLEAR(self->matrix_user);
2440 static void MatrixAccess_dealloc(MatrixAccessObject *self)
2442 if (self->matrix_user) {
2443 PyObject_GC_UnTrack(self);
2444 MatrixAccess_clear(self);
2447 Py_TYPE(self)->tp_free(self);
2450 /* sequence access */
2452 static int MatrixAccess_len(MatrixAccessObject *self)
2454 return (self->type == MAT_ACCESS_ROW) ?
2455 self->matrix_user->num_row :
2456 self->matrix_user->num_col;
2459 static PyObject *MatrixAccess_slice(MatrixAccessObject *self, int begin, int end)
2464 /* row/col access */
2465 MatrixObject *matrix_user = self->matrix_user;
2466 int matrix_access_len;
2467 PyObject *(*Matrix_item_new)(MatrixObject *, int);
2469 if (self->type == MAT_ACCESS_ROW) {
2470 matrix_access_len = matrix_user->num_row;
2471 Matrix_item_new = Matrix_item_row;
2473 else { /* MAT_ACCESS_ROW */
2474 matrix_access_len = matrix_user->num_col;
2475 Matrix_item_new = Matrix_item_col;
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);
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));
2491 static PyObject *MatrixAccess_subscript(MatrixAccessObject *self, PyObject *item)
2493 MatrixObject *matrix_user = self->matrix_user;
2495 if (PyIndex_Check(item)) {
2497 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2498 if (i == -1 && PyErr_Occurred())
2500 if (self->type == MAT_ACCESS_ROW) {
2502 i += matrix_user->num_row;
2503 return Matrix_item_row(matrix_user, i);
2505 else { /* MAT_ACCESS_ROW */
2507 i += matrix_user->num_col;
2508 return Matrix_item_col(matrix_user, i);
2511 else if (PySlice_Check(item)) {
2512 Py_ssize_t start, stop, step, slicelength;
2514 if (PySlice_GetIndicesEx((void *)item, MatrixAccess_len(self), &start, &stop, &step, &slicelength) < 0)
2517 if (slicelength <= 0) {
2518 return PyTuple_New(0);
2520 else if (step == 1) {
2521 return MatrixAccess_slice(self, start, stop);
2524 PyErr_SetString(PyExc_IndexError,
2525 "slice steps not supported with matrix accessors");
2530 PyErr_Format(PyExc_TypeError,
2531 "matrix indices must be integers, not %.200s",
2532 Py_TYPE(item)->tp_name);
2537 static int MatrixAccess_ass_subscript(MatrixAccessObject *self, PyObject *item, PyObject *value)
2539 MatrixObject *matrix_user = self->matrix_user;
2541 if (PyIndex_Check(item)) {
2542 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2543 if (i == -1 && PyErr_Occurred())
2546 if (self->type == MAT_ACCESS_ROW) {
2548 i += matrix_user->num_row;
2549 return Matrix_ass_item_row(matrix_user, i, value);
2551 else { /* MAT_ACCESS_ROW */
2553 i += matrix_user->num_col;
2554 return Matrix_ass_item_col(matrix_user, i, value);
2560 PyErr_Format(PyExc_TypeError,
2561 "matrix indices must be integers, not %.200s",
2562 Py_TYPE(item)->tp_name);
2567 static PyObject *MatrixAccess_iter(MatrixAccessObject *self)
2569 /* Try get values from a collection */
2571 PyObject *iter = NULL;
2572 ret = MatrixAccess_slice(self, 0, MATRIX_MAX_DIM);
2574 /* we know this is a tuple so no need to PyIter_Check
2575 * otherwise it could be NULL (unlikely) if conversion failed */
2577 iter = PyObject_GetIter(ret);
2584 static PyMappingMethods MatrixAccess_AsMapping = {
2585 (lenfunc)MatrixAccess_len,
2586 (binaryfunc)MatrixAccess_subscript,
2587 (objobjargproc) MatrixAccess_ass_subscript
2590 PyTypeObject matrix_access_Type = {
2591 PyVarObject_HEAD_INIT(NULL, 0)
2592 "MatrixAccess", /*tp_name*/
2593 sizeof(MatrixAccessObject), /*tp_basicsize*/
2595 (destructor)MatrixAccess_dealloc, /*tp_dealloc*/
2597 NULL, /*tp_getattr*/
2598 NULL, /*tp_setattr*/
2599 NULL, /*tp_compare*/
2601 NULL, /*tp_as_number*/
2602 NULL /*&MatrixAccess_SeqMethods*/ /* TODO */, /*tp_as_sequence*/
2603 &MatrixAccess_AsMapping, /*tp_as_mapping*/
2607 NULL, /*tp_getattro*/
2608 NULL, /*tp_setattro*/
2609 NULL, /*tp_as_buffer*/
2610 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
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; */
2619 static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type)
2621 MatrixAccessObject *matrix_access = (MatrixAccessObject *)PyObject_GC_New(MatrixObject, &matrix_access_Type);
2623 matrix_access->matrix_user = matrix;
2626 matrix_access->type = type;
2628 return (PyObject *)matrix_access;
2631 /* end special access
2632 * -------------------------------------------------------------------------- */