1use crate::*;
4use super::*;
5
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7#[expect(clippy::module_name_repetitions)]
8pub struct Distance3 <S> {
9 distance_squared : NonNegative <S>,
10 distance : Option <NonNegative <S>>,
11 nearest_a : Point3 <S>,
12 nearest_b : Point3 <S>
13}
14
15pub fn nearest_triangle2_point2 <S : OrderedField> (
22 _triangle : Triangle2 <S>, _point : Point2 <S>
23) -> Triangle2Point <S> {
24 unimplemented!("TODO: nearest triangle2 point2")
25}
26
27pub fn nearest_line2_point2 <S> (line : frame::Line2 <S>, point : Point2 <S>)
29 -> Line2Point <S>
30where S : OrderedRing {
31 let ab = line.basis;
32 let av = point - line.origin;
33 let ab2 = ab.self_dot();
34 let ab_dot_av = ab.dot (av);
35 let t = ab_dot_av / *ab2;
36 let tab = *ab * t;
37 let at = line.origin + tab;
38 (t, at)
39}
40
41pub fn nearest_segment2_point2 <S> (segment : Segment2 <S>, point : Point2 <S>)
43 -> Segment2Point <S>
44where S : OrderedField {
45 use num::One;
46 let (t, point) = nearest_line2_point2 (segment.into(), point);
47 if t < S::zero() {
48 (Normalized::zero(), segment.point_a())
49 } else if t > S::one() {
50 (Normalized::one(), segment.point_b())
51 } else {
52 (Normalized::unchecked (t), point)
53 }
54}
55
56pub fn nearest_triangle3_triangle3 <S> (
63 _triangle_a : Triangle3 <S>, _triangle_b : Triangle3 <S>
64) -> (Triangle3Point <S>, Triangle3Point <S>) {
65 unimplemented!("TODO: nearest triangle3 triangle3")
66}
67
68pub fn nearest_triangle3_line3 <S> (triangle : Triangle3 <S>, line : Segment3 <S>)
72 -> (Triangle3Point <S>, Line3Point <S>)
73where S : Real + approx::RelativeEq <Epsilon=S> {
74 let edge1 = triangle.point_b() - triangle.point_a();
77 let edge2 = triangle.point_c() - triangle.point_a();
78 let n = edge1.cross (edge2);
79 let dir = line.vector();
80 let n_dot_dir = n.dot (*dir);
81 if n_dot_dir.abs() > S::zero() {
82 let diff = line.point_a() - triangle.point_a();
84 let n_dot_diff = n.dot (diff);
85 let intersect = -n_dot_diff / n_dot_dir;
86 let y = line.point_a() + *dir * intersect;
87 let tri0_to_y = y - triangle.point_a();
88 let e1_dot_e1 = edge1.dot (edge1);
89 let e1_dot_e2 = edge1.dot (edge2);
90 let e2_dot_e2 = edge2.dot (edge2);
91 let e1_dot_tri0_to_y = edge1.dot (tri0_to_y);
92 let e2_dot_tri0_to_y = edge2.dot (tri0_to_y);
93 let det = e1_dot_e1 * e2_dot_e2 - e1_dot_e2 * e1_dot_e2;
94 let b1 = (e2_dot_e2 * e1_dot_tri0_to_y - e1_dot_e2 * e2_dot_tri0_to_y) / det;
95 let b2 = (e1_dot_e1 * e2_dot_tri0_to_y - e1_dot_e2 * e1_dot_tri0_to_y) / det;
96 let b0 = S::one() - b1 - b2;
97 if b0 >= S::zero() && b1 >= S::zero() && b2 >= S::zero() {
98 if cfg!(debug_assertions) {
100 approx::assert_relative_eq!(triangle.point_a() + edge1 * b1 + edge2 * b2, y,
101 epsilon = S::default_epsilon() * S::two().powi (36),
102 max_relative = S::default_max_relative() * S::two().powi (36));
103 }
104 return (
105 ([b1, b2].map (Normalized::unchecked), y),
106 (intersect, y) )
107 }
108 }
109 let mut i0 = 2;
111 let mut i1 = 0;
112 let mut i2 = 1;
113 let mut lowest_dist_sq = None;
114 let mut p0 = S::zero();
115 let mut barycentric = [Normalized::zero(), Normalized::zero(), Normalized::zero()];
116 let triangle_points = triangle.points();
117 while i1 < 3 {
118 let segment = Segment3::noisy (triangle_points[i0], triangle_points[i1]);
119 let ((s0, p_line), (s1, p_seg)) = nearest_line3_segment3 (line, segment);
120 let dist_sq = (p_seg - p_line).self_dot();
121 if lowest_dist_sq.is_none_or (|lowest| dist_sq < lowest) {
122 lowest_dist_sq = Some (dist_sq);
123 p0 = s0;
124 barycentric[i0] = s1;
127 barycentric[i1] = Normalized::zero();
128 barycentric[i2] = Normalized::unchecked (S::one() - *s1);
129 }
130 i2 = i0;
131 i0 = i1;
132 i1 += 1;
133 }
134 let point_tri = triangle.point_a() + edge1 * *barycentric[0] + edge2 * *barycentric[1];
135 let point_line = line.point_a() + *dir * p0;
136 ( ([barycentric[0], barycentric[1]], point_tri),
137 (p0, point_line))
138}
139
140pub fn nearest_triangle3_segment3 <S> (triangle : Triangle3 <S>, segment : Segment3 <S>)
144 -> (Triangle3Point <S>, Segment3Point <S>)
145where S : Real + approx::RelativeEq <Epsilon=S> {
146 use num::One;
147 let (out_tri, (r, near_line)) = nearest_triangle3_line3 (triangle, segment);
148 if r < S::zero() {
149 let point_a = segment.point_a();
150 let out_tri = nearest_triangle3_point3 (triangle, point_a);
151 (out_tri, (Normalized::zero(), point_a))
152 } else if r > S::one() {
153 let point_b = segment.point_b();
154 let out_tri = nearest_triangle3_point3 (triangle, point_b);
155 (out_tri, (Normalized::one(), point_b))
156 } else {
157 (out_tri, (Normalized::unchecked (r), near_line))
158 }
159}
160
161pub fn nearest_triangle3_point3 <S> (triangle : Triangle3 <S>, point : Point3 <S>)
164 -> Triangle3Point <S>
165where S : OrderedField {
166 let d = triangle.point_a() - point;
169 let edge0 = triangle.point_b() - triangle.point_a();
170 let edge1 = triangle.point_c() - triangle.point_a();
171 let e00 = edge0.magnitude_squared();
172 let e01 = edge1.dot (edge0);
173 let e11 = edge1.magnitude_squared();
174 let de0 = d.dot (edge0);
175 let de1 = d.dot (edge1);
176 let det = (e00 * e11 - e01 * e01).abs();
177 let mut s = e01 * de1 - e11 * de0;
178 let mut t = e01 * de0 - e00 * de1;
179 if s + t <= det {
181 if s < S::zero() {
182 if t < S::zero() {
183 if de0 < S::zero() {
185 t = S::zero();
186 if -de0 > e00 {
187 s = S::one()
188 } else {
189 s = -de0 / e00
190 }
191 } else {
192 s = S::zero();
193 if de1 > S::zero() {
194 t = S::zero()
195 } else if -de1 >= e11 {
196 t = S::one()
197 } else {
198 t = -de1 / e11
199 }
200 }
201 } else {
202 s = S::zero();
204 if de1 > S::zero() {
205 t = S::zero()
206 } else if -de1 >= e11 {
207 t = S::one()
208 } else {
209 t = -de1 / e11
210 }
211 }
212 } else if t < S::zero() {
213 t = S::zero();
215 if de0 >= S::zero() {
216 s = S::zero()
217 } else if -de0 >= e00 {
218 s = S::one()
219 } else {
220 s = -de0 / e00
221 }
222 } else {
223 let idet = S::one() / det;
226 s *= idet;
227 t *= idet;
228 }
229 } else if s < S::zero() {
230 let tmp0 = e01 + de0;
232 let tmp1 = e11 + de1;
233 if tmp1 > tmp0 {
234 let numer = tmp1 - tmp0;
235 let denom = e00 - S::two() * e01 + e11;
236 if numer >= denom {
237 s = S::one();
238 t = S::zero();
239 } else {
240 s = numer / denom;
241 t = S::one() - s;
242 }
243 } else {
244 s = S::zero();
245 if tmp1 <= S::zero() {
246 t = S::one()
247 } else if de1 >= S::zero() {
248 t = S::zero()
249 } else {
250 t = -de1 / e11
251 }
252 }
253 } else if t < S::zero() {
254 let tmp0 = e01 + de1;
256 let tmp1 = e00 + de0;
257 if tmp1 > tmp0 {
258 let numer = tmp1 - tmp0;
259 let denom = e00 - S::two() * e01 + e11;
260 if numer >= denom {
261 t = S::one();
262 s = S::zero();
263 } else {
264 t = numer / denom;
265 s = S::one() - t;
266 }
267 } else {
268 t = S::zero();
269 if tmp1 <= S::zero() {
270 s = S::one()
271 } else if de0 >= S::zero() {
272 s = S::zero()
273 } else {
274 s = -de0 / e00
275 }
276 }
277 } else {
278 let numer = e11 + de1 - e01 - de0;
280 if numer <= S::zero() {
281 s = S::zero();
282 t = S::one();
283 } else {
284 let denom = e00 - S::two() * e01 + e11;
285 if numer >= denom {
286 s = S::one();
287 t = S::zero();
288 } else {
289 s = numer / denom;
290 t = S::one() - s;
291 }
292 }
293 }
294 let nearest = triangle.point_a() + edge0 * s + edge1 * t;
295 ([s, t].map (Normalized::unchecked), nearest)
296}
297
298pub fn nearest_line3_line3 <S> (line_a : Segment3 <S>, line_b : Segment3 <S>)
300 -> (Line3Point <S>, Line3Point <S>)
301where S : OrderedField {
302 let line_a_vec = line_a.vector();
305 let line_b_vec = line_b.vector();
306 let diff = line_a.point_a() - line_b.point_a();
307 let a00 = line_a_vec.magnitude_squared();
308 let a01 = -line_a_vec.dot (*line_b_vec);
309 let a11 = line_b_vec.magnitude_squared();
310 let b0 = line_a_vec.dot (diff);
311 let det = S::max (a00 * a11 - a01 * a01, S::zero());
312 let s0;
313 let s1;
314 if det > S::zero() {
315 let b1 = -line_b_vec.dot (diff);
316 s0 = (a01 * b1 - a11 * b0) / det;
317 s1 = (a01 * b0 - a00 * b1) / det;
318 } else {
319 s0 = -b0 / a00;
320 s1 = S::zero();
321 }
322 let nearest_a = line_a.point_a() + *line_a_vec * s0;
323 let nearest_b = line_b.point_a() + *line_b_vec * s1;
324 ((s0, nearest_a), (s1, nearest_b))
325}
326
327pub fn nearest_line3_segment3 <S> (line : Segment3 <S>, segment : Segment3 <S>)
329 -> (Line3Point <S>, Segment3Point <S>)
330where S : OrderedField {
331 let line_dir = line.vector();
334 let seg_dir = segment.vector();
335 let diff = line.point_a() - segment.point_a();
336 let a00 = line_dir.magnitude_squared();
337 let a01 = -line_dir.dot (*seg_dir);
338 let a11 = seg_dir.magnitude_squared();
339 let b0 = line_dir.dot (diff);
340 let det = S::max (a00 * a11 - a01 * a01, S::zero());
341 let s0;
342 let mut s1;
343 if det > S::zero() {
344 let b1 = -seg_dir.dot (diff);
346 s1 = a01 * b0 - a00 * b1;
347 if s1 >= S::zero() {
348 if s1 <= det {
349 s0 = (a01 * b1 - a11 * b0) / det;
350 s1 /= det;
351 } else {
352 s0 = -(a01 + b0) / a00;
353 s1 = S::one();
354 }
355 } else {
356 s0 = -b0 / a00;
357 s1 = S::zero();
358 }
359 } else {
360 s0 = -b0 / a00;
362 s1 = S::zero();
363 }
364 let p_line = line.point_a() + *line_dir * s0;
365 let p_seg = segment.point_a() + *seg_dir * s1;
366 ((s0, p_line), (Normalized::unchecked (s1), p_seg))
367}
368
369pub fn nearest_line3_point3 <S> (line : Segment3 <S>, point : Point3 <S>)
371 -> Line3Point <S>
372where S : OrderedRing {
373 let ab = line.vector();
374 let av = point.0 - line.point_a().0;
375 let ab2 = ab.magnitude_squared();
376 let ab_dot_av = ab.dot (av);
377 let t = ab_dot_av / ab2;
378 let tab = *ab * t;
379 let at = line.point_a() + tab;
380 (t, at)
381}
382
383pub fn nearest_segment3_segment3 <S : Real> (
385 _segment_a : Segment3 <S>, _segment_b : Segment3 <S>
386) -> (Segment3Point <S>, Segment3Point <S>) {
387 unimplemented!("TODO: nearest segment3 segment3")
388}
389
390pub fn nearest_segment3_point3 <S> (segment : Segment3 <S>, point : Point3 <S>)
392 -> Segment3Point <S>
393where S : OrderedField {
394 use num::One;
395 let (t, point) = nearest_line3_point3 (segment, point);
396 if t < S::zero() {
397 (Normalized::zero(), segment.point_a())
398 } else if t > S::one() {
399 (Normalized::one(), segment.point_b())
400 } else {
401 (Normalized::unchecked (t), point)
402 }
403}
404
405impl <S : Ring> Distance3 <S> {
406 pub const fn nearest_a (&self) -> Point3 <S> {
407 self.nearest_a
408 }
409 pub const fn nearest_b (&self) -> Point3 <S> {
410 self.nearest_b
411 }
412 pub const fn distance_squared (&self) -> NonNegative <S> {
413 self.distance_squared
414 }
415 pub fn distance (&mut self) -> NonNegative <S> where S : Sqrt {
416 self.distance.unwrap_or_else (|| {
417 let distance = self.distance_squared.sqrt();
418 self.distance = Some (distance);
419 distance
420 })
421 }
422
423 pub fn triangle_point (triangle : Triangle3 <S>, point : Point3 <S>) -> Self
424 where S : OrderedField
425 {
426 let (_, nearest_a) = nearest_triangle3_point3 (triangle, point);
427 let distance_squared = (point - nearest_a).norm_squared();
428 Distance3 { distance_squared, distance: None, nearest_a, nearest_b: point }
429 }
430}
431
432#[cfg(test)]
433mod tests {
434 use super::*;
435
436 #[test]
437 fn nearest_3d_line_segment() {
438 let line = Segment3::noisy (
439 [0.0, 0.0, 0.0].into(),
440 [1.0, 1.0, 0.0].into());
441 let segment = Segment3::noisy (
442 [0.0, -1.0, 0.0].into(),
443 [1.0, -1.0, 0.0].into());
444 let ((s0, p_line), (s1, p_seg)) = nearest_line3_segment3 (line, segment);
445 assert_eq!(s0, -0.5);
446 assert_eq!(*s1, 0.0);
447 assert_eq!(p_line, [-0.5, -0.5, 0.0].into());
448 assert_eq!(p_seg, [0.0, -1.0, 0.0].into());
449 let segment = Segment3::noisy (
450 [0.0, -1.0, 0.0].into(),
451 [1.0, 0.0, 0.0].into());
452 let ((s0, p_line), (s1, p_seg)) = nearest_line3_segment3 (line, segment);
453 assert_eq!(s0, -0.5);
454 assert_eq!(*s1, 0.0);
455 assert_eq!(p_line, [-0.5, -0.5, 0.0].into());
456 assert_eq!(p_seg, [0.0, -1.0, 0.0].into());
457 }
458
459 #[test]
460 fn nearest_3d_triangle_line() {
461 let triangle = Triangle3::noisy (
462 [-1.0, -1.0, 0.0].into(),
463 [ 1.0, -1.0, 0.0].into(),
464 [ 0.0, 1.0, 0.0].into());
465 let line = Segment3::noisy (
466 [-2.0, -2.0, 0.0].into(),
467 [-2.0, -2.0, 1.0].into());
468 let (([t0, t1], p_tri), (s0, p_line)) =
469 nearest_triangle3_line3 (triangle, line);
470 assert_eq!((*t0, *t1), (0.0, 0.0));
471 assert_eq!(p_tri, [-1.0, -1.0, 0.0].into());
472 assert_eq!(s0, 0.0);
473 assert_eq!(p_line, [-2.0, -2.0, 0.0].into());
474 let line = Segment3::noisy (
475 [ 2.0, -2.0, 0.0].into(),
476 [ 2.0, -2.0, 1.0].into());
477 let (([t0, t1], p_tri), (s0, p_line)) =
478 nearest_triangle3_line3 (triangle, line);
479 assert_eq!((*t0, *t1), (1.0, 0.0));
480 assert_eq!(p_tri, [1.0, -1.0, 0.0].into());
481 assert_eq!(s0, 0.0);
482 assert_eq!(p_line, [2.0, -2.0, 0.0].into());
483 let line = Segment3::noisy (
484 [0.0, 2.0, 0.0].into(),
485 [0.0, 2.0, 1.0].into());
486 let (([t0, t1], p_tri), (s0, p_line)) =
487 nearest_triangle3_line3 (triangle, line);
488 assert_eq!((*t0, *t1), (0.0, 1.0));
489 assert_eq!(p_tri, [0.0, 1.0, 0.0].into());
490 assert_eq!(s0, 0.0);
491 assert_eq!(p_line, [0.0, 2.0, 0.0].into());
492 let line = Segment3::noisy (
493 [0.0, -2.0, 0.0].into(),
494 [0.0, -2.0, 1.0].into());
495 let (([t0, t1], p_tri), (s0, p_line)) =
496 nearest_triangle3_line3 (triangle, line);
497 assert_eq!((*t0, *t1), (0.5, 0.0));
498 assert_eq!(p_tri, [0.0, -1.0, 0.0].into());
499 assert_eq!(s0, 0.0);
500 assert_eq!(p_line, [0.0, -2.0, 0.0].into());
501 }
502}