Blender V4.3
mathutils_Matrix.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <algorithm>
10
11#include <Python.h>
12
13#include "mathutils.hh"
14
15#include "BLI_math_matrix.h"
16#include "BLI_math_rotation.h"
17#include "BLI_math_vector.h"
18#include "BLI_utildefines.h"
19
22
23#ifndef MATH_STANDALONE
24# include "BLI_dynstr.h"
25# include "BLI_string.h"
26#endif
27
32
33static PyObject *Matrix_copy_notest(MatrixObject *self, const float *matrix);
34static PyObject *Matrix_copy(MatrixObject *self);
35static PyObject *Matrix_deepcopy(MatrixObject *self, PyObject *args);
36static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value);
37static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *),
39static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type);
40
41/* -------------------------------------------------------------------- */
45static int matrix_row_vector_check(MatrixObject *mat, VectorObject *vec, int row)
46{
47 if ((vec->vec_num != mat->col_num) || (row >= mat->row_num)) {
48 PyErr_SetString(PyExc_AttributeError,
49 "Matrix(): "
50 "owner matrix has been resized since this row vector was created");
51 return 0;
52 }
53
54 return 1;
55}
56
58{
59 if ((vec->vec_num != mat->row_num) || (col >= mat->col_num)) {
60 PyErr_SetString(PyExc_AttributeError,
61 "Matrix(): "
62 "owner matrix has been resized since this column vector was created");
63 return 0;
64 }
65
66 return 1;
67}
68
70static void matrix_3x3_as_4x4(float mat[16])
71{
72 mat[10] = mat[8];
73 mat[9] = mat[7];
74 mat[8] = mat[6];
75 mat[7] = 0.0f;
76 mat[6] = mat[5];
77 mat[5] = mat[4];
78 mat[4] = mat[3];
79 mat[3] = 0.0f;
80}
81
82void matrix_as_3x3(float mat[3][3], MatrixObject *self)
83{
84 copy_v3_v3(mat[0], MATRIX_COL_PTR(self, 0));
85 copy_v3_v3(mat[1], MATRIX_COL_PTR(self, 1));
86 copy_v3_v3(mat[2], MATRIX_COL_PTR(self, 2));
87}
88
89static void matrix_copy(MatrixObject *mat_dst, const MatrixObject *mat_src)
90{
91 BLI_assert((mat_dst->col_num == mat_src->col_num) && (mat_dst->row_num == mat_src->row_num));
92 BLI_assert(mat_dst != mat_src);
93
94 memcpy(mat_dst->matrix, mat_src->matrix, sizeof(float) * (mat_dst->col_num * mat_dst->row_num));
95}
96
98{
99 const int mat_size = sizeof(float) * (self->col_num * self->row_num);
100 memset(self->matrix, 0x0, mat_size);
101 const int col_row_max = min_ii(self->col_num, self->row_num);
102 const int row_num = self->row_num;
103 for (int col = 0; col < col_row_max; col++) {
104 self->matrix[(col * row_num) + col] = 1.0f;
105 }
106}
107
109static void matrix_transpose_internal(float mat_dst_fl[], const MatrixObject *mat_src)
110{
111 ushort col, row;
112 uint i = 0;
113
114 for (row = 0; row < mat_src->row_num; row++) {
115 for (col = 0; col < mat_src->col_num; col++) {
116 mat_dst_fl[i++] = MATRIX_ITEM(mat_src, row, col);
117 }
118 }
119}
120
123{
124 if (self->col_num == 2) {
125 return determinant_m2(MATRIX_ITEM(self, 0, 0),
126 MATRIX_ITEM(self, 0, 1),
127 MATRIX_ITEM(self, 1, 0),
128 MATRIX_ITEM(self, 1, 1));
129 }
130 if (self->col_num == 3) {
131 return determinant_m3(MATRIX_ITEM(self, 0, 0),
132 MATRIX_ITEM(self, 0, 1),
133 MATRIX_ITEM(self, 0, 2),
134 MATRIX_ITEM(self, 1, 0),
135 MATRIX_ITEM(self, 1, 1),
136 MATRIX_ITEM(self, 1, 2),
137 MATRIX_ITEM(self, 2, 0),
138 MATRIX_ITEM(self, 2, 1),
139 MATRIX_ITEM(self, 2, 2));
140 }
141
142 return determinant_m4((const float(*)[4])self->matrix);
143}
144
145static void adjoint_matrix_n(float *mat_dst, const float *mat_src, const ushort dim)
146{
147 /* calculate the classical adjoint */
148 switch (dim) {
149 case 2: {
150 adjoint_m2_m2((float(*)[2])mat_dst, (const float(*)[2])mat_src);
151 break;
152 }
153 case 3: {
154 adjoint_m3_m3((float(*)[3])mat_dst, (const float(*)[3])mat_src);
155 break;
156 }
157 case 4: {
158 adjoint_m4_m4((float(*)[4])mat_dst, (const float(*)[4])mat_src);
159 break;
160 }
161 default:
163 break;
164 }
165}
166
167static void matrix_invert_with_det_n_internal(float *mat_dst,
168 const float *mat_src,
169 const float det,
170 const ushort dim)
171{
172 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
173 ushort i, j, k;
174
175 BLI_assert(det != 0.0f);
176
177 adjoint_matrix_n(mat, mat_src, dim);
178
179 /* divide by determinant & set values */
180 k = 0;
181 for (i = 0; i < dim; i++) { /* col_num */
182 for (j = 0; j < dim; j++) { /* row_num */
183 mat_dst[MATRIX_ITEM_INDEX_NUMROW(dim, j, i)] = mat[k++] / det;
184 }
185 }
186}
187
191static bool matrix_invert_internal(const MatrixObject *self, float *r_mat)
192{
193 float det;
194 BLI_assert(self->col_num == self->row_num);
196
197 if (det != 0.0f) {
198 matrix_invert_with_det_n_internal(r_mat, self->matrix, det, self->col_num);
199 return true;
200 }
201
202 return false;
203}
204
209static void matrix_invert_safe_internal(const MatrixObject *self, float *r_mat)
210{
211 float det;
212 float *in_mat = self->matrix;
213 BLI_assert(self->col_num == self->row_num);
215
216 if (det == 0.0f) {
217 const float eps = PSEUDOINVERSE_EPSILON;
218
219 /* We will copy self->matrix into r_mat (if needed),
220 * and modify it in place to add diagonal epsilon. */
221 in_mat = r_mat;
222
223 switch (self->col_num) {
224 case 2: {
225 float(*mat)[2] = (float(*)[2])in_mat;
226
227 if (in_mat != self->matrix) {
228 copy_m2_m2(mat, (const float(*)[2])self->matrix);
229 }
230 mat[0][0] += eps;
231 mat[1][1] += eps;
232
233 if (UNLIKELY((det = determinant_m2(mat[0][0], mat[0][1], mat[1][0], mat[1][1])) == 0.0f)) {
234 unit_m2(mat);
235 det = 1.0f;
236 }
237 break;
238 }
239 case 3: {
240 float(*mat)[3] = (float(*)[3])in_mat;
241
242 if (in_mat != self->matrix) {
243 copy_m3_m3(mat, (const float(*)[3])self->matrix);
244 }
245 mat[0][0] += eps;
246 mat[1][1] += eps;
247 mat[2][2] += eps;
248
249 if (UNLIKELY((det = determinant_m3_array(mat)) == 0.0f)) {
250 unit_m3(mat);
251 det = 1.0f;
252 }
253 break;
254 }
255 case 4: {
256 float(*mat)[4] = (float(*)[4])in_mat;
257
258 if (in_mat != self->matrix) {
259 copy_m4_m4(mat, (const float(*)[4])self->matrix);
260 }
261 mat[0][0] += eps;
262 mat[1][1] += eps;
263 mat[2][2] += eps;
264 mat[3][3] += eps;
265
266 if (UNLIKELY(det = determinant_m4(mat)) == 0.0f) {
267 unit_m4(mat);
268 det = 1.0f;
269 }
270 break;
271 }
272 default:
274 }
275 }
276
277 matrix_invert_with_det_n_internal(r_mat, in_mat, det, self->col_num);
278}
279
280static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *),
282{
283 PyObject *ret = Matrix_copy(self);
284 if (ret) {
285 PyObject *ret_dummy = matrix_func((MatrixObject *)ret);
286 if (ret_dummy) {
287 Py_DECREF(ret_dummy);
288 return ret;
289 }
290 /* error */
291 Py_DECREF(ret);
292 return nullptr;
293 }
294
295 /* copy may fail if the read callback errors out */
296 return nullptr;
297}
298
300{
301 for (int row = 0; row < self->row_num; row++) {
302 for (int col = 0; col < self->col_num; col++) {
303 if (MATRIX_ITEM(self, row, col) != ((row != col) ? 0.0f : 1.0f)) {
304 return false;
305 }
306 }
307 }
308 return true;
309}
310
313/* -------------------------------------------------------------------- */
319
321{
322 MatrixObject *self = (MatrixObject *)bmo->cb_user;
324}
325
327{
328 MatrixObject *self = (MatrixObject *)bmo->cb_user;
329 int col;
330
331 if (BaseMath_ReadCallback(self) == -1) {
332 return -1;
333 }
334 if (!matrix_row_vector_check(self, (VectorObject *)bmo, row)) {
335 return -1;
336 }
337
338 for (col = 0; col < self->col_num; col++) {
339 bmo->data[col] = MATRIX_ITEM(self, row, col);
340 }
341
342 return 0;
343}
344
346{
347 MatrixObject *self = (MatrixObject *)bmo->cb_user;
348 int col;
349
351 return -1;
352 }
353 if (!matrix_row_vector_check(self, (VectorObject *)bmo, row)) {
354 return -1;
355 }
356
357 for (col = 0; col < self->col_num; col++) {
358 MATRIX_ITEM(self, row, col) = bmo->data[col];
359 }
360
362 return 0;
363}
364
366{
367 MatrixObject *self = (MatrixObject *)bmo->cb_user;
368
369 if (BaseMath_ReadCallback(self) == -1) {
370 return -1;
371 }
372 if (!matrix_row_vector_check(self, (VectorObject *)bmo, row)) {
373 return -1;
374 }
375
376 bmo->data[col] = MATRIX_ITEM(self, row, col);
377 return 0;
378}
379
381{
382 MatrixObject *self = (MatrixObject *)bmo->cb_user;
383
385 return -1;
386 }
387 if (!matrix_row_vector_check(self, (VectorObject *)bmo, row)) {
388 return -1;
389 }
390
391 MATRIX_ITEM(self, row, col) = bmo->data[col];
392
394 return 0;
395}
396
404
407/* -------------------------------------------------------------------- */
413
415{
416 MatrixObject *self = (MatrixObject *)bmo->cb_user;
418}
419
421{
422 MatrixObject *self = (MatrixObject *)bmo->cb_user;
423 int row_num;
424 int row;
425
426 if (BaseMath_ReadCallback(self) == -1) {
427 return -1;
428 }
430 return -1;
431 }
432
433 /* for 'translation' `vec_num` will always be '3' even on 4x4 vec */
434 row_num = min_ii(self->row_num, ((const VectorObject *)bmo)->vec_num);
435
436 for (row = 0; row < row_num; row++) {
437 bmo->data[row] = MATRIX_ITEM(self, row, col);
438 }
439
440 return 0;
441}
442
444{
445 MatrixObject *self = (MatrixObject *)bmo->cb_user;
446 int row_num;
447 int row;
448
450 return -1;
451 }
453 return -1;
454 }
455
456 /* for 'translation' `vec_num` will always be '3' even on 4x4 vec */
457 row_num = min_ii(self->row_num, ((const VectorObject *)bmo)->vec_num);
458
459 for (row = 0; row < row_num; row++) {
460 MATRIX_ITEM(self, row, col) = bmo->data[row];
461 }
462
464 return 0;
465}
466
468{
469 MatrixObject *self = (MatrixObject *)bmo->cb_user;
470
471 if (BaseMath_ReadCallback(self) == -1) {
472 return -1;
473 }
475 return -1;
476 }
477
478 bmo->data[row] = MATRIX_ITEM(self, row, col);
479 return 0;
480}
481
483{
484 MatrixObject *self = (MatrixObject *)bmo->cb_user;
485
487 return -1;
488 }
490 return -1;
491 }
492
493 MATRIX_ITEM(self, row, col) = bmo->data[row];
494
496 return 0;
497}
498
506
509/* -------------------------------------------------------------------- */
517
519{
520 MatrixObject *self = (MatrixObject *)bmo->cb_user;
522}
523
525{
526 MatrixObject *self = (MatrixObject *)bmo->cb_user;
527 int row;
528
529 if (BaseMath_ReadCallback(self) == -1) {
530 return -1;
531 }
532
533 for (row = 0; row < 3; row++) {
534 bmo->data[row] = MATRIX_ITEM(self, row, col);
535 }
536
537 return 0;
538}
539
541{
542 MatrixObject *self = (MatrixObject *)bmo->cb_user;
543 int row;
544
546 return -1;
547 }
548
549 for (row = 0; row < 3; row++) {
550 MATRIX_ITEM(self, row, col) = bmo->data[row];
551 }
552
554 return 0;
555}
556
558{
559 MatrixObject *self = (MatrixObject *)bmo->cb_user;
560
561 if (BaseMath_ReadCallback(self) == -1) {
562 return -1;
563 }
564
565 bmo->data[row] = MATRIX_ITEM(self, row, col);
566 return 0;
567}
568
570{
571 MatrixObject *self = (MatrixObject *)bmo->cb_user;
572
574 return -1;
575 }
576
577 MATRIX_ITEM(self, row, col) = bmo->data[row];
578
580 return 0;
581}
582
590
593/* -------------------------------------------------------------------- */
597static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
598{
599 if (kwds && PyDict_Size(kwds)) {
600 PyErr_SetString(PyExc_TypeError,
601 "Matrix(): "
602 "takes no keyword args");
603 return nullptr;
604 }
605
606 switch (PyTuple_GET_SIZE(args)) {
607 case 0:
608 return Matrix_CreatePyObject(nullptr, 4, 4, type);
609 case 1: {
610 PyObject *arg = PyTuple_GET_ITEM(args, 0);
611
612 /* Input is now as a sequence of rows so length of sequence
613 * is the number of rows */
614 /* -1 is an error, size checks will account for this */
615 const ushort row_num = PySequence_Size(arg);
616
617 if (row_num >= 2 && row_num <= 4) {
618 PyObject *item = PySequence_GetItem(arg, 0);
619 /* Since each item is a row, number of items is the
620 * same as the number of columns */
621 const ushort col_num = PySequence_Size(item);
622 Py_XDECREF(item);
623
624 if (col_num >= 2 && col_num <= 4) {
625 /* Sane row & col size, new matrix and assign as slice. */
626 PyObject *matrix = Matrix_CreatePyObject(nullptr, col_num, row_num, type);
627 if (Matrix_ass_slice((MatrixObject *)matrix, 0, INT_MAX, arg) == 0) {
628 return matrix;
629 }
630 /* matrix ok, slice assignment not */
631 Py_DECREF(matrix);
632 }
633 }
634 break;
635 }
636 }
637
638 /* will overwrite error */
639 PyErr_SetString(PyExc_TypeError,
640 "Matrix(): "
641 "expects no args or a single arg containing 2-4 numeric sequences");
642 return nullptr;
643}
644
647/* -------------------------------------------------------------------- */
653 /* Wrap. */
654 C_Matrix_Identity_doc,
655 ".. classmethod:: Identity(size)\n"
656 "\n"
657 " Create an identity matrix.\n"
658 "\n"
659 " :arg size: The size of the identity matrix to construct [2, 4].\n"
660 " :type size: int\n"
661 " :return: A new identity matrix.\n"
662 " :rtype: :class:`Matrix`\n");
663static PyObject *C_Matrix_Identity(PyObject *cls, PyObject *args)
664{
665 int matSize;
666
667 if (!PyArg_ParseTuple(args, "i:Matrix.Identity", &matSize)) {
668 return nullptr;
669 }
670
671 if (matSize < 2 || matSize > 4) {
672 PyErr_SetString(PyExc_RuntimeError,
673 "Matrix.Identity(): "
674 "size must be between 2 and 4");
675 return nullptr;
676 }
677
678 return Matrix_CreatePyObject(nullptr, matSize, matSize, (PyTypeObject *)cls);
679}
680
683 /* Wrap. */
684 C_Matrix_Rotation_doc,
685 ".. classmethod:: Rotation(angle, size, axis)\n"
686 "\n"
687 " Create a matrix representing a rotation.\n"
688 "\n"
689 " :arg angle: The angle of rotation desired, in radians.\n"
690 " :type angle: float\n"
691 " :arg size: The size of the rotation matrix to construct [2, 4].\n"
692 " :type size: int\n"
693 " :arg axis: a string in ['X', 'Y', 'Z'] or a 3D Vector Object\n"
694 " (optional when size is 2).\n"
695 " :type axis: str | :class:`Vector`\n"
696 " :return: A new rotation matrix.\n"
697 " :rtype: :class:`Matrix`\n");
698static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
699{
700 PyObject *vec = nullptr;
701 const char *axis = nullptr;
702 int matSize;
703 double angle; /* Use double because of precision problems at high values. */
704 float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
705
706 if (!PyArg_ParseTuple(args, "di|O:Matrix.Rotation", &angle, &matSize, &vec)) {
707 return nullptr;
708 }
709
710 if (vec && PyUnicode_Check(vec)) {
711 axis = PyUnicode_AsUTF8((PyObject *)vec);
712 if (axis == nullptr || axis[0] == '\0' || axis[1] != '\0' || axis[0] < 'X' || axis[0] > 'Z') {
713 PyErr_SetString(PyExc_ValueError,
714 "Matrix.Rotation(): "
715 "3rd argument axis value must be a 3D vector "
716 "or a string in 'X', 'Y', 'Z'");
717 return nullptr;
718 }
719
720 /* use the string */
721 vec = nullptr;
722 }
723
724 angle = angle_wrap_rad(angle);
725
726 if (!ELEM(matSize, 2, 3, 4)) {
727 PyErr_SetString(PyExc_ValueError,
728 "Matrix.Rotation(): "
729 "can only return a 2x2 3x3 or 4x4 matrix");
730 return nullptr;
731 }
732 if (matSize == 2 && (vec != nullptr)) {
733 PyErr_SetString(PyExc_ValueError,
734 "Matrix.Rotation(): "
735 "cannot create a 2x2 rotation matrix around arbitrary axis");
736 return nullptr;
737 }
738 if (ELEM(matSize, 3, 4) && (axis == nullptr) && (vec == nullptr)) {
739 PyErr_SetString(PyExc_ValueError,
740 "Matrix.Rotation(): "
741 "axis of rotation for 3d and 4d matrices is required");
742 return nullptr;
743 }
744
745 /* check for valid vector/axis above */
746 if (vec) {
747 float tvec[3];
748
750 tvec, 3, 3, vec, "Matrix.Rotation(angle, size, axis), invalid 'axis' arg") == -1)
751 {
752 return nullptr;
753 }
754
755 axis_angle_to_mat3((float(*)[3])mat, tvec, angle);
756 }
757 else if (matSize == 2) {
758 angle_to_mat2((float(*)[2])mat, angle);
759 }
760 else {
761 /* valid axis checked above */
762 axis_angle_to_mat3_single((float(*)[3])mat, axis[0], angle);
763 }
764
765 if (matSize == 4) {
767 }
768 /* pass to matrix creation */
769 return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
770}
771
774 /* Wrap. */
775 C_Matrix_Translation_doc,
776 ".. classmethod:: Translation(vector)\n"
777 "\n"
778 " Create a matrix representing a translation.\n"
779 "\n"
780 " :arg vector: The translation vector.\n"
781 " :type vector: :class:`Vector`\n"
782 " :return: An identity matrix with a translation.\n"
783 " :rtype: :class:`Matrix`\n");
784static PyObject *C_Matrix_Translation(PyObject *cls, PyObject *value)
785{
786 float mat[4][4];
787
788 unit_m4(mat);
789
791 mat[3], 3, 4, value, "mathutils.Matrix.Translation(vector), invalid vector arg") == -1)
792 {
793 return nullptr;
794 }
795
796 return Matrix_CreatePyObject(&mat[0][0], 4, 4, (PyTypeObject *)cls);
797}
798
800 /* Wrap. */
801 C_Matrix_Diagonal_doc,
802 ".. classmethod:: Diagonal(vector)\n"
803 "\n"
804 " Create a diagonal (scaling) matrix using the values from the vector.\n"
805 "\n"
806 " :arg vector: The vector of values for the diagonal.\n"
807 " :type vector: :class:`Vector`\n"
808 " :return: A diagonal matrix.\n"
809 " :rtype: :class:`Matrix`\n");
811static PyObject *C_Matrix_Diagonal(PyObject *cls, PyObject *value)
812{
813 float mat[16] = {0.0f};
814 float vec[4];
815
816 int size = mathutils_array_parse(
817 vec, 2, 4, value, "mathutils.Matrix.Diagonal(vector), invalid vector arg");
818
819 if (size == -1) {
820 return nullptr;
821 }
822
823 for (int i = 0; i < size; i++) {
824 mat[size * i + i] = vec[i];
825 }
826
827 return Matrix_CreatePyObject(mat, size, size, (PyTypeObject *)cls);
828}
829
832 /* Wrap. */
833 C_Matrix_Scale_doc,
834 ".. classmethod:: Scale(factor, size, axis)\n"
835 "\n"
836 " Create a matrix representing a scaling.\n"
837 "\n"
838 " :arg factor: The factor of scaling to apply.\n"
839 " :type factor: float\n"
840 " :arg size: The size of the scale matrix to construct [2, 4].\n"
841 " :type size: int\n"
842 " :arg axis: Direction to influence scale. (optional).\n"
843 " :type axis: :class:`Vector`\n"
844 " :return: A new scale matrix.\n"
845 " :rtype: :class:`Matrix`\n");
846static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
847{
848 PyObject *vec = nullptr;
849 int vec_num;
850 float tvec[3];
851 float factor;
852 int matSize;
853 float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
854
855 if (!PyArg_ParseTuple(args, "fi|O:Matrix.Scale", &factor, &matSize, &vec)) {
856 return nullptr;
857 }
858 if (!ELEM(matSize, 2, 3, 4)) {
859 PyErr_SetString(PyExc_ValueError,
860 "Matrix.Scale(): "
861 "can only return a 2x2 3x3 or 4x4 matrix");
862 return nullptr;
863 }
864 if (vec) {
865 vec_num = (matSize == 2 ? 2 : 3);
867 tvec, vec_num, vec_num, vec, "Matrix.Scale(factor, size, axis), invalid 'axis' arg") ==
868 -1)
869 {
870 return nullptr;
871 }
872 }
873 if (vec == nullptr) { /* scaling along axis */
874 if (matSize == 2) {
875 mat[0] = factor;
876 mat[3] = factor;
877 }
878 else {
879 mat[0] = factor;
880 mat[4] = factor;
881 mat[8] = factor;
882 }
883 }
884 else {
885 /* scaling in arbitrary direction
886 * normalize arbitrary axis */
887 float norm = 0.0f;
888 int x;
889 for (x = 0; x < vec_num; x++) {
890 norm += tvec[x] * tvec[x];
891 }
892 norm = sqrtf(norm);
893 for (x = 0; x < vec_num; x++) {
894 tvec[x] /= norm;
895 }
896 if (matSize == 2) {
897 mat[0] = 1 + ((factor - 1) * (tvec[0] * tvec[0]));
898 mat[1] = ((factor - 1) * (tvec[0] * tvec[1]));
899 mat[2] = ((factor - 1) * (tvec[0] * tvec[1]));
900 mat[3] = 1 + ((factor - 1) * (tvec[1] * tvec[1]));
901 }
902 else {
903 mat[0] = 1 + ((factor - 1) * (tvec[0] * tvec[0]));
904 mat[1] = ((factor - 1) * (tvec[0] * tvec[1]));
905 mat[2] = ((factor - 1) * (tvec[0] * tvec[2]));
906 mat[3] = ((factor - 1) * (tvec[0] * tvec[1]));
907 mat[4] = 1 + ((factor - 1) * (tvec[1] * tvec[1]));
908 mat[5] = ((factor - 1) * (tvec[1] * tvec[2]));
909 mat[6] = ((factor - 1) * (tvec[0] * tvec[2]));
910 mat[7] = ((factor - 1) * (tvec[1] * tvec[2]));
911 mat[8] = 1 + ((factor - 1) * (tvec[2] * tvec[2]));
912 }
913 }
914 if (matSize == 4) {
916 }
917 /* pass to matrix creation */
918 return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
919}
922 /* Wrap. */
923 C_Matrix_OrthoProjection_doc,
924 ".. classmethod:: OrthoProjection(axis, size)\n"
925 "\n"
926 " Create a matrix to represent an orthographic projection.\n"
927 "\n"
928 " :arg axis: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'],\n"
929 " where a single axis is for a 2D matrix.\n"
930 " Or a vector for an arbitrary axis\n"
931 " :type axis: str | :class:`Vector`\n"
932 " :arg size: The size of the projection matrix to construct [2, 4].\n"
933 " :type size: int\n"
934 " :return: A new projection matrix.\n"
935 " :rtype: :class:`Matrix`\n");
936static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
937{
938 PyObject *axis;
939
940 int matSize, x;
941 float norm = 0.0f;
942 float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
943
944 if (!PyArg_ParseTuple(args, "Oi:Matrix.OrthoProjection", &axis, &matSize)) {
945 return nullptr;
946 }
947 if (!ELEM(matSize, 2, 3, 4)) {
948 PyErr_SetString(PyExc_ValueError,
949 "Matrix.OrthoProjection(): "
950 "can only return a 2x2 3x3 or 4x4 matrix");
951 return nullptr;
952 }
953
954 if (PyUnicode_Check(axis)) { /* ortho projection onto cardinal plane */
955 Py_ssize_t plane_len;
956 const char *plane = PyUnicode_AsUTF8AndSize(axis, &plane_len);
957 if (matSize == 2) {
958 if (plane_len == 1 && plane[0] == 'X') {
959 mat[0] = 1.0f;
960 }
961 else if (plane_len == 1 && plane[0] == 'Y') {
962 mat[3] = 1.0f;
963 }
964 else {
965 PyErr_Format(PyExc_ValueError,
966 "Matrix.OrthoProjection(): "
967 "unknown plane, expected: X, Y, not '%.200s'",
968 plane);
969 return nullptr;
970 }
971 }
972 else {
973 if (plane_len == 2 && plane[0] == 'X' && plane[1] == 'Y') {
974 mat[0] = 1.0f;
975 mat[4] = 1.0f;
976 }
977 else if (plane_len == 2 && plane[0] == 'X' && plane[1] == 'Z') {
978 mat[0] = 1.0f;
979 mat[8] = 1.0f;
980 }
981 else if (plane_len == 2 && plane[0] == 'Y' && plane[1] == 'Z') {
982 mat[4] = 1.0f;
983 mat[8] = 1.0f;
984 }
985 else {
986 PyErr_Format(PyExc_ValueError,
987 "Matrix.OrthoProjection(): "
988 "unknown plane, expected: XY, XZ, YZ, not '%.200s'",
989 plane);
990 return nullptr;
991 }
992 }
993 }
994 else {
995 /* arbitrary plane */
996
997 const int vec_num = (matSize == 2 ? 2 : 3);
998 float tvec[4];
999
1000 if (mathutils_array_parse(tvec,
1001 vec_num,
1002 vec_num,
1003 axis,
1004 "Matrix.OrthoProjection(axis, size), invalid 'axis' arg") == -1)
1005 {
1006 return nullptr;
1007 }
1008
1009 /* normalize arbitrary axis */
1010 for (x = 0; x < vec_num; x++) {
1011 norm += tvec[x] * tvec[x];
1012 }
1013 norm = sqrtf(norm);
1014 for (x = 0; x < vec_num; x++) {
1015 tvec[x] /= norm;
1016 }
1017 if (matSize == 2) {
1018 mat[0] = 1 - (tvec[0] * tvec[0]);
1019 mat[1] = -(tvec[0] * tvec[1]);
1020 mat[2] = -(tvec[0] * tvec[1]);
1021 mat[3] = 1 - (tvec[1] * tvec[1]);
1022 }
1023 else if (matSize > 2) {
1024 mat[0] = 1 - (tvec[0] * tvec[0]);
1025 mat[1] = -(tvec[0] * tvec[1]);
1026 mat[2] = -(tvec[0] * tvec[2]);
1027 mat[3] = -(tvec[0] * tvec[1]);
1028 mat[4] = 1 - (tvec[1] * tvec[1]);
1029 mat[5] = -(tvec[1] * tvec[2]);
1030 mat[6] = -(tvec[0] * tvec[2]);
1031 mat[7] = -(tvec[1] * tvec[2]);
1032 mat[8] = 1 - (tvec[2] * tvec[2]);
1033 }
1034 }
1035 if (matSize == 4) {
1036 matrix_3x3_as_4x4(mat);
1037 }
1038 /* pass to matrix creation */
1039 return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
1040}
1041
1044 /* Wrap. */
1045 C_Matrix_Shear_doc,
1046 ".. classmethod:: Shear(plane, size, factor)\n"
1047 "\n"
1048 " Create a matrix to represent an shear transformation.\n"
1049 "\n"
1050 " :arg plane: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'],\n"
1051 " where a single axis is for a 2D matrix only.\n"
1052 " :type plane: str\n"
1053 " :arg size: The size of the shear matrix to construct [2, 4].\n"
1054 " :type size: int\n"
1055 " :arg factor: The factor of shear to apply. "
1056 "For a 2 *size* matrix use a single float. "
1057 "For a 3 or 4 *size* matrix pass a pair of floats corresponding with the *plane* axis.\n"
1058 " :type factor: float | Sequence[float]\n"
1059 " :return: A new shear matrix.\n"
1060 " :rtype: :class:`Matrix`\n");
1061static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args)
1062{
1063 int matSize;
1064 const char *plane;
1065 PyObject *fac;
1066 float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
1067
1068 if (!PyArg_ParseTuple(args, "siO:Matrix.Shear", &plane, &matSize, &fac)) {
1069 return nullptr;
1070 }
1071 if (!ELEM(matSize, 2, 3, 4)) {
1072 PyErr_SetString(PyExc_ValueError,
1073 "Matrix.Shear(): "
1074 "can only return a 2x2 3x3 or 4x4 matrix");
1075 return nullptr;
1076 }
1077
1078 if (matSize == 2) {
1079 float const factor = PyFloat_AsDouble(fac);
1080
1081 if (factor == -1.0f && PyErr_Occurred()) {
1082 PyErr_SetString(PyExc_TypeError,
1083 "Matrix.Shear(): "
1084 "the factor to be a float");
1085 return nullptr;
1086 }
1087
1088 /* unit */
1089 mat[0] = 1.0f;
1090 mat[3] = 1.0f;
1091
1092 if (STREQ(plane, "X")) {
1093 mat[2] = factor;
1094 }
1095 else if (STREQ(plane, "Y")) {
1096 mat[1] = factor;
1097 }
1098 else {
1099 PyErr_SetString(PyExc_ValueError,
1100 "Matrix.Shear(): "
1101 "expected: X, Y or wrong matrix size for shearing plane");
1102 return nullptr;
1103 }
1104 }
1105 else {
1106 /* 3 or 4, apply as 3x3, resize later if needed */
1107 float factor[2];
1108
1109 if (mathutils_array_parse(factor, 2, 2, fac, "Matrix.Shear()") == -1) {
1110 return nullptr;
1111 }
1112
1113 /* unit */
1114 mat[0] = 1.0f;
1115 mat[4] = 1.0f;
1116 mat[8] = 1.0f;
1117
1118 if (STREQ(plane, "XY")) {
1119 mat[6] = factor[0];
1120 mat[7] = factor[1];
1121 }
1122 else if (STREQ(plane, "XZ")) {
1123 mat[3] = factor[0];
1124 mat[5] = factor[1];
1125 }
1126 else if (STREQ(plane, "YZ")) {
1127 mat[1] = factor[0];
1128 mat[2] = factor[1];
1129 }
1130 else {
1131 PyErr_SetString(PyExc_ValueError,
1132 "Matrix.Shear(): "
1133 "expected: X, Y, XY, XZ, YZ");
1134 return nullptr;
1135 }
1136 }
1137
1138 if (matSize == 4) {
1139 matrix_3x3_as_4x4(mat);
1140 }
1141 /* pass to matrix creation */
1142 return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
1143}
1144
1146 /* Wrap. */
1147 C_Matrix_LocRotScale_doc,
1148 ".. classmethod:: LocRotScale(location, rotation, scale)\n"
1149 "\n"
1150 " Create a matrix combining translation, rotation and scale,\n"
1151 " acting as the inverse of the decompose() method.\n"
1152 "\n"
1153 " Any of the inputs may be replaced with None if not needed.\n"
1154 "\n"
1155 " :arg location: The translation component.\n"
1156 " :type location: :class:`Vector` | None\n"
1157 " :arg rotation: The rotation component as a "
1158 "3x3 matrix, quaternion, euler or None for no rotation.\n"
1159 " :type rotation: :class:`Matrix` | :class:`Quaternion` | :class:`Euler` | None\n"
1160 " :arg scale: The scale component.\n"
1161 " :type scale: :class:`Vector` | None\n"
1162 " :return: Combined transformation as a 4x4 matrix. \n"
1163 " :rtype: :class:`Matrix`\n");
1164static PyObject *C_Matrix_LocRotScale(PyObject *cls, PyObject *args)
1165{
1166 PyObject *loc_obj, *rot_obj, *scale_obj;
1167 float mat[4][4], loc[3];
1168
1169 if (!PyArg_ParseTuple(args, "OOO:Matrix.LocRotScale", &loc_obj, &rot_obj, &scale_obj)) {
1170 return nullptr;
1171 }
1172
1173 /* Decode location. */
1174 if (loc_obj == Py_None) {
1175 zero_v3(loc);
1176 }
1177 else if (mathutils_array_parse(
1178 loc, 3, 3, loc_obj, "Matrix.LocRotScale(), invalid location argument") == -1)
1179 {
1180 return nullptr;
1181 }
1182
1183 /* Decode rotation. */
1184 if (rot_obj == Py_None) {
1185 unit_m4(mat);
1186 }
1187 else if (QuaternionObject_Check(rot_obj)) {
1188 QuaternionObject *quat_obj = (QuaternionObject *)rot_obj;
1189
1190 if (BaseMath_ReadCallback(quat_obj) == -1) {
1191 return nullptr;
1192 }
1193
1194 quat_to_mat4(mat, quat_obj->quat);
1195 }
1196 else if (EulerObject_Check(rot_obj)) {
1197 EulerObject *eul_obj = (EulerObject *)rot_obj;
1198
1199 if (BaseMath_ReadCallback(eul_obj) == -1) {
1200 return nullptr;
1201 }
1202
1203 eulO_to_mat4(mat, eul_obj->eul, eul_obj->order);
1204 }
1205 else if (MatrixObject_Check(rot_obj)) {
1206 MatrixObject *mat_obj = (MatrixObject *)rot_obj;
1207
1208 if (BaseMath_ReadCallback(mat_obj) == -1) {
1209 return nullptr;
1210 }
1211
1212 if (mat_obj->col_num == 3 && mat_obj->row_num == 3) {
1213 copy_m4_m3(mat, (const float(*)[3])mat_obj->matrix);
1214 }
1215 else {
1216 PyErr_SetString(PyExc_ValueError,
1217 "Matrix.LocRotScale(): "
1218 "inappropriate rotation matrix size - expects 3x3 matrix");
1219 return nullptr;
1220 }
1221 }
1222 else {
1223 PyErr_SetString(PyExc_ValueError,
1224 "Matrix.LocRotScale(): "
1225 "rotation argument must be Matrix, Quaternion, Euler or None");
1226 return nullptr;
1227 }
1228
1229 /* Decode scale. */
1230 if (scale_obj != Py_None) {
1231 float scale[3];
1232
1234 scale, 3, 3, scale_obj, "Matrix.LocRotScale(), invalid scale argument") == -1)
1235 {
1236 return nullptr;
1237 }
1238
1239 rescale_m4(mat, scale);
1240 }
1241
1242 copy_v3_v3(mat[3], loc);
1243
1244 return Matrix_CreatePyObject(&mat[0][0], 4, 4, (PyTypeObject *)cls);
1245}
1246
1249/* -------------------------------------------------------------------- */
1254 /* Wrap. */
1255 Matrix_to_quaternion_doc,
1256 ".. method:: to_quaternion()\n"
1257 "\n"
1258 " Return a quaternion representation of the rotation matrix.\n"
1259 "\n"
1260 " :return: Quaternion representation of the rotation matrix.\n"
1261 " :rtype: :class:`Quaternion`\n");
1263{
1264 float quat[4];
1265
1266 if (BaseMath_ReadCallback(self) == -1) {
1267 return nullptr;
1268 }
1269
1270 /* must be 3-4 cols, 3-4 rows, square matrix */
1271 if ((self->row_num < 3) || (self->col_num < 3) || (self->row_num != self->col_num)) {
1272 PyErr_SetString(PyExc_ValueError,
1273 "Matrix.to_quat(): "
1274 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
1275 return nullptr;
1276 }
1277 if (self->row_num == 3) {
1278 mat3_to_quat(quat, (const float(*)[3])self->matrix);
1279 }
1280 else {
1281 mat4_to_quat(quat, (const float(*)[4])self->matrix);
1282 }
1283 return Quaternion_CreatePyObject(quat, nullptr);
1284}
1285
1288/* -------------------------------------------------------------------- */
1293 /* Wrap. */
1294 Matrix_to_euler_doc,
1295 ".. method:: to_euler(order, euler_compat)\n"
1296 "\n"
1297 " Return an Euler representation of the rotation matrix\n"
1298 " (3x3 or 4x4 matrix only).\n"
1299 "\n"
1300 " :arg order: Optional rotation order argument in\n"
1301 " ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n"
1302 " :type order: str\n"
1303 " :arg euler_compat: Optional euler argument the new euler will be made\n"
1304 " compatible with (no axis flipping between them).\n"
1305 " Useful for converting a series of matrices to animation curves.\n"
1306 " :type euler_compat: :class:`Euler`\n"
1307 " :return: Euler representation of the matrix.\n"
1308 " :rtype: :class:`Euler`\n");
1309static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
1310{
1311 const char *order_str = nullptr;
1312 short order = EULER_ORDER_XYZ;
1313 float eul[3], eul_compatf[3];
1314 EulerObject *eul_compat = nullptr;
1315
1316 float mat[3][3];
1317
1318 if (BaseMath_ReadCallback(self) == -1) {
1319 return nullptr;
1320 }
1321
1322 if (!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat)) {
1323 return nullptr;
1324 }
1325
1326 if (eul_compat) {
1327 if (BaseMath_ReadCallback(eul_compat) == -1) {
1328 return nullptr;
1329 }
1330
1331 copy_v3_v3(eul_compatf, eul_compat->eul);
1332 }
1333
1334 /* Must be 3-4 cols, 3-4 rows, square matrix. */
1335 if (self->row_num == 3 && self->col_num == 3) {
1336 copy_m3_m3(mat, (const float(*)[3])self->matrix);
1337 }
1338 else if (self->row_num == 4 && self->col_num == 4) {
1339 copy_m3_m4(mat, (const float(*)[4])self->matrix);
1340 }
1341 else {
1342 PyErr_SetString(PyExc_ValueError,
1343 "Matrix.to_euler(): "
1344 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
1345 return nullptr;
1346 }
1347
1348 if (order_str) {
1349 order = euler_order_from_string(order_str, "Matrix.to_euler()");
1350
1351 if (order == -1) {
1352 return nullptr;
1353 }
1354 }
1355
1356 normalize_m3(mat);
1357
1358 if (eul_compat) {
1359 if (order == 1) {
1360 mat3_normalized_to_compatible_eul(eul, eul_compatf, mat);
1361 }
1362 else {
1363 mat3_normalized_to_compatible_eulO(eul, eul_compatf, order, mat);
1364 }
1365 }
1366 else {
1367 if (order == 1) {
1368 mat3_normalized_to_eul(eul, mat);
1369 }
1370 else {
1371 mat3_normalized_to_eulO(eul, order, mat);
1372 }
1373 }
1374
1375 return Euler_CreatePyObject(eul, order, nullptr);
1376}
1377
1380/* -------------------------------------------------------------------- */
1385 /* Wrap. */
1386 Matrix_resize_4x4_doc,
1387 ".. method:: resize_4x4()\n"
1388 "\n"
1389 " Resize the matrix to 4x4.\n");
1391{
1392 float mat[4][4];
1393 int col;
1394
1395 if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
1396 PyErr_SetString(PyExc_ValueError,
1397 "Matrix.resize_4x4(): "
1398 "cannot resize wrapped data - make a copy and resize that");
1399 return nullptr;
1400 }
1401 if (self->cb_user) {
1402 PyErr_SetString(PyExc_ValueError,
1403 "Matrix.resize_4x4(): "
1404 "cannot resize owned data - make a copy and resize that");
1405 return nullptr;
1406 }
1407
1408 self->matrix = static_cast<float *>(
1409 PyMem_Realloc(self->matrix, (sizeof(float) * (MATRIX_MAX_DIM * MATRIX_MAX_DIM))));
1410 if (self->matrix == nullptr) {
1411 PyErr_SetString(PyExc_MemoryError,
1412 "Matrix.resize_4x4(): "
1413 "problem allocating pointer space");
1414 return nullptr;
1415 }
1416
1417 unit_m4(mat);
1418
1419 for (col = 0; col < self->col_num; col++) {
1420 memcpy(mat[col], MATRIX_COL_PTR(self, col), self->row_num * sizeof(float));
1421 }
1422
1423 copy_m4_m4((float(*)[4])self->matrix, (const float(*)[4])mat);
1424
1425 self->col_num = 4;
1426 self->row_num = 4;
1427
1428 Py_RETURN_NONE;
1429}
1430
1433/* -------------------------------------------------------------------- */
1437static PyObject *Matrix_to_NxN(MatrixObject *self, const int col_num, const int row_num)
1438{
1439 const int mat_size = sizeof(float) * (col_num * row_num);
1441 static_cast<float *>(PyMem_Malloc(mat_size)), col_num, row_num, Py_TYPE(self));
1442
1443 if ((self->row_num == row_num) && (self->col_num == col_num)) {
1444 memcpy(pymat->matrix, self->matrix, mat_size);
1445 }
1446 else {
1447 if ((self->col_num < col_num) || (self->row_num < row_num)) {
1448 matrix_unit_internal(pymat);
1449 }
1450 const int col_len_src = min_ii(col_num, self->col_num);
1451 const int row_len_src = min_ii(row_num, self->row_num);
1452 for (int col = 0; col < col_len_src; col++) {
1453 memcpy(
1454 &pymat->matrix[col * row_num], MATRIX_COL_PTR(self, col), sizeof(float) * row_len_src);
1455 }
1456 }
1457 return (PyObject *)pymat;
1458}
1459
1461 /* Wrap. */
1462 Matrix_to_2x2_doc,
1463 ".. method:: to_2x2()\n"
1464 "\n"
1465 " Return a 2x2 copy of this matrix.\n"
1466 "\n"
1467 " :return: a new matrix.\n"
1468 " :rtype: :class:`Matrix`\n");
1470{
1471 if (BaseMath_ReadCallback(self) == -1) {
1472 return nullptr;
1473 }
1474 return Matrix_to_NxN(self, 2, 2);
1475}
1476
1478 /* Wrap. */
1479 Matrix_to_3x3_doc,
1480 ".. method:: to_3x3()\n"
1481 "\n"
1482 " Return a 3x3 copy of this matrix.\n"
1483 "\n"
1484 " :return: a new matrix.\n"
1485 " :rtype: :class:`Matrix`\n");
1487{
1488 if (BaseMath_ReadCallback(self) == -1) {
1489 return nullptr;
1490 }
1491 return Matrix_to_NxN(self, 3, 3);
1492}
1493
1495 /* Wrap. */
1496 Matrix_to_4x4_doc,
1497 ".. method:: to_4x4()\n"
1498 "\n"
1499 " Return a 4x4 copy of this matrix.\n"
1500 "\n"
1501 " :return: a new matrix.\n"
1502 " :rtype: :class:`Matrix`\n");
1504{
1505
1506 if (BaseMath_ReadCallback(self) == -1) {
1507 return nullptr;
1508 }
1509 return Matrix_to_NxN(self, 4, 4);
1510}
1511
1514/* -------------------------------------------------------------------- */
1519 /* Wrap. */
1520 Matrix_to_translation_doc,
1521 ".. method:: to_translation()\n"
1522 "\n"
1523 " Return the translation part of a 4 row matrix.\n"
1524 "\n"
1525 " :return: Return the translation of a matrix.\n"
1526 " :rtype: :class:`Vector`\n");
1528{
1529 if (BaseMath_ReadCallback(self) == -1) {
1530 return nullptr;
1531 }
1532
1533 if ((self->row_num < 3) || self->col_num < 4) {
1534 PyErr_SetString(PyExc_ValueError,
1535 "Matrix.to_translation(): "
1536 "inappropriate matrix size");
1537 return nullptr;
1538 }
1539
1540 return Vector_CreatePyObject(MATRIX_COL_PTR(self, 3), 3, nullptr);
1541}
1542
1544 /* Wrap. */
1545 Matrix_to_scale_doc,
1546 ".. method:: to_scale()\n"
1547 "\n"
1548 " Return the scale part of a 3x3 or 4x4 matrix.\n"
1549 "\n"
1550 " :return: Return the scale of a matrix.\n"
1551 " :rtype: :class:`Vector`\n"
1552 "\n"
1553 " .. note:: This method does not return a negative scale on any axis because it is "
1554 "not possible to obtain this data from the matrix alone.\n");
1556{
1557 float rot[3][3];
1558 float mat[3][3];
1559 float size[3];
1560
1561 if (BaseMath_ReadCallback(self) == -1) {
1562 return nullptr;
1563 }
1564
1565 /* Must be 3-4 cols, 3-4 rows, square matrix. */
1566 if ((self->row_num < 3) || (self->col_num < 3)) {
1567 PyErr_SetString(PyExc_ValueError,
1568 "Matrix.to_scale(): "
1569 "inappropriate matrix size, 3x3 minimum size");
1570 return nullptr;
1571 }
1572
1573 matrix_as_3x3(mat, self);
1574
1575 /* compatible mat4_to_loc_rot_size */
1576 mat3_to_rot_size(rot, size, mat);
1577
1578 return Vector_CreatePyObject(size, 3, nullptr);
1579}
1580
1583/* -------------------------------------------------------------------- */
1589{
1590 if (self->col_num != self->row_num) {
1591 PyErr_SetString(PyExc_ValueError,
1592 "Matrix.invert(ed): "
1593 "only square matrices are supported");
1594 return false;
1595 }
1596
1597 return true;
1598}
1599
1600static bool matrix_invert_args_check(const MatrixObject *self, PyObject *args, bool check_type)
1601{
1602 switch (PyTuple_GET_SIZE(args)) {
1603 case 0:
1604 return true;
1605 case 1:
1606 if (check_type) {
1607 const MatrixObject *fallback = (const MatrixObject *)PyTuple_GET_ITEM(args, 0);
1608 if (!MatrixObject_Check(fallback)) {
1609 PyErr_SetString(PyExc_TypeError,
1610 "Matrix.invert: "
1611 "expects a matrix argument or nothing");
1612 return false;
1613 }
1614
1615 if ((self->col_num != fallback->col_num) || (self->row_num != fallback->row_num)) {
1616 PyErr_SetString(PyExc_TypeError,
1617 "Matrix.invert: "
1618 "matrix argument has different dimensions");
1619 return false;
1620 }
1621 }
1622
1623 return true;
1624 default:
1625 PyErr_SetString(PyExc_ValueError,
1626 "Matrix.invert(ed): "
1627 "takes at most one argument");
1628 return false;
1629 }
1630}
1631
1633{
1634 PyErr_SetString(PyExc_ValueError,
1635 "Matrix.invert(ed): "
1636 "matrix does not have an inverse");
1637}
1638
1640 /* Wrap. */
1641 Matrix_invert_doc,
1642 ".. method:: invert(fallback=None)\n"
1643 "\n"
1644 " Set the matrix to its inverse.\n"
1645 "\n"
1646 " :arg fallback: Set the matrix to this value when the inverse cannot be calculated\n"
1647 " (instead of raising a :exc:`ValueError` exception).\n"
1648 " :type fallback: :class:`Matrix`\n"
1649 "\n"
1650 " .. seealso:: `Inverse matrix <https://en.wikipedia.org/wiki/Inverse_matrix>`__ on "
1651 "Wikipedia.\n");
1652static PyObject *Matrix_invert(MatrixObject *self, PyObject *args)
1653{
1655 return nullptr;
1656 }
1657
1658 if (matrix_invert_is_compat(self) == false) {
1659 return nullptr;
1660 }
1661
1662 if (matrix_invert_args_check(self, args, true) == false) {
1663 return nullptr;
1664 }
1665
1666 if (matrix_invert_internal(self, self->matrix)) {
1667 /* pass */
1668 }
1669 else {
1670 if (PyTuple_GET_SIZE(args) == 1) {
1671 MatrixObject *fallback = (MatrixObject *)PyTuple_GET_ITEM(args, 0);
1672
1673 if (BaseMath_ReadCallback(fallback) == -1) {
1674 return nullptr;
1675 }
1676
1677 if (self != fallback) {
1678 matrix_copy(self, fallback);
1679 }
1680 }
1681 else {
1683 return nullptr;
1684 }
1685 }
1686
1688 Py_RETURN_NONE;
1689}
1690
1692 /* Wrap. */
1693 Matrix_inverted_doc,
1694 ".. method:: inverted(fallback=None)\n"
1695 "\n"
1696 " Return an inverted copy of the matrix.\n"
1697 "\n"
1698 " :arg fallback: return this when the inverse can't be calculated\n"
1699 " (instead of raising a :exc:`ValueError`).\n"
1700 " :type fallback: Any\n"
1701 " :return: The inverted matrix or fallback when given.\n"
1702 " :rtype: :class:`Matrix` | Any\n");
1703static PyObject *Matrix_inverted(MatrixObject *self, PyObject *args)
1704{
1705 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
1706
1707 if (BaseMath_ReadCallback(self) == -1) {
1708 return nullptr;
1709 }
1710
1711 if (matrix_invert_args_check(self, args, false) == false) {
1712 return nullptr;
1713 }
1714
1715 if (matrix_invert_is_compat(self) == false) {
1716 return nullptr;
1717 }
1718
1719 if (matrix_invert_internal(self, mat)) {
1720 /* pass */
1721 }
1722 else {
1723 if (PyTuple_GET_SIZE(args) == 1) {
1724 PyObject *fallback = PyTuple_GET_ITEM(args, 0);
1725 Py_INCREF(fallback);
1726 return fallback;
1727 }
1728
1730 return nullptr;
1731 }
1732
1733 return Matrix_copy_notest(self, mat);
1734}
1735
1737{
1739 return nullptr;
1740 }
1741
1742 if (matrix_invert_is_compat(self) == false) {
1743 return nullptr;
1744 }
1745
1746 if (matrix_invert_internal(self, self->matrix)) {
1747 /* pass */
1748 }
1749 else {
1751 return nullptr;
1752 }
1753
1755 Py_RETURN_NONE;
1756}
1757
1759 /* Wrap. */
1760 Matrix_invert_safe_doc,
1761 ".. method:: invert_safe()\n"
1762 "\n"
1763 " Set the matrix to its inverse, will never error.\n"
1764 " If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, "
1765 "to get an invertible one.\n"
1766 " If tweaked matrix is still degenerated, set to the identity matrix instead.\n"
1767 "\n"
1768 " .. seealso:: `Inverse Matrix <https://en.wikipedia.org/wiki/Inverse_matrix>`__ on "
1769 "Wikipedia.\n");
1771{
1773 return nullptr;
1774 }
1775
1776 if (matrix_invert_is_compat(self) == false) {
1777 return nullptr;
1778 }
1779
1781
1783 Py_RETURN_NONE;
1784}
1785
1787 /* Wrap. */
1788 Matrix_inverted_safe_doc,
1789 ".. method:: inverted_safe()\n"
1790 "\n"
1791 " Return an inverted copy of the matrix, will never error.\n"
1792 " If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, "
1793 "to get an invertible one.\n"
1794 " If tweaked matrix is still degenerated, return the identity matrix instead.\n"
1795 "\n"
1796 " :return: the inverted matrix.\n"
1797 " :rtype: :class:`Matrix`\n");
1799{
1800 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
1801
1802 if (BaseMath_ReadCallback(self) == -1) {
1803 return nullptr;
1804 }
1805
1806 if (matrix_invert_is_compat(self) == false) {
1807 return nullptr;
1808 }
1809
1811
1812 return Matrix_copy_notest(self, mat);
1813}
1814
1817/* -------------------------------------------------------------------- */
1822 /* Wrap. */
1823 Matrix_adjugate_doc,
1824 ".. method:: adjugate()\n"
1825 "\n"
1826 " Set the matrix to its adjugate.\n"
1827 "\n"
1828 " :raises ValueError: if the matrix cannot be adjugate.\n"
1829 "\n"
1830 " .. seealso:: `Adjugate matrix <https://en.wikipedia.org/wiki/Adjugate_matrix>`__ on "
1831 "Wikipedia.\n");
1833{
1835 return nullptr;
1836 }
1837
1838 if (self->col_num != self->row_num) {
1839 PyErr_SetString(PyExc_ValueError,
1840 "Matrix.adjugate(d): "
1841 "only square matrices are supported");
1842 return nullptr;
1843 }
1844
1845 /* calculate the classical adjoint */
1846 if (self->col_num <= 4) {
1847 adjoint_matrix_n(self->matrix, self->matrix, self->col_num);
1848 }
1849 else {
1850 PyErr_Format(
1851 PyExc_ValueError, "Matrix adjugate(d): size (%d) unsupported", int(self->col_num));
1852 return nullptr;
1853 }
1854
1856 Py_RETURN_NONE;
1857}
1858
1860 /* Wrap. */
1861 Matrix_adjugated_doc,
1862 ".. method:: adjugated()\n"
1863 "\n"
1864 " Return an adjugated copy of the matrix.\n"
1865 "\n"
1866 " :return: the adjugated matrix.\n"
1867 " :rtype: :class:`Matrix`\n"
1868 " :raises ValueError: if the matrix cannot be adjugated\n");
1870{
1872}
1873
1875 /* Wrap. */
1876 Matrix_rotate_doc,
1877 ".. method:: rotate(other)\n"
1878 "\n"
1879 " Rotates the matrix by another mathutils value.\n"
1880 "\n"
1881 " :arg other: rotation component of mathutils value\n"
1882 " :type other: :class:`Euler` | :class:`Quaternion` | :class:`Matrix`\n"
1883 "\n"
1884 " .. note:: If any of the columns are not unit length this may not have desired results.\n");
1885static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value)
1886{
1887 float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
1888
1890 return nullptr;
1891 }
1892
1893 if (mathutils_any_to_rotmat(other_rmat, value, "matrix.rotate(value)") == -1) {
1894 return nullptr;
1895 }
1896
1897 if (self->row_num != 3 || self->col_num != 3) {
1898 PyErr_SetString(PyExc_ValueError,
1899 "Matrix.rotate(): "
1900 "must have 3x3 dimensions");
1901 return nullptr;
1902 }
1903
1904 matrix_as_3x3(self_rmat, self);
1905 mul_m3_m3m3(rmat, other_rmat, self_rmat);
1906
1907 copy_m3_m3((float(*)[3])(self->matrix), rmat);
1908
1910 Py_RETURN_NONE;
1911}
1912
1915/* -------------------------------------------------------------------- */
1920 /* Wrap. */
1921 Matrix_decompose_doc,
1922 ".. method:: decompose()\n"
1923 "\n"
1924 " Return the translation, rotation, and scale components of this matrix.\n"
1925 "\n"
1926 " :return: Tuple of translation, rotation, and scale.\n"
1927 " :rtype: tuple[:class:`Vector`, :class:`Quaternion`, :class:`Vector`]");
1929{
1930 PyObject *ret;
1931 float loc[3];
1932 float rot[3][3];
1933 float quat[4];
1934 float size[3];
1935
1936 if (self->row_num != 4 || self->col_num != 4) {
1937 PyErr_SetString(PyExc_ValueError,
1938 "Matrix.decompose(): "
1939 "inappropriate matrix size - expects 4x4 matrix");
1940 return nullptr;
1941 }
1942
1943 if (BaseMath_ReadCallback(self) == -1) {
1944 return nullptr;
1945 }
1946
1947 mat4_to_loc_rot_size(loc, rot, size, (const float(*)[4])self->matrix);
1949
1950 ret = PyTuple_New(3);
1952 Vector_CreatePyObject(loc, 3, nullptr),
1953 Quaternion_CreatePyObject(quat, nullptr),
1954 Vector_CreatePyObject(size, 3, nullptr));
1955 return ret;
1956}
1957
1960/* -------------------------------------------------------------------- */
1965 /* Wrap. */
1966 Matrix_lerp_doc,
1967 ".. function:: lerp(other, factor)\n"
1968 "\n"
1969 " Returns the interpolation of two matrices. Uses polar decomposition, see"
1970 " \"Matrix Animation and Polar Decomposition\", Shoemake and Duff, 1992.\n"
1971 "\n"
1972 " :arg other: value to interpolate with.\n"
1973 " :type other: :class:`Matrix`\n"
1974 " :arg factor: The interpolation value in [0.0, 1.0].\n"
1975 " :type factor: float\n"
1976 " :return: The interpolated matrix.\n"
1977 " :rtype: :class:`Matrix`\n");
1978static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
1979{
1980 MatrixObject *mat2 = nullptr;
1981 float fac, mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
1982
1983 if (!PyArg_ParseTuple(args, "O!f:lerp", &matrix_Type, &mat2, &fac)) {
1984 return nullptr;
1985 }
1986
1987 if (self->col_num != mat2->col_num || self->row_num != mat2->row_num) {
1988 PyErr_SetString(PyExc_ValueError,
1989 "Matrix.lerp(): "
1990 "expects both matrix objects of the same dimensions");
1991 return nullptr;
1992 }
1993
1994 if (BaseMath_ReadCallback(self) == -1 || BaseMath_ReadCallback(mat2) == -1) {
1995 return nullptr;
1996 }
1997
1998 /* TODO: different sized matrix. */
1999 if (self->col_num == 4 && self->row_num == 4) {
2000#ifdef MATH_STANDALONE
2001 blend_m4_m4m4((float(*)[4])mat, (float(*)[4])self->matrix, (float(*)[4])mat2->matrix, fac);
2002#else
2003 interp_m4_m4m4((float(*)[4])mat, (float(*)[4])self->matrix, (float(*)[4])mat2->matrix, fac);
2004#endif
2005 }
2006 else if (self->col_num == 3 && self->row_num == 3) {
2007#ifdef MATH_STANDALONE
2008 blend_m3_m3m3((float(*)[3])mat, (float(*)[3])self->matrix, (float(*)[3])mat2->matrix, fac);
2009#else
2010 interp_m3_m3m3((float(*)[3])mat, (float(*)[3])self->matrix, (float(*)[3])mat2->matrix, fac);
2011#endif
2012 }
2013 else {
2014 PyErr_SetString(PyExc_ValueError,
2015 "Matrix.lerp(): "
2016 "only 3x3 and 4x4 matrices supported");
2017 return nullptr;
2018 }
2019
2020 return Matrix_CreatePyObject(mat, self->col_num, self->row_num, Py_TYPE(self));
2021}
2022
2024 /* Wrap. */
2025 Matrix_determinant_doc,
2026 ".. method:: determinant()\n"
2027 "\n"
2028 " Return the determinant of a matrix.\n"
2029 "\n"
2030 " :return: Return the determinant of a matrix.\n"
2031 " :rtype: float\n"
2032 "\n"
2033 " .. seealso:: `Determinant <https://en.wikipedia.org/wiki/Determinant>`__ on Wikipedia.\n");
2035{
2036 if (BaseMath_ReadCallback(self) == -1) {
2037 return nullptr;
2038 }
2039
2040 if (self->col_num != self->row_num) {
2041 PyErr_SetString(PyExc_ValueError,
2042 "Matrix.determinant(): "
2043 "only square matrices are supported");
2044 return nullptr;
2045 }
2046
2047 return PyFloat_FromDouble(double(matrix_determinant_internal(self)));
2048}
2049
2052/* -------------------------------------------------------------------- */
2057 /* Wrap. */
2058 Matrix_transpose_doc,
2059 ".. method:: transpose()\n"
2060 "\n"
2061 " Set the matrix to its transpose.\n"
2062 "\n"
2063 " .. seealso:: `Transpose <https://en.wikipedia.org/wiki/Transpose>`__ on Wikipedia.\n");
2065{
2067 return nullptr;
2068 }
2069
2070 if (self->col_num != self->row_num) {
2071 PyErr_SetString(PyExc_ValueError,
2072 "Matrix.transpose(d): "
2073 "only square matrices are supported");
2074 return nullptr;
2075 }
2076
2077 if (self->col_num == 2) {
2078 const float t = MATRIX_ITEM(self, 1, 0);
2079 MATRIX_ITEM(self, 1, 0) = MATRIX_ITEM(self, 0, 1);
2080 MATRIX_ITEM(self, 0, 1) = t;
2081 }
2082 else if (self->col_num == 3) {
2083 transpose_m3((float(*)[3])self->matrix);
2084 }
2085 else {
2086 transpose_m4((float(*)[4])self->matrix);
2087 }
2088
2090 Py_RETURN_NONE;
2091}
2092
2094 /* Wrap. */
2095 Matrix_transposed_doc,
2096 ".. method:: transposed()\n"
2097 "\n"
2098 " Return a new, transposed matrix.\n"
2099 "\n"
2100 " :return: a transposed matrix\n"
2101 " :rtype: :class:`Matrix`\n");
2106
2109/* -------------------------------------------------------------------- */
2114 /* Wrap. */
2115 Matrix_normalize_doc,
2116 ".. method:: normalize()\n"
2117 "\n"
2118 " Normalize each of the matrix columns.\n"
2119 "\n"
2120 " .. note:: for 4x4 matrices, the 4th column (translation) is left untouched.\n");
2122{
2124 return nullptr;
2125 }
2126
2127 if (self->col_num != self->row_num) {
2128 PyErr_SetString(PyExc_ValueError,
2129 "Matrix.normalize(): "
2130 "only square matrices are supported");
2131 return nullptr;
2132 }
2133
2134 if (self->col_num == 3) {
2135 normalize_m3((float(*)[3])self->matrix);
2136 }
2137 else if (self->col_num == 4) {
2138 normalize_m4((float(*)[4])self->matrix);
2139 }
2140 else {
2141 PyErr_SetString(PyExc_ValueError,
2142 "Matrix.normalize(): "
2143 "can only use a 3x3 or 4x4 matrix");
2144 }
2145
2147 Py_RETURN_NONE;
2148}
2149
2151 /* Wrap. */
2152 Matrix_normalized_doc,
2153 ".. method:: normalized()\n"
2154 "\n"
2155 " Return a column normalized matrix\n"
2156 "\n"
2157 " :return: a column normalized matrix\n"
2158 " :rtype: :class:`Matrix`\n"
2159 "\n"
2160 " .. note:: for 4x4 matrices, the 4th column (translation) is left untouched.\n");
2165
2168/* -------------------------------------------------------------------- */
2173 /* Wrap. */
2174 Matrix_zero_doc,
2175 ".. method:: zero()\n"
2176 "\n"
2177 " Set all the matrix values to zero.\n");
2179{
2180 if (BaseMath_Prepare_ForWrite(self) == -1) {
2181 return nullptr;
2182 }
2183
2184 copy_vn_fl(self->matrix, self->col_num * self->row_num, 0.0f);
2185
2186 if (BaseMath_WriteCallback(self) == -1) {
2187 return nullptr;
2188 }
2189
2190 Py_RETURN_NONE;
2191}
2192
2195/* -------------------------------------------------------------------- */
2200{
2201 BLI_assert((self->col_num == self->row_num) && (self->row_num <= 4));
2202
2203 if (self->col_num == 2) {
2204 unit_m2((float(*)[2])self->matrix);
2205 }
2206 else if (self->col_num == 3) {
2207 unit_m3((float(*)[3])self->matrix);
2208 }
2209 else {
2210 unit_m4((float(*)[4])self->matrix);
2211 }
2212}
2213
2215 /* Wrap. */
2216 Matrix_identity_doc,
2217 ".. method:: identity()\n"
2218 "\n"
2219 " Set the matrix to the identity matrix.\n"
2220 "\n"
2221 " .. note:: An object with a location and rotation of zero, and a scale of one\n"
2222 " will have an identity matrix.\n"
2223 "\n"
2224 " .. seealso:: `Identity matrix <https://en.wikipedia.org/wiki/Identity_matrix>`__ "
2225 "on Wikipedia.\n");
2227{
2229 return nullptr;
2230 }
2231
2232 if (self->col_num != self->row_num) {
2233 PyErr_SetString(PyExc_ValueError,
2234 "Matrix.identity(): "
2235 "only square matrices are supported");
2236 return nullptr;
2237 }
2238
2240
2241 if (BaseMath_WriteCallback(self) == -1) {
2242 return nullptr;
2243 }
2244
2245 Py_RETURN_NONE;
2246}
2247
2250/* -------------------------------------------------------------------- */
2255static PyObject *Matrix_copy_notest(MatrixObject *self, const float *matrix)
2256{
2257 return Matrix_CreatePyObject((const float *)matrix, self->col_num, self->row_num, Py_TYPE(self));
2258}
2259
2261 /* Wrap. */
2262 Matrix_copy_doc,
2263 ".. method:: copy()\n"
2264 "\n"
2265 " Returns a copy of this matrix.\n"
2266 "\n"
2267 " :return: an instance of itself\n"
2268 " :rtype: :class:`Matrix`\n");
2270{
2271 if (BaseMath_ReadCallback(self) == -1) {
2272 return nullptr;
2273 }
2274
2275 return Matrix_copy_notest(self, self->matrix);
2276}
2277
2279static PyObject *Matrix_deepcopy(MatrixObject *self, PyObject *args)
2280{
2281 if (!PyC_CheckArgs_DeepCopy(args)) {
2282 return nullptr;
2283 }
2284 return Matrix_copy(self);
2285}
2286
2289/* -------------------------------------------------------------------- */
2294{
2295 int col, row;
2296 PyObject *rows[MATRIX_MAX_DIM] = {nullptr};
2297
2298 if (BaseMath_ReadCallback(self) == -1) {
2299 return nullptr;
2300 }
2301
2302 for (row = 0; row < self->row_num; row++) {
2303 rows[row] = PyTuple_New(self->col_num);
2304 for (col = 0; col < self->col_num; col++) {
2305 PyTuple_SET_ITEM(rows[row], col, PyFloat_FromDouble(MATRIX_ITEM(self, row, col)));
2306 }
2307 }
2308 switch (self->row_num) {
2309 case 2:
2310 return PyUnicode_FromFormat(
2311 "Matrix((%R,\n"
2312 " %R))",
2313 rows[0],
2314 rows[1]);
2315
2316 case 3:
2317 return PyUnicode_FromFormat(
2318 "Matrix((%R,\n"
2319 " %R,\n"
2320 " %R))",
2321 rows[0],
2322 rows[1],
2323 rows[2]);
2324
2325 case 4:
2326 return PyUnicode_FromFormat(
2327 "Matrix((%R,\n"
2328 " %R,\n"
2329 " %R,\n"
2330 " %R))",
2331 rows[0],
2332 rows[1],
2333 rows[2],
2334 rows[3]);
2335 }
2336
2337 Py_FatalError("Matrix(): invalid row size!");
2338 return nullptr;
2339}
2340
2341#ifndef MATH_STANDALONE
2342static PyObject *Matrix_str(MatrixObject *self)
2343{
2344 DynStr *ds;
2345
2346 int maxsize[MATRIX_MAX_DIM];
2347 int row, col;
2348
2349 char dummy_buf[64];
2350
2351 if (BaseMath_ReadCallback(self) == -1) {
2352 return nullptr;
2353 }
2354
2355 ds = BLI_dynstr_new();
2356
2357 /* First determine the maximum width for each column */
2358 for (col = 0; col < self->col_num; col++) {
2359 maxsize[col] = 0;
2360 for (row = 0; row < self->row_num; row++) {
2361 const int size = SNPRINTF_RLEN(dummy_buf, "%.4f", MATRIX_ITEM(self, row, col));
2362 maxsize[col] = max_ii(maxsize[col], size);
2363 }
2364 }
2365
2366 /* Now write the unicode string to be printed */
2367 BLI_dynstr_appendf(ds, "<Matrix %dx%d (", self->row_num, self->col_num);
2368 for (row = 0; row < self->row_num; row++) {
2369 for (col = 0; col < self->col_num; col++) {
2370 BLI_dynstr_appendf(ds, col ? ", %*.4f" : "%*.4f", maxsize[col], MATRIX_ITEM(self, row, col));
2371 }
2372 BLI_dynstr_append(ds, row + 1 != self->row_num ? ")\n (" : ")");
2373 }
2374 BLI_dynstr_append(ds, ">");
2375
2376 return mathutils_dynstr_to_py(ds); /* frees ds */
2377}
2378#endif
2379
2382/* -------------------------------------------------------------------- */
2386static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
2387{
2388 PyObject *res;
2389 int ok = -1; /* zero is true */
2390
2392 MatrixObject *matA = (MatrixObject *)a;
2393 MatrixObject *matB = (MatrixObject *)b;
2394
2395 if (BaseMath_ReadCallback(matA) == -1 || BaseMath_ReadCallback(matB) == -1) {
2396 return nullptr;
2397 }
2398
2399 ok = ((matA->row_num == matB->row_num) && (matA->col_num == matB->col_num) &&
2400 EXPP_VectorsAreEqual(matA->matrix, matB->matrix, (matA->col_num * matA->row_num), 1)) ?
2401 0 :
2402 -1;
2403 }
2404
2405 switch (op) {
2406 case Py_NE:
2407 ok = !ok;
2409 case Py_EQ:
2410 res = ok ? Py_False : Py_True;
2411 break;
2412
2413 case Py_LT:
2414 case Py_LE:
2415 case Py_GT:
2416 case Py_GE:
2417 res = Py_NotImplemented;
2418 break;
2419 default:
2420 PyErr_BadArgument();
2421 return nullptr;
2422 }
2423
2424 return Py_NewRef(res);
2425}
2426
2429/* -------------------------------------------------------------------- */
2434{
2435 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2436
2437 if (BaseMath_ReadCallback(self) == -1) {
2438 return -1;
2439 }
2440
2442 return -1;
2443 }
2444
2446
2447 return mathutils_array_hash(mat, self->row_num * self->col_num);
2448}
2449
2452/* -------------------------------------------------------------------- */
2457static Py_ssize_t Matrix_len(MatrixObject *self)
2458{
2459 return self->row_num;
2460}
2461
2466static PyObject *Matrix_item_row(MatrixObject *self, Py_ssize_t row)
2467{
2469 return nullptr;
2470 }
2471
2472 if (row < 0 || row >= self->row_num) {
2473 PyErr_SetString(PyExc_IndexError,
2474 "matrix[attribute]: "
2475 "array index out of range");
2476 return nullptr;
2477 }
2479 (PyObject *)self, self->col_num, mathutils_matrix_row_cb_index, row);
2480}
2485static PyObject *Matrix_item_col(MatrixObject *self, Py_ssize_t col)
2486{
2488 return nullptr;
2489 }
2490
2491 if (col < 0 || col >= self->col_num) {
2492 PyErr_SetString(PyExc_IndexError,
2493 "matrix[attribute]: "
2494 "array index out of range");
2495 return nullptr;
2496 }
2498 (PyObject *)self, self->row_num, mathutils_matrix_col_cb_index, col);
2499}
2500
2502static int Matrix_ass_item_row(MatrixObject *self, Py_ssize_t row, PyObject *value)
2503{
2504 int col;
2505 float vec[MATRIX_MAX_DIM];
2507 return -1;
2508 }
2509
2510 if (row >= self->row_num || row < 0) {
2511 PyErr_SetString(PyExc_IndexError, "matrix[attribute] = x: bad row");
2512 return -1;
2513 }
2514
2516 vec, self->col_num, self->col_num, value, "matrix[i] = value assignment") == -1)
2517 {
2518 return -1;
2519 }
2520
2521 /* Since we are assigning a row we cannot memcpy */
2522 for (col = 0; col < self->col_num; col++) {
2523 MATRIX_ITEM(self, row, col) = vec[col];
2524 }
2525
2527 return 0;
2528}
2529
2531static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value)
2532{
2533 int row;
2534 float vec[MATRIX_MAX_DIM];
2536 return -1;
2537 }
2538
2539 if (col >= self->col_num || col < 0) {
2540 PyErr_SetString(PyExc_IndexError, "matrix[attribute] = x: bad col");
2541 return -1;
2542 }
2543
2545 vec, self->row_num, self->row_num, value, "matrix[i] = value assignment") == -1)
2546 {
2547 return -1;
2548 }
2549
2550 /* Since we are assigning a row we cannot memcpy */
2551 for (row = 0; row < self->row_num; row++) {
2552 MATRIX_ITEM(self, row, col) = vec[row];
2553 }
2554
2556 return 0;
2557}
2558
2560static PyObject *Matrix_slice(MatrixObject *self, int begin, int end)
2561{
2562
2563 PyObject *tuple;
2564 int count;
2565
2566 if (BaseMath_ReadCallback(self) == -1) {
2567 return nullptr;
2568 }
2569
2570 CLAMP(begin, 0, self->row_num);
2571 CLAMP(end, 0, self->row_num);
2572 begin = std::min(begin, end);
2573
2574 tuple = PyTuple_New(end - begin);
2575 for (count = begin; count < end; count++) {
2576 PyTuple_SET_ITEM(tuple,
2577 count - begin,
2579 (PyObject *)self, self->col_num, mathutils_matrix_row_cb_index, count));
2580 }
2581
2582 return tuple;
2583}
2584
2586static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value)
2587{
2588 PyObject *value_fast;
2589
2591 return -1;
2592 }
2593
2594 CLAMP(begin, 0, self->row_num);
2595 CLAMP(end, 0, self->row_num);
2596 begin = std::min(begin, end);
2597
2598 /* non list/tuple cases */
2599 if (!(value_fast = PySequence_Fast(value, "matrix[begin:end] = value"))) {
2600 /* PySequence_Fast sets the error */
2601 return -1;
2602 }
2603
2604 PyObject **value_fast_items = PySequence_Fast_ITEMS(value_fast);
2605 const int size = end - begin;
2606 int row, col;
2607 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2608 float vec[4];
2609
2610 if (PySequence_Fast_GET_SIZE(value_fast) != size) {
2611 Py_DECREF(value_fast);
2612 PyErr_SetString(PyExc_ValueError,
2613 "matrix[begin:end] = []: "
2614 "size mismatch in slice assignment");
2615 return -1;
2616 }
2617
2618 memcpy(mat, self->matrix, self->col_num * self->row_num * sizeof(float));
2619
2620 /* parse sub items */
2621 for (row = begin; row < end; row++) {
2622 /* parse each sub sequence */
2623 PyObject *item = value_fast_items[row - begin];
2624
2626 vec, self->col_num, self->col_num, item, "matrix[begin:end] = value assignment") == -1)
2627 {
2628 Py_DECREF(value_fast);
2629 return -1;
2630 }
2631
2632 for (col = 0; col < self->col_num; col++) {
2633 mat[col * self->row_num + row] = vec[col];
2634 }
2635 }
2636
2637 Py_DECREF(value_fast);
2638
2639 /* Parsed well - now set in matrix. */
2640 memcpy(self->matrix, mat, self->col_num * self->row_num * sizeof(float));
2641
2643 return 0;
2644}
2645
2647static PyObject *Matrix_subscript(MatrixObject *self, PyObject *item)
2648{
2649 if (PyIndex_Check(item)) {
2650 Py_ssize_t i;
2651 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2652 if (i == -1 && PyErr_Occurred()) {
2653 return nullptr;
2654 }
2655 if (i < 0) {
2656 i += self->row_num;
2657 }
2658 return Matrix_item_row(self, i);
2659 }
2660 if (PySlice_Check(item)) {
2661 Py_ssize_t start, stop, step, slicelength;
2662
2663 if (PySlice_GetIndicesEx(item, self->row_num, &start, &stop, &step, &slicelength) < 0) {
2664 return nullptr;
2665 }
2666
2667 if (slicelength <= 0) {
2668 return PyTuple_New(0);
2669 }
2670 if (step == 1) {
2671 return Matrix_slice(self, start, stop);
2672 }
2673
2674 PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrices");
2675 return nullptr;
2676 }
2677
2678 PyErr_Format(
2679 PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
2680 return nullptr;
2681}
2682
2684static int Matrix_ass_subscript(MatrixObject *self, PyObject *item, PyObject *value)
2685{
2686 if (PyIndex_Check(item)) {
2687 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2688 if (i == -1 && PyErr_Occurred()) {
2689 return -1;
2690 }
2691 if (i < 0) {
2692 i += self->row_num;
2693 }
2694 return Matrix_ass_item_row(self, i, value);
2695 }
2696 if (PySlice_Check(item)) {
2697 Py_ssize_t start, stop, step, slicelength;
2698
2699 if (PySlice_GetIndicesEx(item, self->row_num, &start, &stop, &step, &slicelength) < 0) {
2700 return -1;
2701 }
2702
2703 if (step == 1) {
2704 return Matrix_ass_slice(self, start, stop, value);
2705 }
2706
2707 PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrices");
2708 return -1;
2709 }
2710
2711 PyErr_Format(
2712 PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
2713 return -1;
2714}
2715
2718/* -------------------------------------------------------------------- */
2723static PyObject *Matrix_add(PyObject *m1, PyObject *m2)
2724{
2725 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2726 MatrixObject *mat1 = nullptr, *mat2 = nullptr;
2727
2728 mat1 = (MatrixObject *)m1;
2729 mat2 = (MatrixObject *)m2;
2730
2731 if (!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
2732 PyErr_Format(PyExc_TypeError,
2733 "Matrix addition: (%s + %s) "
2734 "invalid type for this operation",
2735 Py_TYPE(m1)->tp_name,
2736 Py_TYPE(m2)->tp_name);
2737 return nullptr;
2738 }
2739
2740 if (BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1) {
2741 return nullptr;
2742 }
2743
2744 if (mat1->col_num != mat2->col_num || mat1->row_num != mat2->row_num) {
2745 PyErr_SetString(PyExc_ValueError,
2746 "Matrix addition: "
2747 "matrices must have the same dimensions for this operation");
2748 return nullptr;
2749 }
2750
2751 add_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->col_num * mat1->row_num);
2752
2753 return Matrix_CreatePyObject(mat, mat1->col_num, mat1->row_num, Py_TYPE(mat1));
2754}
2755
2757static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
2758{
2759 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2760 MatrixObject *mat1 = nullptr, *mat2 = nullptr;
2761
2762 mat1 = (MatrixObject *)m1;
2763 mat2 = (MatrixObject *)m2;
2764
2765 if (!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
2766 PyErr_Format(PyExc_TypeError,
2767 "Matrix subtraction: (%s - %s) "
2768 "invalid type for this operation",
2769 Py_TYPE(m1)->tp_name,
2770 Py_TYPE(m2)->tp_name);
2771 return nullptr;
2772 }
2773
2774 if (BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1) {
2775 return nullptr;
2776 }
2777
2778 if (mat1->col_num != mat2->col_num || mat1->row_num != mat2->row_num) {
2779 PyErr_SetString(PyExc_ValueError,
2780 "Matrix addition: "
2781 "matrices must have the same dimensions for this operation");
2782 return nullptr;
2783 }
2784
2785 sub_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->col_num * mat1->row_num);
2786
2787 return Matrix_CreatePyObject(mat, mat1->col_num, mat1->row_num, Py_TYPE(mat1));
2788}
2789
2791static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
2792{
2793 float tmat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2794 mul_vn_vn_fl(tmat, mat->matrix, mat->col_num * mat->row_num, scalar);
2795 return Matrix_CreatePyObject(tmat, mat->col_num, mat->row_num, Py_TYPE(mat));
2796}
2797
2798static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
2799{
2800 float scalar;
2801
2802 MatrixObject *mat1 = nullptr, *mat2 = nullptr;
2803
2804 if (MatrixObject_Check(m1)) {
2805 mat1 = (MatrixObject *)m1;
2806 if (BaseMath_ReadCallback(mat1) == -1) {
2807 return nullptr;
2808 }
2809 }
2810 if (MatrixObject_Check(m2)) {
2811 mat2 = (MatrixObject *)m2;
2812 if (BaseMath_ReadCallback(mat2) == -1) {
2813 return nullptr;
2814 }
2815 }
2816
2817 if (mat1 && mat2) {
2818 /* MATRIX * MATRIX */
2819 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2820
2821 if ((mat1->row_num != mat2->row_num) || (mat1->col_num != mat2->col_num)) {
2822 PyErr_SetString(PyExc_ValueError,
2823 "matrix1 * matrix2: matrix1 number of rows/columns "
2824 "and the matrix2 number of rows/columns must be the same");
2825 return nullptr;
2826 }
2827
2828 mul_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->col_num * mat1->row_num);
2829
2830 return Matrix_CreatePyObject(mat, mat2->col_num, mat1->row_num, Py_TYPE(mat1));
2831 }
2832 if (mat2) {
2833 /* FLOAT/INT * MATRIX */
2834 if (((scalar = PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred()) == 0) {
2835 return matrix_mul_float(mat2, scalar);
2836 }
2837 }
2838 else if (mat1) {
2839 /* MATRIX * FLOAT/INT */
2840 if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) {
2841 return matrix_mul_float(mat1, scalar);
2842 }
2843 }
2844
2845 PyErr_Format(PyExc_TypeError,
2846 "Element-wise multiplication: "
2847 "not supported between '%.200s' and '%.200s' types",
2848 Py_TYPE(m1)->tp_name,
2849 Py_TYPE(m2)->tp_name);
2850 return nullptr;
2851}
2852
2854static PyObject *Matrix_imul(PyObject *m1, PyObject *m2)
2855{
2856 float scalar;
2857
2858 MatrixObject *mat1 = nullptr, *mat2 = nullptr;
2859
2860 if (MatrixObject_Check(m1)) {
2861 mat1 = (MatrixObject *)m1;
2862 if (BaseMath_ReadCallback(mat1) == -1) {
2863 return nullptr;
2864 }
2865 }
2866 if (MatrixObject_Check(m2)) {
2867 mat2 = (MatrixObject *)m2;
2868 if (BaseMath_ReadCallback(mat2) == -1) {
2869 return nullptr;
2870 }
2871 }
2872
2873 if (mat1 && mat2) {
2874 /* MATRIX *= MATRIX */
2875 if ((mat1->row_num != mat2->row_num) || (mat1->col_num != mat2->col_num)) {
2876 PyErr_SetString(PyExc_ValueError,
2877 "matrix1 *= matrix2: matrix1 number of rows/columns "
2878 "and the matrix2 number of rows/columns must be the same");
2879 return nullptr;
2880 }
2881
2882 mul_vn_vn(mat1->matrix, mat2->matrix, mat1->col_num * mat1->row_num);
2883 }
2884 else if (mat1 && (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0)) {
2885 /* MATRIX *= FLOAT/INT */
2886 mul_vn_fl(mat1->matrix, mat1->row_num * mat1->col_num, scalar);
2887 }
2888 else {
2889 PyErr_Format(PyExc_TypeError,
2890 "In place element-wise multiplication: "
2891 "not supported between '%.200s' and '%.200s' types",
2892 Py_TYPE(m1)->tp_name,
2893 Py_TYPE(m2)->tp_name);
2894 return nullptr;
2895 }
2896
2897 (void)BaseMath_WriteCallback(mat1);
2898 Py_INCREF(m1);
2899 return m1;
2900}
2901
2903static PyObject *Matrix_matmul(PyObject *m1, PyObject *m2)
2904{
2905 int vec_num;
2906
2907 MatrixObject *mat1 = nullptr, *mat2 = nullptr;
2908
2909 if (MatrixObject_Check(m1)) {
2910 mat1 = (MatrixObject *)m1;
2911 if (BaseMath_ReadCallback(mat1) == -1) {
2912 return nullptr;
2913 }
2914 }
2915 if (MatrixObject_Check(m2)) {
2916 mat2 = (MatrixObject *)m2;
2917 if (BaseMath_ReadCallback(mat2) == -1) {
2918 return nullptr;
2919 }
2920 }
2921
2922 if (mat1 && mat2) {
2923 /* MATRIX @ MATRIX */
2924 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2925
2926 int col, row, item;
2927
2928 if (mat1->col_num != mat2->row_num) {
2929 PyErr_SetString(PyExc_ValueError,
2930 "matrix1 * matrix2: matrix1 number of columns "
2931 "and the matrix2 number of rows must be the same");
2932 return nullptr;
2933 }
2934
2935 for (col = 0; col < mat2->col_num; col++) {
2936 for (row = 0; row < mat1->row_num; row++) {
2937 double dot = 0.0f;
2938 for (item = 0; item < mat1->col_num; item++) {
2939 dot += double(MATRIX_ITEM(mat1, row, item) * MATRIX_ITEM(mat2, item, col));
2940 }
2941 mat[(col * mat1->row_num) + row] = float(dot);
2942 }
2943 }
2944
2945 return Matrix_CreatePyObject(mat, mat2->col_num, mat1->row_num, Py_TYPE(mat1));
2946 }
2947 if (mat1) {
2948 /* MATRIX @ VECTOR */
2949 if (VectorObject_Check(m2)) {
2950 VectorObject *vec2 = (VectorObject *)m2;
2951 float tvec[MATRIX_MAX_DIM];
2952 if (BaseMath_ReadCallback(vec2) == -1) {
2953 return nullptr;
2954 }
2955 if (column_vector_multiplication(tvec, vec2, mat1) == -1) {
2956 return nullptr;
2957 }
2958
2959 if (mat1->col_num == 4 && vec2->vec_num == 3) {
2960 vec_num = 3;
2961 }
2962 else {
2963 vec_num = mat1->row_num;
2964 }
2965
2966 return Vector_CreatePyObject(tvec, vec_num, Py_TYPE(m2));
2967 }
2968 }
2969
2970 PyErr_Format(PyExc_TypeError,
2971 "Matrix multiplication: "
2972 "not supported between '%.200s' and '%.200s' types",
2973 Py_TYPE(m1)->tp_name,
2974 Py_TYPE(m2)->tp_name);
2975 return nullptr;
2976}
2977
2979static PyObject *Matrix_imatmul(PyObject *m1, PyObject *m2)
2980{
2981 MatrixObject *mat1 = nullptr, *mat2 = nullptr;
2982
2983 if (MatrixObject_Check(m1)) {
2984 mat1 = (MatrixObject *)m1;
2985 if (BaseMath_ReadCallback(mat1) == -1) {
2986 return nullptr;
2987 }
2988 }
2989 if (MatrixObject_Check(m2)) {
2990 mat2 = (MatrixObject *)m2;
2991 if (BaseMath_ReadCallback(mat2) == -1) {
2992 return nullptr;
2993 }
2994 }
2995
2996 if (mat1 && mat2) {
2997 /* MATRIX @= MATRIX */
2998 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2999 int col, row, item;
3000
3001 if (mat1->col_num != mat2->row_num) {
3002 PyErr_SetString(PyExc_ValueError,
3003 "matrix1 * matrix2: matrix1 number of columns "
3004 "and the matrix2 number of rows must be the same");
3005 return nullptr;
3006 }
3007
3008 for (col = 0; col < mat2->col_num; col++) {
3009 for (row = 0; row < mat1->row_num; row++) {
3010 double dot = 0.0f;
3011 for (item = 0; item < mat1->col_num; item++) {
3012 dot += double(MATRIX_ITEM(mat1, row, item) * MATRIX_ITEM(mat2, item, col));
3013 }
3014 /* store in new matrix as overwriting original at this point will cause
3015 * subsequent iterations to use incorrect values */
3016 mat[(col * mat1->row_num) + row] = float(dot);
3017 }
3018 }
3019
3020 /* copy matrix back */
3021 memcpy(mat1->matrix, mat, (mat1->row_num * mat1->col_num) * sizeof(float));
3022 }
3023 else {
3024 PyErr_Format(PyExc_TypeError,
3025 "In place matrix multiplication: "
3026 "not supported between '%.200s' and '%.200s' types",
3027 Py_TYPE(m1)->tp_name,
3028 Py_TYPE(m2)->tp_name);
3029 return nullptr;
3030 }
3031
3032 (void)BaseMath_WriteCallback(mat1);
3033 Py_INCREF(m1);
3034 return m1;
3035}
3036
3039/* -------------------------------------------------------------------- */
3043static PySequenceMethods Matrix_SeqMethods = {
3044 /*sq_length*/ (lenfunc)Matrix_len,
3045 /*sq_concat*/ nullptr,
3046 /*sq_repeat*/ nullptr,
3047 /*sq_item*/ (ssizeargfunc)Matrix_item_row,
3048 /*was_sq_slice*/ nullptr, /* DEPRECATED. */
3049 /*sq_ass_item*/ (ssizeobjargproc)Matrix_ass_item_row,
3050 /*was_sq_ass_slice*/ nullptr, /* DEPRECATED. */
3051 /*sq_contains*/ nullptr,
3052 /*sq_inplace_concat*/ nullptr,
3053 /*sq_inplace_repeat*/ nullptr,
3054};
3055
3056static PyMappingMethods Matrix_AsMapping = {
3057 /*mp_length*/ (lenfunc)Matrix_len,
3058 /*mp_subscript*/ (binaryfunc)Matrix_subscript,
3059 /*mp_ass_subscript*/ (objobjargproc)Matrix_ass_subscript,
3060};
3061
3062static PyNumberMethods Matrix_NumMethods = {
3063 /*nb_add*/ (binaryfunc)Matrix_add,
3064 /*nb_subtract*/ (binaryfunc)Matrix_sub,
3065 /*nb_multiply*/ (binaryfunc)Matrix_mul,
3066 /*nb_remainder*/ nullptr,
3067 /*nb_divmod*/ nullptr,
3068 /*nb_power*/ nullptr,
3069 /*nb_negative*/ nullptr,
3070 /*nb_positive*/ nullptr,
3071 /*nb_absolute*/ nullptr,
3072 /*nb_bool*/ nullptr,
3073 /*nb_invert*/ (unaryfunc)Matrix_inverted_noargs,
3074 /*nb_lshift*/ nullptr,
3075 /*nb_rshift*/ nullptr,
3076 /*nb_and*/ nullptr,
3077 /*nb_xor*/ nullptr,
3078 /*nb_or*/ nullptr,
3079 /*nb_int*/ nullptr,
3080 /*nb_reserved*/ nullptr,
3081 /*nb_float*/ nullptr,
3082 /*nb_inplace_add*/ nullptr,
3083 /*nb_inplace_subtract*/ nullptr,
3084 /*nb_inplace_multiply*/ (binaryfunc)Matrix_imul,
3085 /*nb_inplace_remainder*/ nullptr,
3086 /*nb_inplace_power*/ nullptr,
3087 /*nb_inplace_lshift*/ nullptr,
3088 /*nb_inplace_rshift*/ nullptr,
3089 /*nb_inplace_and*/ nullptr,
3090 /*nb_inplace_xor*/ nullptr,
3091 /*nb_inplace_or*/ nullptr,
3092 /*nb_floor_divide*/ nullptr,
3093 /*nb_true_divide*/ nullptr,
3094 /*nb_inplace_floor_divide*/ nullptr,
3095 /*nb_inplace_true_divide*/ nullptr,
3096 /*nb_index*/ nullptr,
3097 /*nb_matrix_multiply*/ (binaryfunc)Matrix_matmul,
3098 /*nb_inplace_matrix_multiply*/ (binaryfunc)Matrix_imatmul,
3099};
3100
3103/* -------------------------------------------------------------------- */
3108 /* Wrap. */
3109 Matrix_translation_doc,
3110 "The translation component of the matrix.\n"
3111 "\n"
3112 ":type: :class:`Vector`");
3113static PyObject *Matrix_translation_get(MatrixObject *self, void * /*closure*/)
3114{
3115 PyObject *ret;
3116
3117 if (BaseMath_ReadCallback(self) == -1) {
3118 return nullptr;
3119 }
3120
3121 /* Must be 4x4 square matrix. */
3122 if (self->row_num != 4 || self->col_num != 4) {
3123 PyErr_SetString(PyExc_AttributeError,
3124 "Matrix.translation: "
3125 "inappropriate matrix size, must be 4x4");
3126 return nullptr;
3127 }
3128
3129 ret = (PyObject *)Vector_CreatePyObject_cb(
3130 (PyObject *)self, 3, mathutils_matrix_translation_cb_index, 3);
3131
3132 return ret;
3133}
3134
3135static int Matrix_translation_set(MatrixObject *self, PyObject *value, void * /*closure*/)
3136{
3137 float tvec[3];
3138
3140 return -1;
3141 }
3142
3143 /* Must be 4x4 square matrix. */
3144 if (self->row_num != 4 || self->col_num != 4) {
3145 PyErr_SetString(PyExc_AttributeError,
3146 "Matrix.translation: "
3147 "inappropriate matrix size, must be 4x4");
3148 return -1;
3149 }
3150
3151 if (mathutils_array_parse(tvec, 3, 3, value, "Matrix.translation") == -1) {
3152 return -1;
3153 }
3154
3155 copy_v3_v3(((float(*)[4])self->matrix)[3], tvec);
3156
3158
3159 return 0;
3160}
3161
3163 /* Wrap. */
3164 Matrix_row_doc,
3165 "Access the matrix by rows (default), (read-only).\n"
3166 "\n"
3167 ":type: Matrix Access");
3168static PyObject *Matrix_row_get(MatrixObject *self, void * /*closure*/)
3169{
3171}
3172
3173PyDoc_STRVAR(Matrix_col_doc,
3174 "Access the matrix by columns, 3x3 and 4x4 only, (read-only).\n"
3175 "\n"
3176 ":type: Matrix Access");
3177static PyObject *Matrix_col_get(MatrixObject *self, void * /*closure*/)
3178{
3180}
3181
3183 /* Wrap. */
3184 Matrix_median_scale_doc,
3185 "The average scale applied to each axis (read-only).\n"
3186 "\n"
3187 ":type: float");
3188static PyObject *Matrix_median_scale_get(MatrixObject *self, void * /*closure*/)
3189{
3190 float mat[3][3];
3191
3192 if (BaseMath_ReadCallback(self) == -1) {
3193 return nullptr;
3194 }
3195
3196 /* Must be 3-4 cols, 3-4 rows, square matrix. */
3197 if ((self->row_num < 3) || (self->col_num < 3)) {
3198 PyErr_SetString(PyExc_AttributeError,
3199 "Matrix.median_scale: "
3200 "inappropriate matrix size, 3x3 minimum");
3201 return nullptr;
3202 }
3203
3204 matrix_as_3x3(mat, self);
3205
3206 return PyFloat_FromDouble(mat3_to_scale(mat));
3207}
3208
3210 /* Wrap. */
3211 Matrix_is_identity_doc,
3212 "True if this is an identity matrix (read-only).\n"
3213 "\n"
3214 ":type: bool");
3215static PyObject *Matrix_is_identity_get(MatrixObject *self, void * /*closure*/)
3216{
3217 if (BaseMath_ReadCallback(self) == -1) {
3218 return nullptr;
3219 }
3220 return PyBool_FromLong(matrix_is_identity(self));
3221}
3222
3224 /* Wrap. */
3225 Matrix_is_negative_doc,
3226 "True if this matrix results in a negative scale, 3x3 and 4x4 only, "
3227 "(read-only).\n"
3228 "\n"
3229 ":type: bool");
3230static PyObject *Matrix_is_negative_get(MatrixObject *self, void * /*closure*/)
3231{
3232 if (BaseMath_ReadCallback(self) == -1) {
3233 return nullptr;
3234 }
3235
3236 /* Must be 3-4 cols, 3-4 rows, square matrix. */
3237 if (self->row_num == 4 && self->col_num == 4) {
3238 return PyBool_FromLong(is_negative_m4((const float(*)[4])self->matrix));
3239 }
3240 if (self->row_num == 3 && self->col_num == 3) {
3241 return PyBool_FromLong(is_negative_m3((const float(*)[3])self->matrix));
3242 }
3243
3244 PyErr_SetString(PyExc_AttributeError,
3245 "Matrix.is_negative: "
3246 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
3247 return nullptr;
3248}
3249
3251 /* Wrap. */
3252 Matrix_is_orthogonal_doc,
3253 "True if this matrix is orthogonal, 3x3 and 4x4 only, (read-only).\n"
3254 "\n"
3255 ":type: bool");
3256static PyObject *Matrix_is_orthogonal_get(MatrixObject *self, void * /*closure*/)
3257{
3258 if (BaseMath_ReadCallback(self) == -1) {
3259 return nullptr;
3260 }
3261
3262 /* Must be 3-4 cols, 3-4 rows, square matrix. */
3263 if (self->row_num == 4 && self->col_num == 4) {
3264 return PyBool_FromLong(is_orthonormal_m4((const float(*)[4])self->matrix));
3265 }
3266 if (self->row_num == 3 && self->col_num == 3) {
3267 return PyBool_FromLong(is_orthonormal_m3((const float(*)[3])self->matrix));
3268 }
3269
3270 PyErr_SetString(PyExc_AttributeError,
3271 "Matrix.is_orthogonal: "
3272 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
3273 return nullptr;
3274}
3275
3277 /* Wrap. */
3278 Matrix_is_orthogonal_axis_vectors_doc,
3279 "True if this matrix has got orthogonal axis vectors, 3x3 and 4x4 only, "
3280 "(read-only).\n"
3281 "\n"
3282 ":type: bool");
3283static PyObject *Matrix_is_orthogonal_axis_vectors_get(MatrixObject *self, void * /*closure*/)
3284{
3285 if (BaseMath_ReadCallback(self) == -1) {
3286 return nullptr;
3287 }
3288
3289 /* Must be 3-4 cols, 3-4 rows, square matrix. */
3290 if (self->row_num == 4 && self->col_num == 4) {
3291 return PyBool_FromLong(is_orthogonal_m4((const float(*)[4])self->matrix));
3292 }
3293 if (self->row_num == 3 && self->col_num == 3) {
3294 return PyBool_FromLong(is_orthogonal_m3((const float(*)[3])self->matrix));
3295 }
3296
3297 PyErr_SetString(PyExc_AttributeError,
3298 "Matrix.is_orthogonal_axis_vectors: "
3299 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
3300 return nullptr;
3301}
3302
3305/* -------------------------------------------------------------------- */
3309static PyGetSetDef Matrix_getseters[] = {
3310 {"median_scale",
3312 (setter) nullptr,
3313 Matrix_median_scale_doc,
3314 nullptr},
3315 {"translation",
3316 (getter)Matrix_translation_get,
3317 (setter)Matrix_translation_set,
3318 Matrix_translation_doc,
3319 nullptr},
3320 {"row", (getter)Matrix_row_get, (setter) nullptr, Matrix_row_doc, nullptr},
3321 {"col", (getter)Matrix_col_get, (setter) nullptr, Matrix_col_doc, nullptr},
3322 {"is_identity",
3323 (getter)Matrix_is_identity_get,
3324 (setter) nullptr,
3325 Matrix_is_identity_doc,
3326 nullptr},
3327 {"is_negative",
3328 (getter)Matrix_is_negative_get,
3329 (setter) nullptr,
3330 Matrix_is_negative_doc,
3331 nullptr},
3332 {"is_orthogonal",
3334 (setter) nullptr,
3335 Matrix_is_orthogonal_doc,
3336 nullptr},
3337 {"is_orthogonal_axis_vectors",
3339 (setter) nullptr,
3340 Matrix_is_orthogonal_axis_vectors_doc,
3341 nullptr},
3342 {"is_wrapped",
3344 (setter) nullptr,
3346 nullptr},
3347 {"is_frozen",
3349 (setter) nullptr,
3351 nullptr},
3352 {"is_valid",
3354 (setter) nullptr,
3356 nullptr},
3357 {"owner",
3359 (setter) nullptr,
3361 nullptr},
3362 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
3363};
3364
3367/* -------------------------------------------------------------------- */
3371#if (defined(__GNUC__) && !defined(__clang__))
3372# pragma GCC diagnostic push
3373# pragma GCC diagnostic ignored "-Wcast-function-type"
3374#endif
3375
3376static PyMethodDef Matrix_methods[] = {
3377 /* Derived values. */
3378 {"determinant", (PyCFunction)Matrix_determinant, METH_NOARGS, Matrix_determinant_doc},
3379 {"decompose", (PyCFunction)Matrix_decompose, METH_NOARGS, Matrix_decompose_doc},
3380
3381 /* In place only. */
3382 {"zero", (PyCFunction)Matrix_zero, METH_NOARGS, Matrix_zero_doc},
3383 {"identity", (PyCFunction)Matrix_identity, METH_NOARGS, Matrix_identity_doc},
3384
3385 /* Operate on original or copy. */
3386 {"transpose", (PyCFunction)Matrix_transpose, METH_NOARGS, Matrix_transpose_doc},
3387 {"transposed", (PyCFunction)Matrix_transposed, METH_NOARGS, Matrix_transposed_doc},
3388 {"normalize", (PyCFunction)Matrix_normalize, METH_NOARGS, Matrix_normalize_doc},
3389 {"normalized", (PyCFunction)Matrix_normalized, METH_NOARGS, Matrix_normalized_doc},
3390 {"invert", (PyCFunction)Matrix_invert, METH_VARARGS, Matrix_invert_doc},
3391 {"inverted", (PyCFunction)Matrix_inverted, METH_VARARGS, Matrix_inverted_doc},
3392 {"invert_safe", (PyCFunction)Matrix_invert_safe, METH_NOARGS, Matrix_invert_safe_doc},
3393 {"inverted_safe", (PyCFunction)Matrix_inverted_safe, METH_NOARGS, Matrix_inverted_safe_doc},
3394 {"adjugate", (PyCFunction)Matrix_adjugate, METH_NOARGS, Matrix_adjugate_doc},
3395 {"adjugated", (PyCFunction)Matrix_adjugated, METH_NOARGS, Matrix_adjugated_doc},
3396 {"to_2x2", (PyCFunction)Matrix_to_2x2, METH_NOARGS, Matrix_to_2x2_doc},
3397 {"to_3x3", (PyCFunction)Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc},
3398 {"to_4x4", (PyCFunction)Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc},
3399 /* TODO: {"resize_3x3", (PyCFunction) Matrix_resize3x3, METH_NOARGS, Matrix_resize3x3_doc}, */
3400 {"resize_4x4", (PyCFunction)Matrix_resize_4x4, METH_NOARGS, Matrix_resize_4x4_doc},
3401 {"rotate", (PyCFunction)Matrix_rotate, METH_O, Matrix_rotate_doc},
3402
3403 /* Return converted representation. */
3404 {"to_euler", (PyCFunction)Matrix_to_euler, METH_VARARGS, Matrix_to_euler_doc},
3405 {"to_quaternion", (PyCFunction)Matrix_to_quaternion, METH_NOARGS, Matrix_to_quaternion_doc},
3406 {"to_scale", (PyCFunction)Matrix_to_scale, METH_NOARGS, Matrix_to_scale_doc},
3407 {"to_translation", (PyCFunction)Matrix_to_translation, METH_NOARGS, Matrix_to_translation_doc},
3408
3409 /* Operation between 2 or more types. */
3410 {"lerp", (PyCFunction)Matrix_lerp, METH_VARARGS, Matrix_lerp_doc},
3411 {"copy", (PyCFunction)Matrix_copy, METH_NOARGS, Matrix_copy_doc},
3412 {"__copy__", (PyCFunction)Matrix_copy, METH_NOARGS, Matrix_copy_doc},
3413 {"__deepcopy__", (PyCFunction)Matrix_deepcopy, METH_VARARGS, Matrix_copy_doc},
3414
3415 /* Base-math methods. */
3416 {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
3417
3418 /* Class methods. */
3419 {"Identity", (PyCFunction)C_Matrix_Identity, METH_VARARGS | METH_CLASS, C_Matrix_Identity_doc},
3420 {"Rotation", (PyCFunction)C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc},
3421 {"Scale", (PyCFunction)C_Matrix_Scale, METH_VARARGS | METH_CLASS, C_Matrix_Scale_doc},
3422 {"Shear", (PyCFunction)C_Matrix_Shear, METH_VARARGS | METH_CLASS, C_Matrix_Shear_doc},
3423 {"Diagonal", (PyCFunction)C_Matrix_Diagonal, METH_O | METH_CLASS, C_Matrix_Diagonal_doc},
3424 {"Translation",
3425 (PyCFunction)C_Matrix_Translation,
3426 METH_O | METH_CLASS,
3427 C_Matrix_Translation_doc},
3428 {"OrthoProjection",
3429 (PyCFunction)C_Matrix_OrthoProjection,
3430 METH_VARARGS | METH_CLASS,
3431 C_Matrix_OrthoProjection_doc},
3432 {"LocRotScale",
3433 (PyCFunction)C_Matrix_LocRotScale,
3434 METH_VARARGS | METH_CLASS,
3435 C_Matrix_LocRotScale_doc},
3436 {nullptr, nullptr, 0, nullptr},
3437};
3438
3439#if (defined(__GNUC__) && !defined(__clang__))
3440# pragma GCC diagnostic pop
3441#endif
3442
3445/* -------------------------------------------------------------------- */
3449#ifdef MATH_STANDALONE
3450# define Matrix_str nullptr
3451#endif
3452
3454 /* Wrap. */
3455 matrix_doc,
3456 ".. class:: Matrix([rows])\n"
3457 "\n"
3458 " This object gives access to Matrices in Blender, supporting square and rectangular\n"
3459 " matrices from 2x2 up to 4x4.\n"
3460 "\n"
3461 " :arg rows: Sequence of rows. When omitted, a 4x4 identity matrix is constructed.\n"
3462 " :type rows: Sequence[Sequence[float]]\n");
3463PyTypeObject matrix_Type = {
3464 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
3465 /*tp_name*/ "Matrix",
3466 /*tp_basicsize*/ sizeof(MatrixObject),
3467 /*tp_itemsize*/ 0,
3468 /*tp_dealloc*/ (destructor)BaseMathObject_dealloc,
3469 /*tp_vectorcall_offset*/ 0,
3470 /*tp_getattr*/ nullptr,
3471 /*tp_setattr*/ nullptr,
3472 /*tp_as_async*/ nullptr,
3473 /*tp_repr*/ (reprfunc)Matrix_repr,
3474 /*tp_as_number*/ &Matrix_NumMethods,
3475 /*tp_as_sequence*/ &Matrix_SeqMethods,
3476 /*tp_as_mapping*/ &Matrix_AsMapping,
3477 /*tp_hash*/ (hashfunc)Matrix_hash,
3478 /*tp_call*/ nullptr,
3479 /*tp_str*/ (reprfunc)Matrix_str,
3480 /*tp_getattro*/ nullptr,
3481 /*tp_setattro*/ nullptr,
3482 /*tp_as_buffer*/ nullptr,
3483 /*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
3484 /*tp_doc*/ matrix_doc,
3485 /*tp_traverse*/ (traverseproc)BaseMathObject_traverse,
3486 /*tp_clear*/ (inquiry)BaseMathObject_clear,
3487 /*tp_richcompare*/ (richcmpfunc)Matrix_richcmpr,
3488 /*tp_weaklistoffset*/ 0,
3489 /*tp_iter*/ nullptr,
3490 /*tp_iternext*/ nullptr,
3491 /*tp_methods*/ Matrix_methods,
3492 /*tp_members*/ nullptr,
3493 /*tp_getset*/ Matrix_getseters,
3494 /*tp_base*/ nullptr,
3495 /*tp_dict*/ nullptr,
3496 /*tp_descr_get*/ nullptr,
3497 /*tp_descr_set*/ nullptr,
3498 /*tp_dictoffset*/ 0,
3499 /*tp_init*/ nullptr,
3500 /*tp_alloc*/ nullptr,
3501 /*tp_new*/ Matrix_new,
3502 /*tp_free*/ nullptr,
3503 /*tp_is_gc*/ (inquiry)BaseMathObject_is_gc,
3504 /*tp_bases*/ nullptr,
3505 /*tp_mro*/ nullptr,
3506 /*tp_cache*/ nullptr,
3507 /*tp_subclasses*/ nullptr,
3508 /*tp_weaklist*/ nullptr,
3509 /*tp_del*/ nullptr,
3510 /*tp_version_tag*/ 0,
3511 /*tp_finalize*/ nullptr,
3512 /*tp_vectorcall*/ nullptr,
3513};
3514
3515#ifdef MATH_STANDALONE
3516# undef Matrix_str
3517#endif
3518
3521/* -------------------------------------------------------------------- */
3525PyObject *Matrix_CreatePyObject(const float *mat,
3526 const ushort col_num,
3527 const ushort row_num,
3528 PyTypeObject *base_type)
3529{
3531 float *mat_alloc;
3532
3533 /* matrix objects can be any 2-4row x 2-4col matrix */
3534 if (col_num < 2 || col_num > 4 || row_num < 2 || row_num > 4) {
3535 PyErr_SetString(PyExc_RuntimeError,
3536 "Matrix(): "
3537 "row and column sizes must be between 2 and 4");
3538 return nullptr;
3539 }
3540
3541 mat_alloc = static_cast<float *>(PyMem_Malloc(col_num * row_num * sizeof(float)));
3542 if (UNLIKELY(mat_alloc == nullptr)) {
3543 PyErr_SetString(PyExc_MemoryError,
3544 "Matrix(): "
3545 "problem allocating data");
3546 return nullptr;
3547 }
3548
3550 if (self) {
3551 self->matrix = mat_alloc;
3552 self->col_num = col_num;
3553 self->row_num = row_num;
3554
3555 /* init callbacks as nullptr */
3556 self->cb_user = nullptr;
3557 self->cb_type = self->cb_subtype = 0;
3558
3559 if (mat) { /* If a float array passed. */
3560 memcpy(self->matrix, mat, col_num * row_num * sizeof(float));
3561 }
3562 else if (col_num == row_num) {
3563 /* or if no arguments are passed return identity matrix for square matrices */
3565 }
3566 else {
3567 /* otherwise zero everything */
3568 memset(self->matrix, 0, col_num * row_num * sizeof(float));
3569 }
3571 }
3572 else {
3573 PyMem_Free(mat_alloc);
3574 }
3575
3576 return (PyObject *)self;
3577}
3578
3579PyObject *Matrix_CreatePyObject_wrap(float *mat,
3580 const ushort col_num,
3581 const ushort row_num,
3582 PyTypeObject *base_type)
3583{
3585
3586 /* matrix objects can be any 2-4row x 2-4col matrix */
3587 if (col_num < 2 || col_num > 4 || row_num < 2 || row_num > 4) {
3588 PyErr_SetString(PyExc_RuntimeError,
3589 "Matrix(): "
3590 "row and column sizes must be between 2 and 4");
3591 return nullptr;
3592 }
3593
3595 if (self) {
3596 self->col_num = col_num;
3597 self->row_num = row_num;
3598
3599 /* init callbacks as nullptr */
3600 self->cb_user = nullptr;
3601 self->cb_type = self->cb_subtype = 0;
3602
3603 self->matrix = mat;
3605 }
3606 return (PyObject *)self;
3607}
3608
3610 PyObject *cb_user, const ushort col_num, const ushort row_num, uchar cb_type, uchar cb_subtype)
3611{
3612 MatrixObject *self = (MatrixObject *)Matrix_CreatePyObject(nullptr, col_num, row_num, nullptr);
3613 if (self) {
3614 Py_INCREF(cb_user);
3615 self->cb_user = cb_user;
3616 self->cb_type = cb_type;
3617 self->cb_subtype = cb_subtype;
3618 BLI_assert(!PyObject_GC_IsTracked((PyObject *)self));
3619 PyObject_GC_Track(self);
3620 }
3621 return (PyObject *)self;
3622}
3623
3624PyObject *Matrix_CreatePyObject_alloc(float *mat,
3625 const ushort col_num,
3626 const ushort row_num,
3627 PyTypeObject *base_type)
3628{
3630 self = (MatrixObject *)Matrix_CreatePyObject_wrap(mat, col_num, row_num, base_type);
3631 if (self) {
3632 self->flag &= ~BASE_MATH_FLAG_IS_WRAP;
3633 }
3634
3635 return (PyObject *)self;
3636}
3637
3640/* -------------------------------------------------------------------- */
3648{
3649 if (!MatrixObject_Check(pymat)) {
3650 PyErr_Format(
3651 PyExc_TypeError, "expected a mathutils.Matrix, not a %.200s", Py_TYPE(pymat)->tp_name);
3652 return false;
3653 }
3654 /* sets error */
3655 if (BaseMath_ReadCallback(pymat) == -1) {
3656 return false;
3657 }
3658 return true;
3659}
3660
3661int Matrix_ParseAny(PyObject *o, void *p)
3662{
3663 MatrixObject **pymat_p = static_cast<MatrixObject **>(p);
3664 MatrixObject *pymat = (MatrixObject *)o;
3665
3666 if (!Matrix_ParseCheck(pymat)) {
3667 return 0;
3668 }
3669 *pymat_p = pymat;
3670 return 1;
3671}
3672
3673int Matrix_Parse2x2(PyObject *o, void *p)
3674{
3675 MatrixObject **pymat_p = static_cast<MatrixObject **>(p);
3676 MatrixObject *pymat = (MatrixObject *)o;
3677
3678 if (!Matrix_ParseCheck(pymat)) {
3679 return 0;
3680 }
3681 if ((pymat->col_num != 2) || (pymat->row_num != 2)) {
3682 PyErr_SetString(PyExc_ValueError, "matrix must be 2x2");
3683 return 0;
3684 }
3685
3686 *pymat_p = pymat;
3687 return 1;
3688}
3689
3690int Matrix_Parse3x3(PyObject *o, void *p)
3691{
3692 MatrixObject **pymat_p = static_cast<MatrixObject **>(p);
3693 MatrixObject *pymat = (MatrixObject *)o;
3694
3695 if (!Matrix_ParseCheck(pymat)) {
3696 return 0;
3697 }
3698 if ((pymat->col_num != 3) || (pymat->row_num != 3)) {
3699 PyErr_SetString(PyExc_ValueError, "matrix must be 3x3");
3700 return 0;
3701 }
3702
3703 *pymat_p = pymat;
3704 return 1;
3705}
3706
3707int Matrix_Parse4x4(PyObject *o, void *p)
3708{
3709 MatrixObject **pymat_p = static_cast<MatrixObject **>(p);
3710 MatrixObject *pymat = (MatrixObject *)o;
3711
3712 if (!Matrix_ParseCheck(pymat)) {
3713 return 0;
3714 }
3715 if ((pymat->col_num != 4) || (pymat->row_num != 4)) {
3716 PyErr_SetString(PyExc_ValueError, "matrix must be 4x4");
3717 return 0;
3718 }
3719
3720 *pymat_p = pymat;
3721 return 1;
3722}
3723
3726/* -------------------------------------------------------------------- */
3731 PyObject_HEAD /* Required Python macro. */
3734};
3735
3736static int MatrixAccess_traverse(MatrixAccessObject *self, visitproc visit, void *arg)
3737{
3738 Py_VISIT(self->matrix_user);
3739 return 0;
3740}
3741
3743{
3744 Py_CLEAR(self->matrix_user);
3745 return 0;
3746}
3747
3749{
3750 if (self->matrix_user) {
3751 PyObject_GC_UnTrack(self);
3753 }
3754
3755 Py_TYPE(self)->tp_free(self);
3756}
3757
3760/* -------------------------------------------------------------------- */
3765{
3766 return (self->type == MAT_ACCESS_ROW) ? self->matrix_user->row_num : self->matrix_user->col_num;
3767}
3768
3769static PyObject *MatrixAccess_slice(MatrixAccessObject *self, Py_ssize_t begin, Py_ssize_t end)
3770{
3771 PyObject *tuple;
3772 Py_ssize_t count;
3773
3774 /* row/col access */
3775 MatrixObject *matrix_user = self->matrix_user;
3776 int matrix_access_len;
3777 PyObject *(*Matrix_item_new)(MatrixObject *, Py_ssize_t);
3778
3779 if (self->type == MAT_ACCESS_ROW) {
3780 matrix_access_len = matrix_user->row_num;
3781 Matrix_item_new = Matrix_item_row;
3782 }
3783 else { /* MAT_ACCESS_ROW */
3784 matrix_access_len = matrix_user->col_num;
3785 Matrix_item_new = Matrix_item_col;
3786 }
3787
3788 CLAMP(begin, 0, matrix_access_len);
3789 if (end < 0) {
3790 end = (matrix_access_len + 1) + end;
3791 }
3792 CLAMP(end, 0, matrix_access_len);
3793 begin = std::min(begin, end);
3794
3795 tuple = PyTuple_New(end - begin);
3796 for (count = begin; count < end; count++) {
3797 PyTuple_SET_ITEM(tuple, count - begin, Matrix_item_new(matrix_user, count));
3798 }
3799
3800 return tuple;
3801}
3802
3803static PyObject *MatrixAccess_subscript(MatrixAccessObject *self, PyObject *item)
3804{
3805 MatrixObject *matrix_user = self->matrix_user;
3806
3807 if (PyIndex_Check(item)) {
3808 Py_ssize_t i;
3809 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
3810 if (i == -1 && PyErr_Occurred()) {
3811 return nullptr;
3812 }
3813 if (self->type == MAT_ACCESS_ROW) {
3814 if (i < 0) {
3815 i += matrix_user->row_num;
3816 }
3817 return Matrix_item_row(matrix_user, i);
3818 }
3819 /* MAT_ACCESS_ROW */
3820 if (i < 0) {
3821 i += matrix_user->col_num;
3822 }
3823 return Matrix_item_col(matrix_user, i);
3824 }
3825 if (PySlice_Check(item)) {
3826 Py_ssize_t start, stop, step, slicelength;
3827
3828 if (PySlice_GetIndicesEx(item, MatrixAccess_len(self), &start, &stop, &step, &slicelength) < 0)
3829 {
3830 return nullptr;
3831 }
3832
3833 if (slicelength <= 0) {
3834 return PyTuple_New(0);
3835 }
3836 if (step == 1) {
3837 return MatrixAccess_slice(self, start, stop);
3838 }
3839
3840 PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrix accessors");
3841 return nullptr;
3842 }
3843
3844 PyErr_Format(
3845 PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
3846 return nullptr;
3847}
3848
3849static int MatrixAccess_ass_subscript(MatrixAccessObject *self, PyObject *item, PyObject *value)
3850{
3851 MatrixObject *matrix_user = self->matrix_user;
3852
3853 if (PyIndex_Check(item)) {
3854 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
3855 if (i == -1 && PyErr_Occurred()) {
3856 return -1;
3857 }
3858
3859 if (self->type == MAT_ACCESS_ROW) {
3860 if (i < 0) {
3861 i += matrix_user->row_num;
3862 }
3863 return Matrix_ass_item_row(matrix_user, i, value);
3864 }
3865 /* MAT_ACCESS_ROW */
3866 if (i < 0) {
3867 i += matrix_user->col_num;
3868 }
3869 return Matrix_ass_item_col(matrix_user, i, value);
3870 }
3871 /* TODO: slice. */
3872
3873 PyErr_Format(
3874 PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
3875 return -1;
3876}
3877
3879{
3880 /* Try get values from a collection. */
3881 PyObject *ret;
3882 PyObject *iter = nullptr;
3884
3885 /* We know this is a tuple so no need to #PyIter_Check
3886 * otherwise it could be nullptr (unlikely) if conversion failed. */
3887 if (ret) {
3888 iter = PyObject_GetIter(ret);
3889 Py_DECREF(ret);
3890 }
3891
3892 return iter;
3893}
3894
3895static PyMappingMethods MatrixAccess_AsMapping = {
3896 /*mp_length*/ (lenfunc)MatrixAccess_len,
3897 /*mp_subscript*/ (binaryfunc)MatrixAccess_subscript,
3898 /*mp_ass_subscript*/ (objobjargproc)MatrixAccess_ass_subscript,
3899};
3900
3903/* -------------------------------------------------------------------- */
3907PyTypeObject matrix_access_Type = {
3908 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
3909 /*tp_name*/ "MatrixAccess",
3910 /*tp_basicsize*/ sizeof(MatrixAccessObject),
3911 /*tp_itemsize*/ 0,
3912 /*tp_dealloc*/ (destructor)MatrixAccess_dealloc,
3913 /*tp_vectorcall_offset*/ 0,
3914 /*tp_getattr*/ nullptr,
3915 /*tp_setattr*/ nullptr,
3916 /*tp_as_async*/ nullptr,
3917 /*tp_repr*/ nullptr,
3918 /*tp_as_number*/ nullptr,
3919 /*tp_as_sequence*/ nullptr /* &MatrixAccess_SeqMethods */ /* TODO. */,
3920 /*tp_as_mapping*/ &MatrixAccess_AsMapping,
3921 /*tp_hash*/ nullptr,
3922 /*tp_call*/ nullptr,
3923 /*tp_str*/ nullptr,
3924 /*tp_getattro*/ nullptr,
3925 /*tp_setattro*/ nullptr,
3926 /*tp_as_buffer*/ nullptr,
3927 /*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
3928 /*tp_doc*/ nullptr,
3929 /*tp_traverse*/ (traverseproc)MatrixAccess_traverse,
3930 /*tp_clear*/ (inquiry)MatrixAccess_clear,
3931 /*tp_richcompare*/ nullptr /* MatrixAccess_richcmpr */ /* TODO. */,
3932 /*tp_weaklistoffset*/ 0,
3933 /*tp_iter*/ (getiterfunc)MatrixAccess_iter,
3934 /*tp_iternext*/ nullptr,
3935 /*tp_methods*/ nullptr,
3936 /*tp_members*/ nullptr,
3937 /*tp_getset*/ nullptr,
3938 /*tp_base*/ nullptr,
3939 /*tp_dict*/ nullptr,
3940 /*tp_descr_get*/ nullptr,
3941 /*tp_descr_set*/ nullptr,
3942 /*tp_dictoffset*/ 0,
3943 /*tp_init*/ nullptr,
3944 /*tp_alloc*/ nullptr,
3945 /*tp_new*/ nullptr,
3946 /*tp_free*/ nullptr,
3947 /*tp_is_gc*/ nullptr,
3948 /*tp_bases*/ nullptr,
3949 /*tp_mro*/ nullptr,
3950 /*tp_cache*/ nullptr,
3951 /*tp_subclasses*/ nullptr,
3952 /*tp_weaklist*/ nullptr,
3953 /*tp_del*/ nullptr,
3954 /*tp_version_tag*/ 0,
3955 /*tp_finalize*/ nullptr,
3956 /*tp_vectorcall*/ nullptr,
3957};
3958
3961/* -------------------------------------------------------------------- */
3965static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type)
3966{
3967 MatrixAccessObject *matrix_access = (MatrixAccessObject *)PyObject_GC_New(MatrixObject,
3969
3970 matrix_access->matrix_user = matrix;
3971 Py_INCREF(matrix);
3972
3973 matrix_access->type = type;
3974
3975 return (PyObject *)matrix_access;
3976}
3977
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define ATTR_FALLTHROUGH
A dynamically sized string ADT.
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_dynstr.c:37
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format,...) ATTR_PRINTF_FORMAT(2
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL()
Definition BLI_dynstr.c:62
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
float mat3_to_scale(const float mat[3][3])
bool is_negative_m3(const float mat[3][3])
bool is_orthogonal_m3(const float m[3][3])
void unit_m2(float m[2][2])
void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], float t)
void copy_m3_m3(float m1[3][3], const float m2[3][3])
bool is_orthogonal_m4(const float m[4][4])
void adjoint_m3_m3(float R[3][3], const float M[3][3])
void unit_m3(float m[3][3])
void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3])
void blend_m4_m4m4(float out[4][4], const float dst[4][4], const float src[4][4], float srcweight)
void copy_m3_m4(float m1[3][3], const float m2[4][4])
#define PSEUDOINVERSE_EPSILON
void unit_m4(float m[4][4])
Definition rct.c:1127
void copy_m4_m3(float m1[4][4], const float m2[3][3])
void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4])
bool is_orthonormal_m3(const float m[3][3])
void normalize_m3(float R[3][3]) ATTR_NONNULL()
float determinant_m2(float a, float b, float c, float d)
void rescale_m4(float mat[4][4], const float scale[3])
void adjoint_m4_m4(float R[4][4], const float M[4][4])
float determinant_m4(const float m[4][4])
void copy_m2_m2(float m1[2][2], const float m2[2][2])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], float t)
bool is_orthonormal_m4(const float m[4][4])
float determinant_m3_array(const float m[3][3])
bool is_negative_m4(const float mat[4][4])
void transpose_m3(float R[3][3])
float determinant_m3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3)
void blend_m3_m3m3(float out[3][3], const float dst[3][3], const float src[3][3], float srcweight)
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
void transpose_m4(float R[4][4])
void normalize_m4(float R[4][4]) ATTR_NONNULL()
void adjoint_m2_m2(float R[2][2], const float M[2][2])
void axis_angle_to_mat3_single(float R[3][3], char axis, float angle)
void mat3_normalized_to_compatible_eul(float eul[3], const float oldrot[3], float mat[3][3])
@ EULER_ORDER_XYZ
void mat3_to_quat(float q[4], const float mat[3][3])
void quat_to_mat4(float m[4][4], const float q[4])
void angle_to_mat2(float R[2][2], float angle)
void eulO_to_mat4(float mat[4][4], const float e[3], short order)
void mat3_normalized_to_eul(float eul[3], const float mat[3][3])
void mat4_to_quat(float q[4], const float mat[4][4])
void mat3_normalized_to_quat_fast(float q[4], const float mat[3][3])
void mat3_normalized_to_eulO(float eul[3], short order, const float m[3][3])
float angle_wrap_rad(float angle)
void axis_angle_to_mat3(float R[3][3], const float axis[3], float angle)
void mat3_normalized_to_compatible_eulO(float eul[3], const float oldrot[3], short order, const float mat[3][3])
void mul_vn_fl(float *array_tar, int size, float f)
void sub_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, int size)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void add_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, int size)
void copy_vn_fl(float *array_tar, int size, float val)
void mul_vn_vn(float *array_tar, const float *array_src, int size)
MINLINE void zero_v3(float r[3])
void mul_vn_vn_fl(float *array_tar, const float *array_src, int size, float f)
void mul_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, int size)
#define SNPRINTF_RLEN(dst, format,...)
Definition BLI_string.h:598
unsigned char uchar
unsigned short ushort
unsigned int uint
#define CLAMP(a, b, c)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
typedef double(DMatrix)[4][4]
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
PyObject * self
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE btScalar norm() const
Return the norm (length) of the vector.
Definition btVector3.h:263
local_group_size(16, 16) .push_constant(Type b
#define sqrtf(x)
draw_view in_light_buf[] float
#define rot(x, k)
uint col
int count
int BaseMathObject_is_gc(BaseMathObject *self)
Definition mathutils.cc:711
Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
Definition mathutils.cc:69
void BaseMathObject_dealloc(BaseMathObject *self)
Definition mathutils.cc:689
int EXPP_VectorsAreEqual(const float *vecA, const float *vecB, int size, int floatSteps)
Definition mathutils.cc:490
int mathutils_array_parse(float *array, int array_num_min, int array_num_max, PyObject *value, const char *error_prefix)
Definition mathutils.cc:97
char BaseMathObject_is_valid_doc[]
Definition mathutils.cc:639
char BaseMathObject_is_wrapped_doc[]
Definition mathutils.cc:625
PyObject * BaseMathObject_owner_get(BaseMathObject *self, void *)
Definition mathutils.cc:619
char BaseMathObject_is_frozen_doc[]
Definition mathutils.cc:632
PyObject * mathutils_dynstr_to_py(DynStr *ds)
Definition mathutils.cc:502
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
Definition mathutils.cc:409
PyObject * BaseMathObject_is_frozen_get(BaseMathObject *self, void *)
Definition mathutils.cc:634
PyObject * BaseMathObject_freeze(BaseMathObject *self)
Definition mathutils.cc:653
PyObject * BaseMathObject_is_wrapped_get(BaseMathObject *self, void *)
Definition mathutils.cc:627
char BaseMathObject_owner_doc[]
Definition mathutils.cc:618
char BaseMathObject_freeze_doc[]
Definition mathutils.cc:645
PyObject * BaseMathObject_is_valid_get(BaseMathObject *self, void *)
Definition mathutils.cc:640
int BaseMathObject_clear(BaseMathObject *self)
Definition mathutils.cc:671
int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
Definition mathutils.cc:665
@ BASE_MATH_FLAG_IS_WRAP
Definition mathutils.hh:36
#define BaseMath_ReadCallback_ForWrite(_self)
Definition mathutils.hh:135
#define BaseMath_WriteCallback(_self)
Definition mathutils.hh:127
#define BASE_MATH_NEW(struct_name, root_type, base_type)
Definition mathutils.hh:26
#define BaseMathObject_Prepare_ForHash(_self)
Definition mathutils.hh:150
int column_vector_multiplication(float r_vec[4], VectorObject *vec, MatrixObject *mat)
#define BASE_MATH_FLAG_DEFAULT
Definition mathutils.hh:43
#define BaseMath_Prepare_ForWrite(_self)
Definition mathutils.hh:145
#define BaseMath_ReadCallback(_self)
Definition mathutils.hh:125
short euler_order_from_string(const char *str, const char *error_prefix)
PyTypeObject euler_Type
PyObject * Euler_CreatePyObject(const float eul[3], const short order, PyTypeObject *base_type)
#define EulerObject_Check(v)
static PyObject * Matrix_repr(MatrixObject *self)
int Matrix_Parse3x3(PyObject *o, void *p)
static bool matrix_invert_internal(const MatrixObject *self, float *r_mat)
PyObject * Matrix_CreatePyObject_cb(PyObject *cb_user, const ushort col_num, const ushort row_num, uchar cb_type, uchar cb_subtype)
static PyObject * Matrix_is_identity_get(MatrixObject *self, void *)
PyObject * Matrix_CreatePyObject(const float *mat, const ushort col_num, const ushort row_num, PyTypeObject *base_type)
static PyMappingMethods MatrixAccess_AsMapping
static PyGetSetDef Matrix_getseters[]
static PyObject * MatrixAccess_slice(MatrixAccessObject *self, Py_ssize_t begin, Py_ssize_t end)
static int mathutils_matrix_col_set(BaseMathObject *bmo, int col)
static PyObject * C_Matrix_Identity(PyObject *cls, PyObject *args)
int Matrix_ParseAny(PyObject *o, void *p)
static Py_ssize_t Matrix_len(MatrixObject *self)
static int mathutils_matrix_row_set(BaseMathObject *bmo, int row)
static int matrix_row_vector_check(MatrixObject *mat, VectorObject *vec, int row)
static PyObject * Matrix_to_translation(MatrixObject *self)
static int mathutils_matrix_row_get_index(BaseMathObject *bmo, int row, int col)
static PyObject * C_Matrix_Rotation(PyObject *cls, PyObject *args)
static PyObject * Matrix_col_get(MatrixObject *self, void *)
static int Matrix_ass_subscript(MatrixObject *self, PyObject *item, PyObject *value)
static PyObject * Matrix_row_get(MatrixObject *self, void *)
static PyObject * Matrix_decompose(MatrixObject *self)
static int mathutils_matrix_row_set_index(BaseMathObject *bmo, int row, int col)
static int mathutils_matrix_col_get(BaseMathObject *bmo, int col)
static PyObject * Matrix_str(MatrixObject *self)
static void matrix_invert_raise_degenerate()
static PyObject * Matrix_imatmul(PyObject *m1, PyObject *m2)
static void matrix_transpose_internal(float mat_dst_fl[], const MatrixObject *mat_src)
static void matrix_identity_internal(MatrixObject *self)
static PyObject * Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
static PyObject * Matrix_mul(PyObject *m1, PyObject *m2)
static PyObject * Matrix_item_row(MatrixObject *self, Py_ssize_t row)
static PyObject * matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *), MatrixObject *self)
static PyObject * Matrix_is_orthogonal_get(MatrixObject *self, void *)
static PyObject * MatrixAccess_subscript(MatrixAccessObject *self, PyObject *item)
static PyObject * Matrix_to_2x2(MatrixObject *self)
static PyObject * Matrix_slice(MatrixObject *self, int begin, int end)
static int mathutils_matrix_row_check(BaseMathObject *bmo)
static int MatrixAccess_clear(MatrixAccessObject *self)
PyObject * Matrix_CreatePyObject_alloc(float *mat, const ushort col_num, const ushort row_num, PyTypeObject *base_type)
static PyObject * Matrix_transposed(MatrixObject *self)
static float matrix_determinant_internal(const MatrixObject *self)
static PyObject * Matrix_inverted_safe(MatrixObject *self)
static PyObject * Matrix_matmul(PyObject *m1, PyObject *m2)
static PyMethodDef Matrix_methods[]
static PyObject * Matrix_inverted_noargs(MatrixObject *self)
PyDoc_STRVAR(C_Matrix_Identity_doc, ".. classmethod:: Identity(size)\n" "\n" " Create an identity matrix.\n" "\n" " :arg size: The size of the identity matrix to construct [2, 4].\n" " :type size: int\n" " :return: A new identity matrix.\n" " :rtype: :class:`Matrix`\n")
static PyObject * C_Matrix_LocRotScale(PyObject *cls, PyObject *args)
static void matrix_unit_internal(MatrixObject *self)
Mathutils_Callback mathutils_matrix_col_cb
static void adjoint_matrix_n(float *mat_dst, const float *mat_src, const ushort dim)
static PyObject * Matrix_is_orthogonal_axis_vectors_get(MatrixObject *self, void *)
static bool matrix_invert_is_compat(const MatrixObject *self)
static PyObject * Matrix_is_negative_get(MatrixObject *self, void *)
static bool matrix_is_identity(MatrixObject *self)
static int mathutils_matrix_translation_set_index(BaseMathObject *bmo, int col, int row)
PyTypeObject matrix_access_Type
static PyObject * Matrix_invert_safe(MatrixObject *self)
static PyObject * Matrix_adjugated(MatrixObject *self)
static PyNumberMethods Matrix_NumMethods
static PyObject * Matrix_to_4x4(MatrixObject *self)
static PySequenceMethods Matrix_SeqMethods
static int mathutils_matrix_col_get_index(BaseMathObject *bmo, int col, int row)
PyObject * Matrix_CreatePyObject_wrap(float *mat, const ushort col_num, const ushort row_num, PyTypeObject *base_type)
eMatrixAccess_t
@ MAT_ACCESS_ROW
@ MAT_ACCESS_COL
static int mathutils_matrix_translation_get_index(BaseMathObject *bmo, int col, int row)
static void matrix_invert_with_det_n_internal(float *mat_dst, const float *mat_src, const float det, const ushort dim)
static PyObject * Matrix_deepcopy(MatrixObject *self, PyObject *args)
static PyObject * Matrix_sub(PyObject *m1, PyObject *m2)
static PyObject * Matrix_identity(MatrixObject *self)
void matrix_as_3x3(float mat[3][3], MatrixObject *self)
static bool Matrix_ParseCheck(MatrixObject *pymat)
static PyMappingMethods Matrix_AsMapping
static PyObject * C_Matrix_Translation(PyObject *cls, PyObject *value)
static PyObject * Matrix_copy(MatrixObject *self)
static PyObject * Matrix_richcmpr(PyObject *a, PyObject *b, int op)
static void matrix_3x3_as_4x4(float mat[16])
static PyObject * Matrix_subscript(MatrixObject *self, PyObject *item)
int Matrix_Parse2x2(PyObject *o, void *p)
Mathutils_Callback mathutils_matrix_row_cb
static int mathutils_matrix_translation_get(BaseMathObject *bmo, int col)
static int MatrixAccess_traverse(MatrixAccessObject *self, visitproc visit, void *arg)
static PyObject * Matrix_median_scale_get(MatrixObject *self, void *)
static PyObject * Matrix_normalized(MatrixObject *self)
Mathutils_Callback mathutils_matrix_translation_cb
static PyObject * Matrix_translation_get(MatrixObject *self, void *)
static int Matrix_translation_set(MatrixObject *self, PyObject *value, void *)
static PyObject * Matrix_imul(PyObject *m1, PyObject *m2)
static PyObject * Matrix_determinant(MatrixObject *self)
static PyObject * C_Matrix_Diagonal(PyObject *cls, PyObject *value)
static PyObject * Matrix_to_scale(MatrixObject *self)
static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value)
int Matrix_Parse4x4(PyObject *o, void *p)
static PyObject * Matrix_invert(MatrixObject *self, PyObject *args)
static PyObject * Matrix_transpose(MatrixObject *self)
uchar mathutils_matrix_col_cb_index
static PyObject * Matrix_item_col(MatrixObject *self, Py_ssize_t col)
static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value)
uchar mathutils_matrix_row_cb_index
static int Matrix_ass_item_row(MatrixObject *self, Py_ssize_t row, PyObject *value)
static PyObject * Matrix_resize_4x4(MatrixObject *self)
static PyObject * C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
static PyObject * Matrix_normalize(MatrixObject *self)
static PyObject * C_Matrix_Scale(PyObject *cls, PyObject *args)
static Py_ssize_t MatrixAccess_len(MatrixAccessObject *self)
static PyObject * Matrix_adjugate(MatrixObject *self)
static PyObject * Matrix_to_NxN(MatrixObject *self, const int col_num, const int row_num)
static int MatrixAccess_ass_subscript(MatrixAccessObject *self, PyObject *item, PyObject *value)
static int mathutils_matrix_row_get(BaseMathObject *bmo, int row)
static PyObject * C_Matrix_Shear(PyObject *cls, PyObject *args)
static int matrix_col_vector_check(MatrixObject *mat, VectorObject *vec, int col)
static PyObject * Matrix_to_quaternion(MatrixObject *self)
static PyObject * matrix_mul_float(MatrixObject *mat, const float scalar)
static PyObject * MatrixAccess_iter(MatrixAccessObject *self)
static bool matrix_invert_args_check(const MatrixObject *self, PyObject *args, bool check_type)
static int mathutils_matrix_translation_check(BaseMathObject *bmo)
static void MatrixAccess_dealloc(MatrixAccessObject *self)
static PyObject * Matrix_lerp(MatrixObject *self, PyObject *args)
static int mathutils_matrix_col_check(BaseMathObject *bmo)
static void matrix_copy(MatrixObject *mat_dst, const MatrixObject *mat_src)
static Py_hash_t Matrix_hash(MatrixObject *self)
static int mathutils_matrix_col_set_index(BaseMathObject *bmo, int col, int row)
static PyObject * Matrix_to_euler(MatrixObject *self, PyObject *args)
static PyObject * Matrix_add(PyObject *m1, PyObject *m2)
static PyObject * Matrix_rotate(MatrixObject *self, PyObject *value)
static int mathutils_matrix_translation_set(BaseMathObject *bmo, int col)
static PyObject * Matrix_to_3x3(MatrixObject *self)
static PyObject * Matrix_copy_notest(MatrixObject *self, const float *matrix)
static PyObject * Matrix_inverted(MatrixObject *self, PyObject *args)
static PyObject * Matrix_zero(MatrixObject *self)
static PyObject * MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type)
static void matrix_invert_safe_internal(const MatrixObject *self, float *r_mat)
uchar mathutils_matrix_translation_cb_index
PyTypeObject matrix_Type
#define MATRIX_COL_PTR(_mat, _col)
#define MATRIX_MAX_DIM
#define MatrixObject_Check(v)
#define MATRIX_ITEM_INDEX_NUMROW(_totrow, _row, _col)
#define MATRIX_ITEM(_mat, _row, _col)
PyObject * Quaternion_CreatePyObject(const float quat[4], PyTypeObject *base_type)
#define QuaternionObject_Check(v)
PyObject * Vector_CreatePyObject(const float *vec, const int vec_num, PyTypeObject *base_type)
PyObject * Vector_CreatePyObject_cb(PyObject *cb_user, int vec_num, uchar cb_type, uchar cb_subtype)
#define VectorObject_Check(v)
const btScalar eps
Definition poly34.cpp:11
int PyC_CheckArgs_DeepCopy(PyObject *args)
header-only utilities
#define PyTuple_SET_ITEMS(op_arg,...)
return ret
unsigned char order
PyObject_HEAD MatrixObject * matrix_user