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<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
layouts. Has to be defined *before* the from-tuple constructor so it
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)};
return out;
}), "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");
}), "Construct from a buffer");
}
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{}
would cause it to not find the buffer functions as we don't add them
anywhere, thus failing with `pybind11_getbuffer(): Internal error`. */
py::class_<Matrix3d, Matrix3x3d> matrix3d{root, "Matrix3d", "2D double transformation matrix"};
py::class_<Matrix4d, Matrix4x4d> matrix4d{root, "Matrix4d", "3D double transformation matrix"};
matrices<Double>(
matrix2x2d, matrix2x3d, matrix2x4d,
matrix3x2d, matrix3x3d, matrix3x4d,
matrix4x2d, matrix4x3d, matrix4x4d,
matrix3d, matrix4d);
/* At this point we should have both float and double types registered,
so register type conversions */
/* 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<Matrix2x2>(matrix2x2d);
convertible<Matrix2x3>(matrix2x3d);
convertible<Matrix2x4>(matrix2x4d);
@ -65,9 +59,33 @@ void mathMatrixDouble(py::module& root) {
convertible<Matrix4x2>(matrix4x2d);
convertible<Matrix4x3>(matrix4x3d);
convertible<Matrix4x4>(matrix4x4d);
convertible<Matrix3>(matrix3d);
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{}
would cause it to not find the buffer functions as we don't add them
anywhere, thus failing with `pybind11_getbuffer(): Internal error`. */
py::class_<Matrix3, Matrix3x3> matrix3{root, "Matrix3", "2D 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
conversions because they need all the types */
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<Matrix2x3d>(matrix2x3);
convertible<Matrix2x4d>(matrix2x4);
@ -67,9 +63,32 @@ void mathMatrixFloat(py::module& root) {
convertible<Matrix4x2d>(matrix4x2);
convertible<Matrix4x3d>(matrix4x3);
convertible<Matrix4x4d>(matrix4x4);
convertible<Matrix3d>(matrix3);
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
constructors */
template<class T, class ...Args> void vectorBuffer(py::class_<T, Args...>& c) {
constructors. Needs to be called also for subclasses. */
template<class T, class ...Args> void everyVectorBuffer(py::class_<T, Args...>& c) {
c
/* Buffer protocol. If not present, implicit conversion from numpy
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");
}
/* 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) {
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 Math::Color3<T>&, Math::Color4<T>>();
c
/* 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>(), "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) {
return Math::Color4<T>{std::get<0>(value), std::get<1>(value), std::get<2>(value)};
}), "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_<Vector3d> vector3d{root, "Vector3d", "Threee-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
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
anywhere, thus failing with `pybind11_getbuffer(): Internal error`. */
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"};
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 */
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(vector3);
convertible(vector4);
@ -116,17 +109,34 @@ void mathVectorFloat(py::module& root, py::module& m) {
convertible(vector4d);
/* 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
gets picked before the general buffer constructor (which would then
fail) */
vectorBuffer(vector2);
vectorBuffer(vector3);
vectorBuffer(vector4);
vectorBuffer(vector2d);
vectorBuffer(vector3d);
vectorBuffer(vector4d);
vectorBuffer(color3_);
vectorBuffer(color4_);
fail). On the other hand, this needs to be before generic from-list
constructors because buffer protocol is generally faster than
iteration. */
everyVectorBuffer(vector2);
everyVectorBuffer(vector3);
everyVectorBuffer(vector4);
everyVectorBuffer(vector2d);
everyVectorBuffer(vector3d);
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_<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{}};
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 */
/* First register type conversions as those should have a priority over
buffer and list constructors. */
convertible(vector2i);
convertible(vector3i);
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
gets picked before the general buffer constructor (which would then
fail) */
vectorBuffer(vector2i);
vectorBuffer(vector3i);
vectorBuffer(vector4i);
vectorBuffer(vector2ui);
vectorBuffer(vector3ui);
vectorBuffer(vector4ui);
fail). On the other hand, this needs to be before generic from-list
constructors because buffer protocol is generally faster than
iteration. */
everyVectorBuffer(vector2i);
everyVectorBuffer(vector3i);
everyVectorBuffer(vector4i);
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