#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct Point {
pub x: i32,
pub y: i32,
}
impl Point {
pub const ZERO: Self = Self { x: 0, y: 0 };
#[inline]
pub const fn new(x: i32, y: i32) -> Self {
Self { x, y }
}
#[inline]
pub fn distance(a: Self, b: Self) -> f32 {
let dx = (b.x - a.x) as f32;
let dy = (b.y - a.y) as f32;
(dx * dx + dy * dy).sqrt()
}
#[inline]
pub fn lerp_i32(origin: Self, target: Self, tx: f32, ty: f32) -> Self {
let x = origin.x as f32 + tx * (target.x - origin.x) as f32;
let y = origin.y as f32 + ty * (target.y - origin.y) as f32;
Self {
x: x.round() as i32,
y: y.round() as i32,
}
}
}
impl From<(i32, i32)> for Point {
#[inline]
fn from((x, y): (i32, i32)) -> Self {
Self { x, y }
}
}
impl From<Point> for (i32, i32) {
#[inline]
fn from(p: Point) -> Self {
(p.x, p.y)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn distance_zero_for_equal_points() {
assert_eq!(Point::distance(Point::new(5, 7), Point::new(5, 7)), 0.0);
}
#[test]
fn distance_matches_pythagoras() {
let d = Point::distance(Point::ZERO, Point::new(3, 4));
assert!((d - 5.0).abs() < 1e-6, "d = {d}");
}
#[test]
fn lerp_endpoints() {
let a = Point::new(10, 20);
let b = Point::new(110, 220);
assert_eq!(Point::lerp_i32(a, b, 0.0, 0.0), a);
assert_eq!(Point::lerp_i32(a, b, 1.0, 1.0), b);
}
#[test]
fn lerp_midpoint_rounds() {
let a = Point::new(0, 0);
let b = Point::new(1, 1); let mid = Point::lerp_i32(a, b, 0.5, 0.5);
assert!(mid == Point::new(1, 1) || mid == Point::new(0, 0));
}
}