mirror of https://github.com/mosra/magnum.git
7 changed files with 796 additions and 1 deletions
@ -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 |
||||||
@ -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) |
||||||
Loading…
Reference in new issue