Browse Source

Math: added generic Range class.

Will replace Geometry::Rectangle.
pull/34/head
Vladimír Vondruš 13 years ago
parent
commit
714c243dd6
  1. 39
      src/Magnum.h
  2. 1
      src/Math/CMakeLists.txt
  3. 10
      src/Math/Math.h
  4. 425
      src/Math/Range.h
  5. 1
      src/Math/Test/CMakeLists.txt
  6. 311
      src/Math/Test/RangeTest.cpp
  7. 10
      src/Math/instantiation.cpp

39
src/Magnum.h

@ -301,6 +301,32 @@ typedef Math::Deg<Float> Deg;
/** @brief Angle in float radians */
typedef Math::Rad<Float> Rad;
/** @brief Float 1D range */
#ifndef CORRADE_GCC46_COMPATIBILITY
typedef Math::Range1D<Float> Range1D;
#else
typedef Math::Range<1, Float> Range1D;
#endif
/** @brief Float 2D range */
typedef Math::Range2D<Float> Range2D;
/** @brief Float 3D range */
typedef Math::Range3D<Float> Range3D;
/** @brief Signed integer 1D range */
#ifndef CORRADE_GCC46_COMPATIBILITY
typedef Math::Range1D<Int> Range1Di;
#else
typedef Math::Range<1, Int> Range1Di;
#endif
/** @brief Signed integer 2D range */
typedef Math::Range2D<Int> Range2Di;
/** @brief Signed integer 3D range */
typedef Math::Range3D<Int> Range3Di;
/** @brief Float rectangle */
typedef Math::Geometry::Rectangle<Float> Rectangle;
@ -444,6 +470,19 @@ typedef Math::Deg<Double> Degd;
/** @brief Angle in double radians */
typedef Math::Rad<Double> Radd;
/** @brief Double 1D range */
#ifndef CORRADE_GCC46_COMPATIBILITY
typedef Math::Range1D<Double> Range1Dd;
#else
typedef Math::Range<1, Double> Range1Dd;
#endif
/** @brief Double 2D range */
typedef Math::Range2D<Double> Range2Dd;
/** @brief Double 3D range */
typedef Math::Range3D<Double> Range3Dd;
/** @brief Double rectangle */
typedef Math::Geometry::Rectangle<Double> Rectangled;

1
src/Math/CMakeLists.txt

@ -37,6 +37,7 @@ set(MagnumMath_HEADERS
Matrix3.h
Matrix4.h
Quaternion.h
Range.h
RectangularMatrix.h
Swizzle.h
Unit.h

10
src/Math/Math.h

@ -29,8 +29,9 @@
*/
#include <cstddef>
#include <corradeConfigure.h>
#include "corradeConfigure.h"
#include "Types.h"
namespace Magnum { namespace Math {
@ -74,6 +75,13 @@ template<class> class Vector2;
template<class> class Vector3;
template<class> class Vector4;
template<UnsignedInt, class> class Range;
#ifndef CORRADE_GCC46_COMPATIBILITY
template<class T> using Range1D = Range<1, T>;
#endif
template<class> class Range2D;
template<class> class Range3D;
namespace Geometry {
template<class> class Rectangle;
}

425
src/Math/Range.h

@ -0,0 +1,425 @@
#ifndef Magnum_Math_Range_h
#define Magnum_Math_Range_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
/** @file
* @brief Class @ref Magnum::Math::Range, @ref Magnum::Math::Range2D, @ref Magnum::Math::Range3D, alias @ref Magnum::Math::Range1D
*/
#include "Math/Vector3.h"
namespace Magnum { namespace Math {
namespace Implementation {
template<UnsignedInt, class> struct RangeTraits;
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<3, T> { typedef Vector3<T> Type; };
}
/**
@brief N-dimensional range
Axis-aligned line (in 1D), rectangle (in 2D) or cube (in 3D). Minimal
coordinate is inclusive, maximal exclusive. See @ref Range1D, @ref Range2D and
@ref Range3D specializations for given dimension count.
*/
template<UnsignedInt dimensions, class T> class Range {
template<UnsignedInt, class> friend class Range;
public:
/**
* @brief Underlying vector type
*
* `T` in 1D, @ref Vector2<T> in 2D, @ref Vector3<T> in 3D.
*/
typedef typename Implementation::RangeTraits<dimensions, T>::Type VectorType;
/**
* Create range from minimal coordinates and size
* @param min Minimal coordinates
* @param size Range size
*/
static Range<dimensions, T> fromSize(const VectorType& min, const VectorType& size) {
return {min, min+size};
}
/**
* @brief Construct zero range
*
* Construct zero-size range positioned at origin.
*/
constexpr Range(): _min{}, _max{} {}
/** @brief Construct range from minimal and maximal coordinates */
constexpr Range(const VectorType& min, const VectorType& max): _min(min), _max(max) {}
/** @brief Copy constructor */
constexpr Range(const Range<dimensions, T>&) = default;
/**
* @brief Construct range from another of different type
*
* Performs only default casting on the values, no rounding or
* anything else. Example usage:
* @code
* Range2D<Float> floatingPoint({1.3f, 2.7f}, {-15.0f, 7.0f});
* Range2D<Byte> integral(floatingPoint); // {{1, 2}, {-15, 7}}
* @endcode
*/
template<class U> constexpr explicit Range(const Range<dimensions, U>& other): _min(other._min), _max(other._max) {}
/** @brief Equality comparison */
constexpr bool operator==(const Range<dimensions, T>& other) const {
return _min == other._min && _max == other._max;
}
/** @brief Non-equality comparison */
constexpr bool operator!=(const Range<dimensions, T>& other) const {
return !operator==(other);
}
/**
* @brief Minimal coordinates (inclusive)
*
* @see @ref size(), @ref Range2D::bottomLeft(),
* @ref Range3D::backBottomLeft()
*/
VectorType& min() { return _min; }
constexpr const VectorType min() const { return _min; } /**< @overload */
/**
* @brief Maximal coordinates (exclusive)
*
* @see @ref size(), @ref Range2D::topRight(),
* @ref Range3D::frontTopRight()
*/
VectorType& max() { return _max; }
constexpr const VectorType max() const { return _max; } /**< @overload */
/**
* @brief Range size
*
* @see @ref min(), @ref max(), @ref Range2D::sizeX(),
* @ref Range2D::sizeY(), @ref Range3D::sizeX(),
* @ref Range3D::sizeY(), @ref Range3D::sizeZ()
*/
VectorType size() const { return _max - _min; }
/**
* @brief Translated range
*
* Translates the minimal and maximal coordinates by given amount. Size
* remains the same.
*/
Range<dimensions, T> translated(const VectorType& vector) const;
private:
VectorType _min, _max;
};
#ifndef DOXYGEN_GENERATING_OUTPUT
#define MAGNUM_RANGE_SUBCLASS_IMPLEMENTATION(dimensions, Type, VectorType) \
static Type<T> fromSize(const VectorType<T>& min, const VectorType<T>& size) { \
return Range<dimensions, T>::fromSize(min, size); \
} \
Type<T> translated(const VectorType<T>& vector) const { \
return Range<dimensions, T>::translated(vector); \
}
#endif
#ifndef CORRADE_GCC46_COMPATIBILITY
/**
@brief One-dimensional range
Convenience alternative to <tt>%Range<1, T></tt>. See @ref Range for more
information.
@note Not available on GCC < 4.7. Use <tt>%Range<1, T></tt> instead.
*/
template<class T> using Range1D = Range<1, T>;
#endif
/**
@brief Two-dimensional range
See @ref Range for more information.
@see @ref Range1D, @ref Range3D
*/
template<class T> class Range2D: public Range<2, T> {
public:
/** @copydoc Range() */
constexpr Range2D() = default;
/** @copydoc Range(const VectorType&, const VectorType&) */
constexpr Range2D(const Vector2<T>& min, const Vector2<T>& max): Range<2, T>(min, max) {}
/** @copydoc Range(const Range&) */
constexpr Range2D(const Range<2, T>& other): Range<2, T>(other) {}
/** @copydoc Range(const Range<dimensions, U>&) */
template<class U> constexpr explicit Range2D(const Range2D<U>& other): Range<2, T>(other) {}
/**
* @brief Bottom left corner
*
* Equivalent to @ref min().
*/
Vector2<T>& bottomLeft() { return Range<2, T>::min(); }
constexpr Vector2<T> bottomLeft() const { return Range<2, T>::min(); } /**< @overload */
/** @brief Bottom right corner */
constexpr Vector2<T> bottomRight() const {
return {Range<2, T>::max().x(), Range<2, T>::min().y()};
}
/** @brief Top left corner */
constexpr Vector2<T> topLeft() const {
return {Range<2, T>::min().x(), Range<2, T>::max().y()};
}
/**
* @brief Top right corner
*
* Equivalent to @ref max().
*/
Vector2<T>& topRight() { return Range<2, T>::max(); }
constexpr Vector2<T> topRight() const { return Range<2, T>::max(); } /**< @overload */
/** @brief Left edge */
T& left() { return Range<2, T>::min().x(); }
constexpr T left() const { return Range<2, T>::min().x(); } /**< @overload */
/** @brief Right edge */
T& right() { return Range<2, T>::max().x(); }
constexpr T right() const { return Range<2, T>::max().x(); } /**< @overload */
/** @brief Bottom edge */
T& bottom() { return Range<2, T>::min().y(); }
constexpr T bottom() const { return Range<2, T>::min().y(); } /**< @overload */
/** @brief Top edge */
T& top() { return Range<2, T>::max().y(); }
constexpr T top() const { return Range<2, T>::max().y(); } /**< @overload */
/**
* @brief %Range width
*
* @see @ref size()
*/
T sizeX() const {
return Range<2, T>::max().x() - Range<2, T>::min().x();
}
/**
* @brief %Range height
*
* @see @ref size()
*/
T sizeY() const {
return Range<2, T>::max().y() - Range<2, T>::min().y();
}
MAGNUM_RANGE_SUBCLASS_IMPLEMENTATION(2, Range2D, Vector2)
};
/**
@brief Two-dimensional range
See @ref Range for more information.
@see @ref Range1D, @ref Range2D
*/
template<class T> class Range3D: public Range<3, T> {
public:
/** @copydoc Range() */
constexpr Range3D() = default;
/** @copydoc Range(const VectorType&, const VectorType&) */
constexpr Range3D(const Vector3<T>& min, const Vector3<T>& max): Range<3, T>(min, max) {}
/** @copydoc Range(const Range&) */
constexpr Range3D(const Range<3, T>& other): Range<3, T>(other) {}
/** @copydoc Range(const Range<dimensions, U>&) */
template<class U> constexpr explicit Range3D(const Range3D<U>& other): Range<3, T>(other) {}
/**
* @brief Back bottom left corner
*
* Equivalent to @ref min().
*/
Vector3<T>& backBottomLeft() { return Range<3, T>::min(); }
constexpr Vector3<T> backBottomLeft() const { return Range<3, T>::min(); } /**< @overload */
/** @brief Back bottom right corner */
constexpr Vector3<T> backBottomRight() const {
return {Range<3, T>::max().x(), Range<3, T>::min().y(), Range<3, T>::min().z()};
}
/** @brief Back top right corner */
constexpr Vector3<T> backTopLeft() const {
return {Range<3, T>::min().x(), Range<3, T>::max().y(), Range<3, T>::min().z()};
}
/** @brief Back top right corner */
constexpr Vector3<T> backTopRight() const {
return {Range<3, T>::max().x(), Range<3, T>::max().y(), Range<3, T>::min().z()};
}
/**
* @brief Front top right corner
*
* Equivalent to @ref max().
*/
Vector3<T>& frontTopRight() { return Range<3, T>::max(); }
constexpr Vector3<T> frontTopRight() const { return Range<3, T>::max(); } /**< @overload */
/** @brief Front top left corner */
constexpr Vector3<T> frontTopLeft() const {
return {Range<3, T>::min().x(), Range<3, T>::max().y(), Range<3, T>::max().z()};
}
/** @brief Front bottom right corner */
constexpr Vector3<T> frontBottomRight() const {
return {Range<3, T>::max().x(), Range<3, T>::min().y(), Range<3, T>::max().z()};
}
/** @brief Front bottom left corner */
constexpr Vector3<T> frontBottomLeft() const {
return {Range<3, T>::min().x(), Range<3, T>::min().y(), Range<3, T>::max().z()};
}
/** @brief Left edge */
T& left() { return Range<3, T>::min().x(); }
constexpr T left() const { return Range<3, T>::min().x(); } /**< @overload */
/** @brief Right edge */
T& right() { return Range<3, T>::max().x(); }
constexpr T right() const { return Range<3, T>::max().x(); } /**< @overload */
/** @brief Bottom edge */
T& bottom() { return Range<3, T>::min().y(); }
constexpr T bottom() const { return Range<3, T>::min().y(); } /**< @overload */
/** @brief Top edge */
T& top() { return Range<3, T>::max().y(); }
constexpr T top() const { return Range<3, T>::max().y(); } /**< @overload */
/** @brief Back edge */
T& back() { return Range<3, T>::min().z(); }
constexpr T back() const { return Range<3, T>::min().z(); } /**< @overload */
/** @brief Front edge */
T& front() { return Range<3, T>::max().z(); }
constexpr T front() const { return Range<3, T>::max().z(); } /**< @overload */
/**
* @brief %Range width
*
* @see @ref size()
*/
T sizeX() const {
return Range<3, T>::max().x() - Range<3, T>::min().x();
}
/**
* @brief %Range height
*
* @see @ref size()
*/
T sizeY() const {
return Range<3, T>::max().y() - Range<3, T>::min().y();
}
/**
* @brief %Range depth
*
* @see @ref size()
*/
T sizeZ() const {
return Range<3, T>::max().z() - Range<3, T>::min().z();
}
MAGNUM_RANGE_SUBCLASS_IMPLEMENTATION(3, Range3D, Vector3)
};
/** @debugoperator{Magnum::Math::Range} */
template<UnsignedInt dimensions, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Range<dimensions, T>& value) {
debug << "Range({";
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false);
debug << value.min()[0];
for(UnsignedInt i = 1; i != dimensions; ++i) debug << ", " << value.min()[i];
debug << "}, {" << value.max()[0];
for(UnsignedInt i = 1; i != dimensions; ++i) debug << ", " << value.max()[i];
debug << "})";
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true);
return debug;
}
template<UnsignedInt dimensions, class T> Range<dimensions, T> Range<dimensions, T>::translated(const VectorType& vector) const {
return {_min + vector, _max + vector};
}
}}
namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::Range} */
template<Magnum::UnsignedInt dimensions, class T> struct ConfigurationValue<Magnum::Math::Range<dimensions, T>> {
ConfigurationValue() = delete;
/** @brief Writes elements separated with spaces */
static std::string toString(const Magnum::Math::Range<dimensions, T>& value, const ConfigurationValueFlags flags) {
return ConfigurationValue<Magnum::Math::Vector<dimensions*2, T>>::toString(
reinterpret_cast<const Magnum::Math::Vector<dimensions*2, T>&>(value), flags);
}
/** @brief Reads elements separated with whitespace */
static Magnum::Math::Range<dimensions, T> fromString(const std::string& stringValue, const ConfigurationValueFlags flags) {
const auto vec = ConfigurationValue<Magnum::Math::Vector<dimensions*2, T>>::fromString(stringValue, flags);
return *reinterpret_cast<const Magnum::Math::Range<dimensions, T>*>(vec.data());
}
};
/** @configurationvalue{Magnum::Math::Range2D} */
template<class T> struct ConfigurationValue<Magnum::Math::Range2D<T>>: public ConfigurationValue<Magnum::Math::Range<2, T>> {};
/** @configurationvalue{Magnum::Math::Range3D} */
template<class T> struct ConfigurationValue<Magnum::Math::Range3D<T>>: public ConfigurationValue<Magnum::Math::Range<3, T>> {};
#ifndef DOXYGEN_GENERATING_OUTPUT
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Range<2, Magnum::Float>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Range<2, Magnum::Int>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Range<3, Magnum::Float>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Range<3, Magnum::Int>>;
#ifndef MAGNUM_TARGET_GLES
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Range<2, Magnum::Double>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Range<3, Magnum::Double>>;
#endif
#endif
}}
#endif

1
src/Math/Test/CMakeLists.txt

@ -40,6 +40,7 @@ corrade_add_test(MathMatrix4Test Matrix4Test.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(MathSwizzleTest SwizzleTest.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(MathUnitTest UnitTest.cpp)
corrade_add_test(MathAngleTest AngleTest.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(MathRangeTest RangeTest.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(MathDualTest DualTest.cpp)
corrade_add_test(MathComplexTest ComplexTest.cpp LIBRARIES MagnumMathTestLib)

311
src/Math/Test/RangeTest.cpp

@ -0,0 +1,311 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <sstream>
#include <TestSuite/Tester.h>
#include <Utility/Configuration.h>
#include "Math/Range.h"
#ifdef MAGNUM_BUILD_DEPRECATED
#include "Math/Geometry/Rectangle.h"
#endif
namespace Magnum { namespace Math { namespace Test {
class RangeTest: public Corrade::TestSuite::Tester {
public:
RangeTest();
void construct();
void constructDefault();
void constructFromSize();
void constructConversion();
void constructCopy();
void access();
void compare();
void size();
void translated();
void subclassTypes();
void subclass();
void debug();
void configuration();
};
typedef Math::Range<1, Float> Range1D;
typedef Math::Range2D<Float> Range2D;
typedef Math::Range3D<Float> Range3D;
typedef Math::Range1D<Int> Range1Di;
typedef Math::Range2D<Int> Range2Di;
typedef Math::Range3D<Int> Range3Di;
typedef Vector2<Int> Vector2i;
typedef Vector3<Int> Vector3i;
RangeTest::RangeTest() {
addTests({&RangeTest::construct,
&RangeTest::constructDefault,
&RangeTest::constructFromSize,
&RangeTest::constructConversion,
&RangeTest::constructCopy,
&RangeTest::access,
&RangeTest::compare,
&RangeTest::size,
&RangeTest::translated,
&RangeTest::subclassTypes,
&RangeTest::subclass,
&RangeTest::debug,
&RangeTest::configuration});
}
void RangeTest::construct() {
constexpr Range1Di a(3, 23);
constexpr Range2Di b({3, 5}, {23, 78});
constexpr Range3Di c({3, 5, -7}, {23, 78, 2});
CORRADE_COMPARE(a, (Range<1, Int>(3, 23)));
CORRADE_COMPARE(b, (Range<2, Int>({3, 5}, {23, 78})));
CORRADE_COMPARE(c, (Range<3, Int>({3, 5, -7}, {23, 78, 2})));
}
void RangeTest::constructDefault() {
constexpr Range1Di a;
constexpr Range2Di b;
constexpr Range3Di c;
CORRADE_COMPARE(a, Range1Di(0, 0));
CORRADE_COMPARE(b, Range2Di({0, 0}, {0, 0}));
CORRADE_COMPARE(c, Range3Di({0, 0, 0}, {0, 0, 0}));
}
void RangeTest::constructFromSize() {
CORRADE_COMPARE(Range1Di::fromSize(3, 23), Range1Di(3, 26));
CORRADE_COMPARE(Range2Di::fromSize({3, 5}, {23, 78}), Range2Di({3, 5}, {26, 83}));
CORRADE_COMPARE(Range3Di::fromSize({3, 5, -7}, {23, 78, 9}), Range3Di({3, 5, -7}, {26, 83, 2}));
}
void RangeTest::constructConversion() {
constexpr Range1D a(1.3f, -15.0f);
constexpr Range2D b({1.3f, 2.7f}, {-15.0f, 7.0f});
constexpr Range3D c({1.3f, 2.7f, -1.5f}, {-15.0f, 7.0f, 0.3f});
#ifndef CORRADE_GCC46_COMPATIBILITY
constexpr /* Not constexpr under GCC < 4.7 */
#endif
Range1Di d(a);
CORRADE_COMPARE(d, Range1Di(1, -15));
#ifndef CORRADE_GCC46_COMPATIBILITY
constexpr /* Not constexpr under GCC < 4.7 */
#endif
Range2Di e(b);
CORRADE_COMPARE(e, Range2Di({1, 2}, {-15, 7}));
#ifndef CORRADE_GCC46_COMPATIBILITY
constexpr /* Not constexpr under GCC < 4.7 */
#endif
Range3Di f(c);
CORRADE_COMPARE(f, Range3Di({1, 2, -1}, {-15, 7, 0}));
/* Implicit conversion is not allowed */
CORRADE_VERIFY(!(std::is_convertible<Range<2, Float>, Range<2, Int>>::value));
CORRADE_VERIFY(!(std::is_convertible<Range1D, Range1Di>::value));
CORRADE_VERIFY(!(std::is_convertible<Range2D, Range2Di>::value));
CORRADE_VERIFY(!(std::is_convertible<Range3D, Range3Di>::value));
}
void RangeTest::constructCopy() {
constexpr Range1Di a(3, 23);
constexpr Range2Di b({3, 5}, {23, 78});
constexpr Range3Di c({3, 5, -7}, {23, 78, 2});
constexpr Range1Di d(a);
constexpr Range2Di e(b);
constexpr Range3Di f(c);
CORRADE_COMPARE(d, Range1Di(3, 23));
CORRADE_COMPARE(e, Range2Di({3, 5}, {23, 78}));
CORRADE_COMPARE(f, Range3Di({3, 5, -7}, {23, 78, 2}));
}
void RangeTest::access() {
Range1Di line(34, 47);
Range2Di rect({34, 23}, {47, 30});
Range3Di cube({34, 23, -17}, {47, 30, 12});
constexpr Range1Di cline(34, 47);
constexpr Range2Di crect({34, 23}, {47, 30});
constexpr Range3Di ccube({34, 23, -17}, {47, 30, 12});
CORRADE_COMPARE(line.min(), 34);
CORRADE_COMPARE(cline.min(), 34);
CORRADE_COMPARE(line.max(), 47);
CORRADE_COMPARE(cline.max(), 47);
CORRADE_COMPARE(rect.bottomLeft(), Vector2i(34, 23));
CORRADE_COMPARE(rect.topRight(), Vector2i(47, 30));
constexpr Vector2i bottomLeft = crect.bottomLeft();
constexpr Vector2i topRight = crect.topRight();
CORRADE_COMPARE(bottomLeft, Vector2i(34, 23));
CORRADE_COMPARE(topRight, Vector2i(47, 30));
CORRADE_COMPARE(rect.left(), 34);
CORRADE_COMPARE(rect.right(), 47);
CORRADE_COMPARE(rect.bottom(), 23);
CORRADE_COMPARE(rect.top(), 30);
constexpr Int left2 = crect.left();
constexpr Int right2 = crect.right();
constexpr Int bottom2 = crect.bottom();
constexpr Int top2 = crect.top();
CORRADE_COMPARE(left2, 34);
CORRADE_COMPARE(right2, 47);
CORRADE_COMPARE(bottom2, 23);
CORRADE_COMPARE(top2, 30);
CORRADE_COMPARE(cube.backBottomLeft(), Vector3i(34, 23, -17));
CORRADE_COMPARE(cube.frontTopRight(), Vector3i(47, 30, 12));
constexpr Vector3i backBottomLeft = ccube.backBottomLeft();
constexpr Vector3i frontTopRight = ccube.frontTopRight();
CORRADE_COMPARE(backBottomLeft, Vector3i(34, 23, -17));
CORRADE_COMPARE(frontTopRight, Vector3i(47, 30, 12));
CORRADE_COMPARE(cube.left(), 34);
CORRADE_COMPARE(cube.right(), 47);
CORRADE_COMPARE(cube.bottom(), 23);
CORRADE_COMPARE(cube.top(), 30);
CORRADE_COMPARE(cube.back(), -17);
CORRADE_COMPARE(cube.front(), 12);
constexpr Int left3 = ccube.left();
constexpr Int right3 = ccube.right();
constexpr Int bottom3 = ccube.bottom();
constexpr Int top3 = ccube.top();
constexpr Int back3 = ccube.back();
constexpr Int front3 = ccube.front();
CORRADE_COMPARE(left3, 34);
CORRADE_COMPARE(right3, 47);
CORRADE_COMPARE(bottom3, 23);
CORRADE_COMPARE(top3, 30);
CORRADE_COMPARE(back3, -17);
CORRADE_COMPARE(front3, 12);
CORRADE_COMPARE(rect.bottomRight(), Vector2i(47, 23));
CORRADE_COMPARE(rect.topLeft(), Vector2i(34, 30));
CORRADE_COMPARE(cube.backBottomRight(), Vector3i(47, 23, -17));
CORRADE_COMPARE(cube.backTopLeft(), Vector3i(34, 30, -17));
CORRADE_COMPARE(cube.backTopRight(), Vector3i(47, 30, -17));
CORRADE_COMPARE(cube.frontBottomLeft(), Vector3i(34, 23, 12));
CORRADE_COMPARE(cube.frontBottomRight(), Vector3i(47, 23, 12));
CORRADE_COMPARE(cube.frontTopLeft(), Vector3i(34, 30, 12));
}
void RangeTest::compare() {
CORRADE_VERIFY(Range2Di({34, 23}, {47, 30}) == Range2Di({34, 23}, {47, 30}));
CORRADE_VERIFY(Range2Di({34, 23}, {47, 30}) != Range2Di({34, 23}, {48, 30}));
CORRADE_VERIFY(Range2Di({34, 23}, {47, 30}) != Range2Di({35, 23}, {47, 30}));
CORRADE_VERIFY(Range1D(1.0f, 1.0f) != Range1D(1.0f + TypeTraits<Float>::epsilon()*2, 1.0f));
CORRADE_VERIFY(Range1D(1.0f, 1.0f) != Range1D(1.0f, 1.0f + TypeTraits<Float>::epsilon()*2));
CORRADE_VERIFY(Range1D(1.0f, 1.0f) == Range1D(1.0f + TypeTraits<Float>::epsilon()/2.0f,
1.0f + TypeTraits<Float>::epsilon()/2.0f));
}
void RangeTest::size() {
const Range1Di line(34, 47);
const Range2Di rect({34, 23}, {47, 30});
const Range3Di cube({34, 23, -17}, {47, 30, 12});
CORRADE_COMPARE(line.size(), 13);
CORRADE_COMPARE(rect.size(), Vector2i(13, 7));
CORRADE_COMPARE(cube.size(), Vector3i(13, 7, 29));
CORRADE_COMPARE(rect.sizeX(), 13);
CORRADE_COMPARE(rect.sizeY(), 7);
CORRADE_COMPARE(cube.sizeX(), 13);
CORRADE_COMPARE(cube.sizeY(), 7);
CORRADE_COMPARE(cube.sizeZ(), 29);
}
void RangeTest::translated() {
Range2Di a({34, 23}, {47, 30});
Range2Di b({17, 63}, {30, 70});
CORRADE_COMPARE(a.translated({-17, 40}), b);
CORRADE_COMPARE(a.size(), b.size());
}
template<class T> class BasicRect: public Math::Range<2, T> {
public:
template<class ...U> BasicRect(U&&... args): Math::Range<2, T>{std::forward<U>(args)...} {}
MAGNUM_RANGE_SUBCLASS_IMPLEMENTATION(2, BasicRect, Vector2)
};
typedef BasicRect<Int> Recti;
void RangeTest::subclassTypes() {
const Vector2i a;
CORRADE_VERIFY((std::is_same<decltype(Recti::fromSize(a, a)), Recti>::value));
const Recti r;
CORRADE_VERIFY((std::is_same<decltype(r.translated(a)), Recti>::value));
}
void RangeTest::subclass() {
CORRADE_COMPARE(Recti::fromSize({3, 5}, {23, 78}),
Recti(Vector2i{3, 5}, Vector2i{26, 83}));
CORRADE_COMPARE(Recti(Vector2i{34, 23}, Vector2i{47, 30}).translated({-17, 40}),
Recti(Vector2i{17, 63}, Vector2i{30, 70}));
}
void RangeTest::debug() {
std::ostringstream o;
Debug(&o) << Range2Di({34, 23}, {47, 30});
CORRADE_COMPARE(o.str(), "Range({34, 23}, {47, 30})\n");
}
void RangeTest::configuration() {
Corrade::Utility::Configuration c;
Range2D rect({3.0f, 3.125f}, {9.0f, 9.55f});
std::string value("3 3.125 9 9.55");
c.setValue("rectangle", rect);
CORRADE_COMPARE(c.value("rectangle"), value);
CORRADE_COMPARE(c.value<Range2D>("rectangle"), rect);
}
}}}
CORRADE_TEST_MAIN(Magnum::Math::Test::RangeTest)

10
src/Math/instantiation.cpp

@ -24,6 +24,7 @@
#include "Math/DualComplex.h"
#include "Math/DualQuaternion.h"
#include "Math/Range.h"
namespace Corrade { namespace Utility {
@ -78,6 +79,15 @@ template struct ConfigurationValue<Magnum::Math::Vector<3, Magnum::Double>>;
template struct ConfigurationValue<Magnum::Math::Vector<4, Magnum::Double>>;
#endif
#endif
template struct ConfigurationValue<Magnum::Math::Range<2, Magnum::Float>>;
template struct ConfigurationValue<Magnum::Math::Range<2, Magnum::Int>>;
template struct ConfigurationValue<Magnum::Math::Range<3, Magnum::Float>>;
template struct ConfigurationValue<Magnum::Math::Range<3, Magnum::Int>>;
#ifndef MAGNUM_TARGET_GLES
template struct ConfigurationValue<Magnum::Math::Range<2, Magnum::Double>>;
template struct ConfigurationValue<Magnum::Math::Range<3, Magnum::Double>>;
#endif
#endif
}}

Loading…
Cancel
Save