use crate::geometry::{Point, Transform, Transformation};
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
pub struct Vector {
pub x: f64,
pub y: f64,
}
impl Vector {
pub fn new(x: f64, y: f64) -> Vector {
Vector { x, y }
}
pub fn zero() -> Vector {
Vector::new(0.0, 0.0)
}
pub fn to_point(self) -> Point {
Point::new(self.x, self.y)
}
pub fn length(self) -> f64 {
self.x.hypot(self.y)
}
pub fn normalize(self) -> Option<Vector> {
let length = self.length();
if length == 0.0 {
None
} else {
Some(self / length)
}
}
pub fn dot(self, other: Vector) -> f64 {
self.x * other.x + self.y * other.y
}
pub fn cross(self, other: Vector) -> f64 {
self.x * other.y - self.y * other.x
}
pub fn scale(self, v: Vector) -> Vector {
Vector::new(self.x * v.x, self.y * v.y)
}
}
impl AddAssign for Vector {
fn add_assign(&mut self, other: Vector) {
*self = *self + other
}
}
impl SubAssign for Vector {
fn sub_assign(&mut self, other: Vector) {
*self = *self - other
}
}
impl MulAssign<f64> for Vector {
fn mul_assign(&mut self, k: f64) {
*self = *self * k
}
}
impl DivAssign<f64> for Vector {
fn div_assign(&mut self, k: f64) {
*self = *self / k
}
}
impl Add for Vector {
type Output = Vector;
fn add(self, other: Vector) -> Vector {
Vector::new(self.x + other.x, self.y + other.y)
}
}
impl Sub for Vector {
type Output = Vector;
fn sub(self, other: Vector) -> Vector {
Vector::new(self.x - other.x, self.y - other.y)
}
}
impl Mul<f64> for Vector {
type Output = Vector;
fn mul(self, k: f64) -> Vector {
Vector::new(self.x * k, self.y * k)
}
}
impl Div<f64> for Vector {
type Output = Vector;
fn div(self, k: f64) -> Vector {
Vector::new(self.x / k, self.y / k)
}
}
impl Neg for Vector {
type Output = Vector;
fn neg(self) -> Vector {
Vector::new(-self.x, -self.y)
}
}
impl Transform for Vector {
fn transform<T>(self, t: &T) -> Vector
where
T: Transformation,
{
t.transform_vector(self)
}
fn transform_mut<T>(&mut self, t: &T)
where
T: Transformation,
{
*self = self.transform(t);
}
}