From 452d9478ab85cdbdfe6d3c8f95d9f7c4cffbe472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 13 May 2019 22:41:26 +0200 Subject: [PATCH] python: make it possible to create matrices from nested tuples. Ugh, I need to drop this std::tuple. It makes code complicated for no reason. --- src/python/magnum/math.matrix.h | 101 ++++++++++++++++ src/python/magnum/test/test_math.py | 179 ++++++++++++++++++++++++++-- 2 files changed, 269 insertions(+), 11 deletions(-) diff --git a/src/python/magnum/math.matrix.h b/src/python/magnum/math.matrix.h index d7608cc..bc91a39 100644 --- a/src/python/magnum/math.matrix.h +++ b/src/python/magnum/math.matrix.h @@ -181,6 +181,13 @@ 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(py::init([](const std::tuple, + std::tuple>& value) { + return Math::Matrix2x2{ + Math::Vector2{std::get<0>(std::get<0>(value)), std::get<1>(std::get<0>(value))}, + Math::Vector2{std::get<0>(std::get<1>(value)), std::get<1>(std::get<1>(value))} + }; + }), "Construct from a column tuple") .def("__matmul__", [](const Math::Matrix2x2& self, const Math::Matrix3x2& other) -> Math::Matrix3x2 { return self*other; }, "Multiply a matrix") @@ -193,6 +200,13 @@ template void matrices( .def(py::init([](const std::tuple, Math::Vector3>& value) { return Math::Matrix2x3{std::get<0>(value), std::get<1>(value)}; }), "Construct from a column vector tuple") + .def(py::init([](const std::tuple, + std::tuple>& value) { + return Math::Matrix2x3{ + Math::Vector3{std::get<0>(std::get<0>(value)), std::get<1>(std::get<0>(value)), std::get<2>(std::get<0>(value))}, + Math::Vector3{std::get<0>(std::get<1>(value)), std::get<1>(std::get<1>(value)), std::get<2>(std::get<1>(value))} + }; + }), "Construct from a column tuple") .def("__matmul__", [](const Math::Matrix2x3& self, const Math::Matrix2x2& other) -> Math::Matrix2x3 { return self*other; }, "Multiply a matrix") @@ -211,6 +225,13 @@ template void matrices( .def(py::init([](const std::tuple, Math::Vector4>& value) { return Math::Matrix2x4{std::get<0>(value), std::get<1>(value)}; }), "Construct from a column vector tuple") + .def(py::init([](const std::tuple, + std::tuple>& value) { + return Math::Matrix2x4{ + Math::Vector4{std::get<0>(std::get<0>(value)), std::get<1>(std::get<0>(value)), std::get<2>(std::get<0>(value)), std::get<3>(std::get<0>(value))}, + Math::Vector4{std::get<0>(std::get<1>(value)), std::get<1>(std::get<1>(value)), std::get<2>(std::get<1>(value)), std::get<3>(std::get<1>(value))} + }; + }), "Construct from a column tuple") .def("__matmul__", [](const Math::Matrix2x4& self, const Math::Matrix2x2& other) -> Math::Matrix2x4 { return self*other; }, "Multiply a matrix") @@ -239,6 +260,15 @@ template void matrices( .def(py::init([](const std::tuple, Math::Vector2, Math::Vector2>& value) { return Math::Matrix3x2{std::get<0>(value), std::get<1>(value), std::get<2>(value)}; }), "Construct from a column vector tuple") + .def(py::init([](const std::tuple, + std::tuple, + std::tuple>& value) { + return Math::Matrix3x2{ + Math::Vector2{std::get<0>(std::get<0>(value)), std::get<1>(std::get<0>(value))}, + Math::Vector2{std::get<0>(std::get<1>(value)), std::get<1>(std::get<1>(value))}, + Math::Vector2{std::get<0>(std::get<2>(value)), std::get<1>(std::get<2>(value))} + }; + }), "Construct from a column tuple") .def("__matmul__", [](const Math::Matrix3x2& self, const Math::Matrix2x3& other) -> Math::Matrix2x2 { return self*other; }, "Multiply a matrix") @@ -257,6 +287,15 @@ template void matrices( .def(py::init([](const std::tuple, Math::Vector3, Math::Vector3>& value) { return Math::Matrix3x3{std::get<0>(value), std::get<1>(value), std::get<2>(value)}; }), "Construct from a column vector tuple") + .def(py::init([](const std::tuple, + std::tuple, + std::tuple>& value) { + return Math::Matrix3x3{ + Math::Vector3{std::get<0>(std::get<0>(value)), std::get<1>(std::get<0>(value)), std::get<2>(std::get<0>(value))}, + Math::Vector3{std::get<0>(std::get<1>(value)), std::get<1>(std::get<1>(value)), std::get<2>(std::get<1>(value))}, + Math::Vector3{std::get<0>(std::get<2>(value)), std::get<1>(std::get<2>(value)), std::get<2>(std::get<2>(value))} + }; + }), "Construct from a column tuple") .def("__matmul__", [](const Math::Matrix3x3& self, const Math::Matrix2x3& other) -> Math::Matrix2x3 { return self*other; }, "Multiply a matrix") @@ -269,6 +308,15 @@ template void matrices( .def(py::init([](const std::tuple, Math::Vector4, Math::Vector4>& value) { return Math::Matrix3x4{std::get<0>(value), std::get<1>(value), std::get<2>(value)}; }), "Construct from a column vector tuple") + .def(py::init([](const std::tuple, + std::tuple, + std::tuple>& value) { + return Math::Matrix3x4{ + Math::Vector4{std::get<0>(std::get<0>(value)), std::get<1>(std::get<0>(value)), std::get<2>(std::get<0>(value)), std::get<3>(std::get<0>(value))}, + Math::Vector4{std::get<0>(std::get<1>(value)), std::get<1>(std::get<1>(value)), std::get<2>(std::get<1>(value)), std::get<3>(std::get<1>(value))}, + Math::Vector4{std::get<0>(std::get<2>(value)), std::get<1>(std::get<2>(value)), std::get<2>(std::get<2>(value)), std::get<3>(std::get<2>(value))} + }; + }), "Construct from a column tuple") .def("__matmul__", [](const Math::Matrix3x4& self, const Math::Matrix2x3& other) -> Math::Matrix2x4 { return self*other; }, "Multiply a matrix") @@ -297,6 +345,17 @@ template void matrices( .def(py::init([](const std::tuple, Math::Vector2, Math::Vector2, Math::Vector2>& value) { return Math::Matrix4x2{std::get<0>(value), std::get<1>(value), std::get<2>(value), std::get<3>(value)}; }), "Construct from a column vector tuple") + .def(py::init([](const std::tuple, + std::tuple, + std::tuple, + std::tuple>& value) { + return Math::Matrix4x2{ + Math::Vector2{std::get<0>(std::get<0>(value)), std::get<1>(std::get<0>(value))}, + Math::Vector2{std::get<0>(std::get<1>(value)), std::get<1>(std::get<1>(value))}, + Math::Vector2{std::get<0>(std::get<2>(value)), std::get<1>(std::get<2>(value))}, + Math::Vector2{std::get<0>(std::get<3>(value)), std::get<1>(std::get<3>(value))} + }; + }), "Construct from a column tuple") .def("__matmul__", [](const Math::Matrix4x2& self, const Math::Matrix2x4& other) -> Math::Matrix2x2 { return self*other; }, "Multiply a matrix") @@ -315,6 +374,17 @@ template void matrices( .def(py::init([](const std::tuple, Math::Vector3, Math::Vector3, Math::Vector3>& value) { return Math::Matrix4x3{std::get<0>(value), std::get<1>(value), std::get<2>(value), std::get<3>(value)}; }), "Construct from a column vector tuple") + .def(py::init([](const std::tuple, + std::tuple, + std::tuple, + std::tuple>& value) { + return Math::Matrix4x3{ + Math::Vector3{std::get<0>(std::get<0>(value)), std::get<1>(std::get<0>(value)), std::get<2>(std::get<0>(value))}, + Math::Vector3{std::get<0>(std::get<1>(value)), std::get<1>(std::get<1>(value)), std::get<2>(std::get<1>(value))}, + Math::Vector3{std::get<0>(std::get<2>(value)), std::get<1>(std::get<2>(value)), std::get<2>(std::get<2>(value))}, + Math::Vector3{std::get<0>(std::get<3>(value)), std::get<1>(std::get<3>(value)), std::get<2>(std::get<3>(value))} + }; + }), "Construct from a column tuple") .def("__matmul__", [](const Math::Matrix4x3& self, const Math::Matrix2x4& other) -> Math::Matrix2x3 { return self*other; }, "Multiply a matrix") @@ -333,6 +403,17 @@ template void matrices( .def(py::init([](const std::tuple, Math::Vector4, Math::Vector4, Math::Vector4>& value) { return Math::Matrix4x4{std::get<0>(value), std::get<1>(value), std::get<2>(value), std::get<3>(value)}; }), "Construct from a column vector tuple") + .def(py::init([](const std::tuple, + std::tuple, + std::tuple, + std::tuple>& value) { + return Math::Matrix4x4{ + Math::Vector4{std::get<0>(std::get<0>(value)), std::get<1>(std::get<0>(value)), std::get<2>(std::get<0>(value)), std::get<3>(std::get<0>(value))}, + Math::Vector4{std::get<0>(std::get<1>(value)), std::get<1>(std::get<1>(value)), std::get<2>(std::get<1>(value)), std::get<3>(std::get<1>(value))}, + Math::Vector4{std::get<0>(std::get<2>(value)), std::get<1>(std::get<2>(value)), std::get<2>(std::get<2>(value)), std::get<3>(std::get<2>(value))}, + Math::Vector4{std::get<0>(std::get<3>(value)), std::get<1>(std::get<3>(value)), std::get<2>(std::get<3>(value)), std::get<3>(std::get<3>(value))}, + }; + }), "Construct from a column tuple") .def("__matmul__", [](const Math::Matrix4x4& self, const Math::Matrix2x4& other) -> Math::Matrix2x4 { return self*other; }, "Multiply a matrix") @@ -380,6 +461,15 @@ template void matrices( .def(py::init([](const std::tuple, Math::Vector3, Math::Vector3>& value) { return Math::Matrix3{std::get<0>(value), std::get<1>(value), std::get<2>(value)}; }), "Construct from a column vector tuple") + .def(py::init([](const std::tuple, + std::tuple, + std::tuple>& value) { + return Math::Matrix3{ + Math::Vector3{std::get<0>(std::get<0>(value)), std::get<1>(std::get<0>(value)), std::get<2>(std::get<0>(value))}, + Math::Vector3{std::get<0>(std::get<1>(value)), std::get<1>(std::get<1>(value)), std::get<2>(std::get<1>(value))}, + Math::Vector3{std::get<0>(std::get<2>(value)), std::get<1>(std::get<2>(value)), std::get<2>(std::get<2>(value))} + }; + }), "Construct from a column tuple") /* Member functions */ .def("is_rigid_transformation", &Math::Matrix3::isRigidTransformation, @@ -495,6 +585,17 @@ template void matrices( .def(py::init([](const std::tuple, Math::Vector4, Math::Vector4, Math::Vector4>& value) { return Math::Matrix4{std::get<0>(value), std::get<1>(value), std::get<2>(value), std::get<3>(value)}; }), "Construct from a column vector tuple") + .def(py::init([](const std::tuple, + std::tuple, + std::tuple, + std::tuple>& value) { + return Math::Matrix4{ + Math::Vector4{std::get<0>(std::get<0>(value)), std::get<1>(std::get<0>(value)), std::get<2>(std::get<0>(value)), std::get<3>(std::get<0>(value))}, + Math::Vector4{std::get<0>(std::get<1>(value)), std::get<1>(std::get<1>(value)), std::get<2>(std::get<1>(value)), std::get<3>(std::get<1>(value))}, + Math::Vector4{std::get<0>(std::get<2>(value)), std::get<1>(std::get<2>(value)), std::get<2>(std::get<2>(value)), std::get<3>(std::get<2>(value))}, + Math::Vector4{std::get<0>(std::get<3>(value)), std::get<1>(std::get<3>(value)), std::get<2>(std::get<3>(value)), std::get<3>(std::get<3>(value))}, + }; + }), "Construct from a column tuple") /* Member functions */ .def("is_rigid_transformation", &Math::Matrix4::isRigidTransformation, diff --git a/src/python/magnum/test/test_math.py b/src/python/magnum/test/test_math.py index 48218ac..d150f88 100644 --- a/src/python/magnum/test/test_math.py +++ b/src/python/magnum/test/test_math.py @@ -371,12 +371,133 @@ class Matrix(unittest.TestCase): self.assertEqual(e[0], Vector3(1.0, 2.0, 3.0)) self.assertEqual(e[1], Vector3(4.0, 5.0, 6.0)) - f = Matrix3x2(((1.0, 2.0), + def test_init_tuple_of_vectors(self): + a = Matrix2x2((Vector2(1.0, 2.0), + Vector2(3.0, 4.0))) + self.assertEqual(a, Matrix2x2(Vector2(1.0, 2.0), + Vector2(3.0, 4.0))) + + a = Matrix2x3((Vector3(1.0, 2.0, 3.0), + Vector3(4.0, 5.0, 6.0))) + self.assertEqual(a, Matrix2x3(Vector3(1.0, 2.0, 3.0), + Vector3(4.0, 5.0, 6.0))) + + a = Matrix2x4((Vector4(1.0, 2.0, 3.0, 4.0), + Vector4(5.0, 6.0, 7.0, 8.0))) + self.assertEqual(a, Matrix2x4(Vector4(1.0, 2.0, 3.0, 4.0), + Vector4(5.0, 6.0, 7.0, 8.0))) + + a = Matrix3x2((Vector2(1.0, 2.0), + Vector2(3.0, 4.0), + Vector2(5.0, 6.0))) + self.assertEqual(a, Matrix3x2(Vector2(1.0, 2.0), + Vector2(3.0, 4.0), + Vector2(5.0, 6.0))) + + a = Matrix3x3((Vector3(1.0, 2.0, 3.0), + Vector3(4.0, 5.0, 6.0), + Vector3(7.0, 8.0, 9.0))) + self.assertEqual(a, Matrix3x3(Vector3(1.0, 2.0, 3.0), + Vector3(4.0, 5.0, 6.0), + Vector3(7.0, 8.0, 9.0))) + + a = Matrix3x4((Vector4(1.0, 2.0, 3.0, 4.0), + Vector4(5.0, 6.0, 7.0, 8.0), + Vector4(9.0, 10.0, 11.0, 12.0))) + self.assertEqual(a, Matrix3x4(Vector4(1.0, 2.0, 3.0, 4.0), + Vector4(5.0, 6.0, 7.0, 8.0), + Vector4(9.0, 10.0, 11.0, 12.0))) + + a = Matrix4x2((Vector2(1.0, 2.0), + Vector2(3.0, 4.0), + Vector2(5.0, 6.0), + Vector2(7.0, 8.0))) + self.assertEqual(a, Matrix4x2(Vector2(1.0, 2.0), + Vector2(3.0, 4.0), + Vector2(5.0, 6.0), + Vector2(7.0, 8.0))) + + a = Matrix4x3((Vector3(1.0, 2.0, 3.0), + Vector3(4.0, 5.0, 6.0), + Vector3(7.0, 8.0, 9.0), + Vector3(10.0, 11.0, 12.0))) + self.assertEqual(a, Matrix4x3(Vector3(1.0, 2.0, 3.0), + Vector3(4.0, 5.0, 6.0), + Vector3(7.0, 8.0, 9.0), + Vector3(10.0, 11.0, 12.0))) + + a = Matrix4x4((Vector4(1.0, 2.0, 3.0, 4.0), + Vector4(5.0, 6.0, 7.0, 8.0), + Vector4(9.0, 10.0, 11.0, 12.0), + Vector4(13.0, 14.0, 15.0, 16.0))) + self.assertEqual(a, Matrix4x4(Vector4(1.0, 2.0, 3.0, 4.0), + Vector4(5.0, 6.0, 7.0, 8.0), + Vector4(9.0, 10.0, 11.0, 12.0), + Vector4(13.0, 14.0, 15.0, 16.0))) + + def test_init_tuple_of_tuples(self): + a = Matrix2x2(((1.0, 2.0), + (3.0, 4.0))) + self.assertEqual(a, Matrix2x2(Vector2(1.0, 2.0), + Vector2(3.0, 4.0))) + + a = Matrix2x3(((1.0, 2.0, 3.0), + (4.0, 5.0, 6.0))) + self.assertEqual(a, Matrix2x3(Vector3(1.0, 2.0, 3.0), + Vector3(4.0, 5.0, 6.0))) + + a = Matrix2x4(((1.0, 2.0, 3.0, 4.0), + (5.0, 6.0, 7.0, 8.0))) + self.assertEqual(a, Matrix2x4(Vector4(1.0, 2.0, 3.0, 4.0), + Vector4(5.0, 6.0, 7.0, 8.0))) + + a = Matrix3x2(((1.0, 2.0), (3.0, 4.0), (5.0, 6.0))) - self.assertEqual(f[0], Vector2(1.0, 2.0)) - self.assertEqual(f[1], Vector2(3.0, 4.0)) - self.assertEqual(f[2], Vector2(5.0, 6.0)) + self.assertEqual(a, Matrix3x2(Vector2(1.0, 2.0), + Vector2(3.0, 4.0), + Vector2(5.0, 6.0))) + + a = Matrix3x3(((1.0, 2.0, 3.0), + (4.0, 5.0, 6.0), + (7.0, 8.0, 9.0))) + self.assertEqual(a, Matrix3x3(Vector3(1.0, 2.0, 3.0), + Vector3(4.0, 5.0, 6.0), + Vector3(7.0, 8.0, 9.0))) + + a = Matrix3x4(((1.0, 2.0, 3.0, 4.0), + (5.0, 6.0, 7.0, 8.0), + (9.0, 10.0, 11.0, 12.0))) + self.assertEqual(a, Matrix3x4(Vector4(1.0, 2.0, 3.0, 4.0), + Vector4(5.0, 6.0, 7.0, 8.0), + Vector4(9.0, 10.0, 11.0, 12.0))) + + a = Matrix4x2(((1.0, 2.0), + (3.0, 4.0), + (5.0, 6.0), + (7.0, 8.0))) + self.assertEqual(a, Matrix4x2(Vector2(1.0, 2.0), + Vector2(3.0, 4.0), + Vector2(5.0, 6.0), + Vector2(7.0, 8.0))) + + a = Matrix4x3(((1.0, 2.0, 3.0), + (4.0, 5.0, 6.0), + (7.0, 8.0, 9.0), + (10.0, 11.0, 12.0))) + self.assertEqual(a, Matrix4x3(Vector3(1.0, 2.0, 3.0), + Vector3(4.0, 5.0, 6.0), + Vector3(7.0, 8.0, 9.0), + Vector3(10.0, 11.0, 12.0))) + + a = Matrix4x4(((1.0, 2.0, 3.0, 4.0), + (5.0, 6.0, 7.0, 8.0), + (9.0, 10.0, 11.0, 12.0), + (13.0, 14.0, 15.0, 16.0))) + self.assertEqual(a, Matrix4x4(Vector4(1.0, 2.0, 3.0, 4.0), + Vector4(5.0, 6.0, 7.0, 8.0), + Vector4(9.0, 10.0, 11.0, 12.0), + Vector4(13.0, 14.0, 15.0, 16.0))) def test_convert(self): a = Matrix2x3d(Matrix2x3((1.0, 2.0, 3.0), @@ -462,13 +583,29 @@ class Matrix3_(unittest.TestCase): self.assertEqual(c3[1], Vector3.y_axis(3.0)) self.assertEqual(c3[2], Vector3.z_axis(3.0)) - d = Matrix3(((1.0, 2.0, 3.0), - (4.0, 5.0, 6.0), - (7.0, 8.0, 9.0))) + d = Matrix3((1.0, 2.0, 3.0), + (4.0, 5.0, 6.0), + (7.0, 8.0, 9.0)) self.assertEqual(d[0], Vector3(1.0, 2.0, 3.0)) self.assertEqual(d[1], Vector3(4.0, 5.0, 6.0)) self.assertEqual(d[2], Vector3(7.0, 8.0, 9.0)) + # Tuple of vectors + e = Matrix3((Vector3(1.0, 2.0, 3.0), + Vector3(4.0, 5.0, 6.0), + Vector3(7.0, 8.0, 9.0))) + self.assertEqual(e, Matrix3(Vector3(1.0, 2.0, 3.0), + Vector3(4.0, 5.0, 6.0), + Vector3(7.0, 8.0, 9.0))) + + # Tuple of tuples + e = Matrix3(((1.0, 2.0, 3.0), + (4.0, 5.0, 6.0), + (7.0, 8.0, 9.0))) + self.assertEqual(e, Matrix3(Vector3(1.0, 2.0, 3.0), + Vector3(4.0, 5.0, 6.0), + Vector3(7.0, 8.0, 9.0))) + def test_convert(self): a = Matrix3(Matrix3d((1.0, 2.0, 3.0), (4.0, 5.0, 6.0), @@ -527,15 +664,35 @@ class Matrix4_(unittest.TestCase): self.assertEqual(c3[2], Vector4(0.0, 0.0, 3.0, 0.0)) self.assertEqual(c3[3], Vector4(0.0, 0.0, 0.0, 3.0)) - d = Matrix4(((1.0, 2.0, 3.0, 4.0), - (5.0, 6.0, 7.0, 8.0), - (9.0, 10.0, 11.0, 12.0), - (13.0, 14.0, 15.0, 16.0))) + d = Matrix4((1.0, 2.0, 3.0, 4.0), + (5.0, 6.0, 7.0, 8.0), + (9.0, 10.0, 11.0, 12.0), + (13.0, 14.0, 15.0, 16.0)) self.assertEqual(d[0], Vector4(1.0, 2.0, 3.0, 4.0)) self.assertEqual(d[1], Vector4(5.0, 6.0, 7.0, 8.0)) self.assertEqual(d[2], Vector4(9.0, 10.0, 11.0, 12.0)) self.assertEqual(d[3], Vector4(13.0, 14.0, 15.0, 16.0)) + # Tuple of vectors + e = Matrix4((Vector4(1.0, 2.0, 3.0, 4.0), + Vector4(5.0, 6.0, 7.0, 8.0), + Vector4(9.0, 10.0, 11.0, 12.0), + Vector4(13.0, 14.0, 15.0, 16.0))) + self.assertEqual(e, Matrix4(Vector4(1.0, 2.0, 3.0, 4.0), + Vector4(5.0, 6.0, 7.0, 8.0), + Vector4(9.0, 10.0, 11.0, 12.0), + Vector4(13.0, 14.0, 15.0, 16.0))) + + # Tuple of tuples + e = Matrix4(((1.0, 2.0, 3.0, 4.0), + (5.0, 6.0, 7.0, 8.0), + (9.0, 10.0, 11.0, 12.0), + (13.0, 14.0, 15.0, 16.0))) + self.assertEqual(e, Matrix4(Vector4(1.0, 2.0, 3.0, 4.0), + Vector4(5.0, 6.0, 7.0, 8.0), + Vector4(9.0, 10.0, 11.0, 12.0), + Vector4(13.0, 14.0, 15.0, 16.0))) + def test_convert(self): a = Matrix4d(Matrix4((1.0, 2.0, 3.0, 4.0), (5.0, 6.0, 7.0, 8.0),