use crate::geometry::vec::*; use std::ops::*; use num_traits::{NumOps, NumAssignOps}; use num_traits::pow::Pow; use num_traits::real::Real; macro_rules! impl_point { ($PointN:ident { $($field:ident),+ }, $VecN:ident) => { #[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)] pub struct $PointN { $(pub $field: T),+ } impl $PointN { pub fn new($($field: T),+) -> $PointN { $PointN { $($field),+ } } } impl + Copy> $PointN { pub fn distance_squared(self, other: $PointN) -> T { (self - other).magnitude_squared() } } impl> $PointN { pub fn distance(self, other: $PointN) -> T { (self - other).magnitude() } } impl Add<$VecN> for $PointN { type Output = Self; fn add(self, other: $VecN) -> Self { $PointN { $($field: self.$field + other.$field),+ } } } impl AddAssign<$VecN> for $PointN { fn add_assign(&mut self, other: $VecN) { $(self.$field += other.$field);+ } } impl Sub for $PointN { type Output = $VecN; fn sub(self, other: Self) -> $VecN { $VecN { $($field: self.$field - other.$field),+ } } } } } impl_point!(Point2d { x, y }, Vec2d); impl_point!(Point3d { x, y, z }, Vec3d); #[cfg(test)] mod tests { use super::*; #[test] fn distance_in_x_dimension_example() { let a = Point2d::new(1., 1.); let b = Point2d::new(3., 1.); assert_eq!(a.distance(b), 2.); assert_eq!(a.distance_squared(b), 4.); } #[test] fn distance_in_y_dimension_example() { let a = Point2d::new(1., 1.); let b = Point2d::new(1., 3.); assert_eq!(b.distance(a), 2.); assert_eq!(b.distance_squared(a), 4.); } }