diff --git a/src/python/magnum/math.cpp b/src/python/magnum/math.cpp index 4b81111..598083b 100644 --- a/src/python/magnum/math.cpp +++ b/src/python/magnum/math.cpp @@ -155,6 +155,10 @@ template void boolVector(py::class_& c) { c.def_static("__len__", []() { return int(T::Size); }, lenDocstring); } +template void convertible(py::class_& c) { + c.def(py::init(), "Construct from different underlying type"); +} + template void quaternion(py::module& m, py::class_& c) { /* Missing APIs: @@ -311,15 +315,15 @@ void math(py::module& root, py::module& m) { /* These are needed for the quaternion, so register them before */ magnum::mathVectorFloat(root, m); - magnum::mathVectorIntegral(root, m); magnum::mathMatrixFloat(root); - magnum::mathMatrixDouble(root); /* Quaternion */ py::class_ quaternion_(root, "Quaternion", "Float quaternion"); py::class_ quaterniond(root, "Quaterniond", "Double quaternion"); quaternion(m, quaternion_); quaternion(m, quaterniond); + convertible(quaternion_); + convertible(quaterniond); } } diff --git a/src/python/magnum/math.matrix.h b/src/python/magnum/math.matrix.h index 583b757..d7608cc 100644 --- a/src/python/magnum/math.matrix.h +++ b/src/python/magnum/math.matrix.h @@ -154,6 +154,10 @@ template void matrix(py::class_& c) { .def("determinant", &T::determinant, "Determinant"); } +template void convertible(py::class_& c) { + c.def(py::init(), "Construct from different underlying type"); +} + template void matrices( py::class_>& matrix2x2, py::class_>& matrix2x3, diff --git a/src/python/magnum/math.matrixdouble.cpp b/src/python/magnum/math.matrixdouble.cpp index 9b44cc1..cf8e955 100644 --- a/src/python/magnum/math.matrixdouble.cpp +++ b/src/python/magnum/math.matrixdouble.cpp @@ -48,6 +48,21 @@ void mathMatrixDouble(py::module& root) { matrix3x2d, matrix3x3d, matrix3x4d, matrix4x2d, matrix4x3d, matrix4x4d, matrix3d, matrix4d); + + /* At this point we should have both float and double types registered, + so register type conversions */ + convertible(matrix2x2d); + convertible(matrix2x3d); + convertible(matrix2x4d); + convertible(matrix3x2d); + convertible(matrix3x3d); + convertible(matrix3x4d); + convertible(matrix4x2d); + convertible(matrix4x3d); + convertible(matrix4x4d); + + convertible(matrix3d); + convertible(matrix4d); } } diff --git a/src/python/magnum/math.matrixfloat.cpp b/src/python/magnum/math.matrixfloat.cpp index d0ce98a..8a7069c 100644 --- a/src/python/magnum/math.matrixfloat.cpp +++ b/src/python/magnum/math.matrixfloat.cpp @@ -48,6 +48,23 @@ void mathMatrixFloat(py::module& root) { matrix3x2, matrix3x3, matrix3x4, matrix4x2, matrix4x3, matrix4x4, matrix3, matrix4); + + /* Register the double types as well, only after that register type + conversions because they need all the types */ + mathMatrixDouble(root); + + convertible(matrix2x2); + convertible(matrix2x3); + convertible(matrix2x4); + convertible(matrix3x2); + convertible(matrix3x3); + convertible(matrix3x4); + convertible(matrix4x2); + convertible(matrix4x3); + convertible(matrix4x4); + + convertible(matrix3); + convertible(matrix4); } } diff --git a/src/python/magnum/math.vector.h b/src/python/magnum/math.vector.h index 38efe12..4967fdd 100644 --- a/src/python/magnum/math.vector.h +++ b/src/python/magnum/math.vector.h @@ -261,6 +261,19 @@ template void vector4(py::class_>& c) { "XY part of the vector"); } +template class Type, class T, class ...Args> void convertibleImplementation(py::class_, Args...>& c, std::false_type) { + c.def(py::init>(), "Construct from different underlying type"); +} + +template class Type, class T, class ...Args> void convertibleImplementation(py::class_, Args...>&, std::true_type) {} + +template class Type, class T, class ...Args> void convertible(py::class_, Args...>& c) { + convertibleImplementation(c, std::is_same{}); + convertibleImplementation(c, std::is_same{}); + convertibleImplementation(c, std::is_same{}); + convertibleImplementation(c, std::is_same{}); +} + template void color(py::class_& c) { c .def_static("zero_init", []() { diff --git a/src/python/magnum/math.vectorfloat.cpp b/src/python/magnum/math.vectorfloat.cpp index 53b8c7a..1a7cd1c 100644 --- a/src/python/magnum/math.vectorfloat.cpp +++ b/src/python/magnum/math.vectorfloat.cpp @@ -93,6 +93,18 @@ void mathVectorFloat(py::module& root, py::module& m) { py::class_ color4_{root, "Color4", "Color in linear RGBA color space"}; color(color4_); color4(color4_); + + /* Register the integer types as well, only after that register type + conversions because they need all the types */ + mathVectorIntegral(root, m); + + convertible(vector2); + convertible(vector3); + convertible(vector4); + convertible(vector2d); + convertible(vector3d); + convertible(vector4d); + /* Colors are float-only at the moment, thus no conversions */ } } diff --git a/src/python/magnum/math.vectorintegral.cpp b/src/python/magnum/math.vectorintegral.cpp index e55f6da..87f558a 100644 --- a/src/python/magnum/math.vectorintegral.cpp +++ b/src/python/magnum/math.vectorintegral.cpp @@ -78,6 +78,15 @@ void mathVectorIntegral(py::module& root, py::module& m) { py::class_ vector4ui{root, "Vector4ui", "Four-component unsigned integral vector"}; vectorsIntegral(m, vector2i, vector3i, vector4i); vectorsIntegral(m, vector2ui, vector3ui, vector4ui); + + /* At this point we should have both float and integral types registered, + so register type conversions */ + convertible(vector2i); + convertible(vector3i); + convertible(vector4i); + convertible(vector2ui); + convertible(vector3ui); + convertible(vector4ui); } } diff --git a/src/python/magnum/test/test_math.py b/src/python/magnum/test/test_math.py index 552d8de..48218ac 100644 --- a/src/python/magnum/test/test_math.py +++ b/src/python/magnum/test/test_math.py @@ -129,6 +129,10 @@ class Vector(unittest.TestCase): self.assertEqual(d, Vector3(1.0, 0.3, 1.1)) self.assertEqual(e, Vector4d(1.0, 0.3, 1.1, 0.5)) + def test_convert(self): + a = Vector2i(Vector2(4.3, 3.1)) + self.assertEqual(a, Vector2i(4, 3)) + def test_static_methods(self): self.assertEqual(Vector2.y_scale(5), Vector2(1, 5)) self.assertEqual(Vector3d.z_axis(-3), Vector3d(0, 0, -3)) @@ -374,6 +378,12 @@ class Matrix(unittest.TestCase): self.assertEqual(f[1], Vector2(3.0, 4.0)) self.assertEqual(f[2], Vector2(5.0, 6.0)) + def test_convert(self): + a = Matrix2x3d(Matrix2x3((1.0, 2.0, 3.0), + (4.0, 5.0, 6.0))) + self.assertEqual(a, Matrix2x3d((1.0, 2.0, 3.0), + (4.0, 5.0, 6.0))) + def test_length(self): self.assertEqual(Matrix3x4.__len__(), 3) #self.assertEqual(len(Matrix4x3), 4) TODO: Y not? @@ -459,6 +469,14 @@ class Matrix3_(unittest.TestCase): self.assertEqual(d[1], Vector3(4.0, 5.0, 6.0)) self.assertEqual(d[2], 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), + (7.0, 8.0, 9.0))) + self.assertEqual(a, Matrix3((1.0, 2.0, 3.0), + (4.0, 5.0, 6.0), + (7.0, 8.0, 9.0))) + def test_static_methods(self): a = Matrix3.translation((0.0, -1.0)) self.assertEqual(a[2].xy, Vector2(0.0, -1.0)) @@ -518,6 +536,16 @@ class Matrix4_(unittest.TestCase): 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)) + def test_convert(self): + a = Matrix4d(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(a, Matrix4d((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))) + def test_static_methods(self): a = Matrix4.translation((0.0, -1.0, 2.0)) self.assertEqual(a[3].xyz, Vector3(0.0, -1.0, 2.0)) @@ -567,6 +595,10 @@ class Quaternion_(unittest.TestCase): self.assertEqual(e.vector, Vector3(1.0, 2.0, 3.0)) self.assertEqual(e.scalar, 4.0) + def test_convert(self): + a = Quaterniond(Quaternion((1.0, 2.0, 3.0), 4.0)) + self.assertEqual(a, Quaterniond((1.0, 2.0, 3.0), 4.0)) + def test_static_methods(self): a = Quaternion.rotation(Deg(45.0), Vector3.x_axis()) self.assertEqual(a, Quaternion((0.382683, 0.0, 0.0), 0.92388))