Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/python_api/examples/mathutils.Matrix.LocRotScale.py5
-rw-r--r--doc/python_api/examples/mathutils.Matrix.py6
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c102
-rw-r--r--tests/python/bl_pyapi_mathutils.py23
4 files changed, 134 insertions, 2 deletions
diff --git a/doc/python_api/examples/mathutils.Matrix.LocRotScale.py b/doc/python_api/examples/mathutils.Matrix.LocRotScale.py
new file mode 100644
index 00000000000..016a5002e82
--- /dev/null
+++ b/doc/python_api/examples/mathutils.Matrix.LocRotScale.py
@@ -0,0 +1,5 @@
+# Compute local object transformation matrix:
+if obj.rotation_mode == 'QUATERNION':
+ matrix = mathutils.Matrix.LocRotScale(obj.location, obj.rotation_quaternion, obj.scale)
+else:
+ matrix = mathutils.Matrix.LocRotScale(obj.location, obj.rotation_euler, obj.scale)
diff --git a/doc/python_api/examples/mathutils.Matrix.py b/doc/python_api/examples/mathutils.Matrix.py
index 26c7ccba27c..84e09b97c15 100644
--- a/doc/python_api/examples/mathutils.Matrix.py
+++ b/doc/python_api/examples/mathutils.Matrix.py
@@ -14,10 +14,14 @@ mat_rot = mathutils.Matrix.Rotation(math.radians(45.0), 4, 'X')
mat_out = mat_loc @ mat_rot @ mat_sca
print(mat_out)
-# extract components back out of the matrix
+# extract components back out of the matrix as two vectors and a quaternion
loc, rot, sca = mat_out.decompose()
print(loc, rot, sca)
+# recombine extracted components
+mat_out2 = mathutils.Matrix.LocRotScale(loc, rot, sca)
+print(mat_out2)
+
# it can also be useful to access components of a matrix directly
mat = mathutils.Matrix()
mat[0][0], mat[1][0], mat[2][0] = 0.0, 1.0, 2.0
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 161d2f41592..e3c76408e62 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -969,6 +969,104 @@ static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args)
return Matrix_CreatePyObject(mat, matSize, matSize, (PyTypeObject *)cls);
}
+PyDoc_STRVAR(
+ C_Matrix_LocRotScale_doc,
+ ".. classmethod:: LocRotScale(location, rotation, scale)\n"
+ "\n"
+ " Create a matrix combining translation, rotation and scale,\n"
+ " acting as the inverse of the decompose() method.\n"
+ "\n"
+ " Any of the inputs may be replaced with None if not needed.\n"
+ "\n"
+ " :arg location: The translation component.\n"
+ " :type location: :class:`Vector` or None\n"
+ " :arg rotation: The rotation component.\n"
+ " :type rotation: 3x3 :class:`Matrix`, :class:`Quaternion`, :class:`Euler` or None\n"
+ " :arg scale: The scale component.\n"
+ " :type scale: :class:`Vector` or None\n"
+ " :return: Combined transformation matrix. \n"
+ " :rtype: 4x4 :class:`Matrix`\n");
+static PyObject *C_Matrix_LocRotScale(PyObject *cls, PyObject *args)
+{
+ PyObject *loc_obj, *rot_obj, *scale_obj;
+ float mat[4][4], loc[3];
+
+ if (!PyArg_ParseTuple(args, "OOO:Matrix.LocRotScale", &loc_obj, &rot_obj, &scale_obj)) {
+ return NULL;
+ }
+
+ /* Decode location. */
+ if (loc_obj == Py_None) {
+ zero_v3(loc);
+ }
+ else if (mathutils_array_parse(
+ loc, 3, 3, loc_obj, "Matrix.LocRotScale(), invalid location argument") == -1) {
+ return NULL;
+ }
+
+ /* Decode rotation. */
+ if (rot_obj == Py_None) {
+ unit_m4(mat);
+ }
+ else if (QuaternionObject_Check(rot_obj)) {
+ QuaternionObject *quat_obj = (QuaternionObject *)rot_obj;
+
+ if (BaseMath_ReadCallback(quat_obj) == -1) {
+ return NULL;
+ }
+
+ quat_to_mat4(mat, quat_obj->quat);
+ }
+ else if (EulerObject_Check(rot_obj)) {
+ EulerObject *eul_obj = (EulerObject *)rot_obj;
+
+ if (BaseMath_ReadCallback(eul_obj) == -1) {
+ return NULL;
+ }
+
+ eulO_to_mat4(mat, eul_obj->eul, eul_obj->order);
+ }
+ else if (MatrixObject_Check(rot_obj)) {
+ MatrixObject *mat_obj = (MatrixObject *)rot_obj;
+
+ if (BaseMath_ReadCallback(mat_obj) == -1) {
+ return NULL;
+ }
+
+ if (mat_obj->num_col == 3 && mat_obj->num_row == 3) {
+ copy_m4_m3(mat, (float(*)[3])mat_obj->matrix);
+ }
+ else {
+ PyErr_SetString(PyExc_ValueError,
+ "Matrix.LocRotScale(): "
+ "inappropriate rotation matrix size - expects 3x3 matrix");
+ return NULL;
+ }
+ }
+ else {
+ PyErr_SetString(PyExc_ValueError,
+ "Matrix.LocRotScale(): "
+ "rotation argument must be Matrix, Quaternion, Euler or None");
+ return NULL;
+ }
+
+ /* Decode scale. */
+ if (scale_obj != Py_None) {
+ float scale[3];
+
+ if (mathutils_array_parse(
+ scale, 3, 3, scale_obj, "Matrix.LocRotScale(), invalid scale argument") == -1) {
+ return NULL;
+ }
+
+ rescale_m4(mat, scale);
+ }
+
+ copy_v3_v3(mat[3], loc);
+
+ return Matrix_CreatePyObject(&mat[0][0], 4, 4, (PyTypeObject *)cls);
+}
+
void matrix_as_3x3(float mat[3][3], MatrixObject *self)
{
copy_v3_v3(mat[0], MATRIX_COL_PTR(self, 0));
@@ -3111,6 +3209,10 @@ static struct PyMethodDef Matrix_methods[] = {
(PyCFunction)C_Matrix_OrthoProjection,
METH_VARARGS | METH_CLASS,
C_Matrix_OrthoProjection_doc},
+ {"LocRotScale",
+ (PyCFunction)C_Matrix_LocRotScale,
+ METH_VARARGS | METH_CLASS,
+ C_Matrix_LocRotScale_doc},
{NULL, NULL, 0, NULL},
};
diff --git a/tests/python/bl_pyapi_mathutils.py b/tests/python/bl_pyapi_mathutils.py
index 9dfc6c159cc..914b1689a5c 100644
--- a/tests/python/bl_pyapi_mathutils.py
+++ b/tests/python/bl_pyapi_mathutils.py
@@ -2,7 +2,7 @@
# ./blender.bin --background -noaudio --python tests/python/bl_pyapi_mathutils.py -- --verbose
import unittest
-from mathutils import Matrix, Vector, Quaternion
+from mathutils import Matrix, Vector, Quaternion, Euler
from mathutils import kdtree, geometry
import math
@@ -233,6 +233,27 @@ class MatrixTesting(unittest.TestCase):
self.assertEqual(mat @ mat, prod_mat)
+ def test_loc_rot_scale(self):
+ euler = Euler((math.radians(90), 0, math.radians(90)), 'ZYX')
+ expected = Matrix(((0, -5, 0, 1),
+ (0, 0, -6, 2),
+ (4, 0, 0, 3),
+ (0, 0, 0, 1)))
+
+ result = Matrix.LocRotScale((1, 2, 3), euler, (4, 5, 6))
+ self.assertAlmostEqualMatrix(result, expected, 4)
+
+ result = Matrix.LocRotScale((1, 2, 3), euler.to_quaternion(), (4, 5, 6))
+ self.assertAlmostEqualMatrix(result, expected, 4)
+
+ result = Matrix.LocRotScale((1, 2, 3), euler.to_matrix(), (4, 5, 6))
+ self.assertAlmostEqualMatrix(result, expected, 4)
+
+ def assertAlmostEqualMatrix(self, first, second, size, *, places=6, msg=None, delta=None):
+ for i in range(size):
+ for j in range(size):
+ self.assertAlmostEqual(first[i][j], second[i][j], places=places, msg=msg, delta=delta)
+
class VectorTesting(unittest.TestCase):