1pub type Real = f32;
11
12#[inline]
14pub fn vert_leq(u_s: Real, u_t: Real, v_s: Real, v_t: Real) -> bool {
15 u_s < v_s || (u_s == v_s && u_t <= v_t)
16}
17
18#[inline]
20pub fn vert_eq(u_s: Real, u_t: Real, v_s: Real, v_t: Real) -> bool {
21 u_s == v_s && u_t == v_t
22}
23
24#[inline]
26pub fn trans_leq(u_s: Real, u_t: Real, v_s: Real, v_t: Real) -> bool {
27 u_t < v_t || (u_t == v_t && u_s <= v_s)
28}
29
30pub fn edge_eval(u_s: Real, u_t: Real, v_s: Real, v_t: Real, w_s: Real, w_t: Real) -> Real {
36 let gap_l = v_s - u_s;
38 let gap_r = w_s - v_s;
39 if gap_l + gap_r > 0.0 {
40 if gap_l < gap_r {
41 (v_t - u_t) + (u_t - w_t) * (gap_l / (gap_l + gap_r))
42 } else {
43 (v_t - w_t) + (w_t - u_t) * (gap_r / (gap_l + gap_r))
44 }
45 } else {
46 0.0
47 }
48}
49
50#[inline]
54pub fn edge_sign(u_s: Real, u_t: Real, v_s: Real, v_t: Real, w_s: Real, w_t: Real) -> Real {
55 edge_eval(u_s, u_t, v_s, v_t, w_s, w_t)
56}
57
58pub fn trans_eval(u_s: Real, u_t: Real, v_s: Real, v_t: Real, w_s: Real, w_t: Real) -> Real {
60 let gap_l = v_t - u_t;
62 let gap_r = w_t - v_t;
63 if gap_l + gap_r > 0.0 {
64 if gap_l < gap_r {
65 (v_s - u_s) + (u_s - w_s) * (gap_l / (gap_l + gap_r))
66 } else {
67 (v_s - w_s) + (w_s - u_s) * (gap_r / (gap_l + gap_r))
68 }
69 } else {
70 0.0
71 }
72}
73
74pub fn trans_sign(u_s: Real, u_t: Real, v_s: Real, v_t: Real, w_s: Real, w_t: Real) -> Real {
76 let gap_l = v_t - u_t;
78 let gap_r = w_t - v_t;
79 if gap_l + gap_r > 0.0 {
80 (v_s - w_s) * gap_l + (v_s - u_s) * gap_r
81 } else {
82 0.0
83 }
84}
85
86#[inline]
88pub fn vert_ccw(u_s: Real, u_t: Real, v_s: Real, v_t: Real, w_s: Real, w_t: Real) -> bool {
89 u_s * (v_t - w_t) + v_s * (w_t - u_t) + w_s * (u_t - v_t) >= 0.0
90}
91
92#[inline]
94pub fn vert_l1_dist(u_s: Real, u_t: Real, v_s: Real, v_t: Real) -> Real {
95 (u_s - v_s).abs() + (u_t - v_t).abs()
96}
97
98#[inline]
102pub fn real_interpolate(mut a: Real, x: Real, mut b: Real, y: Real) -> Real {
103 if a < 0.0 {
104 a = 0.0;
105 }
106 if b < 0.0 {
107 b = 0.0;
108 }
109 if a <= b {
110 if b == 0.0 {
111 x / 2.0 + y / 2.0
112 } else {
113 x + (y - x) * (a / (a + b))
114 }
115 } else {
116 y + (x - y) * (b / (a + b))
117 }
118}
119
120pub fn edge_intersect(
124 o1_s: Real,
125 o1_t: Real,
126 d1_s: Real,
127 d1_t: Real,
128 o2_s: Real,
129 o2_t: Real,
130 d2_s: Real,
131 d2_t: Real,
132) -> (Real, Real) {
133 let v_s;
135 {
136 let (mut a_s, mut a_t) = (o1_s, o1_t);
137 let (mut b_s, mut b_t) = (d1_s, d1_t);
138 let (mut c_s, mut c_t) = (o2_s, o2_t);
139 let (mut d_s, mut d_t) = (d2_s, d2_t);
140
141 if !vert_leq(a_s, a_t, b_s, b_t) {
142 core::mem::swap(&mut a_s, &mut b_s);
143 core::mem::swap(&mut a_t, &mut b_t);
144 }
145 if !vert_leq(c_s, c_t, d_s, d_t) {
146 core::mem::swap(&mut c_s, &mut d_s);
147 core::mem::swap(&mut c_t, &mut d_t);
148 }
149 if !vert_leq(a_s, a_t, c_s, c_t) {
150 core::mem::swap(&mut a_s, &mut c_s);
151 core::mem::swap(&mut a_t, &mut c_t);
152 core::mem::swap(&mut b_s, &mut d_s);
153 core::mem::swap(&mut b_t, &mut d_t);
154 }
155
156 if !vert_leq(c_s, c_t, b_s, b_t) {
157 v_s = c_s / 2.0 + b_s / 2.0;
158 } else if vert_leq(b_s, b_t, d_s, d_t) {
159 let mut z1 = edge_eval(a_s, a_t, c_s, c_t, b_s, b_t);
160 let mut z2 = edge_eval(c_s, c_t, b_s, b_t, d_s, d_t);
161 if z1 + z2 < 0.0 {
162 z1 = -z1;
163 z2 = -z2;
164 }
165 v_s = real_interpolate(z1, c_s, z2, b_s);
166 } else {
167 let mut z1 = edge_sign(a_s, a_t, c_s, c_t, b_s, b_t);
168 let mut z2 = -edge_sign(a_s, a_t, d_s, d_t, b_s, b_t);
169 if z1 + z2 < 0.0 {
170 z1 = -z1;
171 z2 = -z2;
172 }
173 v_s = real_interpolate(z1, c_s, z2, d_s);
174 }
175 }
176
177 let v_t;
179 {
180 let (mut a_s, mut a_t) = (o1_s, o1_t);
181 let (mut b_s, mut b_t) = (d1_s, d1_t);
182 let (mut c_s, mut c_t) = (o2_s, o2_t);
183 let (mut d_s, mut d_t) = (d2_s, d2_t);
184
185 if !trans_leq(a_s, a_t, b_s, b_t) {
186 core::mem::swap(&mut a_s, &mut b_s);
187 core::mem::swap(&mut a_t, &mut b_t);
188 }
189 if !trans_leq(c_s, c_t, d_s, d_t) {
190 core::mem::swap(&mut c_s, &mut d_s);
191 core::mem::swap(&mut c_t, &mut d_t);
192 }
193 if !trans_leq(a_s, a_t, c_s, c_t) {
194 core::mem::swap(&mut a_s, &mut c_s);
195 core::mem::swap(&mut a_t, &mut c_t);
196 core::mem::swap(&mut b_s, &mut d_s);
197 core::mem::swap(&mut b_t, &mut d_t);
198 }
199
200 if !trans_leq(c_s, c_t, b_s, b_t) {
201 v_t = c_t / 2.0 + b_t / 2.0;
202 } else if trans_leq(b_s, b_t, d_s, d_t) {
203 let mut z1 = trans_eval(a_s, a_t, c_s, c_t, b_s, b_t);
204 let mut z2 = trans_eval(c_s, c_t, b_s, b_t, d_s, d_t);
205 if z1 + z2 < 0.0 {
206 z1 = -z1;
207 z2 = -z2;
208 }
209 v_t = real_interpolate(z1, c_t, z2, b_t);
210 } else {
211 let mut z1 = trans_sign(a_s, a_t, c_s, c_t, b_s, b_t);
212 let mut z2 = -trans_sign(a_s, a_t, d_s, d_t, b_s, b_t);
213 if z1 + z2 < 0.0 {
214 z1 = -z1;
215 z2 = -z2;
216 }
217 v_t = real_interpolate(z1, c_t, z2, d_t);
218 }
219 }
220
221 (v_s, v_t)
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227
228 #[test]
229 fn vert_leq_basic() {
230 assert!(vert_leq(0.0, 0.0, 1.0, 0.0));
231 assert!(vert_leq(0.0, 0.0, 0.0, 1.0));
232 assert!(vert_leq(0.0, 0.0, 0.0, 0.0));
233 assert!(!vert_leq(1.0, 0.0, 0.0, 0.0));
234 }
235
236 #[test]
237 fn trans_leq_basic() {
238 assert!(trans_leq(0.0, 0.0, 0.0, 1.0));
239 assert!(trans_leq(0.0, 0.0, 1.0, 0.0));
240 assert!(!trans_leq(0.0, 1.0, 0.0, 0.0));
241 }
242
243 #[test]
244 fn edge_eval_horizontal() {
245 let r = edge_eval(0.0, 0.0, 0.5, 1.0, 1.0, 0.0);
249 assert!((r - 1.0).abs() < 1e-6, "got {}", r);
250 }
251
252 #[test]
253 fn edge_eval_vertical_returns_zero() {
254 let r = edge_eval(0.0, 0.0, 0.0, 0.5, 0.0, 1.0);
256 assert_eq!(r, 0.0);
257 }
258
259 #[test]
260 fn vert_ccw_basic() {
261 assert!(vert_ccw(0.0, 0.0, 1.0, 0.0, 0.5, 1.0));
262 assert!(!vert_ccw(0.0, 0.0, 0.5, 1.0, 1.0, 0.0));
263 }
264
265 #[test]
266 fn real_interpolate_midpoint() {
267 let r = real_interpolate(0.0, 0.0, 0.0, 1.0);
268 assert!((r - 0.5).abs() < 1e-6);
269 }
270
271 #[test]
272 fn real_interpolate_weighted() {
273 let r = real_interpolate(1.0, 0.0, 1.0, 2.0);
277 assert!((r - 1.0).abs() < 1e-6);
278 }
279
280 #[test]
281 fn edge_intersect_crossing() {
282 let (s, t) = edge_intersect(0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0);
286 assert!((s - 0.5).abs() < 1e-5, "s={}", s);
287 assert!((t - 0.5).abs() < 1e-5, "t={}", t);
288 }
289}