1#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
15pub struct Point {
16 pub x: i32,
17 pub y: i32,
18}
19
20impl Point {
21 pub const ZERO: Self = Self { x: 0, y: 0 };
22
23 #[inline]
24 pub const fn new(x: i32, y: i32) -> Self {
25 Self { x, y }
26 }
27
28 #[inline]
30 pub fn distance(a: Self, b: Self) -> f32 {
31 let dx = (b.x - a.x) as f32;
32 let dy = (b.y - a.y) as f32;
33 (dx * dx + dy * dy).sqrt()
34 }
35
36 #[inline]
39 pub fn lerp_i32(origin: Self, target: Self, tx: f32, ty: f32) -> Self {
40 let x = origin.x as f32 + tx * (target.x - origin.x) as f32;
41 let y = origin.y as f32 + ty * (target.y - origin.y) as f32;
42 Self {
43 x: x.round() as i32,
44 y: y.round() as i32,
45 }
46 }
47}
48
49impl From<(i32, i32)> for Point {
50 #[inline]
51 fn from((x, y): (i32, i32)) -> Self {
52 Self { x, y }
53 }
54}
55
56impl From<Point> for (i32, i32) {
57 #[inline]
58 fn from(p: Point) -> Self {
59 (p.x, p.y)
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 #[test]
68 fn distance_zero_for_equal_points() {
69 assert_eq!(Point::distance(Point::new(5, 7), Point::new(5, 7)), 0.0);
70 }
71
72 #[test]
73 fn distance_matches_pythagoras() {
74 let d = Point::distance(Point::ZERO, Point::new(3, 4));
76 assert!((d - 5.0).abs() < 1e-6, "d = {d}");
77 }
78
79 #[test]
80 fn lerp_endpoints() {
81 let a = Point::new(10, 20);
82 let b = Point::new(110, 220);
83 assert_eq!(Point::lerp_i32(a, b, 0.0, 0.0), a);
84 assert_eq!(Point::lerp_i32(a, b, 1.0, 1.0), b);
85 }
86
87 #[test]
88 fn lerp_midpoint_rounds() {
89 let a = Point::new(0, 0);
90 let b = Point::new(1, 1); let mid = Point::lerp_i32(a, b, 0.5, 0.5);
92 assert!(mid == Point::new(1, 1) || mid == Point::new(0, 0));
93 }
94}