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