#pragma once #include #include "third-party/fmt/core.h" namespace math { template class Vector { public: Vector() = default; static Vector zero() { Vector result; for (auto& x : result.m_data) { x = T(0); } return result; } template Vector(Args... args) : m_data{T(args)...} {} T* begin() { return &m_data[0]; } T* end() { return &m_data[Size]; } const T* begin() const { return &m_data[0]; } const T* end() const { return &m_data[Size]; } T& x() { return m_data[0]; } const T& x() const { return m_data[0]; } T& y() { static_assert(Size >= 1, "Out of bounds"); return m_data[1]; } const T& y() const { static_assert(Size >= 1, "Out of bounds"); return m_data[1]; } T& z() { static_assert(Size >= 2, "Out of bounds"); return m_data[2]; } const T& z() const { static_assert(Size >= 2, "Out of bounds"); return m_data[2]; } T& w() { static_assert(Size >= 3, "Out of bounds"); return m_data[3]; } const T& w() const { static_assert(Size >= 3, "Out of bounds"); return m_data[3]; } const T squared_length() const { T sum = T(0); for (auto val : m_data) { sum += val * val; } return sum; } const T length() const { return std::sqrt(squared_length()); } Vector operator+(const Vector& other) const { Vector result; for (int i = 0; i < Size; i++) { result[i] = m_data[i] + other[i]; } return result; } Vector operator-(const Vector& other) const { Vector result; for (int i = 0; i < Size; i++) { result[i] = m_data[i] - other[i]; } return result; } T dot(const Vector& other) const { T result(0); for (int i = 0; i < Size; i++) { result += m_data[i] * other[i]; } return result; } T operator[](int idx) const { return m_data[idx]; } T& operator[](int idx) { return m_data[idx]; } Vector operator/(const T& val) const { Vector result; for (int i = 0; i < Size; i++) { result[i] = m_data[i] / val; } return result; } Vector operator*(const T& val) const { Vector result; for (int i = 0; i < Size; i++) { result[i] = m_data[i] * val; } return result; } Vector normalized(const T& norm = T(1)) const { return (*this) * (norm / length()); } void normalize(const T& norm = T(1)) { *this = normalized(norm); } std::string to_string_aligned() const { std::string result = "["; for (auto x : m_data) { result.append(fmt::format("{: 6.3f} ", x)); } result.pop_back(); return result + "]"; } private: T m_data[Size]; }; template using Vector2 = Vector; template using Vector3 = Vector; template using Vector4 = Vector; using Vector2f = Vector2; using Vector3f = Vector3; using Vector4f = Vector4; using Vector2d = Vector2; using Vector3d = Vector3; using Vector4d = Vector4; } // namespace math