#include "vec.hpp" #include #include #include namespace math { float vec3f::dot(const vec3f &rhs) const { return (x * rhs.x) + (y * rhs.y) + (z * rhs.z); } double vec3f::ddot(const vec3f &rhs) const { return (static_cast(x) * rhs.x) + (static_cast(y) * rhs.y) + (static_cast(z) * rhs.z); } float vec3f::dot(const vec4f &rhs) const { return (x * rhs.x) + (y * rhs.y) + (z * rhs.z); } double vec3f::ddot(const vec4f &rhs) const { return (static_cast(x) * rhs.x) + (static_cast(y) * rhs.y) + (static_cast(z) * rhs.z); } float vec3f::operator*(const vec3f &rhs) const { return dot(rhs); } float vec3f::operator*(const vec4f &rhs) const { return dot(rhs); } vec3f vec3f::operator*(const float rhs) const { return {x * rhs, y * rhs, z * rhs}; } vec3f vec3f::operator+(const vec3f &rhs) const { return {x + rhs.x, y + rhs.y, z + rhs.z}; } vec3f vec3f::operator-(const vec3f &rhs) const { return {x - rhs.x, y - rhs.y, z - rhs.z}; } bool vec3f::operator==(const vec3f &rhs) const { return x == rhs.x && y == rhs.y && z == rhs.z; } float &vec3f::operator[](const std::size_t i) { switch (i) { case 0: return x; case 1: return y; case 2: return z; default: throw std::out_of_range("vec3f::operator[]"); } } vec3f vec3f::normalize() const { vec3f res{0.0f, 0.0f, 0.0f}; if (const auto d = dot(*this); d > 0.0f) { res = *this * (1.0f / std::sqrt(d)); } return res; } vec3f vec3f::multiply_add(const vec3f &rhs, const float scale) const { return { x + (scale * rhs.x), y + (scale * rhs.y), z + (scale * rhs.z) }; } vec3f vec3f::cross(const vec3f &rhs) const { return { (y * rhs.z) - (z * rhs.y), (z * rhs.x) - (x * rhs.z), (x * rhs.y) - (y * rhs.x) }; } float vec3f::magnitude() const { return std::sqrt(dot(*this)); } vec3f vec3f::operator-() const { return {-x, -y, -z}; } vec3f project_point_on_plane(const vec3f &point, const vec3f &normal) { const auto inv_denom = 1.0f / normal.dot(normal); const auto dist = normal.dot(point) * inv_denom; const auto scaled_normal = normal * inv_denom; return point - (scaled_normal * dist); } vec3f vec3f::perpendicular() const { vec3f res{0.0f, 0.0f, 0.0f}; auto pos = 0; auto min = 1.0f; if (std::abs(x) < min) { pos = 0; min = std::abs(x); } if (std::abs(y) < min) { pos = 1; min = std::abs(y); } if (std::abs(z) < min) { pos = 2; min = std::abs(z); } switch (pos) { case 0: res.x = 1.0f; break; case 1: res.y = 1.0f; break; case 2: res.z = 1.0f; break; default: std::unreachable(); } res = project_point_on_plane(res, *this); res = res.normalize(); return res; } std::array vec3f::into_array() const { return std::array{x, y, z}; } vec3f vec3f::to_angles(const vec3f forward) { const vec3f temp{forward.x, forward.y, 0.0f}; auto pitch = -std::atan2(forward.z, temp.magnitude()); auto yaw = std::atan2(forward.y, forward.x); auto roll = 0.0f; return {pitch, yaw, roll}; } std::tuple vec3f::from_angles(const vec3f &angles) { vec3f forward{0.0f, 0.0f, 0.0f}; vec3f right{0.0f, 0.0f, 0.0f}; vec3f up{0.0f, 0.0f, 0.0f}; const auto pitch = angles.x * (std::numbers::pi * 2 / 360); const auto pitch_sin = std::sin(pitch); const auto pitch_cos = std::cos(pitch); const auto yaw = angles.y * (std::numbers::pi * 2 / 360); const auto yaw_sin = std::sin(yaw); const auto yaw_cos = std::cos(yaw); const auto roll = angles.z * (std::numbers::pi * 2 / 360); const auto roll_sin = std::sin(roll); const auto roll_cos = std::cos(roll); forward = { static_cast(pitch_cos * yaw_cos), static_cast(pitch_cos * yaw_sin), static_cast(-pitch_sin) }; right = { static_cast(-1 * roll_sin * pitch_sin * yaw_cos + -1 * roll_cos * -yaw_sin), static_cast(-1 * roll_sin * pitch_sin * yaw_sin + -1 * roll_cos * yaw_cos), static_cast(-1 * roll_sin * pitch_cos), }; up = { static_cast(roll_cos * pitch_sin * yaw_cos + -roll_sin * -yaw_sin), static_cast(roll_cos * pitch_sin * yaw_sin + -roll_sin * yaw_cos), static_cast(roll_cos * pitch_cos), }; return {forward, right, up}; } /** * turn forward towards side on the plane defined by forward and side * if angle = 90, the result will be equal to side * assumes side and forward are perpendicular, and normalized * to turn away from side, use a negative angle * * @param forward * @param side * @param angle * @return */ vec3f vec3f::turn(const vec3f &forward, const vec3f &side, const float angle) { const float scale_forward = static_cast(std::cos(degrees_to_radians(angle))); const float scale_side = static_cast(std::sin(degrees_to_radians(angle))); return (forward * scale_forward) + (side * scale_side); } float & vec4f::operator[](std::size_t i) { switch (i) { case 0: return x; case 1: return y; case 2: return z; case 3: return w; default: throw std::out_of_range("vec4f::operator[]"); } } }