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) {
287 Py_DECREF(ret_dummy);
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++) {
597static PyObject *
Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
599 if (kwds && PyDict_Size(kwds)) {
600 PyErr_SetString(PyExc_TypeError,
602 "takes no keyword args");
606 switch (PyTuple_GET_SIZE(args)) {
610 PyObject *arg = PyTuple_GET_ITEM(args, 0);
615 const ushort row_num = PySequence_Size(arg);
617 if (row_num >= 2 && row_num <= 4) {
618 PyObject *item = PySequence_GetItem(arg, 0);
621 const ushort col_num = PySequence_Size(item);
624 if (col_num >= 2 && col_num <= 4) {
639 PyErr_SetString(PyExc_TypeError,
641 "expects no args or a single arg containing 2-4 numeric sequences");
654 C_Matrix_Identity_doc,
655 ".. classmethod:: Identity(size)\n"
657 " Create an identity matrix.\n"
659 " :arg size: The size of the identity matrix to construct [2, 4].\n"
661 " :return: A new identity matrix.\n"
662 " :rtype: :class:`Matrix`\n");
667 if (!PyArg_ParseTuple(args,
"i:Matrix.Identity", &matSize)) {
671 if (matSize < 2 || matSize > 4) {
672 PyErr_SetString(PyExc_RuntimeError,
673 "Matrix.Identity(): "
674 "size must be between 2 and 4");
684 C_Matrix_Rotation_doc,
685 ".. classmethod:: Rotation(angle, size, axis)\n"
687 " Create a matrix representing a rotation.\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"
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");
700 PyObject *vec =
nullptr;
701 const char *axis =
nullptr;
704 float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
706 if (!PyArg_ParseTuple(args,
"di|O:Matrix.Rotation", &angle, &matSize, &vec)) {
710 if (vec && PyUnicode_Check(vec)) {
711 axis = PyUnicode_AsUTF8((PyObject *)vec);
712 if (axis ==
nullptr || axis[0] ==
'\0' || axis[1] !=
'\0' || axis[0] <
'X' || axis[0] >
'Z') {
713 PyErr_SetString(PyExc_ValueError,
714 "Matrix.Rotation(): "
715 "3rd argument axis value must be a 3D vector "
716 "or a string in 'X', 'Y', 'Z'");
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");
732 if (matSize == 2 && (vec !=
nullptr)) {
733 PyErr_SetString(PyExc_ValueError,
734 "Matrix.Rotation(): "
735 "cannot create a 2x2 rotation matrix around arbitrary axis");
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");
750 tvec, 3, 3, vec,
"Matrix.Rotation(angle, size, axis), invalid 'axis' arg") == -1)
757 else if (matSize == 2) {
775 C_Matrix_Translation_doc,
776 ".. classmethod:: Translation(vector)\n"
778 " Create a matrix representing a translation.\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");
791 mat[3], 3, 4, value,
"mathutils.Matrix.Translation(vector), invalid vector arg") == -1)
801 C_Matrix_Diagonal_doc,
802 ".. classmethod:: Diagonal(vector)\n"
804 " Create a diagonal (scaling) matrix using the values from the vector.\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");
813 float mat[16] = {0.0f};
817 vec, 2, 4, value,
"mathutils.Matrix.Diagonal(vector), invalid vector arg");
823 for (
int i = 0; i <
size; i++) {
824 mat[size * i + i] = vec[i];
834 ".. classmethod:: Scale(factor, size, axis)\n"
836 " Create a matrix representing a scaling.\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"
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");
848 PyObject *vec =
nullptr;
853 float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
855 if (!PyArg_ParseTuple(args,
"fi|O:Matrix.Scale", &factor, &matSize, &vec)) {
858 if (!
ELEM(matSize, 2, 3, 4)) {
859 PyErr_SetString(PyExc_ValueError,
861 "can only return a 2x2 3x3 or 4x4 matrix");
865 vec_num = (matSize == 2 ? 2 : 3);
867 tvec, vec_num, vec_num, vec,
"Matrix.Scale(factor, size, axis), invalid 'axis' arg") ==
873 if (vec ==
nullptr) {
889 for (x = 0; x < vec_num; x++) {
890 norm += tvec[
x] * tvec[
x];
893 for (x = 0; x < vec_num; x++) {
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]));
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]));
923 C_Matrix_OrthoProjection_doc,
924 ".. classmethod:: OrthoProjection(axis, size)\n"
926 " Create a matrix to represent an orthographic projection.\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"
934 " :return: A new projection matrix.\n"
935 " :rtype: :class:`Matrix`\n");
942 float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
944 if (!PyArg_ParseTuple(args,
"Oi:Matrix.OrthoProjection", &axis, &matSize)) {
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");
954 if (PyUnicode_Check(axis)) {
955 Py_ssize_t plane_len;
956 const char *plane = PyUnicode_AsUTF8AndSize(axis, &plane_len);
958 if (plane_len == 1 && plane[0] ==
'X') {
961 else if (plane_len == 1 && plane[0] ==
'Y') {
965 PyErr_Format(PyExc_ValueError,
966 "Matrix.OrthoProjection(): "
967 "unknown plane, expected: X, Y, not '%.200s'",
973 if (plane_len == 2 && plane[0] ==
'X' && plane[1] ==
'Y') {
977 else if (plane_len == 2 && plane[0] ==
'X' && plane[1] ==
'Z') {
981 else if (plane_len == 2 && plane[0] ==
'Y' && plane[1] ==
'Z') {
986 PyErr_Format(PyExc_ValueError,
987 "Matrix.OrthoProjection(): "
988 "unknown plane, expected: XY, XZ, YZ, not '%.200s'",
997 const int vec_num = (matSize == 2 ? 2 : 3);
1004 "Matrix.OrthoProjection(axis, size), invalid 'axis' arg") == -1)
1010 for (x = 0; x < vec_num; x++) {
1011 norm += tvec[
x] * tvec[
x];
1014 for (x = 0; x < vec_num; x++) {
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]);
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]);
1046 ".. classmethod:: Shear(plane, size, factor)\n"
1048 " Create a matrix to represent an shear transformation.\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");
1066 float mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
1068 if (!PyArg_ParseTuple(args,
"siO:Matrix.Shear", &plane, &matSize, &fac)) {
1071 if (!
ELEM(matSize, 2, 3, 4)) {
1072 PyErr_SetString(PyExc_ValueError,
1074 "can only return a 2x2 3x3 or 4x4 matrix");
1079 float const factor = PyFloat_AsDouble(fac);
1081 if (factor == -1.0f && PyErr_Occurred()) {
1082 PyErr_SetString(PyExc_TypeError,
1084 "the factor to be a float");
1092 if (
STREQ(plane,
"X")) {
1095 else if (
STREQ(plane,
"Y")) {
1099 PyErr_SetString(PyExc_ValueError,
1101 "expected: X, Y or wrong matrix size for shearing plane");
1118 if (
STREQ(plane,
"XY")) {
1122 else if (
STREQ(plane,
"XZ")) {
1126 else if (
STREQ(plane,
"YZ")) {
1131 PyErr_SetString(PyExc_ValueError,
1133 "expected: X, Y, XY, XZ, YZ");
1147 C_Matrix_LocRotScale_doc,
1148 ".. classmethod:: LocRotScale(location, rotation, scale)\n"
1150 " Create a matrix combining translation, rotation and scale,\n"
1151 " acting as the inverse of the decompose() method.\n"
1153 " Any of the inputs may be replaced with None if not needed.\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");
1166 PyObject *loc_obj, *rot_obj, *scale_obj;
1167 float mat[4][4], loc[3];
1169 if (!PyArg_ParseTuple(args,
"OOO:Matrix.LocRotScale", &loc_obj, &rot_obj, &scale_obj)) {
1174 if (loc_obj == Py_None) {
1178 loc, 3, 3, loc_obj,
"Matrix.LocRotScale(), invalid location argument") == -1)
1184 if (rot_obj == Py_None) {
1213 copy_m4_m3(mat, (
const float(*)[3])mat_obj->matrix);
1216 PyErr_SetString(PyExc_ValueError,
1217 "Matrix.LocRotScale(): "
1218 "inappropriate rotation matrix size - expects 3x3 matrix");
1223 PyErr_SetString(PyExc_ValueError,
1224 "Matrix.LocRotScale(): "
1225 "rotation argument must be Matrix, Quaternion, Euler or None");
1230 if (scale_obj != Py_None) {
1234 scale, 3, 3, scale_obj,
"Matrix.LocRotScale(), invalid scale argument") == -1)
1255 Matrix_to_quaternion_doc,
1256 ".. method:: to_quaternion()\n"
1258 " Return a quaternion representation of the rotation matrix.\n"
1260 " :return: Quaternion representation of the rotation matrix.\n"
1261 " :rtype: :class:`Quaternion`\n");
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");
1277 if (
self->row_num == 3) {
1294 Matrix_to_euler_doc,
1295 ".. method:: to_euler(order, euler_compat)\n"
1297 " Return an Euler representation of the rotation matrix\n"
1298 " (3x3 or 4x4 matrix only).\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");
1311 const char *order_str =
nullptr;
1313 float eul[3], eul_compatf[3];
1322 if (!PyArg_ParseTuple(args,
"|sO!:to_euler", &order_str, &
euler_Type, &eul_compat)) {
1335 if (
self->row_num == 3 &&
self->col_num == 3) {
1338 else if (
self->row_num == 4 &&
self->col_num == 4) {
1342 PyErr_SetString(PyExc_ValueError,
1343 "Matrix.to_euler(): "
1344 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
1386 Matrix_resize_4x4_doc,
1387 ".. method:: resize_4x4()\n"
1389 " Resize the matrix to 4x4.\n");
1396 PyErr_SetString(PyExc_ValueError,
1397 "Matrix.resize_4x4(): "
1398 "cannot resize wrapped data - make a copy and resize that");
1401 if (
self->cb_user) {
1402 PyErr_SetString(PyExc_ValueError,
1403 "Matrix.resize_4x4(): "
1404 "cannot resize owned data - make a copy and resize that");
1408 self->matrix =
static_cast<float *
>(
1410 if (
self->matrix ==
nullptr) {
1411 PyErr_SetString(PyExc_MemoryError,
1412 "Matrix.resize_4x4(): "
1413 "problem allocating pointer space");
1439 const int mat_size =
sizeof(
float) * (col_num * row_num);
1441 static_cast<float *
>(PyMem_Malloc(mat_size)), col_num, row_num, Py_TYPE(
self));
1443 if ((
self->row_num == row_num) && (
self->col_num == col_num)) {
1444 memcpy(pymat->matrix,
self->matrix, mat_size);
1447 if ((
self->col_num < col_num) || (
self->row_num < row_num)) {
1450 const int col_len_src =
min_ii(col_num,
self->col_num);
1451 const int row_len_src =
min_ii(row_num,
self->row_num);
1452 for (
int col = 0;
col < col_len_src;
col++) {
1457 return (PyObject *)pymat;
1463 ".. method:: to_2x2()\n"
1465 " Return a 2x2 copy of this matrix.\n"
1467 " :return: a new matrix.\n"
1468 " :rtype: :class:`Matrix`\n");
1480 ".. method:: to_3x3()\n"
1482 " Return a 3x3 copy of this matrix.\n"
1484 " :return: a new matrix.\n"
1485 " :rtype: :class:`Matrix`\n");
1497 ".. method:: to_4x4()\n"
1499 " Return a 4x4 copy of this matrix.\n"
1501 " :return: a new matrix.\n"
1502 " :rtype: :class:`Matrix`\n");
1520 Matrix_to_translation_doc,
1521 ".. method:: to_translation()\n"
1523 " Return the translation part of a 4 row matrix.\n"
1525 " :return: Return the translation of a matrix.\n"
1526 " :rtype: :class:`Vector`\n");
1533 if ((
self->row_num < 3) ||
self->col_num < 4) {
1534 PyErr_SetString(PyExc_ValueError,
1535 "Matrix.to_translation(): "
1536 "inappropriate matrix size");
1545 Matrix_to_scale_doc,
1546 ".. method:: to_scale()\n"
1548 " Return the scale part of a 3x3 or 4x4 matrix.\n"
1550 " :return: Return the scale of a matrix.\n"
1551 " :rtype: :class:`Vector`\n"
1553 " .. note:: This method does not return a negative scale on any axis because it is "
1554 "not possible to obtain this data from the matrix alone.\n");
1566 if ((
self->row_num < 3) || (
self->col_num < 3)) {
1567 PyErr_SetString(PyExc_ValueError,
1568 "Matrix.to_scale(): "
1569 "inappropriate matrix size, 3x3 minimum size");
1590 if (
self->col_num !=
self->row_num) {
1591 PyErr_SetString(PyExc_ValueError,
1592 "Matrix.invert(ed): "
1593 "only square matrices are supported");
1602 switch (PyTuple_GET_SIZE(args)) {
1609 PyErr_SetString(PyExc_TypeError,
1611 "expects a matrix argument or nothing");
1616 PyErr_SetString(PyExc_TypeError,
1618 "matrix argument has different dimensions");
1625 PyErr_SetString(PyExc_ValueError,
1626 "Matrix.invert(ed): "
1627 "takes at most one argument");
1634 PyErr_SetString(PyExc_ValueError,
1635 "Matrix.invert(ed): "
1636 "matrix does not have an inverse");
1642 ".. method:: invert(fallback=None)\n"
1644 " Set the matrix to its inverse.\n"
1646 " :arg fallback: Set the matrix to this value when the inverse cannot be calculated\n"
1647 " (instead of raising a :exc:`ValueError` exception).\n"
1648 " :type fallback: :class:`Matrix`\n"
1650 " .. seealso:: `Inverse matrix <https://en.wikipedia.org/wiki/Inverse_matrix>`__ on "
1670 if (PyTuple_GET_SIZE(args) == 1) {
1677 if (
self != fallback) {
1693 Matrix_inverted_doc,
1694 ".. method:: inverted(fallback=None)\n"
1696 " Return an inverted copy of the matrix.\n"
1698 " :arg fallback: return this when the inverse can't be calculated\n"
1699 " (instead of raising a :exc:`ValueError`).\n"
1700 " :type fallback: Any\n"
1701 " :return: The inverted matrix or fallback when given.\n"
1702 " :rtype: :class:`Matrix` | Any\n");
1723 if (PyTuple_GET_SIZE(args) == 1) {
1724 PyObject *fallback = PyTuple_GET_ITEM(args, 0);
1725 Py_INCREF(fallback);
1760 Matrix_invert_safe_doc,
1761 ".. method:: invert_safe()\n"
1763 " Set the matrix to its inverse, will never error.\n"
1764 " If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, "
1765 "to get an invertible one.\n"
1766 " If tweaked matrix is still degenerated, set to the identity matrix instead.\n"
1768 " .. seealso:: `Inverse Matrix <https://en.wikipedia.org/wiki/Inverse_matrix>`__ on "
1788 Matrix_inverted_safe_doc,
1789 ".. method:: inverted_safe()\n"
1791 " Return an inverted copy of the matrix, will never error.\n"
1792 " If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, "
1793 "to get an invertible one.\n"
1794 " If tweaked matrix is still degenerated, return the identity matrix instead.\n"
1796 " :return: the inverted matrix.\n"
1797 " :rtype: :class:`Matrix`\n");
1823 Matrix_adjugate_doc,
1824 ".. method:: adjugate()\n"
1826 " Set the matrix to its adjugate.\n"
1828 " :raises ValueError: if the matrix cannot be adjugate.\n"
1830 " .. seealso:: `Adjugate matrix <https://en.wikipedia.org/wiki/Adjugate_matrix>`__ on "
1838 if (
self->col_num !=
self->row_num) {
1839 PyErr_SetString(PyExc_ValueError,
1840 "Matrix.adjugate(d): "
1841 "only square matrices are supported");
1846 if (
self->col_num <= 4) {
1851 PyExc_ValueError,
"Matrix adjugate(d): size (%d) unsupported",
int(
self->col_num));
1861 Matrix_adjugated_doc,
1862 ".. method:: adjugated()\n"
1864 " Return an adjugated copy of the matrix.\n"
1866 " :return: the adjugated matrix.\n"
1867 " :rtype: :class:`Matrix`\n"
1868 " :raises ValueError: if the matrix cannot be adjugated\n");
1877 ".. method:: rotate(other)\n"
1879 " Rotates the matrix by another mathutils value.\n"
1881 " :arg other: rotation component of mathutils value\n"
1882 " :type other: :class:`Euler` | :class:`Quaternion` | :class:`Matrix`\n"
1884 " .. note:: If any of the columns are not unit length this may not have desired results.\n");
1887 float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
1897 if (
self->row_num != 3 ||
self->col_num != 3) {
1898 PyErr_SetString(PyExc_ValueError,
1900 "must have 3x3 dimensions");
1921 Matrix_decompose_doc,
1922 ".. method:: decompose()\n"
1924 " Return the translation, rotation, and scale components of this matrix.\n"
1926 " :return: Tuple of translation, rotation, and scale.\n"
1927 " :rtype: tuple[:class:`Vector`, :class:`Quaternion`, :class:`Vector`]");
1936 if (
self->row_num != 4 ||
self->col_num != 4) {
1937 PyErr_SetString(PyExc_ValueError,
1938 "Matrix.decompose(): "
1939 "inappropriate matrix size - expects 4x4 matrix");
1950 ret = PyTuple_New(3);
1967 ".. function:: lerp(other, factor)\n"
1969 " Returns the interpolation of two matrices. Uses polar decomposition, see"
1970 " \"Matrix Animation and Polar Decomposition\", Shoemake and Duff, 1992.\n"
1972 " :arg other: value to interpolate with.\n"
1973 " :type other: :class:`Matrix`\n"
1974 " :arg factor: The interpolation value in [0.0, 1.0].\n"
1975 " :type factor: float\n"
1976 " :return: The interpolated matrix.\n"
1977 " :rtype: :class:`Matrix`\n");
1983 if (!PyArg_ParseTuple(args,
"O!f:lerp", &
matrix_Type, &mat2, &fac)) {
1988 PyErr_SetString(PyExc_ValueError,
1990 "expects both matrix objects of the same dimensions");
1999 if (
self->col_num == 4 &&
self->row_num == 4) {
2000#ifdef MATH_STANDALONE
2001 blend_m4_m4m4((
float(*)[4])mat, (
float(*)[4])
self->matrix, (
float(*)[4])mat2->matrix, fac);
2003 interp_m4_m4m4((
float(*)[4])mat, (
float(*)[4])
self->matrix, (
float(*)[4])mat2->matrix, fac);
2006 else if (
self->col_num == 3 &&
self->row_num == 3) {
2007#ifdef MATH_STANDALONE
2008 blend_m3_m3m3((
float(*)[3])mat, (
float(*)[3])
self->matrix, (
float(*)[3])mat2->matrix, fac);
2010 interp_m3_m3m3((
float(*)[3])mat, (
float(*)[3])
self->matrix, (
float(*)[3])mat2->matrix, fac);
2014 PyErr_SetString(PyExc_ValueError,
2016 "only 3x3 and 4x4 matrices supported");
2025 Matrix_determinant_doc,
2026 ".. method:: determinant()\n"
2028 " Return the determinant of a matrix.\n"
2030 " :return: Return the determinant of a matrix.\n"
2033 " .. seealso:: `Determinant <https://en.wikipedia.org/wiki/Determinant>`__ on Wikipedia.\n");
2040 if (
self->col_num !=
self->row_num) {
2041 PyErr_SetString(PyExc_ValueError,
2042 "Matrix.determinant(): "
2043 "only square matrices are supported");
2058 Matrix_transpose_doc,
2059 ".. method:: transpose()\n"
2061 " Set the matrix to its transpose.\n"
2063 " .. seealso:: `Transpose <https://en.wikipedia.org/wiki/Transpose>`__ on Wikipedia.\n");
2070 if (
self->col_num !=
self->row_num) {
2071 PyErr_SetString(PyExc_ValueError,
2072 "Matrix.transpose(d): "
2073 "only square matrices are supported");
2077 if (
self->col_num == 2) {
2082 else if (
self->col_num == 3) {
2095 Matrix_transposed_doc,
2096 ".. method:: transposed()\n"
2098 " Return a new, transposed matrix.\n"
2100 " :return: a transposed matrix\n"
2101 " :rtype: :class:`Matrix`\n");
2115 Matrix_normalize_doc,
2116 ".. method:: normalize()\n"
2118 " Normalize each of the matrix columns.\n"
2120 " .. note:: for 4x4 matrices, the 4th column (translation) is left untouched.\n");
2127 if (
self->col_num !=
self->row_num) {
2128 PyErr_SetString(PyExc_ValueError,
2129 "Matrix.normalize(): "
2130 "only square matrices are supported");
2134 if (
self->col_num == 3) {
2137 else if (
self->col_num == 4) {
2141 PyErr_SetString(PyExc_ValueError,
2142 "Matrix.normalize(): "
2143 "can only use a 3x3 or 4x4 matrix");
2152 Matrix_normalized_doc,
2153 ".. method:: normalized()\n"
2155 " Return a column normalized matrix\n"
2157 " :return: a column normalized matrix\n"
2158 " :rtype: :class:`Matrix`\n"
2160 " .. note:: for 4x4 matrices, the 4th column (translation) is left untouched.\n");
2175 ".. method:: zero()\n"
2177 " Set all the matrix values to zero.\n");
2203 if (
self->col_num == 2) {
2206 else if (
self->col_num == 3) {
2216 Matrix_identity_doc,
2217 ".. method:: identity()\n"
2219 " Set the matrix to the identity matrix.\n"
2221 " .. note:: An object with a location and rotation of zero, and a scale of one\n"
2222 " will have an identity matrix.\n"
2224 " .. seealso:: `Identity matrix <https://en.wikipedia.org/wiki/Identity_matrix>`__ "
2232 if (
self->col_num !=
self->row_num) {
2233 PyErr_SetString(PyExc_ValueError,
2234 "Matrix.identity(): "
2235 "only square matrices are supported");
2263 ".. method:: copy()\n"
2265 " Returns a copy of this matrix.\n"
2267 " :return: an instance of itself\n"
2268 " :rtype: :class:`Matrix`\n");
2302 for (row = 0; row <
self->row_num; row++) {
2303 rows[row] = PyTuple_New(
self->col_num);
2308 switch (
self->row_num) {
2310 return PyUnicode_FromFormat(
2317 return PyUnicode_FromFormat(
2326 return PyUnicode_FromFormat(
2337 Py_FatalError(
"Matrix(): invalid row size!");
2341#ifndef MATH_STANDALONE
2360 for (row = 0; row <
self->row_num; row++) {
2368 for (row = 0; row <
self->row_num; row++) {
2410 res = ok ? Py_False : Py_True;
2417 res = Py_NotImplemented;
2420 PyErr_BadArgument();
2424 return Py_NewRef(res);
2459 return self->row_num;
2472 if (row < 0 || row >=
self->row_num) {
2473 PyErr_SetString(PyExc_IndexError,
2474 "matrix[attribute]: "
2475 "array index out of range");
2492 PyErr_SetString(PyExc_IndexError,
2493 "matrix[attribute]: "
2494 "array index out of range");
2510 if (row >=
self->row_num || row < 0) {
2511 PyErr_SetString(PyExc_IndexError,
"matrix[attribute] = x: bad row");
2516 vec,
self->col_num,
self->col_num, value,
"matrix[i] = value assignment") == -1)
2540 PyErr_SetString(PyExc_IndexError,
"matrix[attribute] = x: bad col");
2545 vec,
self->row_num,
self->row_num, value,
"matrix[i] = value assignment") == -1)
2551 for (row = 0; row <
self->row_num; row++) {
2572 begin = std::min(begin, end);
2574 tuple = PyTuple_New(end - begin);
2576 PyTuple_SET_ITEM(tuple,
2588 PyObject *value_fast;
2596 begin = std::min(begin, end);
2599 if (!(value_fast = PySequence_Fast(value,
"matrix[begin:end] = value"))) {
2604 PyObject **value_fast_items = PySequence_Fast_ITEMS(value_fast);
2605 const int size = end - begin;
2610 if (PySequence_Fast_GET_SIZE(value_fast) != size) {
2611 Py_DECREF(value_fast);
2612 PyErr_SetString(PyExc_ValueError,
2613 "matrix[begin:end] = []: "
2614 "size mismatch in slice assignment");
2618 memcpy(mat,
self->matrix,
self->col_num *
self->row_num *
sizeof(
float));
2621 for (row = begin; row < end; row++) {
2623 PyObject *item = value_fast_items[row - begin];
2626 vec,
self->col_num,
self->col_num, item,
"matrix[begin:end] = value assignment") == -1)
2628 Py_DECREF(value_fast);
2637 Py_DECREF(value_fast);
2640 memcpy(
self->matrix, mat,
self->col_num *
self->row_num *
sizeof(
float));
2649 if (PyIndex_Check(item)) {
2651 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2652 if (i == -1 && PyErr_Occurred()) {
2660 if (PySlice_Check(item)) {
2661 Py_ssize_t start, stop, step, slicelength;
2663 if (PySlice_GetIndicesEx(item,
self->row_num, &start, &stop, &step, &slicelength) < 0) {
2667 if (slicelength <= 0) {
2668 return PyTuple_New(0);
2674 PyErr_SetString(PyExc_IndexError,
"slice steps not supported with matrices");
2679 PyExc_TypeError,
"matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
2686 if (PyIndex_Check(item)) {
2687 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
2688 if (i == -1 && PyErr_Occurred()) {
2696 if (PySlice_Check(item)) {
2697 Py_ssize_t start, stop, step, slicelength;
2699 if (PySlice_GetIndicesEx(item,
self->row_num, &start, &stop, &step, &slicelength) < 0) {
2707 PyErr_SetString(PyExc_IndexError,
"slice steps not supported with matrices");
2712 PyExc_TypeError,
"matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
2732 PyErr_Format(PyExc_TypeError,
2733 "Matrix addition: (%s + %s) "
2734 "invalid type for this operation",
2735 Py_TYPE(m1)->tp_name,
2736 Py_TYPE(m2)->tp_name);
2744 if (mat1->
col_num != mat2->col_num || mat1->
row_num != mat2->row_num) {
2745 PyErr_SetString(PyExc_ValueError,
2747 "matrices must have the same dimensions for this operation");
2766 PyErr_Format(PyExc_TypeError,
2767 "Matrix subtraction: (%s - %s) "
2768 "invalid type for this operation",
2769 Py_TYPE(m1)->tp_name,
2770 Py_TYPE(m2)->tp_name);
2778 if (mat1->
col_num != mat2->col_num || mat1->
row_num != mat2->row_num) {
2779 PyErr_SetString(PyExc_ValueError,
2781 "matrices must have the same dimensions for this operation");
2821 if ((mat1->
row_num != mat2->row_num) || (mat1->
col_num != mat2->col_num)) {
2822 PyErr_SetString(PyExc_ValueError,
2823 "matrix1 * matrix2: matrix1 number of rows/columns "
2824 "and the matrix2 number of rows/columns must be the same");
2834 if (((scalar = PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred()) == 0) {
2840 if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) {
2845 PyErr_Format(PyExc_TypeError,
2846 "Element-wise multiplication: "
2847 "not supported between '%.200s' and '%.200s' types",
2848 Py_TYPE(m1)->tp_name,
2849 Py_TYPE(m2)->tp_name);
2875 if ((mat1->
row_num != mat2->row_num) || (mat1->
col_num != mat2->col_num)) {
2876 PyErr_SetString(PyExc_ValueError,
2877 "matrix1 *= matrix2: matrix1 number of rows/columns "
2878 "and the matrix2 number of rows/columns must be the same");
2884 else if (mat1 && (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0)) {
2889 PyErr_Format(PyExc_TypeError,
2890 "In place element-wise multiplication: "
2891 "not supported between '%.200s' and '%.200s' types",
2892 Py_TYPE(m1)->tp_name,
2893 Py_TYPE(m2)->tp_name);
2928 if (mat1->
col_num != mat2->row_num) {
2929 PyErr_SetString(PyExc_ValueError,
2930 "matrix1 * matrix2: matrix1 number of columns "
2931 "and the matrix2 number of rows must be the same");
2935 for (
col = 0;
col < mat2->col_num;
col++) {
2936 for (row = 0; row < mat1->
row_num; row++) {
2938 for (item = 0; item < mat1->
col_num; item++) {
2970 PyErr_Format(PyExc_TypeError,
2971 "Matrix multiplication: "
2972 "not supported between '%.200s' and '%.200s' types",
2973 Py_TYPE(m1)->tp_name,
2974 Py_TYPE(m2)->tp_name);
3001 if (mat1->
col_num != mat2->row_num) {
3002 PyErr_SetString(PyExc_ValueError,
3003 "matrix1 * matrix2: matrix1 number of columns "
3004 "and the matrix2 number of rows must be the same");
3008 for (
col = 0;
col < mat2->col_num;
col++) {
3009 for (row = 0; row < mat1->
row_num; row++) {
3011 for (item = 0; item < mat1->
col_num; item++) {
3021 memcpy(mat1->matrix, mat, (mat1->
row_num * mat1->
col_num) *
sizeof(
float));
3024 PyErr_Format(PyExc_TypeError,
3025 "In place matrix multiplication: "
3026 "not supported between '%.200s' and '%.200s' types",
3027 Py_TYPE(m1)->tp_name,
3028 Py_TYPE(m2)->tp_name);
3109 Matrix_translation_doc,
3110 "The translation component of the matrix.\n"
3112 ":type: :class:`Vector`");
3122 if (
self->row_num != 4 ||
self->col_num != 4) {
3123 PyErr_SetString(PyExc_AttributeError,
3124 "Matrix.translation: "
3125 "inappropriate matrix size, must be 4x4");
3144 if (
self->row_num != 4 ||
self->col_num != 4) {
3145 PyErr_SetString(PyExc_AttributeError,
3146 "Matrix.translation: "
3147 "inappropriate matrix size, must be 4x4");
3165 "Access the matrix by rows (default), (read-only).\n"
3167 ":type: Matrix Access");
3174 "Access the matrix by columns, 3x3 and 4x4 only, (read-only).\n"
3176 ":type: Matrix Access");
3184 Matrix_median_scale_doc,
3185 "The average scale applied to each axis (read-only).\n"
3197 if ((
self->row_num < 3) || (
self->col_num < 3)) {
3198 PyErr_SetString(PyExc_AttributeError,
3199 "Matrix.median_scale: "
3200 "inappropriate matrix size, 3x3 minimum");
3211 Matrix_is_identity_doc,
3212 "True if this is an identity matrix (read-only).\n"
3225 Matrix_is_negative_doc,
3226 "True if this matrix results in a negative scale, 3x3 and 4x4 only, "
3237 if (
self->row_num == 4 &&
self->col_num == 4) {
3240 if (
self->row_num == 3 &&
self->col_num == 3) {
3244 PyErr_SetString(PyExc_AttributeError,
3245 "Matrix.is_negative: "
3246 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
3252 Matrix_is_orthogonal_doc,
3253 "True if this matrix is orthogonal, 3x3 and 4x4 only, (read-only).\n"
3263 if (
self->row_num == 4 &&
self->col_num == 4) {
3266 if (
self->row_num == 3 &&
self->col_num == 3) {
3270 PyErr_SetString(PyExc_AttributeError,
3271 "Matrix.is_orthogonal: "
3272 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
3278 Matrix_is_orthogonal_axis_vectors_doc,
3279 "True if this matrix has got orthogonal axis vectors, 3x3 and 4x4 only, "
3290 if (
self->row_num == 4 &&
self->col_num == 4) {
3293 if (
self->row_num == 3 &&
self->col_num == 3) {
3297 PyErr_SetString(PyExc_AttributeError,
3298 "Matrix.is_orthogonal_axis_vectors: "
3299 "inappropriate matrix size - expects 3x3 or 4x4 matrix");
3313 Matrix_median_scale_doc,
3318 Matrix_translation_doc,
3320 {
"row", (getter)
Matrix_row_get, (setter)
nullptr, Matrix_row_doc,
nullptr},
3321 {
"col", (getter)
Matrix_col_get, (setter)
nullptr, Matrix_col_doc,
nullptr},
3325 Matrix_is_identity_doc,
3330 Matrix_is_negative_doc,
3335 Matrix_is_orthogonal_doc,
3337 {
"is_orthogonal_axis_vectors",
3340 Matrix_is_orthogonal_axis_vectors_doc,
3362 {
nullptr,
nullptr,
nullptr,
nullptr,
nullptr}
3371#if (defined(__GNUC__) && !defined(__clang__))
3372# pragma GCC diagnostic push
3373# pragma GCC diagnostic ignored "-Wcast-function-type"
3378 {
"determinant", (PyCFunction)
Matrix_determinant, METH_NOARGS, Matrix_determinant_doc},
3379 {
"decompose", (PyCFunction)
Matrix_decompose, METH_NOARGS, Matrix_decompose_doc},
3382 {
"zero", (PyCFunction)
Matrix_zero, METH_NOARGS, Matrix_zero_doc},
3383 {
"identity", (PyCFunction)
Matrix_identity, METH_NOARGS, Matrix_identity_doc},
3386 {
"transpose", (PyCFunction)
Matrix_transpose, METH_NOARGS, Matrix_transpose_doc},
3387 {
"transposed", (PyCFunction)
Matrix_transposed, METH_NOARGS, Matrix_transposed_doc},
3388 {
"normalize", (PyCFunction)
Matrix_normalize, METH_NOARGS, Matrix_normalize_doc},
3389 {
"normalized", (PyCFunction)
Matrix_normalized, METH_NOARGS, Matrix_normalized_doc},
3390 {
"invert", (PyCFunction)
Matrix_invert, METH_VARARGS, Matrix_invert_doc},
3391 {
"inverted", (PyCFunction)
Matrix_inverted, METH_VARARGS, Matrix_inverted_doc},
3392 {
"invert_safe", (PyCFunction)
Matrix_invert_safe, METH_NOARGS, Matrix_invert_safe_doc},
3394 {
"adjugate", (PyCFunction)
Matrix_adjugate, METH_NOARGS, Matrix_adjugate_doc},
3395 {
"adjugated", (PyCFunction)
Matrix_adjugated, METH_NOARGS, Matrix_adjugated_doc},
3396 {
"to_2x2", (PyCFunction)
Matrix_to_2x2, METH_NOARGS, Matrix_to_2x2_doc},
3397 {
"to_3x3", (PyCFunction)
Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc},
3398 {
"to_4x4", (PyCFunction)
Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc},
3400 {
"resize_4x4", (PyCFunction)
Matrix_resize_4x4, METH_NOARGS, Matrix_resize_4x4_doc},
3401 {
"rotate", (PyCFunction)
Matrix_rotate, METH_O, Matrix_rotate_doc},
3404 {
"to_euler", (PyCFunction)
Matrix_to_euler, METH_VARARGS, Matrix_to_euler_doc},
3406 {
"to_scale", (PyCFunction)
Matrix_to_scale, METH_NOARGS, Matrix_to_scale_doc},
3410 {
"lerp", (PyCFunction)
Matrix_lerp, METH_VARARGS, Matrix_lerp_doc},
3411 {
"copy", (PyCFunction)
Matrix_copy, METH_NOARGS, Matrix_copy_doc},
3412 {
"__copy__", (PyCFunction)
Matrix_copy, METH_NOARGS, Matrix_copy_doc},
3413 {
"__deepcopy__", (PyCFunction)
Matrix_deepcopy, METH_VARARGS, Matrix_copy_doc},
3419 {
"Identity", (PyCFunction)
C_Matrix_Identity, METH_VARARGS | METH_CLASS, C_Matrix_Identity_doc},
3420 {
"Rotation", (PyCFunction)
C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc},
3421 {
"Scale", (PyCFunction)
C_Matrix_Scale, METH_VARARGS | METH_CLASS, C_Matrix_Scale_doc},
3422 {
"Shear", (PyCFunction)
C_Matrix_Shear, METH_VARARGS | METH_CLASS, C_Matrix_Shear_doc},
3423 {
"Diagonal", (PyCFunction)
C_Matrix_Diagonal, METH_O | METH_CLASS, C_Matrix_Diagonal_doc},
3426 METH_O | METH_CLASS,
3427 C_Matrix_Translation_doc},
3430 METH_VARARGS | METH_CLASS,
3431 C_Matrix_OrthoProjection_doc},
3434 METH_VARARGS | METH_CLASS,
3435 C_Matrix_LocRotScale_doc},
3436 {
nullptr,
nullptr, 0,
nullptr},
3439#if (defined(__GNUC__) && !defined(__clang__))
3440# pragma GCC diagnostic pop
3449#ifdef MATH_STANDALONE
3450# define Matrix_str nullptr
3456 ".. class:: Matrix([rows])\n"
3458 " This object gives access to Matrices in Blender, supporting square and rectangular\n"
3459 " matrices from 2x2 up to 4x4.\n"
3461 " :arg rows: Sequence of rows. When omitted, a 4x4 identity matrix is constructed.\n"
3462 " :type rows: Sequence[Sequence[float]]\n");
3464 PyVarObject_HEAD_INIT(
nullptr, 0)
3483 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
3515#ifdef MATH_STANDALONE
3528 PyTypeObject *base_type)
3534 if (col_num < 2 || col_num > 4 || row_num < 2 || row_num > 4) {
3535 PyErr_SetString(PyExc_RuntimeError,
3537 "row and column sizes must be between 2 and 4");
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,
3545 "problem allocating data");
3551 self->matrix = mat_alloc;
3552 self->col_num = col_num;
3553 self->row_num = row_num;
3556 self->cb_user =
nullptr;
3557 self->cb_type =
self->cb_subtype = 0;
3560 memcpy(
self->matrix, mat, col_num * row_num *
sizeof(
float));
3562 else if (col_num == row_num) {
3568 memset(
self->matrix, 0, col_num * row_num *
sizeof(
float));
3573 PyMem_Free(mat_alloc);
3576 return (PyObject *)
self;
3582 PyTypeObject *base_type)
3587 if (col_num < 2 || col_num > 4 || row_num < 2 || row_num > 4) {
3588 PyErr_SetString(PyExc_RuntimeError,
3590 "row and column sizes must be between 2 and 4");
3596 self->col_num = col_num;
3597 self->row_num = row_num;
3600 self->cb_user =
nullptr;
3601 self->cb_type =
self->cb_subtype = 0;
3606 return (PyObject *)
self;
3615 self->cb_user = cb_user;
3616 self->cb_type = cb_type;
3617 self->cb_subtype = cb_subtype;
3619 PyObject_GC_Track(
self);
3621 return (PyObject *)
self;
3627 PyTypeObject *base_type)
3632 self->flag &= ~BASE_MATH_FLAG_IS_WRAP;
3635 return (PyObject *)
self;
3651 PyExc_TypeError,
"expected a mathutils.Matrix, not a %.200s", Py_TYPE(pymat)->tp_name);
3682 PyErr_SetString(PyExc_ValueError,
"matrix must be 2x2");
3699 PyErr_SetString(PyExc_ValueError,
"matrix must be 3x3");
3716 PyErr_SetString(PyExc_ValueError,
"matrix must be 4x4");
3738 Py_VISIT(
self->matrix_user);
3744 Py_CLEAR(
self->matrix_user);
3750 if (
self->matrix_user) {
3751 PyObject_GC_UnTrack(
self);
3776 int matrix_access_len;
3777 PyObject *(*Matrix_item_new)(
MatrixObject *, Py_ssize_t);
3780 matrix_access_len = matrix_user->
row_num;
3784 matrix_access_len = matrix_user->
col_num;
3788 CLAMP(begin, 0, matrix_access_len);
3790 end = (matrix_access_len + 1) + end;
3792 CLAMP(end, 0, matrix_access_len);
3793 begin = std::min(begin, end);
3795 tuple = PyTuple_New(end - begin);
3797 PyTuple_SET_ITEM(tuple,
count - begin, Matrix_item_new(matrix_user,
count));
3807 if (PyIndex_Check(item)) {
3809 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
3810 if (i == -1 && PyErr_Occurred()) {
3825 if (PySlice_Check(item)) {
3826 Py_ssize_t start, stop, step, slicelength;
3828 if (PySlice_GetIndicesEx(item,
MatrixAccess_len(
self), &start, &stop, &step, &slicelength) < 0)
3833 if (slicelength <= 0) {
3834 return PyTuple_New(0);
3840 PyErr_SetString(PyExc_IndexError,
"slice steps not supported with matrix accessors");
3845 PyExc_TypeError,
"matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
3853 if (PyIndex_Check(item)) {
3854 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
3855 if (i == -1 && PyErr_Occurred()) {
3874 PyExc_TypeError,
"matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
3882 PyObject *iter =
nullptr;
3888 iter = PyObject_GetIter(
ret);
3908 PyVarObject_HEAD_INIT(
nullptr, 0)
3927 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
3973 matrix_access->
type = type;
3975 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 unit_m4(float m[4][4])
void copy_m4_m3(float m1[4][4], const float m2[3][3])
void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4])
bool is_orthonormal_m3(const float m[3][3])
void normalize_m3(float R[3][3]) ATTR_NONNULL()
float determinant_m2(float a, float b, float c, float d)
void rescale_m4(float mat[4][4], const float scale[3])
void adjoint_m4_m4(float R[4][4], const float M[4][4])
float determinant_m4(const float m[4][4])
void copy_m2_m2(float m1[2][2], const float m2[2][2])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], float t)
bool is_orthonormal_m4(const float m[4][4])
float determinant_m3_array(const float m[3][3])
bool is_negative_m4(const float mat[4][4])
void transpose_m3(float R[3][3])
float determinant_m3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3)
void blend_m3_m3m3(float out[3][3], const float dst[3][3], const float src[3][3], float srcweight)
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
void transpose_m4(float R[4][4])
void normalize_m4(float R[4][4]) ATTR_NONNULL()
void adjoint_m2_m2(float R[2][2], const float M[2][2])
void axis_angle_to_mat3_single(float R[3][3], char axis, float angle)
void mat3_normalized_to_compatible_eul(float eul[3], const float oldrot[3], float mat[3][3])
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,...)
typedef double(DMatrix)[4][4]
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.
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
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 BaseMath_ReadCallback_ForWrite(_self)
#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)
#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)
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)
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
#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