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, s1) = if det > S::zero() {
313 let b1 = -line_b_vec.dot (diff);
314 ( (a01 * b1 - a11 * b0) / det,
315 (a01 * b0 - a00 * b1) / det )
316 } else {
317 (-b0 / a00, S::zero())
318 };
319 let nearest_a = line_a.point_a() + *line_a_vec * s0;
320 let nearest_b = line_b.point_a() + *line_b_vec * s1;
321 ((s0, nearest_a), (s1, nearest_b))
322}
323
324pub fn nearest_line3_segment3 <S> (line : Segment3 <S>, segment : Segment3 <S>)
326 -> (Line3Point <S>, Segment3Point <S>)
327where S : OrderedField {
328 let line_dir = line.vector();
331 let seg_dir = segment.vector();
332 let diff = line.point_a() - segment.point_a();
333 let a00 = line_dir.magnitude_squared();
334 let a01 = -line_dir.dot (*seg_dir);
335 let a11 = seg_dir.magnitude_squared();
336 let b0 = line_dir.dot (diff);
337 let det = S::max (a00 * a11 - a01 * a01, S::zero());
338 let s0;
339 let mut s1;
340 if det > S::zero() {
341 let b1 = -seg_dir.dot (diff);
343 s1 = a01 * b0 - a00 * b1;
344 if s1 >= S::zero() {
345 if s1 <= det {
346 s0 = (a01 * b1 - a11 * b0) / det;
347 s1 /= det;
348 } else {
349 s0 = -(a01 + b0) / a00;
350 s1 = S::one();
351 }
352 } else {
353 s0 = -b0 / a00;
354 s1 = S::zero();
355 }
356 } else {
357 s0 = -b0 / a00;
359 s1 = S::zero();
360 }
361 let p_line = line.point_a() + *line_dir * s0;
362 let p_seg = segment.point_a() + *seg_dir * s1;
363 ((s0, p_line), (Normalized::unchecked (s1), p_seg))
364}
365
366pub fn nearest_line3_point3 <S> (line : Segment3 <S>, point : Point3 <S>)
368 -> Line3Point <S>
369where S : OrderedRing {
370 let ab = line.vector();
371 let av = point.0 - line.point_a().0;
372 let ab2 = ab.magnitude_squared();
373 let ab_dot_av = ab.dot (av);
374 let t = ab_dot_av / ab2;
375 let tab = *ab * t;
376 let at = line.point_a() + tab;
377 (t, at)
378}
379
380pub fn nearest_segment3_segment3 <S : Real> (
382 _segment_a : Segment3 <S>, _segment_b : Segment3 <S>
383) -> (Segment3Point <S>, Segment3Point <S>) {
384 unimplemented!("TODO: nearest segment3 segment3")
385}
386
387pub fn nearest_segment3_point3 <S> (segment : Segment3 <S>, point : Point3 <S>)
389 -> Segment3Point <S>
390where S : OrderedField {
391 use num::One;
392 let (t, point) = nearest_line3_point3 (segment, point);
393 if t < S::zero() {
394 (Normalized::zero(), segment.point_a())
395 } else if t > S::one() {
396 (Normalized::one(), segment.point_b())
397 } else {
398 (Normalized::unchecked (t), point)
399 }
400}
401
402impl <S : Ring> Distance3 <S> {
403 pub const fn nearest_a (&self) -> Point3 <S> {
404 self.nearest_a
405 }
406 pub const fn nearest_b (&self) -> Point3 <S> {
407 self.nearest_b
408 }
409 pub const fn distance_squared (&self) -> NonNegative <S> {
410 self.distance_squared
411 }
412 pub fn distance (&mut self) -> NonNegative <S> where S : Sqrt {
413 self.distance.unwrap_or_else (|| {
414 let distance = self.distance_squared.sqrt();
415 self.distance = Some (distance);
416 distance
417 })
418 }
419
420 pub fn triangle_point (triangle : Triangle3 <S>, point : Point3 <S>) -> Self
421 where S : OrderedField
422 {
423 let (_, nearest_a) = nearest_triangle3_point3 (triangle, point);
424 let distance_squared = (point - nearest_a).norm_squared();
425 Distance3 { distance_squared, distance: None, nearest_a, nearest_b: point }
426 }
427}
428
429#[cfg(test)]
430mod tests {
431 use super::*;
432
433 #[test]
434 fn nearest_3d_line_segment() {
435 let line = Segment3::noisy (
436 [0.0, 0.0, 0.0].into(),
437 [1.0, 1.0, 0.0].into());
438 let segment = Segment3::noisy (
439 [0.0, -1.0, 0.0].into(),
440 [1.0, -1.0, 0.0].into());
441 let ((s0, p_line), (s1, p_seg)) = nearest_line3_segment3 (line, segment);
442 assert_eq!(s0, -0.5);
443 assert_eq!(*s1, 0.0);
444 assert_eq!(p_line, [-0.5, -0.5, 0.0].into());
445 assert_eq!(p_seg, [0.0, -1.0, 0.0].into());
446 let segment = Segment3::noisy (
447 [0.0, -1.0, 0.0].into(),
448 [1.0, 0.0, 0.0].into());
449 let ((s0, p_line), (s1, p_seg)) = nearest_line3_segment3 (line, segment);
450 assert_eq!(s0, -0.5);
451 assert_eq!(*s1, 0.0);
452 assert_eq!(p_line, [-0.5, -0.5, 0.0].into());
453 assert_eq!(p_seg, [0.0, -1.0, 0.0].into());
454 }
455
456 #[test]
457 fn nearest_3d_triangle_line() {
458 let triangle = Triangle3::noisy (
459 [-1.0, -1.0, 0.0].into(),
460 [ 1.0, -1.0, 0.0].into(),
461 [ 0.0, 1.0, 0.0].into());
462 let line = Segment3::noisy (
463 [-2.0, -2.0, 0.0].into(),
464 [-2.0, -2.0, 1.0].into());
465 let (([t0, t1], p_tri), (s0, p_line)) =
466 nearest_triangle3_line3 (triangle, line);
467 assert_eq!((*t0, *t1), (0.0, 0.0));
468 assert_eq!(p_tri, [-1.0, -1.0, 0.0].into());
469 assert_eq!(s0, 0.0);
470 assert_eq!(p_line, [-2.0, -2.0, 0.0].into());
471 let line = Segment3::noisy (
472 [ 2.0, -2.0, 0.0].into(),
473 [ 2.0, -2.0, 1.0].into());
474 let (([t0, t1], p_tri), (s0, p_line)) =
475 nearest_triangle3_line3 (triangle, line);
476 assert_eq!((*t0, *t1), (1.0, 0.0));
477 assert_eq!(p_tri, [1.0, -1.0, 0.0].into());
478 assert_eq!(s0, 0.0);
479 assert_eq!(p_line, [2.0, -2.0, 0.0].into());
480 let line = Segment3::noisy (
481 [0.0, 2.0, 0.0].into(),
482 [0.0, 2.0, 1.0].into());
483 let (([t0, t1], p_tri), (s0, p_line)) =
484 nearest_triangle3_line3 (triangle, line);
485 assert_eq!((*t0, *t1), (0.0, 1.0));
486 assert_eq!(p_tri, [0.0, 1.0, 0.0].into());
487 assert_eq!(s0, 0.0);
488 assert_eq!(p_line, [0.0, 2.0, 0.0].into());
489 let line = Segment3::noisy (
490 [0.0, -2.0, 0.0].into(),
491 [0.0, -2.0, 1.0].into());
492 let (([t0, t1], p_tri), (s0, p_line)) =
493 nearest_triangle3_line3 (triangle, line);
494 assert_eq!((*t0, *t1), (0.5, 0.0));
495 assert_eq!(p_tri, [0.0, -1.0, 0.0].into());
496 assert_eq!(s0, 0.0);
497 assert_eq!(p_line, [0.0, -2.0, 0.0].into());
498 }
499}