1pub type Real = f64;
22
23#[inline]
25pub fn vert_leq(u_s: Real, u_t: Real, v_s: Real, v_t: Real) -> bool {
26 u_s < v_s || (u_s == v_s && u_t <= v_t)
27}
28
29#[inline]
31pub fn vert_eq(u_s: Real, u_t: Real, v_s: Real, v_t: Real) -> bool {
32 u_s == v_s && u_t == v_t
33}
34
35#[inline]
37pub fn trans_leq(u_s: Real, u_t: Real, v_s: Real, v_t: Real) -> bool {
38 u_t < v_t || (u_t == v_t && u_s <= v_s)
39}
40
41pub fn edge_eval(u_s: Real, u_t: Real, v_s: Real, v_t: Real, w_s: Real, w_t: Real) -> Real {
47 let gap_l = v_s - u_s;
49 let gap_r = w_s - v_s;
50 if gap_l + gap_r > 0.0 {
51 if gap_l < gap_r {
52 (v_t - u_t) + (u_t - w_t) * (gap_l / (gap_l + gap_r))
53 } else {
54 (v_t - w_t) + (w_t - u_t) * (gap_r / (gap_l + gap_r))
55 }
56 } else {
57 0.0
58 }
59}
60
61#[inline]
78pub fn edge_sign(u_s: Real, u_t: Real, v_s: Real, v_t: Real, w_s: Real, w_t: Real) -> Real {
79 let gap_l = v_s - u_s;
81 let gap_r = w_s - v_s;
82 if gap_l + gap_r > 0.0 {
83 (v_t - w_t) * gap_l + (v_t - u_t) * gap_r
84 } else {
85 0.0
87 }
88}
89
90pub fn trans_eval(u_s: Real, u_t: Real, v_s: Real, v_t: Real, w_s: Real, w_t: Real) -> Real {
92 let gap_l = v_t - u_t;
94 let gap_r = w_t - v_t;
95 if gap_l + gap_r > 0.0 {
96 if gap_l < gap_r {
97 (v_s - u_s) + (u_s - w_s) * (gap_l / (gap_l + gap_r))
98 } else {
99 (v_s - w_s) + (w_s - u_s) * (gap_r / (gap_l + gap_r))
100 }
101 } else {
102 0.0
103 }
104}
105
106pub fn trans_sign(u_s: Real, u_t: Real, v_s: Real, v_t: Real, w_s: Real, w_t: Real) -> Real {
108 let gap_l = v_t - u_t;
110 let gap_r = w_t - v_t;
111 if gap_l + gap_r > 0.0 {
112 (v_s - w_s) * gap_l + (v_s - u_s) * gap_r
113 } else {
114 0.0
115 }
116}
117
118#[inline]
120pub fn vert_ccw(u_s: Real, u_t: Real, v_s: Real, v_t: Real, w_s: Real, w_t: Real) -> bool {
121 u_s * (v_t - w_t) + v_s * (w_t - u_t) + w_s * (u_t - v_t) >= 0.0
122}
123
124#[inline]
126pub fn vert_l1_dist(u_s: Real, u_t: Real, v_s: Real, v_t: Real) -> Real {
127 (u_s - v_s).abs() + (u_t - v_t).abs()
128}
129
130#[inline]
134pub fn real_interpolate(mut a: Real, x: Real, mut b: Real, y: Real) -> Real {
135 if a < 0.0 {
136 a = 0.0;
137 }
138 if b < 0.0 {
139 b = 0.0;
140 }
141 if a <= b {
142 if b == 0.0 {
143 x / 2.0 + y / 2.0
144 } else {
145 x + (y - x) * (a / (a + b))
146 }
147 } else {
148 y + (x - y) * (b / (a + b))
149 }
150}
151
152pub fn edge_intersect(
156 o1_s: Real,
157 o1_t: Real,
158 d1_s: Real,
159 d1_t: Real,
160 o2_s: Real,
161 o2_t: Real,
162 d2_s: Real,
163 d2_t: Real,
164) -> (Real, Real) {
165 let v_s;
167 {
168 let (mut a_s, mut a_t) = (o1_s, o1_t);
169 let (mut b_s, mut b_t) = (d1_s, d1_t);
170 let (mut c_s, mut c_t) = (o2_s, o2_t);
171 let (mut d_s, mut d_t) = (d2_s, d2_t);
172
173 if !vert_leq(a_s, a_t, b_s, b_t) {
174 core::mem::swap(&mut a_s, &mut b_s);
175 core::mem::swap(&mut a_t, &mut b_t);
176 }
177 if !vert_leq(c_s, c_t, d_s, d_t) {
178 core::mem::swap(&mut c_s, &mut d_s);
179 core::mem::swap(&mut c_t, &mut d_t);
180 }
181 if !vert_leq(a_s, a_t, c_s, c_t) {
182 core::mem::swap(&mut a_s, &mut c_s);
183 core::mem::swap(&mut a_t, &mut c_t);
184 core::mem::swap(&mut b_s, &mut d_s);
185 core::mem::swap(&mut b_t, &mut d_t);
186 }
187
188 if !vert_leq(c_s, c_t, b_s, b_t) {
189 v_s = c_s / 2.0 + b_s / 2.0;
190 } else if vert_leq(b_s, b_t, d_s, d_t) {
191 let mut z1 = edge_eval(a_s, a_t, c_s, c_t, b_s, b_t);
192 let mut z2 = edge_eval(c_s, c_t, b_s, b_t, d_s, d_t);
193 if z1 + z2 < 0.0 {
194 z1 = -z1;
195 z2 = -z2;
196 }
197 v_s = real_interpolate(z1, c_s, z2, b_s);
198 } else {
199 let mut z1 = edge_sign(a_s, a_t, c_s, c_t, b_s, b_t);
200 let mut z2 = -edge_sign(a_s, a_t, d_s, d_t, b_s, b_t);
201 if z1 + z2 < 0.0 {
202 z1 = -z1;
203 z2 = -z2;
204 }
205 v_s = real_interpolate(z1, c_s, z2, d_s);
206 }
207 }
208
209 let v_t;
211 {
212 let (mut a_s, mut a_t) = (o1_s, o1_t);
213 let (mut b_s, mut b_t) = (d1_s, d1_t);
214 let (mut c_s, mut c_t) = (o2_s, o2_t);
215 let (mut d_s, mut d_t) = (d2_s, d2_t);
216
217 if !trans_leq(a_s, a_t, b_s, b_t) {
218 core::mem::swap(&mut a_s, &mut b_s);
219 core::mem::swap(&mut a_t, &mut b_t);
220 }
221 if !trans_leq(c_s, c_t, d_s, d_t) {
222 core::mem::swap(&mut c_s, &mut d_s);
223 core::mem::swap(&mut c_t, &mut d_t);
224 }
225 if !trans_leq(a_s, a_t, c_s, c_t) {
226 core::mem::swap(&mut a_s, &mut c_s);
227 core::mem::swap(&mut a_t, &mut c_t);
228 core::mem::swap(&mut b_s, &mut d_s);
229 core::mem::swap(&mut b_t, &mut d_t);
230 }
231
232 if !trans_leq(c_s, c_t, b_s, b_t) {
233 v_t = c_t / 2.0 + b_t / 2.0;
234 } else if trans_leq(b_s, b_t, d_s, d_t) {
235 let mut z1 = trans_eval(a_s, a_t, c_s, c_t, b_s, b_t);
236 let mut z2 = trans_eval(c_s, c_t, b_s, b_t, d_s, d_t);
237 if z1 + z2 < 0.0 {
238 z1 = -z1;
239 z2 = -z2;
240 }
241 v_t = real_interpolate(z1, c_t, z2, b_t);
242 } else {
243 let mut z1 = trans_sign(a_s, a_t, c_s, c_t, b_s, b_t);
244 let mut z2 = -trans_sign(a_s, a_t, d_s, d_t, b_s, b_t);
245 if z1 + z2 < 0.0 {
246 z1 = -z1;
247 z2 = -z2;
248 }
249 v_t = real_interpolate(z1, c_t, z2, d_t);
250 }
251 }
252
253 (v_s, v_t)
254}
255
256#[cfg(test)]
257mod tests {
258 use super::*;
259
260 #[test]
261 fn vert_leq_basic() {
262 assert!(vert_leq(0.0, 0.0, 1.0, 0.0));
263 assert!(vert_leq(0.0, 0.0, 0.0, 1.0));
264 assert!(vert_leq(0.0, 0.0, 0.0, 0.0));
265 assert!(!vert_leq(1.0, 0.0, 0.0, 0.0));
266 }
267
268 #[test]
269 fn trans_leq_basic() {
270 assert!(trans_leq(0.0, 0.0, 0.0, 1.0));
271 assert!(trans_leq(0.0, 0.0, 1.0, 0.0));
272 assert!(!trans_leq(0.0, 1.0, 0.0, 0.0));
273 }
274
275 #[test]
276 fn edge_eval_horizontal() {
277 let r = edge_eval(0.0, 0.0, 0.5, 1.0, 1.0, 0.0);
281 assert!((r - 1.0).abs() < 1e-6, "got {}", r);
282 }
283
284 #[test]
285 fn edge_eval_vertical_returns_zero() {
286 let r = edge_eval(0.0, 0.0, 0.0, 0.5, 0.0, 1.0);
288 assert_eq!(r, 0.0);
289 }
290
291 #[test]
292 fn vert_ccw_basic() {
293 assert!(vert_ccw(0.0, 0.0, 1.0, 0.0, 0.5, 1.0));
294 assert!(!vert_ccw(0.0, 0.0, 0.5, 1.0, 1.0, 0.0));
295 }
296
297 #[test]
298 fn real_interpolate_midpoint() {
299 let r = real_interpolate(0.0, 0.0, 0.0, 1.0);
300 assert!((r - 0.5).abs() < 1e-6);
301 }
302
303 #[test]
304 fn real_interpolate_weighted() {
305 let r = real_interpolate(1.0, 0.0, 1.0, 2.0);
309 assert!((r - 1.0).abs() < 1e-6);
310 }
311
312 #[test]
313 fn edge_intersect_crossing() {
314 let (s, t) = edge_intersect(0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0);
318 assert!((s - 0.5).abs() < 1e-5, "s={}", s);
319 assert!((t - 0.5).abs() < 1e-5, "t={}", t);
320 }
321}