From 714c243dd6bbb519e0b7dc1321b3305874255248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 28 Nov 2013 20:22:06 +0100 Subject: [PATCH] Math: added generic Range class. Will replace Geometry::Rectangle. --- src/Magnum.h | 39 ++++ src/Math/CMakeLists.txt | 1 + src/Math/Math.h | 10 +- src/Math/Range.h | 425 +++++++++++++++++++++++++++++++++++ src/Math/Test/CMakeLists.txt | 1 + src/Math/Test/RangeTest.cpp | 311 +++++++++++++++++++++++++ src/Math/instantiation.cpp | 10 + 7 files changed, 796 insertions(+), 1 deletion(-) create mode 100644 src/Math/Range.h create mode 100644 src/Math/Test/RangeTest.cpp diff --git a/src/Magnum.h b/src/Magnum.h index 0b38b8e8f..59f9b1773 100644 --- a/src/Magnum.h +++ b/src/Magnum.h @@ -301,6 +301,32 @@ typedef Math::Deg Deg; /** @brief Angle in float radians */ typedef Math::Rad Rad; +/** @brief Float 1D range */ +#ifndef CORRADE_GCC46_COMPATIBILITY +typedef Math::Range1D Range1D; +#else +typedef Math::Range<1, Float> Range1D; +#endif + +/** @brief Float 2D range */ +typedef Math::Range2D Range2D; + +/** @brief Float 3D range */ +typedef Math::Range3D Range3D; + +/** @brief Signed integer 1D range */ +#ifndef CORRADE_GCC46_COMPATIBILITY +typedef Math::Range1D Range1Di; +#else +typedef Math::Range<1, Int> Range1Di; +#endif + +/** @brief Signed integer 2D range */ +typedef Math::Range2D Range2Di; + +/** @brief Signed integer 3D range */ +typedef Math::Range3D Range3Di; + /** @brief Float rectangle */ typedef Math::Geometry::Rectangle Rectangle; @@ -444,6 +470,19 @@ typedef Math::Deg Degd; /** @brief Angle in double radians */ typedef Math::Rad Radd; +/** @brief Double 1D range */ +#ifndef CORRADE_GCC46_COMPATIBILITY +typedef Math::Range1D Range1Dd; +#else +typedef Math::Range<1, Double> Range1Dd; +#endif + +/** @brief Double 2D range */ +typedef Math::Range2D Range2Dd; + +/** @brief Double 3D range */ +typedef Math::Range3D Range3Dd; + /** @brief Double rectangle */ typedef Math::Geometry::Rectangle Rectangled; diff --git a/src/Math/CMakeLists.txt b/src/Math/CMakeLists.txt index 9552fd85c..3fe8950f2 100644 --- a/src/Math/CMakeLists.txt +++ b/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 diff --git a/src/Math/Math.h b/src/Math/Math.h index ab239d11b..9a53412b8 100644 --- a/src/Math/Math.h +++ b/src/Math/Math.h @@ -29,8 +29,9 @@ */ #include +#include -#include "corradeConfigure.h" +#include "Types.h" namespace Magnum { namespace Math { @@ -74,6 +75,13 @@ template class Vector2; template class Vector3; template class Vector4; +template class Range; +#ifndef CORRADE_GCC46_COMPATIBILITY +template using Range1D = Range<1, T>; +#endif +template class Range2D; +template class Range3D; + namespace Geometry { template class Rectangle; } diff --git a/src/Math/Range.h b/src/Math/Range.h new file mode 100644 index 000000000..e2fb51f23 --- /dev/null +++ b/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š + + 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 struct RangeTraits; + + template struct RangeTraits<1, T> { typedef Vector<1, T> Type; }; + template struct RangeTraits<2, T> { typedef Vector2 Type; }; + template struct RangeTraits<3, T> { typedef Vector3 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 class Range { + template friend class Range; + + public: + /** + * @brief Underlying vector type + * + * `T` in 1D, @ref Vector2 in 2D, @ref Vector3 in 3D. + */ + typedef typename Implementation::RangeTraits::Type VectorType; + + /** + * Create range from minimal coordinates and size + * @param min Minimal coordinates + * @param size Range size + */ + static Range 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&) = 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 floatingPoint({1.3f, 2.7f}, {-15.0f, 7.0f}); + * Range2D integral(floatingPoint); // {{1, 2}, {-15, 7}} + * @endcode + */ + template constexpr explicit Range(const Range& other): _min(other._min), _max(other._max) {} + + /** @brief Equality comparison */ + constexpr bool operator==(const Range& other) const { + return _min == other._min && _max == other._max; + } + + /** @brief Non-equality comparison */ + constexpr bool operator!=(const Range& 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 translated(const VectorType& vector) const; + + private: + VectorType _min, _max; +}; + +#ifndef DOXYGEN_GENERATING_OUTPUT +#define MAGNUM_RANGE_SUBCLASS_IMPLEMENTATION(dimensions, Type, VectorType) \ + static Type fromSize(const VectorType& min, const VectorType& size) { \ + return Range::fromSize(min, size); \ + } \ + Type translated(const VectorType& vector) const { \ + return Range::translated(vector); \ + } +#endif + +#ifndef CORRADE_GCC46_COMPATIBILITY +/** +@brief One-dimensional range + +Convenience alternative to %Range<1, T>. See @ref Range for more +information. +@note Not available on GCC < 4.7. Use %Range<1, T> instead. +*/ +template using Range1D = Range<1, T>; +#endif + +/** +@brief Two-dimensional range + +See @ref Range for more information. +@see @ref Range1D, @ref Range3D +*/ +template class Range2D: public Range<2, T> { + public: + /** @copydoc Range() */ + constexpr Range2D() = default; + + /** @copydoc Range(const VectorType&, const VectorType&) */ + constexpr Range2D(const Vector2& min, const Vector2& 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&) */ + template constexpr explicit Range2D(const Range2D& other): Range<2, T>(other) {} + + /** + * @brief Bottom left corner + * + * Equivalent to @ref min(). + */ + Vector2& bottomLeft() { return Range<2, T>::min(); } + constexpr Vector2 bottomLeft() const { return Range<2, T>::min(); } /**< @overload */ + + /** @brief Bottom right corner */ + constexpr Vector2 bottomRight() const { + return {Range<2, T>::max().x(), Range<2, T>::min().y()}; + } + + /** @brief Top left corner */ + constexpr Vector2 topLeft() const { + return {Range<2, T>::min().x(), Range<2, T>::max().y()}; + } + + /** + * @brief Top right corner + * + * Equivalent to @ref max(). + */ + Vector2& topRight() { return Range<2, T>::max(); } + constexpr Vector2 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 Range3D: public Range<3, T> { + public: + /** @copydoc Range() */ + constexpr Range3D() = default; + + /** @copydoc Range(const VectorType&, const VectorType&) */ + constexpr Range3D(const Vector3& min, const Vector3& 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&) */ + template constexpr explicit Range3D(const Range3D& other): Range<3, T>(other) {} + + /** + * @brief Back bottom left corner + * + * Equivalent to @ref min(). + */ + Vector3& backBottomLeft() { return Range<3, T>::min(); } + constexpr Vector3 backBottomLeft() const { return Range<3, T>::min(); } /**< @overload */ + + /** @brief Back bottom right corner */ + constexpr Vector3 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 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 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& frontTopRight() { return Range<3, T>::max(); } + constexpr Vector3 frontTopRight() const { return Range<3, T>::max(); } /**< @overload */ + + /** @brief Front top left corner */ + constexpr Vector3 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 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 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 Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Range& 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 Range Range::translated(const VectorType& vector) const { + return {_min + vector, _max + vector}; +} + +}} + +namespace Corrade { namespace Utility { + +/** @configurationvalue{Magnum::Math::Range} */ +template struct ConfigurationValue> { + ConfigurationValue() = delete; + + /** @brief Writes elements separated with spaces */ + static std::string toString(const Magnum::Math::Range& value, const ConfigurationValueFlags flags) { + return ConfigurationValue>::toString( + reinterpret_cast&>(value), flags); + } + + /** @brief Reads elements separated with whitespace */ + static Magnum::Math::Range fromString(const std::string& stringValue, const ConfigurationValueFlags flags) { + const auto vec = ConfigurationValue>::fromString(stringValue, flags); + return *reinterpret_cast*>(vec.data()); + } +}; + +/** @configurationvalue{Magnum::Math::Range2D} */ +template struct ConfigurationValue>: public ConfigurationValue> {}; + +/** @configurationvalue{Magnum::Math::Range3D} */ +template struct ConfigurationValue>: public ConfigurationValue> {}; + +#ifndef DOXYGEN_GENERATING_OUTPUT +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +#ifndef MAGNUM_TARGET_GLES +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +#endif +#endif + +}} + +#endif diff --git a/src/Math/Test/CMakeLists.txt b/src/Math/Test/CMakeLists.txt index 65fe5141c..4dadcfcdf 100644 --- a/src/Math/Test/CMakeLists.txt +++ b/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) diff --git a/src/Math/Test/RangeTest.cpp b/src/Math/Test/RangeTest.cpp new file mode 100644 index 000000000..c0e4caa7a --- /dev/null +++ b/src/Math/Test/RangeTest.cpp @@ -0,0 +1,311 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + 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 +#include +#include + +#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 Range2D; +typedef Math::Range3D Range3D; +typedef Math::Range1D Range1Di; +typedef Math::Range2D Range2Di; +typedef Math::Range3D Range3Di; +typedef Vector2 Vector2i; +typedef Vector3 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, Int>>::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::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::epsilon()*2, 1.0f)); + CORRADE_VERIFY(Range1D(1.0f, 1.0f) != Range1D(1.0f, 1.0f + TypeTraits::epsilon()*2)); + CORRADE_VERIFY(Range1D(1.0f, 1.0f) == Range1D(1.0f + TypeTraits::epsilon()/2.0f, + 1.0f + TypeTraits::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 BasicRect: public Math::Range<2, T> { + public: + template BasicRect(U&&... args): Math::Range<2, T>{std::forward(args)...} {} + + MAGNUM_RANGE_SUBCLASS_IMPLEMENTATION(2, BasicRect, Vector2) +}; + +typedef BasicRect Recti; + +void RangeTest::subclassTypes() { + const Vector2i a; + CORRADE_VERIFY((std::is_same::value)); + + const Recti r; + CORRADE_VERIFY((std::is_same::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("rectangle"), rect); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Math::Test::RangeTest) diff --git a/src/Math/instantiation.cpp b/src/Math/instantiation.cpp index fcb4772a8..27957187f 100644 --- a/src/Math/instantiation.cpp +++ b/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>; template struct ConfigurationValue>; #endif #endif + +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +#ifndef MAGNUM_TARGET_GLES +template struct ConfigurationValue>; +template struct ConfigurationValue>; +#endif #endif }}