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 core::f64;
102
103 use super::*;
104
105 #[test]
106 fn test_interpolate_usize() {
107 let test = |(x, t): (usize, f64), (expected_x, expected_t): (usize, f64)| {
108 assert_eq!(x, expected_x);
109 assert!((t - expected_t).abs() < f64::EPSILON);
110 };
111
112 test(interpolate_usize(0, 10, 0.0), (0, 0.0));
113 test(interpolate_usize(0, 10, 0.5), (5, 0.0));
114 test(interpolate_usize(0, 10, 1.0), (10, 0.0));
115
116 test(interpolate_usize(0, 1, 0.0), (0, 0.0));
117 test(interpolate_usize(0, 1, 0.5), (0, 0.5));
118 test(interpolate_usize(0, 1, 1.0), (1, 0.0));
119
120 test(interpolate_usize(0, 2, 0.0), (0, 0.0));
121 test(interpolate_usize(0, 2, 0.2), (0, 0.4));
122 test(interpolate_usize(0, 2, 0.4), (0, 0.8));
123 test(interpolate_usize(0, 2, 0.6), (1, 0.2));
124 test(interpolate_usize(0, 2, 0.8), (1, 0.6));
125 test(interpolate_usize(0, 2, 1.0), (2, 0.0));
126 }
127
128 #[test]
129 fn test_intersection() {
130 use glam::dvec3;
131
132 let p1 = dvec3(0.0, 0.0, 0.0);
134 let v1 = dvec3(1.0, 0.0, 0.0);
135 let p2 = dvec3(0.0, 1.0, 0.0);
136 let v2 = dvec3(0.0, -1.0, 0.0);
137 assert_eq!(intersection(p1, v1, p2, v2), Some(dvec3(0.0, 0.0, 0.0)));
138
139 let p1 = dvec3(1.0, 1.0, 0.0);
141 let v1 = dvec3(1.0, 2.0, 0.0);
142 let p2 = dvec3(3.0, 1.0, 0.0);
143 let v2 = dvec3(-1.0, 2.0, 0.0);
144 assert_eq!(intersection(p1, v1, p2, v2), Some(dvec3(2.0, 3.0, 0.0)));
145
146 let p1 = dvec3(0.0, 0.0, 0.0);
148 let v1 = dvec3(1.0, 1.0, 1.0);
149 let p2 = dvec3(1.0, 1.0, 1.0);
150 let v2 = dvec3(2.0, 2.0, 2.0);
151 assert!(intersection(p1, v1, p2, v2).is_none());
152
153 let p1 = dvec3(0.0, 0.0, 0.0);
155 let v1 = dvec3(1.0, 1.0, 0.0);
156 let p2 = dvec3(1.0, 0.0, 0.0);
157 let v2 = dvec3(1.0, 1.0, 0.0);
158 assert!(intersection(p1, v1, p2, v2).is_none());
159
160 let p1 = dvec3(0.0, 0.0, 0.0);
162 let v1 = dvec3(1.0, 0.0, 1.0);
163 let p2 = dvec3(0.0, 1.0, 0.0);
164 let v2 = dvec3(1.0, 0.0, -1.0);
165 assert!(intersection(p1, v1, p2, v2).is_none());
166 }
167}