use core::{
fmt,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use vexide::{devices::math::Point2, float::Float};
#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
pub struct Vec2<T> {
pub x: T,
pub y: T,
}
impl<T> Vec2<T> {
pub const fn new(x: T, y: T) -> Self {
Self { x, y }
}
pub fn set_x(&mut self, x: T) {
self.x = x;
}
pub fn set_y(&mut self, y: T) {
self.y = y;
}
}
impl<T: Copy> Vec2<T> {
pub const fn x(&self) -> T {
self.x
}
pub const fn y(&self) -> T {
self.y
}
}
impl<T: Float + Copy + Mul<Output = T>> Vec2<T> {
pub fn from_polar(r: T, theta: T) -> Self {
let (sin, cos) = theta.sin_cos();
Vec2 {
x: r * cos,
y: r * sin,
}
}
}
impl<T: Float + Copy> Vec2<T> {
pub fn angle(&self) -> T {
self.y.atan2(self.x)
}
pub fn length(&self) -> T {
self.x.hypot(self.y)
}
}
impl<T: Float + Copy + Sub<Output = T>> Vec2<T> {
pub fn distance(&self, other: Vec2<T>) -> T {
(*self - other).length()
}
}
impl<T: Float + Copy + Div<Output = T>> Vec2<T> {
#[must_use]
pub fn unit(&self) -> Self {
*self / self.length()
}
}
impl<T: Float + Copy + Add<Output = T> + Sub<Output = T> + Mul<Output = T>> Vec2<T> {
#[must_use]
pub fn lerp(self, other: Vec2<T>, t: T) -> Vec2<T> {
self + ((other - self) * t)
}
#[must_use]
pub fn rotated(&self, angle: T) -> Self {
let (sin, cos) = angle.sin_cos();
Self {
x: self.x * cos - self.y * sin,
y: self.x * sin + self.y * cos,
}
}
}
impl<T: Float + Copy + Mul<Output = T> + Sub<Output = T>> Vec2<T> {
pub fn cross(&self, other: Vec2<T>) -> T {
self.x * other.y - self.y * other.x
}
}
impl<T: Float + Copy + Mul<Output = T> + Add<Output = T>> Vec2<T> {
pub fn dot(&self, other: Vec2<T>) -> T {
self.x * other.x + self.y * other.y
}
}
impl<T: Float + Copy + Mul<Output = T> + Add<Output = T> + Div<Output = T>> Vec2<T> {
#[must_use]
pub fn projected(&self, onto: Vec2<T>) -> Self {
onto * (self.dot(onto) / onto.length().powi(2))
}
}
impl<T> From<(T, T)> for Vec2<T> {
fn from(tuple: (T, T)) -> Self {
Self {
x: tuple.0,
y: tuple.1,
}
}
}
impl<T> From<Point2<T>> for Vec2<T> {
fn from(value: Point2<T>) -> Self {
Self {
x: value.x,
y: value.y,
}
}
}
impl<T: fmt::Display> fmt::Display for Vec2<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
impl<T: Add<Output = T>> Add for Vec2<T> {
type Output = Self;
fn add(self, other: Vec2<T>) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl<T: Sub<Output = T>> Sub for Vec2<T> {
type Output = Self;
fn sub(self, other: Vec2<T>) -> Self {
Self {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
impl<T: Mul<Output = T> + Copy> Mul<T> for Vec2<T> {
type Output = Self;
fn mul(self, scalar: T) -> Self {
Self {
x: self.x * scalar,
y: self.y * scalar,
}
}
}
impl<T: Div<Output = T> + Copy> Div<T> for Vec2<T> {
type Output = Self;
fn div(self, scalar: T) -> Self {
Self {
x: self.x / scalar,
y: self.y / scalar,
}
}
}
impl<T: Neg<Output = T>> Neg for Vec2<T> {
type Output = Self;
fn neg(self) -> Self {
Self {
x: -self.x,
y: -self.y,
}
}
}
impl<T: AddAssign> AddAssign for Vec2<T> {
fn add_assign(&mut self, other: Vec2<T>) {
self.x += other.x;
self.y += other.y;
}
}
impl<T: SubAssign> SubAssign for Vec2<T> {
fn sub_assign(&mut self, other: Vec2<T>) {
self.x -= other.x;
self.y -= other.y;
}
}
impl<T: MulAssign + Copy> MulAssign<T> for Vec2<T> {
fn mul_assign(&mut self, scalar: T) {
self.x *= scalar;
self.y *= scalar;
}
}
impl<T: DivAssign + Copy> DivAssign<T> for Vec2<T> {
fn div_assign(&mut self, scalar: T) {
self.x /= scalar;
self.y /= scalar;
}
}