#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 "MathTypeTraits.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 */ template class Vector { static_assert(size != 0, "Vector cannot have zero elements"); public: const static size_t Size = size; /**< @brief %Vector size */ typedef T Type; /**< @brief %Vector data type */ /** * @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[ * a \cdot b = \sum_{i=0}^{n-1} a_ib_i * @f] */ static T dot(const Vector& a, const Vector& b) { T out(0); for(size_t i = 0; i != size; ++i) out += a[i]*b[i]; return out; } /** * @brief Angle between vectors * * @f[ * \phi = \frac{a \cdot b}{|a| \cdot |b|} * @f] * * @todo optimize - Assume the vectors are normalized? */ inline static T angle(const Vector& a, const Vector& b) { return std::acos(dot(a, b)/(a.length()*b.length())); } /** @brief Default constructor */ inline constexpr Vector(): _data() {} /** * @brief Initializer-list constructor * @param first First value * @param next Next values * * @todoc Remove workaround when Doxygen supports uniform initialization */ #ifndef DOXYGEN_GENERATING_OUTPUT template inline constexpr Vector(T first, U... next): _data{first, next...} { static_assert(sizeof...(next)+1 == size, "Improper number of arguments passed to Vector constructor"); } #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(size_t i = 0; i != size; ++i) _data[i] = value; } /** @brief Copy constructor */ inline constexpr Vector(const Vector&) = default; /** @brief Assignment operator */ inline Vector& operator=(const Vector&) = default; /** * @brief Raw data * @return Array with the same size as the vector */ inline T* data() { return _data; } inline constexpr const T* data() const { return _data; } /**< @overload */ /** @brief Value at given position */ inline T& operator[](size_t pos) { return _data[pos]; } inline constexpr T operator[](size_t pos) const { return _data[pos]; } /**< @overload */ /** @brief Equality operator */ inline bool operator==(const Vector& other) const { for(size_t pos = 0; pos != size; ++pos) if(!MathTypeTraits::equals((*this)[pos], other[pos])) return false; return true; } /** @brief Non-equality operator */ inline bool operator!=(const Vector& other) const { return !operator==(other); } /** * @brief Multiply vector * * Note that corresponding operator with swapped type order * (multiplying number with vector) is not available, because it would * cause ambiguity in some cases. */ template inline Vector operator*(U number) const { return Vector(*this)*=number; } /** * @brief Multiply and assign vector * * More efficient than operator*(), because it does the computation * in-place. */ template Vector& operator*=(U number) { for(size_t i = 0; i != size; ++i) (*this)[i] *= number; return *this; } /** @brief Divide vector */ template inline Vector operator/(U number) const { return Vector(*this)/=number; } /** * @brief Divide and assign vector * * More efficient than operator/(), because it does the computation * in-place. */ template Vector& operator/=(U number) { for(size_t i = 0; i != size; ++i) (*this)[i] /= number; return *this; } /** @brief Add two vectors */ inline Vector operator+(const Vector& other) const { return Vector(*this)+=other; } /** * @brief Add and assign vector * * More efficient than operator+(), because it does the computation * in-place. */ Vector& operator+=(const Vector& other) { for(size_t i = 0; i != size; ++i) (*this)[i] += other[i]; return *this; } /** @brief Substract two vectors */ inline Vector operator-(const Vector& other) const { return Vector(*this)-=other; } /** * @brief Substract and assign vector * * More efficient than operator-(), because it does the computation * in-place. */ Vector& operator-=(const Vector& other) { for(size_t i = 0; i != size; ++i) (*this)[i] -= other[i]; return *this; } /** @brief Negative vector */ Vector operator-() const { Vector out; for(size_t i = 0; i != size; ++i) out[i] = -(*this)[i]; return out; } /** * @brief %Vector length * * @see lengthSquared() */ inline T length() const { return std::sqrt(dot(*this, *this)); } /** * @brief %Vector length squared * * More efficient than 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$. */ inline T lengthSquared() const { return dot(*this, *this); } /** @brief Normalized vector (of length 1) */ inline Vector normalized() const { return *this/length(); } /** @brief Product of values in the vector */ T product() const { T out = 1; for(size_t i = 0; i != size; ++i) out *= (*this)[i]; return out; } private: T _data[size]; }; /** @debugoperator{Vector} */ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Vector& value) { debug << "Vector("; debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); for(size_t i = 0; i != size; ++i) { if(i != 0) debug << ", "; debug << value[i]; } debug << ')'; debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); return debug; } #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); \ } \ \ inline Type& operator=(const Type& other) { \ Vector::operator=(other); \ return *this; \ } \ \ template inline Type operator*(U number) const { \ return Vector::operator*(number); \ } \ template inline Type& operator*=(U number) { \ Vector::operator*=(number); \ return *this; \ } \ template inline Type operator/(U number) const { \ return Vector::operator/(number); \ } \ template inline Type& operator/=(U number) { \ Vector::operator/=(number); \ return *this; \ } \ \ inline Type operator+(const Vector& other) const { \ return Vector::operator+(other); \ } \ inline Type& operator+=(const Vector& other) { \ Vector::operator+=(other); \ return *this; \ } \ inline Type operator-(const Vector& other) const { \ return Vector::operator-(other); \ } \ inline Type& operator-=(const Vector& other) { \ Vector::operator-=(other); \ return *this; \ } \ \ inline Type operator-() const { return Vector::operator-(); } \ inline Type normalized() const { return Vector::normalized(); } #endif }} #endif