#pragma once #include "StarArray.hpp" #include "StarMathCommon.hpp" #include "StarAlgorithm.hpp" #include "StarHash.hpp" namespace Star { template class Vector : public Array { public: typedef Array Base; template using Enable2D = typename std::enable_if

::type; template using Enable3D = typename std::enable_if

::type; template using Enable4D = typename std::enable_if

::type; template using Enable2DOrHigher = typename std::enable_if

= 2 && N == P, T2>::type; template using Enable3DOrHigher = typename std::enable_if

= 3 && N == P, T2>::type; template using Enable4DOrHigher = typename std::enable_if

= 4 && N == P, T2>::type; static Vector filled(T const& t); template static Vector floor(Vector const& v); template static Vector ceil(Vector const& v); template static Vector round(Vector const& v); template static Vector copyFrom(Iterator p); // Is zero-initialized (from Array) Vector(); explicit Vector(T const& e1); template Vector(T const& e1, TN const&... rest); template explicit Vector(Array const& v); template Vector(Array const& u, T3 const& v); template Vector toSize() const; Vector vec2() const; Vector vec3() const; Vector vec4() const; Vector piecewiseMultiply(Vector const& v2) const; Vector piecewiseDivide(Vector const& v2) const; Vector piecewiseMin(Vector const& v2) const; Vector piecewiseMax(Vector const& v2) const; Vector piecewiseClamp(Vector const& min, Vector const& max) const; T min() const; T max() const; T sum() const; T product() const; template Vector combine(Vector const& v, Function f) const; // Outputs angles in the range [0, pi] T angleBetween(Vector const& v) const; // Angle between two normalized vectors. T angleBetweenNormalized(Vector const& v) const; T magnitudeSquared() const; T magnitude() const; void normalize(); Vector normalized() const; Vector projectOnto(Vector const& v) const; Vector projectOntoNormalized(Vector const& v) const; void negate(); // Reverses order of components of vector void reverse(); Vector abs() const; Vector floor() const; Vector ceil() const; Vector round() const; void fill(T const& v); void clamp(T const& min, T const& max); template void transform(Function&& function); template Vector()(std::declval())), N> transformed(Function&& function) const; Vector operator-() const; Vector operator+(Vector const& v) const; Vector operator-(Vector const& v) const; T operator*(Vector const& v) const; Vector operator*(T s) const; Vector operator/(T s) const; Vector& operator+=(Vector const& v); Vector& operator-=(Vector const& v); Vector& operator*=(T s); Vector& operator/=(T s); // Vector2 // Return vector rotated to given angle template static Enable2D withAngle(T angle, T magnitude = 1); template static Enable2D angleBetween2(Vector const& u, Vector const& v); template static Enable2D angleFormedBy2(Vector const& a, Vector const& b, Vector const& c); template static Enable2D angleFormedBy2(Vector const& a, Vector const& b, Vector const& c, std::function const& diff); template Enable2D rotate(T angle) const; // Faster than rotate(Constants::pi/2). template Enable2D rot90() const; // Angle of vector on 2d plane, in the range [-pi, pi] template Enable2D angle() const; // Returns polar coordinates of this cartesian vector template Enable2D toPolar() const; // Returns cartesian coordinates of this polar vector template Enable2D toCartesian() const; template Enable2DOrHigher const& x() const; template Enable2DOrHigher const& y() const; template Enable2DOrHigher

setX(T const& t); template Enable2DOrHigher

setY(T const& t); // Vector3 template static Enable3D fromAngles(T psi, T theta); template static Enable3D fromAnglesEnu(T psi, T theta); template static Enable3D tripleScalarProduct(Vector const& u, Vector const& v, Vector const& w); template static Enable3D angle(Vector const& v1, Vector const& v2); template Enable3D psi() const; template Enable3D theta() const; template Enable3D> eulers() const; template Enable3D psiEnu() const; template Enable3D thetaEnu() const; template Enable3D nedToEnu() const; template Enable3D enuToNed() const; template Enable3DOrHigher const& z() const; template Enable3DOrHigher

setZ(T const& t); // Vector4 template Enable4DOrHigher const& w() const; template Enable4DOrHigher

setW(T const& t); using Base::size; using Base::empty; }; typedef Vector Vec2I; typedef Vector Vec2U; typedef Vector Vec2F; typedef Vector Vec2D; typedef Vector Vec2B; typedef Vector Vec2S; typedef Vector Vec3I; typedef Vector Vec3U; typedef Vector Vec3F; typedef Vector Vec3D; typedef Vector Vec3B; typedef Vector Vec3S; typedef Vector Vec4I; typedef Vector Vec4U; typedef Vector Vec4F; typedef Vector Vec4D; typedef Vector Vec4B; typedef Vector Vec4S; template std::ostream& operator<<(std::ostream& os, Vector const& v); template Vector operator*(T s, Vector v); template Vector vnorm(Vector v); template T vmag(Vector const& v); template T vmagSquared(Vector const& v); template Vector vmin(Vector const& a, Vector const& b); template Vector vmax(Vector const& a, Vector const& b); template Vector vclamp(Vector const& a, Vector const& min, Vector const& max); template VectorType vmult(VectorType const& a, VectorType const& b); template VectorType vdiv(VectorType const& a, VectorType const& b); // Returns the cross product template Vector operator^(Vector v1, Vector v2); // Returns the cross product / determinant template T operator^(Vector const& v1, Vector const& v2); template struct hash> : hash> {}; template Vector Vector::filled(T const& t) { Vector v; for (size_t i = 0; i < N; ++i) v[i] = t; return v; } template template Vector Vector::floor(Vector const& v) { Vector vec; for (size_t i = 0; i < N; ++i) vec[i] = Star::floor(v[i]); return vec; } template template Vector Vector::ceil(Vector const& v) { Vector vec; for (size_t i = 0; i < N; ++i) vec[i] = Star::ceil(v[i]); return vec; } template template Vector Vector::round(Vector const& v) { Vector vec; for (size_t i = 0; i < N; ++i) vec[i] = Star::round(v[i]); return vec; } template template Vector Vector::copyFrom(Iterator p) { Vector v; for (size_t i = 0; i < N; ++i) v[i] = *(p++); return v; } template Vector::Vector() {} template Vector::Vector(T const& e1) : Base(e1) {} template template Vector::Vector(T const& e1, TN const&... rest) : Base(e1, rest...) {} template template Vector::Vector(Array const& v) : Base(v) {} template template Vector::Vector(Array const& u, T3 const& v) { for (size_t i = 0; i < N - 1; ++i) { Base::operator[](i) = u[i]; } Base::operator[](N - 1) = v; } template template Vector Vector::toSize() const { Vector r; size_t ns = Star::min(N2, N); for (size_t i = 0; i < ns; ++i) r[i] = (*this)[i]; return r; } template Vector Vector::vec2() const { return toSize<2>(); } template Vector Vector::vec3() const { return toSize<3>(); } template Vector Vector::vec4() const { return toSize<4>(); } template Vector Vector::piecewiseMultiply(Vector const& v2) const { return combine(v2, std::multiplies()); } template Vector Vector::piecewiseDivide(Vector const& v2) const { return combine(v2, std::divides()); } template Vector Vector::piecewiseMin(Vector const& v2) const { Vector r; for (size_t i = 0; i < N; ++i) r[i] = Star::min((*this)[i], v2[i]); return r; } template Vector Vector::piecewiseMax(Vector const& v2) const { Vector r; for (size_t i = 0; i < N; ++i) r[i] = Star::max((*this)[i], v2[i]); return r; } template Vector Vector::piecewiseClamp(Vector const& min, Vector const& max) const { Vector r; for (size_t i = 0; i < N; ++i) r[i] = Star::max(Star::min((*this)[i], max[i]), min[i]); return r; } template T Vector::min() const { T s = (*this)[0]; for (size_t i = 1; i < N; ++i) s = Star::min(s, (*this)[i]); return s; } template T Vector::max() const { T s = (*this)[0]; for (size_t i = 1; i < N; ++i) s = Star::max(s, (*this)[i]); return s; } template T Vector::sum() const { T s = (*this)[0]; for (size_t i = 1; i < N; ++i) s += (*this)[i]; return s; } template T Vector::product() const { T p = (*this)[0]; for (size_t i = 1; i < N; ++i) p *= (*this)[i]; return p; } template template Vector Vector::combine(Vector const& v, Function f) const { Vector r; for (size_t i = 0; i < N; ++i) r[i] = f((*this)[i], v[i]); return r; } template T Vector::angleBetween(Vector const& v) const { return acos(this->normalized() * v.normalized()); } template T Vector::angleBetweenNormalized(Vector const& v) const { return acos(*this * v); } template T Vector::magnitudeSquared() const { T m = 0; for (size_t i = 0; i < N; ++i) m += square((*this)[i]); return m; } template T Vector::magnitude() const { return sqrt(magnitudeSquared()); } template void Vector::normalize() { T m = magnitude(); if (m != 0) *this = (*this) / m; } template Vector Vector::normalized() const { T m = magnitude(); if (m != 0) return (*this) / m; else return *this; } template Vector Vector::projectOnto(Vector const& v) const { T m = v.magnitudeSquared(); if (m != 0) return projectOntoNormalized(v) / m; else return Vector(); } template Vector Vector::projectOntoNormalized(Vector const& v) const { return ((*this) * v) * v; } template Vector Vector::operator-() const { auto v = *this; v.negate(); return v; } template void Vector::negate() { for (size_t i = 0; i < N; ++i) (*this)[i] = -(*this)[i]; } template Vector Vector::abs() const { Vector v; for (size_t i = 0; i < N; ++i) v[i] = fabs((*this)[i]); return v; } template Vector Vector::floor() const { return floor(*this); } template Vector Vector::ceil() const { return ceil(*this); } template Vector Vector::round() const { return round(*this); } template void Vector::reverse() { std::reverse(Base::begin(), Base::end()); } template void Vector::fill(T const& v) { Base::fill(v); } template void Vector::clamp(T const& min, T const& max) { for (size_t i = 0; i < N; ++i) (*this)[i] = Star::max(min, Star::min(max, (*this)[i])); } template template void Vector::transform(Function&& function) { for (auto& e : *this) e = function(e); } template template Vector()(std::declval())), N> Vector::transformed(Function&& function) const { return Star::transform()(std::declval())), N>>(*this, function); } template Vector Vector::operator+(Vector const& v) const { Vector r; for (size_t i = 0; i < N; ++i) r[i] = (*this)[i] + v[i]; return r; } template Vector Vector::operator-(Vector const& v) const { Vector r; for (size_t i = 0; i < N; ++i) r[i] = (*this)[i] - v[i]; return r; } template T Vector::operator*(Vector const& v) const { T sum = 0; for (size_t i = 0; i < N; ++i) sum += (*this)[i] * v[i]; return sum; } template Vector Vector::operator*(T s) const { Vector r; for (size_t i = 0; i < N; ++i) r[i] = (*this)[i] * s; return r; } template Vector Vector::operator/(T s) const { Vector r; for (size_t i = 0; i < N; ++i) r[i] = (*this)[i] / s; return r; } template Vector& Vector::operator+=(Vector const& v) { return (*this = *this + v); } template Vector& Vector::operator-=(Vector const& v) { return (*this = *this - v); } template Vector& Vector::operator*=(T s) { return (*this = *this * s); } template Vector& Vector::operator/=(T s) { return (*this = *this / s); } // Vector2 template template auto Vector::withAngle(T angle, T magnitude) -> Enable2D> { return Vector(std::cos(angle) * magnitude, std::sin(angle) * magnitude); } template template auto Vector::angleBetween2(Vector const& v1, Vector const& v2) -> Enable2D { // TODO: Inefficient return v2.angle() - v1.angle(); } template template auto Vector::angleFormedBy2(Vector const& a, Vector const& b, Vector const& c) -> Enable2D { return angleBetween2(b - a, b - c); } template template auto Vector::angleFormedBy2( Vector const& a, Vector const& b, Vector const& c, std::function const& diff) -> Enable2D { return angleBetween2(diff(b, a), diff(b, c)); } template template auto Vector::angle() const -> Enable2D { return atan2(Base::operator[](1), Base::operator[](0)); } template template auto Vector::rotate(T a) const -> Enable2D> { // TODO: Need a Matrix2 T cosa = std::cos(a); T sina = std::sin(a); return Vector( Base::operator[](0) * cosa - Base::operator[](1) * sina, Base::operator[](0) * sina + Base::operator[](1) * cosa); } template template auto Vector::rot90() const -> Enable2D> { return Vector(-y(), x()); } template template auto Vector::toPolar() const -> Enable2D> { return Vector(angle(), Base::magnitude()); } template template auto Vector::toCartesian() const -> Enable2D> { return vec2d(sin((*this)[0]) * (*this)[1], cos((*this)[0]) * (*this)[1]); } template template auto Vector::x() const -> Enable2DOrHigher const & { return Base::operator[](0); } template template auto Vector::y() const -> Enable2DOrHigher const & { return Base::operator[](1); } template template auto Vector::setX(T const& t) -> Enable2DOrHigher

{ Base::operator[](0) = t; } template template auto Vector::setY(T const& t) -> Enable2DOrHigher

{ Base::operator[](1) = t; } // Vector3 template template auto Vector::tripleScalarProduct(Vector const& a, Vector const& b, Vector const& c) -> Enable3D { return a * (b ^ c); } template template auto Vector::theta() const -> Enable3D { Vector vn = norm(*this); T tmp = fabs(vn.z()); if (tmp > 0.99999) { return tmp > 0.0 ? T(-Constants::pi / 2) : T(Constants::pi / 2); } else { return asin(-vn.z()); } } template template auto Vector::psi() const -> Enable3D { Vector vn = norm(*this); T tmp = T(fabs(vn.z())); if (tmp > 0.99999) { return 0.0; } else { return T(atan2(vn.y(), vn.x())); } } template template auto Vector::thetaEnu() const -> Enable3D { Vector vn = norm(*this); T tmp = fabs(vn.z()); if (tmp > 0.99999) { return tmp > 0.0 ? -Constants::pi / 2 : Constants::pi / 2; } else { return asin(vn.z()); } } template template auto Vector::psiEnu() const -> Enable3D { Vector vn = norm(*this); T tmp = fabs(vn.z()); if (tmp > 0.99999) { return 0.0; } else { return atan2(vn.x(), vn.y()); } } template template auto Vector::eulers() const -> Enable3D> { T psi, theta; Vector vn = norm(*this); T tmp = fabs(vn.z()); if (tmp > 0.99999) { psi = 0.0; theta = tmp > 0.0 ? -Constants::pi / 2 : Constants::pi / 2; } else { psi = atan2(vn.y(), vn.x()); theta = asin(-vn.z()); } return Vector(psi, theta); } template template auto Vector::fromAngles(T psi, T theta) -> Enable3D> { Vec3F nv; T cosTheta = T(cos(theta)); nv.x() = T(cos(psi)); nv.y() = T(sin(psi)); nv.x() *= cosTheta; nv.y() *= cosTheta; nv.z() = T(-sin(theta)); return nv; } template template auto Vector::fromAnglesEnu(T psi, T theta) -> Enable3D> { Vector nv = fromAngles(psi, theta); return Vector(nv.y(), nv.x(), -nv.z()); } template template auto Vector::angle(Vector const& v1, Vector const& v2) -> Enable3D { return acos(Star::min(norm(v1) * norm(v2), 1.0)); } template template auto Vector::nedToEnu() const -> Enable3D> { return Vector(y(), x(), -z()); } template template auto Vector::enuToNed() const -> Enable3D> { return Vector(y(), x(), -z()); } template template auto Vector::z() const -> Enable3DOrHigher const & { return Base::operator[](2); } template template auto Vector::setZ(T const& t) -> Enable3DOrHigher

{ Base::operator[](2) = t; } // Vector4 template template auto Vector::w() const -> Enable4DOrHigher const & { return Base::operator[](3); } template template auto Vector::setW(T const& t) -> Enable4DOrHigher

{ Base::operator[](3) = t; } // Free Functions template std::ostream& operator<<(std::ostream& os, Vector const& v) { os << '('; for (size_t i = 0; i < N; ++i) { os << v[i]; if (i != N - 1) os << ", "; } os << ')'; return os; } template Vector operator*(T s, Vector v) { return v * s; } template Vector vnorm(Vector v) { return v.normalized(); } template T vmag(Vector const& v) { return v.magnitude(); } template T vmagSquared(Vector const& v) { return v.magnitudeSquared(); } template Vector vmin(Vector const& a, Vector const& b) { return a.piecewiseMin(b); } template Vector vmax(Vector const& a, Vector const& b) { return a.piecewiseMax(b); } template Vector vclamp(Vector const& a, Vector const& min, Vector const& max) { return a.piecewiseClamp(min, max); } template VectorType vmult(VectorType const& a, VectorType const& b) { return a.piecewiseMultiply(b); } template VectorType vdiv(VectorType const& a, VectorType const& b) { return a.piecewiseDivide(b); } template Vector operator^(Vector v1, Vector v2) { return Vector(v1[1] * v2[2] - v1[2] * v2[1], v1[2] * v2[0] - v1[0] * v2[2], v1[0] * v2[1] - v1[1] * v2[0]); } template T operator^(Vector const& v1, Vector const& v2) { return v1[0] * v2[1] - v1[1] * v2[0]; } }