Blender V5.0
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
8
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_utf8.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/* -------------------------------------------------------------------- */
44
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
312
313/* -------------------------------------------------------------------- */
317
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
406
407/* -------------------------------------------------------------------- */
411
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
508
509/* -------------------------------------------------------------------- */
515
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
592
593/* -------------------------------------------------------------------- */
596
597static PyObject *Matrix_vectorcall(PyObject *type,
598 PyObject *const *args,
599 const size_t nargsf,
600 PyObject *kwnames)
601{
602 if (UNLIKELY(kwnames && PyTuple_GET_SIZE(kwnames))) {
603 PyErr_SetString(PyExc_TypeError,
604 "Matrix(): "
605 "takes no keyword args");
606 return nullptr;
607 }
608
609 switch (PyVectorcall_NARGS(nargsf)) {
610 case 0: {
611 return Matrix_CreatePyObject(nullptr, 4, 4, (PyTypeObject *)type);
612 }
613 case 1: {
614 PyObject *arg = args[0];
615
616 /* Input is now as a sequence of rows so length of sequence
617 * is the number of rows */
618 /* -1 is an error, size checks will account for this */
619 const ushort row_num = PySequence_Size(arg);
620
621 if (row_num >= 2 && row_num <= 4) {
622 PyObject *item = PySequence_GetItem(arg, 0);
623 /* Since each item is a row, number of items is the
624 * same as the number of columns */
625 const ushort col_num = PySequence_Size(item);
626 Py_XDECREF(item);
627
628 if (col_num >= 2 && col_num <= 4) {
629 /* Sane row & col size, new matrix and assign as slice. */
630 PyObject *matrix = Matrix_CreatePyObject(
631 nullptr, col_num, row_num, (PyTypeObject *)type);
632 if (Matrix_ass_slice((MatrixObject *)matrix, 0, INT_MAX, arg) == 0) {
633 return matrix;
634 }
635 /* matrix ok, slice assignment not */
636 Py_DECREF(matrix);
637 }
638 }
639 break;
640 }
641 }
642
643 /* will overwrite error */
644 PyErr_SetString(PyExc_TypeError,
645 "mathutils.Matrix(): "
646 "expects no args or a single arg containing 2-4 numeric sequences");
647 return nullptr;
648}
649
650static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
651{
652 /* Only called on sub-classes. */
653 if (UNLIKELY(kwds && PyDict_GET_SIZE(kwds))) {
654 PyErr_SetString(PyExc_TypeError,
655 "mathutils.Matrix(): "
656 "takes no keyword args");
657 return nullptr;
658 }
659 PyObject *const *args_array = &PyTuple_GET_ITEM(args, 0);
660 const size_t args_array_num = PyTuple_GET_SIZE(args);
661 return Matrix_vectorcall(
662 reinterpret_cast<PyObject *>(type), args_array, args_array_num, nullptr);
663}
664
666
667/* -------------------------------------------------------------------- */
670
673 /* Wrap. */
674 C_Matrix_Identity_doc,
675 ".. classmethod:: Identity(size, /)\n"
676 "\n"
677 " Create an identity matrix.\n"
678 "\n"
679 " :arg size: The size of the identity matrix to construct [2, 4].\n"
680 " :type size: int\n"
681 " :return: A new identity matrix.\n"
682 " :rtype: :class:`Matrix`\n");
683static PyObject *C_Matrix_Identity(PyObject *cls, PyObject *args)
684{
685 int matSize;
686
687 if (!PyArg_ParseTuple(args, "i:Matrix.Identity", &matSize)) {
688 return nullptr;
689 }
690
691 if (matSize < 2 || matSize > 4) {
692 PyErr_SetString(PyExc_RuntimeError,
693 "Matrix.Identity(): "
694 "size must be between 2 and 4");
695 return nullptr;
696 }
697
698 return Matrix_CreatePyObject(nullptr, matSize, matSize, (PyTypeObject *)cls);
699}
700
703 /* Wrap. */
704 C_Matrix_Rotation_doc,
705 ".. classmethod:: Rotation(angle, size, axis, /)\n"
706 "\n"
707 " Create a matrix representing a rotation.\n"
708 "\n"
709 " :arg angle: The angle of rotation desired, in radians.\n"
710 " :type angle: float\n"
711 " :arg size: The size of the rotation matrix to construct [2, 4].\n"
712 " :type size: int\n"
713 " :arg axis: an axis string or a 3D Vector Object\n"
714 " (optional when size is 2).\n"
715 " :type axis: Literal['X', 'Y', 'Z'] | :class:`Vector`\n"
716 " :return: A new rotation matrix.\n"
717 " :rtype: :class:`Matrix`\n");
718static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
719{
720 PyObject *vec = nullptr;
721 const char *axis = nullptr;
722 int matSize;
723 double angle; /* Use double because of precision problems at high values. */
724 float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
725
726 if (!PyArg_ParseTuple(args, "di|O:Matrix.Rotation", &angle, &matSize, &vec)) {
727 return nullptr;
728 }
729
730 if (vec && PyUnicode_Check(vec)) {
731 axis = PyUnicode_AsUTF8(vec);
732 if (axis == nullptr || axis[0] == '\0' || axis[1] != '\0' || axis[0] < 'X' || axis[0] > 'Z') {
733 PyErr_SetString(PyExc_ValueError,
734 "Matrix.Rotation(): "
735 "3rd argument axis value must be a 3D vector "
736 "or a string in 'X', 'Y', 'Z'");
737 return nullptr;
738 }
739
740 /* use the string */
741 vec = nullptr;
742 }
743
745
746 if (!ELEM(matSize, 2, 3, 4)) {
747 PyErr_SetString(PyExc_ValueError,
748 "Matrix.Rotation(): "
749 "can only return a 2x2 3x3 or 4x4 matrix");
750 return nullptr;
751 }
752 if (matSize == 2 && (vec != nullptr)) {
753 PyErr_SetString(PyExc_ValueError,
754 "Matrix.Rotation(): "
755 "cannot create a 2x2 rotation matrix around arbitrary axis");
756 return nullptr;
757 }
758 if (ELEM(matSize, 3, 4) && (axis == nullptr) && (vec == nullptr)) {
759 PyErr_SetString(PyExc_ValueError,
760 "Matrix.Rotation(): "
761 "axis of rotation for 3d and 4d matrices is required");
762 return nullptr;
763 }
764
765 /* check for valid vector/axis above */
766 if (vec) {
767 float tvec[3];
768
770 tvec, 3, 3, vec, "Matrix.Rotation(angle, size, axis), invalid 'axis' arg") == -1)
771 {
772 return nullptr;
773 }
774
775 axis_angle_to_mat3((float (*)[3])mat, tvec, angle);
776 }
777 else if (matSize == 2) {
778 angle_to_mat2((float (*)[2])mat, angle);
779 }
780 else {
781 /* valid axis checked above */
782 axis_angle_to_mat3_single((float (*)[3])mat, axis[0], angle);
783 }
784
785 if (matSize == 4) {
787 }
788 /* pass to matrix creation */
789 return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
790}
791
794 /* Wrap. */
795 C_Matrix_Translation_doc,
796 ".. classmethod:: Translation(vector, /)\n"
797 "\n"
798 " Create a matrix representing a translation.\n"
799 "\n"
800 " :arg vector: The translation vector.\n"
801 " :type vector: :class:`Vector`\n"
802 " :return: An identity matrix with a translation.\n"
803 " :rtype: :class:`Matrix`\n");
804static PyObject *C_Matrix_Translation(PyObject *cls, PyObject *value)
805{
806 float mat[4][4];
807
808 unit_m4(mat);
809
811 mat[3], 3, 4, value, "mathutils.Matrix.Translation(vector), invalid vector arg") == -1)
812 {
813 return nullptr;
814 }
815
816 return Matrix_CreatePyObject(&mat[0][0], 4, 4, (PyTypeObject *)cls);
817}
818
820 /* Wrap. */
821 C_Matrix_Diagonal_doc,
822 ".. classmethod:: Diagonal(vector, /)\n"
823 "\n"
824 " Create a diagonal (scaling) matrix using the values from the vector.\n"
825 "\n"
826 " :arg vector: The vector of values for the diagonal.\n"
827 " :type vector: :class:`Vector`\n"
828 " :return: A diagonal matrix.\n"
829 " :rtype: :class:`Matrix`\n");
831static PyObject *C_Matrix_Diagonal(PyObject *cls, PyObject *value)
832{
833 float mat[16] = {0.0f};
834 float vec[4];
835
837 vec, 2, 4, value, "mathutils.Matrix.Diagonal(vector), invalid vector arg");
838
839 if (size == -1) {
840 return nullptr;
841 }
842
843 for (int i = 0; i < size; i++) {
844 mat[size * i + i] = vec[i];
845 }
846
847 return Matrix_CreatePyObject(mat, size, size, (PyTypeObject *)cls);
848}
849
852 /* Wrap. */
853 C_Matrix_Scale_doc,
854 ".. classmethod:: Scale(factor, size, axis, /)\n"
855 "\n"
856 " Create a matrix representing a scaling.\n"
857 "\n"
858 " :arg factor: The factor of scaling to apply.\n"
859 " :type factor: float\n"
860 " :arg size: The size of the scale matrix to construct [2, 4].\n"
861 " :type size: int\n"
862 " :arg axis: Direction to influence scale. (optional).\n"
863 " :type axis: :class:`Vector`\n"
864 " :return: A new scale matrix.\n"
865 " :rtype: :class:`Matrix`\n");
866static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
867{
868 PyObject *vec = nullptr;
869 int vec_num;
870 float tvec[3];
871 float factor;
872 int matSize;
873 float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
874
875 if (!PyArg_ParseTuple(args, "fi|O:Matrix.Scale", &factor, &matSize, &vec)) {
876 return nullptr;
877 }
878 if (!ELEM(matSize, 2, 3, 4)) {
879 PyErr_SetString(PyExc_ValueError,
880 "Matrix.Scale(): "
881 "can only return a 2x2 3x3 or 4x4 matrix");
882 return nullptr;
883 }
884 if (vec) {
885 vec_num = (matSize == 2 ? 2 : 3);
887 tvec, vec_num, vec_num, vec, "Matrix.Scale(factor, size, axis), invalid 'axis' arg") ==
888 -1)
889 {
890 return nullptr;
891 }
892 }
893 if (vec == nullptr) { /* scaling along axis */
894 if (matSize == 2) {
895 mat[0] = factor;
896 mat[3] = factor;
897 }
898 else {
899 mat[0] = factor;
900 mat[4] = factor;
901 mat[8] = factor;
902 }
903 }
904 else {
905 /* scaling in arbitrary direction
906 * normalize arbitrary axis */
907 float norm = 0.0f;
908 int x;
909 for (x = 0; x < vec_num; x++) {
910 norm += tvec[x] * tvec[x];
911 }
912 norm = sqrtf(norm);
913 for (x = 0; x < vec_num; x++) {
914 tvec[x] /= norm;
915 }
916 if (matSize == 2) {
917 mat[0] = 1 + ((factor - 1) * (tvec[0] * tvec[0]));
918 mat[1] = ((factor - 1) * (tvec[0] * tvec[1]));
919 mat[2] = ((factor - 1) * (tvec[0] * tvec[1]));
920 mat[3] = 1 + ((factor - 1) * (tvec[1] * tvec[1]));
921 }
922 else {
923 mat[0] = 1 + ((factor - 1) * (tvec[0] * tvec[0]));
924 mat[1] = ((factor - 1) * (tvec[0] * tvec[1]));
925 mat[2] = ((factor - 1) * (tvec[0] * tvec[2]));
926 mat[3] = ((factor - 1) * (tvec[0] * tvec[1]));
927 mat[4] = 1 + ((factor - 1) * (tvec[1] * tvec[1]));
928 mat[5] = ((factor - 1) * (tvec[1] * tvec[2]));
929 mat[6] = ((factor - 1) * (tvec[0] * tvec[2]));
930 mat[7] = ((factor - 1) * (tvec[1] * tvec[2]));
931 mat[8] = 1 + ((factor - 1) * (tvec[2] * tvec[2]));
932 }
933 }
934 if (matSize == 4) {
936 }
937 /* pass to matrix creation */
938 return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
939}
940
942 /* Wrap. */
943 C_Matrix_OrthoProjection_doc,
944 ".. classmethod:: OrthoProjection(axis, size, /)\n"
945 "\n"
946 " Create a matrix to represent an orthographic projection.\n"
947 "\n"
948 " :arg axis: An axis string,\n"
949 " where a single axis is for a 2D matrix.\n"
950 " Or a vector for an arbitrary axis\n"
951 " :type axis: Literal['X', 'Y', 'XY', 'XZ', 'YZ'] | :class:`Vector`\n"
952 " :arg size: The size of the projection matrix to construct [2, 4].\n"
953 " :type size: int\n"
954 " :return: A new projection matrix.\n"
955 " :rtype: :class:`Matrix`\n");
956static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
957{
958 PyObject *axis;
959
960 int matSize, x;
961 float norm = 0.0f;
962 float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
963
964 if (!PyArg_ParseTuple(args, "Oi:Matrix.OrthoProjection", &axis, &matSize)) {
965 return nullptr;
966 }
967 if (!ELEM(matSize, 2, 3, 4)) {
968 PyErr_SetString(PyExc_ValueError,
969 "Matrix.OrthoProjection(): "
970 "can only return a 2x2 3x3 or 4x4 matrix");
971 return nullptr;
972 }
973
974 if (PyUnicode_Check(axis)) { /* ortho projection onto cardinal plane */
975 Py_ssize_t plane_len;
976 const char *plane = PyUnicode_AsUTF8AndSize(axis, &plane_len);
977 if (matSize == 2) {
978 if (plane_len == 1 && plane[0] == 'X') {
979 mat[0] = 1.0f;
980 }
981 else if (plane_len == 1 && plane[0] == 'Y') {
982 mat[3] = 1.0f;
983 }
984 else {
985 PyErr_Format(PyExc_ValueError,
986 "Matrix.OrthoProjection(): "
987 "unknown plane, expected: X, Y, not '%.200s'",
988 plane);
989 return nullptr;
990 }
991 }
992 else {
993 if (plane_len == 2 && plane[0] == 'X' && plane[1] == 'Y') {
994 mat[0] = 1.0f;
995 mat[4] = 1.0f;
996 }
997 else if (plane_len == 2 && plane[0] == 'X' && plane[1] == 'Z') {
998 mat[0] = 1.0f;
999 mat[8] = 1.0f;
1000 }
1001 else if (plane_len == 2 && plane[0] == 'Y' && plane[1] == 'Z') {
1002 mat[4] = 1.0f;
1003 mat[8] = 1.0f;
1004 }
1005 else {
1006 PyErr_Format(PyExc_ValueError,
1007 "Matrix.OrthoProjection(): "
1008 "unknown plane, expected: XY, XZ, YZ, not '%.200s'",
1009 plane);
1010 return nullptr;
1011 }
1012 }
1013 }
1014 else {
1015 /* arbitrary plane */
1016
1017 const int vec_num = (matSize == 2 ? 2 : 3);
1018 float tvec[4];
1019
1020 if (mathutils_array_parse(tvec,
1021 vec_num,
1022 vec_num,
1023 axis,
1024 "Matrix.OrthoProjection(axis, size), invalid 'axis' arg") == -1)
1025 {
1026 return nullptr;
1027 }
1028
1029 /* normalize arbitrary axis */
1030 for (x = 0; x < vec_num; x++) {
1031 norm += tvec[x] * tvec[x];
1032 }
1033 norm = sqrtf(norm);
1034 for (x = 0; x < vec_num; x++) {
1035 tvec[x] /= norm;
1036 }
1037 if (matSize == 2) {
1038 mat[0] = 1 - (tvec[0] * tvec[0]);
1039 mat[1] = -(tvec[0] * tvec[1]);
1040 mat[2] = -(tvec[0] * tvec[1]);
1041 mat[3] = 1 - (tvec[1] * tvec[1]);
1042 }
1043 else if (matSize > 2) {
1044 mat[0] = 1 - (tvec[0] * tvec[0]);
1045 mat[1] = -(tvec[0] * tvec[1]);
1046 mat[2] = -(tvec[0] * tvec[2]);
1047 mat[3] = -(tvec[0] * tvec[1]);
1048 mat[4] = 1 - (tvec[1] * tvec[1]);
1049 mat[5] = -(tvec[1] * tvec[2]);
1050 mat[6] = -(tvec[0] * tvec[2]);
1051 mat[7] = -(tvec[1] * tvec[2]);
1052 mat[8] = 1 - (tvec[2] * tvec[2]);
1053 }
1054 }
1055 if (matSize == 4) {
1056 matrix_3x3_as_4x4(mat);
1057 }
1058 /* pass to matrix creation */
1059 return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
1060}
1061
1064 /* Wrap. */
1065 C_Matrix_Shear_doc,
1066 ".. classmethod:: Shear(plane, size, factor, /)\n"
1067 "\n"
1068 " Create a matrix to represent a shear transformation.\n"
1069 "\n"
1070 " :arg plane: An axis string,\n"
1071 " where a single axis is for a 2D matrix only.\n"
1072 " :type plane: Literal['X', 'Y', 'XY', 'XZ', 'YZ']\n"
1073 " :arg size: The size of the shear matrix to construct [2, 4].\n"
1074 " :type size: int\n"
1075 " :arg factor: The factor of shear to apply. "
1076 "For a 2 *size* matrix use a single float. "
1077 "For a 3 or 4 *size* matrix pass a pair of floats corresponding with the *plane* axis.\n"
1078 " :type factor: float | Sequence[float]\n"
1079 " :return: A new shear matrix.\n"
1080 " :rtype: :class:`Matrix`\n");
1081static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args)
1082{
1083 int matSize;
1084 const char *plane;
1085 PyObject *fac;
1086 float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
1087
1088 if (!PyArg_ParseTuple(args, "siO:Matrix.Shear", &plane, &matSize, &fac)) {
1089 return nullptr;
1090 }
1091 if (!ELEM(matSize, 2, 3, 4)) {
1092 PyErr_SetString(PyExc_ValueError,
1093 "Matrix.Shear(): "
1094 "can only return a 2x2 3x3 or 4x4 matrix");
1095 return nullptr;
1096 }
1097
1098 if (matSize == 2) {
1099 float const factor = PyFloat_AsDouble(fac);
1100
1101 if (factor == -1.0f && PyErr_Occurred()) {
1102 PyErr_SetString(PyExc_TypeError,
1103 "Matrix.Shear(): "
1104 "the factor to be a float");
1105 return nullptr;
1106 }
1107
1108 /* unit */
1109 mat[0] = 1.0f;
1110 mat[3] = 1.0f;
1111
1112 if (STREQ(plane, "X")) {
1113 mat[2] = factor;
1114 }
1115 else if (STREQ(plane, "Y")) {
1116 mat[1] = factor;
1117 }
1118 else {
1119 PyErr_SetString(PyExc_ValueError,
1120 "Matrix.Shear(): "
1121 "expected: X, Y or wrong matrix size for shearing plane");
1122 return nullptr;
1123 }
1124 }
1125 else {
1126 /* 3 or 4, apply as 3x3, resize later if needed */
1127 float factor[2];
1128
1129 if (mathutils_array_parse(factor, 2, 2, fac, "Matrix.Shear()") == -1) {
1130 return nullptr;
1131 }
1132
1133 /* unit */
1134 mat[0] = 1.0f;
1135 mat[4] = 1.0f;
1136 mat[8] = 1.0f;
1137
1138 if (STREQ(plane, "XY")) {
1139 mat[6] = factor[0];
1140 mat[7] = factor[1];
1141 }
1142 else if (STREQ(plane, "XZ")) {
1143 mat[3] = factor[0];
1144 mat[5] = factor[1];
1145 }
1146 else if (STREQ(plane, "YZ")) {
1147 mat[1] = factor[0];
1148 mat[2] = factor[1];
1149 }
1150 else {
1151 PyErr_SetString(PyExc_ValueError,
1152 "Matrix.Shear(): "
1153 "expected: X, Y, XY, XZ, YZ");
1154 return nullptr;
1155 }
1156 }
1157
1158 if (matSize == 4) {
1159 matrix_3x3_as_4x4(mat);
1160 }
1161 /* pass to matrix creation */
1162 return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
1163}
1164
1166 /* Wrap. */
1167 C_Matrix_LocRotScale_doc,
1168 ".. classmethod:: LocRotScale(location, rotation, scale, /)\n"
1169 "\n"
1170 " Create a matrix combining translation, rotation and scale,\n"
1171 " acting as the inverse of the decompose() method.\n"
1172 "\n"
1173 " Any of the inputs may be replaced with None if not needed.\n"
1174 "\n"
1175 " :arg location: The translation component.\n"
1176 " :type location: :class:`Vector` | None\n"
1177 " :arg rotation: The rotation component as a "
1178 "3x3 matrix, quaternion, euler or None for no rotation.\n"
1179 " :type rotation: :class:`Matrix` | :class:`Quaternion` | :class:`Euler` | None\n"
1180 " :arg scale: The scale component.\n"
1181 " :type scale: :class:`Vector` | None\n"
1182 " :return: Combined transformation as a 4x4 matrix. \n"
1183 " :rtype: :class:`Matrix`\n");
1184static PyObject *C_Matrix_LocRotScale(PyObject *cls, PyObject *args)
1185{
1186 PyObject *loc_obj, *rot_obj, *scale_obj;
1187 float mat[4][4], loc[3];
1188
1189 if (!PyArg_ParseTuple(args, "OOO:Matrix.LocRotScale", &loc_obj, &rot_obj, &scale_obj)) {
1190 return nullptr;
1191 }
1192
1193 /* Decode location. */
1194 if (loc_obj == Py_None) {
1195 zero_v3(loc);
1196 }
1197 else if (mathutils_array_parse(
1198 loc, 3, 3, loc_obj, "Matrix.LocRotScale(), invalid location argument") == -1)
1199 {
1200 return nullptr;
1201 }
1202
1203 /* Decode rotation. */
1204 if (rot_obj == Py_None) {
1205 unit_m4(mat);
1206 }
1207 else if (QuaternionObject_Check(rot_obj)) {
1208 QuaternionObject *quat_obj = (QuaternionObject *)rot_obj;
1209
1210 if (BaseMath_ReadCallback(quat_obj) == -1) {
1211 return nullptr;
1212 }
1213
1214 quat_to_mat4(mat, quat_obj->quat);
1215 }
1216 else if (EulerObject_Check(rot_obj)) {
1217 EulerObject *eul_obj = (EulerObject *)rot_obj;
1218
1219 if (BaseMath_ReadCallback(eul_obj) == -1) {
1220 return nullptr;
1221 }
1222
1223 eulO_to_mat4(mat, eul_obj->eul, eul_obj->order);
1224 }
1225 else if (MatrixObject_Check(rot_obj)) {
1226 MatrixObject *mat_obj = (MatrixObject *)rot_obj;
1227
1228 if (BaseMath_ReadCallback(mat_obj) == -1) {
1229 return nullptr;
1230 }
1231
1232 if (mat_obj->col_num == 3 && mat_obj->row_num == 3) {
1233 copy_m4_m3(mat, (const float (*)[3])mat_obj->matrix);
1234 }
1235 else {
1236 PyErr_SetString(PyExc_ValueError,
1237 "Matrix.LocRotScale(): "
1238 "inappropriate rotation matrix size - expects 3x3 matrix");
1239 return nullptr;
1240 }
1241 }
1242 else {
1243 PyErr_SetString(PyExc_ValueError,
1244 "Matrix.LocRotScale(): "
1245 "rotation argument must be Matrix, Quaternion, Euler or None");
1246 return nullptr;
1247 }
1248
1249 /* Decode scale. */
1250 if (scale_obj != Py_None) {
1251 float scale[3];
1252
1254 scale, 3, 3, scale_obj, "Matrix.LocRotScale(), invalid scale argument") == -1)
1255 {
1256 return nullptr;
1257 }
1258
1259 rescale_m4(mat, scale);
1260 }
1261
1262 copy_v3_v3(mat[3], loc);
1263
1264 return Matrix_CreatePyObject(&mat[0][0], 4, 4, (PyTypeObject *)cls);
1265}
1266
1268
1269/* -------------------------------------------------------------------- */
1272
1274 /* Wrap. */
1275 Matrix_to_quaternion_doc,
1276 ".. method:: to_quaternion()\n"
1277 "\n"
1278 " Return a quaternion representation of the rotation matrix.\n"
1279 "\n"
1280 " :return: Quaternion representation of the rotation matrix.\n"
1281 " :rtype: :class:`Quaternion`\n");
1283{
1284 float quat[4];
1285
1286 if (BaseMath_ReadCallback(self) == -1) {
1287 return nullptr;
1288 }
1289
1290 /* must be 3-4 cols, 3-4 rows, square matrix */
1291 if ((self->row_num < 3) || (self->col_num < 3) || (self->row_num != self->col_num)) {
1292 PyErr_SetString(PyExc_ValueError,
1293 "Matrix.to_quat(): "
1294 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
1295 return nullptr;
1296 }
1297 if (self->row_num == 3) {
1298 mat3_to_quat(quat, (const float (*)[3])self->matrix);
1299 }
1300 else {
1301 mat4_to_quat(quat, (const float (*)[4])self->matrix);
1302 }
1303 return Quaternion_CreatePyObject(quat, nullptr);
1304}
1305
1307
1308/* -------------------------------------------------------------------- */
1311
1313 /* Wrap. */
1314 Matrix_to_euler_doc,
1315 ".. method:: to_euler(order='XYZ', euler_compat=None, /)\n"
1316 "\n"
1317 " Return an Euler representation of the rotation matrix\n"
1318 " (3x3 or 4x4 matrix only).\n"
1319 "\n"
1320 " :arg order: A rotation order string."
1321 " :type order: Literal['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX']\n"
1322 " :arg euler_compat: Optional euler argument the new euler will be made\n"
1323 " compatible with (no axis flipping between them).\n"
1324 " Useful for converting a series of matrices to animation curves.\n"
1325 " :type euler_compat: :class:`Euler`\n"
1326 " :return: Euler representation of the matrix.\n"
1327 " :rtype: :class:`Euler`\n");
1328static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
1329{
1330 const char *order_str = nullptr;
1331 short order = EULER_ORDER_XYZ;
1332 float eul[3], eul_compatf[3];
1333 EulerObject *eul_compat = nullptr;
1334
1335 float mat[3][3];
1336
1337 if (BaseMath_ReadCallback(self) == -1) {
1338 return nullptr;
1339 }
1340
1341 if (!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat)) {
1342 return nullptr;
1343 }
1344
1345 if (eul_compat) {
1346 if (BaseMath_ReadCallback(eul_compat) == -1) {
1347 return nullptr;
1348 }
1349
1350 copy_v3_v3(eul_compatf, eul_compat->eul);
1351 }
1352
1353 /* Must be 3-4 cols, 3-4 rows, square matrix. */
1354 if (self->row_num == 3 && self->col_num == 3) {
1355 copy_m3_m3(mat, (const float (*)[3])self->matrix);
1356 }
1357 else if (self->row_num == 4 && self->col_num == 4) {
1358 copy_m3_m4(mat, (const float (*)[4])self->matrix);
1359 }
1360 else {
1361 PyErr_SetString(PyExc_ValueError,
1362 "Matrix.to_euler(): "
1363 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
1364 return nullptr;
1365 }
1366
1367 if (order_str) {
1368 order = euler_order_from_string(order_str, "Matrix.to_euler()");
1369
1370 if (order == -1) {
1371 return nullptr;
1372 }
1373 }
1374
1375 normalize_m3(mat);
1376
1377 if (eul_compat) {
1378 if (order == 1) {
1379 mat3_normalized_to_compatible_eul(eul, eul_compatf, mat);
1380 }
1381 else {
1382 mat3_normalized_to_compatible_eulO(eul, eul_compatf, order, mat);
1383 }
1384 }
1385 else {
1386 if (order == 1) {
1387 mat3_normalized_to_eul(eul, mat);
1388 }
1389 else {
1390 mat3_normalized_to_eulO(eul, order, mat);
1391 }
1392 }
1393
1394 return Euler_CreatePyObject(eul, order, nullptr);
1395}
1396
1398
1399/* -------------------------------------------------------------------- */
1402
1404 /* Wrap. */
1405 Matrix_resize_4x4_doc,
1406 ".. method:: resize_4x4()\n"
1407 "\n"
1408 " Resize the matrix to 4x4.\n");
1410{
1411 float mat[4][4];
1412 int col;
1413
1414 if (UNLIKELY(BaseMathObject_Prepare_ForResize(self, "Matrix.resize_4x4()") == -1)) {
1415 /* An exception has been raised. */
1416 return nullptr;
1417 }
1418
1419 self->matrix = static_cast<float *>(
1420 PyMem_Realloc(self->matrix, (sizeof(float) * (MATRIX_MAX_DIM * MATRIX_MAX_DIM))));
1421 if (self->matrix == nullptr) {
1422 PyErr_SetString(PyExc_MemoryError,
1423 "Matrix.resize_4x4(): "
1424 "problem allocating pointer space");
1425 return nullptr;
1426 }
1427
1428 unit_m4(mat);
1429
1430 for (col = 0; col < self->col_num; col++) {
1431 memcpy(mat[col], MATRIX_COL_PTR(self, col), self->row_num * sizeof(float));
1432 }
1433
1434 copy_m4_m4((float (*)[4])self->matrix, (const float (*)[4])mat);
1435
1436 self->col_num = 4;
1437 self->row_num = 4;
1438
1439 Py_RETURN_NONE;
1440}
1441
1443
1444/* -------------------------------------------------------------------- */
1447
1448static PyObject *Matrix_to_NxN(MatrixObject *self, const int col_num, const int row_num)
1449{
1450 const int mat_size = sizeof(float) * (col_num * row_num);
1452 static_cast<float *>(PyMem_Malloc(mat_size)), col_num, row_num, Py_TYPE(self));
1453
1454 if ((self->row_num == row_num) && (self->col_num == col_num)) {
1455 memcpy(pymat->matrix, self->matrix, mat_size);
1456 }
1457 else {
1458 if ((self->col_num < col_num) || (self->row_num < row_num)) {
1459 matrix_unit_internal(pymat);
1460 }
1461 const int col_len_src = min_ii(col_num, self->col_num);
1462 const int row_len_src = min_ii(row_num, self->row_num);
1463 for (int col = 0; col < col_len_src; col++) {
1464 memcpy(
1465 &pymat->matrix[col * row_num], MATRIX_COL_PTR(self, col), sizeof(float) * row_len_src);
1466 }
1467 }
1468 return (PyObject *)pymat;
1469}
1470
1472 /* Wrap. */
1473 Matrix_to_2x2_doc,
1474 ".. method:: to_2x2()\n"
1475 "\n"
1476 " Return a 2x2 copy of this matrix.\n"
1477 "\n"
1478 " :return: a new matrix.\n"
1479 " :rtype: :class:`Matrix`\n");
1481{
1482 if (BaseMath_ReadCallback(self) == -1) {
1483 return nullptr;
1484 }
1485 return Matrix_to_NxN(self, 2, 2);
1486}
1487
1489 /* Wrap. */
1490 Matrix_to_3x3_doc,
1491 ".. method:: to_3x3()\n"
1492 "\n"
1493 " Return a 3x3 copy of this matrix.\n"
1494 "\n"
1495 " :return: a new matrix.\n"
1496 " :rtype: :class:`Matrix`\n");
1498{
1499 if (BaseMath_ReadCallback(self) == -1) {
1500 return nullptr;
1501 }
1502 return Matrix_to_NxN(self, 3, 3);
1503}
1504
1506 /* Wrap. */
1507 Matrix_to_4x4_doc,
1508 ".. method:: to_4x4()\n"
1509 "\n"
1510 " Return a 4x4 copy of this matrix.\n"
1511 "\n"
1512 " :return: a new matrix.\n"
1513 " :rtype: :class:`Matrix`\n");
1515{
1516
1517 if (BaseMath_ReadCallback(self) == -1) {
1518 return nullptr;
1519 }
1520 return Matrix_to_NxN(self, 4, 4);
1521}
1522
1524
1525/* -------------------------------------------------------------------- */
1528
1530 /* Wrap. */
1531 Matrix_to_translation_doc,
1532 ".. method:: to_translation()\n"
1533 "\n"
1534 " Return the translation part of a 4 row matrix.\n"
1535 "\n"
1536 " :return: Return the translation of a matrix.\n"
1537 " :rtype: :class:`Vector`\n");
1539{
1540 if (BaseMath_ReadCallback(self) == -1) {
1541 return nullptr;
1542 }
1543
1544 if ((self->row_num < 3) || self->col_num < 4) {
1545 PyErr_SetString(PyExc_ValueError,
1546 "Matrix.to_translation(): "
1547 "inappropriate matrix size");
1548 return nullptr;
1549 }
1550
1551 return Vector_CreatePyObject(MATRIX_COL_PTR(self, 3), 3, nullptr);
1552}
1553
1555 /* Wrap. */
1556 Matrix_to_scale_doc,
1557 ".. method:: to_scale()\n"
1558 "\n"
1559 " Return the scale part of a 3x3 or 4x4 matrix.\n"
1560 "\n"
1561 " :return: Return the scale of a matrix.\n"
1562 " :rtype: :class:`Vector`\n"
1563 "\n"
1564 " .. note:: This method does not return a negative scale on any axis because it is "
1565 "not possible to obtain this data from the matrix alone.\n");
1567{
1568 float rot[3][3];
1569 float mat[3][3];
1570 float size[3];
1571
1572 if (BaseMath_ReadCallback(self) == -1) {
1573 return nullptr;
1574 }
1575
1576 /* Must be 3-4 cols, 3-4 rows, square matrix. */
1577 if ((self->row_num < 3) || (self->col_num < 3)) {
1578 PyErr_SetString(PyExc_ValueError,
1579 "Matrix.to_scale(): "
1580 "inappropriate matrix size, 3x3 minimum size");
1581 return nullptr;
1582 }
1583
1584 matrix_as_3x3(mat, self);
1585
1586 /* compatible mat4_to_loc_rot_size */
1587 mat3_to_rot_size(rot, size, mat);
1588
1589 return Vector_CreatePyObject(size, 3, nullptr);
1590}
1591
1593
1594/* -------------------------------------------------------------------- */
1597
1600{
1601 if (self->col_num != self->row_num) {
1602 PyErr_SetString(PyExc_ValueError,
1603 "Matrix.invert(ed): "
1604 "only square matrices are supported");
1605 return false;
1606 }
1607
1608 return true;
1609}
1610
1611static bool matrix_invert_args_check(const MatrixObject *self, PyObject *args, bool check_type)
1612{
1613 switch (PyTuple_GET_SIZE(args)) {
1614 case 0: {
1615 return true;
1616 }
1617 case 1: {
1618 if (check_type) {
1619 const MatrixObject *fallback = (const MatrixObject *)PyTuple_GET_ITEM(args, 0);
1620 if (!MatrixObject_Check(fallback)) {
1621 PyErr_SetString(PyExc_TypeError,
1622 "Matrix.invert: "
1623 "expects a matrix argument or nothing");
1624 return false;
1625 }
1626
1627 if ((self->col_num != fallback->col_num) || (self->row_num != fallback->row_num)) {
1628 PyErr_SetString(PyExc_TypeError,
1629 "Matrix.invert: "
1630 "matrix argument has different dimensions");
1631 return false;
1632 }
1633 }
1634
1635 return true;
1636 }
1637 default: {
1638 PyErr_SetString(PyExc_ValueError,
1639 "Matrix.invert(ed): "
1640 "takes at most one argument");
1641 return false;
1642 }
1643 }
1644}
1645
1647{
1648 PyErr_SetString(PyExc_ValueError,
1649 "Matrix.invert(ed): "
1650 "matrix does not have an inverse");
1651}
1652
1654 /* Wrap. */
1655 Matrix_invert_doc,
1656 ".. method:: invert(fallback=None, /)\n"
1657 "\n"
1658 " Set the matrix to its inverse.\n"
1659 "\n"
1660 " :arg fallback: Set the matrix to this value when the inverse cannot be calculated\n"
1661 " (instead of raising a :exc:`ValueError` exception).\n"
1662 " :type fallback: :class:`Matrix`\n"
1663 "\n"
1664 " .. seealso:: `Inverse matrix <https://en.wikipedia.org/wiki/Inverse_matrix>`__ on "
1665 "Wikipedia.\n");
1666static PyObject *Matrix_invert(MatrixObject *self, PyObject *args)
1667{
1669 return nullptr;
1670 }
1671
1672 if (matrix_invert_is_compat(self) == false) {
1673 return nullptr;
1674 }
1675
1676 if (matrix_invert_args_check(self, args, true) == false) {
1677 return nullptr;
1678 }
1679
1680 if (matrix_invert_internal(self, self->matrix)) {
1681 /* pass */
1682 }
1683 else {
1684 if (PyTuple_GET_SIZE(args) == 1) {
1685 MatrixObject *fallback = (MatrixObject *)PyTuple_GET_ITEM(args, 0);
1686
1687 if (BaseMath_ReadCallback(fallback) == -1) {
1688 return nullptr;
1689 }
1690
1691 if (self != fallback) {
1692 matrix_copy(self, fallback);
1693 }
1694 }
1695 else {
1697 return nullptr;
1698 }
1699 }
1700
1702 Py_RETURN_NONE;
1703}
1704
1706 /* Wrap. */
1707 Matrix_inverted_doc,
1708 ".. method:: inverted(fallback=None, /)\n"
1709 "\n"
1710 " Return an inverted copy of the matrix.\n"
1711 "\n"
1712 " :arg fallback: return this when the inverse can't be calculated\n"
1713 " (instead of raising a :exc:`ValueError`).\n"
1714 " :type fallback: Any\n"
1715 " :return: The inverted matrix or fallback when given.\n"
1716 " :rtype: :class:`Matrix` | Any\n");
1717static PyObject *Matrix_inverted(MatrixObject *self, PyObject *args)
1718{
1719 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
1720
1721 if (BaseMath_ReadCallback(self) == -1) {
1722 return nullptr;
1723 }
1724
1725 if (matrix_invert_args_check(self, args, false) == false) {
1726 return nullptr;
1727 }
1728
1729 if (matrix_invert_is_compat(self) == false) {
1730 return nullptr;
1731 }
1732
1733 if (matrix_invert_internal(self, mat)) {
1734 /* pass */
1735 }
1736 else {
1737 if (PyTuple_GET_SIZE(args) == 1) {
1738 PyObject *fallback = PyTuple_GET_ITEM(args, 0);
1739 Py_INCREF(fallback);
1740 return fallback;
1741 }
1742
1744 return nullptr;
1745 }
1746
1747 return Matrix_copy_notest(self, mat);
1748}
1749
1751{
1753 return nullptr;
1754 }
1755
1756 if (matrix_invert_is_compat(self) == false) {
1757 return nullptr;
1758 }
1759
1760 if (matrix_invert_internal(self, self->matrix)) {
1761 /* pass */
1762 }
1763 else {
1765 return nullptr;
1766 }
1767
1769 Py_RETURN_NONE;
1770}
1771
1773 /* Wrap. */
1774 Matrix_invert_safe_doc,
1775 ".. method:: invert_safe()\n"
1776 "\n"
1777 " Set the matrix to its inverse, will never error.\n"
1778 " If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, "
1779 "to get an invertible one.\n"
1780 " If tweaked matrix is still degenerated, set to the identity matrix instead.\n"
1781 "\n"
1782 " .. seealso:: `Inverse Matrix <https://en.wikipedia.org/wiki/Inverse_matrix>`__ on "
1783 "Wikipedia.\n");
1785{
1787 return nullptr;
1788 }
1789
1790 if (matrix_invert_is_compat(self) == false) {
1791 return nullptr;
1792 }
1793
1795
1797 Py_RETURN_NONE;
1798}
1799
1801 /* Wrap. */
1802 Matrix_inverted_safe_doc,
1803 ".. method:: inverted_safe()\n"
1804 "\n"
1805 " Return an inverted copy of the matrix, will never error.\n"
1806 " If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, "
1807 "to get an invertible one.\n"
1808 " If tweaked matrix is still degenerated, return the identity matrix instead.\n"
1809 "\n"
1810 " :return: the inverted matrix.\n"
1811 " :rtype: :class:`Matrix`\n");
1813{
1814 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
1815
1816 if (BaseMath_ReadCallback(self) == -1) {
1817 return nullptr;
1818 }
1819
1820 if (matrix_invert_is_compat(self) == false) {
1821 return nullptr;
1822 }
1823
1825
1826 return Matrix_copy_notest(self, mat);
1827}
1828
1830
1831/* -------------------------------------------------------------------- */
1834
1836 /* Wrap. */
1837 Matrix_adjugate_doc,
1838 ".. method:: adjugate()\n"
1839 "\n"
1840 " Set the matrix to its adjugate.\n"
1841 "\n"
1842 " :raises ValueError: if the matrix cannot be adjugated.\n"
1843 "\n"
1844 " .. seealso:: `Adjugate matrix <https://en.wikipedia.org/wiki/Adjugate_matrix>`__ on "
1845 "Wikipedia.\n");
1847{
1849 return nullptr;
1850 }
1851
1852 if (self->col_num != self->row_num) {
1853 PyErr_SetString(PyExc_ValueError,
1854 "Matrix.adjugate(d): "
1855 "only square matrices are supported");
1856 return nullptr;
1857 }
1858
1859 /* calculate the classical adjoint */
1860 if (self->col_num <= 4) {
1861 adjoint_matrix_n(self->matrix, self->matrix, self->col_num);
1862 }
1863 else {
1864 PyErr_Format(
1865 PyExc_ValueError, "Matrix adjugate(d): size (%d) unsupported", int(self->col_num));
1866 return nullptr;
1867 }
1868
1870 Py_RETURN_NONE;
1871}
1872
1874 /* Wrap. */
1875 Matrix_adjugated_doc,
1876 ".. method:: adjugated()\n"
1877 "\n"
1878 " Return an adjugated copy of the matrix.\n"
1879 "\n"
1880 " :return: the adjugated matrix.\n"
1881 " :rtype: :class:`Matrix`\n"
1882 " :raises ValueError: if the matrix cannot be adjugated\n");
1884{
1886}
1887
1889 /* Wrap. */
1890 Matrix_rotate_doc,
1891 ".. method:: rotate(other, /)\n"
1892 "\n"
1893 " Rotates the matrix by another mathutils value.\n"
1894 "\n"
1895 " :arg other: rotation component of mathutils value\n"
1896 " :type other: :class:`Euler` | :class:`Quaternion` | :class:`Matrix`\n"
1897 "\n"
1898 " .. note:: If any of the columns are not unit length this may not have desired results.\n");
1899static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value)
1900{
1901 float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
1902
1904 return nullptr;
1905 }
1906
1907 if (mathutils_any_to_rotmat(other_rmat, value, "matrix.rotate(value)") == -1) {
1908 return nullptr;
1909 }
1910
1911 if (self->row_num != 3 || self->col_num != 3) {
1912 PyErr_SetString(PyExc_ValueError,
1913 "Matrix.rotate(): "
1914 "must have 3x3 dimensions");
1915 return nullptr;
1916 }
1917
1918 matrix_as_3x3(self_rmat, self);
1919 mul_m3_m3m3(rmat, other_rmat, self_rmat);
1920
1921 copy_m3_m3((float (*)[3])(self->matrix), rmat);
1922
1924 Py_RETURN_NONE;
1925}
1926
1928
1929/* -------------------------------------------------------------------- */
1932
1934 /* Wrap. */
1935 Matrix_decompose_doc,
1936 ".. method:: decompose()\n"
1937 "\n"
1938 " Return the translation, rotation, and scale components of this matrix.\n"
1939 "\n"
1940 " :return: Tuple of translation, rotation, and scale.\n"
1941 " :rtype: tuple[:class:`Vector`, :class:`Quaternion`, :class:`Vector`]\n");
1943{
1944 PyObject *ret;
1945 float loc[3];
1946 float rot[3][3];
1947 float quat[4];
1948 float size[3];
1949
1950 if (self->row_num != 4 || self->col_num != 4) {
1951 PyErr_SetString(PyExc_ValueError,
1952 "Matrix.decompose(): "
1953 "inappropriate matrix size - expects 4x4 matrix");
1954 return nullptr;
1955 }
1956
1957 if (BaseMath_ReadCallback(self) == -1) {
1958 return nullptr;
1959 }
1960
1961 mat4_to_loc_rot_size(loc, rot, size, (const float (*)[4])self->matrix);
1963
1964 ret = PyTuple_New(3);
1966 Vector_CreatePyObject(loc, 3, nullptr),
1967 Quaternion_CreatePyObject(quat, nullptr),
1968 Vector_CreatePyObject(size, 3, nullptr));
1969 return ret;
1970}
1971
1973
1974/* -------------------------------------------------------------------- */
1977
1979 /* Wrap. */
1980 Matrix_lerp_doc,
1981 ".. function:: lerp(other, factor, /)\n"
1982 "\n"
1983 " Returns the interpolation of two matrices. Uses polar decomposition, see"
1984 " \"Matrix Animation and Polar Decomposition\", Shoemake and Duff, 1992.\n"
1985 "\n"
1986 " :arg other: value to interpolate with.\n"
1987 " :type other: :class:`Matrix`\n"
1988 " :arg factor: The interpolation value in [0.0, 1.0].\n"
1989 " :type factor: float\n"
1990 " :return: The interpolated matrix.\n"
1991 " :rtype: :class:`Matrix`\n");
1992static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
1993{
1994 MatrixObject *mat2 = nullptr;
1995 float fac, mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
1996
1997 if (!PyArg_ParseTuple(args, "O!f:lerp", &matrix_Type, &mat2, &fac)) {
1998 return nullptr;
1999 }
2000
2001 if (self->col_num != mat2->col_num || self->row_num != mat2->row_num) {
2002 PyErr_SetString(PyExc_ValueError,
2003 "Matrix.lerp(): "
2004 "expects both matrix objects of the same dimensions");
2005 return nullptr;
2006 }
2007
2008 if (BaseMath_ReadCallback(self) == -1 || BaseMath_ReadCallback(mat2) == -1) {
2009 return nullptr;
2010 }
2011
2012 /* TODO: different sized matrix. */
2013 if (self->col_num == 4 && self->row_num == 4) {
2014#ifdef MATH_STANDALONE
2015 blend_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac);
2016#else
2017 interp_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac);
2018#endif
2019 }
2020 else if (self->col_num == 3 && self->row_num == 3) {
2021#ifdef MATH_STANDALONE
2022 blend_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac);
2023#else
2024 interp_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac);
2025#endif
2026 }
2027 else {
2028 PyErr_SetString(PyExc_ValueError,
2029 "Matrix.lerp(): "
2030 "only 3x3 and 4x4 matrices supported");
2031 return nullptr;
2032 }
2033
2034 return Matrix_CreatePyObject(mat, self->col_num, self->row_num, Py_TYPE(self));
2035}
2036
2038 /* Wrap. */
2039 Matrix_determinant_doc,
2040 ".. method:: determinant()\n"
2041 "\n"
2042 " Return the determinant of a matrix.\n"
2043 "\n"
2044 " :return: Return the determinant of a matrix.\n"
2045 " :rtype: float\n"
2046 "\n"
2047 " .. seealso:: `Determinant <https://en.wikipedia.org/wiki/Determinant>`__ on Wikipedia.\n");
2049{
2050 if (BaseMath_ReadCallback(self) == -1) {
2051 return nullptr;
2052 }
2053
2054 if (self->col_num != self->row_num) {
2055 PyErr_SetString(PyExc_ValueError,
2056 "Matrix.determinant(): "
2057 "only square matrices are supported");
2058 return nullptr;
2059 }
2060
2061 return PyFloat_FromDouble(double(matrix_determinant_internal(self)));
2062}
2063
2065
2066/* -------------------------------------------------------------------- */
2069
2071 /* Wrap. */
2072 Matrix_transpose_doc,
2073 ".. method:: transpose()\n"
2074 "\n"
2075 " Set the matrix to its transpose.\n"
2076 "\n"
2077 " .. seealso:: `Transpose <https://en.wikipedia.org/wiki/Transpose>`__ on Wikipedia.\n");
2079{
2081 return nullptr;
2082 }
2083
2084 if (self->col_num != self->row_num) {
2085 PyErr_SetString(PyExc_ValueError,
2086 "Matrix.transpose(d): "
2087 "only square matrices are supported");
2088 return nullptr;
2089 }
2090
2091 if (self->col_num == 2) {
2092 const float t = MATRIX_ITEM(self, 1, 0);
2093 MATRIX_ITEM(self, 1, 0) = MATRIX_ITEM(self, 0, 1);
2094 MATRIX_ITEM(self, 0, 1) = t;
2095 }
2096 else if (self->col_num == 3) {
2097 transpose_m3((float (*)[3])self->matrix);
2098 }
2099 else {
2100 transpose_m4((float (*)[4])self->matrix);
2101 }
2102
2104 Py_RETURN_NONE;
2105}
2106
2108 /* Wrap. */
2109 Matrix_transposed_doc,
2110 ".. method:: transposed()\n"
2111 "\n"
2112 " Return a new, transposed matrix.\n"
2113 "\n"
2114 " :return: a transposed matrix\n"
2115 " :rtype: :class:`Matrix`\n");
2120
2122
2123/* -------------------------------------------------------------------- */
2126
2128 /* Wrap. */
2129 Matrix_normalize_doc,
2130 ".. method:: normalize()\n"
2131 "\n"
2132 " Normalize each of the matrix columns.\n"
2133 "\n"
2134 " .. note:: for 4x4 matrices, the 4th column (translation) is left untouched.\n");
2136{
2138 return nullptr;
2139 }
2140
2141 if (self->col_num != self->row_num) {
2142 PyErr_SetString(PyExc_ValueError,
2143 "Matrix.normalize(): "
2144 "only square matrices are supported");
2145 return nullptr;
2146 }
2147
2148 if (self->col_num == 3) {
2149 normalize_m3((float (*)[3])self->matrix);
2150 }
2151 else if (self->col_num == 4) {
2152 normalize_m4((float (*)[4])self->matrix);
2153 }
2154 else {
2155 PyErr_SetString(PyExc_ValueError,
2156 "Matrix.normalize(): "
2157 "can only use a 3x3 or 4x4 matrix");
2158 }
2159
2161 Py_RETURN_NONE;
2162}
2163
2165 /* Wrap. */
2166 Matrix_normalized_doc,
2167 ".. method:: normalized()\n"
2168 "\n"
2169 " Return a column normalized matrix\n"
2170 "\n"
2171 " :return: a column normalized matrix\n"
2172 " :rtype: :class:`Matrix`\n"
2173 "\n"
2174 " .. note:: for 4x4 matrices, the 4th column (translation) is left untouched.\n");
2179
2181
2182/* -------------------------------------------------------------------- */
2185
2187 /* Wrap. */
2188 Matrix_zero_doc,
2189 ".. method:: zero()\n"
2190 "\n"
2191 " Set all the matrix values to zero.\n");
2193{
2194 if (BaseMath_Prepare_ForWrite(self) == -1) {
2195 return nullptr;
2196 }
2197
2198 copy_vn_fl(self->matrix, self->col_num * self->row_num, 0.0f);
2199
2200 if (BaseMath_WriteCallback(self) == -1) {
2201 return nullptr;
2202 }
2203
2204 Py_RETURN_NONE;
2205}
2206
2208
2209/* -------------------------------------------------------------------- */
2212
2214{
2215 BLI_assert((self->col_num == self->row_num) && (self->row_num <= 4));
2216
2217 if (self->col_num == 2) {
2218 unit_m2((float (*)[2])self->matrix);
2219 }
2220 else if (self->col_num == 3) {
2221 unit_m3((float (*)[3])self->matrix);
2222 }
2223 else {
2224 unit_m4((float (*)[4])self->matrix);
2225 }
2226}
2227
2229 /* Wrap. */
2230 Matrix_identity_doc,
2231 ".. method:: identity()\n"
2232 "\n"
2233 " Set the matrix to the identity matrix.\n"
2234 "\n"
2235 " .. note:: An object with a location and rotation of zero, and a scale of one\n"
2236 " will have an identity matrix.\n"
2237 "\n"
2238 " .. seealso:: `Identity matrix <https://en.wikipedia.org/wiki/Identity_matrix>`__ "
2239 "on Wikipedia.\n");
2241{
2243 return nullptr;
2244 }
2245
2246 if (self->col_num != self->row_num) {
2247 PyErr_SetString(PyExc_ValueError,
2248 "Matrix.identity(): "
2249 "only square matrices are supported");
2250 return nullptr;
2251 }
2252
2254
2255 if (BaseMath_WriteCallback(self) == -1) {
2256 return nullptr;
2257 }
2258
2259 Py_RETURN_NONE;
2260}
2261
2263
2264/* -------------------------------------------------------------------- */
2267
2269static PyObject *Matrix_copy_notest(MatrixObject *self, const float *matrix)
2270{
2271 return Matrix_CreatePyObject(matrix, self->col_num, self->row_num, Py_TYPE(self));
2272}
2273
2275 /* Wrap. */
2276 Matrix_copy_doc,
2277 ".. method:: copy()\n"
2278 "\n"
2279 " Returns a copy of this matrix.\n"
2280 "\n"
2281 " :return: an instance of itself\n"
2282 " :rtype: :class:`Matrix`\n");
2284{
2285 if (BaseMath_ReadCallback(self) == -1) {
2286 return nullptr;
2287 }
2288
2289 return Matrix_copy_notest(self, self->matrix);
2290}
2291
2293static PyObject *Matrix_deepcopy(MatrixObject *self, PyObject *args)
2294{
2295 if (!PyC_CheckArgs_DeepCopy(args)) {
2296 return nullptr;
2297 }
2298 return Matrix_copy(self);
2299}
2300
2302
2303/* -------------------------------------------------------------------- */
2306
2308{
2309 int col, row;
2310 PyObject *rows[MATRIX_MAX_DIM] = {nullptr};
2311
2312 if (BaseMath_ReadCallback(self) == -1) {
2313 return nullptr;
2314 }
2315
2316 for (row = 0; row < self->row_num; row++) {
2317 rows[row] = PyTuple_New(self->col_num);
2318 for (col = 0; col < self->col_num; col++) {
2319 PyTuple_SET_ITEM(rows[row], col, PyFloat_FromDouble(MATRIX_ITEM(self, row, col)));
2320 }
2321 }
2322 switch (self->row_num) {
2323 case 2: {
2324 return PyUnicode_FromFormat(
2325 "Matrix((%R,\n"
2326 " %R))",
2327 rows[0],
2328 rows[1]);
2329 }
2330 case 3: {
2331 return PyUnicode_FromFormat(
2332 "Matrix((%R,\n"
2333 " %R,\n"
2334 " %R))",
2335 rows[0],
2336 rows[1],
2337 rows[2]);
2338 }
2339 case 4: {
2340 return PyUnicode_FromFormat(
2341 "Matrix((%R,\n"
2342 " %R,\n"
2343 " %R,\n"
2344 " %R))",
2345 rows[0],
2346 rows[1],
2347 rows[2],
2348 rows[3]);
2349 }
2350 }
2351
2352 Py_FatalError("Matrix(): invalid row size!");
2353 return nullptr;
2354}
2355
2356#ifndef MATH_STANDALONE
2357static PyObject *Matrix_str(MatrixObject *self)
2358{
2359 DynStr *ds;
2360
2361 int maxsize[MATRIX_MAX_DIM];
2362 int row, col;
2363
2364 char dummy_buf[64];
2365
2366 if (BaseMath_ReadCallback(self) == -1) {
2367 return nullptr;
2368 }
2369
2370 ds = BLI_dynstr_new();
2371
2372 /* First determine the maximum width for each column */
2373 for (col = 0; col < self->col_num; col++) {
2374 maxsize[col] = 0;
2375 for (row = 0; row < self->row_num; row++) {
2376 const int size = SNPRINTF_UTF8_RLEN(dummy_buf, "%.4f", MATRIX_ITEM(self, row, col));
2377 maxsize[col] = max_ii(maxsize[col], size);
2378 }
2379 }
2380
2381 /* Now write the unicode string to be printed */
2382 BLI_dynstr_appendf(ds, "<Matrix %dx%d (", self->row_num, self->col_num);
2383 for (row = 0; row < self->row_num; row++) {
2384 for (col = 0; col < self->col_num; col++) {
2385 BLI_dynstr_appendf(ds, col ? ", %*.4f" : "%*.4f", maxsize[col], MATRIX_ITEM(self, row, col));
2386 }
2387 BLI_dynstr_append(ds, row + 1 != self->row_num ? ")\n (" : ")");
2388 }
2389 BLI_dynstr_append(ds, ">");
2390
2391 return mathutils_dynstr_to_py(ds); /* frees ds */
2392}
2393#endif
2394
2396
2397/* -------------------------------------------------------------------- */
2400
2401static int Matrix_getbuffer(PyObject *obj, Py_buffer *view, int flags)
2402{
2403 MatrixObject *self = (MatrixObject *)obj;
2404 if (UNLIKELY(BaseMath_Prepare_ForBufferAccess(self, view, flags) == -1)) {
2405 return -1;
2406 }
2407 if (UNLIKELY(BaseMath_ReadCallback(self) == -1)) {
2408 return -1;
2409 }
2410
2411 memset(view, 0, sizeof(*view));
2412
2413 view->obj = (PyObject *)self;
2414 view->buf = (void *)self->matrix;
2415 view->len = Py_ssize_t(self->row_num * self->col_num * sizeof(float));
2416 view->itemsize = sizeof(float);
2417 if ((flags & PyBUF_WRITABLE) == 0) {
2418 view->readonly = 1;
2419 }
2420 if (flags & PyBUF_FORMAT) {
2421 view->format = (char *)"f";
2422 }
2423 if (flags & PyBUF_ND) {
2424 view->ndim = 2;
2425 view->shape = MEM_malloc_arrayN<Py_ssize_t>(size_t(view->ndim), __func__);
2426 view->shape[0] = self->row_num;
2427 view->shape[1] = self->col_num;
2428 }
2429 if (flags & PyBUF_STRIDES) {
2430 view->strides = MEM_malloc_arrayN<Py_ssize_t>(size_t(view->ndim), __func__);
2431 view->strides[0] = sizeof(float); /* step between lines in column-major */
2432 view->strides[1] = Py_ssize_t(self->row_num) * sizeof(float); /* step between columns */
2433 }
2434
2436
2437 Py_INCREF(self);
2438 return 0;
2439}
2440
2441static void Matrix_releasebuffer(PyObject * /*exporter*/, Py_buffer *view)
2442{
2445
2446 if (view->readonly == 0) {
2447 if (UNLIKELY(BaseMath_WriteCallback(self) == -1)) {
2448 PyErr_Print();
2449 }
2450 }
2451 MEM_SAFE_FREE(view->shape);
2452 MEM_SAFE_FREE(view->strides);
2453}
2454
2455static PyBufferProcs Matrix_as_buffer = {
2456 (getbufferproc)Matrix_getbuffer,
2457 (releasebufferproc)Matrix_releasebuffer,
2458};
2459
2461
2462/* -------------------------------------------------------------------- */
2465
2466static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
2467{
2468 PyObject *res;
2469 int ok = -1; /* zero is true */
2470
2472 MatrixObject *matA = (MatrixObject *)a;
2473 MatrixObject *matB = (MatrixObject *)b;
2474
2475 if (BaseMath_ReadCallback(matA) == -1 || BaseMath_ReadCallback(matB) == -1) {
2476 return nullptr;
2477 }
2478
2479 ok = ((matA->row_num == matB->row_num) && (matA->col_num == matB->col_num) &&
2480 EXPP_VectorsAreEqual(matA->matrix, matB->matrix, (matA->col_num * matA->row_num), 1)) ?
2481 0 :
2482 -1;
2483 }
2484
2485 switch (op) {
2486 case Py_NE: {
2487 ok = !ok;
2489 }
2490 case Py_EQ: {
2491 res = ok ? Py_False : Py_True;
2492 break;
2493 }
2494 case Py_LT:
2495 case Py_LE:
2496 case Py_GT:
2497 case Py_GE: {
2498 res = Py_NotImplemented;
2499 break;
2500 }
2501 default: {
2502 PyErr_BadArgument();
2503 return nullptr;
2504 }
2505 }
2506
2507 return Py_NewRef(res);
2508}
2509
2511
2512/* -------------------------------------------------------------------- */
2515
2517{
2518 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2519
2520 if (BaseMath_ReadCallback(self) == -1) {
2521 return -1;
2522 }
2523
2525 return -1;
2526 }
2527
2529
2530 return mathutils_array_hash(mat, self->row_num * self->col_num);
2531}
2532
2534
2535/* -------------------------------------------------------------------- */
2538
2540static Py_ssize_t Matrix_len(MatrixObject *self)
2541{
2542 return self->row_num;
2543}
2544
2549static PyObject *Matrix_item_row(MatrixObject *self, Py_ssize_t row)
2550{
2552 return nullptr;
2553 }
2554
2555 if (row < 0 || row >= self->row_num) {
2556 PyErr_SetString(PyExc_IndexError,
2557 "matrix[attribute]: "
2558 "array index out of range");
2559 return nullptr;
2560 }
2562 (PyObject *)self, self->col_num, mathutils_matrix_row_cb_index, row);
2563}
2564
2568static PyObject *Matrix_item_col(MatrixObject *self, Py_ssize_t col)
2569{
2571 return nullptr;
2572 }
2573
2574 if (col < 0 || col >= self->col_num) {
2575 PyErr_SetString(PyExc_IndexError,
2576 "matrix[attribute]: "
2577 "array index out of range");
2578 return nullptr;
2579 }
2581 (PyObject *)self, self->row_num, mathutils_matrix_col_cb_index, col);
2582}
2583
2585static int Matrix_ass_item_row(MatrixObject *self, Py_ssize_t row, PyObject *value)
2586{
2587 int col;
2588 float vec[MATRIX_MAX_DIM];
2590 return -1;
2591 }
2592
2593 if (row >= self->row_num || row < 0) {
2594 PyErr_SetString(PyExc_IndexError, "matrix[attribute] = x: bad row");
2595 return -1;
2596 }
2597
2599 vec, self->col_num, self->col_num, value, "matrix[i] = value assignment") == -1)
2600 {
2601 return -1;
2602 }
2603
2604 /* Since we are assigning a row we cannot memcpy */
2605 for (col = 0; col < self->col_num; col++) {
2606 MATRIX_ITEM(self, row, col) = vec[col];
2607 }
2608
2610 return 0;
2611}
2612
2614static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value)
2615{
2616 int row;
2617 float vec[MATRIX_MAX_DIM];
2619 return -1;
2620 }
2621
2622 if (col >= self->col_num || col < 0) {
2623 PyErr_SetString(PyExc_IndexError, "matrix[attribute] = x: bad col");
2624 return -1;
2625 }
2626
2628 vec, self->row_num, self->row_num, value, "matrix[i] = value assignment") == -1)
2629 {
2630 return -1;
2631 }
2632
2633 /* Since we are assigning a row we cannot memcpy */
2634 for (row = 0; row < self->row_num; row++) {
2635 MATRIX_ITEM(self, row, col) = vec[row];
2636 }
2637
2639 return 0;
2640}
2641
2643static PyObject *Matrix_slice(MatrixObject *self, int begin, int end)
2644{
2645
2646 PyObject *tuple;
2647 int count;
2648
2649 if (BaseMath_ReadCallback(self) == -1) {
2650 return nullptr;
2651 }
2652
2653 CLAMP(begin, 0, self->row_num);
2654 CLAMP(end, 0, self->row_num);
2655 begin = std::min(begin, end);
2656
2657 tuple = PyTuple_New(end - begin);
2658 for (count = begin; count < end; count++) {
2659 PyTuple_SET_ITEM(tuple,
2660 count - begin,
2662 (PyObject *)self, self->col_num, mathutils_matrix_row_cb_index, count));
2663 }
2664
2665 return tuple;
2666}
2667
2669static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value)
2670{
2671 PyObject *value_fast;
2672
2674 return -1;
2675 }
2676
2677 CLAMP(begin, 0, self->row_num);
2678 CLAMP(end, 0, self->row_num);
2679 begin = std::min(begin, end);
2680
2681 /* non list/tuple cases */
2682 if (!(value_fast = PySequence_Fast(value, "matrix[begin:end] = value"))) {
2683 /* PySequence_Fast sets the error */
2684 return -1;
2685 }
2686
2687 PyObject **value_fast_items = PySequence_Fast_ITEMS(value_fast);
2688 const int size = end - begin;
2689 int row, col;
2690 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2691 float vec[4];
2692
2693 if (PySequence_Fast_GET_SIZE(value_fast) != size) {
2694 Py_DECREF(value_fast);
2695 PyErr_SetString(PyExc_ValueError,
2696 "matrix[begin:end] = []: "
2697 "size mismatch in slice assignment");
2698 return -1;
2699 }
2700
2701 memcpy(mat, self->matrix, self->col_num * self->row_num * sizeof(float));
2702
2703 /* parse sub items */
2704 for (row = begin; row < end; row++) {
2705 /* parse each sub sequence */
2706 PyObject *item = value_fast_items[row - begin];
2707
2709 vec, self->col_num, self->col_num, item, "matrix[begin:end] = value assignment") == -1)
2710 {
2711 Py_DECREF(value_fast);
2712 return -1;
2713 }
2714
2715 for (col = 0; col < self->col_num; col++) {
2716 mat[col * self->row_num + row] = vec[col];
2717 }
2718 }
2719
2720 Py_DECREF(value_fast);
2721
2722 /* Parsed well - now set in matrix. */
2723 memcpy(self->matrix, mat, self->col_num * self->row_num * sizeof(float));
2724
2726 return 0;
2727}
2728
2730static PyObject *Matrix_subscript(MatrixObject *self, PyObject *item)
2731{
2732 if (PyIndex_Check(item)) {
2733 Py_ssize_t i;
2734 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2735 if (i == -1 && PyErr_Occurred()) {
2736 return nullptr;
2737 }
2738 if (i < 0) {
2739 i += self->row_num;
2740 }
2741 return Matrix_item_row(self, i);
2742 }
2743 if (PySlice_Check(item)) {
2744 Py_ssize_t start, stop, step, slicelength;
2745
2746 if (PySlice_GetIndicesEx(item, self->row_num, &start, &stop, &step, &slicelength) < 0) {
2747 return nullptr;
2748 }
2749
2750 if (slicelength <= 0) {
2751 return PyTuple_New(0);
2752 }
2753 if (step == 1) {
2754 return Matrix_slice(self, start, stop);
2755 }
2756
2757 PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrices");
2758 return nullptr;
2759 }
2760
2761 PyErr_Format(
2762 PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
2763 return nullptr;
2764}
2765
2767static int Matrix_ass_subscript(MatrixObject *self, PyObject *item, PyObject *value)
2768{
2769 if (PyIndex_Check(item)) {
2770 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2771 if (i == -1 && PyErr_Occurred()) {
2772 return -1;
2773 }
2774 if (i < 0) {
2775 i += self->row_num;
2776 }
2777 return Matrix_ass_item_row(self, i, value);
2778 }
2779 if (PySlice_Check(item)) {
2780 Py_ssize_t start, stop, step, slicelength;
2781
2782 if (PySlice_GetIndicesEx(item, self->row_num, &start, &stop, &step, &slicelength) < 0) {
2783 return -1;
2784 }
2785
2786 if (step == 1) {
2787 return Matrix_ass_slice(self, start, stop, value);
2788 }
2789
2790 PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrices");
2791 return -1;
2792 }
2793
2794 PyErr_Format(
2795 PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
2796 return -1;
2797}
2798
2800
2801/* -------------------------------------------------------------------- */
2804
2806static PyObject *Matrix_add(PyObject *m1, PyObject *m2)
2807{
2808 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2809 MatrixObject *mat1 = nullptr, *mat2 = nullptr;
2810
2811 mat1 = (MatrixObject *)m1;
2812 mat2 = (MatrixObject *)m2;
2813
2814 if (!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
2815 PyErr_Format(PyExc_TypeError,
2816 "Matrix addition: (%s + %s) "
2817 "invalid type for this operation",
2818 Py_TYPE(m1)->tp_name,
2819 Py_TYPE(m2)->tp_name);
2820 return nullptr;
2821 }
2822
2823 if (BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1) {
2824 return nullptr;
2825 }
2826
2827 if (mat1->col_num != mat2->col_num || mat1->row_num != mat2->row_num) {
2828 PyErr_SetString(PyExc_ValueError,
2829 "Matrix addition: "
2830 "matrices must have the same dimensions for this operation");
2831 return nullptr;
2832 }
2833
2834 add_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->col_num * mat1->row_num);
2835
2836 return Matrix_CreatePyObject(mat, mat1->col_num, mat1->row_num, Py_TYPE(mat1));
2837}
2838
2840static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
2841{
2842 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2843 MatrixObject *mat1 = nullptr, *mat2 = nullptr;
2844
2845 mat1 = (MatrixObject *)m1;
2846 mat2 = (MatrixObject *)m2;
2847
2848 if (!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
2849 PyErr_Format(PyExc_TypeError,
2850 "Matrix subtraction: (%s - %s) "
2851 "invalid type for this operation",
2852 Py_TYPE(m1)->tp_name,
2853 Py_TYPE(m2)->tp_name);
2854 return nullptr;
2855 }
2856
2857 if (BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1) {
2858 return nullptr;
2859 }
2860
2861 if (mat1->col_num != mat2->col_num || mat1->row_num != mat2->row_num) {
2862 PyErr_SetString(PyExc_ValueError,
2863 "Matrix addition: "
2864 "matrices must have the same dimensions for this operation");
2865 return nullptr;
2866 }
2867
2868 sub_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->col_num * mat1->row_num);
2869
2870 return Matrix_CreatePyObject(mat, mat1->col_num, mat1->row_num, Py_TYPE(mat1));
2871}
2872
2874static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
2875{
2876 float tmat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2877 mul_vn_vn_fl(tmat, mat->matrix, mat->col_num * mat->row_num, scalar);
2878 return Matrix_CreatePyObject(tmat, mat->col_num, mat->row_num, Py_TYPE(mat));
2879}
2880
2881static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
2882{
2883 float scalar;
2884
2885 MatrixObject *mat1 = nullptr, *mat2 = nullptr;
2886
2887 if (MatrixObject_Check(m1)) {
2888 mat1 = (MatrixObject *)m1;
2889 if (BaseMath_ReadCallback(mat1) == -1) {
2890 return nullptr;
2891 }
2892 }
2893 if (MatrixObject_Check(m2)) {
2894 mat2 = (MatrixObject *)m2;
2895 if (BaseMath_ReadCallback(mat2) == -1) {
2896 return nullptr;
2897 }
2898 }
2899
2900 if (mat1 && mat2) {
2901 /* MATRIX * MATRIX */
2902 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
2903
2904 if ((mat1->row_num != mat2->row_num) || (mat1->col_num != mat2->col_num)) {
2905 PyErr_SetString(PyExc_ValueError,
2906 "matrix1 * matrix2: matrix1 number of rows/columns "
2907 "and the matrix2 number of rows/columns must be the same");
2908 return nullptr;
2909 }
2910
2911 mul_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->col_num * mat1->row_num);
2912
2913 return Matrix_CreatePyObject(mat, mat2->col_num, mat1->row_num, Py_TYPE(mat1));
2914 }
2915 if (mat2) {
2916 /* FLOAT/INT * MATRIX */
2917 if (((scalar = PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred()) == 0) {
2918 return matrix_mul_float(mat2, scalar);
2919 }
2920 }
2921 else if (mat1) {
2922 /* MATRIX * FLOAT/INT */
2923 if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) {
2924 return matrix_mul_float(mat1, scalar);
2925 }
2926 }
2927
2928 PyErr_Format(PyExc_TypeError,
2929 "Element-wise multiplication: "
2930 "not supported between '%.200s' and '%.200s' types",
2931 Py_TYPE(m1)->tp_name,
2932 Py_TYPE(m2)->tp_name);
2933 return nullptr;
2934}
2935
2937static PyObject *Matrix_imul(PyObject *m1, PyObject *m2)
2938{
2939 float scalar;
2940
2941 MatrixObject *mat1 = nullptr, *mat2 = nullptr;
2942
2943 if (MatrixObject_Check(m1)) {
2944 mat1 = (MatrixObject *)m1;
2945 if (BaseMath_ReadCallback(mat1) == -1) {
2946 return nullptr;
2947 }
2948 }
2949 if (MatrixObject_Check(m2)) {
2950 mat2 = (MatrixObject *)m2;
2951 if (BaseMath_ReadCallback(mat2) == -1) {
2952 return nullptr;
2953 }
2954 }
2955
2956 if (mat1 && mat2) {
2957 /* MATRIX *= MATRIX */
2958 if ((mat1->row_num != mat2->row_num) || (mat1->col_num != mat2->col_num)) {
2959 PyErr_SetString(PyExc_ValueError,
2960 "matrix1 *= matrix2: matrix1 number of rows/columns "
2961 "and the matrix2 number of rows/columns must be the same");
2962 return nullptr;
2963 }
2964
2965 mul_vn_vn(mat1->matrix, mat2->matrix, mat1->col_num * mat1->row_num);
2966 }
2967 else if (mat1 && (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0)) {
2968 /* MATRIX *= FLOAT/INT */
2969 mul_vn_fl(mat1->matrix, mat1->row_num * mat1->col_num, scalar);
2970 }
2971 else {
2972 PyErr_Format(PyExc_TypeError,
2973 "In place element-wise multiplication: "
2974 "not supported between '%.200s' and '%.200s' types",
2975 Py_TYPE(m1)->tp_name,
2976 Py_TYPE(m2)->tp_name);
2977 return nullptr;
2978 }
2979
2980 (void)BaseMath_WriteCallback(mat1);
2981 Py_INCREF(m1);
2982 return m1;
2983}
2984
2986static PyObject *Matrix_matmul(PyObject *m1, PyObject *m2)
2987{
2988 int vec_num;
2989
2990 MatrixObject *mat1 = nullptr, *mat2 = nullptr;
2991
2992 if (MatrixObject_Check(m1)) {
2993 mat1 = (MatrixObject *)m1;
2994 if (BaseMath_ReadCallback(mat1) == -1) {
2995 return nullptr;
2996 }
2997 }
2998 if (MatrixObject_Check(m2)) {
2999 mat2 = (MatrixObject *)m2;
3000 if (BaseMath_ReadCallback(mat2) == -1) {
3001 return nullptr;
3002 }
3003 }
3004
3005 if (mat1 && mat2) {
3006 /* MATRIX @ MATRIX */
3007 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
3008
3009 int col, row, item;
3010
3011 if (mat1->col_num != mat2->row_num) {
3012 PyErr_SetString(PyExc_ValueError,
3013 "matrix1 * matrix2: matrix1 number of columns "
3014 "and the matrix2 number of rows must be the same");
3015 return nullptr;
3016 }
3017
3018 for (col = 0; col < mat2->col_num; col++) {
3019 for (row = 0; row < mat1->row_num; row++) {
3020 double dot = 0.0f;
3021 for (item = 0; item < mat1->col_num; item++) {
3022 dot += double(MATRIX_ITEM(mat1, row, item) * MATRIX_ITEM(mat2, item, col));
3023 }
3024 mat[(col * mat1->row_num) + row] = float(dot);
3025 }
3026 }
3027
3028 return Matrix_CreatePyObject(mat, mat2->col_num, mat1->row_num, Py_TYPE(mat1));
3029 }
3030 if (mat1) {
3031 /* MATRIX @ VECTOR */
3032 if (VectorObject_Check(m2)) {
3033 VectorObject *vec2 = (VectorObject *)m2;
3034 float tvec[MATRIX_MAX_DIM];
3035 if (BaseMath_ReadCallback(vec2) == -1) {
3036 return nullptr;
3037 }
3038 if (column_vector_multiplication(tvec, vec2, mat1) == -1) {
3039 return nullptr;
3040 }
3041
3042 if (mat1->col_num == 4 && vec2->vec_num == 3) {
3043 vec_num = 3;
3044 }
3045 else {
3046 vec_num = mat1->row_num;
3047 }
3048
3049 return Vector_CreatePyObject(tvec, vec_num, Py_TYPE(m2));
3050 }
3051 }
3052
3053 PyErr_Format(PyExc_TypeError,
3054 "Matrix multiplication: "
3055 "not supported between '%.200s' and '%.200s' types",
3056 Py_TYPE(m1)->tp_name,
3057 Py_TYPE(m2)->tp_name);
3058 return nullptr;
3059}
3060
3062static PyObject *Matrix_imatmul(PyObject *m1, PyObject *m2)
3063{
3064 MatrixObject *mat1 = nullptr, *mat2 = nullptr;
3065
3066 if (MatrixObject_Check(m1)) {
3067 mat1 = (MatrixObject *)m1;
3068 if (BaseMath_ReadCallback(mat1) == -1) {
3069 return nullptr;
3070 }
3071 }
3072 if (MatrixObject_Check(m2)) {
3073 mat2 = (MatrixObject *)m2;
3074 if (BaseMath_ReadCallback(mat2) == -1) {
3075 return nullptr;
3076 }
3077 }
3078
3079 if (mat1 && mat2) {
3080 /* MATRIX @= MATRIX */
3081 float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
3082 int col, row, item;
3083
3084 if (mat1->col_num != mat2->row_num) {
3085 PyErr_SetString(PyExc_ValueError,
3086 "matrix1 * matrix2: matrix1 number of columns "
3087 "and the matrix2 number of rows must be the same");
3088 return nullptr;
3089 }
3090
3091 for (col = 0; col < mat2->col_num; col++) {
3092 for (row = 0; row < mat1->row_num; row++) {
3093 double dot = 0.0f;
3094 for (item = 0; item < mat1->col_num; item++) {
3095 dot += double(MATRIX_ITEM(mat1, row, item) * MATRIX_ITEM(mat2, item, col));
3096 }
3097 /* store in new matrix as overwriting original at this point will cause
3098 * subsequent iterations to use incorrect values */
3099 mat[(col * mat1->row_num) + row] = float(dot);
3100 }
3101 }
3102
3103 /* copy matrix back */
3104 memcpy(mat1->matrix, mat, (mat1->row_num * mat1->col_num) * sizeof(float));
3105 }
3106 else {
3107 PyErr_Format(PyExc_TypeError,
3108 "In place matrix multiplication: "
3109 "not supported between '%.200s' and '%.200s' types",
3110 Py_TYPE(m1)->tp_name,
3111 Py_TYPE(m2)->tp_name);
3112 return nullptr;
3113 }
3114
3115 (void)BaseMath_WriteCallback(mat1);
3116 Py_INCREF(m1);
3117 return m1;
3118}
3119
3121
3122/* -------------------------------------------------------------------- */
3125
3126static PySequenceMethods Matrix_SeqMethods = {
3127 /*sq_length*/ (lenfunc)Matrix_len,
3128 /*sq_concat*/ nullptr,
3129 /*sq_repeat*/ nullptr,
3130 /*sq_item*/ (ssizeargfunc)Matrix_item_row,
3131 /*was_sq_slice*/ nullptr, /* DEPRECATED. */
3132 /*sq_ass_item*/ (ssizeobjargproc)Matrix_ass_item_row,
3133 /*was_sq_ass_slice*/ nullptr, /* DEPRECATED. */
3134 /*sq_contains*/ nullptr,
3135 /*sq_inplace_concat*/ nullptr,
3136 /*sq_inplace_repeat*/ nullptr,
3137};
3138
3139static PyMappingMethods Matrix_AsMapping = {
3140 /*mp_length*/ (lenfunc)Matrix_len,
3141 /*mp_subscript*/ (binaryfunc)Matrix_subscript,
3142 /*mp_ass_subscript*/ (objobjargproc)Matrix_ass_subscript,
3143};
3144
3145static PyNumberMethods Matrix_NumMethods = {
3146 /*nb_add*/ (binaryfunc)Matrix_add,
3147 /*nb_subtract*/ (binaryfunc)Matrix_sub,
3148 /*nb_multiply*/ (binaryfunc)Matrix_mul,
3149 /*nb_remainder*/ nullptr,
3150 /*nb_divmod*/ nullptr,
3151 /*nb_power*/ nullptr,
3152 /*nb_negative*/ nullptr,
3153 /*nb_positive*/ nullptr,
3154 /*nb_absolute*/ nullptr,
3155 /*nb_bool*/ nullptr,
3156 /*nb_invert*/ (unaryfunc)Matrix_inverted_noargs,
3157 /*nb_lshift*/ nullptr,
3158 /*nb_rshift*/ nullptr,
3159 /*nb_and*/ nullptr,
3160 /*nb_xor*/ nullptr,
3161 /*nb_or*/ nullptr,
3162 /*nb_int*/ nullptr,
3163 /*nb_reserved*/ nullptr,
3164 /*nb_float*/ nullptr,
3165 /*nb_inplace_add*/ nullptr,
3166 /*nb_inplace_subtract*/ nullptr,
3167 /*nb_inplace_multiply*/ (binaryfunc)Matrix_imul,
3168 /*nb_inplace_remainder*/ nullptr,
3169 /*nb_inplace_power*/ nullptr,
3170 /*nb_inplace_lshift*/ nullptr,
3171 /*nb_inplace_rshift*/ nullptr,
3172 /*nb_inplace_and*/ nullptr,
3173 /*nb_inplace_xor*/ nullptr,
3174 /*nb_inplace_or*/ nullptr,
3175 /*nb_floor_divide*/ nullptr,
3176 /*nb_true_divide*/ nullptr,
3177 /*nb_inplace_floor_divide*/ nullptr,
3178 /*nb_inplace_true_divide*/ nullptr,
3179 /*nb_index*/ nullptr,
3180 /*nb_matrix_multiply*/ (binaryfunc)Matrix_matmul,
3181 /*nb_inplace_matrix_multiply*/ (binaryfunc)Matrix_imatmul,
3182};
3183
3185
3186/* -------------------------------------------------------------------- */
3189
3191 /* Wrap. */
3192 Matrix_translation_doc,
3193 "The translation component of the matrix.\n"
3194 "\n"
3195 ":type: :class:`Vector`\n");
3196static PyObject *Matrix_translation_get(MatrixObject *self, void * /*closure*/)
3197{
3198 PyObject *ret;
3199
3200 if (BaseMath_ReadCallback(self) == -1) {
3201 return nullptr;
3202 }
3203
3204 /* Must be 4x4 square matrix. */
3205 if (self->row_num != 4 || self->col_num != 4) {
3206 PyErr_SetString(PyExc_AttributeError,
3207 "Matrix.translation: "
3208 "inappropriate matrix size, must be 4x4");
3209 return nullptr;
3210 }
3211
3213
3214 return ret;
3215}
3216
3217static int Matrix_translation_set(MatrixObject *self, PyObject *value, void * /*closure*/)
3218{
3219 float tvec[3];
3220
3222 return -1;
3223 }
3224
3225 /* Must be 4x4 square matrix. */
3226 if (self->row_num != 4 || self->col_num != 4) {
3227 PyErr_SetString(PyExc_AttributeError,
3228 "Matrix.translation: "
3229 "inappropriate matrix size, must be 4x4");
3230 return -1;
3231 }
3232
3233 if (mathutils_array_parse(tvec, 3, 3, value, "Matrix.translation") == -1) {
3234 return -1;
3235 }
3236
3237 copy_v3_v3(((float (*)[4])self->matrix)[3], tvec);
3238
3240
3241 return 0;
3242}
3243
3245 /* Wrap. */
3246 Matrix_row_doc,
3247 "Access the matrix by rows (default), (read-only).\n"
3248 "\n"
3249 ":type: Matrix Access\n");
3250static PyObject *Matrix_row_get(MatrixObject *self, void * /*closure*/)
3251{
3253}
3254
3256 /* Wrap. */
3257 Matrix_col_doc,
3258 "Access the matrix by columns, 3x3 and 4x4 only, (read-only).\n"
3259 "\n"
3260 ":type: Matrix Access\n");
3261static PyObject *Matrix_col_get(MatrixObject *self, void * /*closure*/)
3262{
3264}
3265
3267 /* Wrap. */
3268 Matrix_median_scale_doc,
3269 "The average scale applied to each axis (read-only).\n"
3270 "\n"
3271 ":type: float\n");
3272static PyObject *Matrix_median_scale_get(MatrixObject *self, void * /*closure*/)
3273{
3274 float mat[3][3];
3275
3276 if (BaseMath_ReadCallback(self) == -1) {
3277 return nullptr;
3278 }
3279
3280 /* Must be 3-4 cols, 3-4 rows, square matrix. */
3281 if ((self->row_num < 3) || (self->col_num < 3)) {
3282 PyErr_SetString(PyExc_AttributeError,
3283 "Matrix.median_scale: "
3284 "inappropriate matrix size, 3x3 minimum");
3285 return nullptr;
3286 }
3287
3288 matrix_as_3x3(mat, self);
3289
3290 return PyFloat_FromDouble(mat3_to_scale(mat));
3291}
3292
3294 /* Wrap. */
3295 Matrix_is_identity_doc,
3296 "True if this is an identity matrix (read-only).\n"
3297 "\n"
3298 ":type: bool\n");
3299static PyObject *Matrix_is_identity_get(MatrixObject *self, void * /*closure*/)
3300{
3301 if (BaseMath_ReadCallback(self) == -1) {
3302 return nullptr;
3303 }
3304 return PyBool_FromLong(matrix_is_identity(self));
3305}
3306
3308 /* Wrap. */
3309 Matrix_is_negative_doc,
3310 "True if this matrix results in a negative scale, 3x3 and 4x4 only, "
3311 "(read-only).\n"
3312 "\n"
3313 ":type: bool\n");
3314static PyObject *Matrix_is_negative_get(MatrixObject *self, void * /*closure*/)
3315{
3316 if (BaseMath_ReadCallback(self) == -1) {
3317 return nullptr;
3318 }
3319
3320 /* Must be 3-4 cols, 3-4 rows, square matrix. */
3321 if (self->row_num == 4 && self->col_num == 4) {
3322 return PyBool_FromLong(is_negative_m4((const float (*)[4])self->matrix));
3323 }
3324 if (self->row_num == 3 && self->col_num == 3) {
3325 return PyBool_FromLong(is_negative_m3((const float (*)[3])self->matrix));
3326 }
3327
3328 PyErr_SetString(PyExc_AttributeError,
3329 "Matrix.is_negative: "
3330 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
3331 return nullptr;
3332}
3333
3335 /* Wrap. */
3336 Matrix_is_orthogonal_doc,
3337 "True if this matrix is orthogonal, 3x3 and 4x4 only, (read-only).\n"
3338 "\n"
3339 ":type: bool\n");
3340static PyObject *Matrix_is_orthogonal_get(MatrixObject *self, void * /*closure*/)
3341{
3342 if (BaseMath_ReadCallback(self) == -1) {
3343 return nullptr;
3344 }
3345
3346 /* Must be 3-4 cols, 3-4 rows, square matrix. */
3347 if (self->row_num == 4 && self->col_num == 4) {
3348 return PyBool_FromLong(is_orthonormal_m4((const float (*)[4])self->matrix));
3349 }
3350 if (self->row_num == 3 && self->col_num == 3) {
3351 return PyBool_FromLong(is_orthonormal_m3((const float (*)[3])self->matrix));
3352 }
3353
3354 PyErr_SetString(PyExc_AttributeError,
3355 "Matrix.is_orthogonal: "
3356 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
3357 return nullptr;
3358}
3359
3361 /* Wrap. */
3362 Matrix_is_orthogonal_axis_vectors_doc,
3363 "True if this matrix has got orthogonal axis vectors, 3x3 and 4x4 only, "
3364 "(read-only).\n"
3365 "\n"
3366 ":type: bool\n");
3367static PyObject *Matrix_is_orthogonal_axis_vectors_get(MatrixObject *self, void * /*closure*/)
3368{
3369 if (BaseMath_ReadCallback(self) == -1) {
3370 return nullptr;
3371 }
3372
3373 /* Must be 3-4 cols, 3-4 rows, square matrix. */
3374 if (self->row_num == 4 && self->col_num == 4) {
3375 return PyBool_FromLong(is_orthogonal_m4((const float (*)[4])self->matrix));
3376 }
3377 if (self->row_num == 3 && self->col_num == 3) {
3378 return PyBool_FromLong(is_orthogonal_m3((const float (*)[3])self->matrix));
3379 }
3380
3381 PyErr_SetString(PyExc_AttributeError,
3382 "Matrix.is_orthogonal_axis_vectors: "
3383 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
3384 return nullptr;
3385}
3386
3388
3389/* -------------------------------------------------------------------- */
3392
3393static PyGetSetDef Matrix_getseters[] = {
3394 {"median_scale",
3396 (setter) nullptr,
3397 Matrix_median_scale_doc,
3398 nullptr},
3399 {"translation",
3400 (getter)Matrix_translation_get,
3401 (setter)Matrix_translation_set,
3402 Matrix_translation_doc,
3403 nullptr},
3404 {"row", (getter)Matrix_row_get, (setter) nullptr, Matrix_row_doc, nullptr},
3405 {"col", (getter)Matrix_col_get, (setter) nullptr, Matrix_col_doc, nullptr},
3406 {"is_identity",
3407 (getter)Matrix_is_identity_get,
3408 (setter) nullptr,
3409 Matrix_is_identity_doc,
3410 nullptr},
3411 {"is_negative",
3412 (getter)Matrix_is_negative_get,
3413 (setter) nullptr,
3414 Matrix_is_negative_doc,
3415 nullptr},
3416 {"is_orthogonal",
3418 (setter) nullptr,
3419 Matrix_is_orthogonal_doc,
3420 nullptr},
3421 {"is_orthogonal_axis_vectors",
3423 (setter) nullptr,
3424 Matrix_is_orthogonal_axis_vectors_doc,
3425 nullptr},
3426 {"is_wrapped",
3428 (setter) nullptr,
3430 nullptr},
3431 {"is_frozen",
3433 (setter) nullptr,
3435 nullptr},
3436 {"is_valid",
3438 (setter) nullptr,
3440 nullptr},
3441 {"owner",
3443 (setter) nullptr,
3445 nullptr},
3446 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
3447};
3448
3450
3451/* -------------------------------------------------------------------- */
3454
3455#ifdef __GNUC__
3456# ifdef __clang__
3457# pragma clang diagnostic push
3458# pragma clang diagnostic ignored "-Wcast-function-type"
3459# else
3460# pragma GCC diagnostic push
3461# pragma GCC diagnostic ignored "-Wcast-function-type"
3462# endif
3463#endif
3464
3465static PyMethodDef Matrix_methods[] = {
3466 /* Derived values. */
3467 {"determinant", (PyCFunction)Matrix_determinant, METH_NOARGS, Matrix_determinant_doc},
3468 {"decompose", (PyCFunction)Matrix_decompose, METH_NOARGS, Matrix_decompose_doc},
3469
3470 /* In place only. */
3471 {"zero", (PyCFunction)Matrix_zero, METH_NOARGS, Matrix_zero_doc},
3472 {"identity", (PyCFunction)Matrix_identity, METH_NOARGS, Matrix_identity_doc},
3473
3474 /* Operate on original or copy. */
3475 {"transpose", (PyCFunction)Matrix_transpose, METH_NOARGS, Matrix_transpose_doc},
3476 {"transposed", (PyCFunction)Matrix_transposed, METH_NOARGS, Matrix_transposed_doc},
3477 {"normalize", (PyCFunction)Matrix_normalize, METH_NOARGS, Matrix_normalize_doc},
3478 {"normalized", (PyCFunction)Matrix_normalized, METH_NOARGS, Matrix_normalized_doc},
3479 {"invert", (PyCFunction)Matrix_invert, METH_VARARGS, Matrix_invert_doc},
3480 {"inverted", (PyCFunction)Matrix_inverted, METH_VARARGS, Matrix_inverted_doc},
3481 {"invert_safe", (PyCFunction)Matrix_invert_safe, METH_NOARGS, Matrix_invert_safe_doc},
3482 {"inverted_safe", (PyCFunction)Matrix_inverted_safe, METH_NOARGS, Matrix_inverted_safe_doc},
3483 {"adjugate", (PyCFunction)Matrix_adjugate, METH_NOARGS, Matrix_adjugate_doc},
3484 {"adjugated", (PyCFunction)Matrix_adjugated, METH_NOARGS, Matrix_adjugated_doc},
3485 {"to_2x2", (PyCFunction)Matrix_to_2x2, METH_NOARGS, Matrix_to_2x2_doc},
3486 {"to_3x3", (PyCFunction)Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc},
3487 {"to_4x4", (PyCFunction)Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc},
3488 /* TODO: {"resize_3x3", (PyCFunction) Matrix_resize3x3, METH_NOARGS, Matrix_resize3x3_doc}, */
3489 {"resize_4x4", (PyCFunction)Matrix_resize_4x4, METH_NOARGS, Matrix_resize_4x4_doc},
3490 {"rotate", (PyCFunction)Matrix_rotate, METH_O, Matrix_rotate_doc},
3491
3492 /* Return converted representation. */
3493 {"to_euler", (PyCFunction)Matrix_to_euler, METH_VARARGS, Matrix_to_euler_doc},
3494 {"to_quaternion", (PyCFunction)Matrix_to_quaternion, METH_NOARGS, Matrix_to_quaternion_doc},
3495 {"to_scale", (PyCFunction)Matrix_to_scale, METH_NOARGS, Matrix_to_scale_doc},
3496 {"to_translation", (PyCFunction)Matrix_to_translation, METH_NOARGS, Matrix_to_translation_doc},
3497
3498 /* Operation between 2 or more types. */
3499 {"lerp", (PyCFunction)Matrix_lerp, METH_VARARGS, Matrix_lerp_doc},
3500 {"copy", (PyCFunction)Matrix_copy, METH_NOARGS, Matrix_copy_doc},
3501 {"__copy__", (PyCFunction)Matrix_copy, METH_NOARGS, Matrix_copy_doc},
3502 {"__deepcopy__", (PyCFunction)Matrix_deepcopy, METH_VARARGS, Matrix_copy_doc},
3503
3504 /* Base-math methods. */
3505 {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
3506
3507 /* Class methods. */
3508 {"Identity", (PyCFunction)C_Matrix_Identity, METH_VARARGS | METH_CLASS, C_Matrix_Identity_doc},
3509 {"Rotation", (PyCFunction)C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc},
3510 {"Scale", (PyCFunction)C_Matrix_Scale, METH_VARARGS | METH_CLASS, C_Matrix_Scale_doc},
3511 {"Shear", (PyCFunction)C_Matrix_Shear, METH_VARARGS | METH_CLASS, C_Matrix_Shear_doc},
3512 {"Diagonal", (PyCFunction)C_Matrix_Diagonal, METH_O | METH_CLASS, C_Matrix_Diagonal_doc},
3513 {"Translation",
3514 (PyCFunction)C_Matrix_Translation,
3515 METH_O | METH_CLASS,
3516 C_Matrix_Translation_doc},
3517 {"OrthoProjection",
3518 (PyCFunction)C_Matrix_OrthoProjection,
3519 METH_VARARGS | METH_CLASS,
3520 C_Matrix_OrthoProjection_doc},
3521 {"LocRotScale",
3522 (PyCFunction)C_Matrix_LocRotScale,
3523 METH_VARARGS | METH_CLASS,
3524 C_Matrix_LocRotScale_doc},
3525 {nullptr, nullptr, 0, nullptr},
3526};
3527
3528#ifdef __GNUC__
3529# ifdef __clang__
3530# pragma clang diagnostic pop
3531# else
3532# pragma GCC diagnostic pop
3533# endif
3534#endif
3535
3537
3538/* -------------------------------------------------------------------- */
3541
3542#ifdef MATH_STANDALONE
3543# define Matrix_str nullptr
3544#endif
3545
3547 /* Wrap. */
3548 matrix_doc,
3549 ".. class:: Matrix(rows=Matrix.Identity(4), /)\n"
3550 "\n"
3551 " This object gives access to Matrices in Blender, supporting square and rectangular\n"
3552 " matrices from 2x2 up to 4x4.\n"
3553 "\n"
3554 " :arg rows: Sequence of rows.\n"
3555 " :type rows: Sequence[Sequence[float]]\n");
3556PyTypeObject matrix_Type = {
3557 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
3558 /*tp_name*/ "Matrix",
3559 /*tp_basicsize*/ sizeof(MatrixObject),
3560 /*tp_itemsize*/ 0,
3561 /*tp_dealloc*/ (destructor)BaseMathObject_dealloc,
3562 /*tp_vectorcall_offset*/ 0,
3563 /*tp_getattr*/ nullptr,
3564 /*tp_setattr*/ nullptr,
3565 /*tp_as_async*/ nullptr,
3566 /*tp_repr*/ (reprfunc)Matrix_repr,
3567 /*tp_as_number*/ &Matrix_NumMethods,
3568 /*tp_as_sequence*/ &Matrix_SeqMethods,
3569 /*tp_as_mapping*/ &Matrix_AsMapping,
3570 /*tp_hash*/ (hashfunc)Matrix_hash,
3571 /*tp_call*/ nullptr,
3572 /*tp_str*/ (reprfunc)Matrix_str,
3573 /*tp_getattro*/ nullptr,
3574 /*tp_setattro*/ nullptr,
3575 /*tp_as_buffer*/ &Matrix_as_buffer,
3576 /*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
3577 /*tp_doc*/ matrix_doc,
3578 /*tp_traverse*/ (traverseproc)BaseMathObject_traverse,
3579 /*tp_clear*/ (inquiry)BaseMathObject_clear,
3580 /*tp_richcompare*/ (richcmpfunc)Matrix_richcmpr,
3581 /*tp_weaklistoffset*/ 0,
3582 /*tp_iter*/ nullptr,
3583 /*tp_iternext*/ nullptr,
3584 /*tp_methods*/ Matrix_methods,
3585 /*tp_members*/ nullptr,
3586 /*tp_getset*/ Matrix_getseters,
3587 /*tp_base*/ nullptr,
3588 /*tp_dict*/ nullptr,
3589 /*tp_descr_get*/ nullptr,
3590 /*tp_descr_set*/ nullptr,
3591 /*tp_dictoffset*/ 0,
3592 /*tp_init*/ nullptr,
3593 /*tp_alloc*/ nullptr,
3594 /*tp_new*/ Matrix_new,
3595 /*tp_free*/ nullptr,
3596 /*tp_is_gc*/ (inquiry)BaseMathObject_is_gc,
3597 /*tp_bases*/ nullptr,
3598 /*tp_mro*/ nullptr,
3599 /*tp_cache*/ nullptr,
3600 /*tp_subclasses*/ nullptr,
3601 /*tp_weaklist*/ nullptr,
3602 /*tp_del*/ nullptr,
3603 /*tp_version_tag*/ 0,
3604 /*tp_finalize*/ nullptr,
3605 /*tp_vectorcall*/ Matrix_vectorcall,
3606};
3607
3608#ifdef MATH_STANDALONE
3609# undef Matrix_str
3610#endif
3611
3613
3614/* -------------------------------------------------------------------- */
3617
3618PyObject *Matrix_CreatePyObject(const float *mat,
3619 const ushort col_num,
3620 const ushort row_num,
3621 PyTypeObject *base_type)
3622{
3624 float *mat_alloc;
3625
3626 /* matrix objects can be any 2-4row x 2-4col matrix */
3627 if (col_num < 2 || col_num > 4 || row_num < 2 || row_num > 4) {
3628 PyErr_SetString(PyExc_RuntimeError,
3629 "Matrix(): "
3630 "row and column sizes must be between 2 and 4");
3631 return nullptr;
3632 }
3633
3634 mat_alloc = static_cast<float *>(PyMem_Malloc(col_num * row_num * sizeof(float)));
3635 if (UNLIKELY(mat_alloc == nullptr)) {
3636 PyErr_SetString(PyExc_MemoryError,
3637 "Matrix(): "
3638 "problem allocating data");
3639 return nullptr;
3640 }
3641
3643 if (self) {
3644 self->matrix = mat_alloc;
3645 self->col_num = col_num;
3646 self->row_num = row_num;
3647
3648 /* init callbacks as nullptr */
3649 self->cb_user = nullptr;
3650 self->cb_type = self->cb_subtype = 0;
3651
3652 if (mat) { /* If a float array passed. */
3653 memcpy(self->matrix, mat, col_num * row_num * sizeof(float));
3654 }
3655 else if (col_num == row_num) {
3656 /* or if no arguments are passed return identity matrix for square matrices */
3658 }
3659 else {
3660 /* otherwise zero everything */
3661 memset(self->matrix, 0, col_num * row_num * sizeof(float));
3662 }
3664 }
3665 else {
3666 PyMem_Free(mat_alloc);
3667 }
3668
3669 return (PyObject *)self;
3670}
3671
3672PyObject *Matrix_CreatePyObject_wrap(float *mat,
3673 const ushort col_num,
3674 const ushort row_num,
3675 PyTypeObject *base_type)
3676{
3678
3679 /* matrix objects can be any 2-4row x 2-4col matrix */
3680 if (col_num < 2 || col_num > 4 || row_num < 2 || row_num > 4) {
3681 PyErr_SetString(PyExc_RuntimeError,
3682 "Matrix(): "
3683 "row and column sizes must be between 2 and 4");
3684 return nullptr;
3685 }
3686
3688 if (self) {
3689 self->col_num = col_num;
3690 self->row_num = row_num;
3691
3692 /* init callbacks as nullptr */
3693 self->cb_user = nullptr;
3694 self->cb_type = self->cb_subtype = 0;
3695
3696 self->matrix = mat;
3698 }
3699 return (PyObject *)self;
3700}
3701
3703 PyObject *cb_user, const ushort col_num, const ushort row_num, uchar cb_type, uchar cb_subtype)
3704{
3705 MatrixObject *self = (MatrixObject *)Matrix_CreatePyObject(nullptr, col_num, row_num, nullptr);
3706 if (self) {
3707 Py_INCREF(cb_user);
3708 self->cb_user = cb_user;
3709 self->cb_type = cb_type;
3710 self->cb_subtype = cb_subtype;
3711 BLI_assert(!PyObject_GC_IsTracked((PyObject *)self));
3712 PyObject_GC_Track(self);
3713 }
3714 return (PyObject *)self;
3715}
3716
3717PyObject *Matrix_CreatePyObject_alloc(float *mat,
3718 const ushort col_num,
3719 const ushort row_num,
3720 PyTypeObject *base_type)
3721{
3723 self = (MatrixObject *)Matrix_CreatePyObject_wrap(mat, col_num, row_num, base_type);
3724 if (self) {
3726 }
3727
3728 return (PyObject *)self;
3729}
3730
3732
3733/* -------------------------------------------------------------------- */
3736
3741{
3742 if (!MatrixObject_Check(pymat)) {
3743 PyErr_Format(
3744 PyExc_TypeError, "expected a mathutils.Matrix, not a %.200s", Py_TYPE(pymat)->tp_name);
3745 return false;
3746 }
3747 /* sets error */
3748 if (BaseMath_ReadCallback(pymat) == -1) {
3749 return false;
3750 }
3751 return true;
3752}
3753
3754int Matrix_ParseAny(PyObject *o, void *p)
3755{
3756 MatrixObject **pymat_p = static_cast<MatrixObject **>(p);
3757 MatrixObject *pymat = (MatrixObject *)o;
3758
3759 if (!Matrix_ParseCheck(pymat)) {
3760 return 0;
3761 }
3762 *pymat_p = pymat;
3763 return 1;
3764}
3765
3766int Matrix_Parse2x2(PyObject *o, void *p)
3767{
3768 MatrixObject **pymat_p = static_cast<MatrixObject **>(p);
3769 MatrixObject *pymat = (MatrixObject *)o;
3770
3771 if (!Matrix_ParseCheck(pymat)) {
3772 return 0;
3773 }
3774 if ((pymat->col_num != 2) || (pymat->row_num != 2)) {
3775 PyErr_SetString(PyExc_ValueError, "matrix must be 2x2");
3776 return 0;
3777 }
3778
3779 *pymat_p = pymat;
3780 return 1;
3781}
3782
3783int Matrix_Parse3x3(PyObject *o, void *p)
3784{
3785 MatrixObject **pymat_p = static_cast<MatrixObject **>(p);
3786 MatrixObject *pymat = (MatrixObject *)o;
3787
3788 if (!Matrix_ParseCheck(pymat)) {
3789 return 0;
3790 }
3791 if ((pymat->col_num != 3) || (pymat->row_num != 3)) {
3792 PyErr_SetString(PyExc_ValueError, "matrix must be 3x3");
3793 return 0;
3794 }
3795
3796 *pymat_p = pymat;
3797 return 1;
3798}
3799
3800int Matrix_Parse4x4(PyObject *o, void *p)
3801{
3802 MatrixObject **pymat_p = static_cast<MatrixObject **>(p);
3803 MatrixObject *pymat = (MatrixObject *)o;
3804
3805 if (!Matrix_ParseCheck(pymat)) {
3806 return 0;
3807 }
3808 if ((pymat->col_num != 4) || (pymat->row_num != 4)) {
3809 PyErr_SetString(PyExc_ValueError, "matrix must be 4x4");
3810 return 0;
3811 }
3812
3813 *pymat_p = pymat;
3814 return 1;
3815}
3816
3818
3819/* -------------------------------------------------------------------- */
3822
3824 PyObject_HEAD /* Required Python macro. */
3827};
3828
3829static int MatrixAccess_traverse(MatrixAccessObject *self, visitproc visit, void *arg)
3830{
3831 Py_VISIT(self->matrix_user);
3832 return 0;
3833}
3834
3836{
3837 Py_CLEAR(self->matrix_user);
3838 return 0;
3839}
3840
3842{
3843 if (self->matrix_user) {
3844 PyObject_GC_UnTrack(self);
3846 }
3847
3848 Py_TYPE(self)->tp_free(self);
3849}
3850
3852
3853/* -------------------------------------------------------------------- */
3856
3858{
3859 return (self->type == MAT_ACCESS_ROW) ? self->matrix_user->row_num : self->matrix_user->col_num;
3860}
3861
3862static PyObject *MatrixAccess_slice(MatrixAccessObject *self, Py_ssize_t begin, Py_ssize_t end)
3863{
3864 PyObject *tuple;
3865 Py_ssize_t count;
3866
3867 /* row/col access */
3868 MatrixObject *matrix_user = self->matrix_user;
3869 int matrix_access_len;
3870 PyObject *(*Matrix_item_new)(MatrixObject *, Py_ssize_t);
3871
3872 if (self->type == MAT_ACCESS_ROW) {
3873 matrix_access_len = matrix_user->row_num;
3874 Matrix_item_new = Matrix_item_row;
3875 }
3876 else { /* MAT_ACCESS_ROW */
3877 matrix_access_len = matrix_user->col_num;
3878 Matrix_item_new = Matrix_item_col;
3879 }
3880
3881 CLAMP(begin, 0, matrix_access_len);
3882 if (end < 0) {
3883 end = (matrix_access_len + 1) + end;
3884 }
3885 CLAMP(end, 0, matrix_access_len);
3886 begin = std::min(begin, end);
3887
3888 tuple = PyTuple_New(end - begin);
3889 for (count = begin; count < end; count++) {
3890 PyTuple_SET_ITEM(tuple, count - begin, Matrix_item_new(matrix_user, count));
3891 }
3892
3893 return tuple;
3894}
3895
3896static PyObject *MatrixAccess_subscript(MatrixAccessObject *self, PyObject *item)
3897{
3898 MatrixObject *matrix_user = self->matrix_user;
3899
3900 if (PyIndex_Check(item)) {
3901 Py_ssize_t i;
3902 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
3903 if (i == -1 && PyErr_Occurred()) {
3904 return nullptr;
3905 }
3906 if (self->type == MAT_ACCESS_ROW) {
3907 if (i < 0) {
3908 i += matrix_user->row_num;
3909 }
3910 return Matrix_item_row(matrix_user, i);
3911 }
3912 /* MAT_ACCESS_ROW */
3913 if (i < 0) {
3914 i += matrix_user->col_num;
3915 }
3916 return Matrix_item_col(matrix_user, i);
3917 }
3918 if (PySlice_Check(item)) {
3919 Py_ssize_t start, stop, step, slicelength;
3920
3921 if (PySlice_GetIndicesEx(item, MatrixAccess_len(self), &start, &stop, &step, &slicelength) < 0)
3922 {
3923 return nullptr;
3924 }
3925
3926 if (slicelength <= 0) {
3927 return PyTuple_New(0);
3928 }
3929 if (step == 1) {
3930 return MatrixAccess_slice(self, start, stop);
3931 }
3932
3933 PyErr_SetString(PyExc_IndexError, "slice steps not supported with matrix accessors");
3934 return nullptr;
3935 }
3936
3937 PyErr_Format(
3938 PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
3939 return nullptr;
3940}
3941
3942static int MatrixAccess_ass_subscript(MatrixAccessObject *self, PyObject *item, PyObject *value)
3943{
3944 MatrixObject *matrix_user = self->matrix_user;
3945
3946 if (PyIndex_Check(item)) {
3947 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
3948 if (i == -1 && PyErr_Occurred()) {
3949 return -1;
3950 }
3951
3952 if (self->type == MAT_ACCESS_ROW) {
3953 if (i < 0) {
3954 i += matrix_user->row_num;
3955 }
3956 return Matrix_ass_item_row(matrix_user, i, value);
3957 }
3958 /* MAT_ACCESS_ROW */
3959 if (i < 0) {
3960 i += matrix_user->col_num;
3961 }
3962 return Matrix_ass_item_col(matrix_user, i, value);
3963 }
3964 /* TODO: slice. */
3965
3966 PyErr_Format(
3967 PyExc_TypeError, "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
3968 return -1;
3969}
3970
3972{
3973 /* Try get values from a collection. */
3974 PyObject *ret;
3975 PyObject *iter = nullptr;
3977
3978 /* We know this is a tuple so no need to #PyIter_Check
3979 * otherwise it could be nullptr (unlikely) if conversion failed. */
3980 if (ret) {
3981 iter = PyObject_GetIter(ret);
3982 Py_DECREF(ret);
3983 }
3984
3985 return iter;
3986}
3987
3988static PyMappingMethods MatrixAccess_AsMapping = {
3989 /*mp_length*/ (lenfunc)MatrixAccess_len,
3990 /*mp_subscript*/ (binaryfunc)MatrixAccess_subscript,
3991 /*mp_ass_subscript*/ (objobjargproc)MatrixAccess_ass_subscript,
3992};
3993
3995
3996/* -------------------------------------------------------------------- */
3999
4000PyTypeObject matrix_access_Type = {
4001 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
4002 /*tp_name*/ "MatrixAccess",
4003 /*tp_basicsize*/ sizeof(MatrixAccessObject),
4004 /*tp_itemsize*/ 0,
4005 /*tp_dealloc*/ (destructor)MatrixAccess_dealloc,
4006 /*tp_vectorcall_offset*/ 0,
4007 /*tp_getattr*/ nullptr,
4008 /*tp_setattr*/ nullptr,
4009 /*tp_as_async*/ nullptr,
4010 /*tp_repr*/ nullptr,
4011 /*tp_as_number*/ nullptr,
4012 /*tp_as_sequence*/ nullptr /* &MatrixAccess_SeqMethods */ /* TODO. */,
4013 /*tp_as_mapping*/ &MatrixAccess_AsMapping,
4014 /*tp_hash*/ nullptr,
4015 /*tp_call*/ nullptr,
4016 /*tp_str*/ nullptr,
4017 /*tp_getattro*/ nullptr,
4018 /*tp_setattro*/ nullptr,
4019 /*tp_as_buffer*/ nullptr,
4020 /*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
4021 /*tp_doc*/ nullptr,
4022 /*tp_traverse*/ (traverseproc)MatrixAccess_traverse,
4023 /*tp_clear*/ (inquiry)MatrixAccess_clear,
4024 /*tp_richcompare*/ nullptr /* MatrixAccess_richcmpr */ /* TODO. */,
4025 /*tp_weaklistoffset*/ 0,
4026 /*tp_iter*/ (getiterfunc)MatrixAccess_iter,
4027 /*tp_iternext*/ nullptr,
4028 /*tp_methods*/ nullptr,
4029 /*tp_members*/ nullptr,
4030 /*tp_getset*/ nullptr,
4031 /*tp_base*/ nullptr,
4032 /*tp_dict*/ nullptr,
4033 /*tp_descr_get*/ nullptr,
4034 /*tp_descr_set*/ nullptr,
4035 /*tp_dictoffset*/ 0,
4036 /*tp_init*/ nullptr,
4037 /*tp_alloc*/ nullptr,
4038 /*tp_new*/ nullptr,
4039 /*tp_free*/ nullptr,
4040 /*tp_is_gc*/ nullptr,
4041 /*tp_bases*/ nullptr,
4042 /*tp_mro*/ nullptr,
4043 /*tp_cache*/ nullptr,
4044 /*tp_subclasses*/ nullptr,
4045 /*tp_weaklist*/ nullptr,
4046 /*tp_del*/ nullptr,
4047 /*tp_version_tag*/ 0,
4048 /*tp_finalize*/ nullptr,
4049 /*tp_vectorcall*/ nullptr,
4050};
4051
4053
4054/* -------------------------------------------------------------------- */
4057
4058static PyObject *MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type)
4059{
4060 MatrixAccessObject *matrix_access = (MatrixAccessObject *)PyObject_GC_New(MatrixObject,
4062
4063 matrix_access->matrix_user = matrix;
4064 Py_INCREF(matrix);
4065
4066 matrix_access->type = type;
4067
4068 return (PyObject *)matrix_access;
4069}
4070
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ATTR_FALLTHROUGH
A dynamically sized string ADT.
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_dynstr.cc: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.cc:56
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 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 unit_m4(float m[4][4])
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_UTF8_RLEN(dst, format,...)
unsigned char uchar
unsigned int uint
unsigned short ushort
#define CLAMP(a, b, c)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
static AppView * view
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
#define MEM_SAFE_FREE(v)
iter begin(iter)
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
nullptr float
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
#define rot(x, k)
uint col
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
int count
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
int BaseMathObject_is_gc(BaseMathObject *self)
Definition mathutils.cc:762
Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
Definition mathutils.cc:68
void BaseMathObject_dealloc(BaseMathObject *self)
Definition mathutils.cc:740
int EXPP_VectorsAreEqual(const float *vecA, const float *vecB, int size, int floatSteps)
Definition mathutils.cc:489
int mathutils_array_parse(float *array, int array_num_min, int array_num_max, PyObject *value, const char *error_prefix)
Definition mathutils.cc:96
char BaseMathObject_is_valid_doc[]
Definition mathutils.cc:685
char BaseMathObject_is_wrapped_doc[]
Definition mathutils.cc:671
PyObject * BaseMathObject_owner_get(BaseMathObject *self, void *)
Definition mathutils.cc:665
char BaseMathObject_is_frozen_doc[]
Definition mathutils.cc:678
PyObject * mathutils_dynstr_to_py(DynStr *ds)
Definition mathutils.cc:501
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
Definition mathutils.cc:408
PyObject * BaseMathObject_is_frozen_get(BaseMathObject *self, void *)
Definition mathutils.cc:680
PyObject * BaseMathObject_freeze(BaseMathObject *self)
Definition mathutils.cc:699
PyObject * BaseMathObject_is_wrapped_get(BaseMathObject *self, void *)
Definition mathutils.cc:673
char BaseMathObject_owner_doc[]
Definition mathutils.cc:664
char BaseMathObject_freeze_doc[]
Definition mathutils.cc:691
PyObject * BaseMathObject_is_valid_get(BaseMathObject *self, void *)
Definition mathutils.cc:686
int BaseMathObject_clear(BaseMathObject *self)
Definition mathutils.cc:722
int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
Definition mathutils.cc:716
#define BaseMathObject_Prepare_ForResize(_self, error_prefix)
Definition mathutils.hh:174
#define BaseMath_ReadCallback_ForWrite(_self)
Definition mathutils.hh:151
#define BaseMath_Prepare_ForBufferAccess(_self, _view, _flags)
Definition mathutils.hh:183
#define BaseMath_WriteCallback(_self)
Definition mathutils.hh:143
#define BASE_MATH_NEW(struct_name, root_type, base_type)
Definition mathutils.hh:27
#define BaseMathObject_Prepare_ForHash(_self)
Definition mathutils.hh:166
int column_vector_multiplication(float r_vec[4], VectorObject *vec, MatrixObject *mat)
#define BASE_MATH_FLAG_DEFAULT
Definition mathutils.hh:52
#define BaseMath_Prepare_ForWrite(_self)
Definition mathutils.hh:161
@ BASE_MATH_FLAG_HAS_BUFFER_VIEW
Definition mathutils.hh:50
@ BASE_MATH_FLAG_IS_WRAP
Definition mathutils.hh:37
#define BaseMath_ReadCallback(_self)
Definition mathutils.hh:141
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)
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)
static int Matrix_getbuffer(PyObject *obj, Py_buffer *view, int flags)
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 void Matrix_releasebuffer(PyObject *, Py_buffer *view)
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)
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 * 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
static PyBufferProcs Matrix_as_buffer
PyTypeObject matrix_Type
static PyObject * Matrix_vectorcall(PyObject *type, PyObject *const *args, const size_t nargsf, PyObject *kwnames)
#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)
Py_DECREF(oname)
header-only utilities
#define PyTuple_SET_ITEMS(op_arg,...)
return ret
#define sqrtf
unsigned char order
PyObject_HEAD MatrixObject * matrix_user
i
Definition text_draw.cc:230