1use glam::{DVec2, DVec3, IVec2, dvec2};
2
3pub fn cross2d(a: DVec2, b: DVec2) -> f64 {
5 a.x * b.y - b.x * a.y
6}
7
8pub fn intersection(p1: DVec3, v1: DVec3, p2: DVec3, v2: DVec3) -> Option<DVec3> {
10 let cross = v1.cross(v2);
12 let denom = cross.length_squared();
13 if denom < f64::EPSILON {
14 return None;
15 }
16
17 let diff = p2 - p1;
18 let t = (diff).cross(v2).dot(cross) / denom;
19 let s = (diff).cross(v1).dot(cross) / denom;
20
21 let point1 = p1 + v1 * t;
22 let point2 = p2 + v2 * s;
23
24 if (point1 - point2).length_squared() < f64::EPSILON {
25 Some(point1)
26 } else {
27 None
28 }
29}
30
31#[derive(Debug, Clone, Copy)]
33pub struct Rect {
34 min: DVec2,
35 max: DVec2,
36}
37
38impl Rect {
39 pub fn union(&self, other: &Self) -> Self {
41 let min = self.min.min(other.min);
42 let max = self.max.max(other.max);
43 Self { min, max }
44 }
45 pub fn intersection(&self, other: &Self) -> Self {
47 let min = self.min.max(other.min);
48 let max = self.max.min(other.max);
49 Self { min, max }
50 }
51 pub fn center(&self) -> DVec2 {
53 (self.min + self.max) / 2.0
54 }
55
56 pub fn point(&self, edge: IVec2) -> DVec2 {
65 let min = self.min;
66 let center = self.center();
67 let max = self.max;
68
69 let x = match edge.x {
70 -1 => min.y,
71 0 => center.y,
72 1 => max.y,
73 _ => unreachable!(),
74 };
75 let y = match edge.y {
76 -1 => min.y,
77 0 => center.y,
78 1 => max.y,
79 _ => unreachable!(),
80 };
81
82 dvec2(x, y)
83 }
84}
85
86pub fn interpolate_usize(a: usize, b: usize, t: f64) -> (usize, f64) {
90 assert!(b >= a);
91 let t = t.clamp(0.0, 1.0);
92 let v = b - a;
93
94 let p = v as f64 * t;
95
96 (a + p.floor() as usize, p.fract())
97}
98
99#[cfg(test)]
100mod test {
101 use super::*;
102
103 #[test]
104 fn test_interpolate_usize() {
105 for (start, end, alpha, expected, remainder) in [
106 (0, 10, 0.0, 0, 0.0),
107 (0, 10, 0.5, 5, 0.0),
108 (0, 10, 1.0, 10, 0.0),
109 (0, 1, 0.5, 0, 0.5),
110 (0, 2, 0.8, 1, 0.6),
111 ] {
112 let (value, fraction) = interpolate_usize(start, end, alpha);
113 assert_eq!(value, expected);
114 assert!((fraction - remainder).abs() < f64::EPSILON);
115 }
116 }
117
118 #[test]
119 fn test_intersection() {
120 use glam::dvec3;
121
122 let p1 = dvec3(0.0, 0.0, 0.0);
124 let v1 = dvec3(1.0, 0.0, 0.0);
125 let p2 = dvec3(0.0, 1.0, 0.0);
126 let v2 = dvec3(0.0, -1.0, 0.0);
127 assert_eq!(intersection(p1, v1, p2, v2), Some(dvec3(0.0, 0.0, 0.0)));
128
129 let p1 = dvec3(1.0, 1.0, 0.0);
131 let v1 = dvec3(1.0, 2.0, 0.0);
132 let p2 = dvec3(3.0, 1.0, 0.0);
133 let v2 = dvec3(-1.0, 2.0, 0.0);
134 assert_eq!(intersection(p1, v1, p2, v2), Some(dvec3(2.0, 3.0, 0.0)));
135
136 let p1 = dvec3(0.0, 0.0, 0.0);
138 let v1 = dvec3(1.0, 1.0, 1.0);
139 let p2 = dvec3(1.0, 1.0, 1.0);
140 let v2 = dvec3(2.0, 2.0, 2.0);
141 assert!(intersection(p1, v1, p2, v2).is_none());
142
143 let p1 = dvec3(0.0, 0.0, 0.0);
145 let v1 = dvec3(1.0, 1.0, 0.0);
146 let p2 = dvec3(1.0, 0.0, 0.0);
147 let v2 = dvec3(1.0, 1.0, 0.0);
148 assert!(intersection(p1, v1, p2, v2).is_none());
149
150 let p1 = dvec3(0.0, 0.0, 0.0);
152 let v1 = dvec3(1.0, 0.0, 1.0);
153 let p2 = dvec3(0.0, 1.0, 0.0);
154 let v2 = dvec3(1.0, 0.0, -1.0);
155 assert!(intersection(p1, v1, p2, v2).is_none());
156 }
157}