#pragma once #include "../scalar.hpp" #include "../../containers/array/static_array.hpp" namespace hpr { template class VectorSpace : public StaticArray { static_assert(std::is_arithmetic::value, "Type must be numeric"); using base = StaticArray; using SubVector = typename std::conditional= 2, VectorSpace, VectorSpace>::type; public: using value_type = Type; using size_type = size_t; using pointer = Type*; using reference = Type&; using iterator = Iterator; using const_iterator = Iterator; public: inline VectorSpace() : base {} {} inline VectorSpace(const VectorSpace& vs) : base {static_cast(vs)} {} inline VectorSpace(VectorSpace&& vs) noexcept : base {std::forward(static_cast(vs))} {} inline VectorSpace& operator=(const VectorSpace& vs) { base::operator=(vs); return *this; } inline VectorSpace& operator=(VectorSpace&& vs) noexcept { swap(*this, vs);//std::forward(static_cast(*this)), std::forward(static_cast(vs))); //std::swap(*this, vs); return *this; } virtual ~VectorSpace() = default; inline VectorSpace(typename base::iterator start, typename base::iterator end) : base {start, end} {} inline VectorSpace(typename base::const_iterator start, typename base::const_iterator end) : base {start, end} {} inline VectorSpace(std::initializer_list list) : base {list} {} template ... Args> inline VectorSpace(const value_type& v, const Args& ...args) : base {v, static_cast(args)...} { static_assert(1 + sizeof...(args) == Size, "Number of arguments must be equal to size of vector"); } template ... Args> inline VectorSpace(value_type&& v, Args&& ...args) : base {v, static_cast(std::forward(args))...} { static_assert(1 + sizeof...(args) == Size, "Number of arguments must be equal to size of vector"); } /*template ... Args> inline VectorSpace(const VectorSpace& subvec, const value_type& v, const Args& ...args) : base {static_cast>(subvec), v, static_cast(std::forward(args))...} {}*/ inline VectorSpace(const SubVector& subvs, const value_type& v) : base {} { for (auto n = 0; n < subvs.size(); ++n) (*this)[n] = subvs[n]; (*this)[subvs.size()] = v; } template inline VectorSpace(const VectorSpace& vs) : base {vs.begin(), vs.begin() + Size} { static_assert(BiggerSize > Size, "Size should be bigger"); } // Member functions // vector versus scalar (per element operations) friend inline VectorSpace operator-(const VectorSpace& rhs) { VectorSpace vs {rhs}; for (value_type& v : vs) v = -v; return vs; } inline void operator*=(const value_type& val) { //for (value_type& v : *this) // v *= val; for (auto n = 0; n < Size; ++n) (*this)[n] *= val; } inline void operator+=(const value_type& val) { for (auto n = 0; n < Size; ++n) (*this)[n] += val; } inline void operator-=(const value_type& val) { //for (value_type& v : *this) // v -= val; for (auto n = 0; n < Size; ++n) (*this)[n] -= val; } inline void operator/=(const value_type& val) { for (value_type& v : *this) v /= val; } friend inline VectorSpace operator+(const VectorSpace& lhs, const value_type& rhs) { VectorSpace vs {lhs}; vs += rhs; return vs; } friend inline VectorSpace operator+(const value_type& lhs, const VectorSpace& rhs) { return operator+(rhs, lhs); } friend inline VectorSpace operator*(const VectorSpace& lhs, const value_type& rhs) { VectorSpace vs {lhs}; vs *= rhs; return vs; } friend inline VectorSpace operator*(const value_type& lhs, const VectorSpace& rhs) { return operator*(rhs, lhs); } friend inline VectorSpace operator/(const VectorSpace& lhs, const value_type& rhs) { VectorSpace vs {lhs}; vs /= rhs; return vs; } friend inline VectorSpace operator/(const value_type& lhs, const VectorSpace& rhs) { VectorSpace vs; for (auto n = 0; n < vs.size(); ++n) vs[n] = lhs / rhs[n]; return vs; } // vector versus vector (per element operations) inline void operator*=(const VectorSpace& vs) { for (auto n = 0; n < Size; ++n) (*this)[n] *= vs[n]; } inline void operator+=(const VectorSpace& vs) { for (auto n = 0; n < Size; ++n) (*this)[n] += vs[n]; } inline void operator-=(const VectorSpace& vs) { for (auto n = 0; n < Size; ++n) (*this)[n] -= vs[n]; } inline void operator/=(const VectorSpace& vs) { for (auto n = 0; n < Size; ++n) (*this)[n] /= vs[n]; } friend inline VectorSpace operator+(const VectorSpace& lhs, const VectorSpace& rhs) { VectorSpace vs {lhs}; vs += rhs; return vs; } friend inline VectorSpace operator-(const VectorSpace& lhs, const VectorSpace& rhs) { VectorSpace vs {lhs}; vs -= rhs; return vs; } friend inline VectorSpace operator*(const VectorSpace& lhs, const VectorSpace& rhs) { VectorSpace vs {lhs}; vs *= rhs; return vs; } friend inline VectorSpace operator/(const VectorSpace& lhs, const VectorSpace& rhs) { VectorSpace vs {lhs}; vs /= rhs; return vs; } friend inline bool operator==(const VectorSpace& lhs, const VectorSpace& rhs) { for (auto n = 0; n < Size; ++n) if (lhs[n] != rhs[n]) return false; return true; } friend inline bool operator!=(const VectorSpace& lhs, const VectorSpace& rhs) { return !(lhs == rhs); } }; template inline VectorSpace equal(const VectorSpace& lhs, const VectorSpace& rhs, scalar precision = 1e-5) { VectorSpace res; for (auto n = 0; n < Size; ++n) res[n] = equal(lhs[n], rhs[n], precision); return res; } template inline Type sum(const VectorSpace& vs) { Type sum {}; for (const Type& v : vs) sum += v; return sum; } template constexpr Type dot(const VectorSpace& lhs, const VectorSpace& rhs) { return sum(lhs * rhs); } template inline Type length(const VectorSpace& vs) { return sqrt(dot(vs, vs)); } template inline Type distance(const VectorSpace& point1, const VectorSpace& point2) { return length(point1 - point2); } template constexpr VectorSpace cross(const VectorSpace& lhs, const VectorSpace& rhs) { return VectorSpace( lhs[1] * rhs[2] - lhs[2] * rhs[1], lhs[2] * rhs[0] - lhs[0] * rhs[2], lhs[0] * rhs[1] - lhs[1] * rhs[0] ); } template constexpr VectorSpace pow(const VectorSpace& vs, scalar degree) { VectorSpace res; for (auto n = 0; n < Size; ++n) res[n] = std::pow(vs[n], degree); return res; } template constexpr VectorSpace abs(const VectorSpace& vs) { VectorSpace res; for (auto n = 0; n < Size; ++n) res[n] = std::abs(vs[n]); return res; } template constexpr Type norm(const VectorSpace& vs) { return sqrt(sum(pow(abs(vs), 2))); } template constexpr Type angle(const VectorSpace& lhs, const VectorSpace& rhs) { scalar cos = dot(lhs, rhs) / (norm(lhs) * norm(rhs)); return acos(cos); //clip(cos, -1., 1.)); } template inline VectorSpace normalize(const VectorSpace& vs) { return vs * inversesqrt(dot(vs, vs)); } template constexpr bool any(const VectorSpace& vs) { bool res = false; for (auto e : vs) res = res || e; return res; } template constexpr bool all(const VectorSpace& vs) { bool res = true; for (auto e : vs) res = res && e; return res; } // Aliases template using vec = VectorSpace; using vec2 = VectorSpace; using vec3 = VectorSpace; using vec4 = VectorSpace; }