use std::fmt;
use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Neg};
#[derive(PartialEq, Debug, Clone, Copy)]
pub struct Vec2 {
pub x: f32,
pub y: f32,
}
impl Vec2 {
pub const DOWN: Vec2 = Vec2 {x: 0., y: -1. };
pub const UP: Vec2 = Vec2 {x: 0., y: 1. };
pub const RIGHT: Vec2 = Vec2 {x: 1., y: 0. };
pub const LEFT: Vec2 = Vec2 {x: -1., y: 0. };
pub const ONE: Vec2 = Vec2 {x: 1., y: 1. };
pub const ZERO: Vec2 = Vec2 {x: 0., y: 0. };
pub fn new(x: f32, y: f32) -> Vec2 {
Vec2 { x, y }
}
pub fn set(&mut self, x: f32, y: f32) {
self.x = x;
self.y = y;
}
pub fn magnitude(&self) -> f32 {
Vec2::ZERO.distance_to(*self)
}
pub fn magnitude_squared(&self) -> f32 {
Vec2::ZERO.distance_to_squared(*self)
}
pub fn equals(&self, other: Vec2, epsilon: f32) -> bool {
(self.x - other.x).abs() < epsilon && (self.y - other.y).abs() < epsilon
}
pub fn normalized(&self) -> Vec2 {
let magnitude = self.magnitude();
*self / Vec2::new(magnitude, magnitude)
}
pub fn distance_to(&self, other: Vec2) -> f32 {
self.distance_to_squared(other).sqrt()
}
pub fn distance_to_squared(&self, other: Vec2) -> f32 {
let lx = other.x - self.x;
let ly = other.y - self.y;
lx.powi(2) + ly.powi(2)
}
pub fn dot(&self, other: Vec2) -> f32 {
self.x * other.x + self.y * other.y
}
pub fn angle_between(&self, other: Vec2) -> f32 {
let dot = self.dot(other);
let magnitude_product = self.magnitude() * other.magnitude();
if magnitude_product == 0.0 {
return 0.0;
}
let cos_theta = dot / magnitude_product;
cos_theta.min(1.0).max(-1.0).acos()
}
pub fn lerp(&self, other: Vec2, t: f32) -> Vec2 {
Vec2 {
x: self.x * (1.0 - t) + other.x * t,
y: self.y * (1.0 - t) + other.y * t,
}
}
pub fn add_length_by_angle(&self, angle: f32, length: f32) -> Vec2 {
Vec2 {
x: self.x + angle.cos() * length,
y: self.y + angle.sin() * length,
}
}
pub fn project(&self, onto: Vec2) -> Vec2 {
let onto_normalized = onto.normalized();
let scalar = self.dot(onto_normalized);
Vec2 { x: onto_normalized.x * scalar, y: onto_normalized.y * scalar }
}
pub fn rotate(&self, angle: f32) -> Vec2 {
let mut new_vec = Vec2::new(0.0, 0.0);
new_vec.x = self.x * angle.cos() - self.y * angle.sin();
new_vec.y = self.x * angle.sin() + self.y * angle.cos();
new_vec
}
}
impl Add for Vec2 {
type Output = Vec2;
fn add(self, rhs: Self) -> Self::Output {
Self {x: self.x + rhs.x, y: self.y + rhs.y }
}
}
impl AddAssign<Vec2> for Vec2 {
fn add_assign(&mut self, rhs: Vec2) {
self.x += rhs.x;
self.y += rhs.y;
}
}
impl Sub for Vec2 {
type Output = Vec2;
fn sub(self, rhs: Self) -> Self::Output {
Vec2::new(self.x - rhs.x, self.y - rhs.y)
}
}
impl SubAssign<Vec2> for Vec2 {
fn sub_assign(&mut self, rhs: Vec2) {
self.x -= rhs.x;
self.y -= rhs.y;
}
}
impl Mul for Vec2 {
type Output = Vec2;
fn mul(self, rhs: Self) -> Self::Output {
Vec2::new(self.x * rhs.x, self.y * rhs.y)
}
}
impl MulAssign<Vec2> for Vec2 {
fn mul_assign(&mut self, rhs: Vec2) {
self.x *= rhs.x;
self.y *= rhs.y;
}
}
impl Div for Vec2 {
type Output = Vec2;
fn div(self, rhs: Self) -> Self::Output {
Vec2::new(self.x / rhs.x, self.y / rhs.y)
}
}
impl DivAssign<Vec2> for Vec2 {
fn div_assign(&mut self, rhs: Vec2) {
self.x /= rhs.x;
self.y /= rhs.y;
}
}
impl Neg for Vec2 {
type Output = Vec2;
fn neg(self) -> Self::Output {
Vec2::new(-self.x, -self.y)
}
}
impl fmt::Display for Vec2 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}