use std::ops::{Add, Sub};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Point {
pub x: f32,
pub y: f32,
}
impl Point {
pub fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
pub fn distance(&self, other: &Point) -> f32 {
((self.x - other.x).powi(2) + (self.y - other.y).powi(2)).sqrt()
}
pub fn cross(&self, other: &Point) -> f32 {
self.x * other.y - self.y * other.x
}
pub fn dot(&self, other: &Point) -> f32 {
self.x * other.x + self.y * other.y
}
}
impl From<(f32, f32)> for Point {
fn from((x, y): (f32, f32)) -> Self {
Point::new(x, y)
}
}
impl Add for Point {
type Output = Point;
fn add(self, rhs: Point) -> Point {
Point::new(self.x + rhs.x, self.y + rhs.y)
}
}
impl Sub for Point {
type Output = Point;
fn sub(self, rhs: Point) -> Point {
Point::new(self.x - rhs.x, self.y - rhs.y)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn distance_is_euclidean() {
let a = Point::new(0.0, 0.0);
let b = Point::new(3.0, 4.0);
assert!((a.distance(&b) - 5.0).abs() < 1e-6);
}
#[test]
fn cross_product_sign_indicates_rotation() {
let a = Point::new(1.0, 0.0);
let b = Point::new(0.0, 1.0);
assert!(a.cross(&b) > 0.0);
assert!(b.cross(&a) < 0.0);
}
#[test]
fn sub_yields_displacement_vector() {
let a = Point::new(5.0, 5.0);
let b = Point::new(2.0, 1.0);
let d = a - b;
assert_eq!(d, Point::new(3.0, 4.0));
}
}