Browse Source

python: implement conversions between different underlying types.

Such a tiny feature and such a pain when it's not there.
pull/1/head
Vladimír Vondruš 7 years ago
parent
commit
464154adca
  1. 8
      src/python/magnum/math.cpp
  2. 4
      src/python/magnum/math.matrix.h
  3. 15
      src/python/magnum/math.matrixdouble.cpp
  4. 17
      src/python/magnum/math.matrixfloat.cpp
  5. 13
      src/python/magnum/math.vector.h
  6. 12
      src/python/magnum/math.vectorfloat.cpp
  7. 9
      src/python/magnum/math.vectorintegral.cpp
  8. 32
      src/python/magnum/test/test_math.py

8
src/python/magnum/math.cpp

@ -155,6 +155,10 @@ template<class T> void boolVector(py::class_<T>& c) {
c.def_static("__len__", []() { return int(T::Size); }, lenDocstring);
}
template<class U, class T, class ...Args> void convertible(py::class_<T, Args...>& c) {
c.def(py::init<U>(), "Construct from different underlying type");
}
template<class T> void quaternion(py::module& m, py::class_<T>& 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> quaternion_(root, "Quaternion", "Float quaternion");
py::class_<Quaterniond> quaterniond(root, "Quaterniond", "Double quaternion");
quaternion(m, quaternion_);
quaternion(m, quaterniond);
convertible<Quaterniond>(quaternion_);
convertible<Quaternion>(quaterniond);
}
}

4
src/python/magnum/math.matrix.h

@ -154,6 +154,10 @@ template<class T> void matrix(py::class_<T>& c) {
.def("determinant", &T::determinant, "Determinant");
}
template<class U, class T, class ...Args> void convertible(py::class_<T, Args...>& c) {
c.def(py::init<U>(), "Construct from different underlying type");
}
template<class T> void matrices(
py::class_<Math::Matrix2x2<T>>& matrix2x2,
py::class_<Math::Matrix2x3<T>>& matrix2x3,

15
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<Matrix2x2>(matrix2x2d);
convertible<Matrix2x3>(matrix2x3d);
convertible<Matrix2x4>(matrix2x4d);
convertible<Matrix3x2>(matrix3x2d);
convertible<Matrix3x3>(matrix3x3d);
convertible<Matrix3x4>(matrix3x4d);
convertible<Matrix4x2>(matrix4x2d);
convertible<Matrix4x3>(matrix4x3d);
convertible<Matrix4x4>(matrix4x4d);
convertible<Matrix3>(matrix3d);
convertible<Matrix4>(matrix4d);
}
}

17
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<Matrix2x2d>(matrix2x2);
convertible<Matrix2x3d>(matrix2x3);
convertible<Matrix2x4d>(matrix2x4);
convertible<Matrix3x2d>(matrix3x2);
convertible<Matrix3x3d>(matrix3x3);
convertible<Matrix3x4d>(matrix3x4);
convertible<Matrix4x2d>(matrix4x2);
convertible<Matrix4x3d>(matrix4x3);
convertible<Matrix4x4d>(matrix4x4);
convertible<Matrix3d>(matrix3);
convertible<Matrix4d>(matrix4);
}
}

13
src/python/magnum/math.vector.h

@ -261,6 +261,19 @@ template<class T> void vector4(py::class_<Math::Vector4<T>>& c) {
"XY part of the vector");
}
template<class U, template<class> class Type, class T, class ...Args> void convertibleImplementation(py::class_<Type<T>, Args...>& c, std::false_type) {
c.def(py::init<Type<U>>(), "Construct from different underlying type");
}
template<class U, template<class> class Type, class T, class ...Args> void convertibleImplementation(py::class_<Type<T>, Args...>&, std::true_type) {}
template<template<class> class Type, class T, class ...Args> void convertible(py::class_<Type<T>, Args...>& c) {
convertibleImplementation<UnsignedInt>(c, std::is_same<T, UnsignedInt>{});
convertibleImplementation<Int>(c, std::is_same<T, Int>{});
convertibleImplementation<Float>(c, std::is_same<T, Float>{});
convertibleImplementation<Double>(c, std::is_same<T, Double>{});
}
template<class T, class Base> void color(py::class_<T, Base>& c) {
c
.def_static("zero_init", []() {

12
src/python/magnum/math.vectorfloat.cpp

@ -93,6 +93,18 @@ void mathVectorFloat(py::module& root, py::module& m) {
py::class_<Color4, Vector4> 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 */
}
}

9
src/python/magnum/math.vectorintegral.cpp

@ -78,6 +78,15 @@ void mathVectorIntegral(py::module& root, py::module& m) {
py::class_<Vector4ui> vector4ui{root, "Vector4ui", "Four-component unsigned integral vector"};
vectorsIntegral<Int>(m, vector2i, vector3i, vector4i);
vectorsIntegral<UnsignedInt>(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);
}
}

32
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))

Loading…
Cancel
Save