#ifndef Magnum_Math_Vector_h #define Magnum_Math_Vector_h /* Copyright © 2010, 2011, 2012 Vladimír Vondruš This file is part of Magnum. Magnum is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3 only, as published by the Free Software Foundation. Magnum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License version 3 for more details. */ /** @file * @brief Class Magnum::Math::Vector */ #include #include #include #include #include #include "Math/BoolVector.h" #include "Math/MathTypeTraits.h" #include "magnumVisibility.h" namespace Magnum { namespace Math { #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template struct Sequence {}; /* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */ template struct GenerateSequence: GenerateSequence {}; template struct GenerateSequence<0, sequence...> { typedef Sequence Type; }; } #endif /** @brief %Vector @tparam size %Vector size @tparam T Data type See @ref matrix-vector for brief introduction. @configurationvalueref{Magnum::Math::Vector} */ template class Vector { static_assert(size != 0, "Vector cannot have zero elements"); template friend class Vector; public: typedef T Type; /**< @brief Data type */ const static std::size_t Size = size; /**< @brief %Vector size */ /** * @brief %Vector from array * @return Reference to the data as if it was Vector, thus doesn't * perform any copying. * * @attention Use with caution, the function doesn't check whether the * array is long enough. */ inline constexpr static Vector& from(T* data) { return *reinterpret_cast*>(data); } /** @overload */ inline constexpr static const Vector& from(const T* data) { return *reinterpret_cast*>(data); } /** * @brief Dot product * * @f[ * \boldsymbol a \cdot \boldsymbol b = \sum_{i=0}^{n-1} \boldsymbol a_i \boldsymbol b_i * @f] * @see dot() const */ static T dot(const Vector& a, const Vector& b) { T out(0); for(std::size_t i = 0; i != size; ++i) out += a[i]*b[i]; return out; } /** * @brief Angle between normalized vectors (in radians) * * Expects that both vectors are normalized. @f[ * \theta = acos \left( \frac{\boldsymbol a \cdot \boldsymbol b}{|\boldsymbol a| \cdot |\boldsymbol b|} \right) = acos (\boldsymbol a \cdot \boldsymbol b) * @f] */ inline static T angle(const Vector& normalizedA, const Vector& normalizedB) { CORRADE_ASSERT(MathTypeTraits::equals(normalizedA.dot(), T(1)) && MathTypeTraits::equals(normalizedB.dot(), T(1)), "Math::Vector::angle(): vectors must be normalized", std::numeric_limits::quiet_NaN()); return std::acos(dot(normalizedA, normalizedB)); } /** * @brief Linear interpolation of two vectors * @param a First vector * @param b Second vector * @param t Interpolation phase (from range @f$ [0; 1] @f$) * * The interpolation is done as in following: @f[ * \boldsymbol v_{LERP} = (1 - t) \boldsymbol v_A + t \boldsymbol v_B * @f] * @todo http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/ * (when SIMD is in place) */ template inline static Vector lerp(const Vector& a, const Vector& b, U t) { return (U(1) - t)*a + t*b; } /** @brief Construct zero-filled vector */ inline constexpr /*implicit*/ Vector(): _data() {} /** @todo Creating Vector from combination of vector and scalar types */ /** * @brief Construct vector from values * @param first First value * @param next Next values */ #ifdef DOXYGEN_GENERATING_OUTPUT template inline constexpr /*implicit*/ Vector(T first, U... next); #else template::type> inline constexpr /*implicit*/ Vector(T first, U... next): _data{first, next...} {} #endif /** @brief Construct vector with one value for all fields */ #ifdef DOXYGEN_GENERATING_OUTPUT inline explicit Vector(T value); #else template::value && size != 1, T>::type> inline explicit Vector(U value) { #endif for(std::size_t i = 0; i != size; ++i) _data[i] = value; } /** * @brief Construct vector from another of different type * * Performs only default casting on the values, no rounding or * anything else. Example usage: * @code * Vector<4, float> floatingPoint(1.3f, 2.7f, -15.0f, 7.0f); * Vector<4, std::int8_t> integral(floatingPoint); * // integral == {1, 2, -15, 7} * @endcode */ template inline constexpr explicit Vector(const Vector& other): Vector(typename Implementation::GenerateSequence::Type(), other) {} /** @brief Copy constructor */ inline constexpr Vector(const Vector&) = default; /** @brief Assignment operator */ inline Vector& operator=(const Vector&) = default; /** * @brief Raw data * @return One-dimensional array of `size*size` length in column-major * order. * * @see operator[] */ inline T* data() { return _data; } inline constexpr const T* data() const { return _data; } /**< @overload */ /** * @brief Value at given position * * @see data() */ inline T& operator[](std::size_t pos) { return _data[pos]; } inline constexpr T operator[](std::size_t pos) const { return _data[pos]; } /**< @overload */ /** @brief Equality comparison */ inline bool operator==(const Vector& other) const { for(std::size_t i = 0; i != size; ++i) if(!MathTypeTraits::equals(_data[i], other._data[i])) return false; return true; } /** @brief Non-equality comparison */ inline bool operator!=(const Vector& other) const { return !operator==(other); } /** @brief Component-wise less than */ inline BoolVector operator<(const Vector& other) const { BoolVector out; for(std::size_t i = 0; i != size; ++i) out.set(i, _data[i] < other._data[i]); return out; } /** @brief Component-wise less than or equal */ inline BoolVector operator<=(const Vector& other) const { BoolVector out; for(std::size_t i = 0; i != size; ++i) out.set(i, _data[i] <= other._data[i]); return out; } /** @brief Component-wise greater than or equal */ inline BoolVector operator>=(const Vector& other) const { BoolVector out; for(std::size_t i = 0; i != size; ++i) out.set(i, _data[i] >= other._data[i]); return out; } /** @brief Component-wise greater than */ inline BoolVector operator>(const Vector& other) const { BoolVector out; for(std::size_t i = 0; i != size; ++i) out.set(i, _data[i] > other._data[i]); return out; } /** * @brief Negated vector * * The computation is done in-place. @f[ * \boldsymbol a_i = -\boldsymbol a_i * @f] */ Vector operator-() const { Vector out; for(std::size_t i = 0; i != size; ++i) out._data[i] = -_data[i]; return out; } /** * @brief Add and assign vector * * The computation is done in-place. @f[ * \boldsymbol a_i = \boldsymbol a_i + \boldsymbol b_i * @f] */ Vector& operator+=(const Vector& other) { for(std::size_t i = 0; i != size; ++i) _data[i] += other._data[i]; return *this; } /** * @brief Add vector * * @see operator+=() */ inline Vector operator+(const Vector& other) const { return Vector(*this) += other; } /** * @brief Subtract and assign vector * * The computation is done in-place. @f[ * \boldsymbol a_i = \boldsymbol a_i - \boldsymbol b_i * @f] */ Vector& operator-=(const Vector& other) { for(std::size_t i = 0; i != size; ++i) _data[i] -= other._data[i]; return *this; } /** * @brief Subtract vector * * @see operator-=() */ inline Vector operator-(const Vector& other) const { return Vector(*this) -= other; } /** * @brief Multiply vector with number and assign * * The computation is done in-place. @f[ * \boldsymbol a_i = b \boldsymbol a_i * @f] */ #ifdef DOXYGEN_GENERATING_OUTPUT template Vector& operator*=(U number) { #else template inline typename std::enable_if::value, Vector&>::type operator*=(U number) { #endif for(std::size_t i = 0; i != size; ++i) _data[i] *= number; return *this; } /** * @brief Multiply vector with number * * @see operator*=(U), operator*(U, const Vector&) */ #ifdef DOXYGEN_GENERATING_OUTPUT template inline Vector operator*(U number) const { #else template inline typename std::enable_if::value, Vector>::type operator*(U number) const { #endif return Vector(*this) *= number; } /** * @brief Divide vector with number and assign * * The computation is done in-place. @f[ * \boldsymbol a_i = \frac{\boldsymbol a_i} b * @f] */ #ifdef DOXYGEN_GENERATING_OUTPUT template Vector& operator/=(U number) { #else template inline typename std::enable_if::value, Vector&>::type operator/=(U number) { #endif for(std::size_t i = 0; i != size; ++i) _data[i] /= number; return *this; } /** * @brief Divide vector with number * * @see operator/=(), operator/(U, const Vector&) */ #ifdef DOXYGEN_GENERATING_OUTPUT template inline Vector operator/(U number) const { #else template inline typename std::enable_if::value, Vector>::type operator/(U number) const { #endif return Vector(*this) /= number; } /** * @brief Multiply vector component-wise and assign * * The computation is done in-place. @f[ * \boldsymbol a_i = \boldsymbol a_i \boldsymbol b_i * @f] */ template Vector& operator*=(const Vector& other) { for(std::size_t i = 0; i != size; ++i) _data[i] *= other._data[i]; return *this; } /** * @brief Multiply vector component-wise * * @see operator*=(const Vector&) */ template inline Vector operator*(const Vector& other) const { return Vector(*this) *= other; } /** * @brief Divide vector component-wise and assign * * The computation is done in-place. @f[ * \boldsymbol a_i = \frac{\boldsymbol a_i}{\boldsymbol b_i} * @f] */ template Vector& operator/=(const Vector& other) { for(std::size_t i = 0; i != size; ++i) _data[i] /= other._data[i]; return *this; } /** * @brief Divide vector component-wise * * @see operator/=(const Vector&) */ template inline Vector operator/(const Vector& other) const { return Vector(*this) /= other; } /** * @brief Dot product of the vector * * Should be used instead of length() for comparing vector length with * other values, because it doesn't compute the square root. @f[ * \boldsymbol a \cdot \boldsymbol a = \sum_{i=0}^{n-1} \boldsymbol a_i^2 * @f] * @see dot(const Vector&, const Vector&) */ inline T dot() const { return dot(*this, *this); } /** * @brief %Vector length * * @f[ * |\boldsymbol a| = \sqrt{\boldsymbol a \cdot \boldsymbol a} * @f] * @see dot() const */ inline T length() const { return std::sqrt(dot()); } /** @brief Normalized vector (of length 1) */ inline Vector normalized() const { return *this/length(); } /** * @brief %Vector projected onto another * * Returns vector projected onto line defined by @p other. @f[ * \boldsymbol a_1 = \frac{\boldsymbol a \cdot \boldsymbol b}{\boldsymbol b \cdot \boldsymbol b} \boldsymbol b * @f] */ inline Vector projected(const Vector& other) const { return other*dot(*this, other)/other.dot(); } /** @brief Sum of values in the vector */ T sum() const { T out(_data[0]); for(std::size_t i = 1; i != size; ++i) out += _data[i]; return out; } /** @brief Product of values in the vector */ T product() const { T out(_data[0]); for(std::size_t i = 1; i != size; ++i) out *= _data[i]; return out; } /** @brief Minimal value in the vector */ T min() const { T out(_data[0]); for(std::size_t i = 1; i != size; ++i) out = std::min(out, _data[i]); return out; } /** @brief Minimal absolute value in the vector */ T minAbs() const { T out(std::abs(_data[0])); for(std::size_t i = 1; i != size; ++i) out = std::min(out, std::abs(_data[i])); return out; } /** @brief Maximal value in the vector */ T max() const { T out(_data[0]); for(std::size_t i = 1; i != size; ++i) out = std::max(out, _data[i]); return out; } /** @brief Maximal absolute value in the vector */ T maxAbs() const { T out(std::abs(_data[0])); for(std::size_t i = 1; i != size; ++i) out = std::max(out, std::abs(_data[i])); return out; } private: /* Implementation for Vector::Vector(const Vector&) */ template inline constexpr explicit Vector(Implementation::Sequence, const Vector& vector): _data{T(vector.data()[sequence])...} {} T _data[size]; }; /** @relates Vector @brief Multiply number with vector Same as Vector::operator*(U) const. */ #ifdef DOXYGEN_GENERATING_OUTPUT template inline Vector operator*(U number, const Vector& vector) { #else template inline typename std::enable_if::value, Vector>::type operator*(U number, const Vector& vector) { #endif return vector*number; } /** @relates Vector @brief Divide vector with number and invert @f[ \boldsymbol c_i = \frac b {\boldsymbol a_i} @f] @see Vector::operator/() */ #ifdef DOXYGEN_GENERATING_OUTPUT template inline Vector operator/(U number, const Vector& vector) { #else template inline typename std::enable_if::value, Vector>::type operator/(U number, const Vector& vector) { #endif Vector out; for(std::size_t i = 0; i != size; ++i) out[i] = number/vector[i]; return out; } /** @debugoperator{Magnum::Math::Vector} */ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector& value) { debug << "Vector("; debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); for(std::size_t i = 0; i != size; ++i) { if(i != 0) debug << ", "; debug << value[i]; } debug << ")"; debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); return debug; } /* Explicit instantiation for types used in OpenGL */ #ifndef DOXYGEN_GENERATING_OUTPUT extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<2, float>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<3, float>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<4, float>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<2, int>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<3, int>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<4, int>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<2, unsigned int>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<3, unsigned int>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<4, unsigned int>&); #ifndef MAGNUM_TARGET_GLES extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<2, double>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<3, double>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Vector<4, double>&); #endif #endif #ifndef DOXYGEN_GENERATING_OUTPUT #define MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Type, size) \ inline constexpr static Type& from(T* data) { \ return *reinterpret_cast*>(data); \ } \ inline constexpr static const Type& from(const T* data) { \ return *reinterpret_cast*>(data); \ } \ template inline static const Type lerp(const Math::Vector& a, const Math::Vector& b, U t) { \ return Math::Vector::lerp(a, b, t); \ } \ \ inline Type& operator=(const Type& other) { \ Math::Vector::operator=(other); \ return *this; \ } \ \ inline Type operator-() const { \ return Math::Vector::operator-(); \ } \ inline Type& operator+=(const Math::Vector& other) { \ Math::Vector::operator+=(other); \ return *this; \ } \ inline Type operator+(const Math::Vector& other) const { \ return Math::Vector::operator+(other); \ } \ inline Type& operator-=(const Math::Vector& other) { \ Math::Vector::operator-=(other); \ return *this; \ } \ inline Type operator-(const Math::Vector& other) const { \ return Math::Vector::operator-(other); \ } \ template inline typename std::enable_if::value, Type&>::type operator*=(U number) { \ Math::Vector::operator*=(number); \ return *this; \ } \ template inline typename std::enable_if::value, Type>::type operator*(U number) const { \ return Math::Vector::operator*(number); \ } \ template inline typename std::enable_if::value, Type&>::type operator/=(U number) { \ Math::Vector::operator/=(number); \ return *this; \ } \ template inline typename std::enable_if::value, Type>::type operator/(U number) const { \ return Math::Vector::operator/(number); \ } \ template inline Type& operator*=(const Math::Vector& other) { \ Math::Vector::operator*=(other); \ return *this; \ } \ template inline Type operator*(const Math::Vector& other) const { \ return Math::Vector::operator*(other); \ } \ template inline Type& operator/=(const Math::Vector& other) { \ Math::Vector::operator/=(other); \ return *this; \ } \ template inline Type operator/(const Math::Vector& other) const { \ return Math::Vector::operator/(other); \ } \ \ inline Type normalized() const { return Math::Vector::normalized(); } \ inline Type projected(const Math::Vector& other) const { \ return Math::Vector::projected(other); \ } #define MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \ template inline typename std::enable_if::value, Type>::type operator*(U number, const Type& vector) { \ return number*Math::Vector(vector); \ } \ template inline typename std::enable_if::value, Type>::type operator/(U number, const Type& vector) { \ return number/Math::Vector(vector); \ } #endif }} namespace Corrade { namespace Utility { /** @configurationvalue{Magnum::Math::RectangularMatrix} */ template struct ConfigurationValue> { ConfigurationValue() = delete; /** @brief Writes elements separated with spaces */ static std::string toString(const Magnum::Math::Vector& value, ConfigurationValueFlags flags) { std::string output; for(std::size_t i = 0; i != size; ++i) { if(!output.empty()) output += ' '; output += ConfigurationValue::toString(value[i], flags); } return output; } /** @brief Reads elements separated with whitespace */ static Magnum::Math::Vector fromString(const std::string& stringValue, ConfigurationValueFlags flags) { Magnum::Math::Vector result; std::size_t oldpos = 0, pos = std::string::npos, i = 0; do { pos = stringValue.find(' ', oldpos); std::string part = stringValue.substr(oldpos, pos-oldpos); if(!part.empty()) { result[i] = ConfigurationValue::fromString(part, flags); ++i; } oldpos = pos+1; } while(pos != std::string::npos); return result; } }; #ifndef DOXYGEN_GENERATING_OUTPUT /* Vectors */ extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; 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>; extern template struct MAGNUM_EXPORT ConfigurationValue>; #endif #endif }} #endif