23#ifndef MATH_STANDALONE
48 PyErr_SetString(PyExc_AttributeError,
50 "owner matrix has been resized since this row vector was created");
60 PyErr_SetString(PyExc_AttributeError,
62 "owner matrix has been resized since this column vector was created");
94 memcpy(mat_dst->matrix, mat_src->matrix,
sizeof(
float) * (mat_dst->
col_num * mat_dst->
row_num));
99 const int mat_size =
sizeof(
float) * (
self->col_num *
self->row_num);
100 memset(
self->matrix, 0x0, mat_size);
102 const int row_num =
self->row_num;
103 for (
int col = 0;
col < col_row_max;
col++) {
114 for (row = 0; row < mat_src->
row_num; row++) {
124 if (
self->col_num == 2) {
130 if (
self->col_num == 3) {
150 adjoint_m2_m2((
float (*)[2])mat_dst, (
const float (*)[2])mat_src);
154 adjoint_m3_m3((
float (*)[3])mat_dst, (
const float (*)[3])mat_src);
158 adjoint_m4_m4((
float (*)[4])mat_dst, (
const float (*)[4])mat_src);
168 const float *mat_src,
181 for (
i = 0;
i < dim;
i++) {
182 for (j = 0; j < dim; j++) {
212 float *in_mat =
self->matrix;
223 switch (
self->col_num) {
227 if (in_mat !=
self->matrix) {
242 if (in_mat !=
self->matrix) {
258 if (in_mat !=
self->matrix) {
301 for (
int row = 0; row <
self->row_num; row++) {
436 for (row = 0; row < row_num; row++) {
459 for (row = 0; row < row_num; row++) {
533 for (row = 0; row < 3; row++) {
549 for (row = 0; row < 3; row++) {
598 PyObject *
const *args,
602 if (
UNLIKELY(kwnames && PyTuple_GET_SIZE(kwnames))) {
603 PyErr_SetString(PyExc_TypeError,
605 "takes no keyword args");
609 switch (PyVectorcall_NARGS(nargsf)) {
614 PyObject *arg = args[0];
619 const ushort row_num = PySequence_Size(arg);
621 if (row_num >= 2 && row_num <= 4) {
622 PyObject *item = PySequence_GetItem(arg, 0);
625 const ushort col_num = PySequence_Size(item);
628 if (col_num >= 2 && col_num <= 4) {
631 nullptr, col_num, row_num, (PyTypeObject *)type);
644 PyErr_SetString(PyExc_TypeError,
645 "mathutils.Matrix(): "
646 "expects no args or a single arg containing 2-4 numeric sequences");
650static PyObject *
Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
653 if (
UNLIKELY(kwds && PyDict_GET_SIZE(kwds))) {
654 PyErr_SetString(PyExc_TypeError,
655 "mathutils.Matrix(): "
656 "takes no keyword args");
659 PyObject *
const *args_array = &PyTuple_GET_ITEM(args, 0);
660 const size_t args_array_num = PyTuple_GET_SIZE(args);
662 reinterpret_cast<PyObject *
>(type), args_array, args_array_num,
nullptr);
674 C_Matrix_Identity_doc,
675 ".. classmethod:: Identity(size, /)\n"
677 " Create an identity matrix.\n"
679 " :arg size: The size of the identity matrix to construct [2, 4].\n"
681 " :return: A new identity matrix.\n"
682 " :rtype: :class:`Matrix`\n");
687 if (!PyArg_ParseTuple(args,
"i:Matrix.Identity", &matSize)) {
691 if (matSize < 2 || matSize > 4) {
692 PyErr_SetString(PyExc_RuntimeError,
693 "Matrix.Identity(): "
694 "size must be between 2 and 4");
704 C_Matrix_Rotation_doc,
705 ".. classmethod:: Rotation(angle, size, axis, /)\n"
707 " Create a matrix representing a rotation.\n"
709 " :arg angle: The angle of rotation desired, in radians.\n"
710 " :type angle: float\n"
711 " :arg size: The size of the rotation matrix to construct [2, 4].\n"
713 " :arg axis: an axis string or a 3D Vector Object\n"
714 " (optional when size is 2).\n"
715 " :type axis: Literal['X', 'Y', 'Z'] | :class:`Vector`\n"
716 " :return: A new rotation matrix.\n"
717 " :rtype: :class:`Matrix`\n");
720 PyObject *vec =
nullptr;
721 const char *axis =
nullptr;
724 float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
726 if (!PyArg_ParseTuple(args,
"di|O:Matrix.Rotation", &
angle, &matSize, &vec)) {
730 if (vec && PyUnicode_Check(vec)) {
731 axis = PyUnicode_AsUTF8(vec);
732 if (axis ==
nullptr || axis[0] ==
'\0' || axis[1] !=
'\0' || axis[0] <
'X' || axis[0] >
'Z') {
733 PyErr_SetString(PyExc_ValueError,
734 "Matrix.Rotation(): "
735 "3rd argument axis value must be a 3D vector "
736 "or a string in 'X', 'Y', 'Z'");
746 if (!
ELEM(matSize, 2, 3, 4)) {
747 PyErr_SetString(PyExc_ValueError,
748 "Matrix.Rotation(): "
749 "can only return a 2x2 3x3 or 4x4 matrix");
752 if (matSize == 2 && (vec !=
nullptr)) {
753 PyErr_SetString(PyExc_ValueError,
754 "Matrix.Rotation(): "
755 "cannot create a 2x2 rotation matrix around arbitrary axis");
758 if (
ELEM(matSize, 3, 4) && (axis ==
nullptr) && (vec ==
nullptr)) {
759 PyErr_SetString(PyExc_ValueError,
760 "Matrix.Rotation(): "
761 "axis of rotation for 3d and 4d matrices is required");
770 tvec, 3, 3, vec,
"Matrix.Rotation(angle, size, axis), invalid 'axis' arg") == -1)
777 else if (matSize == 2) {
795 C_Matrix_Translation_doc,
796 ".. classmethod:: Translation(vector, /)\n"
798 " Create a matrix representing a translation.\n"
800 " :arg vector: The translation vector.\n"
801 " :type vector: :class:`Vector`\n"
802 " :return: An identity matrix with a translation.\n"
803 " :rtype: :class:`Matrix`\n");
811 mat[3], 3, 4, value,
"mathutils.Matrix.Translation(vector), invalid vector arg") == -1)
821 C_Matrix_Diagonal_doc,
822 ".. classmethod:: Diagonal(vector, /)\n"
824 " Create a diagonal (scaling) matrix using the values from the vector.\n"
826 " :arg vector: The vector of values for the diagonal.\n"
827 " :type vector: :class:`Vector`\n"
828 " :return: A diagonal matrix.\n"
829 " :rtype: :class:`Matrix`\n");
833 float mat[16] = {0.0f};
837 vec, 2, 4, value,
"mathutils.Matrix.Diagonal(vector), invalid vector arg");
843 for (
int i = 0;
i <
size;
i++) {
854 ".. classmethod:: Scale(factor, size, axis, /)\n"
856 " Create a matrix representing a scaling.\n"
858 " :arg factor: The factor of scaling to apply.\n"
859 " :type factor: float\n"
860 " :arg size: The size of the scale matrix to construct [2, 4].\n"
862 " :arg axis: Direction to influence scale. (optional).\n"
863 " :type axis: :class:`Vector`\n"
864 " :return: A new scale matrix.\n"
865 " :rtype: :class:`Matrix`\n");
868 PyObject *vec =
nullptr;
873 float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
875 if (!PyArg_ParseTuple(args,
"fi|O:Matrix.Scale", &factor, &matSize, &vec)) {
878 if (!
ELEM(matSize, 2, 3, 4)) {
879 PyErr_SetString(PyExc_ValueError,
881 "can only return a 2x2 3x3 or 4x4 matrix");
885 vec_num = (matSize == 2 ? 2 : 3);
887 tvec, vec_num, vec_num, vec,
"Matrix.Scale(factor, size, axis), invalid 'axis' arg") ==
893 if (vec ==
nullptr) {
909 for (
x = 0;
x < vec_num;
x++) {
910 norm += tvec[
x] * tvec[
x];
913 for (
x = 0;
x < vec_num;
x++) {
917 mat[0] = 1 + ((factor - 1) * (tvec[0] * tvec[0]));
918 mat[1] = ((factor - 1) * (tvec[0] * tvec[1]));
919 mat[2] = ((factor - 1) * (tvec[0] * tvec[1]));
920 mat[3] = 1 + ((factor - 1) * (tvec[1] * tvec[1]));
923 mat[0] = 1 + ((factor - 1) * (tvec[0] * tvec[0]));
924 mat[1] = ((factor - 1) * (tvec[0] * tvec[1]));
925 mat[2] = ((factor - 1) * (tvec[0] * tvec[2]));
926 mat[3] = ((factor - 1) * (tvec[0] * tvec[1]));
927 mat[4] = 1 + ((factor - 1) * (tvec[1] * tvec[1]));
928 mat[5] = ((factor - 1) * (tvec[1] * tvec[2]));
929 mat[6] = ((factor - 1) * (tvec[0] * tvec[2]));
930 mat[7] = ((factor - 1) * (tvec[1] * tvec[2]));
931 mat[8] = 1 + ((factor - 1) * (tvec[2] * tvec[2]));
943 C_Matrix_OrthoProjection_doc,
944 ".. classmethod:: OrthoProjection(axis, size, /)\n"
946 " Create a matrix to represent an orthographic projection.\n"
948 " :arg axis: An axis string,\n"
949 " where a single axis is for a 2D matrix.\n"
950 " Or a vector for an arbitrary axis\n"
951 " :type axis: Literal['X', 'Y', 'XY', 'XZ', 'YZ'] | :class:`Vector`\n"
952 " :arg size: The size of the projection matrix to construct [2, 4].\n"
954 " :return: A new projection matrix.\n"
955 " :rtype: :class:`Matrix`\n");
962 float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
964 if (!PyArg_ParseTuple(args,
"Oi:Matrix.OrthoProjection", &axis, &matSize)) {
967 if (!
ELEM(matSize, 2, 3, 4)) {
968 PyErr_SetString(PyExc_ValueError,
969 "Matrix.OrthoProjection(): "
970 "can only return a 2x2 3x3 or 4x4 matrix");
974 if (PyUnicode_Check(axis)) {
975 Py_ssize_t plane_len;
976 const char *plane = PyUnicode_AsUTF8AndSize(axis, &plane_len);
978 if (plane_len == 1 && plane[0] ==
'X') {
981 else if (plane_len == 1 && plane[0] ==
'Y') {
985 PyErr_Format(PyExc_ValueError,
986 "Matrix.OrthoProjection(): "
987 "unknown plane, expected: X, Y, not '%.200s'",
993 if (plane_len == 2 && plane[0] ==
'X' && plane[1] ==
'Y') {
997 else if (plane_len == 2 && plane[0] ==
'X' && plane[1] ==
'Z') {
1001 else if (plane_len == 2 && plane[0] ==
'Y' && plane[1] ==
'Z') {
1006 PyErr_Format(PyExc_ValueError,
1007 "Matrix.OrthoProjection(): "
1008 "unknown plane, expected: XY, XZ, YZ, not '%.200s'",
1017 const int vec_num = (matSize == 2 ? 2 : 3);
1024 "Matrix.OrthoProjection(axis, size), invalid 'axis' arg") == -1)
1030 for (
x = 0;
x < vec_num;
x++) {
1031 norm += tvec[
x] * tvec[
x];
1034 for (
x = 0;
x < vec_num;
x++) {
1038 mat[0] = 1 - (tvec[0] * tvec[0]);
1039 mat[1] = -(tvec[0] * tvec[1]);
1040 mat[2] = -(tvec[0] * tvec[1]);
1041 mat[3] = 1 - (tvec[1] * tvec[1]);
1043 else if (matSize > 2) {
1044 mat[0] = 1 - (tvec[0] * tvec[0]);
1045 mat[1] = -(tvec[0] * tvec[1]);
1046 mat[2] = -(tvec[0] * tvec[2]);
1047 mat[3] = -(tvec[0] * tvec[1]);
1048 mat[4] = 1 - (tvec[1] * tvec[1]);
1049 mat[5] = -(tvec[1] * tvec[2]);
1050 mat[6] = -(tvec[0] * tvec[2]);
1051 mat[7] = -(tvec[1] * tvec[2]);
1052 mat[8] = 1 - (tvec[2] * tvec[2]);
1066 ".. classmethod:: Shear(plane, size, factor, /)\n"
1068 " Create a matrix to represent a shear transformation.\n"
1070 " :arg plane: An axis string,\n"
1071 " where a single axis is for a 2D matrix only.\n"
1072 " :type plane: Literal['X', 'Y', 'XY', 'XZ', 'YZ']\n"
1073 " :arg size: The size of the shear matrix to construct [2, 4].\n"
1074 " :type size: int\n"
1075 " :arg factor: The factor of shear to apply. "
1076 "For a 2 *size* matrix use a single float. "
1077 "For a 3 or 4 *size* matrix pass a pair of floats corresponding with the *plane* axis.\n"
1078 " :type factor: float | Sequence[float]\n"
1079 " :return: A new shear matrix.\n"
1080 " :rtype: :class:`Matrix`\n");
1086 float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
1088 if (!PyArg_ParseTuple(args,
"siO:Matrix.Shear", &plane, &matSize, &fac)) {
1091 if (!
ELEM(matSize, 2, 3, 4)) {
1092 PyErr_SetString(PyExc_ValueError,
1094 "can only return a 2x2 3x3 or 4x4 matrix");
1099 float const factor = PyFloat_AsDouble(fac);
1101 if (factor == -1.0f && PyErr_Occurred()) {
1102 PyErr_SetString(PyExc_TypeError,
1104 "the factor to be a float");
1112 if (
STREQ(plane,
"X")) {
1115 else if (
STREQ(plane,
"Y")) {
1119 PyErr_SetString(PyExc_ValueError,
1121 "expected: X, Y or wrong matrix size for shearing plane");
1138 if (
STREQ(plane,
"XY")) {
1142 else if (
STREQ(plane,
"XZ")) {
1146 else if (
STREQ(plane,
"YZ")) {
1151 PyErr_SetString(PyExc_ValueError,
1153 "expected: X, Y, XY, XZ, YZ");
1167 C_Matrix_LocRotScale_doc,
1168 ".. classmethod:: LocRotScale(location, rotation, scale, /)\n"
1170 " Create a matrix combining translation, rotation and scale,\n"
1171 " acting as the inverse of the decompose() method.\n"
1173 " Any of the inputs may be replaced with None if not needed.\n"
1175 " :arg location: The translation component.\n"
1176 " :type location: :class:`Vector` | None\n"
1177 " :arg rotation: The rotation component as a "
1178 "3x3 matrix, quaternion, euler or None for no rotation.\n"
1179 " :type rotation: :class:`Matrix` | :class:`Quaternion` | :class:`Euler` | None\n"
1180 " :arg scale: The scale component.\n"
1181 " :type scale: :class:`Vector` | None\n"
1182 " :return: Combined transformation as a 4x4 matrix. \n"
1183 " :rtype: :class:`Matrix`\n");
1186 PyObject *loc_obj, *rot_obj, *scale_obj;
1187 float mat[4][4], loc[3];
1189 if (!PyArg_ParseTuple(args,
"OOO:Matrix.LocRotScale", &loc_obj, &rot_obj, &scale_obj)) {
1194 if (loc_obj == Py_None) {
1198 loc, 3, 3, loc_obj,
"Matrix.LocRotScale(), invalid location argument") == -1)
1204 if (rot_obj == Py_None) {
1233 copy_m4_m3(mat, (
const float (*)[3])mat_obj->matrix);
1236 PyErr_SetString(PyExc_ValueError,
1237 "Matrix.LocRotScale(): "
1238 "inappropriate rotation matrix size - expects 3x3 matrix");
1243 PyErr_SetString(PyExc_ValueError,
1244 "Matrix.LocRotScale(): "
1245 "rotation argument must be Matrix, Quaternion, Euler or None");
1250 if (scale_obj != Py_None) {
1254 scale, 3, 3, scale_obj,
"Matrix.LocRotScale(), invalid scale argument") == -1)
1275 Matrix_to_quaternion_doc,
1276 ".. method:: to_quaternion()\n"
1278 " Return a quaternion representation of the rotation matrix.\n"
1280 " :return: Quaternion representation of the rotation matrix.\n"
1281 " :rtype: :class:`Quaternion`\n");
1291 if ((
self->row_num < 3) || (
self->col_num < 3) || (
self->row_num !=
self->col_num)) {
1292 PyErr_SetString(PyExc_ValueError,
1293 "Matrix.to_quat(): "
1294 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
1297 if (
self->row_num == 3) {
1314 Matrix_to_euler_doc,
1315 ".. method:: to_euler(order='XYZ', euler_compat=None, /)\n"
1317 " Return an Euler representation of the rotation matrix\n"
1318 " (3x3 or 4x4 matrix only).\n"
1320 " :arg order: A rotation order string."
1321 " :type order: Literal['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX']\n"
1322 " :arg euler_compat: Optional euler argument the new euler will be made\n"
1323 " compatible with (no axis flipping between them).\n"
1324 " Useful for converting a series of matrices to animation curves.\n"
1325 " :type euler_compat: :class:`Euler`\n"
1326 " :return: Euler representation of the matrix.\n"
1327 " :rtype: :class:`Euler`\n");
1330 const char *order_str =
nullptr;
1332 float eul[3], eul_compatf[3];
1341 if (!PyArg_ParseTuple(args,
"|sO!:to_euler", &order_str, &
euler_Type, &eul_compat)) {
1354 if (
self->row_num == 3 &&
self->col_num == 3) {
1357 else if (
self->row_num == 4 &&
self->col_num == 4) {
1361 PyErr_SetString(PyExc_ValueError,
1362 "Matrix.to_euler(): "
1363 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
1405 Matrix_resize_4x4_doc,
1406 ".. method:: resize_4x4()\n"
1408 " Resize the matrix to 4x4.\n");
1419 self->matrix =
static_cast<float *
>(
1421 if (
self->matrix ==
nullptr) {
1422 PyErr_SetString(PyExc_MemoryError,
1423 "Matrix.resize_4x4(): "
1424 "problem allocating pointer space");
1450 const int mat_size =
sizeof(
float) * (col_num * row_num);
1452 static_cast<float *
>(PyMem_Malloc(mat_size)), col_num, row_num, Py_TYPE(
self));
1454 if ((
self->row_num == row_num) && (
self->col_num == col_num)) {
1455 memcpy(pymat->matrix,
self->matrix, mat_size);
1458 if ((
self->col_num < col_num) || (
self->row_num < row_num)) {
1461 const int col_len_src =
min_ii(col_num,
self->col_num);
1462 const int row_len_src =
min_ii(row_num,
self->row_num);
1463 for (
int col = 0;
col < col_len_src;
col++) {
1468 return (PyObject *)pymat;
1474 ".. method:: to_2x2()\n"
1476 " Return a 2x2 copy of this matrix.\n"
1478 " :return: a new matrix.\n"
1479 " :rtype: :class:`Matrix`\n");
1491 ".. method:: to_3x3()\n"
1493 " Return a 3x3 copy of this matrix.\n"
1495 " :return: a new matrix.\n"
1496 " :rtype: :class:`Matrix`\n");
1508 ".. method:: to_4x4()\n"
1510 " Return a 4x4 copy of this matrix.\n"
1512 " :return: a new matrix.\n"
1513 " :rtype: :class:`Matrix`\n");
1531 Matrix_to_translation_doc,
1532 ".. method:: to_translation()\n"
1534 " Return the translation part of a 4 row matrix.\n"
1536 " :return: Return the translation of a matrix.\n"
1537 " :rtype: :class:`Vector`\n");
1544 if ((
self->row_num < 3) ||
self->col_num < 4) {
1545 PyErr_SetString(PyExc_ValueError,
1546 "Matrix.to_translation(): "
1547 "inappropriate matrix size");
1556 Matrix_to_scale_doc,
1557 ".. method:: to_scale()\n"
1559 " Return the scale part of a 3x3 or 4x4 matrix.\n"
1561 " :return: Return the scale of a matrix.\n"
1562 " :rtype: :class:`Vector`\n"
1564 " .. note:: This method does not return a negative scale on any axis because it is "
1565 "not possible to obtain this data from the matrix alone.\n");
1577 if ((
self->row_num < 3) || (
self->col_num < 3)) {
1578 PyErr_SetString(PyExc_ValueError,
1579 "Matrix.to_scale(): "
1580 "inappropriate matrix size, 3x3 minimum size");
1601 if (
self->col_num !=
self->row_num) {
1602 PyErr_SetString(PyExc_ValueError,
1603 "Matrix.invert(ed): "
1604 "only square matrices are supported");
1613 switch (PyTuple_GET_SIZE(args)) {
1621 PyErr_SetString(PyExc_TypeError,
1623 "expects a matrix argument or nothing");
1628 PyErr_SetString(PyExc_TypeError,
1630 "matrix argument has different dimensions");
1638 PyErr_SetString(PyExc_ValueError,
1639 "Matrix.invert(ed): "
1640 "takes at most one argument");
1648 PyErr_SetString(PyExc_ValueError,
1649 "Matrix.invert(ed): "
1650 "matrix does not have an inverse");
1656 ".. method:: invert(fallback=None, /)\n"
1658 " Set the matrix to its inverse.\n"
1660 " :arg fallback: Set the matrix to this value when the inverse cannot be calculated\n"
1661 " (instead of raising a :exc:`ValueError` exception).\n"
1662 " :type fallback: :class:`Matrix`\n"
1664 " .. seealso:: `Inverse matrix <https://en.wikipedia.org/wiki/Inverse_matrix>`__ on "
1684 if (PyTuple_GET_SIZE(args) == 1) {
1691 if (
self != fallback) {
1707 Matrix_inverted_doc,
1708 ".. method:: inverted(fallback=None, /)\n"
1710 " Return an inverted copy of the matrix.\n"
1712 " :arg fallback: return this when the inverse can't be calculated\n"
1713 " (instead of raising a :exc:`ValueError`).\n"
1714 " :type fallback: Any\n"
1715 " :return: The inverted matrix or fallback when given.\n"
1716 " :rtype: :class:`Matrix` | Any\n");
1737 if (PyTuple_GET_SIZE(args) == 1) {
1738 PyObject *fallback = PyTuple_GET_ITEM(args, 0);
1739 Py_INCREF(fallback);
1774 Matrix_invert_safe_doc,
1775 ".. method:: invert_safe()\n"
1777 " Set the matrix to its inverse, will never error.\n"
1778 " If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, "
1779 "to get an invertible one.\n"
1780 " If tweaked matrix is still degenerated, set to the identity matrix instead.\n"
1782 " .. seealso:: `Inverse Matrix <https://en.wikipedia.org/wiki/Inverse_matrix>`__ on "
1802 Matrix_inverted_safe_doc,
1803 ".. method:: inverted_safe()\n"
1805 " Return an inverted copy of the matrix, will never error.\n"
1806 " If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, "
1807 "to get an invertible one.\n"
1808 " If tweaked matrix is still degenerated, return the identity matrix instead.\n"
1810 " :return: the inverted matrix.\n"
1811 " :rtype: :class:`Matrix`\n");
1837 Matrix_adjugate_doc,
1838 ".. method:: adjugate()\n"
1840 " Set the matrix to its adjugate.\n"
1842 " :raises ValueError: if the matrix cannot be adjugated.\n"
1844 " .. seealso:: `Adjugate matrix <https://en.wikipedia.org/wiki/Adjugate_matrix>`__ on "
1852 if (
self->col_num !=
self->row_num) {
1853 PyErr_SetString(PyExc_ValueError,
1854 "Matrix.adjugate(d): "
1855 "only square matrices are supported");
1860 if (
self->col_num <= 4) {
1865 PyExc_ValueError,
"Matrix adjugate(d): size (%d) unsupported",
int(
self->col_num));
1875 Matrix_adjugated_doc,
1876 ".. method:: adjugated()\n"
1878 " Return an adjugated copy of the matrix.\n"
1880 " :return: the adjugated matrix.\n"
1881 " :rtype: :class:`Matrix`\n"
1882 " :raises ValueError: if the matrix cannot be adjugated\n");
1891 ".. method:: rotate(other, /)\n"
1893 " Rotates the matrix by another mathutils value.\n"
1895 " :arg other: rotation component of mathutils value\n"
1896 " :type other: :class:`Euler` | :class:`Quaternion` | :class:`Matrix`\n"
1898 " .. note:: If any of the columns are not unit length this may not have desired results.\n");
1901 float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
1911 if (
self->row_num != 3 ||
self->col_num != 3) {
1912 PyErr_SetString(PyExc_ValueError,
1914 "must have 3x3 dimensions");
1935 Matrix_decompose_doc,
1936 ".. method:: decompose()\n"
1938 " Return the translation, rotation, and scale components of this matrix.\n"
1940 " :return: Tuple of translation, rotation, and scale.\n"
1941 " :rtype: tuple[:class:`Vector`, :class:`Quaternion`, :class:`Vector`]\n");
1950 if (
self->row_num != 4 ||
self->col_num != 4) {
1951 PyErr_SetString(PyExc_ValueError,
1952 "Matrix.decompose(): "
1953 "inappropriate matrix size - expects 4x4 matrix");
1964 ret = PyTuple_New(3);
1981 ".. function:: lerp(other, factor, /)\n"
1983 " Returns the interpolation of two matrices. Uses polar decomposition, see"
1984 " \"Matrix Animation and Polar Decomposition\", Shoemake and Duff, 1992.\n"
1986 " :arg other: value to interpolate with.\n"
1987 " :type other: :class:`Matrix`\n"
1988 " :arg factor: The interpolation value in [0.0, 1.0].\n"
1989 " :type factor: float\n"
1990 " :return: The interpolated matrix.\n"
1991 " :rtype: :class:`Matrix`\n");
1997 if (!PyArg_ParseTuple(args,
"O!f:lerp", &
matrix_Type, &mat2, &fac)) {
2002 PyErr_SetString(PyExc_ValueError,
2004 "expects both matrix objects of the same dimensions");
2013 if (
self->col_num == 4 &&
self->row_num == 4) {
2014#ifdef MATH_STANDALONE
2020 else if (
self->col_num == 3 &&
self->row_num == 3) {
2021#ifdef MATH_STANDALONE
2028 PyErr_SetString(PyExc_ValueError,
2030 "only 3x3 and 4x4 matrices supported");
2039 Matrix_determinant_doc,
2040 ".. method:: determinant()\n"
2042 " Return the determinant of a matrix.\n"
2044 " :return: Return the determinant of a matrix.\n"
2047 " .. seealso:: `Determinant <https://en.wikipedia.org/wiki/Determinant>`__ on Wikipedia.\n");
2054 if (
self->col_num !=
self->row_num) {
2055 PyErr_SetString(PyExc_ValueError,
2056 "Matrix.determinant(): "
2057 "only square matrices are supported");
2072 Matrix_transpose_doc,
2073 ".. method:: transpose()\n"
2075 " Set the matrix to its transpose.\n"
2077 " .. seealso:: `Transpose <https://en.wikipedia.org/wiki/Transpose>`__ on Wikipedia.\n");
2084 if (
self->col_num !=
self->row_num) {
2085 PyErr_SetString(PyExc_ValueError,
2086 "Matrix.transpose(d): "
2087 "only square matrices are supported");
2091 if (
self->col_num == 2) {
2096 else if (
self->col_num == 3) {
2109 Matrix_transposed_doc,
2110 ".. method:: transposed()\n"
2112 " Return a new, transposed matrix.\n"
2114 " :return: a transposed matrix\n"
2115 " :rtype: :class:`Matrix`\n");
2129 Matrix_normalize_doc,
2130 ".. method:: normalize()\n"
2132 " Normalize each of the matrix columns.\n"
2134 " .. note:: for 4x4 matrices, the 4th column (translation) is left untouched.\n");
2141 if (
self->col_num !=
self->row_num) {
2142 PyErr_SetString(PyExc_ValueError,
2143 "Matrix.normalize(): "
2144 "only square matrices are supported");
2148 if (
self->col_num == 3) {
2151 else if (
self->col_num == 4) {
2155 PyErr_SetString(PyExc_ValueError,
2156 "Matrix.normalize(): "
2157 "can only use a 3x3 or 4x4 matrix");
2166 Matrix_normalized_doc,
2167 ".. method:: normalized()\n"
2169 " Return a column normalized matrix\n"
2171 " :return: a column normalized matrix\n"
2172 " :rtype: :class:`Matrix`\n"
2174 " .. note:: for 4x4 matrices, the 4th column (translation) is left untouched.\n");
2189 ".. method:: zero()\n"
2191 " Set all the matrix values to zero.\n");
2217 if (
self->col_num == 2) {
2220 else if (
self->col_num == 3) {
2230 Matrix_identity_doc,
2231 ".. method:: identity()\n"
2233 " Set the matrix to the identity matrix.\n"
2235 " .. note:: An object with a location and rotation of zero, and a scale of one\n"
2236 " will have an identity matrix.\n"
2238 " .. seealso:: `Identity matrix <https://en.wikipedia.org/wiki/Identity_matrix>`__ "
2246 if (
self->col_num !=
self->row_num) {
2247 PyErr_SetString(PyExc_ValueError,
2248 "Matrix.identity(): "
2249 "only square matrices are supported");
2277 ".. method:: copy()\n"
2279 " Returns a copy of this matrix.\n"
2281 " :return: an instance of itself\n"
2282 " :rtype: :class:`Matrix`\n");
2316 for (row = 0; row <
self->row_num; row++) {
2317 rows[row] = PyTuple_New(
self->col_num);
2322 switch (
self->row_num) {
2324 return PyUnicode_FromFormat(
2331 return PyUnicode_FromFormat(
2340 return PyUnicode_FromFormat(
2352 Py_FatalError(
"Matrix(): invalid row size!");
2356#ifndef MATH_STANDALONE
2375 for (row = 0; row <
self->row_num; row++) {
2383 for (row = 0; row <
self->row_num; row++) {
2415 view->len = Py_ssize_t(
self->row_num *
self->col_num *
sizeof(
float));
2417 if ((flags & PyBUF_WRITABLE) == 0) {
2420 if (flags & PyBUF_FORMAT) {
2421 view->format = (
char *)
"f";
2423 if (flags & PyBUF_ND) {
2429 if (flags & PyBUF_STRIDES) {
2432 view->strides[1] = Py_ssize_t(
self->row_num) *
sizeof(
float);
2446 if (
view->readonly == 0) {
2491 res = ok ? Py_False : Py_True;
2498 res = Py_NotImplemented;
2502 PyErr_BadArgument();
2507 return Py_NewRef(res);
2542 return self->row_num;
2555 if (row < 0 || row >=
self->row_num) {
2556 PyErr_SetString(PyExc_IndexError,
2557 "matrix[attribute]: "
2558 "array index out of range");
2575 PyErr_SetString(PyExc_IndexError,
2576 "matrix[attribute]: "
2577 "array index out of range");
2593 if (row >=
self->row_num || row < 0) {
2594 PyErr_SetString(PyExc_IndexError,
"matrix[attribute] = x: bad row");
2599 vec,
self->col_num,
self->col_num, value,
"matrix[i] = value assignment") == -1)
2623 PyErr_SetString(PyExc_IndexError,
"matrix[attribute] = x: bad col");
2628 vec,
self->row_num,
self->row_num, value,
"matrix[i] = value assignment") == -1)
2634 for (row = 0; row <
self->row_num; row++) {
2657 tuple = PyTuple_New(end -
begin);
2659 PyTuple_SET_ITEM(tuple,
2671 PyObject *value_fast;
2682 if (!(value_fast = PySequence_Fast(value,
"matrix[begin:end] = value"))) {
2687 PyObject **value_fast_items = PySequence_Fast_ITEMS(value_fast);
2693 if (PySequence_Fast_GET_SIZE(value_fast) !=
size) {
2695 PyErr_SetString(PyExc_ValueError,
2696 "matrix[begin:end] = []: "
2697 "size mismatch in slice assignment");
2701 memcpy(mat,
self->matrix,
self->col_num *
self->row_num *
sizeof(
float));
2704 for (row =
begin; row < end; row++) {
2706 PyObject *item = value_fast_items[row -
begin];
2709 vec,
self->col_num,
self->col_num, item,
"matrix[begin:end] = value assignment") == -1)
2723 memcpy(
self->matrix, mat,
self->col_num *
self->row_num *
sizeof(
float));
2732 if (PyIndex_Check(item)) {
2734 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2735 if (
i == -1 && PyErr_Occurred()) {
2743 if (PySlice_Check(item)) {
2744 Py_ssize_t start, stop,
step, slicelength;
2746 if (PySlice_GetIndicesEx(item,
self->row_num, &start, &stop, &
step, &slicelength) < 0) {
2750 if (slicelength <= 0) {
2751 return PyTuple_New(0);
2757 PyErr_SetString(PyExc_IndexError,
"slice steps not supported with matrices");
2762 PyExc_TypeError,
"matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
2769 if (PyIndex_Check(item)) {
2770 Py_ssize_t
i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2771 if (
i == -1 && PyErr_Occurred()) {
2779 if (PySlice_Check(item)) {
2780 Py_ssize_t start, stop,
step, slicelength;
2782 if (PySlice_GetIndicesEx(item,
self->row_num, &start, &stop, &
step, &slicelength) < 0) {
2790 PyErr_SetString(PyExc_IndexError,
"slice steps not supported with matrices");
2795 PyExc_TypeError,
"matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
2815 PyErr_Format(PyExc_TypeError,
2816 "Matrix addition: (%s + %s) "
2817 "invalid type for this operation",
2818 Py_TYPE(m1)->tp_name,
2819 Py_TYPE(m2)->tp_name);
2827 if (mat1->
col_num != mat2->col_num || mat1->
row_num != mat2->row_num) {
2828 PyErr_SetString(PyExc_ValueError,
2830 "matrices must have the same dimensions for this operation");
2849 PyErr_Format(PyExc_TypeError,
2850 "Matrix subtraction: (%s - %s) "
2851 "invalid type for this operation",
2852 Py_TYPE(m1)->tp_name,
2853 Py_TYPE(m2)->tp_name);
2861 if (mat1->
col_num != mat2->col_num || mat1->
row_num != mat2->row_num) {
2862 PyErr_SetString(PyExc_ValueError,
2864 "matrices must have the same dimensions for this operation");
2904 if ((mat1->
row_num != mat2->row_num) || (mat1->
col_num != mat2->col_num)) {
2905 PyErr_SetString(PyExc_ValueError,
2906 "matrix1 * matrix2: matrix1 number of rows/columns "
2907 "and the matrix2 number of rows/columns must be the same");
2917 if (((scalar = PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred()) == 0) {
2923 if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) {
2928 PyErr_Format(PyExc_TypeError,
2929 "Element-wise multiplication: "
2930 "not supported between '%.200s' and '%.200s' types",
2931 Py_TYPE(m1)->tp_name,
2932 Py_TYPE(m2)->tp_name);
2958 if ((mat1->
row_num != mat2->row_num) || (mat1->
col_num != mat2->col_num)) {
2959 PyErr_SetString(PyExc_ValueError,
2960 "matrix1 *= matrix2: matrix1 number of rows/columns "
2961 "and the matrix2 number of rows/columns must be the same");
2967 else if (mat1 && (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0)) {
2972 PyErr_Format(PyExc_TypeError,
2973 "In place element-wise multiplication: "
2974 "not supported between '%.200s' and '%.200s' types",
2975 Py_TYPE(m1)->tp_name,
2976 Py_TYPE(m2)->tp_name);
3011 if (mat1->
col_num != mat2->row_num) {
3012 PyErr_SetString(PyExc_ValueError,
3013 "matrix1 * matrix2: matrix1 number of columns "
3014 "and the matrix2 number of rows must be the same");
3018 for (
col = 0;
col < mat2->col_num;
col++) {
3019 for (row = 0; row < mat1->
row_num; row++) {
3021 for (item = 0; item < mat1->
col_num; item++) {
3053 PyErr_Format(PyExc_TypeError,
3054 "Matrix multiplication: "
3055 "not supported between '%.200s' and '%.200s' types",
3056 Py_TYPE(m1)->tp_name,
3057 Py_TYPE(m2)->tp_name);
3084 if (mat1->
col_num != mat2->row_num) {
3085 PyErr_SetString(PyExc_ValueError,
3086 "matrix1 * matrix2: matrix1 number of columns "
3087 "and the matrix2 number of rows must be the same");
3091 for (
col = 0;
col < mat2->col_num;
col++) {
3092 for (row = 0; row < mat1->
row_num; row++) {
3094 for (item = 0; item < mat1->
col_num; item++) {
3104 memcpy(mat1->matrix, mat, (mat1->
row_num * mat1->
col_num) *
sizeof(
float));
3107 PyErr_Format(PyExc_TypeError,
3108 "In place matrix multiplication: "
3109 "not supported between '%.200s' and '%.200s' types",
3110 Py_TYPE(m1)->tp_name,
3111 Py_TYPE(m2)->tp_name);
3192 Matrix_translation_doc,
3193 "The translation component of the matrix.\n"
3195 ":type: :class:`Vector`\n");
3205 if (
self->row_num != 4 ||
self->col_num != 4) {
3206 PyErr_SetString(PyExc_AttributeError,
3207 "Matrix.translation: "
3208 "inappropriate matrix size, must be 4x4");
3226 if (
self->row_num != 4 ||
self->col_num != 4) {
3227 PyErr_SetString(PyExc_AttributeError,
3228 "Matrix.translation: "
3229 "inappropriate matrix size, must be 4x4");
3247 "Access the matrix by rows (default), (read-only).\n"
3249 ":type: Matrix Access\n");
3258 "Access the matrix by columns, 3x3 and 4x4 only, (read-only).\n"
3260 ":type: Matrix Access\n");
3268 Matrix_median_scale_doc,
3269 "The average scale applied to each axis (read-only).\n"
3281 if ((
self->row_num < 3) || (
self->col_num < 3)) {
3282 PyErr_SetString(PyExc_AttributeError,
3283 "Matrix.median_scale: "
3284 "inappropriate matrix size, 3x3 minimum");
3295 Matrix_is_identity_doc,
3296 "True if this is an identity matrix (read-only).\n"
3309 Matrix_is_negative_doc,
3310 "True if this matrix results in a negative scale, 3x3 and 4x4 only, "
3321 if (
self->row_num == 4 &&
self->col_num == 4) {
3324 if (
self->row_num == 3 &&
self->col_num == 3) {
3328 PyErr_SetString(PyExc_AttributeError,
3329 "Matrix.is_negative: "
3330 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
3336 Matrix_is_orthogonal_doc,
3337 "True if this matrix is orthogonal, 3x3 and 4x4 only, (read-only).\n"
3347 if (
self->row_num == 4 &&
self->col_num == 4) {
3350 if (
self->row_num == 3 &&
self->col_num == 3) {
3354 PyErr_SetString(PyExc_AttributeError,
3355 "Matrix.is_orthogonal: "
3356 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
3362 Matrix_is_orthogonal_axis_vectors_doc,
3363 "True if this matrix has got orthogonal axis vectors, 3x3 and 4x4 only, "
3374 if (
self->row_num == 4 &&
self->col_num == 4) {
3377 if (
self->row_num == 3 &&
self->col_num == 3) {
3381 PyErr_SetString(PyExc_AttributeError,
3382 "Matrix.is_orthogonal_axis_vectors: "
3383 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
3397 Matrix_median_scale_doc,
3402 Matrix_translation_doc,
3404 {
"row", (getter)
Matrix_row_get, (setter)
nullptr, Matrix_row_doc,
nullptr},
3405 {
"col", (getter)
Matrix_col_get, (setter)
nullptr, Matrix_col_doc,
nullptr},
3409 Matrix_is_identity_doc,
3414 Matrix_is_negative_doc,
3419 Matrix_is_orthogonal_doc,
3421 {
"is_orthogonal_axis_vectors",
3424 Matrix_is_orthogonal_axis_vectors_doc,
3446 {
nullptr,
nullptr,
nullptr,
nullptr,
nullptr}
3457# pragma clang diagnostic push
3458# pragma clang diagnostic ignored "-Wcast-function-type"
3460# pragma GCC diagnostic push
3461# pragma GCC diagnostic ignored "-Wcast-function-type"
3467 {
"determinant", (PyCFunction)
Matrix_determinant, METH_NOARGS, Matrix_determinant_doc},
3468 {
"decompose", (PyCFunction)
Matrix_decompose, METH_NOARGS, Matrix_decompose_doc},
3471 {
"zero", (PyCFunction)
Matrix_zero, METH_NOARGS, Matrix_zero_doc},
3472 {
"identity", (PyCFunction)
Matrix_identity, METH_NOARGS, Matrix_identity_doc},
3475 {
"transpose", (PyCFunction)
Matrix_transpose, METH_NOARGS, Matrix_transpose_doc},
3476 {
"transposed", (PyCFunction)
Matrix_transposed, METH_NOARGS, Matrix_transposed_doc},
3477 {
"normalize", (PyCFunction)
Matrix_normalize, METH_NOARGS, Matrix_normalize_doc},
3478 {
"normalized", (PyCFunction)
Matrix_normalized, METH_NOARGS, Matrix_normalized_doc},
3479 {
"invert", (PyCFunction)
Matrix_invert, METH_VARARGS, Matrix_invert_doc},
3480 {
"inverted", (PyCFunction)
Matrix_inverted, METH_VARARGS, Matrix_inverted_doc},
3481 {
"invert_safe", (PyCFunction)
Matrix_invert_safe, METH_NOARGS, Matrix_invert_safe_doc},
3483 {
"adjugate", (PyCFunction)
Matrix_adjugate, METH_NOARGS, Matrix_adjugate_doc},
3484 {
"adjugated", (PyCFunction)
Matrix_adjugated, METH_NOARGS, Matrix_adjugated_doc},
3485 {
"to_2x2", (PyCFunction)
Matrix_to_2x2, METH_NOARGS, Matrix_to_2x2_doc},
3486 {
"to_3x3", (PyCFunction)
Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc},
3487 {
"to_4x4", (PyCFunction)
Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc},
3489 {
"resize_4x4", (PyCFunction)
Matrix_resize_4x4, METH_NOARGS, Matrix_resize_4x4_doc},
3490 {
"rotate", (PyCFunction)
Matrix_rotate, METH_O, Matrix_rotate_doc},
3493 {
"to_euler", (PyCFunction)
Matrix_to_euler, METH_VARARGS, Matrix_to_euler_doc},
3495 {
"to_scale", (PyCFunction)
Matrix_to_scale, METH_NOARGS, Matrix_to_scale_doc},
3499 {
"lerp", (PyCFunction)
Matrix_lerp, METH_VARARGS, Matrix_lerp_doc},
3500 {
"copy", (PyCFunction)
Matrix_copy, METH_NOARGS, Matrix_copy_doc},
3501 {
"__copy__", (PyCFunction)
Matrix_copy, METH_NOARGS, Matrix_copy_doc},
3502 {
"__deepcopy__", (PyCFunction)
Matrix_deepcopy, METH_VARARGS, Matrix_copy_doc},
3508 {
"Identity", (PyCFunction)
C_Matrix_Identity, METH_VARARGS | METH_CLASS, C_Matrix_Identity_doc},
3509 {
"Rotation", (PyCFunction)
C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc},
3510 {
"Scale", (PyCFunction)
C_Matrix_Scale, METH_VARARGS | METH_CLASS, C_Matrix_Scale_doc},
3511 {
"Shear", (PyCFunction)
C_Matrix_Shear, METH_VARARGS | METH_CLASS, C_Matrix_Shear_doc},
3512 {
"Diagonal", (PyCFunction)
C_Matrix_Diagonal, METH_O | METH_CLASS, C_Matrix_Diagonal_doc},
3515 METH_O | METH_CLASS,
3516 C_Matrix_Translation_doc},
3519 METH_VARARGS | METH_CLASS,
3520 C_Matrix_OrthoProjection_doc},
3523 METH_VARARGS | METH_CLASS,
3524 C_Matrix_LocRotScale_doc},
3525 {
nullptr,
nullptr, 0,
nullptr},
3530# pragma clang diagnostic pop
3532# pragma GCC diagnostic pop
3542#ifdef MATH_STANDALONE
3543# define Matrix_str nullptr
3549 ".. class:: Matrix(rows=Matrix.Identity(4), /)\n"
3551 " This object gives access to Matrices in Blender, supporting square and rectangular\n"
3552 " matrices from 2x2 up to 4x4.\n"
3554 " :arg rows: Sequence of rows.\n"
3555 " :type rows: Sequence[Sequence[float]]\n");
3557 PyVarObject_HEAD_INIT(
nullptr, 0)
3576 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
3608#ifdef MATH_STANDALONE
3621 PyTypeObject *base_type)
3627 if (col_num < 2 || col_num > 4 || row_num < 2 || row_num > 4) {
3628 PyErr_SetString(PyExc_RuntimeError,
3630 "row and column sizes must be between 2 and 4");
3634 mat_alloc =
static_cast<float *
>(PyMem_Malloc(col_num * row_num *
sizeof(
float)));
3635 if (
UNLIKELY(mat_alloc ==
nullptr)) {
3636 PyErr_SetString(PyExc_MemoryError,
3638 "problem allocating data");
3644 self->matrix = mat_alloc;
3645 self->col_num = col_num;
3646 self->row_num = row_num;
3649 self->cb_user =
nullptr;
3650 self->cb_type =
self->cb_subtype = 0;
3653 memcpy(
self->matrix, mat, col_num * row_num *
sizeof(
float));
3655 else if (col_num == row_num) {
3661 memset(
self->matrix, 0, col_num * row_num *
sizeof(
float));
3666 PyMem_Free(mat_alloc);
3669 return (PyObject *)
self;
3675 PyTypeObject *base_type)
3680 if (col_num < 2 || col_num > 4 || row_num < 2 || row_num > 4) {
3681 PyErr_SetString(PyExc_RuntimeError,
3683 "row and column sizes must be between 2 and 4");
3689 self->col_num = col_num;
3690 self->row_num = row_num;
3693 self->cb_user =
nullptr;
3694 self->cb_type =
self->cb_subtype = 0;
3699 return (PyObject *)
self;
3708 self->cb_user = cb_user;
3709 self->cb_type = cb_type;
3710 self->cb_subtype = cb_subtype;
3712 PyObject_GC_Track(
self);
3714 return (PyObject *)
self;
3720 PyTypeObject *base_type)
3728 return (PyObject *)
self;
3744 PyExc_TypeError,
"expected a mathutils.Matrix, not a %.200s", Py_TYPE(pymat)->tp_name);
3775 PyErr_SetString(PyExc_ValueError,
"matrix must be 2x2");
3792 PyErr_SetString(PyExc_ValueError,
"matrix must be 3x3");
3809 PyErr_SetString(PyExc_ValueError,
"matrix must be 4x4");
3831 Py_VISIT(
self->matrix_user);
3837 Py_CLEAR(
self->matrix_user);
3843 if (
self->matrix_user) {
3844 PyObject_GC_UnTrack(
self);
3869 int matrix_access_len;
3870 PyObject *(*Matrix_item_new)(
MatrixObject *, Py_ssize_t);
3873 matrix_access_len = matrix_user->
row_num;
3877 matrix_access_len = matrix_user->
col_num;
3883 end = (matrix_access_len + 1) + end;
3885 CLAMP(end, 0, matrix_access_len);
3888 tuple = PyTuple_New(end -
begin);
3890 PyTuple_SET_ITEM(tuple,
count -
begin, Matrix_item_new(matrix_user,
count));
3900 if (PyIndex_Check(item)) {
3902 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
3903 if (
i == -1 && PyErr_Occurred()) {
3918 if (PySlice_Check(item)) {
3919 Py_ssize_t start, stop,
step, slicelength;
3926 if (slicelength <= 0) {
3927 return PyTuple_New(0);
3933 PyErr_SetString(PyExc_IndexError,
"slice steps not supported with matrix accessors");
3938 PyExc_TypeError,
"matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
3946 if (PyIndex_Check(item)) {
3947 Py_ssize_t
i = PyNumber_AsSsize_t(item, PyExc_IndexError);
3948 if (
i == -1 && PyErr_Occurred()) {
3967 PyExc_TypeError,
"matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
3975 PyObject *iter =
nullptr;
3981 iter = PyObject_GetIter(
ret);
4001 PyVarObject_HEAD_INIT(
nullptr, 0)
4020 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
4066 matrix_access->
type = type;
4068 return (PyObject *)matrix_access;
#define BLI_assert_unreachable()
A dynamically sized string ADT.
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
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()
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])
void mat3_to_quat(float q[4], const float mat[3][3])
void quat_to_mat4(float m[4][4], const float q[4])
void angle_to_mat2(float R[2][2], float angle)
void eulO_to_mat4(float mat[4][4], const float e[3], short order)
void mat3_normalized_to_eul(float eul[3], const float mat[3][3])
void mat4_to_quat(float q[4], const float mat[4][4])
void mat3_normalized_to_quat_fast(float q[4], const float mat[3][3])
void mat3_normalized_to_eulO(float eul[3], short order, const float m[3][3])
float angle_wrap_rad(float angle)
void axis_angle_to_mat3(float R[3][3], const float axis[3], float angle)
void mat3_normalized_to_compatible_eulO(float eul[3], const float oldrot[3], short order, const float mat[3][3])
void mul_vn_fl(float *array_tar, int size, float f)
void sub_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, int size)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void add_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, int size)
void copy_vn_fl(float *array_tar, int size, float val)
void mul_vn_vn(float *array_tar, const float *array_src, int size)
MINLINE void zero_v3(float r[3])
void mul_vn_vn_fl(float *array_tar, const float *array_src, int size, float f)
void mul_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, int size)
#define SNPRINTF_UTF8_RLEN(dst, format,...)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
SIMD_FORCE_INLINE btScalar norm() const
Return the norm (length) of the vector.
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
int BaseMathObject_is_gc(BaseMathObject *self)
Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
void BaseMathObject_dealloc(BaseMathObject *self)
int EXPP_VectorsAreEqual(const float *vecA, const float *vecB, int size, int floatSteps)
int mathutils_array_parse(float *array, int array_num_min, int array_num_max, PyObject *value, const char *error_prefix)
char BaseMathObject_is_valid_doc[]
char BaseMathObject_is_wrapped_doc[]
PyObject * BaseMathObject_owner_get(BaseMathObject *self, void *)
char BaseMathObject_is_frozen_doc[]
PyObject * mathutils_dynstr_to_py(DynStr *ds)
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
PyObject * BaseMathObject_is_frozen_get(BaseMathObject *self, void *)
PyObject * BaseMathObject_freeze(BaseMathObject *self)
PyObject * BaseMathObject_is_wrapped_get(BaseMathObject *self, void *)
char BaseMathObject_owner_doc[]
char BaseMathObject_freeze_doc[]
PyObject * BaseMathObject_is_valid_get(BaseMathObject *self, void *)
int BaseMathObject_clear(BaseMathObject *self)
int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
#define BaseMathObject_Prepare_ForResize(_self, error_prefix)
#define BaseMath_ReadCallback_ForWrite(_self)
#define BaseMath_Prepare_ForBufferAccess(_self, _view, _flags)
#define BaseMath_WriteCallback(_self)
#define BASE_MATH_NEW(struct_name, root_type, base_type)
#define BaseMathObject_Prepare_ForHash(_self)
int column_vector_multiplication(float r_vec[4], VectorObject *vec, MatrixObject *mat)
#define BASE_MATH_FLAG_DEFAULT
#define BaseMath_Prepare_ForWrite(_self)
@ BASE_MATH_FLAG_HAS_BUFFER_VIEW
#define BaseMath_ReadCallback(_self)
short euler_order_from_string(const char *str, const char *error_prefix)
PyObject * Euler_CreatePyObject(const float eul[3], const short order, PyTypeObject *base_type)
#define EulerObject_Check(v)
static PyObject * Matrix_repr(MatrixObject *self)
int Matrix_Parse3x3(PyObject *o, void *p)
static bool matrix_invert_internal(const MatrixObject *self, float *r_mat)
PyObject * Matrix_CreatePyObject_cb(PyObject *cb_user, const ushort col_num, const ushort row_num, uchar cb_type, uchar cb_subtype)
static PyObject * Matrix_is_identity_get(MatrixObject *self, void *)
PyObject * Matrix_CreatePyObject(const float *mat, const ushort col_num, const ushort row_num, PyTypeObject *base_type)
static PyMappingMethods MatrixAccess_AsMapping
static PyGetSetDef Matrix_getseters[]
static PyObject * MatrixAccess_slice(MatrixAccessObject *self, Py_ssize_t begin, Py_ssize_t end)
static int mathutils_matrix_col_set(BaseMathObject *bmo, int col)
static PyObject * C_Matrix_Identity(PyObject *cls, PyObject *args)
int Matrix_ParseAny(PyObject *o, void *p)
static Py_ssize_t Matrix_len(MatrixObject *self)
static int mathutils_matrix_row_set(BaseMathObject *bmo, int row)
static int matrix_row_vector_check(MatrixObject *mat, VectorObject *vec, int row)
static PyObject * Matrix_to_translation(MatrixObject *self)
static int mathutils_matrix_row_get_index(BaseMathObject *bmo, int row, int col)
static PyObject * C_Matrix_Rotation(PyObject *cls, PyObject *args)
static PyObject * Matrix_col_get(MatrixObject *self, void *)
static int Matrix_ass_subscript(MatrixObject *self, PyObject *item, PyObject *value)
static PyObject * Matrix_row_get(MatrixObject *self, void *)
static PyObject * Matrix_decompose(MatrixObject *self)
static int mathutils_matrix_row_set_index(BaseMathObject *bmo, int row, int col)
static int mathutils_matrix_col_get(BaseMathObject *bmo, int col)
static PyObject * Matrix_str(MatrixObject *self)
static void matrix_invert_raise_degenerate()
static PyObject * Matrix_imatmul(PyObject *m1, PyObject *m2)
static void matrix_transpose_internal(float mat_dst_fl[], const MatrixObject *mat_src)
static void matrix_identity_internal(MatrixObject *self)
static PyObject * Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
static PyObject * Matrix_mul(PyObject *m1, PyObject *m2)
static PyObject * Matrix_item_row(MatrixObject *self, Py_ssize_t row)
static PyObject * matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *), MatrixObject *self)
static PyObject * Matrix_is_orthogonal_get(MatrixObject *self, void *)
static PyObject * MatrixAccess_subscript(MatrixAccessObject *self, PyObject *item)
static PyObject * Matrix_to_2x2(MatrixObject *self)
static PyObject * Matrix_slice(MatrixObject *self, int begin, int end)
static int mathutils_matrix_row_check(BaseMathObject *bmo)
static int MatrixAccess_clear(MatrixAccessObject *self)
PyObject * Matrix_CreatePyObject_alloc(float *mat, const ushort col_num, const ushort row_num, PyTypeObject *base_type)
static PyObject * Matrix_transposed(MatrixObject *self)
static float matrix_determinant_internal(const MatrixObject *self)
static PyObject * Matrix_inverted_safe(MatrixObject *self)
static PyObject * Matrix_matmul(PyObject *m1, PyObject *m2)
static PyMethodDef Matrix_methods[]
static PyObject * Matrix_inverted_noargs(MatrixObject *self)
static PyObject * C_Matrix_LocRotScale(PyObject *cls, PyObject *args)
static void matrix_unit_internal(MatrixObject *self)
Mathutils_Callback mathutils_matrix_col_cb
static void adjoint_matrix_n(float *mat_dst, const float *mat_src, const ushort dim)
static PyObject * Matrix_is_orthogonal_axis_vectors_get(MatrixObject *self, void *)
static bool matrix_invert_is_compat(const MatrixObject *self)
static PyObject * Matrix_is_negative_get(MatrixObject *self, void *)
static bool matrix_is_identity(MatrixObject *self)
static int mathutils_matrix_translation_set_index(BaseMathObject *bmo, int col, int row)
static int Matrix_getbuffer(PyObject *obj, Py_buffer *view, int flags)
PyTypeObject matrix_access_Type
static PyObject * Matrix_invert_safe(MatrixObject *self)
static PyObject * Matrix_adjugated(MatrixObject *self)
static PyNumberMethods Matrix_NumMethods
static PyObject * Matrix_to_4x4(MatrixObject *self)
static void Matrix_releasebuffer(PyObject *, Py_buffer *view)
static PySequenceMethods Matrix_SeqMethods
static int mathutils_matrix_col_get_index(BaseMathObject *bmo, int col, int row)
PyObject * Matrix_CreatePyObject_wrap(float *mat, const ushort col_num, const ushort row_num, PyTypeObject *base_type)
static int mathutils_matrix_translation_get_index(BaseMathObject *bmo, int col, int row)
static void matrix_invert_with_det_n_internal(float *mat_dst, const float *mat_src, const float det, const ushort dim)
static PyObject * Matrix_deepcopy(MatrixObject *self, PyObject *args)
static PyObject * Matrix_sub(PyObject *m1, PyObject *m2)
static PyObject * Matrix_identity(MatrixObject *self)
void matrix_as_3x3(float mat[3][3], MatrixObject *self)
static bool Matrix_ParseCheck(MatrixObject *pymat)
static PyMappingMethods Matrix_AsMapping
static PyObject * C_Matrix_Translation(PyObject *cls, PyObject *value)
static PyObject * Matrix_copy(MatrixObject *self)
static PyObject * Matrix_richcmpr(PyObject *a, PyObject *b, int op)
static void matrix_3x3_as_4x4(float mat[16])
static PyObject * Matrix_subscript(MatrixObject *self, PyObject *item)
int Matrix_Parse2x2(PyObject *o, void *p)
Mathutils_Callback mathutils_matrix_row_cb
static int mathutils_matrix_translation_get(BaseMathObject *bmo, int col)
static int MatrixAccess_traverse(MatrixAccessObject *self, visitproc visit, void *arg)
static PyObject * Matrix_median_scale_get(MatrixObject *self, void *)
static PyObject * Matrix_normalized(MatrixObject *self)
Mathutils_Callback mathutils_matrix_translation_cb
static PyObject * Matrix_translation_get(MatrixObject *self, void *)
static int Matrix_translation_set(MatrixObject *self, PyObject *value, void *)
static PyObject * Matrix_imul(PyObject *m1, PyObject *m2)
static PyObject * Matrix_determinant(MatrixObject *self)
static PyObject * C_Matrix_Diagonal(PyObject *cls, PyObject *value)
static PyObject * Matrix_to_scale(MatrixObject *self)
static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value)
int Matrix_Parse4x4(PyObject *o, void *p)
static PyObject * Matrix_invert(MatrixObject *self, PyObject *args)
static PyObject * Matrix_transpose(MatrixObject *self)
uchar mathutils_matrix_col_cb_index
static PyObject * Matrix_item_col(MatrixObject *self, Py_ssize_t col)
static int Matrix_ass_item_col(MatrixObject *self, int col, PyObject *value)
uchar mathutils_matrix_row_cb_index
static int Matrix_ass_item_row(MatrixObject *self, Py_ssize_t row, PyObject *value)
static PyObject * Matrix_resize_4x4(MatrixObject *self)
static PyObject * C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
static PyObject * Matrix_normalize(MatrixObject *self)
static PyObject * C_Matrix_Scale(PyObject *cls, PyObject *args)
static Py_ssize_t MatrixAccess_len(MatrixAccessObject *self)
static PyObject * Matrix_adjugate(MatrixObject *self)
static PyObject * Matrix_to_NxN(MatrixObject *self, const int col_num, const int row_num)
static int MatrixAccess_ass_subscript(MatrixAccessObject *self, PyObject *item, PyObject *value)
static int mathutils_matrix_row_get(BaseMathObject *bmo, int row)
static PyObject * C_Matrix_Shear(PyObject *cls, PyObject *args)
static int matrix_col_vector_check(MatrixObject *mat, VectorObject *vec, int col)
static PyObject * Matrix_to_quaternion(MatrixObject *self)
static PyObject * matrix_mul_float(MatrixObject *mat, const float scalar)
static PyObject * MatrixAccess_iter(MatrixAccessObject *self)
static bool matrix_invert_args_check(const MatrixObject *self, PyObject *args, bool check_type)
static int mathutils_matrix_translation_check(BaseMathObject *bmo)
static void MatrixAccess_dealloc(MatrixAccessObject *self)
static PyObject * Matrix_lerp(MatrixObject *self, PyObject *args)
static int mathutils_matrix_col_check(BaseMathObject *bmo)
static void matrix_copy(MatrixObject *mat_dst, const MatrixObject *mat_src)
static Py_hash_t Matrix_hash(MatrixObject *self)
static int mathutils_matrix_col_set_index(BaseMathObject *bmo, int col, int row)
static PyObject * Matrix_to_euler(MatrixObject *self, PyObject *args)
static PyObject * Matrix_add(PyObject *m1, PyObject *m2)
static PyObject * Matrix_rotate(MatrixObject *self, PyObject *value)
static int mathutils_matrix_translation_set(BaseMathObject *bmo, int col)
static PyObject * Matrix_to_3x3(MatrixObject *self)
PyDoc_STRVAR(C_Matrix_Identity_doc, ".. classmethod:: Identity(size, /)\n" "\n" " Create an identity matrix.\n" "\n" " :arg size: The size of the identity matrix to construct [2, 4].\n" " :type size: int\n" " :return: A new identity matrix.\n" " :rtype: :class:`Matrix`\n")
static PyObject * Matrix_copy_notest(MatrixObject *self, const float *matrix)
static PyObject * Matrix_inverted(MatrixObject *self, PyObject *args)
static PyObject * Matrix_zero(MatrixObject *self)
static PyObject * MatrixAccess_CreatePyObject(MatrixObject *matrix, const eMatrixAccess_t type)
static void matrix_invert_safe_internal(const MatrixObject *self, float *r_mat)
uchar mathutils_matrix_translation_cb_index
static PyBufferProcs Matrix_as_buffer
static PyObject * Matrix_vectorcall(PyObject *type, PyObject *const *args, const size_t nargsf, PyObject *kwnames)
#define MATRIX_COL_PTR(_mat, _col)
#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)
int PyC_CheckArgs_DeepCopy(PyObject *args)
#define PyTuple_SET_ITEMS(op_arg,...)
PyObject_HEAD MatrixObject * matrix_user