Browse Source

Math: ability to convert ranges from/to external representation.

pull/107/head
Vladimír Vondruš 11 years ago
parent
commit
562d71dbe6
  1. 16
      src/Magnum/Math/Range.h
  2. 138
      src/Magnum/Math/Test/RangeTest.cpp

16
src/Magnum/Math/Range.h

@ -39,6 +39,8 @@ namespace Implementation {
template<class T> struct RangeTraits<1, T> { typedef Vector<1, T> Type; }; template<class T> struct RangeTraits<1, T> { typedef Vector<1, T> Type; };
template<class T> struct RangeTraits<2, T> { typedef Vector2<T> Type; }; template<class T> struct RangeTraits<2, T> { typedef Vector2<T> Type; };
template<class T> struct RangeTraits<3, T> { typedef Vector3<T> Type; }; template<class T> struct RangeTraits<3, T> { typedef Vector3<T> Type; };
template<std::size_t, class, class> struct RangeConverter;
} }
/** /**
@ -93,6 +95,14 @@ template<UnsignedInt dimensions, class T> class Range {
*/ */
template<class U> constexpr explicit Range(const Range<dimensions, U>& other): _min(other._min), _max(other._max) {} template<class U> constexpr explicit Range(const Range<dimensions, U>& other): _min(other._min), _max(other._max) {}
/** @brief Construct range from external representation */
template<class U, class V = decltype(Implementation::RangeConverter<dimensions, T, U>::from(std::declval<U>()))> constexpr explicit Range(const U& other): Range{Implementation::RangeConverter<dimensions, T, U>::from(other)} {}
/** @brief Convert range to external representation */
template<class U, class V = decltype(Implementation::RangeConverter<dimensions, T, U>::to(std::declval<Range<dimensions, T>>()))> constexpr explicit operator U() const {
return Implementation::RangeConverter<dimensions, T, U>::to(*this);
}
/** @brief Equality comparison */ /** @brief Equality comparison */
constexpr bool operator==(const Range<dimensions, T>& other) const { constexpr bool operator==(const Range<dimensions, T>& other) const {
return _min == other._min && _max == other._max; return _min == other._min && _max == other._max;
@ -220,6 +230,9 @@ template<class T> class Range2D: public Range<2, T> {
/** @copydoc Range(const Range<dimensions, U>&) */ /** @copydoc Range(const Range<dimensions, U>&) */
template<class U> constexpr explicit Range2D(const Range2D<U>& other): Range<2, T>(other) {} template<class U> constexpr explicit Range2D(const Range2D<U>& other): Range<2, T>(other) {}
/** @brief Construct range from external representation */
template<class U, class V = decltype(Implementation::RangeConverter<2, T, U>::from(std::declval<U>()))> constexpr explicit Range2D(const U& other): Range<2, T>{Implementation::RangeConverter<2, T, U>::from(other)} {}
/** /**
* @brief Bottom left corner * @brief Bottom left corner
* *
@ -321,6 +334,9 @@ template<class T> class Range3D: public Range<3, T> {
/** @copydoc Range(const Range<dimensions, U>&) */ /** @copydoc Range(const Range<dimensions, U>&) */
template<class U> constexpr explicit Range3D(const Range3D<U>& other): Range<3, T>(other) {} template<class U> constexpr explicit Range3D(const Range3D<U>& other): Range<3, T>(other) {}
/** @brief Construct range from external representation */
template<class U, class V = decltype(Implementation::RangeConverter<3, T, U>::from(std::declval<U>()))> constexpr explicit Range3D(const U& other): Range<3, T>{Implementation::RangeConverter<3, T, U>::from(other)} {}
/** /**
* @brief Back bottom left corner * @brief Back bottom left corner
* *

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

@ -29,7 +29,79 @@
#include "Magnum/Math/Range.h" #include "Magnum/Math/Range.h"
namespace Magnum { namespace Math { namespace Test { struct Dim {
float offset, size;
};
struct Rect {
float x, y, w, h;
};
struct Box {
float x, y, z, w, h, d;
};
namespace Magnum { namespace Math {
namespace Implementation {
template<> struct RangeConverter<1, Float, Dim> {
#if !defined(__GNUC__) || defined(__clang__)
constexpr /* See the convert() test case */
#endif
static Range<1, Float> from(const Dim& other) {
/* Doing it this way to preserve constexpr */
return {other.offset, other.offset + other.size};
}
constexpr static Dim to(const Range<1, Float>& other) {
return {other.min()[0],
/* Doing it this way to preserve constexpr */
other.max()[0] - other.min()[0]};
}
};
template<> struct RangeConverter<2, Float, Rect> {
#if !defined(__GNUC__) || defined(__clang__)
constexpr /* See the convert() test case */
#endif
static Range<2, Float> from(const Rect& other) {
/* Doing it this way to preserve constexpr */
return {{other.x, other.y}, {other.x + other.w, other.y + other.h}};
}
constexpr static Rect to(const Range<2, Float>& other) {
return {other.min().x(), other.min().y(),
/* Doing it this way to preserve constexpr */
other.max().x() - other.min().x(),
other.max().y() - other.min().y()};
}
};
template<> struct RangeConverter<3, Float, Box> {
#if !defined(__GNUC__) || defined(__clang__)
constexpr /* See the convert() test case */
#endif
static Range<3, Float> from(const Box& other) {
return {{other.x, other.y, other.z},
/* Doing it this way to preserve constexpr */
{other.x + other.w,
other.y + other.h,
other.z + other.d}};
}
constexpr static Box to(const Range<3, Float>& other) {
return {other.min().x(), other.min().y(), other.min().z(),
/* Doing it this way to preserve constexpr */
other.max().x() - other.min().x(),
other.max().y() - other.min().y(),
other.max().z() - other.min().z()};
}
};
}
namespace Test {
struct RangeTest: Corrade::TestSuite::Tester { struct RangeTest: Corrade::TestSuite::Tester {
explicit RangeTest(); explicit RangeTest();
@ -39,6 +111,7 @@ struct RangeTest: Corrade::TestSuite::Tester {
void constructFromSize(); void constructFromSize();
void constructConversion(); void constructConversion();
void constructCopy(); void constructCopy();
void convert();
void access(); void access();
void compare(); void compare();
@ -71,6 +144,7 @@ RangeTest::RangeTest() {
&RangeTest::constructFromSize, &RangeTest::constructFromSize,
&RangeTest::constructConversion, &RangeTest::constructConversion,
&RangeTest::constructCopy, &RangeTest::constructCopy,
&RangeTest::convert,
&RangeTest::access, &RangeTest::access,
&RangeTest::compare, &RangeTest::compare,
@ -149,6 +223,68 @@ void RangeTest::constructCopy() {
CORRADE_COMPARE(f, Range3Di({3, 5, -7}, {23, 78, 2})); CORRADE_COMPARE(f, Range3Di({3, 5, -7}, {23, 78, 2}));
} }
void RangeTest::convert() {
/* It's position/size, not min/max */
constexpr Dim a{1.5f, 3.5f};
constexpr Rect b{1.5f, -2.0f, 3.5f, 0.5f};
constexpr Box c{1.5f, -2.0f, -0.5f, 3.5f, 0.5f, 9.5f};
constexpr Range1D d{1.5f, 5.0f};
constexpr Range2D e{{1.5f, -2.0f}, {5.0f, -1.5f}};
constexpr Range3D f{{1.5f, -2.0f, -0.5f}, {5.0f, -1.5f, 9.0f}};
/* GCC 5.1 fills the result with zeros instead of properly calling
delegated copy constructor if using constexpr. Reported here:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66450 */
#if !defined(__GNUC__) || defined(__clang__)
constexpr
#endif
Range<2, Float> g{b};
#if !defined(__GNUC__) || defined(__clang__)
constexpr
#endif
Range1D h{a};
#if !defined(__GNUC__) || defined(__clang__)
constexpr
#endif
Range2D i{b};
#if !defined(__GNUC__) || defined(__clang__)
constexpr
#endif
Range3D j{c};
CORRADE_COMPARE(g, e);
CORRADE_COMPARE(h, d);
CORRADE_COMPARE(i, e);
CORRADE_COMPARE(j, f);
constexpr Dim k(d);
CORRADE_COMPARE(k.offset, a.offset);
CORRADE_COMPARE(k.size, a.size);
constexpr Rect l(e);
CORRADE_COMPARE(l.x, b.x);
CORRADE_COMPARE(l.y, b.y);
CORRADE_COMPARE(l.w, b.w);
CORRADE_COMPARE(l.h, b.h);
constexpr Box m(f);
CORRADE_COMPARE(m.x, c.x);
CORRADE_COMPARE(m.y, c.y);
CORRADE_COMPARE(m.z, c.z);
CORRADE_COMPARE(m.w, c.w);
CORRADE_COMPARE(m.h, c.h);
CORRADE_COMPARE(m.d, c.d);
/* Implicit conversion is not allowed */
CORRADE_VERIFY(!(std::is_convertible<Rect, Range<2, Float>>::value));
CORRADE_VERIFY(!(std::is_convertible<Dim, Range1D>::value));
CORRADE_VERIFY(!(std::is_convertible<Rect, Range2D>::value));
CORRADE_VERIFY(!(std::is_convertible<Box, Range3D>::value));
CORRADE_VERIFY(!(std::is_convertible<Range1D, Dim>::value));
CORRADE_VERIFY(!(std::is_convertible<Range2D, Rect>::value));
CORRADE_VERIFY(!(std::is_convertible<Range3D, Box>::value));
}
void RangeTest::access() { void RangeTest::access() {
Range1Di line(34, 47); Range1Di line(34, 47);
Range2Di rect({34, 23}, {47, 30}); Range2Di rect({34, 23}, {47, 30});

Loading…
Cancel
Save