diff --git a/src/math/vector.cpp b/src/math/vector.cpp new file mode 100644 index 0000000..ded2d7d --- /dev/null +++ b/src/math/vector.cpp @@ -0,0 +1,101 @@ +#include "vector.hpp" +#include +#include + +#define VECTOR_EPSILON 0.00001f + +Vecf::Vecf(float x, float y) +: x{x}, y{y} {} + +Vecf::Vecf(Vecf const &&src) +: x{src.x}, y{src.y} {} + +Vecf::Vecf(std::initializer_list members) +: x{*members.begin()} +, y{*(members.begin() + 1)} {} + +Vecf &Vecf::operator=(Vecf const &src) { + this->x = src.x; + this->y = src.y; + return *this; +} + +Vecf &Vecf::operator=(std::initializer_list list) { + this->x = *list.begin(); + this->y = *(list.begin() + 1); + return *this; +} + +Vecf::operator SDL_FPoint() { + return (SDL_FPoint){this->x, this->y}; +} + +float Vecf::sqr_distance(Vecf const &from, Vecf const &to) { + float const xdif = std::fabs(to.x - from.x); + float const ydif = std::fabs(to.y - from.y); + return xdif * xdif + ydif * ydif; +} + +float Vecf::distance(Vecf const &from, Vecf const &to) { + return std::sqrt(Vecf::sqr_distance(from, to)); +} + +bool Vecf::equals_approximate(Vecf const &lhs, Vecf const &rhs) { + return std::fabs(lhs.x - rhs.x) < VECTOR_EPSILON && std::fabs(lhs.y - rhs.y) < VECTOR_EPSILON; +} + +float Vecf::dot(Vecf const &lhs, Vecf const &rhs) { + return (lhs.x*rhs.x) + (lhs.y*rhs.y); +} + +float Vecf::angle_between(Vecf const &lhs, Vecf const &rhs) { + return Vecf::dot(lhs, rhs) / (lhs.magnitude() * rhs.magnitude()); +} + +Vecf Vecf::lerp(Vecf const &from, Vecf const &to, float t) { + return from + ((to - from) * std::clamp(t, 0.f, 1.f)); +} + +Vecf Vecf::move_towards(Vecf const &from, Vecf const &to, float delta) { + return Vecf::lerp(from, to, delta / Vecf::distance(from, to)); +} + +float Vecf::magnitude() const { + return std::sqrt(this->x * this->x + this->y * this->y); +} + +float Vecf::sqr_magnitude() const { + return this->x * this->x + this->y * this->y; +} + +Vecf Vecf::perpendicular() const { + return {this->y, -this->x}; +} + +Vecf Vecf::rotate(float t) const { + return{ + cosf(t) * this->x - sinf(t) * this->y, + sinf(t) * this->x + cosf(t) * this->y + }; +} + +Vecf Vecf::normalized() const { + return *this / this->magnitude(); +} + +Vecf Vecf::reciprocal() const { + return {1.f / this->x, 1.f / this->y}; +} + +bool Vecf::is_nan() const { + return std::isnan(this->x) || std::isnan(this->y); +} + +void Vecf::scale(float x, float y) { + this->x *= x; + this->y *= y; +} + +void Vecf::scale(Vecf const &factors) { + this->scale(factors.x, factors.y); +} diff --git a/src/math/vector.hpp b/src/math/vector.hpp new file mode 100644 index 0000000..a7daefe --- /dev/null +++ b/src/math/vector.hpp @@ -0,0 +1,101 @@ +#ifndef VECTOR_MATH_HPP +#define VECTOR_MATH_HPP + +#include +#include + +struct Vecf { + Vecf() = default; + Vecf(float x, float y); + Vecf(std::initializer_list members); + Vecf(Vecf const &&src); + Vecf(Vecf const &src); + + ~Vecf() = default; + + Vecf &operator=(Vecf const &src); + Vecf &operator=(std::initializer_list list); + operator SDL_FPoint(); + //! squared distance between two vectors as points. Use for comparing distances efficiently. + static float sqr_distance(Vecf const &from, Vecf const &to); + //! distance between two vectors as points + static float distance(Vecf const &from, Vecf const &to); + //! compare based on an epsilon + static bool equals_approximate(Vecf const &lhs, Vecf const &rhs); + //! scalar member-wise multiplication product + static float dot(Vecf const &lhs, Vecf const &rhs); + //! unsigned angle difference in radians between lhs and rhs + static float angle_between(Vecf const &lhs, Vecf const &rhs); + //! interpolate linearly between two points + static Vecf lerp(Vecf const &from, Vecf const &to, float t); + //! move towards a point by a set unit distance + static Vecf move_towards(Vecf const &from, Vecf const &to, float delta); + //! magnitude (a.k.a length or absolute) of this vector + float magnitude() const; + //! square of the magnitude, use for comparing lengths of vectors efficiently + float sqr_magnitude() const; + //! vector perpendicular to this one + Vecf perpendicular() const; + //! rotate vector by t Radians + Vecf rotate(float t) const; + //! vector pointing in the same direction with a length of 1. Or, vector divided by it's magnitude + Vecf normalized() const; + //! reverse scale of vector + Vecf reciprocal() const; + //! returns true if either the x or y element is NaN + bool is_nan() const; + + //! scale vector member-wise + void scale(float x, float y); + //! scale vector member-wise + void scale(Vecf const &factors); + + float x{0.f}, y{0.f}; +}; + +static inline +Vecf operator-(Vecf const &v) { + return {-v.x, -v.y}; +} + +static inline +bool operator==(Vecf const &lhs, Vecf const &rhs) { + return lhs.x == rhs.x && lhs.y == rhs.y; +} + +static inline +Vecf operator+(Vecf const &lhs, Vecf const &rhs) { + return Vecf(lhs.x + rhs.x, lhs.y + rhs.y); +} + +static inline +Vecf operator-(Vecf const &lhs, Vecf const &rhs) { + return Vecf(lhs.x - rhs.x, lhs.y - rhs.y); +} +static inline +Vecf operator*(Vecf const &v, float f) { + return Vecf(v.x * f, v.y * f); +} +static inline +Vecf operator/(Vecf const &v, float f) { + return Vecf(v.x / f, v.y / f); +} + +static inline +Vecf &operator+=(Vecf &lhs, Vecf const &rhs) { + return lhs = lhs + rhs; +} +static inline +Vecf &operator-=(Vecf &lhs, Vecf const &rhs) { + return lhs = lhs - rhs; +} +static inline +Vecf &operator*=(Vecf &lhs, float rhs) { + return (lhs = lhs * rhs); +} +static inline +Vecf &operator/=(Vecf &lhs, float rhs) { + return lhs = lhs * rhs; +} + +#endif // !VECTOR_MATH_HPP