diff options
Diffstat (limited to 'source/core/StarVector.hpp')
-rw-r--r-- | source/core/StarVector.hpp | 925 |
1 files changed, 925 insertions, 0 deletions
diff --git a/source/core/StarVector.hpp b/source/core/StarVector.hpp new file mode 100644 index 0000000..aaa5909 --- /dev/null +++ b/source/core/StarVector.hpp @@ -0,0 +1,925 @@ +#ifndef STAR_VECTOR_HPP +#define STAR_VECTOR_HPP + +#include "StarArray.hpp" +#include "StarMathCommon.hpp" +#include "StarAlgorithm.hpp" +#include "StarHash.hpp" + +namespace Star { + +template <typename T, size_t N> +class Vector : public Array<T, N> { +public: + typedef Array<T, N> Base; + + template <size_t P, typename T2 = void> + using Enable2D = typename std::enable_if<P == 2 && N == P, T2>::type; + + template <size_t P, typename T2 = void> + using Enable3D = typename std::enable_if<P == 3 && N == P, T2>::type; + + template <size_t P, typename T2 = void> + using Enable4D = typename std::enable_if<P == 4 && N == P, T2>::type; + + template <size_t P, typename T2 = void> + using Enable2DOrHigher = typename std::enable_if<P >= 2 && N == P, T2>::type; + + template <size_t P, typename T2 = void> + using Enable3DOrHigher = typename std::enable_if<P >= 3 && N == P, T2>::type; + + template <size_t P, typename T2 = void> + using Enable4DOrHigher = typename std::enable_if<P >= 4 && N == P, T2>::type; + + static Vector filled(T const& t); + + template <typename T2> + static Vector floor(Vector<T2, N> const& v); + + template <typename T2> + static Vector ceil(Vector<T2, N> const& v); + + template <typename T2> + static Vector round(Vector<T2, N> const& v); + + template <typename Iterator> + static Vector copyFrom(Iterator p); + + // Is zero-initialized (from Array) + Vector(); + + explicit Vector(T const& e1); + + template <typename... TN> + Vector(T const& e1, TN const&... rest); + + template <typename T2> + explicit Vector(Array<T2, N> const& v); + + template <typename T2, typename T3> + Vector(Array<T2, N - 1> const& u, T3 const& v); + + template <size_t N2> + Vector<T, N2> toSize() const; + Vector<T, 2> vec2() const; + Vector<T, 3> vec3() const; + Vector<T, 4> 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 <typename Function> + 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 <typename Function> + void transform(Function&& function); + + template <typename Function> + Vector<decltype(std::declval<Function>()(std::declval<T>())), 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 <size_t P = N> + static Enable2D<P, Vector> withAngle(T angle, T magnitude = 1); + + template <size_t P = N> + static Enable2D<P, T> angleBetween2(Vector const& u, Vector const& v); + template <size_t P = N> + static Enable2D<P, T> angleFormedBy2(Vector const& a, Vector const& b, Vector const& c); + template <size_t P = N> + static Enable2D<P, T> angleFormedBy2(Vector const& a, Vector const& b, Vector const& c, std::function<Vector(Vector, Vector)> const& diff); + + template <size_t P = N> + Enable2D<P, Vector> rotate(T angle) const; + + // Faster than rotate(Constants::pi/2). + template <size_t P = N> + Enable2D<P, Vector> rot90() const; + + // Angle of vector on 2d plane, in the range [-pi, pi] + template <size_t P = N> + Enable2D<P, T> angle() const; + + // Returns polar coordinates of this cartesian vector + template <size_t P = N> + Enable2D<P, Vector> toPolar() const; + + // Returns cartesian coordinates of this polar vector + template <size_t P = N> + Enable2D<P, Vector> toCartesian() const; + + template <size_t P = N> + Enable2DOrHigher<P, T> const& x() const; + template <size_t P = N> + Enable2DOrHigher<P, T> const& y() const; + + template <size_t P = N> + Enable2DOrHigher<P> setX(T const& t); + template <size_t P = N> + Enable2DOrHigher<P> setY(T const& t); + + // Vector3 + + template <size_t P = N> + static Enable3D<P, Vector> fromAngles(T psi, T theta); + template <size_t P = N> + static Enable3D<P, Vector> fromAnglesEnu(T psi, T theta); + template <size_t P = N> + static Enable3D<P, T> tripleScalarProduct(Vector const& u, Vector const& v, Vector const& w); + template <size_t P = N> + static Enable3D<P, T> angle(Vector const& v1, Vector const& v2); + + template <size_t P = N> + Enable3D<P, T> psi() const; + template <size_t P = N> + Enable3D<P, T> theta() const; + template <size_t P = N> + Enable3D<P, Vector<T, 2>> eulers() const; + + template <size_t P = N> + Enable3D<P, T> psiEnu() const; + template <size_t P = N> + Enable3D<P, T> thetaEnu() const; + + template <size_t P = N> + Enable3D<P, Vector> nedToEnu() const; + template <size_t P = N> + Enable3D<P, Vector> enuToNed() const; + + template <size_t P = N> + Enable3DOrHigher<P, T> const& z() const; + + template <size_t P = N> + Enable3DOrHigher<P> setZ(T const& t); + + // Vector4 + + template <size_t P = N> + Enable4DOrHigher<P, T> const& w() const; + + template <size_t P = N> + Enable4DOrHigher<P> setW(T const& t); + +private: + using Base::size; + using Base::empty; +}; + +typedef Vector<int, 2> Vec2I; +typedef Vector<unsigned, 2> Vec2U; +typedef Vector<float, 2> Vec2F; +typedef Vector<double, 2> Vec2D; +typedef Vector<uint8_t, 2> Vec2B; +typedef Vector<size_t, 2> Vec2S; + +typedef Vector<int, 3> Vec3I; +typedef Vector<unsigned, 3> Vec3U; +typedef Vector<float, 3> Vec3F; +typedef Vector<double, 3> Vec3D; +typedef Vector<uint8_t, 3> Vec3B; +typedef Vector<size_t, 3> Vec3S; + +typedef Vector<int, 4> Vec4I; +typedef Vector<unsigned, 4> Vec4U; +typedef Vector<float, 4> Vec4F; +typedef Vector<double, 4> Vec4D; +typedef Vector<uint8_t, 4> Vec4B; +typedef Vector<size_t, 4> Vec4S; + +template <typename T, size_t N> +std::ostream& operator<<(std::ostream& os, Vector<T, N> const& v); + +template <typename T, size_t N> +Vector<T, N> operator*(T s, Vector<T, N> v); + +template <typename T, size_t N> +Vector<T, N> vnorm(Vector<T, N> v); + +template <typename T, size_t N> +T vmag(Vector<T, N> const& v); + +template <typename T, size_t N> +T vmagSquared(Vector<T, N> const& v); + +template <typename T, size_t N> +Vector<T, N> vmin(Vector<T, N> const& a, Vector<T, N> const& b); + +template <typename T, size_t N> +Vector<T, N> vmax(Vector<T, N> const& a, Vector<T, N> const& b); + +template <typename T, size_t N> +Vector<T, N> vclamp(Vector<T, N> const& a, Vector<T, N> const& min, Vector<T, N> const& max); + +template <typename VectorType> +VectorType vmult(VectorType const& a, VectorType const& b); + +template <typename VectorType> +VectorType vdiv(VectorType const& a, VectorType const& b); + +// Returns the cross product +template <typename T> +Vector<T, 3> operator^(Vector<T, 3> v1, Vector<T, 3> v2); + +// Returns the cross product / determinant +template <typename T> +T operator^(Vector<T, 2> const& v1, Vector<T, 2> const& v2); + +template <typename T, size_t N> +struct hash<Vector<T, N>> : hash<Array<T, N>> {}; + +template <typename T, size_t N> +Vector<T, N> Vector<T, N>::filled(T const& t) { + Vector v; + for (size_t i = 0; i < N; ++i) + v[i] = t; + return v; +} + +template <typename T, size_t N> +template <typename T2> +Vector<T, N> Vector<T, N>::floor(Vector<T2, N> const& v) { + Vector vec; + for (size_t i = 0; i < N; ++i) + vec[i] = Star::floor(v[i]); + return vec; +} + +template <typename T, size_t N> +template <typename T2> +Vector<T, N> Vector<T, N>::ceil(Vector<T2, N> const& v) { + Vector vec; + for (size_t i = 0; i < N; ++i) + vec[i] = Star::ceil(v[i]); + return vec; +} + +template <typename T, size_t N> +template <typename T2> +Vector<T, N> Vector<T, N>::round(Vector<T2, N> const& v) { + Vector vec; + for (size_t i = 0; i < N; ++i) + vec[i] = Star::round(v[i]); + return vec; +} + +template <typename T, size_t N> +template <typename Iterator> +Vector<T, N> Vector<T, N>::copyFrom(Iterator p) { + Vector v; + for (size_t i = 0; i < N; ++i) + v[i] = *(p++); + return v; +} + +template <typename T, size_t N> +Vector<T, N>::Vector() {} + +template <typename T, size_t N> +Vector<T, N>::Vector(T const& e1) + : Base(e1) {} + +template <typename T, size_t N> +template <typename... TN> +Vector<T, N>::Vector(T const& e1, TN const&... rest) + : Base(e1, rest...) {} + +template <typename T, size_t N> +template <typename T2> +Vector<T, N>::Vector(Array<T2, N> const& v) + : Base(v) {} + +template <typename T, size_t N> +template <typename T2, typename T3> +Vector<T, N>::Vector(Array<T2, N - 1> 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 <typename T, size_t N> +template <size_t N2> +Vector<T, N2> Vector<T, N>::toSize() const { + Vector<T, N2> r; + size_t ns = Star::min(N2, N); + for (size_t i = 0; i < ns; ++i) + r[i] = (*this)[i]; + return r; +} + +template <typename T, size_t N> +Vector<T, 2> Vector<T, N>::vec2() const { + return toSize<2>(); +} + +template <typename T, size_t N> +Vector<T, 3> Vector<T, N>::vec3() const { + return toSize<3>(); +} + +template <typename T, size_t N> +Vector<T, 4> Vector<T, N>::vec4() const { + return toSize<4>(); +} + +template <typename T, size_t N> +Vector<T, N> Vector<T, N>::piecewiseMultiply(Vector const& v2) const { + return combine(v2, std::multiplies<T>()); +} + +template <typename T, size_t N> +Vector<T, N> Vector<T, N>::piecewiseDivide(Vector const& v2) const { + return combine(v2, std::divides<T>()); +} + +template <typename T, size_t N> +Vector<T, N> Vector<T, N>::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 <typename T, size_t N> +Vector<T, N> Vector<T, N>::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 <typename T, size_t N> +Vector<T, N> Vector<T, N>::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 <typename T, size_t N> +T Vector<T, N>::min() const { + T s = (*this)[0]; + for (size_t i = 1; i < N; ++i) + s = Star::min(s, (*this)[i]); + return s; +} + +template <typename T, size_t N> +T Vector<T, N>::max() const { + T s = (*this)[0]; + for (size_t i = 1; i < N; ++i) + s = Star::max(s, (*this)[i]); + return s; +} + +template <typename T, size_t N> +T Vector<T, N>::sum() const { + T s = (*this)[0]; + for (size_t i = 1; i < N; ++i) + s += (*this)[i]; + return s; +} + +template <typename T, size_t N> +T Vector<T, N>::product() const { + T p = (*this)[0]; + for (size_t i = 1; i < N; ++i) + p *= (*this)[i]; + return p; +} + +template <typename T, size_t N> +template <typename Function> +Vector<T, N> Vector<T, N>::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 <typename T, size_t N> +T Vector<T, N>::angleBetween(Vector const& v) const { + return acos(this->normalized() * v.normalized()); +} + +template <typename T, size_t N> +T Vector<T, N>::angleBetweenNormalized(Vector const& v) const { + return acos(*this * v); +} + +template <typename T, size_t N> +T Vector<T, N>::magnitudeSquared() const { + T m = 0; + for (size_t i = 0; i < N; ++i) + m += square((*this)[i]); + return m; +} + +template <typename T, size_t N> +T Vector<T, N>::magnitude() const { + return sqrt(magnitudeSquared()); +} + +template <typename T, size_t N> +void Vector<T, N>::normalize() { + T m = magnitude(); + if (m != 0) + *this = (*this) / m; +} + +template <typename T, size_t N> +Vector<T, N> Vector<T, N>::normalized() const { + T m = magnitude(); + if (m != 0) + return (*this) / m; + else + return *this; +} + +template <typename T, size_t N> +Vector<T, N> Vector<T, N>::projectOnto(Vector const& v) const { + T m = v.magnitudeSquared(); + if (m != 0) + return projectOntoNormalized(v) / m; + else + return Vector(); +} + +template <typename T, size_t N> +Vector<T, N> Vector<T, N>::projectOntoNormalized(Vector const& v) const { + return ((*this) * v) * v; +} + +template <typename T, size_t N> +Vector<T, N> Vector<T, N>::operator-() const { + auto v = *this; + v.negate(); + return v; +} + +template <typename T, size_t N> +void Vector<T, N>::negate() { + for (size_t i = 0; i < N; ++i) + (*this)[i] = -(*this)[i]; +} + +template <typename T, size_t N> +Vector<T, N> Vector<T, N>::abs() const { + Vector v; + for (size_t i = 0; i < N; ++i) + v[i] = fabs((*this)[i]); + return v; +} + +template <typename T, size_t N> +Vector<T, N> Vector<T, N>::floor() const { + return floor(*this); +} + +template <typename T, size_t N> +Vector<T, N> Vector<T, N>::ceil() const { + return ceil(*this); +} + +template <typename T, size_t N> +Vector<T, N> Vector<T, N>::round() const { + return round(*this); +} + +template <typename T, size_t N> +void Vector<T, N>::reverse() { + std::reverse(Base::begin(), Base::end()); +} + +template <typename T, size_t N> +void Vector<T, N>::fill(T const& v) { + Base::fill(v); +} + +template <typename T, size_t N> +void Vector<T, N>::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 <typename T, size_t N> +template <typename Function> +void Vector<T, N>::transform(Function&& function) { + for (auto& e : *this) + e = function(e); +} + +template <typename T, size_t N> +template <typename Function> +Vector<decltype(std::declval<Function>()(std::declval<T>())), N> Vector<T, N>::transformed(Function&& function) const { + return Star::transform<Vector<decltype(std::declval<Function>()(std::declval<T>())), N>>(*this, function); +} + +template <typename T, size_t N> +Vector<T, N> Vector<T, N>::operator+(Vector const& v) const { + Vector r; + for (size_t i = 0; i < N; ++i) + r[i] = (*this)[i] + v[i]; + return r; +} + +template <typename T, size_t N> +Vector<T, N> Vector<T, N>::operator-(Vector const& v) const { + Vector r; + for (size_t i = 0; i < N; ++i) + r[i] = (*this)[i] - v[i]; + return r; +} + +template <typename T, size_t N> +T Vector<T, N>::operator*(Vector const& v) const { + T sum = 0; + for (size_t i = 0; i < N; ++i) + sum += (*this)[i] * v[i]; + return sum; +} + +template <typename T, size_t N> +Vector<T, N> Vector<T, N>::operator*(T s) const { + Vector r; + for (size_t i = 0; i < N; ++i) + r[i] = (*this)[i] * s; + return r; +} + +template <typename T, size_t N> +Vector<T, N> Vector<T, N>::operator/(T s) const { + Vector r; + for (size_t i = 0; i < N; ++i) + r[i] = (*this)[i] / s; + return r; +} + +template <typename T, size_t N> +Vector<T, N>& Vector<T, N>::operator+=(Vector const& v) { + return (*this = *this + v); +} + +template <typename T, size_t N> +Vector<T, N>& Vector<T, N>::operator-=(Vector const& v) { + return (*this = *this - v); +} + +template <typename T, size_t N> +Vector<T, N>& Vector<T, N>::operator*=(T s) { + return (*this = *this * s); +} + +template <typename T, size_t N> +Vector<T, N>& Vector<T, N>::operator/=(T s) { + return (*this = *this / s); +} + +// Vector2 + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::withAngle(T angle, T magnitude) -> Enable2D<P, Vector<T, N>> { + return Vector(std::cos(angle) * magnitude, std::sin(angle) * magnitude); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::angleBetween2(Vector const& v1, Vector const& v2) -> Enable2D<P, T> { + // TODO: Inefficient + return v2.angle() - v1.angle(); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::angleFormedBy2(Vector const& a, Vector const& b, Vector const& c) -> Enable2D<P, T> { + return angleBetween2(b - a, b - c); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::angleFormedBy2( + Vector const& a, Vector const& b, Vector const& c, std::function<Vector(Vector, Vector)> const& diff) + -> Enable2D<P, T> { + return angleBetween2(diff(b, a), diff(b, c)); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::angle() const -> Enable2D<P, T> { + return atan2(Base::operator[](1), Base::operator[](0)); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::rotate(T a) const -> Enable2D<P, Vector<T, N>> { + // 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 <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::rot90() const -> Enable2D<P, Vector<T, N>> { + return Vector(-y(), x()); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::toPolar() const -> Enable2D<P, Vector<T, N>> { + return Vector(angle(), Base::magnitude()); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::toCartesian() const -> Enable2D<P, Vector<T, N>> { + return vec2d(sin((*this)[0]) * (*this)[1], cos((*this)[0]) * (*this)[1]); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::x() const -> Enable2DOrHigher<P, T> const & { + return Base::operator[](0); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::y() const -> Enable2DOrHigher<P, T> const & { + return Base::operator[](1); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::setX(T const& t) -> Enable2DOrHigher<P> { + Base::operator[](0) = t; +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::setY(T const& t) -> Enable2DOrHigher<P> { + Base::operator[](1) = t; +} + +// Vector3 + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::tripleScalarProduct(Vector const& a, Vector const& b, Vector const& c) -> Enable3D<P, T> { + return a * (b ^ c); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::theta() const -> Enable3D<P, T> { + Vector<T, N> 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 <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::psi() const -> Enable3D<P, T> { + Vector<T, N> 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 <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::thetaEnu() const -> Enable3D<P, T> { + Vector<T, N> 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 <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::psiEnu() const -> Enable3D<P, T> { + Vector<T, N> vn = norm(*this); + T tmp = fabs(vn.z()); + if (tmp > 0.99999) { + return 0.0; + } else { + return atan2(vn.x(), vn.y()); + } +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::eulers() const -> Enable3D<P, Vector<T, 2>> { + T psi, theta; + Vector<T, N> 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<T, 2>(psi, theta); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::fromAngles(T psi, T theta) -> Enable3D<P, Vector<T, N>> { + 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 <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::fromAnglesEnu(T psi, T theta) -> Enable3D<P, Vector<T, N>> { + Vector nv = fromAngles(psi, theta); + return Vector(nv.y(), nv.x(), -nv.z()); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::angle(Vector const& v1, Vector const& v2) -> Enable3D<P, T> { + return acos(Star::min(norm(v1) * norm(v2), 1.0)); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::nedToEnu() const -> Enable3D<P, Vector<T, N>> { + return Vector(y(), x(), -z()); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::enuToNed() const -> Enable3D<P, Vector<T, N>> { + return Vector(y(), x(), -z()); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::z() const -> Enable3DOrHigher<P, T> const & { + return Base::operator[](2); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::setZ(T const& t) -> Enable3DOrHigher<P> { + Base::operator[](2) = t; +} + +// Vector4 + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::w() const -> Enable4DOrHigher<P, T> const & { + return Base::operator[](3); +} + +template <typename T, size_t N> +template <size_t P> +auto Vector<T, N>::setW(T const& t) -> Enable4DOrHigher<P> { + Base::operator[](3) = t; +} + +// Free Functions + +template <typename T, size_t N> +std::ostream& operator<<(std::ostream& os, Vector<T, N> const& v) { + os << '('; + for (size_t i = 0; i < N; ++i) { + os << v[i]; + if (i != N - 1) + os << ", "; + } + os << ')'; + return os; +} + +template <typename T, size_t N> +Vector<T, N> operator*(T s, Vector<T, N> v) { + return v * s; +} + +template <typename T, size_t N> +Vector<T, N> vnorm(Vector<T, N> v) { + return v.normalized(); +} + +template <typename T, size_t N> +T vmag(Vector<T, N> const& v) { + return v.magnitude(); +} + +template <typename T, size_t N> +T vmagSquared(Vector<T, N> const& v) { + return v.magnitudeSquared(); +} + +template <typename T, size_t N> +Vector<T, N> vmin(Vector<T, N> const& a, Vector<T, N> const& b) { + return a.piecewiseMin(b); +} + +template <typename T, size_t N> +Vector<T, N> vmax(Vector<T, N> const& a, Vector<T, N> const& b) { + return a.piecewiseMax(b); +} + +template <typename T, size_t N> +Vector<T, N> vclamp(Vector<T, N> const& a, Vector<T, N> const& min, Vector<T, N> const& max) { + return a.piecewiseClamp(min, max); +} + +template <typename VectorType> +VectorType vmult(VectorType const& a, VectorType const& b) { + return a.piecewiseMultiply(b); +} + +template <typename VectorType> +VectorType vdiv(VectorType const& a, VectorType const& b) { + return a.piecewiseDivide(b); +} + +template <typename T> +Vector<T, 3> operator^(Vector<T, 3> v1, Vector<T, 3> v2) { + return Vector<T, 3>(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 <typename T> +T operator^(Vector<T, 2> const& v1, Vector<T, 2> const& v2) { + return v1[0] * v2[1] - v1[1] * v2[0]; +} + +} + +#endif |