#[cfg(test)]
mod tests;
use std::fmt::{Display, Formatter};
use std::ops::{Add, Sub};
#[derive(Debug, PartialEq, Copy, Clone)]
#[must_use]
pub struct Vector2D {
pub origin: Point2D,
pub target: Point2D
}
#[derive(Debug, PartialEq, Copy, Clone)]
#[must_use]
pub struct Point2D {
pub x: f64,
pub y: f64,
}
impl Point2D {
pub fn zero() -> Self {
Point2D {
x: 0.0,
y: 0.0,
}
}
pub fn new(x: f64, y: f64) -> Self {
Point2D {
x,
y,
}
}
pub fn set_x(mut self, x: f64) -> Self {
self.x = x;
self
}
pub fn set_y(mut self, y: f64) -> Self {
self.y = y;
self
}
pub fn shift(mut self, shift: (impl Into<f64>, impl Into<f64>)) -> Self {
self.x += shift.0.into();
self.y += shift.1.into();
self
}
pub fn get_distance(&self, rhs: Point2D) -> f64 {
f64::sqrt(
(self.x - rhs.x).powf(2.0)
+
(self.y - rhs.y).powf(2.0)
)
}
pub fn to_vector2d(&self, target: &Point2D) -> Vector2D {
Vector2D {
origin: *self,
target: *target
}
}
}
impl Vector2D {
pub fn zero() -> Self {
Vector2D {
origin: Point2D { x: 0.0, y: 0.0},
target: Point2D { x: 0.0, y: 0.0},
}
}
pub fn null(origin: Point2D) -> Self {
Vector2D {
origin,
target: Point2D { x: 0.0, y: 0.0},
}
}
pub fn new(origin: Point2D, target: Point2D) -> Self {
Vector2D {
origin,
target,
}
}
pub fn with_absolute_target(origin: Point2D, target: Point2D) -> Self {
Vector2D {
origin,
target: Point2D {
x: target.x - origin.x,
y: target.y - origin.y
},
}
}
pub fn set_origin(mut self, origin: Point2D) -> Self {
self.origin = origin;
self
}
pub fn set_target(mut self, target: Point2D) -> Self {
self.target = target;
self
}
pub fn set_target_absolute(mut self, target: Point2D) -> Self {
self.target = Point2D {
x: ((target.x - self.origin.x) * 1_000_000.0).round() / 1_000_000.0,
y: ((target.y - self.origin.y) * 1_000_000.0).round() / 1_000_000.0,
};
self
}
pub fn shift(mut self, shift: (impl Into<f64>, impl Into<f64>)) -> Self {
self.origin = Point2D {
x: self.origin.x + shift.0.into(),
y: self.origin.y + shift.1.into()
};
self
}
pub fn get_magnitude(&self) -> f64 {
f64::sqrt(
(self.origin.x - self.target.x).powf(2.0)
+
(self.origin.y - self.target.y).powf(2.0)
)
}
pub fn dot_product(&self, vector: Vector2D) -> f64 {
self.target.x * vector.target.x + self.target.y * vector.target.y
}
pub fn get_angle_between(&self, vector: Vector2D) -> f64 {
f64::acos(self.dot_product(vector) / (self.get_magnitude() * vector.get_magnitude()))
}
}
impl Display for Vector2D {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"({},{})[{},{}]",
self.origin.x,
self.origin.y,
self.target.x,
self.target.y,
)
}
}
impl Add for Vector2D {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Vector2D {
origin: self.origin,
target: Point2D {
x: rhs.target.x + self.target.x,
y: rhs.target.y + self.target.y
},
}
}
}
impl Sub for Vector2D {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Vector2D {
origin: self.origin,
target: Point2D {
x: self.target.x - rhs.target.x,
y: self.target.y - rhs.target.y
},
}
}
}
impl<T: Into<f64>, E: Into<f64>> From<(T, E)> for Point2D {
fn from(value: (T, E)) -> Self {
let value: (f64, f64) = (value.0.into(), value.1.into());
Point2D {
x: value.0,
y: value.1,
}
}
}
impl Add for Point2D {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Point2D {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl Sub for Point2D {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Point2D {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}