#ifndef Magnum_Math_Range_h #define Magnum_Math_Range_h /* This file is part of Magnum. Copyright © 2010, 2011, 2012, 2013, 2014 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 "Magnum/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(), @ref center() */ VectorType size() const { return _max - _min; } /** * @brief %Range center * * @see @ref Range2D::centerX(), @ref Range2D::centerY(), * @ref Range3D::centerX(), @ref Range3D::centerY(), * @ref Range3D::centerZ(), @ref size() */ VectorType center() const { return (_min + _max)/T(2); } /** * @brief Translated range * * Translates the minimal and maximal coordinates by given amount. Size * remains the same. * @see @ref padded() */ Range translated(const VectorType& vector) const; /** * @brief Padded rage * * Translates the minimal and maximal coordinates by given amount. * Center remains the same. * @see @ref translated() */ Range padded(const VectorType& padding) const; /** * @brief Scaled range * * Multiplies the minimal and maximal coordinates by given amount. * @see @ref padded() */ Range scaled(const VectorType& scaling) 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); \ } \ Type padded(const VectorType& padding) const { \ return Range::padded(padding); \ } \ Type scaled(const VectorType& scaling) const { \ return Range::scaled(scaling); \ } #endif /** @brief One-dimensional range Convenience alternative to %Range<1, T>. See @ref Range for more information. */ template using Range1D = Range<1, T>; /** @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 /*implicit*/ Range2D() {} /** @copydoc Range(const VectorType&, const VectorType&) */ constexpr /*implicit*/ Range2D(const Vector2& min, const Vector2& max): Range<2, T>(min, max) {} /** @copydoc Range(const Range&) */ constexpr /*implicit*/ 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(); } /** * @brief %Range center on X axis * * @see @ref center() */ T centerX() const { return (Range<2, T>::min().x() + Range<2, T>::max().x())/T(2); } /** * @brief %Range center on Y axis * * @see @ref center() */ T centerY() const { return (Range<2, T>::min().y() + Range<2, T>::max().y())/T(2); } 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 /*implicit*/ Range3D() {} /** @copydoc Range(const VectorType&, const VectorType&) */ constexpr /*implicit*/ Range3D(const Vector3& min, const Vector3& max): Range<3, T>(min, max) {} /** @copydoc Range(const Range&) */ constexpr /*implicit*/ 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(); } /** * * @brief %Range center on X axis * * @see @ref center() */ T centerX() const { return (Range<3, T>::min().x() + Range<3, T>::max().x())/T(2); } /** * @brief %Range center on Y axis * * @see @ref center() */ T centerY() const { return (Range<3, T>::min().y() + Range<3, T>::max().y())/T(2); } /** * @brief %Range center on Z axis * * @see @ref center() */ T centerZ() const { return (Range<3, T>::min().z() + Range<3, T>::max().z())/T(2); } 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}; } template Range Range::padded(const VectorType& padding) const { return {_min - padding, _max + padding}; } template Range Range::scaled(const VectorType& scaling) const { return {_min*scaling, _max*scaling}; } }} 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