use core::fmt::{Debug, Formatter}; use core::ops::{Mul, Sub, Add}; use num::{One, pow, integer::Roots}; use core::cmp::{min, max}; pub trait CoordinateOp: PartialOrd + PartialEq + Sub + Clone + Mul + Copy + One + Add + Eq + Debug where Self: Sub { const MIN: Self; const MAX: Self; fn distance(x1: Self, y1: Self, x2: Self, y2: Self) -> Self; } pub trait CoordinateSpace { type Data: CoordinateOp; } #[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord)] pub struct Coordinates { pub x: S::Data, pub y: S::Data, } impl Debug for Coordinates where S::Data: Debug { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_tuple("@") .field(&self.x) .field(&self.y) .finish() } } impl CoordinateOp for u8 { const MIN: u8 = 0; const MAX: u8 = 255; fn distance(x1: Self, y1: Self, x2: Self, y2: Self) -> Self { (max(x2, x1) - min(x2, x1)).saturating_add(max(y2, y1) - min(y2, y1)) } } impl CoordinateOp for u16 { const MIN: u16 = u16::MIN; const MAX: u16 = u16::MAX; fn distance(x1: Self, y1: Self, x2: Self, y2: Self) -> Self { (pow(x2 - x1, 2) + pow(y2 - y1, 2)).sqrt() } } impl CoordinateOp for usize { const MIN: usize = usize::MIN; const MAX: usize = usize::MAX; fn distance(x1: Self, y1: Self, x2: Self, y2: Self) -> Self { (pow(x2 - x1, 2) + pow(y2 - y1, 2)).sqrt() } } impl Coordinates { pub const fn new(x: S::Data, y: S::Data) -> Self { Self { x, y } } const fn top_left() -> Self { Self::new(S::Data::MIN, S::Data::MIN) } const fn top_right() -> Self { Self::new(S::Data::MAX, S::Data::MIN) } const fn bottom_left() -> Self { Self::new(S::Data::MIN, S::Data::MAX) } const fn bottom_right() -> Self { Self::new(S::Data::MAX, S::Data::MAX) } pub fn distance_to(&self, other: &Self) -> S::Data { S::Data::distance(self.x, other.x, self.y, other.y) } } #[derive(PartialEq, Debug, Copy, Clone)] pub struct Virtual {} impl CoordinateSpace for Virtual { type Data = u8; } pub type VirtualCoordinates = Coordinates; #[derive(PartialEq, Eq, Copy, Clone, Debug, PartialOrd)] pub struct Rectangle { pub top_left: Coordinates, pub bottom_right: Coordinates } impl Rectangle { pub const fn new(top_left: Coordinates, bottom_right: Coordinates) -> Self { Self { top_left, bottom_right } } pub const fn everything() -> Self { Self { top_left: Coordinates::::top_left(), bottom_right: Coordinates::::bottom_right() } } pub fn width(&self) -> Space::Data { self.bottom_right.x - self.top_left.x } pub fn height(&self) -> Space::Data { self.bottom_right.y - self.top_left.y } pub const fn left(&self) -> Space::Data { self.top_left.x } pub const fn top(&self) -> Space::Data { self.top_left.y } pub const fn right (&self) -> Space::Data { self.bottom_right.x } pub const fn bottom(&self) -> Space::Data { self.bottom_right.y } }