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