#pragma once #include "../Common/Sizes.hpp" #include #include template struct Vector { Vector(): elements{} {} template = 0> Vector(Args... args) : elements{ static_cast(args)... } {} explicit Vector(const T values[S]) { std::copy(values, values + S, elements); } explicit Vector(const T scalar) { std::fill(elements, elements + S, scalar); } Vector(const Vector vector, const T scalar) { std::copy(vector.elements, vector.elements + S - 1, elements); elements[S - 1] = scalar; } template S), Int> = 0> explicit Vector(const Vector vector) { std::copy(vector.elements, vector.elements + S, elements); } template explicit Vector(const Vector vector) { for (Int i = 0; i < S; i++) { elements[i] = (T)vector[i]; } } template Vector map(F f) const { Vector result{}; for (Int i = 0; i < S; i++) { result[i] = f(elements[i]); } return result; } template Vector zip(const Vector other, F f) const { Vector result{}; for (Int i = 0; i < S; i++) { result[i] = f(elements[i], other[i]); } return result; } template T reduce(F f) const { T result = elements[0]; for (Int i = 1; i < S; i++) { result = f(result, elements[i]); } return result; } T sum() const { return reduce([](auto x, auto y) { return x + y; }); } T magnitude() const { return sqrt(map([](auto x) { return x * x;}).sum()); } Vector normalize() const { auto m = magnitude(); return map([=](auto x) { return x / m; }); } T distance(const Vector other) const { return (*this - other).magnitude(); } Vector<3, T> any_orthogonal() { if (Vector a{y(), -x(), 0.0f}; a != zero()) return a; if (Vector b{z(), 0.0f, -x()}; b != zero()) return b; if (Vector c{0.0f, z(), -y()}; c != zero()) return c; return zero(); } Vector abs() const { return map([=](auto x) { return std::abs(x); }); } Vector<3, T> cross(const Vector<3, T> other) const { return { y() * other.z() - z() * other.y(), z() * other.x() - x() * other.z(), x() * other.y() - y() * other.x(), }; } T operator[](USize index) const { return elements[index]; } T& operator[](USize index) { return elements[index]; } Vector operator+(const Vector other) const { return zip(other, [](auto a, auto b) { return a + b; }); } Vector operator+(T scalar) const { return map([=](auto x) { return x + scalar; }); } Vector operator*(T scalar) const { return map([=](auto x) { return x * scalar; }); } T operator*(const Vector other) const { return zip(other, [](auto a, auto b) { return a * b; }).sum(); } Vector operator-(const Vector other) const { return zip(other, [](auto a, auto b) { return a - b; }); } Vector operator-() const { return map([](T x) -> T { return -x; }); } Vector operator/(T scalar) const { return map([=](auto x) { return x / scalar; }); } Vector operator/(const Vector other) const { return zip(other, [](auto a, auto b) { return a / b; }); } Bool operator==(const Vector& other) { for (Int i = 0; i < S; i++) { if (elements[i] != other[i]) { return false; } } return true; } Bool operator!=(const Vector& other) { return !this->operator==(other); } Vector& operator+=(const Vector& other) { *this = *this + other; return *this; } T& x() { static_assert(S > 0); return elements[0]; } const T& x() const { static_assert(S > 0); return elements[0]; } T& y() { static_assert(S > 1); return elements[1]; } const T& y() const { static_assert(S > 1); return elements[1]; } T& z() { static_assert(S > 2); return elements[2]; } const T& z() const { static_assert(S > 2); return elements[2]; } T& w() { static_assert(S > 3); return elements[3]; } const T& w() const { static_assert(S > 3); return elements[3]; } std::string string() const { std::stringstream str{}; str << "[ "; for (Int i = 0; i < S; i++) { str << elements[i] << " "; } str << "]"; return str.str(); } static Vector<3, T> up() { return {(T)0, (T)1, (T)0}; } static Vector<3, T> down() { return {(T)0, (T)-1, (T)0}; } static Vector<3, T> forward() { return {(T)0, (T)0, (T)1}; } static Vector<3, T> back() { return {(T)0, (T)0, (T)-1}; } static Vector<3, T> right() { return {(T)1, (T)0, (T)0}; } static Vector<3, T> left() { return {(T)-1, (T)0, (T)0}; } static Vector<3, T> one() { return Vector{(T)1}; } static Vector<3, T> zero() { return Vector{(T)0}; } static Vector<3, T> max() { return Vector{(T)std::numeric_limits::max()}; } T elements[S]; }; using Vec2 = Vector<2, Real>; using Vec3 = Vector<3, Real>; using Vec4 = Vector<4, Real>;