diff --git a/src/python/magnum/math.vector.h b/src/python/magnum/math.vector.h index 4967fdd..f4052d9 100644 --- a/src/python/magnum/math.vector.h +++ b/src/python/magnum/math.vector.h @@ -33,6 +33,33 @@ namespace magnum { +/* Things that have to be defined for both VectorN and Color so they construct + / return a proper type */ +template void everyVector(py::class_& c) { + c + .def_static("zero_init", []() { + return T{Math::ZeroInit}; + }, "Construct a zero vector") + .def(py::init(), "Default constructor") + + /* Operators */ + .def(-py::self, "Negated vector") + .def(py::self += py::self, "Add and assign a vector") + .def(py::self + py::self, "Add a vector") + .def(py::self -= py::self, "Subtract and assign a vector") + .def(py::self - py::self, "Subtract a vector") + .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(py::self *= py::self, "Multiply a vector component-wise and assign") + .def(py::self * py::self, "Multiply a vector component-wise") + .def(py::self /= py::self, "Divide a vector component-wise and assign") + .def(py::self / py::self, "Divide a vector component-wise") + .def(typename T::Type{} * py::self, "Multiply a scalar with a vector") + .def(typename T::Type{} / py::self, "Divide a vector with a scalar and invert"); +} + /* Things common for vectors of all sizes and types */ template void vector(py::module& m, py::class_& c) { /* @@ -50,10 +77,6 @@ template void vector(py::module& m, py::class_& c) { c /* Constructors */ - .def_static("zero_init", []() { - return T{Math::ZeroInit}; - }, "Construct a zero vector") - .def(py::init(), "Default constructor") .def(py::init(), "Construct a vector with one value for all components") /* Comparison */ @@ -75,23 +98,6 @@ template void vector(py::module& m, py::class_& c) { return self[i]; }, "Value at given position") - /* Operators */ - .def(-py::self, "Negated vector") - .def(py::self += py::self, "Add and assign a vector") - .def(py::self + py::self, "Add a vector") - .def(py::self -= py::self, "Subtract and assign a vector") - .def(py::self - py::self, "Subtract a vector") - .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(py::self *= py::self, "Multiply a vector component-wise and assign") - .def(py::self * py::self, "Multiply a vector component-wise") - .def(py::self /= py::self, "Divide a vector component-wise and assign") - .def(py::self / py::self, "Divide a vector component-wise") - .def(typename T::Type{} * py::self, "Multiply a scalar with a vector") - .def(typename T::Type{} / py::self, "Divide a vector with a scalar and invert") - /* Member functions common for floating-point and integer types */ .def("is_zero", &T::isZero, "Whether the vector is zero") .def("dot", static_cast(&T::dot), "Dot product of the vector") @@ -341,7 +347,17 @@ template void color4(py::class_, Math::Vector4>& c) return Degd(self.hue()); }, "Hue") .def("saturation", &Math::Color4::saturation, "Saturation") - .def("value", &Math::Color4::value, "Value"); + .def("value", &Math::Color4::value, "Value") + + /* Properties */ + .def_property("xyz", + static_cast(Math::Color4::*)() const>(&Math::Color4::xyz), + [](Math::Color4& self, const Math::Color3& value) { self.xyz() = value; }, + "XYZ part of the vector") + .def_property("rgb", + static_cast(Math::Color4::*)() const>(&Math::Color4::rgb), + [](Math::Color4& self, const Math::Color3& value) { self.rgb() = value; }, + "RGB part of the vector"); } } diff --git a/src/python/magnum/math.vectorfloat.cpp b/src/python/magnum/math.vectorfloat.cpp index 1a7cd1c..3e251ff 100644 --- a/src/python/magnum/math.vectorfloat.cpp +++ b/src/python/magnum/math.vectorfloat.cpp @@ -58,6 +58,7 @@ template void vectorsFloat(py::module& m, py::class_>& "Aspect ratio") .def("cross", static_cast&, const Math::Vector2&)>(Math::cross), "2D cross product"); + everyVector(vector2_); vector>(m, vector2_); vectorFloat>(m, vector2_); vector2(vector2_); @@ -65,10 +66,12 @@ template void vectorsFloat(py::module& m, py::class_>& vector3_ .def("cross", static_cast(*)(const Math::Vector3&, const Math::Vector3&)>(Math::cross), "Cross product"); + everyVector(vector3_); vector>(m, vector3_); vectorFloat>(m, vector3_); vector3(vector3_); + everyVector(vector4_); vector>(m, vector4_); vectorFloat>(m, vector4_); vector4(vector4_); @@ -87,10 +90,12 @@ void mathVectorFloat(py::module& root, py::module& m) { vectorsFloat(m, vector2d, vector3d, vector4d); py::class_ color3_{root, "Color3", "Color in linear RGB color space"}; + everyVector(color3_); color(color3_); color3(color3_); py::class_ color4_{root, "Color4", "Color in linear RGBA color space"}; + everyVector(color4_); color(color4_); color4(color4_); diff --git a/src/python/magnum/math.vectorintegral.cpp b/src/python/magnum/math.vectorintegral.cpp index 87f558a..74dfe55 100644 --- a/src/python/magnum/math.vectorintegral.cpp +++ b/src/python/magnum/math.vectorintegral.cpp @@ -54,14 +54,17 @@ template void vectorIntegral(py::class_& c) { } template void vectorsIntegral(py::module& m, py::class_>& vector2_, py::class_>& vector3_, py::class_>& vector4_) { + everyVector(vector2_); vector>(m, vector2_); vectorIntegral>(vector2_); vector2(vector2_); + everyVector(vector3_); vector>(m, vector3_); vectorIntegral>(vector3_); vector3(vector3_); + everyVector(vector4_); vector>(m, vector4_); vectorIntegral>(vector4_); vector4(vector4_); diff --git a/src/python/magnum/test/test_math.py b/src/python/magnum/test/test_math.py index a884f70..5232816 100644 --- a/src/python/magnum/test/test_math.py +++ b/src/python/magnum/test/test_math.py @@ -292,6 +292,11 @@ class Color3_(unittest.TestCase): self.assertAlmostEqual(a.to_hsv()[1], 0.749) self.assertAlmostEqual(a.to_hsv()[2], 0.427) + def test_methods_return_type(self): + self.assertIsInstance(Color3()*1.5, Color3) + self.assertIsInstance(Color3()+Color3(), Color3) + self.assertIsInstance(Color3.zero_init(), Color3) + class Color4_(unittest.TestCase): def test_init(self): a1 = Color4() @@ -338,6 +343,13 @@ class Color4_(unittest.TestCase): b = Color4.from_hsv(Deg(230.0), 0.749, 0.427) self.assertEqual(b, Color4(0.107177, 0.160481, 0.427, 1.0)) + def test_methods_return_type(self): + self.assertIsInstance(Color4()*1.5, Color4) + self.assertIsInstance(Color4()+Color4(), Color4) + self.assertIsInstance(Color4.zero_init(), Color4) + self.assertIsInstance(Color4().rgb, Color3) + self.assertIsInstance(Color4().xyz, Color3) + class Matrix(unittest.TestCase): def test_init(self): a = Matrix3x2()