Browse Source

magnum: again (and hopefully for the last time) reorder constructors.

The order should be (and now is):

 1. magnum's own conversion constructors (double from integer and such)
 2. stuff like implicit color3 -> color4, if applicable
 3. buffer protocol constructors
 4. general "init from a tuple" constructors last, because they're the
    slowest
pull/2/head
Vladimír Vondruš 7 years ago
parent
commit
d157b55637
  1. 53
      src/python/magnum/math.matrix.h
  2. 38
      src/python/magnum/math.matrixdouble.cpp
  3. 35
      src/python/magnum/math.matrixfloat.cpp
  4. 16
      src/python/magnum/math.vector.h
  5. 50
      src/python/magnum/math.vectorfloat.cpp
  6. 26
      src/python/magnum/math.vectorintegral.cpp

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

@ -68,6 +68,34 @@ template<class T, class ...Args> void everyRectangularMatrix(py::class_<T, Args.
.def(py::init(), "Default constructor") .def(py::init(), "Default constructor")
.def(py::init<typename T::Type>(), "Construct a matrix with one value for all components") .def(py::init<typename T::Type>(), "Construct a matrix with one value for all components")
/* 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<T::Cols, typename T::Type>::Type& vector) -> typename VectorTraits<T::Rows, typename T::Type>::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<T::DiagonalSize, typename T::Type>::Type {
return self.diagonal();
}, "Values on diagonal");
}
/* Separate because it needs to be registered after the type conversion
constructors. Needs to be called also for subclasses. */
template<class T, class ...Args> void everyRectangularMatrixBuffer(py::class_<T, Args...>& c) {
c
/* Buffer protocol, needed in order to properly detect row-major /* Buffer protocol, needed in order to properly detect row-major
layouts. Has to be defined *before* the from-tuple constructor so it layouts. Has to be defined *before* the from-tuple constructor so it
gets precedence for types that implement the buffer protocol. */ gets precedence for types that implement the buffer protocol. */
@ -94,30 +122,7 @@ template<class T, class ...Args> void everyRectangularMatrix(py::class_<T, Args.
else throw py::buffer_error{Utility::formatString("expected format f or d but got {}", buffer.format)}; else throw py::buffer_error{Utility::formatString("expected format f or d but got {}", buffer.format)};
return out; return out;
}), "Construct from a buffer") }), "Construct from a buffer");
/* 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<T::Cols, typename T::Type>::Type& vector) -> typename VectorTraits<T::Rows, typename T::Type>::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<T::DiagonalSize, typename T::Type>::Type {
return self.diagonal();
}, "Values on diagonal");
} }
template<class T> bool rectangularMatrixBufferProtocol(T& self, Py_buffer& buffer, int flags) { template<class T> bool rectangularMatrixBufferProtocol(T& self, Py_buffer& buffer, int flags) {

38
src/python/magnum/math.matrixdouble.cpp

@ -44,18 +44,12 @@ void mathMatrixDouble(py::module& root) {
done by the base classes. Moreover, just adding py::buffer_protocol{} done by the base classes. Moreover, just adding py::buffer_protocol{}
would cause it to not find the buffer functions as we don't add them would cause it to not find the buffer functions as we don't add them
anywhere, thus failing with `pybind11_getbuffer(): Internal error`. */ anywhere, thus failing with `pybind11_getbuffer(): Internal error`. */
py::class_<Matrix3d, Matrix3x3d> matrix3d{root, "Matrix3d", "2D double transformation matrix"}; py::class_<Matrix3d, Matrix3x3d> matrix3d{root, "Matrix3d", "2D double transformation matrix"};
py::class_<Matrix4d, Matrix4x4d> matrix4d{root, "Matrix4d", "3D double transformation matrix"}; py::class_<Matrix4d, Matrix4x4d> matrix4d{root, "Matrix4d", "3D double transformation matrix"};
matrices<Double>( /* Register type conversions as soon as possible as those should have a
matrix2x2d, matrix2x3d, matrix2x4d, priority over buffer and list constructors. These need all the types to
matrix3x2d, matrix3x3d, matrix3x4d, be present, so can't be interwinted with the class definitions above. */
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<Matrix2x2>(matrix2x2d);
convertible<Matrix2x3>(matrix2x3d); convertible<Matrix2x3>(matrix2x3d);
convertible<Matrix2x4>(matrix2x4d); convertible<Matrix2x4>(matrix2x4d);
@ -65,9 +59,33 @@ void mathMatrixDouble(py::module& root) {
convertible<Matrix4x2>(matrix4x2d); convertible<Matrix4x2>(matrix4x2d);
convertible<Matrix4x3>(matrix4x3d); convertible<Matrix4x3>(matrix4x3d);
convertible<Matrix4x4>(matrix4x4d); convertible<Matrix4x4>(matrix4x4d);
convertible<Matrix3>(matrix3d); convertible<Matrix3>(matrix3d);
convertible<Matrix4>(matrix4d); convertible<Matrix4>(matrix4d);
/* This needs to be *after* conversion constructors so the type conversion
gets picked before the general buffer constructor (which would then
fail). On the other hand, this needs to be before generic from-list
constructors because buffer protocol is generally faster than
iteration. */
everyRectangularMatrixBuffer(matrix2x2d);
everyRectangularMatrixBuffer(matrix2x3d);
everyRectangularMatrixBuffer(matrix2x4d);
everyRectangularMatrixBuffer(matrix3x2d);
everyRectangularMatrixBuffer(matrix3x3d);
everyRectangularMatrixBuffer(matrix3x4d);
everyRectangularMatrixBuffer(matrix4x2d);
everyRectangularMatrixBuffer(matrix4x3d);
everyRectangularMatrixBuffer(matrix4x4d);
everyRectangularMatrixBuffer(matrix3d);
everyRectangularMatrixBuffer(matrix4d);
/* Now register the generic from-list constructors and everything else */
matrices<Double>(
matrix2x2d, matrix2x3d, matrix2x4d,
matrix3x2d, matrix3x3d, matrix3x4d,
matrix4x2d, matrix4x3d, matrix4x4d,
matrix3d, matrix4d);
} }
} }

35
src/python/magnum/math.matrixfloat.cpp

@ -44,20 +44,16 @@ void mathMatrixFloat(py::module& root) {
done by the base classes. Moreover, just adding py::buffer_protocol{} done by the base classes. Moreover, just adding py::buffer_protocol{}
would cause it to not find the buffer functions as we don't add them would cause it to not find the buffer functions as we don't add them
anywhere, thus failing with `pybind11_getbuffer(): Internal error`. */ anywhere, thus failing with `pybind11_getbuffer(): Internal error`. */
py::class_<Matrix3, Matrix3x3> matrix3{root, "Matrix3", "2D float transformation matrix"}; py::class_<Matrix3, Matrix3x3> matrix3{root, "Matrix3", "2D float transformation matrix"};
py::class_<Matrix4, Matrix4x4> matrix4{root, "Matrix4", "3D float transformation matrix"}; py::class_<Matrix4, Matrix4x4> matrix4{root, "Matrix4", "3D float transformation matrix"};
matrices<Float>(
matrix2x2, matrix2x3, matrix2x4,
matrix3x2, matrix3x3, matrix3x4,
matrix4x2, matrix4x3, matrix4x4,
matrix3, matrix4);
/* Register the double types as well, only after that register type /* Register the double types as well, only after that register type
conversions because they need all the types */ conversions because they need all the types */
mathMatrixDouble(root); mathMatrixDouble(root);
/* Register type conversions as soon as possible as those should have a
priority over buffer and list constructors. These need all the types to
be present, so can't be interwinted with the class definitions above. */
convertible<Matrix2x2d>(matrix2x2); convertible<Matrix2x2d>(matrix2x2);
convertible<Matrix2x3d>(matrix2x3); convertible<Matrix2x3d>(matrix2x3);
convertible<Matrix2x4d>(matrix2x4); convertible<Matrix2x4d>(matrix2x4);
@ -67,9 +63,32 @@ void mathMatrixFloat(py::module& root) {
convertible<Matrix4x2d>(matrix4x2); convertible<Matrix4x2d>(matrix4x2);
convertible<Matrix4x3d>(matrix4x3); convertible<Matrix4x3d>(matrix4x3);
convertible<Matrix4x4d>(matrix4x4); convertible<Matrix4x4d>(matrix4x4);
convertible<Matrix3d>(matrix3); convertible<Matrix3d>(matrix3);
convertible<Matrix4d>(matrix4); convertible<Matrix4d>(matrix4);
/* This needs to be *after* conversion constructors so the type conversion
gets picked before the general buffer constructor (which would then
fail). On the other hand, this needs to be before generic from-list
constructors because buffer protocol is generally faster than
iteration. */
everyRectangularMatrixBuffer(matrix2x2);
everyRectangularMatrixBuffer(matrix2x3);
everyRectangularMatrixBuffer(matrix2x4);
everyRectangularMatrixBuffer(matrix3x2);
everyRectangularMatrixBuffer(matrix3x3);
everyRectangularMatrixBuffer(matrix3x4);
everyRectangularMatrixBuffer(matrix4x2);
everyRectangularMatrixBuffer(matrix4x3);
everyRectangularMatrixBuffer(matrix4x4);
everyRectangularMatrixBuffer(matrix3);
everyRectangularMatrixBuffer(matrix4);
/* Now register the generic from-list constructors and everything else */
matrices<Float>(
matrix2x2, matrix2x3, matrix2x4,
matrix3x2, matrix3x3, matrix3x4,
matrix4x2, matrix4x3, matrix4x4,
matrix3, matrix4);
} }
} }

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

@ -111,8 +111,8 @@ template<class T, class ...Args> void everyVector(py::class_<T, Args...>& c) {
} }
/* Separate because it needs to be registered after the type conversion /* Separate because it needs to be registered after the type conversion
constructors */ constructors. Needs to be called also for subclasses. */
template<class T, class ...Args> void vectorBuffer(py::class_<T, Args...>& c) { template<class T, class ...Args> void everyVectorBuffer(py::class_<T, Args...>& c) {
c c
/* Buffer protocol. If not present, implicit conversion from numpy /* Buffer protocol. If not present, implicit conversion from numpy
arrays of non-default types somehow doesn't work. There's also the arrays of non-default types somehow doesn't work. There's also the
@ -437,17 +437,23 @@ template<class T> void color3(py::class_<Math::Color3<T>, Math::Vector3<T>>& c)
.def("value", &Math::Color3<T>::value, "Value"); .def("value", &Math::Color3<T>::value, "Value");
} }
/* Needs to be separate to make it a priority over buffer protocol */
template<class T> void color4from3(py::class_<Math::Color4<T>, Math::Vector4<T>>& c) {
py::implicitly_convertible<const Math::Vector3<T>&, Math::Color4<T>>();
c
.def(py::init<Math::Vector3<T>, T>(), "Construct from a three-component color", py::arg("rgb"), py::arg("alpha") = Math::Implementation::fullChannel<T>())
.def(py::init<Math::Vector4<T>>(), "Construct from a vector");
}
template<class T> void color4(py::class_<Math::Color4<T>, Math::Vector4<T>>& c) { template<class T> void color4(py::class_<Math::Color4<T>, Math::Vector4<T>>& c) {
py::implicitly_convertible<const std::tuple<T, T, T>&, Math::Color4<T>>(); py::implicitly_convertible<const std::tuple<T, T, T>&, Math::Color4<T>>();
py::implicitly_convertible<const std::tuple<T, T, T, T>&, Math::Color4<T>>(); py::implicitly_convertible<const std::tuple<T, T, T, T>&, Math::Color4<T>>();
py::implicitly_convertible<const Math::Color3<T>&, Math::Color4<T>>();
c c
/* Constructors */ /* Constructors */
.def(py::init<T, T, T, T>(), "Constructor", py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = Math::Implementation::fullChannel<T>()) .def(py::init<T, T, T, T>(), "Constructor", py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = Math::Implementation::fullChannel<T>())
.def(py::init<T, T>(), "Construct with one value for all components", py::arg("rgb"), py::arg("alpha") = Math::Implementation::fullChannel<T>()) .def(py::init<T, T>(), "Construct with one value for all components", py::arg("rgb"), py::arg("alpha") = Math::Implementation::fullChannel<T>())
.def(py::init<Math::Color3<T>, T>(), "Construct from a vector", py::arg("rgb"), py::arg("alpha") = Math::Implementation::fullChannel<T>())
.def(py::init<Math::Vector4<T>>(), "Construct from a vector")
.def(py::init([](const std::tuple<T, T, T>& value) { .def(py::init([](const std::tuple<T, T, T>& value) {
return Math::Color4<T>{std::get<0>(value), std::get<1>(value), std::get<2>(value)}; return Math::Color4<T>{std::get<0>(value), std::get<1>(value), std::get<2>(value)};
}), "Construct from a RGB tuple") }), "Construct from a RGB tuple")

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

@ -86,28 +86,21 @@ void mathVectorFloat(py::module& root, py::module& m) {
py::class_<Vector2d> vector2d{root, "Vector2d", "Two-component double vector", py::buffer_protocol{}}; py::class_<Vector2d> vector2d{root, "Vector2d", "Two-component double vector", py::buffer_protocol{}};
py::class_<Vector3d> vector3d{root, "Vector3d", "Threee-component double vector", py::buffer_protocol{}}; py::class_<Vector3d> vector3d{root, "Vector3d", "Threee-component double vector", py::buffer_protocol{}};
py::class_<Vector4d> vector4d{root, "Vector4d", "Four-component double vector", py::buffer_protocol{}}; py::class_<Vector4d> vector4d{root, "Vector4d", "Four-component double vector", py::buffer_protocol{}};
vectorsFloat<Float>(m, vector2, vector3, vector4);
vectorsFloat<Double>(m, vector2d, vector3d, vector4d);
/* The subclasses don't have buffer protocol enabled, as that's already /* The subclasses don't have buffer protocol enabled, as that's already
done by the base classes. Moreover, just adding py::buffer_protocol{} done by the base classes. Moreover, just adding py::buffer_protocol{}
would cause it to not find the buffer functions as we don't add them would cause it to not find the buffer functions as we don't add them
anywhere, thus failing with `pybind11_getbuffer(): Internal error`. */ anywhere, thus failing with `pybind11_getbuffer(): Internal error`. */
py::class_<Color3, Vector3> color3_{root, "Color3", "Color in linear RGB color space"}; py::class_<Color3, Vector3> color3_{root, "Color3", "Color in linear RGB color space"};
everyVector(color3_);
color(color3_);
color3(color3_);
py::class_<Color4, Vector4> color4_{root, "Color4", "Color in linear RGBA color space"}; py::class_<Color4, Vector4> color4_{root, "Color4", "Color in linear RGBA color space"};
everyVector(color4_);
color(color4_);
color4(color4_);
/* Register the integer types as well, only after that register type /* Register the integer types first, only after that register type
conversions because they need all the types */ conversions because they need all the types */
mathVectorIntegral(root, m); mathVectorIntegral(root, m);
/* Register type conversions as soon as possible as those should have a
priority over buffer and list constructors. These need all the types to
be present, so can't be interwinted with the class definitions above. */
convertible(vector2); convertible(vector2);
convertible(vector3); convertible(vector3);
convertible(vector4); convertible(vector4);
@ -116,17 +109,34 @@ void mathVectorFloat(py::module& root, py::module& m) {
convertible(vector4d); convertible(vector4d);
/* Colors are float-only at the moment, thus no conversions */ /* Colors are float-only at the moment, thus no conversions */
/* This needs to be before buffer constructors otherwise a buffer
constructor gets picked and it will fail because there are just 3
elements */
color4from3(color4_);
/* This needs to be *after* conversion constructors so the type conversion /* This needs to be *after* conversion constructors so the type conversion
gets picked before the general buffer constructor (which would then gets picked before the general buffer constructor (which would then
fail) */ fail). On the other hand, this needs to be before generic from-list
vectorBuffer(vector2); constructors because buffer protocol is generally faster than
vectorBuffer(vector3); iteration. */
vectorBuffer(vector4); everyVectorBuffer(vector2);
vectorBuffer(vector2d); everyVectorBuffer(vector3);
vectorBuffer(vector3d); everyVectorBuffer(vector4);
vectorBuffer(vector4d); everyVectorBuffer(vector2d);
vectorBuffer(color3_); everyVectorBuffer(vector3d);
vectorBuffer(color4_); everyVectorBuffer(vector4d);
everyVectorBuffer(color3_);
everyVectorBuffer(color4_);
/* Now register the generic from-list constructors and everything else */
vectorsFloat<Float>(m, vector2, vector3, vector4);
vectorsFloat<Double>(m, vector2d, vector3d, vector4d);
everyVector(color3_);
color(color3_);
color3(color3_);
everyVector(color4_);
color(color4_);
color4(color4_);
} }
} }

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

@ -79,11 +79,9 @@ void mathVectorIntegral(py::module& root, py::module& m) {
py::class_<Vector2ui> vector2ui{root, "Vector2ui", "Two-component unsigned integral vector", py::buffer_protocol{}}; py::class_<Vector2ui> vector2ui{root, "Vector2ui", "Two-component unsigned integral vector", py::buffer_protocol{}};
py::class_<Vector3ui> vector3ui{root, "Vector3ui", "Threee-component unsigned integral vector", py::buffer_protocol{}}; py::class_<Vector3ui> vector3ui{root, "Vector3ui", "Threee-component unsigned integral vector", py::buffer_protocol{}};
py::class_<Vector4ui> vector4ui{root, "Vector4ui", "Four-component unsigned integral vector", py::buffer_protocol{}}; py::class_<Vector4ui> vector4ui{root, "Vector4ui", "Four-component unsigned integral vector", py::buffer_protocol{}};
vectorsIntegral<Int>(m, vector2i, vector3i, vector4i);
vectorsIntegral<UnsignedInt>(m, vector2ui, vector3ui, vector4ui);
/* At this point we should have both float and integral types registered, /* First register type conversions as those should have a priority over
so register type conversions */ buffer and list constructors. */
convertible(vector2i); convertible(vector2i);
convertible(vector3i); convertible(vector3i);
convertible(vector4i); convertible(vector4i);
@ -93,13 +91,19 @@ void mathVectorIntegral(py::module& root, py::module& m) {
/* This needs to be *after* conversion constructors so the type conversion /* This needs to be *after* conversion constructors so the type conversion
gets picked before the general buffer constructor (which would then gets picked before the general buffer constructor (which would then
fail) */ fail). On the other hand, this needs to be before generic from-list
vectorBuffer(vector2i); constructors because buffer protocol is generally faster than
vectorBuffer(vector3i); iteration. */
vectorBuffer(vector4i); everyVectorBuffer(vector2i);
vectorBuffer(vector2ui); everyVectorBuffer(vector3i);
vectorBuffer(vector3ui); everyVectorBuffer(vector4i);
vectorBuffer(vector4ui); everyVectorBuffer(vector2ui);
everyVectorBuffer(vector3ui);
everyVectorBuffer(vector4ui);
/* Now register the generic from-list constructors and everything else */
vectorsIntegral<Int>(m, vector2i, vector3i, vector4i);
vectorsIntegral<UnsignedInt>(m, vector2ui, vector3ui, vector4ui);
} }
} }

Loading…
Cancel
Save