#[derive(Debug, Clone, Copy, PartialEq, Default)] pub struct Point2D { x: f32, y: f32, } impl Point2D { pub const fn new(x: f32, y: f32) -> Option { if x.is_finite() && y.is_finite() { Some(Self { x, y }) } else { None } } pub const fn x(&self) -> f32 { self.x } pub const fn y(&self) -> f32 { self.y } pub(crate) fn translated(self, by: Vector2D) -> Option { Self::new(self.x + by.dx, self.y + by.dy) } } #[derive(Debug, Clone, Copy, PartialEq)] pub struct Vector2D { dx: f32, dy: f32, } impl Vector2D { pub const fn new(dx: f32, dy: f32) -> Option { if dx.is_finite() && dy.is_finite() { Some(Self { dx, dy }) } else { None } } pub const fn dx(&self) -> f32 { self.dx } pub const fn dy(&self) -> f32 { self.dy } pub(crate) const fn reflected_x(self) -> Self { Self { dx: -self.dx, dy: self.dy, } } pub(crate) const fn reflected_y(self) -> Self { Self { dx: self.dx, dy: -self.dy, } } } #[derive(Debug, Clone, Copy, PartialEq)] pub struct Dimensions { width: u32, height: u32, } impl Dimensions { pub const fn new(width: u32, height: u32) -> Option { if width == 0 || height == 0 { None } else { Some(Self { width, height }) } } pub const fn width(&self) -> u32 { self.width } pub const fn height(&self) -> u32 { self.height } } #[derive(Debug, Clone, Copy, PartialEq)] pub struct Color { pub r: u8, pub g: u8, pub b: u8, pub a: u8, }