#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 "RectangularMatrix.h" namespace Magnum { namespace Math { /** @brief %Vector @tparam size %Vector size @tparam T Data type See @ref matrix-vector for brief introduction. @configurationvalueref{Magnum::Math::Vector} */ template class Vector: public RectangularMatrix<1, size, T> { public: const static std::size_t Size = size; /**< @brief %Vector size */ /** * @brief Dot product * * @f[ * a \cdot b = \sum_{i=0}^{n-1} a_ib_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 * * @f[ * \phi = acos \left(\frac{a \cdot b}{|a| \cdot |b|} \right) * @f] * @attention Assertion fails on non-normalized vectors and NaN is * returned. */ 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 Default constructor */ inline constexpr Vector() {} /** @todo Creating Vector from combination of vector and scalar types */ /** * @brief Initializer-list constructor * @param first First value * @param next Next values */ #ifndef DOXYGEN_GENERATING_OUTPUT template inline constexpr Vector(T first, U... next): RectangularMatrix<1, size, T>(first, next...) {} #else template inline constexpr Vector(T first, U... next); #endif /** * @brief Constructor * @param value Value for all fields */ #ifndef DOXYGEN_GENERATING_OUTPUT template inline explicit Vector(typename std::enable_if::value && size != 1, U>::type value) { #else inline explicit Vector(T value) { #endif for(std::size_t i = 0; i != size; ++i) (*this)[i] = value; } /** @brief Copy constructor */ inline constexpr Vector(const RectangularMatrix<1, size, T>& other): RectangularMatrix<1, size, T>(other) {} /** @brief Value at given position */ inline T& operator[](std::size_t pos) { return RectangularMatrix<1, size, T>::_data[pos]; } inline constexpr T operator[](std::size_t pos) const { return RectangularMatrix<1, size, T>::_data[pos]; } /**< @overload */ /** * @brief Multiply vector component-wise * * @see operator*=(const Vector&) */ inline Vector operator*(const Vector& other) const { return Vector(*this)*=other; } /** * @brief Multiply vector component-wise and assign * * More efficient than operator*(const Vector&) const, * because it does the computation in-place. */ Vector& operator*=(const Vector& other) { for(std::size_t i = 0; i != size; ++i) (*this)[i] *= other[i]; return *this; } /** * @brief Divide vector component-wise * * @see operator/=(const Vector&) */ inline Vector operator/(const Vector& other) const { return Vector(*this)/=other; } /** * @brief Divide vector component-wise and assign * * More efficient than operator/(const Vector&) const, * because it does the computation in-place. */ Vector& operator/=(const Vector& other) { for(std::size_t i = 0; i != size; ++i) (*this)[i] /= other[i]; return *this; } /** * @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, just the * dot product: @f$ a \cdot a < length \cdot length @f$ is faster * than @f$ \sqrt{a \cdot a} < length @f$. * * @see dot(const Vector&, const Vector&) */ inline T dot() const { return dot(*this, *this); } /** * @brief %Vector length * * @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 Sum of values in the vector */ T sum() const { T out(0); for(std::size_t i = 0; i != size; ++i) out += (*this)[i]; return out; } /** @brief Product of values in the vector */ T product() const { T out(1); for(std::size_t i = 0; i != size; ++i) out *= (*this)[i]; return out; } /** @brief Minimal value in the vector */ T min() const { T out((*this)[0]); for(std::size_t i = 1; i != size; ++i) out = std::min(out, (*this)[i]); return out; } /** @brief Maximal value in the vector */ T max() const { T out((*this)[0]); for(std::size_t i = 1; i != size; ++i) out = std::max(out, (*this)[i]); return out; } #ifndef DOXYGEN_GENERATING_OUTPUT /* Reimplementation of functions to return correct type */ template inline RectangularMatrix operator*(const RectangularMatrix& other) const { return RectangularMatrix<1, size, T>::operator*(other); } MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(1, size, Vector) MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, size, Vector) #endif private: /* Hiding unused things from RectangularMatrix */ using RectangularMatrix<1, size, T>::Cols; using RectangularMatrix<1, size, T>::Rows; using RectangularMatrix<1, size, T>::operator[]; using RectangularMatrix<1, size, T>::operator(); }; #ifndef DOXYGEN_GENERATING_OUTPUT template inline typename std::enable_if::value, Vector>::type operator*(U number, const Vector& vector) { return number*RectangularMatrix<1, size, T>(vector); } template inline typename std::enable_if::value, Vector>::type operator/(U number, const Vector& vector) { return number/RectangularMatrix<1, size, T>(vector); } #endif /** @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 << typename MathTypeTraits::NumericType(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 constexpr static Type from(const Math::Vector& other) { \ return Math::Vector::from(other); \ } \ \ inline Type& operator=(const Type& other) { \ Math::Vector::operator=(other); \ return *this; \ } \ \ template inline Math::RectangularMatrix operator*(const Math::RectangularMatrix& other) const { \ return Math::Vector::operator*(other); \ } \ 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); \ } \ inline Type& operator/=(const Math::Vector& other) { \ Math::Vector::operator/=(other); \ return *this; \ } \ \ inline Type normalized() const { return Math::Vector::normalized(); } #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::Vector} */ template struct ConfigurationValue>: public ConfigurationValue> {}; }} #endif