Browse Source

Math: remove remaining uses of std::pair.

Using Containers::Pair allows me to make certain Range APIs constexpr
that weren't possible in C++11 before. Compared to std::pair it's also
trivially copyable, which is a nice property when storing it in various
growable containers.

As usual, the <Corrade/Containers/PairStl.h> include is in place to help
people with porting, although in many cases this change will be
breaking. I had to do it at some point anyway, so the earlier it is the
better.
pull/168/head
Vladimír Vondruš 3 years ago
parent
commit
04419335d4
  1. 2
      doc/changelog.dox
  2. 10
      doc/snippets/MagnumMath.cpp
  3. 4
      src/Magnum/DebugTools/CompareImage.cpp
  4. 9
      src/Magnum/Math/Algorithms/Qr.h
  5. 22
      src/Magnum/Math/Algorithms/Test/QrTest.cpp
  6. 7
      src/Magnum/Math/Bezier.h
  7. 14
      src/Magnum/Math/Dual.h
  8. 8
      src/Magnum/Math/DualQuaternion.h
  9. 30
      src/Magnum/Math/Functions.h
  10. 45
      src/Magnum/Math/FunctionsBatch.h
  11. 11
      src/Magnum/Math/Intersection.h
  12. 26
      src/Magnum/Math/Range.h
  13. 50
      src/Magnum/Math/Test/BezierTest.cpp
  14. 12
      src/Magnum/Math/Test/DualTest.cpp
  15. 50
      src/Magnum/Math/Test/FunctionsBatchTest.cpp
  16. 4
      src/Magnum/Math/Test/FunctionsBenchmark.cpp
  17. 36
      src/Magnum/Math/Test/FunctionsTest.cpp
  18. 12
      src/Magnum/Math/Test/IntersectionTest.cpp
  19. 21
      src/Magnum/Math/Test/RangeTest.cpp
  20. 10
      src/Magnum/Math/Test/VectorTest.cpp
  21. 11
      src/Magnum/Math/Vector.h
  22. 2
      src/Magnum/MeshTools/CompressIndices.cpp
  23. 12
      src/Magnum/Primitives/Capsule.cpp
  24. 16
      src/Magnum/Primitives/Circle.cpp
  25. 30
      src/Magnum/Primitives/Implementation/Spheroid.cpp
  26. 24
      src/Magnum/Primitives/Implementation/WireframeSpheroid.cpp

2
doc/changelog.dox

@ -1469,6 +1469,8 @@ See also:
- @ref Vk::DescriptorPoolCreateInfo and @ref Vk::AttachmentDescription
APIs now take a @relativeref{Corrade,Containers::Pair} instead of a
@ref std::pair
- All @ref Math APIs that took or returned @ref std::pair now use
@relativeref{Corrade,Containers::Pair} instead
To handle most backwards compatibility, @ref Corrade/Containers/StringStl.h
and/or @ref Corrade/Containers/PairStl.h is included in affected headers
for implicit conversions from/to a @ref std::string and/or @ref std::pair,

10
doc/snippets/MagnumMath.cpp

@ -337,9 +337,9 @@ mat = Matrix3x2::fromVector(vec);
{
Deg value;
/* [matrix-vector-operations-functions-scalar] */
std::pair<Int, Int> minmax = Math::minmax(24, -5); // -5, 24
Int a = Math::lerp(0, 360, 0.75f); // 270
auto b = Math::pack<UnsignedByte>(0.89f); // 226
Containers::Pair<Int, Int> minmax = Math::minmax(24, -5); // -5, 24
Int a = Math::lerp(0, 360, 0.75f); // 270
auto b = Math::pack<UnsignedByte>(0.89f); // 226
Deg c = Math::clamp(value, 25.0_degf, 55.0_degf);
/* [matrix-vector-operations-functions-scalar] */
@ -987,9 +987,9 @@ return true;
{
/* [div] */
Int quotient, remainder;
std::tie(quotient, remainder) = Math::div(57, 6); // {9, 3}
Containers::Pair<Int, Int> quotientRemainder = Math::div(57, 6); // {9, 3}
/* [div] */
static_cast<void>(quotientRemainder);
}
{

4
src/Magnum/DebugTools/CompareImage.cpp

@ -409,8 +409,8 @@ void printPixelDeltas(Debug& out, Containers::ArrayView<const Float> delta, Pixe
for(auto it = large.crbegin(); it != large.crend(); ++it) {
if(++count > maxCount) break;
Vector2i pos;
std::tie(pos.y(), pos.x()) = Math::div(Int(it->second), Int(expectedPixels.size()[1]));
const Containers::Pair<Int, Int> div = Math::div(Int(it->second), Int(expectedPixels.size()[1]));
const Vector2i pos{div.second(), div.first()};
out << Debug::newline << " [" << Debug::nospace << pos.x()
<< Debug::nospace << "," << Debug::nospace << pos.y()
<< Debug::nospace << "]";

9
src/Magnum/Math/Algorithms/Qr.h

@ -29,8 +29,15 @@
* @brief Function @ref Magnum::Math::Algorithms::qr()
*/
#include <Corrade/Containers/Pair.h>
#include "Magnum/Math/Algorithms/GramSchmidt.h"
#ifdef MAGNUM_BUILD_DEPRECATED
/* Some APIs returned std::pair before */
#include <Corrade/Containers/PairStl.h>
#endif
namespace Magnum { namespace Math { namespace Algorithms {
/**
@ -60,7 +67,7 @@ See the [associated test case](https://github.com/mosra/magnum/blob/master/src/M
for an example.
@see @ref svd(), @ref Matrix3::rotationShear(), @ref Matrix4::rotationShear()
*/
template<std::size_t size, class T> std::pair<Matrix<size, T>, Matrix<size, T>> qr(const Matrix<size, T>& matrix) {
template<std::size_t size, class T> Containers::Pair<Matrix<size, T>, Matrix<size, T>> qr(const Matrix<size, T>& matrix) {
const Matrix<size, T> q = gramSchmidtOrthonormalize(matrix);
Matrix<size, T> r{ZeroInit};
for(std::size_t k = 0; k != size; ++k) {

22
src/Magnum/Math/Algorithms/Test/QrTest.cpp

@ -56,27 +56,27 @@ void QrTest::test() {
Vector3{-20.0f, 27.0f, 11.0f},
Vector3{-14.0f, -4.0f, -2.0f}};
std::pair<Matrix3x3, Matrix3x3> qr = Algorithms::qr(a);
Containers::Pair<Matrix3x3, Matrix3x3> qr = Algorithms::qr(a);
auto qExpected = Matrix3x3{Vector3{ 0.0f, 15.0f, 20.0f},
Vector3{-20.0f, 12.0f, -9.0f},
Vector3{-15.0f, -16.0f, 12.0f}}/25.0f;
CORRADE_COMPARE(qr.first, qExpected);
CORRADE_COMPARE(qr.first(), qExpected);
Matrix3x3 rExpected{Vector3{ 5.0f, 0.0f, 0.0f},
Vector3{25.0f, 25.0f, 0.0f},
Vector3{-4.0f, 10.0f, 10.0f}};
CORRADE_COMPARE(qr.second, rExpected);
CORRADE_COMPARE(qr.second(), rExpected);
}
void QrTest::decomposeRotationScaling() {
Matrix4 a = Matrix4::rotationZ(35.0_degf)*Matrix4::scaling({1.5f, 2.0f, 1.0f});
std::pair<Matrix3x3, Matrix3x3> qr = Algorithms::qr(a.rotationScaling());
CORRADE_COMPARE(qr.first*qr.second, a.rotationScaling());
Containers::Pair<Matrix3x3, Matrix3x3> qr = Algorithms::qr(a.rotationScaling());
CORRADE_COMPARE(qr.first()*qr.second(), a.rotationScaling());
auto q4 = Matrix4::from(qr.first, {});
auto r4 = Matrix4::from(qr.second, {});
auto q4 = Matrix4::from(qr.first(), {});
auto r4 = Matrix4::from(qr.second(), {});
CORRADE_COMPARE(q4, Matrix4::rotationZ(35.0_degf));
CORRADE_COMPARE(r4, Matrix4::scaling({1.5f, 2.0f, 1.0f}));
@ -86,11 +86,11 @@ void QrTest::decomposeRotationShear() {
/* Like above, but with order flipped, which results in a shear */
Matrix4 a = Matrix4::scaling({1.5f, 2.0f, 1.0f})*Matrix4::rotationZ(35.0_degf);
std::pair<Matrix3x3, Matrix3x3> qr = Algorithms::qr(a.rotationScaling());
CORRADE_COMPARE(qr.first*qr.second, a.rotationScaling());
Containers::Pair<Matrix3x3, Matrix3x3> qr = Algorithms::qr(a.rotationScaling());
CORRADE_COMPARE(qr.first()*qr.second(), a.rotationScaling());
auto q4 = Matrix4::from(qr.first, {});
auto r4 = Matrix4::from(qr.second, {});
auto q4 = Matrix4::from(qr.first(), {});
auto r4 = Matrix4::from(qr.second(), {});
CORRADE_COMPARE(q4, Matrix4::rotationZ(43.03357_degf));
CORRADE_COMPARE(r4.scaling(), (Vector3{1.68099f, 1.85048f, 1.0f}));

7
src/Magnum/Math/Bezier.h

@ -32,6 +32,11 @@
#include "Magnum/Math/Vector.h"
#ifdef MAGNUM_BUILD_DEPRECATED
/* Some APIs returned std::pair before */
#include <Corrade/Containers/PairStl.h>
#endif
namespace Magnum { namespace Math {
namespace Implementation {
@ -194,7 +199,7 @@ template<UnsignedInt order, UnsignedInt dimensions, class T> class Bezier {
* given interpolation factor. Uses the [De Casteljau's algorithm](https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm).
* @see @ref value()
*/
std::pair<Bezier<order, dimensions, T>, Bezier<order, dimensions, T>> subdivide(T t) const {
Containers::Pair<Bezier<order, dimensions, T>, Bezier<order, dimensions, T>> subdivide(T t) const {
Bezier<order, dimensions, T> iPoints[order + 1];
calculateIntermediatePoints(iPoints, t);
Bezier<order, dimensions, T> left, right;

14
src/Magnum/Math/Dual.h

@ -29,6 +29,7 @@
* @brief Class @ref Magnum::Math::Dual
*/
#include <Corrade/Containers/Pair.h>
#ifndef CORRADE_SINGLES_NO_DEBUG
#include <Corrade/Utility/Debug.h>
#endif
@ -39,6 +40,11 @@
#include "Magnum/Math/Tags.h"
#include "Magnum/Math/TypeTraits.h"
#ifdef MAGNUM_BUILD_DEPRECATED
/* Some APIs returned std::pair before */
#include <Corrade/Containers/PairStl.h>
#endif
namespace Magnum { namespace Math {
namespace Implementation {
@ -409,7 +415,7 @@ template<class T> Dual<T> sqrt(const Dual<T>& dual) {
*/
/* The function accepts Unit instead of Rad to make it working with operator
products (e.g. 2*35.0_degf, which is of type Unit) */
template<class T> std::pair<Dual<T>, Dual<T>> sincos(const Dual<Rad<T>>& angle)
template<class T> Containers::Pair<Dual<T>, Dual<T>> sincos(const Dual<Rad<T>>& angle)
{
/* Not using Math::sincos(), because I don't want to include Functions.h */
const T sin = std::sin(T(angle.real()));
@ -417,9 +423,9 @@ template<class T> std::pair<Dual<T>, Dual<T>> sincos(const Dual<Rad<T>>& angle)
return {{sin, T(angle.dual())*cos}, {cos, -T(angle.dual())*sin}};
}
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class T> std::pair<Dual<T>, Dual<T>> sincos(const Dual<Deg<T>>& angle) { return sincos(Dual<Rad<T>>(angle)); }
template<class T> std::pair<Dual<T>, Dual<T>> sincos(const Dual<Unit<Rad, T>>& angle) { return sincos(Dual<Rad<T>>(angle)); }
template<class T> std::pair<Dual<T>, Dual<T>> sincos(const Dual<Unit<Deg, T>>& angle) { return sincos(Dual<Rad<T>>(angle)); }
template<class T> Containers::Pair<Dual<T>, Dual<T>> sincos(const Dual<Deg<T>>& angle) { return sincos(Dual<Rad<T>>(angle)); }
template<class T> Containers::Pair<Dual<T>, Dual<T>> sincos(const Dual<Unit<Rad, T>>& angle) { return sincos(Dual<Rad<T>>(angle)); }
template<class T> Containers::Pair<Dual<T>, Dual<T>> sincos(const Dual<Unit<Deg, T>>& angle) { return sincos(Dual<Rad<T>>(angle)); }
#endif
#ifndef MAGNUM_NO_MATH_STRICT_WEAK_ORDERING

8
src/Magnum/Math/DualQuaternion.h

@ -104,8 +104,8 @@ template<class T> inline DualQuaternion<T> sclerp(const DualQuaternion<T>& norma
const Dual<Vector3<T>> n{direction, moment};
/* q_ScLERP = q_A*(cos(t*a/2) + n*sin(t*a/2)) */
const std::pair<Dual<T>, Dual<T>> sincos = Math::sincos(t*Dual<Rad<T>>(aHalf));
return normalizedA*DualQuaternion<T>{n*sincos.first, sincos.second};
const Containers::Pair<Dual<T>, Dual<T>> sincos = Math::sincos(t*Dual<Rad<T>>(aHalf));
return normalizedA*DualQuaternion<T>{n*sincos.first(), sincos.second()};
}
/** @relatesalso DualQuaternion
@ -170,8 +170,8 @@ template<class T> inline DualQuaternion<T> sclerpShortestPath(const DualQuaterni
const Dual<Vector3<T>> n{direction, moment};
/* q_ScLERP = q_A*(cos(t*a/2) + n*sin(t*a/2)) */
const std::pair<Dual<T>, Dual<T>> sincos = Math::sincos(t*Dual<Rad<T>>(aHalf));
return normalizedA*DualQuaternion<T>{n*sincos.first, sincos.second};
const Containers::Pair<Dual<T>, Dual<T>> sincos = Math::sincos(t*Dual<Rad<T>>(aHalf));
return normalizedA*DualQuaternion<T>{n*sincos.first(), sincos.second()};
}
/**

30
src/Magnum/Math/Functions.h

@ -34,13 +34,17 @@
#include <cstdlib> /* std::div() */
#include <type_traits>
#include <utility> /* std::pair */
#include <Corrade/Utility/Move.h>
#include <Corrade/Utility/StlMath.h>
#include "Magnum/visibility.h"
#include "Magnum/Math/Vector.h"
#ifdef MAGNUM_BUILD_DEPRECATED
/* Some APIs returned std::pair before */
#include <Corrade/Containers/PairStl.h>
#endif
namespace Magnum { namespace Math {
namespace Implementation {
@ -73,7 +77,7 @@ Equivalent to the following, but possibly done in a single CPU instruction:
@snippet MagnumMath.cpp div-equivalent
*/
template<class Integral> inline std::pair<Integral, Integral> div(Integral x, Integral y) {
template<class Integral> inline Containers::Pair<Integral, Integral> div(Integral x, Integral y) {
static_assert(IsIntegral<Integral>::value && IsScalar<Integral>::value,
"scalar integral type expected");
const auto result = std::div(x, y);
@ -193,18 +197,18 @@ instruction as well.
@see @ref sin(), @ref cos(), @ref sincos(const Dual<Rad<T>>&)
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class T> inline std::pair<T, T> sincos(Rad<T> angle);
template<class T> inline Containers::Pair<T, T> sincos(Rad<T> angle);
#else
template<class T> inline std::pair<T, T> sincos(Unit<Rad, T> angle) {
template<class T> inline Containers::Pair<T, T> sincos(Unit<Rad, T> angle) {
#if defined(CORRADE_TARGET_GCC) && !defined(CORRADE_TARGET_CLANG)
std::pair<T, T> out;
Implementation::sincos(T(angle), out.first, out.second);
Containers::Pair<T, T> out{Magnum::NoInit};
Implementation::sincos(T(angle), out.first(), out.second());
return out;
#else
return {std::sin(T(angle)), std::cos(T(angle))};
#endif
}
template<class T> inline std::pair<T, T> sincos(Unit<Deg, T> angle) { return sincos(Rad<T>(angle)); }
template<class T> inline Containers::Pair<T, T> sincos(Unit<Deg, T> angle) { return sincos(Rad<T>(angle)); }
#endif
/** @brief Tangent */
@ -343,18 +347,18 @@ template<std::size_t size, class T> inline Vector<size, T> max(const Vector<size
@see @ref min(), @ref max(), @ref clamp(),
@ref minmax(const Containers::StridedArrayView1D<const T>&),
@ref Vector::minmax(),
@ref Range::Range(const std::pair<VectorType, VectorType>&)
@ref Range::Range(const Containers::Pair<VectorType, VectorType>&)
*/
template<class T> inline typename std::enable_if<IsScalar<T>::value, std::pair<T, T>>::type minmax(T a, T b) {
return a < b ? std::make_pair(a, b) : std::make_pair(b, a);
template<class T> inline typename std::enable_if<IsScalar<T>::value, Containers::Pair<T, T>>::type minmax(T a, T b) {
return a < b ? Containers::pair(a, b) : Containers::pair(b, a);
}
/** @overload */
template<std::size_t size, class T> inline std::pair<Vector<size, T>, Vector<size, T>> minmax(const Vector<size, T>& a, const Vector<size, T>& b) {
template<std::size_t size, class T> inline Containers::Pair<Vector<size, T>, Vector<size, T>> minmax(const Vector<size, T>& a, const Vector<size, T>& b) {
using Utility::swap;
std::pair<Vector<size, T>, Vector<size, T>> out{a, b};
Containers::Pair<Vector<size, T>, Vector<size, T>> out{a, b};
for(std::size_t i = 0; i != size; ++i)
if(out.first[i] > out.second[i]) swap(out.first[i], out.second[i]);
if(out.first()[i] > out.second()[i]) swap(out.first()[i], out.second()[i]);
return out;
}

45
src/Magnum/Math/FunctionsBatch.h

@ -34,6 +34,11 @@
#include "Magnum/Math/Functions.h"
#ifdef MAGNUM_BUILD_DEPRECATED
/* Some APIs returned std::pair before */
#include <Corrade/Containers/PairStl.h>
#endif
namespace Magnum { namespace Math {
namespace Implementation {
@ -160,11 +165,11 @@ template<class T, std::size_t size> inline auto isNan(const T(&array)[size]) ->
namespace Implementation {
/* Non-floating-point types, the first is a non-NaN for sure */
template<class T, bool any> constexpr std::pair<std::size_t, T> firstNonNan(Containers::StridedArrayView1D<const T> range, std::false_type, std::integral_constant<bool, any>) {
template<class T, bool any> constexpr Containers::Pair<std::size_t, T> firstNonNan(Containers::StridedArrayView1D<const T> range, std::false_type, std::integral_constant<bool, any>) {
return {0, range.front()};
}
/* Floating-point scalars, return the first that's not NaN */
template<class T> inline std::pair<std::size_t, T> firstNonNan(Containers::StridedArrayView1D<const T> range, std::true_type, std::false_type) {
template<class T> inline Containers::Pair<std::size_t, T> firstNonNan(Containers::StridedArrayView1D<const T> range, std::true_type, std::false_type) {
/* Find the first non-NaN value to compare against. If all are NaN,
return the last value so the following loop in min/max/minmax()
doesn't even execute. */
@ -179,7 +184,7 @@ namespace Implementation {
apply the min/max/minmax operation. I expect the cases of heavily
NaN-filled vectors (and thus the need to loop twice through most of the
range) to be very rare, so this shouldn't be a problem. */
template<class T> inline std::pair<std::size_t, T> firstNonNan(Containers::StridedArrayView1D<const T> range, std::true_type, std::true_type) {
template<class T> inline Containers::Pair<std::size_t, T> firstNonNan(Containers::StridedArrayView1D<const T> range, std::true_type, std::true_type) {
T out = range[0];
std::size_t firstValid = 0;
for(std::size_t i = 1; i != range.size(); ++i) {
@ -202,11 +207,11 @@ ignored, unless the range is all <em>NaN</em>s.
template<class T> inline T min(const Containers::StridedArrayView1D<const T>& range) {
if(range.isEmpty()) return {};
std::pair<std::size_t, T> iOut = Implementation::firstNonNan(range, IsFloatingPoint<T>{}, IsVector<T>{});
for(++iOut.first; iOut.first != range.size(); ++iOut.first)
iOut.second = Math::min(iOut.second, range[iOut.first]);
Containers::Pair<std::size_t, T> iOut = Implementation::firstNonNan(range, IsFloatingPoint<T>{}, IsVector<T>{});
for(++iOut.first(); iOut.first() != range.size(); ++iOut.first())
iOut.second() = Math::min(iOut.second(), range[iOut.first()]);
return iOut.second;
return iOut.second();
}
/**
@ -247,11 +252,11 @@ ignored, unless the range is all <em>NaN</em>s.
template<class T> inline T max(const Containers::StridedArrayView1D<const T>& range) {
if(range.isEmpty()) return {};
std::pair<std::size_t, T> iOut = Implementation::firstNonNan(range, IsFloatingPoint<T>{}, IsVector<T>{});
for(++iOut.first; iOut.first != range.size(); ++iOut.first)
iOut.second = Math::max(iOut.second, range[iOut.first]);
Containers::Pair<std::size_t, T> iOut = Implementation::firstNonNan(range, IsFloatingPoint<T>{}, IsVector<T>{});
for(++iOut.first(); iOut.first() != range.size(); ++iOut.first())
iOut.second() = Math::max(iOut.second(), range[iOut.first()]);
return iOut.second;
return iOut.second();
}
/**
@ -301,16 +306,16 @@ namespace Implementation {
If the range is empty, returns default-constructed values. <em>NaN</em>s are
ignored, unless the range is all <em>NaN</em>s.
@see @ref minmax(T, T),
@ref Range::Range(const std::pair<VectorType, VectorType>&),
@ref Range::Range(const Containers::Pair<VectorType, VectorType>&),
@ref isNan(const Containers::StridedArrayView1D<const T>&)
*/
template<class T> inline std::pair<T, T> minmax(const Containers::StridedArrayView1D<const T>& range) {
template<class T> inline Containers::Pair<T, T> minmax(const Containers::StridedArrayView1D<const T>& range) {
if(range.isEmpty()) return {};
std::pair<std::size_t, T> iOut = Implementation::firstNonNan(range, IsFloatingPoint<T>{}, IsVector<T>{});
T min{iOut.second}, max{iOut.second};
for(++iOut.first; iOut.first != range.size(); ++iOut.first)
Implementation::minmax(min, max, range[iOut.first]);
Containers::Pair<std::size_t, T> iOut = Implementation::firstNonNan(range, IsFloatingPoint<T>{}, IsVector<T>{});
T min{iOut.second()}, max{iOut.second()};
for(++iOut.first(); iOut.first() != range.size(); ++iOut.first())
Implementation::minmax(min, max, range[iOut.first()]);
return {min, max};
}
@ -323,21 +328,21 @@ Converts @p range to @ref Containers::StridedArrayView1D and calls the above
overload. Works with any type that's convertible to
@relativeref{Corrade,Containers::StridedArrayView}.
*/
template<class Iterable, class T = decltype(Implementation::stridedArrayViewTypeFor(std::declval<Iterable&&>()))> inline std::pair<T, T> minmax(Iterable&& range) {
template<class Iterable, class T = decltype(Implementation::stridedArrayViewTypeFor(std::declval<Iterable&&>()))> inline Containers::Pair<T, T> minmax(Iterable&& range) {
/* Specifying the template explicitly to avoid recursion into the generic
function again */
return minmax<T>(Containers::StridedArrayView1D<const T>{range});
}
/** @overload */
template<class T> inline std::pair<T, T> minmax(std::initializer_list<T> list) {
template<class T> inline Containers::Pair<T, T> minmax(std::initializer_list<T> list) {
/* Specifying the template explicitly to avoid recursion into the generic
function again */
return minmax<T>(Containers::stridedArrayView(list));
}
/** @overload */
template<class T, std::size_t size> inline std::pair<T, T> minmax(const T(&array)[size]) {
template<class T, std::size_t size> inline Containers::Pair<T, T> minmax(const T(&array)[size]) {
/* Specifying the template explicitly to avoid recursion into the generic
function again */
return minmax<T>(Containers::StridedArrayView1D<const T>{array});

11
src/Magnum/Math/Intersection.h

@ -38,6 +38,11 @@
#include "Magnum/Math/Vector3.h"
#include "Magnum/Math/Matrix4.h"
#ifdef MAGNUM_BUILD_DEPRECATED
/* Some APIs returned std::pair before */
#include <Corrade/Containers/PairStl.h>
#endif
namespace Magnum { namespace Math { namespace Intersection {
/**
@ -130,7 +135,7 @@ don't need to test that the intersection lies inside line segment defined by
@see @ref isInf(), @ref isNan()
*/
template<class T> inline std::pair<T, T> lineSegmentLineSegment(const Vector2<T>& p, const Vector2<T>& r, const Vector2<T>& q, const Vector2<T>& s) {
template<class T> inline Containers::Pair<T, T> lineSegmentLineSegment(const Vector2<T>& p, const Vector2<T>& r, const Vector2<T>& q, const Vector2<T>& s) {
const Vector2<T> qp = q - p;
const T rs = cross(r, s);
return {cross(qp, s)/rs, cross(qp, r)/rs};
@ -508,9 +513,9 @@ template<class T> bool rangeFrustum(const Range3D<T>& range, const Frustum<T>& f
template<class T> bool rayRange(const Vector3<T>& rayOrigin, const Vector3<T>& inverseRayDirection, const Range3D<T>& range) {
const Vector3<T> t0 = (range.min() - rayOrigin)*inverseRayDirection;
const Vector3<T> t1 = (range.max() - rayOrigin)*inverseRayDirection;
const std::pair<Vector3<T>, Vector3<T>> tminMax = minmax(t0, t1);
const Containers::Pair<Vector3<T>, Vector3<T>> tminMax{minmax(t0, t1)};
return tminMax.first.max() <= tminMax.second.min();
return tminMax.first().max() <= tminMax.second().min();
}
template<class T> bool aabbFrustum(const Vector3<T>& aabbCenter, const Vector3<T>& aabbExtents, const Frustum<T>& frustum) {

26
src/Magnum/Math/Range.h

@ -32,6 +32,11 @@
#include "Magnum/Math/Functions.h"
#include "Magnum/Math/Vector3.h"
#ifdef MAGNUM_BUILD_DEPRECATED
/* Some APIs were taking a std::pair before */
#include <Corrade/Containers/PairStl.h>
#endif
namespace Magnum { namespace Math {
namespace Implementation {
@ -145,18 +150,15 @@ template<UnsignedInt dimensions, class T> class Range {
* calculate bounds of a triangle:
*
* @snippet MagnumMath.cpp Range-construct-minmax3D
*
* @todo std::pair constructors are not constexpr in C++11, make it so in C++14... actually, replace with Pair
*/
/*implicit*/ Range(const std::pair<VectorType, VectorType>& minmax) noexcept:
_min{minmax.first}, _max{minmax.second} {}
constexpr /*implicit*/ Range(const Containers::Pair<VectorType, VectorType>& minmax) noexcept:
_min{minmax.first()}, _max{minmax.second()} {}
/** @overload */
/** @todo std::pair constructors are not constexpr in C++11, make it so in C++14... actually, replace with Pair */
#ifndef DOXYGEN_GENERATING_OUTPUT
template<UnsignedInt d = dimensions, class = typename std::enable_if<d != 1>::type>
#endif
/*implicit*/ Range(const std::pair<Vector<dimensions, T>, Vector<dimensions, T>>& minmax) noexcept: _min{minmax.first}, _max{minmax.second} {}
constexpr /*implicit*/ Range(const Containers::Pair<Vector<dimensions, T>, Vector<dimensions, T>>& minmax) noexcept: _min{minmax.first()}, _max{minmax.second()} {}
/**
* @brief Construct range from another of different type
@ -419,16 +421,14 @@ template<class T> class Range2D: public Range<2, T> {
* calculate texture bounds:
*
* @snippet MagnumMath.cpp Range-construct-minmax2D
*
* @todo std::pair constructors are not constexpr in C++11, make it so in C++14... actually, replace with Pair
*/
/*implicit*/ Range2D(const std::pair<Vector2<T>, Vector2<T>>& minmax) noexcept: Range<2, T>{minmax.first, minmax.second} {}
constexpr /*implicit*/ Range2D(const Containers::Pair<Vector2<T>, Vector2<T>>& minmax) noexcept: Range<2, T>{minmax.first(), minmax.second()} {}
/**
* @overload
* @m_since{2020,06}
*/
/*implicit*/ Range2D(const std::pair<Vector<2, T>, Vector<2, T>>& minmax) noexcept: Range<2, T>{minmax.first, minmax.second} {}
constexpr /*implicit*/ Range2D(const Containers::Pair<Vector<2, T>, Vector<2, T>>& minmax) noexcept: Range<2, T>{minmax.first(), minmax.second()} {}
/** @copydoc Range(const Range<dimensions, U>&) */
template<class U> constexpr explicit Range2D(const Range2D<U>& other) noexcept: Range<2, T>(other) {}
@ -573,16 +573,14 @@ template<class T> class Range3D: public Range<3, T> {
* calculate bounds of a triangle:
*
* @snippet MagnumMath.cpp Range-construct-minmax3D
*
* @todo std::pair constructors are not constexpr in C++11, make it so in C++14... actually, replace with Pair
*/
/*implicit*/ Range3D(const std::pair<Vector3<T>, Vector3<T>>& minmax) noexcept: Range<3, T>{minmax.first, minmax.second} {}
constexpr /*implicit*/ Range3D(const Containers::Pair<Vector3<T>, Vector3<T>>& minmax) noexcept: Range<3, T>{minmax.first(), minmax.second()} {}
/**
* @overload
* @m_since{2020,06}
*/
/*implicit*/ Range3D(const std::pair<Vector<3, T>, Vector<3, T>>& minmax) noexcept: Range<3, T>{minmax.first, minmax.second} {}
constexpr /*implicit*/ Range3D(const Containers::Pair<Vector<3, T>, Vector<3, T>>& minmax) noexcept: Range<3, T>{minmax.first(), minmax.second()} {}
/** @copydoc Range(const Range<dimensions, U>&) */
template<class U> constexpr explicit Range3D(const Range3D<U>& other) noexcept: Range<3, T>(other) {}

50
src/Magnum/Math/Test/BezierTest.cpp

@ -289,43 +289,43 @@ void BezierTest::valueCubic() {
void BezierTest::subdivideLinear() {
LinearBezier2D bezier{Vector2{0.0f, 0.0f}, Vector2{20.0f, 4.0f}};
std::pair<LinearBezier2D, LinearBezier2D> subdivided = bezier.subdivide(0.25f);
CORRADE_COMPARE(subdivided.first[0], bezier[0]);
CORRADE_COMPARE(subdivided.first[1], subdivided.second[0]);
CORRADE_COMPARE(subdivided.second[1], bezier[1]);
CORRADE_COMPARE(subdivided.first.value(0.8f), bezier.value(0.2f));
CORRADE_COMPARE(subdivided.second.value(0.33333f), bezier.value(0.5f));
CORRADE_COMPARE(subdivided.first, (LinearBezier2D{Vector2{0.0f, 0.0f}, Vector2{5.0f, 1.0f}}));
CORRADE_COMPARE(subdivided.second, (LinearBezier2D{Vector2{5.0f, 1.0f}, Vector2{20.0f, 4.0f}}));
Containers::Pair<LinearBezier2D, LinearBezier2D> subdivided = bezier.subdivide(0.25f);
CORRADE_COMPARE(subdivided.first()[0], bezier[0]);
CORRADE_COMPARE(subdivided.first()[1], subdivided.second()[0]);
CORRADE_COMPARE(subdivided.second()[1], bezier[1]);
CORRADE_COMPARE(subdivided.first().value(0.8f), bezier.value(0.2f));
CORRADE_COMPARE(subdivided.second().value(0.33333f), bezier.value(0.5f));
CORRADE_COMPARE(subdivided.first(), (LinearBezier2D{Vector2{0.0f, 0.0f}, Vector2{5.0f, 1.0f}}));
CORRADE_COMPARE(subdivided.second(), (LinearBezier2D{Vector2{5.0f, 1.0f}, Vector2{20.0f, 4.0f}}));
}
void BezierTest::subdivideQuadratic() {
QuadraticBezier2D bezier{Vector2{0.0f, 0.0f}, Vector2{10.0f, 15.0f}, Vector2{20.0f, 4.0f}};
std::pair<QuadraticBezier2D, QuadraticBezier2D> subdivided = bezier.subdivide(0.25f);
Containers::Pair<QuadraticBezier2D, QuadraticBezier2D> subdivided = bezier.subdivide(0.25f);
CORRADE_COMPARE(subdivided.first[0], bezier[0]);
CORRADE_COMPARE(subdivided.first[2], subdivided.second[0]);
CORRADE_COMPARE(subdivided.second[2], bezier[2]);
CORRADE_COMPARE(subdivided.first.value(0.8f), bezier.value(0.2f));
CORRADE_COMPARE(subdivided.second.value(0.33333f), bezier.value(0.5f));
CORRADE_COMPARE(subdivided.first, (QuadraticBezier2D{Vector2{0.0f, 0.0f}, Vector2{2.5f, 3.75f}, Vector2{5.0f, 5.875f}}));
CORRADE_COMPARE(subdivided.second, (QuadraticBezier2D{Vector2{5.0f, 5.875f}, Vector2{12.5f, 12.25f}, Vector2{20.0f, 4.0f}}));
CORRADE_COMPARE(subdivided.first()[0], bezier[0]);
CORRADE_COMPARE(subdivided.first()[2], subdivided.second()[0]);
CORRADE_COMPARE(subdivided.second()[2], bezier[2]);
CORRADE_COMPARE(subdivided.first().value(0.8f), bezier.value(0.2f));
CORRADE_COMPARE(subdivided.second().value(0.33333f), bezier.value(0.5f));
CORRADE_COMPARE(subdivided.first(), (QuadraticBezier2D{Vector2{0.0f, 0.0f}, Vector2{2.5f, 3.75f}, Vector2{5.0f, 5.875f}}));
CORRADE_COMPARE(subdivided.second(), (QuadraticBezier2D{Vector2{5.0f, 5.875f}, Vector2{12.5f, 12.25f}, Vector2{20.0f, 4.0f}}));
}
void BezierTest::subdivideCubic() {
CubicBezier2D bezier{Vector2{0.0f, 0.0f}, Vector2{10.0f, 15.0f}, Vector2{20.0f, 4.0f}, Vector2{5.0f, -20.0f}};
std::pair<CubicBezier2D, CubicBezier2D> subdivided = bezier.subdivide(0.25f);
Containers::Pair<CubicBezier2D, CubicBezier2D> subdivided = bezier.subdivide(0.25f);
CORRADE_COMPARE(subdivided.first[0], bezier[0]);
CORRADE_COMPARE(subdivided.first[3], subdivided.second[0]);
CORRADE_COMPARE(subdivided.second[3], bezier[3]);
CORRADE_COMPARE(subdivided.first.value(0.8f), bezier.value(0.2f));
CORRADE_COMPARE(subdivided.second.value(0.33333f), bezier.value(0.5f));
CORRADE_COMPARE(subdivided.first, (CubicBezier2D{Vector2{0.0f, 0.0f}, Vector2{2.5f, 3.75f}, Vector2{5.0f, 5.875f}, Vector2{7.10938f, 6.57812f}}));
CORRADE_COMPARE(subdivided.second, (CubicBezier2D{Vector2{7.10938f, 6.57812f}, Vector2{13.4375f, 8.6875f}, Vector2{16.25f, -2.0f}, Vector2{5.0f, -20.0f}}));
CORRADE_COMPARE(subdivided.first()[0], bezier[0]);
CORRADE_COMPARE(subdivided.first()[3], subdivided.second()[0]);
CORRADE_COMPARE(subdivided.second()[3], bezier[3]);
CORRADE_COMPARE(subdivided.first().value(0.8f), bezier.value(0.2f));
CORRADE_COMPARE(subdivided.second().value(0.33333f), bezier.value(0.5f));
CORRADE_COMPARE(subdivided.first(), (CubicBezier2D{Vector2{0.0f, 0.0f}, Vector2{2.5f, 3.75f}, Vector2{5.0f, 5.875f}, Vector2{7.10938f, 6.57812f}}));
CORRADE_COMPARE(subdivided.second(), (CubicBezier2D{Vector2{7.10938f, 6.57812f}, Vector2{13.4375f, 8.6875f}, Vector2{16.25f, -2.0f}, Vector2{5.0f, -20.0f}}));
}
void BezierTest::strictWeakOrdering() {

12
src/Magnum/Math/Test/DualTest.cpp

@ -281,9 +281,9 @@ void DualTest::sqrt() {
}
void DualTest::sincos() {
const auto result = std::make_pair(
Dual(0.5f, 0.8660254037844386f*Constants::pi()/2),
Dual(0.8660254037844386f, -0.5f*Constants::pi()/2));
Containers::Pair<Dual, Dual> result{
{0.5f, 0.8660254037844386f*Constants::pi()/2},
{0.8660254037844386f, -0.5f*Constants::pi()/2}};
CORRADE_COMPARE(Math::sincos(Math::Dual<Deg>(30.0_degf, 90.0_degf)), result);
CORRADE_COMPARE(Math::sincos(Math::Dual<Rad>(Rad(Constants::pi()/6), Rad(Constants::pi()/2))), result);
}
@ -293,9 +293,9 @@ void DualTest::sincosWithBase() {
CORRADE_VERIFY(std::is_same<decltype(2*Math::Dual<Deg>{15.0_degf}), Math::Dual<Unit<Math::Deg, Float>>>::value);
CORRADE_VERIFY(std::is_same<decltype(2*Math::Dual<Rad>{Rad{Constants::pi()/12}}), Math::Dual<Unit<Math::Rad, Float>>>::value);
const auto result = std::make_pair(
Dual(0.5f, 0.8660254037844386f*Constants::pi()/2),
Dual(0.8660254037844386f, -0.5f*Constants::pi()/2));
Containers::Pair<Dual, Dual> result{
{0.5f, 0.8660254037844386f*Constants::pi()/2},
{0.8660254037844386f, -0.5f*Constants::pi()/2}};
CORRADE_COMPARE(Math::sincos(2*Math::Dual<Deg>(15.0_degf, 45.0_degf)), result);
CORRADE_COMPARE(Math::sincos(2*Math::Dual<Rad>(Rad(Constants::pi()/12), Rad(Constants::pi()/4))), result);
}

50
src/Magnum/Math/Test/FunctionsBatchTest.cpp

@ -176,7 +176,7 @@ void FunctionsBatchTest::max() {
}
void FunctionsBatchTest::minmax() {
const auto expected = std::make_pair(-3.0f, 2.0f);
Containers::Pair<Float, Float> expected{-3.0f, 2.0f};
CORRADE_COMPARE(Math::minmax({-1.0f, 2.0f, -3.0f}), expected);
CORRADE_COMPARE(Math::minmax({-1.0f, -3.0f, 2.0f}), expected);
CORRADE_COMPARE(Math::minmax({2.0f, -1.0f, -3.0f}), expected);
@ -184,7 +184,7 @@ void FunctionsBatchTest::minmax() {
CORRADE_COMPARE(Math::minmax({-3.0f, 2.0f, -1.0f}), expected);
CORRADE_COMPARE(Math::minmax({-3.0f, -1.0f, 2.0f}), expected);
const std::pair<Vector2, Vector2> expectedVec{Vector2{-3.0f, -2.0f}, Vector2{2.0f, 3.0f}};
Containers::Pair<Vector2, Vector2> expectedVec{{-3.0f, -2.0f}, {2.0f, 3.0f}};
CORRADE_COMPARE(Math::minmax({Vector2{-1.0f, 3.0f}, Vector2{2.0f, 1.0f}, Vector2{-3.0f, -2.0f}}), expectedVec);
CORRADE_COMPARE(Math::minmax({Vector2{-1.0f, 1.0f}, Vector2{-3.0f, 3.0f}, Vector2{2.0f, -2.0f}}), expectedVec);
CORRADE_COMPARE(Math::minmax({Vector2{2.0f, -2.0f}, Vector2{-1.0f, 1.0f}, Vector2{-3.0f, 3.0f}}), expectedVec);
@ -202,7 +202,7 @@ void FunctionsBatchTest::minmax() {
CORRADE_COMPARE(Math::minmax(std::vector<Float>{-1.0f, 2.0f, -3.0f}), expected);
/* Wrapped types */
CORRADE_COMPARE(Math::minmax({1.0_radf, 2.0_radf, 3.0_radf}), std::make_pair(1.0_radf, 3.0_radf));
CORRADE_COMPARE(Math::minmax({1.0_radf, 2.0_radf, 3.0_radf}), Containers::pair(1.0_radf, 3.0_radf));
}
void FunctionsBatchTest::nanIgnoring() {
@ -218,11 +218,11 @@ void FunctionsBatchTest::nanIgnoring() {
CORRADE_COMPARE(Math::max(firstNan), 1.0f);
CORRADE_COMPARE(Math::max(allNan), Constants::nan());
CORRADE_COMPARE(Math::minmax(oneNan), std::make_pair(-3.0f, 1.0f));
CORRADE_COMPARE(Math::minmax(firstNan), std::make_pair(-3.0f, 1.0f));
CORRADE_COMPARE(Math::minmax(oneNan), Containers::pair(-3.0f, 1.0f));
CORRADE_COMPARE(Math::minmax(firstNan), Containers::pair(-3.0f, 1.0f));
/* Need to compare this way because of NaNs */
CORRADE_COMPARE(Math::minmax(allNan).first, Constants::nan());
CORRADE_COMPARE(Math::minmax(allNan).second, Constants::nan());
CORRADE_COMPARE(Math::minmax(allNan).first(), Constants::nan());
CORRADE_COMPARE(Math::minmax(allNan).second(), Constants::nan());
}
void FunctionsBatchTest::nanIgnoringVector() {
@ -267,39 +267,39 @@ void FunctionsBatchTest::nanIgnoringVector() {
CORRADE_COMPARE(Math::max(allNan)[0], Constants::nan());
CORRADE_COMPARE(Math::max(allNan)[1], Constants::nan());
CORRADE_COMPARE(Math::minmax(oneNan), std::make_pair(
CORRADE_COMPARE(Math::minmax(oneNan), Containers::pair(
Vector2{0.4f, -3.0f}, Vector2{1.0f, 0.5f}));
CORRADE_COMPARE(Math::minmax(firstNan), std::make_pair(
CORRADE_COMPARE(Math::minmax(firstNan), Containers::pair(
Vector2{0.4f, -3.0f}, Vector2{2.2f, -1.0f}));
CORRADE_COMPARE(Math::minmax(nanEveryComponent), std::make_pair(
CORRADE_COMPARE(Math::minmax(nanEveryComponent), Containers::pair(
Vector2{0.4f, -3.0f}, Vector2{2.2f, -1.0f}));
/* Need to compare this way because of NaNs */
CORRADE_COMPARE(Math::minmax(oneComponentNan).first[0], Constants::nan());
CORRADE_COMPARE(Math::minmax(oneComponentNan).first[1], 0.3f);
CORRADE_COMPARE(Math::minmax(oneComponentNan).second[0], Constants::nan());
CORRADE_COMPARE(Math::minmax(oneComponentNan).second[1], 1.5f);
CORRADE_COMPARE(Math::minmax(firstFullNan).first[0], 0.3f);
CORRADE_COMPARE(Math::minmax(firstFullNan).first[1], Constants::nan());
CORRADE_COMPARE(Math::minmax(firstFullNan).second[0], 1.5f);
CORRADE_COMPARE(Math::minmax(firstFullNan).second[1], Constants::nan());
CORRADE_COMPARE(Math::minmax(allNan).first[0], Constants::nan());
CORRADE_COMPARE(Math::minmax(allNan).first[1], Constants::nan());
CORRADE_COMPARE(Math::minmax(allNan).second[0], Constants::nan());
CORRADE_COMPARE(Math::minmax(allNan).second[1], Constants::nan());
CORRADE_COMPARE(Math::minmax(oneComponentNan).first()[0], Constants::nan());
CORRADE_COMPARE(Math::minmax(oneComponentNan).first()[1], 0.3f);
CORRADE_COMPARE(Math::minmax(oneComponentNan).second()[0], Constants::nan());
CORRADE_COMPARE(Math::minmax(oneComponentNan).second()[1], 1.5f);
CORRADE_COMPARE(Math::minmax(firstFullNan).first()[0], 0.3f);
CORRADE_COMPARE(Math::minmax(firstFullNan).first()[1], Constants::nan());
CORRADE_COMPARE(Math::minmax(firstFullNan).second()[0], 1.5f);
CORRADE_COMPARE(Math::minmax(firstFullNan).second()[1], Constants::nan());
CORRADE_COMPARE(Math::minmax(allNan).first()[0], Constants::nan());
CORRADE_COMPARE(Math::minmax(allNan).first()[1], Constants::nan());
CORRADE_COMPARE(Math::minmax(allNan).second()[0], Constants::nan());
CORRADE_COMPARE(Math::minmax(allNan).second()[1], Constants::nan());
}
void FunctionsBatchTest::constIterable() {
const Vector2 data[]{{5, -3}, {-2, 14}, {9, -5}};
/* It shouldn't try to operate with a const type (such as trying to to
assign to `std::pair<std::size_t, const Vector2>`) internally, instead
it should remove the const */
assign to `Containers::Pair<std::size_t, const Vector2>`) internally,
instead it should remove the const */
CORRADE_COMPARE(Math::min(Containers::arrayView(data)),
(Vector2{-2, -5}));
CORRADE_COMPARE(Math::max(Containers::stridedArrayView(data)),
(Vector2{9, 14}));
CORRADE_COMPARE(Math::minmax(Containers::Array<const Vector2>{data, 3, [](const Vector2*, std::size_t){}}),
std::make_pair(Vector2{-2, -5}, Vector2{9, 14}));
Containers::pair(Vector2{-2, -5}, Vector2{9, 14}));
}
}}}}

4
src/Magnum/Math/Test/FunctionsBenchmark.cpp

@ -211,8 +211,8 @@ void FunctionsBenchmark::sinCosCombined() {
Float sin{}, cos{}, a{};
CORRADE_BENCHMARK(1000) {
auto sincos = Math::sincos(Rad(a));
sin += sincos.first;
cos += sincos.second;
sin += sincos.first();
cos += sincos.second();
a += 0.1f;
}

36
src/Magnum/Math/Test/FunctionsTest.cpp

@ -208,18 +208,18 @@ void FunctionsTest::max() {
}
void FunctionsTest::minmax() {
const auto expectedScalar = std::make_pair(-5.0f, 4.0f);
const auto expectedScalar = Containers::pair(-5.0f, 4.0f);
CORRADE_COMPARE(Math::minmax(-5.0f, 4.0f), expectedScalar);
CORRADE_COMPARE(Math::minmax(4.0f, -5.0f), expectedScalar);
const Vector3 a(5.0f, -4.0f, 1.0f);
const Vector3 b(7.0f, -3.0f, 1.0f);
const std::pair<Vector3, Vector3> expectedVector{{5.0f, -4.0f, 1.0f}, {7.0f, -3.0f, 1.0f}};
CORRADE_COMPARE_AS(Math::minmax(a, b), expectedVector, std::pair<Vector3, Vector3>);
CORRADE_COMPARE_AS(Math::minmax(b, a), expectedVector, std::pair<Vector3, Vector3>);
const Containers::Pair<Vector3, Vector3> expectedVector{{5.0f, -4.0f, 1.0f}, {7.0f, -3.0f, 1.0f}};
CORRADE_COMPARE((Containers::Pair<Vector3, Vector3>{Math::minmax(a, b)}), expectedVector);
CORRADE_COMPARE((Containers::Pair<Vector3, Vector3>{Math::minmax(b, a)}), expectedVector);
/* Wrapped types */
CORRADE_COMPARE(Math::minmax(4.0_degf, 5.0_degf), std::make_pair(4.0_degf, 5.0_degf));
CORRADE_COMPARE(Math::minmax(4.0_degf, 5.0_degf), Containers::pair(4.0_degf, 5.0_degf));
}
void FunctionsTest::clamp() {
@ -462,9 +462,9 @@ void FunctionsTest::exp() {
}
void FunctionsTest::div() {
std::pair<Int, Int> div = Math::div(57, 6);
CORRADE_COMPARE(div.first, 9);
CORRADE_COMPARE(div.second, 3);
Containers::Pair<Int, Int> div = Math::div(57, 6);
CORRADE_COMPARE(div.first(), 9);
CORRADE_COMPARE(div.second(), 3);
}
void FunctionsTest::isInf() {
@ -558,10 +558,10 @@ void FunctionsTest::trigonometric() {
CORRADE_COMPARE(Math::cos(Rad(Constants::pi()/3)), 0.5f);
CORRADE_COMPARE_AS(Math::acos(0.5f), 60.0_degf, Deg);
CORRADE_COMPARE(Math::sincos(30.0_degf).first, 0.5f);
CORRADE_COMPARE(Math::sincos(30.0_degf).second, 0.8660254037844386f);
CORRADE_COMPARE(Math::sincos(Rad(Constants::pi()/6)).first, 0.5f);
CORRADE_COMPARE(Math::sincos(Rad(Constants::pi()/6)).second, 0.8660254037844386f);
CORRADE_COMPARE(Math::sincos(30.0_degf).first(), 0.5f);
CORRADE_COMPARE(Math::sincos(30.0_degf).second(), 0.8660254037844386f);
CORRADE_COMPARE(Math::sincos(Rad(Constants::pi()/6)).first(), 0.5f);
CORRADE_COMPARE(Math::sincos(Rad(Constants::pi()/6)).second(), 0.8660254037844386f);
CORRADE_COMPARE(Math::tan(45.0_degf), 1.0f);
CORRADE_COMPARE(Math::tan(Rad(Constants::pi()/4)), 1.0f);
@ -579,10 +579,10 @@ void FunctionsTest::trigonometricWithBase() {
CORRADE_COMPARE(Math::cos(2*30.0_degf), 0.5f);
CORRADE_COMPARE(Math::cos(2*Rad(Constants::pi()/6)), 0.5f);
CORRADE_COMPARE(Math::sincos(2*15.0_degf).first, 0.5f);
CORRADE_COMPARE(Math::sincos(2*15.0_degf).second, 0.8660254037844386f);
CORRADE_COMPARE(Math::sincos(2*Rad(Constants::pi()/12)).first, 0.5f);
CORRADE_COMPARE(Math::sincos(2*Rad(Constants::pi()/12)).second, 0.8660254037844386f);
CORRADE_COMPARE(Math::sincos(2*15.0_degf).first(), 0.5f);
CORRADE_COMPARE(Math::sincos(2*15.0_degf).second(), 0.8660254037844386f);
CORRADE_COMPARE(Math::sincos(2*Rad(Constants::pi()/12)).first(), 0.5f);
CORRADE_COMPARE(Math::sincos(2*Rad(Constants::pi()/12)).second(), 0.8660254037844386f);
CORRADE_COMPARE(Math::tan(2*22.5_degf), 1.0f);
CORRADE_COMPARE(Math::tan(2*Rad(Constants::pi()/8)), 1.0f);
@ -593,8 +593,8 @@ template<class T> void FunctionsTest::sincos() {
/* For GCC's __builtin_sincos this verifies that all specializations are
correct */
CORRADE_COMPARE(Math::sincos(Math::Deg<T>(T(30.0))).first, T(0.5));
CORRADE_COMPARE(Math::sincos(Math::Deg<T>(T(30.0))).second, T(0.866025403784438647l));
CORRADE_COMPARE(Math::sincos(Math::Deg<T>(T(30.0))).first(), T(0.5));
CORRADE_COMPARE(Math::sincos(Math::Deg<T>(T(30.0))).second(), T(0.866025403784438647l));
}
}}}}

12
src/Magnum/Math/Test/IntersectionTest.cpp

@ -141,27 +141,27 @@ void IntersectionTest::lineLine() {
/* Inside both line segments */
CORRADE_COMPARE(Intersection::lineSegmentLineSegment(p, r,
{0.0f, 0.0f}, {-1.0f, 0.0f}), std::make_pair(0.5f, 0.5f));
{0.0f, 0.0f}, {-1.0f, 0.0f}), Containers::pair(0.5f, 0.5f));
CORRADE_COMPARE(Intersection::lineSegmentLine(p, r,
{0.0f, 0.0f}, {-1.0f, 0.0f}), 0.5);
{0.0f, 0.0f}, {-1.0f, 0.0f}), 0.5f);
/* Outside both line segments */
CORRADE_COMPARE(Intersection::lineSegmentLineSegment(p, r,
{0.0f, -2.0f}, {-1.0f, 0.0f}), std::make_pair(-0.5f, 1.5f));
{0.0f, -2.0f}, {-1.0f, 0.0f}), Containers::pair(-0.5f, 1.5f));
CORRADE_COMPARE(Intersection::lineSegmentLine(p, r,
{0.0f, -2.0f}, {-1.0f, 0.0f}), -0.5f);
/* Collinear lines */
const auto tu = Intersection::lineSegmentLineSegment(p, r,
{0.0f, 1.0f}, {-1.0f, -2.0f});
CORRADE_COMPARE(tu.first, -Constants::nan());
CORRADE_COMPARE(tu.second, -Constants::nan());
CORRADE_COMPARE(tu.first(), -Constants::nan());
CORRADE_COMPARE(tu.second(), -Constants::nan());
CORRADE_COMPARE(Intersection::lineSegmentLine(p, r,
{0.0f, 1.0f}, {-1.0f, -2.0f}), -Constants::nan());
/* Parallel lines */
CORRADE_COMPARE(Intersection::lineSegmentLineSegment(p, r,
{0.0f, 0.0f}, {1.0f, 2.0f}), std::make_pair(Constants::inf(), Constants::inf()));
{0.0f, 0.0f}, {1.0f, 2.0f}), Containers::pair(Constants::inf(), Constants::inf()));
CORRADE_COMPARE(Intersection::lineSegmentLine(p, r,
{0.0f, 0.0f}, {1.0f, 2.0f}), Constants::inf());
}

21
src/Magnum/Math/Test/RangeTest.cpp

@ -302,7 +302,7 @@ void RangeTest::constructPair() {
CORRADE_COMPARE(bounds1a, bounds1c);
Range2Di bounds2a = Math::minmax({a, b, c});
Range2Di bounds2b = std::pair<Math::Vector<2, Int>, Math::Vector<2, Int>>{{10, 18}, {30, 25}};
Range2Di bounds2b = Containers::Pair<Math::Vector<2, Int>, Math::Vector<2, Int>>{{10, 18}, {30, 25}};
Range2Di bounds2c{{10, 18}, {30, 25}};
CORRADE_COMPARE(bounds2a, bounds2c);
CORRADE_COMPARE(bounds2b, bounds2c);
@ -312,10 +312,27 @@ void RangeTest::constructPair() {
Vector3i c3{c, 123};
Range3Di bounds3a = Math::minmax({a3, b3, c3});
Range3Di bounds3b = std::pair<Math::Vector<3, Int>, Math::Vector<3, Int>>{{10, 18, 122}, {30, 25, 123}};
Range3Di bounds3b = Containers::Pair<Math::Vector<3, Int>, Math::Vector<3, Int>>{{10, 18, 122}, {30, 25, 123}};
Range3Di bounds3c{{10, 18, 122}, {30, 25, 123}};
CORRADE_COMPARE(bounds3a, bounds3c);
CORRADE_COMPARE(bounds3b, bounds3c);
constexpr Range1Di cbounds1a = Containers::pair(10, 30);
constexpr Range2Di cbounds2a = Containers::Pair<Vector2i, Vector2i>{{10, 18}, {30, 25}};
#ifndef CORRADE_MSVC2015_COMPATIBILITY
constexpr /* No idea what's up. Also, I can't say I actually care. */
#endif
Range2Di cbounds2b = Containers::Pair<Math::Vector<2, Int>, Math::Vector<2, Int>>{{10, 18}, {30, 25}};
constexpr Range3Di cbounds3a = Containers::Pair<Vector3i, Vector3i>{{10, 18, 122}, {30, 25, 123}};
#ifndef CORRADE_MSVC2015_COMPATIBILITY
constexpr /* No idea what's up. Also, I can't say I actually care. */
#endif
Range3Di cbounds3b = Containers::Pair<Math::Vector<3, Int>, Math::Vector<3, Int>>{{10, 18, 122}, {30, 25, 123}};
CORRADE_COMPARE(cbounds1a, bounds1a);
CORRADE_COMPARE(cbounds2a, bounds2a);
CORRADE_COMPARE(cbounds2b, bounds2b);
CORRADE_COMPARE(cbounds3a, bounds3a);
CORRADE_COMPARE(cbounds3b, bounds3b);
}
void RangeTest::constructConversion() {

10
src/Magnum/Math/Test/VectorTest.cpp

@ -529,7 +529,7 @@ void VectorTest::max() {
}
void VectorTest::minmax() {
const auto expected = std::make_pair(-3.0f, 2.0f);
const auto expected = Containers::pair(-3.0f, 2.0f);
CORRADE_COMPARE((Vector3{-1.0f, 2.0f, -3.0f}.minmax()), expected);
CORRADE_COMPARE((Vector3{-1.0f, -3.0f, 2.0f}.minmax()), expected);
CORRADE_COMPARE((Vector3{2.0f, -1.0f, -3.0f}.minmax()), expected);
@ -551,11 +551,11 @@ void VectorTest::nanIgnoring() {
CORRADE_COMPARE(firstNan.max(), 1.0f);
CORRADE_COMPARE(allNan.max(), Constants::nan());
CORRADE_COMPARE(oneNan.minmax(), std::make_pair(-3.0f, 1.0f));
CORRADE_COMPARE(firstNan.minmax(), std::make_pair(-3.0f, 1.0f));
CORRADE_COMPARE(oneNan.minmax(), Containers::pair(-3.0f, 1.0f));
CORRADE_COMPARE(firstNan.minmax(), Containers::pair(-3.0f, 1.0f));
/* Need to compare this way because of NaNs */
CORRADE_COMPARE(allNan.minmax().first, Constants::nan());
CORRADE_COMPARE(allNan.minmax().second, Constants::nan());
CORRADE_COMPARE(allNan.minmax().first(), Constants::nan());
CORRADE_COMPARE(allNan.minmax().second(), Constants::nan());
}
void VectorTest::projected() {

11
src/Magnum/Math/Vector.h

@ -29,7 +29,7 @@
* @brief Class @ref Magnum::Math::Vector, function @ref Magnum::Math::dot(), @ref Magnum::Math::angle()
*/
#include <utility> /* std::pair */
#include <Corrade/Containers/Pair.h>
#ifndef CORRADE_SINGLES_NO_DEBUG
#include <Corrade/Utility/Debug.h>
#endif
@ -42,6 +42,11 @@
#include "Magnum/Math/BitVector.h"
#include "Magnum/Math/TypeTraits.h"
#ifdef MAGNUM_BUILD_DEPRECATED
/* Some APIs returned std::pair before */
#include <Corrade/Containers/PairStl.h>
#endif
namespace Magnum { namespace Math {
#ifndef DOXYGEN_GENERATING_OUTPUT
@ -681,7 +686,7 @@ template<std::size_t size, class T> class Vector {
* <em>NaN</em>s are ignored, unless the vector is all <em>NaN</em>s.
* @see @ref min(), @ref max(), @ref Math::minmax(), @ref Math::isNan()
*/
std::pair<T, T> minmax() const;
Containers::Pair<T, T> minmax() const;
#ifndef DOXYGEN_GENERATING_OUTPUT
protected:
@ -1572,7 +1577,7 @@ template<std::size_t size, class T> inline T Vector<size, T>::max() const {
return out;
}
template<std::size_t size, class T> inline std::pair<T, T> Vector<size, T>::minmax() const {
template<std::size_t size, class T> inline Containers::Pair<T, T> Vector<size, T>::minmax() const {
std::size_t i = Implementation::firstNonNan(_data, IsFloatingPoint<T>{});
T min{_data[i]}, max{_data[i]};

2
src/Magnum/MeshTools/CompressIndices.cpp

@ -185,7 +185,7 @@ Trade::MeshData compressIndices(const Trade::MeshData& mesh, MeshIndexType atLea
std::tuple<Containers::Array<char>, MeshIndexType, UnsignedInt, UnsignedInt> compressIndices(const std::vector<UnsignedInt>& indices) {
const auto minmax = Math::minmax(indices);
Containers::Pair<Containers::Array<char>, MeshIndexType> dataType = compressIndices(indices, MeshIndexType::UnsignedByte);
return std::make_tuple(Utility::move(dataType.first()), dataType.second(), minmax.first, minmax.second);
return std::make_tuple(Utility::move(dataType.first()), dataType.second(), minmax.first(), minmax.second());
}
template<class T> Containers::Array<T> compressIndicesAs(const std::vector<UnsignedInt>& indices) {

12
src/Magnum/Primitives/Capsule.cpp

@ -53,9 +53,9 @@ Trade::MeshData capsule2DWireframe(const UnsignedInt hemisphereRings, const Unsi
/* Bottom hemisphere */
for(UnsignedInt i = 0; i != hemisphereRings; ++i) {
const Rad angle(Float(i+1)*angleIncrement);
const std::pair<Float, Float> sincos = Math::sincos(angle);
const Float x = sincos.first;
const Float y = -sincos.second-halfLength;
const Containers::Pair<Float, Float> sincos = Math::sincos(angle);
const Float x = sincos.first();
const Float y = -sincos.second() - halfLength;
Containers::arrayAppend<Trade::ArrayAllocator>(vertexData,
{{-x, y}, {x, y}});
}
@ -70,9 +70,9 @@ Trade::MeshData capsule2DWireframe(const UnsignedInt hemisphereRings, const Unsi
/* Top hemisphere */
for(UnsignedInt i = 0; i != hemisphereRings; ++i) {
const Rad angle(Float(i)*angleIncrement);
const std::pair<Float, Float> sincos = Math::sincos(angle);
const Float x = sincos.second;
const Float y = sincos.first+halfLength;
const Containers::Pair<Float, Float> sincos = Math::sincos(angle);
const Float x = sincos.second();
const Float y = sincos.first() + halfLength;
Containers::arrayAppend<Trade::ArrayAllocator>(vertexData,
{{-x, y}, {x, y}});
}

16
src/Magnum/Primitives/Circle.cpp

@ -71,8 +71,8 @@ Trade::MeshData circle2DSolid(const UnsignedInt segments, const Circle2DFlags fl
const Rad angleIncrement(Constants::tau()/segments);
for(UnsignedInt i = 0; i != segments + 1; ++i) {
const Rad angle(Float(i)*angleIncrement);
const std::pair<Float, Float> sincos = Math::sincos(angle);
positions[i + 1] = {sincos.second, sincos.first};
const Containers::Pair<Float, Float> sincos = Math::sincos(angle);
positions[i + 1] = {sincos.second(), sincos.first()};
}
/* Fill texture coords, if any */
@ -107,8 +107,8 @@ Trade::MeshData circle2DWireframe(const UnsignedInt segments) {
const Rad angleIncrement(Constants::tau()/segments);
for(UnsignedInt i = 0; i != segments; ++i) {
const Rad angle(Float(i)*angleIncrement);
const std::pair<Float, Float> sincos = Math::sincos(angle);
positions[i] = {sincos.second, sincos.first};
const Containers::Pair<Float, Float> sincos = Math::sincos(angle);
positions[i] = {sincos.second(), sincos.first()};
}
return Trade::MeshData{MeshPrimitive::LineLoop, Utility::move(vertexData),
@ -185,9 +185,9 @@ Trade::MeshData circle3DSolid(const UnsignedInt segments, const Circle3DFlags fl
const Rad angleIncrement(Constants::tau()/segments);
for(UnsignedInt i = 1; i != segments + 2; ++i) {
const Rad angle(Float(i - 1)*angleIncrement);
const std::pair<Float, Float> sincos = Math::sincos(angle);
const Containers::Pair<Float, Float> sincos = Math::sincos(angle);
positions[i] = {sincos.second, sincos.first, 0.0f};
positions[i] = {sincos.second(), sincos.first(), 0.0f};
normals[i] = {0.0f, 0.0f, 1.0f};
if(flags & Circle3DFlag::Tangents)
tangents[i] = {1.0f, 0.0f, 0.0f, 1.0f};
@ -228,8 +228,8 @@ Trade::MeshData circle3DWireframe(const UnsignedInt segments) {
const Rad angleIncrement(Constants::tau()/segments);
for(UnsignedInt i = 0; i != segments; ++i) {
const Rad angle(Float(i)*angleIncrement);
const std::pair<Float, Float> sincos = Math::sincos(angle);
positions[i] = {sincos.second, sincos.first, 0.0f};
const Containers::Pair<Float, Float> sincos = Math::sincos(angle);
positions[i] = {sincos.second(), sincos.first(), 0.0f};
}
return Trade::MeshData{MeshPrimitive::LineLoop, Utility::move(vertexData),

30
src/Magnum/Primitives/Implementation/Spheroid.cpp

@ -96,19 +96,19 @@ void Spheroid::hemisphereVertexRings(UnsignedInt count, Float centerY, Rad start
const Rad segmentAngleIncrement(Constants::tau()/_segments);
for(UnsignedInt i = 0; i != count; ++i) {
const Rad ringAngle = startRingAngle + Float(i)*ringAngleIncrement;
const std::pair<Float, Float> ringSinCos = Math::sincos(ringAngle);
const Float x = ringSinCos.second;
const Float z = ringSinCos.second;
const Float y = ringSinCos.first;
const Containers::Pair<Float, Float> ringSinCos = Math::sincos(ringAngle);
const Float x = ringSinCos.second();
const Float z = ringSinCos.second();
const Float y = ringSinCos.first();
for(UnsignedInt j = 0; j != _segments; ++j) {
const Rad segmentAngle = Float(j)*segmentAngleIncrement;
const std::pair<Float, Float> segmentSinCos = Math::sincos(segmentAngle);
append({x*segmentSinCos.first, centerY+y, z*segmentSinCos.second},
{x*segmentSinCos.first, y, z*segmentSinCos.second});
const Containers::Pair<Float, Float> segmentSinCos = Math::sincos(segmentAngle);
append({x*segmentSinCos.first(), centerY+y, z*segmentSinCos.second()},
{x*segmentSinCos.first(), y, z*segmentSinCos.second()});
if(_flags & Flag::Tangents)
lastVertexTangent(1) = {segmentSinCos.second, 0.0f, -segmentSinCos.first, 1.0f};
lastVertexTangent(1) = {segmentSinCos.second(), 0.0f, -segmentSinCos.first(), 1.0f};
if(_flags & Flag::TextureCoordinates)
lastVertexTextureCoords(1) = {j*1.0f/_segments, startTextureCoordsV + i*textureCoordsVIncrement};
}
@ -133,12 +133,12 @@ void Spheroid::cylinderVertexRings(const UnsignedInt count, const Float startY,
for(UnsignedInt i = 0; i != count; ++i) {
for(UnsignedInt j = 0; j != _segments; ++j) {
const Rad segmentAngle = Float(j)*segmentAngleIncrement;
const std::pair<Float, Float> segmentSinCos = Math::sincos(segmentAngle);
append({base.x()*segmentSinCos.first, base.y(), base.x()*segmentSinCos.second},
{baseNormal.x()*segmentSinCos.first, baseNormal.y(), baseNormal.x()*segmentSinCos.second});
const Containers::Pair<Float, Float> segmentSinCos = Math::sincos(segmentAngle);
append({base.x()*segmentSinCos.first(), base.y(), base.x()*segmentSinCos.second()},
{baseNormal.x()*segmentSinCos.first(), baseNormal.y(), baseNormal.x()*segmentSinCos.second()});
if(_flags & Flag::Tangents)
lastVertexTangent(1) = {segmentSinCos.second, 0.0f, -segmentSinCos.first, 1.0f};
lastVertexTangent(1) = {segmentSinCos.second(), 0.0f, -segmentSinCos.first(), 1.0f};
if(_flags & Flag::TextureCoordinates)
lastVertexTextureCoords(1) = {j*1.0f/_segments, startTextureCoordsV + i*textureCoordsVIncrement};
}
@ -220,11 +220,11 @@ void Spheroid::capVertexRing(Float y, Float textureCoordsV, const Vector3& norma
for(UnsignedInt i = 0; i != _segments; ++i) {
const Rad segmentAngle = Float(i)*segmentAngleIncrement;
const std::pair<Float, Float> segmentSinCos = Math::sincos(segmentAngle);
append({segmentSinCos.first, y, segmentSinCos.second}, normal);
const Containers::Pair<Float, Float> segmentSinCos = Math::sincos(segmentAngle);
append({segmentSinCos.first(), y, segmentSinCos.second()}, normal);
if(_flags & Flag::Tangents)
lastVertexTangent(1) = {segmentSinCos.second, 0.0f, -segmentSinCos.first, 1.0f};
lastVertexTangent(1) = {segmentSinCos.second(), 0.0f, -segmentSinCos.first(), 1.0f};
if(_flags & Flag::TextureCoordinates)
lastVertexTextureCoords(1) = {i*1.0f/_segments, textureCoordsV};
}

24
src/Magnum/Primitives/Implementation/WireframeSpheroid.cpp

@ -50,13 +50,13 @@ void WireframeSpheroid::bottomHemisphere(const Float endY, const UnsignedInt rin
const Rad ringAngleIncrement(Constants::piHalf()/rings);
for(UnsignedInt j = 0; j != rings-1; ++j) {
const Rad angle = Float(j+1)*ringAngleIncrement;
const std::pair<Float, Float> sincos = Math::sincos(angle);
const Containers::Pair<Float, Float> sincos = Math::sincos(angle);
Containers::arrayAppend<Trade::ArrayAllocator>(_vertexData, {
{0.0f, endY - sincos.second, sincos.first},
{sincos.first, endY - sincos.second, 0.0f},
{0.0f, endY - sincos.second, -sincos.first},
{-sincos.first, endY - sincos.second, 0.0f}
{0.0f, endY - sincos.second(), sincos.first()},
{sincos.first(), endY - sincos.second(), 0.0f},
{0.0f, endY - sincos.second(), -sincos.first()},
{-sincos.first(), endY - sincos.second(), 0.0f}
});
/* Connect vertices to next ring */
@ -78,7 +78,7 @@ void WireframeSpheroid::topHemisphere(const Float startY, const UnsignedInt ring
const Rad ringAngleIncrement(Constants::piHalf()/rings);
for(UnsignedInt j = 0; j != rings-1; ++j) {
const Rad angle = Float(j+1)*ringAngleIncrement;
const std::pair<Float, Float> sincos = Math::sincos(angle);
const Containers::Pair<Float, Float> sincos = Math::sincos(angle);
/* Connect previous hemisphere ring to current vertices */
if(j != 0) for(UnsignedInt i = 0; i != 4; ++i) {
@ -87,10 +87,10 @@ void WireframeSpheroid::topHemisphere(const Float startY, const UnsignedInt ring
}
Containers::arrayAppend<Trade::ArrayAllocator>(_vertexData, {
{0.0f, startY + sincos.first, sincos.second},
{sincos.second, startY + sincos.first, 0.0f},
{0.0f, startY + sincos.first, -sincos.second},
{-sincos.second, startY + sincos.first, 0.0f}
{0.0f, startY + sincos.first(), sincos.second()},
{sincos.second(), startY + sincos.first(), 0.0f},
{0.0f, startY + sincos.first(), -sincos.second()},
{-sincos.second(), startY + sincos.first(), 0.0f}
});
}
@ -113,11 +113,11 @@ void WireframeSpheroid::ring(const Float y) {
for(UnsignedInt j = 0; j != _segments; ++j) {
for(UnsignedInt i = 0; i != 4; ++i) {
const Rad segmentAngle = Rad(Float(i)*Constants::piHalf()) + Float(j)*segmentAngleIncrement;
const std::pair<Float, Float> sincos = Math::sincos(segmentAngle);
const Containers::Pair<Float, Float> sincos = Math::sincos(segmentAngle);
if(j != 0) Containers::arrayAppend<Trade::ArrayAllocator>(_indexData,
{UnsignedInt(_vertexData.size() - 4), UnsignedInt(_vertexData.size())});
Containers::arrayAppend<Trade::ArrayAllocator>(_vertexData,
{sincos.first, y, sincos.second});
{sincos.first(), y, sincos.second()});
}
}

Loading…
Cancel
Save