use std::ops::{Add, AddAssign, RangeInclusive, Sub, SubAssign}; use crate::math::*; // Sometimes called a Point. I prefer the shorter `Pos2` so it is equal length to `Vec2` /// A position on screen. /// /// Normally given in points, e.g. logical pixels. #[derive(Clone, Copy, Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Pos2 { pub x: f32, pub y: f32, // implicit w = 1 } pub const fn pos2(x: f32, y: f32) -> Pos2 { Pos2 { x, y } } impl From<[f32; 2]> for Pos2 { fn from(v: [f32; 2]) -> Self { Self { x: v[0], y: v[1] } } } impl From<&[f32; 2]> for Pos2 { fn from(v: &[f32; 2]) -> Self { Self { x: v[0], y: v[1] } } } impl Pos2 { pub const fn new(x: f32, y: f32) -> Self { Self { x, y } } pub fn to_vec2(self) -> Vec2 { Vec2 { x: self.x, y: self.y, } } pub fn distance(self, other: Self) -> f32 { (self - other).length() } pub fn distance_sq(self, other: Self) -> f32 { (self - other).length_sq() } pub fn floor(self) -> Self { pos2(self.x.floor(), self.y.floor()) } pub fn round(self) -> Self { pos2(self.x.round(), self.y.round()) } pub fn ceil(self) -> Self { pos2(self.x.ceil(), self.y.ceil()) } pub fn is_finite(self) -> bool { self.x.is_finite() && self.y.is_finite() } #[must_use] pub fn min(self, other: Self) -> Self { pos2(self.x.min(other.x), self.y.min(other.y)) } #[must_use] pub fn max(self, other: Self) -> Self { pos2(self.x.max(other.x), self.y.max(other.y)) } #[must_use] pub fn clamp(self, range: RangeInclusive) -> Self { Self { x: clamp(self.x, range.start().x..=range.end().x), y: clamp(self.y, range.start().y..=range.end().y), } } } impl PartialEq for Pos2 { fn eq(&self, other: &Self) -> bool { self.x == other.x && self.y == other.y } } impl Eq for Pos2 {} impl AddAssign for Pos2 { fn add_assign(&mut self, rhs: Vec2) { *self = Pos2 { x: self.x + rhs.x, y: self.y + rhs.y, }; } } impl SubAssign for Pos2 { fn sub_assign(&mut self, rhs: Vec2) { *self = Pos2 { x: self.x - rhs.x, y: self.y - rhs.y, }; } } impl Add for Pos2 { type Output = Pos2; fn add(self, rhs: Vec2) -> Pos2 { Pos2 { x: self.x + rhs.x, y: self.y + rhs.y, } } } impl Sub for Pos2 { type Output = Vec2; fn sub(self, rhs: Pos2) -> Vec2 { Vec2 { x: self.x - rhs.x, y: self.y - rhs.y, } } } impl Sub for Pos2 { type Output = Pos2; fn sub(self, rhs: Vec2) -> Pos2 { Pos2 { x: self.x - rhs.x, y: self.y - rhs.y, } } } impl std::fmt::Debug for Pos2 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "[{:.1} {:.1}]", self.x, self.y) } }