From 2c82dc8b3db2d6132eafe9db9055f0be638ad447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 23 May 2019 01:12:48 +0200 Subject: [PATCH] python: make Matrix4 operations return Matrix4, not Matrix4x4. Similarly for Matrix3. Also make it implicitly convertible from the base type. --- src/python/magnum/math.matrix.h | 113 +++++++++++++--------- src/python/magnum/test/test_math.py | 12 +++ src/python/magnum/test/test_shaders_gl.py | 4 +- 3 files changed, 81 insertions(+), 48 deletions(-) diff --git a/src/python/magnum/math.matrix.h b/src/python/magnum/math.matrix.h index 8bf1ee5..583b757 100644 --- a/src/python/magnum/math.matrix.h +++ b/src/python/magnum/math.matrix.h @@ -41,6 +41,34 @@ template struct VectorTraits<2, T> { typedef Math::Vector2 Type; }; template struct VectorTraits<3, T> { typedef Math::Vector3 Type; }; template struct VectorTraits<4, T> { typedef Math::Vector4 Type; }; +/* Called for both Matrix3x3 and Matrix3 in order to return a proper type, so + has to be separate */ +template void everyRectangularMatrix(py::class_& c) { + c + /* Operators */ + .def(-py::self, "Negated matrix") + .def(py::self += py::self, "Add and assign a matrix") + .def(py::self + py::self, "Add a matrix") + .def(py::self -= py::self, "Subtract and assign a matrix") + .def(py::self - py::self, "Subtract a matrix") + .def(py::self *= typename T::Type{}, "Multiply with a scalar and assign") + .def(py::self * typename T::Type{}, "Multiply with a scalar") + .def(py::self /= typename T::Type{}, "Divide with a scalar and assign") + .def(py::self / typename T::Type{}, "Divide with a scalar") + .def("__mul__", [](const T& self, const typename VectorTraits::Type& vector) -> typename VectorTraits::Type { + return self*vector; + }, "Multiply a vector") + .def(typename T::Type{} * py::self, "Multiply a scalar with a matrix") + .def(typename T::Type{} / py::self, "Divide a matrix with a scalar and invert") + + /* Member functions that don't return a size-dependent type */ + .def("flipped_cols", &T::flippedCols, "Matrix with flipped cols") + .def("flipped_rows", &T::flippedRows, "Matrix with flipped rows") + .def("diagonal", [](const T& self) -> typename VectorTraits::Type { + return self.diagonal(); + }, "Values on diagonal"); +} + template void rectangularMatrix(py::class_& c) { /* Missing APIs: @@ -91,29 +119,6 @@ template void rectangularMatrix(py::class_& c) { return self[i.first][i.second]; }, "Value at given col/row") - /* Operators */ - .def(-py::self, "Negated matrix") - .def(py::self += py::self, "Add and assign a matrix") - .def(py::self + py::self, "Add a matrix") - .def(py::self -= py::self, "Subtract and assign a matrix") - .def(py::self - py::self, "Subtract a matrix") - .def(py::self *= typename T::Type{}, "Multiply with a scalar and assign") - .def(py::self * typename T::Type{}, "Multiply with a scalar") - .def(py::self /= typename T::Type{}, "Divide with a scalar and assign") - .def(py::self / typename T::Type{}, "Divide with a scalar") - .def("__mul__", [](const T& self, const typename VectorTraits::Type& vector) -> typename VectorTraits::Type { - return self*vector; - }, "Multiply a vector") - .def(typename T::Type{} * py::self, "Multiply a scalar with a matrix") - .def(typename T::Type{} / py::self, "Divide a matrix with a scalar and invert") - - /* Member functions that don't return a size-dependent type */ - .def("flipped_cols", &T::flippedCols, "Matrix with flipped cols") - .def("flipped_rows", &T::flippedRows, "Matrix with flipped rows") - .def("diagonal", [](const T& self) -> typename VectorTraits::Type { - return self.diagonal(); - }, "Values on diagonal") - .def("__repr__", repr, "Object representation"); /* Matrix column count */ @@ -122,6 +127,20 @@ template void rectangularMatrix(py::class_& c) { c.def_static("__len__", []() { return int(T::Cols); }, lenDocstring); } +/* Called for both Matrix3x3 and Matrix3 in order to return a proper type, so + has to be separate */ +template void everyMatrix(py::class_& c) { + c + .def("inverted", &T::inverted, "Inverted matrix") + .def("inverted_orthogonal", &T::invertedOrthogonal, "Inverted orthogonal matrix") + .def("__matmul__", [](const T& self, const T& other) -> T { + return self*other; + }, "Multiply a matrix") + .def("transposed", [](const T& self) -> T { + return self.transposed(); + }, "Transposed matrix"); +} + template void matrix(py::class_& c) { c /* Constructors */ @@ -132,9 +151,7 @@ template void matrix(py::class_& c) { /* Member functions for square matrices only */ .def("is_orthogonal", &T::isOrthogonal, "Whether the matrix is orthogonal") .def("trace", &T::trace, "Trace of the matrix") - .def("determinant", &T::determinant, "Determinant") - .def("inverted", &T::inverted, "Inverted matrix") - .def("inverted_orthogonal", &T::invertedOrthogonal, "Inverted orthogonal matrix"); + .def("determinant", &T::determinant, "Determinant"); } template void matrices( @@ -160,18 +177,12 @@ template void matrices( .def(py::init([](const std::tuple, Math::Vector2>& value) { return Math::Matrix2x2{std::get<0>(value), std::get<1>(value)}; }), "Construct from a column vector tuple") - .def("__matmul__", [](const Math::Matrix2x2& self, const Math::Matrix2x2& other) -> Math::Matrix2x2 { - return self*other; - }, "Multiply a matrix") .def("__matmul__", [](const Math::Matrix2x2& self, const Math::Matrix3x2& other) -> Math::Matrix3x2 { return self*other; }, "Multiply a matrix") .def("__matmul__", [](const Math::Matrix2x2& self, const Math::Matrix4x2& other) -> Math::Matrix4x2 { return self*other; - }, "Multiply a matrix") - .def("transposed", [](const Math::Matrix2x2& self) -> Math::Matrix2x2 { - return self.transposed(); - }, "Transposed matrix"); + }, "Multiply a matrix"); matrix2x3 .def(py::init&, const Math::Vector3&>(), "Construct from column vectors") @@ -208,9 +219,13 @@ template void matrices( .def("transposed", [](const Math::Matrix2x4& self) -> Math::Matrix4x2 { return self.transposed(); }, "Transposed matrix"); + everyRectangularMatrix(matrix2x2); + everyRectangularMatrix(matrix2x3); + everyRectangularMatrix(matrix2x4); rectangularMatrix(matrix2x2); rectangularMatrix(matrix2x3); rectangularMatrix(matrix2x4); + everyMatrix(matrix2x2); matrix(matrix2x2); /* Three-column matrices */ @@ -241,15 +256,9 @@ template void matrices( .def("__matmul__", [](const Math::Matrix3x3& self, const Math::Matrix2x3& other) -> Math::Matrix2x3 { return self*other; }, "Multiply a matrix") - .def("__matmul__", [](const Math::Matrix3x3& self, const Math::Matrix3x3& other) -> Math::Matrix3x3 { - return self*other; - }, "Multiply a matrix") .def("__matmul__", [](const Math::Matrix3x3& self, const Math::Matrix4x3& other) -> Math::Matrix4x3 { return self*other; - }, "Multiply a matrix") - .def("transposed", [](const Math::Matrix3x3& self) -> Math::Matrix3x3 { - return self.transposed(); - }, "Transposed matrix"); + }, "Multiply a matrix"); matrix3x4 .def(py::init&, const Math::Vector4&, const Math::Vector4&>(), "Construct from column vectors") @@ -268,9 +277,13 @@ template void matrices( .def("transposed", [](const Math::Matrix3x4& self) -> Math::Matrix4x3 { return self.transposed(); }, "Transposed matrix"); + everyRectangularMatrix(matrix3x2); + everyRectangularMatrix(matrix3x3); + everyRectangularMatrix(matrix3x4); rectangularMatrix(matrix3x2); rectangularMatrix(matrix3x3); rectangularMatrix(matrix3x4); + everyMatrix(matrix3x3); matrix(matrix3x3); /* Four-column matrices */ @@ -321,19 +334,19 @@ template void matrices( }, "Multiply a matrix") .def("__matmul__", [](const Math::Matrix4x4& self, const Math::Matrix3x4& other) -> Math::Matrix3x4 { return self*other; - }, "Multiply a matrix") - .def("__matmul__", [](const Math::Matrix4x4& self, const Math::Matrix4x4& other) -> Math::Matrix4x4 { - return self*other; - }, "Multiply a matrix") - .def("transposed", [](const Math::Matrix4x4& self) -> Math::Matrix4x4 { - return self.transposed(); - }, "Transposed matrix"); + }, "Multiply a matrix"); + everyRectangularMatrix(matrix4x2); + everyRectangularMatrix(matrix4x3); + everyRectangularMatrix(matrix4x4); rectangularMatrix(matrix4x2); rectangularMatrix(matrix4x3); rectangularMatrix(matrix4x4); + everyMatrix(matrix4x4); matrix(matrix4x4); /* 3x3 transformation matrix */ + py::implicitly_convertible, Math::Matrix3>(); + matrix3 /* Constructors. The scaling() / rotation() are handled below as they conflict with member functions. */ @@ -424,8 +437,12 @@ template void matrices( return matrix3.attr("_srotation")(*args, **kwargs); } }); + everyRectangularMatrix(matrix3); + everyMatrix(matrix3); /* 4x4 transformation matrix */ + py::implicitly_convertible, Math::Matrix4>(); + matrix4 /* Constructors. The scaling() / rotation() are handled below as they conflict with member functions. */ @@ -539,6 +556,8 @@ template void matrices( return matrix4.attr("_srotation")(*args, **kwargs); } }); + everyRectangularMatrix(matrix4); + everyMatrix(matrix4); } } diff --git a/src/python/magnum/test/test_math.py b/src/python/magnum/test/test_math.py index 3d2947d..552d8de 100644 --- a/src/python/magnum/test/test_math.py +++ b/src/python/magnum/test/test_math.py @@ -478,6 +478,12 @@ class Matrix3_(unittest.TestCase): self.assertEqual(Matrix3.rotation(Deg(45.0)).inverted(), Matrix3.rotation(Deg(-45.0))) + def test_methods_return_type(self): + self.assertIsInstance(Matrix3()@Matrix3(), Matrix3) + self.assertIsInstance(Matrix3()+Matrix3(), Matrix3) + self.assertIsInstance(Matrix3().transposed(), Matrix3) + self.assertIsInstance(Matrix3().inverted(), Matrix3) + class Matrix4_(unittest.TestCase): def test_init(self): a = Matrix4() @@ -533,6 +539,12 @@ class Matrix4_(unittest.TestCase): self.assertEqual(Matrix4.rotation_x(Deg(45.0)).inverted(), Matrix4.rotation_x(Deg(-45.0))) + def test_methods_return_type(self): + self.assertIsInstance(Matrix4()@Matrix4(), Matrix4) + self.assertIsInstance(Matrix4()+Matrix4(), Matrix4) + self.assertIsInstance(Matrix4().transposed(), Matrix4) + self.assertIsInstance(Matrix4().inverted(), Matrix4) + class Quaternion_(unittest.TestCase): def test_init(self): a = Quaternion() diff --git a/src/python/magnum/test/test_shaders_gl.py b/src/python/magnum/test/test_shaders_gl.py index da407b2..1bd2aaf 100644 --- a/src/python/magnum/test/test_shaders_gl.py +++ b/src/python/magnum/test/test_shaders_gl.py @@ -39,7 +39,9 @@ class VertexColor(GLTestCase): def test_uniforms(self): a = shaders.VertexColor2D() - a.transformation_projection_matrix = Matrix3.translation(Vector2.x_axis()) + a.transformation_projection_matrix = ( + Matrix3.translation(Vector2.x_axis())@ + Matrix3.rotation(Deg(35.0))) class Phong(GLTestCase): def test_init(self):