Skip to main content

math_utils/geometry/
distance.rs

1//! Nearest point and distance routines
2
3use crate::*;
4use super::*;
5
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7#[expect(clippy::module_name_repetitions)]
8pub struct Distance2 <S> {
9  distance_squared : NonNegative <S>,
10  distance         : Option <NonNegative <S>>,
11  nearest_a        : Point2 <S>,
12  nearest_b        : Point2 <S>
13}
14
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16#[expect(clippy::module_name_repetitions)]
17pub struct Distance3 <S> {
18  distance_squared : NonNegative <S>,
19  distance         : Option <NonNegative <S>>,
20  nearest_a        : Point3 <S>,
21  nearest_b        : Point3 <S>
22}
23
24//
25//  2D
26//
27
28/// Returns the nearest 2D point on 2D triangle together with barycentric coordinates in
29/// relation to the triangle edges $ab$ and $ac$
30pub fn nearest_triangle2_point2 <S : OrderedField> (
31  _triangle : Triangle2 <S>, _point : Point2 <S>
32) -> Triangle2Point <S> {
33  unimplemented!("TODO: nearest triangle2 point2")
34}
35
36/// Nearest 2D point on a 2D line defined by a line segment
37pub fn nearest_line2_point2 <S> (line : frame::Line2 <S>, point : Point2 <S>)
38  -> Line2Point <S>
39where S : OrderedRing {
40  let ab        = line.basis;
41  let av        = point - line.origin;
42  let ab2       = ab.self_dot();
43  let ab_dot_av = ab.dot (av);
44  let t         = ab_dot_av / *ab2;
45  let tab       = *ab * t;
46  let at        = line.origin + tab;
47  (t, at)
48}
49
50/// Returns the nearest point on a 2D segment
51pub fn nearest_segment2_point2 <S> (segment : Segment2 <S>, point : Point2 <S>)
52  -> Segment2Point <S>
53where S : OrderedField {
54  use num::One;
55  let (t, point) = nearest_line2_point2 (segment.into(), point);
56  if t < S::zero() {
57    (Normalized::zero(), segment.point_a())
58  } else if t > S::one() {
59    (Normalized::one(), segment.point_b())
60  } else {
61    (Normalized::unchecked (t), point)
62  }
63}
64
65//
66//  3D
67//
68
69/// Returns the nearest 3D points two 3D triangles together with barycentric coordinates
70/// in relation to the triangle edges $ab$ and $ac$
71pub fn nearest_triangle3_triangle3 <S> (
72  _triangle_a : Triangle3 <S>, _triangle_b : Triangle3 <S>
73) -> (Triangle3Point <S>, Triangle3Point <S>) {
74  unimplemented!("TODO: nearest triangle3 triangle3")
75}
76
77/// Returns the nearest 3D point on 3D triangle together with barycentric coordinates in
78/// relation to the triangle edges $ab$ and $ac$, and the nearest point in the 3D line
79/// defined by the segment endpoints together with parameter
80pub fn nearest_triangle3_line3 <S> (triangle : Triangle3 <S>, line : frame::Line3 <S>)
81  -> (Triangle3Point <S>, Line3Point <S>)
82where S : Real + approx::RelativeEq <Epsilon=S> {
83  // method from Eberly GeometricTools:
84  // <https://github.com/davideberly/GeometricTools/blob/a9a2b149485857273ea1f1cfa5416b392f495882/GTE/Mathematics/DistLine3Triangle3.h>
85  let edge1     = triangle.point_b() - triangle.point_a();
86  let edge2     = triangle.point_c() - triangle.point_a();
87  let n         = edge1.cross (edge2);
88  let dir       = line.basis;
89  let n_dot_dir = n.dot (*dir);
90  if n_dot_dir.abs() > S::zero() {
91    // line and triangle are not parallel
92    let diff             = line.origin - triangle.point_a();
93    let n_dot_diff       = n.dot (diff);
94    let intersect        = -n_dot_diff / n_dot_dir;
95    let y                = line.origin + *dir * intersect;
96    let tri0_to_y        = y - triangle.point_a();
97    let e1_dot_e1        = edge1.dot (edge1);
98    let e1_dot_e2        = edge1.dot (edge2);
99    let e2_dot_e2        = edge2.dot (edge2);
100    let e1_dot_tri0_to_y = edge1.dot (tri0_to_y);
101    let e2_dot_tri0_to_y = edge2.dot (tri0_to_y);
102    let det = e1_dot_e1 * e2_dot_e2 - e1_dot_e2 * e1_dot_e2;
103    let b1  = (e2_dot_e2 * e1_dot_tri0_to_y - e1_dot_e2 * e2_dot_tri0_to_y) / det;
104    let b2  = (e1_dot_e1 * e2_dot_tri0_to_y - e1_dot_e2 * e1_dot_tri0_to_y) / det;
105    let b0  = S::one() - b1 - b2;
106    if b0 >= S::zero() && b1 >= S::zero() && b2 >= S::zero() {
107      // line and triangle intersect
108      if cfg!(debug_assertions) {
109        approx::assert_relative_eq!(triangle.point_a() + edge1 * b1 + edge2 * b2, y,
110          epsilon = S::default_epsilon() * S::two().powi (36),
111          max_relative = S::default_max_relative() * S::two().powi (36));
112      }
113      return (
114        ([b1, b2].map (Normalized::unchecked), y),
115        (intersect, y) )
116    }
117  }
118  // either parallel or intersection outside triangle: nearest point is on an edge
119  let mut i0 = 2;
120  let mut i1 = 0;
121  let mut i2 = 1;
122  let mut lowest_dist_sq = None;
123  let mut p0 = S::zero();
124  let mut barycentric = [Normalized::zero(), Normalized::zero(), Normalized::zero()];
125  let triangle_points = triangle.points();
126  while i1 < 3 {
127    let segment = Segment3::noisy (triangle_points[i0], triangle_points[i1]);
128    let ((s0, p_line), (s1, p_seg)) = nearest_line3_segment3 (line, segment);
129    let dist_sq = (p_seg - p_line).self_dot();
130    if lowest_dist_sq.is_none_or (|lowest| dist_sq < lowest) {
131      lowest_dist_sq  = Some (dist_sq);
132      p0 = s0;
133      // NOTE: in the reference implementation these indices are in a different order,
134      // but the following gives the correct results in tests
135      barycentric[i0] = s1;
136      barycentric[i1] = Normalized::zero();
137      barycentric[i2] = Normalized::unchecked (S::one() - *s1);
138    }
139    i2 = i0;
140    i0 = i1;
141    i1 += 1;
142  }
143  let point_tri = triangle.point_a() + edge1 * barycentric[0] + edge2 * barycentric[1];
144  let point_line = line.origin + *dir * p0;
145  ( ([barycentric[0], barycentric[1]], point_tri),
146    (p0, point_line))
147}
148
149/// Returns the nearest 3D point on 3D triangle together with barycentric coordinates in
150/// relation to the triangle edges $ab$ and $ac$, and the nearest point in the 3D
151/// segment
152pub fn nearest_triangle3_segment3 <S> (triangle : Triangle3 <S>, segment : Segment3 <S>)
153  -> (Triangle3Point <S>, Segment3Point <S>)
154where S : Real + approx::RelativeEq <Epsilon=S> {
155  use num::One;
156  let (out_tri, (r, near_line)) =
157    nearest_triangle3_line3 (triangle, segment.affine_line());
158  if r < S::zero() {
159    let point_a = segment.point_a();
160    let out_tri = nearest_triangle3_point3 (triangle, point_a);
161    (out_tri, (Normalized::zero(), point_a))
162  } else if r > S::one() {
163    let point_b = segment.point_b();
164    let out_tri = nearest_triangle3_point3 (triangle, point_b);
165    (out_tri, (Normalized::one(), point_b))
166  } else {
167    (out_tri, (Normalized::unchecked (r), near_line))
168  }
169}
170
171/// Returns the nearest 3D point on 3D triangle together with barycentric coordinates in
172/// relation to the triangle edges $ab$ and $ac$
173pub fn nearest_triangle3_point3 <S> (triangle : Triangle3 <S>, point : Point3 <S>)
174  -> Triangle3Point <S>
175where S : OrderedField {
176  // method from Eberly GeometricTools:
177  // <https://github.com/davideberly/GeometricTools/blob/87e5d3924200515fd49812844812acf232da26aa/GTE/Mathematics/DistPointTriangle.h>
178  let d = triangle.point_a() - point;
179  let edge0 = triangle.point_b() - triangle.point_a();
180  let edge1 = triangle.point_c() - triangle.point_a();
181  let e00 = edge0.magnitude_squared();
182  let e01 = edge1.dot (edge0);
183  let e11 = edge1.magnitude_squared();
184  let de0 = d.dot (edge0);
185  let de1 = d.dot (edge1);
186  let det = (e00 * e11 - e01 * e01).abs();
187  let mut s = e01 * de1 - e11 * de0;
188  let mut t = e01 * de0 - e00 * de1;
189  // NOTE: in a previous version of this function this was a strict inequality
190  if s + t <= det {
191    if s < S::zero() {
192      if t < S::zero() {
193        // region 4
194        if de0 < S::zero() {
195          t = S::zero();
196          if -de0 > e00 {
197            s = S::one()
198          } else {
199            s = -de0 / e00
200          }
201        } else {
202          s = S::zero();
203          if de1 > S::zero() {
204            t = S::zero()
205          } else if -de1 >= e11 {
206            t = S::one()
207          } else {
208            t = -de1 / e11
209          }
210        }
211      } else {
212        // region 3
213        s = S::zero();
214        if de1 > S::zero() {
215          t = S::zero()
216        } else if -de1 >= e11 {
217          t = S::one()
218        } else {
219          t = -de1 / e11
220        }
221      }
222    } else if t < S::zero() {
223      // region 5
224      t = S::zero();
225      if de0 >= S::zero() {
226        s = S::zero()
227      } else if -de0 >= e00 {
228        s = S::one()
229      } else {
230        s = -de0 / e00
231      }
232    } else {
233      // region 0
234      // minimum at interior point
235      let idet = S::one() / det;
236      s *= idet;
237      t *= idet;
238    }
239  } else if s < S::zero() {
240    // region 2
241    let tmp0 = e01 + de0;
242    let tmp1 = e11 + de1;
243    if tmp1 > tmp0 {
244      let numer = tmp1 - tmp0;
245      let denom = e00 - S::two() * e01 + e11;
246      if numer >= denom {
247        s = S::one();
248        t = S::zero();
249      } else {
250        s = numer / denom;
251        t = S::one() - s;
252      }
253    } else {
254      s = S::zero();
255      if tmp1 <= S::zero() {
256        t = S::one()
257      } else if de1 >= S::zero() {
258        t = S::zero()
259      } else {
260        t = -de1 / e11
261      }
262    }
263  } else if t < S::zero() {
264    // region 6
265    let tmp0 = e01 + de1;
266    let tmp1 = e00 + de0;
267    if tmp1 > tmp0 {
268      let numer = tmp1 - tmp0;
269      let denom = e00 - S::two() * e01 + e11;
270      if numer >= denom {
271        t = S::one();
272        s = S::zero();
273      } else {
274        t = numer / denom;
275        s = S::one() - t;
276      }
277    } else {
278      t = S::zero();
279      if tmp1 <= S::zero() {
280        s = S::one()
281      } else if de0 >= S::zero() {
282        s = S::zero()
283      } else {
284        s = -de0 / e00
285      }
286    }
287  } else {
288    // region 1
289    let numer = e11 + de1 - e01 - de0;
290    if numer <= S::zero() {
291      s = S::zero();
292      t = S::one();
293    } else {
294      let denom = e00 - S::two() * e01 + e11;
295      if numer >= denom {
296        s = S::one();
297        t = S::zero();
298      } else {
299        s = numer / denom;
300        t = S::one() - s;
301      }
302    }
303  }
304  let nearest = triangle.point_a() + edge0 * s + edge1 * t;
305  ([s, t].map (Normalized::unchecked), nearest)
306}
307
308/// Returns the nearest points on given 3D lines
309pub fn nearest_line3_line3 <S> (line_a : frame::Line3 <S>, line_b : frame::Line3 <S>)
310  -> (Line3Point <S>, Line3Point <S>)
311where S : OrderedField {
312  // method from Eberly GeometricTools:
313  // <https://github.com/davideberly/GeometricTools/blob/e095b84018766274f1546a7baa12c257fd18f7d8/GTE/Mathematics/DistLineLine.h>
314  let line_a_vec = line_a.basis;
315  let line_b_vec = line_b.basis;
316  let diff       = line_a.origin - line_b.origin;
317  let a00        = line_a_vec.magnitude_squared();
318  let a01        = -line_a_vec.dot (*line_b_vec);
319  let a11        = line_b_vec.magnitude_squared();
320  let b0         = line_a_vec.dot (diff);
321  let det        = S::max (a00 * a11 - a01 * a01, S::zero());
322  let (s0, s1)   = if det > S::zero() {
323    let b1 = -line_b_vec.dot (diff);
324    ( (a01 * b1 - a11 * b0) / det,
325      (a01 * b0 - a00 * b1) / det )
326  } else {
327    (-b0 / a00, S::zero())
328  };
329  let nearest_a = line_a.origin + *line_a_vec * s0;
330  let nearest_b = line_b.origin + *line_b_vec * s1;
331  ((s0, nearest_a), (s1, nearest_b))
332}
333
334/// Returns the nearest points in given 3D line and segment
335pub fn nearest_line3_segment3 <S> (line : frame::Line3 <S>, segment : Segment3 <S>)
336  -> (Line3Point <S>, Segment3Point <S>)
337where S : OrderedField {
338  // method from Eberly GeometricTools:
339  // <https://github.com/davideberly/GeometricTools/blob/2339413089df7c2b21c2ec403729d9d72f75f2de/GTE/Mathematics/DistLineSegment.h>
340  let line_dir = line.basis;
341  let seg_dir  = segment.vector();
342  let diff     = line.origin - segment.point_a();
343  let a00      = line_dir.magnitude_squared();
344  let a01      = -line_dir.dot (*seg_dir);
345  let a11      = seg_dir.magnitude_squared();
346  let b0       = line_dir.dot (diff);
347  let det      = S::max (a00 * a11 - a01 * a01, S::zero());
348  let s0;
349  let mut s1;
350  if det > S::zero() {
351    // line and segment are not parallel
352    let b1 = -seg_dir.dot (diff);
353    s1 = a01 * b0 - a00 * b1;
354    if s1 >= S::zero() {
355      if s1 <= det {
356        s0 = (a01 * b1 - a11 * b0) / det;
357        s1 /= det;
358      } else {
359        s0 = -(a01 + b0) / a00;
360        s1 = S::one();
361      }
362    } else {
363      s0 = -b0 / a00;
364      s1 = S::zero();
365    }
366  } else {
367    // line and segment are parallel
368    s0 = -b0 / a00;
369    s1 = S::zero();
370  }
371  let p_line = line.origin + *line_dir * s0;
372  let p_seg  = segment.point_a() + *seg_dir * s1;
373  ((s0, p_line), (Normalized::unchecked (s1), p_seg))
374}
375
376/// Nearest 3D point on a 3D line defined by a line segment
377pub fn nearest_line3_point3 <S> (line : frame::Line3 <S>, point : Point3 <S>)
378  -> Line3Point <S>
379where S : OrderedRing {
380  let ab = line.basis;
381  let av = point.0 - line.origin.0;
382  let ab2 = ab.magnitude_squared();
383  let ab_dot_av = ab.dot (av);
384  let t = ab_dot_av / ab2;
385  let tab = *ab * t;
386  let at = line.origin + tab;
387  (t, at)
388}
389
390/// Returns the nearest points on given 3D segments
391pub fn nearest_segment3_segment3 <S : Real> (
392  _segment_a : Segment3 <S>, _segment_b : Segment3 <S>
393) -> (Segment3Point <S>, Segment3Point <S>) {
394  unimplemented!("TODO: nearest segment3 segment3")
395}
396
397/// Returns the nearest point on a 3D segment
398pub fn nearest_segment3_point3 <S> (segment : Segment3 <S>, point : Point3 <S>)
399  -> Segment3Point <S>
400where S : OrderedField {
401  use num::One;
402  let (t, point) = nearest_line3_point3 (segment.affine_line(), point);
403  if t < S::zero() {
404    (Normalized::zero(), segment.point_a())
405  } else if t > S::one() {
406    (Normalized::one(), segment.point_b())
407  } else {
408    (Normalized::unchecked (t), point)
409  }
410}
411
412impl <S : Ring> Distance2 <S> {
413  pub const fn nearest_a (&self) -> Point2 <S> {
414    self.nearest_a
415  }
416  pub const fn nearest_b (&self) -> Point2 <S> {
417    self.nearest_b
418  }
419  pub const fn distance_squared (&self) -> NonNegative <S> {
420    self.distance_squared
421  }
422  pub fn distance (&mut self) -> NonNegative <S> where S : Sqrt {
423    self.distance.unwrap_or_else (|| {
424      let distance = self.distance_squared.sqrt();
425      self.distance = Some (distance);
426      distance
427    })
428  }
429
430  pub fn segment_point (segment : Segment2 <S>, point : Point2 <S>) -> Self
431    where S : OrderedField
432  {
433    let (_, nearest_a) = nearest_segment2_point2 (segment, point);
434    let distance_squared = (point - nearest_a).norm_squared();
435    Distance2 { distance_squared, distance: None, nearest_a, nearest_b: point }
436  }
437
438  pub fn line_point (line : frame::Line2 <S>, point : Point2 <S>) -> Self
439    where S : OrderedField
440  {
441    let (_, nearest_a) = nearest_line2_point2 (line, point);
442    let distance_squared = (point - nearest_a).norm_squared();
443    Distance2 { distance_squared, distance: None, nearest_a, nearest_b: point }
444  }
445
446  pub fn triangle_point (triangle : Triangle2 <S>, point : Point2 <S>) -> Self
447    where S : OrderedField
448  {
449    let (_, nearest_a) = nearest_triangle2_point2 (triangle, point);
450    let distance_squared = (point - nearest_a).norm_squared();
451    Distance2 { distance_squared, distance: None, nearest_a, nearest_b: point }
452  }
453}
454
455impl <S : Ring> Distance3 <S> {
456  pub const fn nearest_a (&self) -> Point3 <S> {
457    self.nearest_a
458  }
459  pub const fn nearest_b (&self) -> Point3 <S> {
460    self.nearest_b
461  }
462  pub const fn distance_squared (&self) -> NonNegative <S> {
463    self.distance_squared
464  }
465  pub fn distance (&mut self) -> NonNegative <S> where S : Sqrt {
466    self.distance.unwrap_or_else (|| {
467      let distance = self.distance_squared.sqrt();
468      self.distance = Some (distance);
469      distance
470    })
471  }
472
473  pub fn segment_point (segment : Segment3 <S>, point : Point3 <S>) -> Self
474    where S : OrderedField
475  {
476    let (_, nearest_a) = nearest_segment3_point3 (segment, point);
477    let distance_squared = (point - nearest_a).norm_squared();
478    Distance3 { distance_squared, distance: None, nearest_a, nearest_b: point }
479  }
480
481  pub fn segment_segment (segment_a : Segment3 <S>, segment_b : Segment3 <S>) -> Self
482    where S : Real
483  {
484    let ((_, nearest_a), (_, nearest_b)) =
485      nearest_segment3_segment3 (segment_a, segment_b);
486    let distance_squared = (nearest_b - nearest_a).norm_squared();
487    Distance3 { distance_squared, distance: None, nearest_a, nearest_b }
488  }
489
490  pub fn line_point (line : frame::Line3 <S>, point : Point3 <S>) -> Self
491    where S : OrderedField
492  {
493    let (_, nearest_a) = nearest_line3_point3 (line, point);
494    let distance_squared = (point - nearest_a).norm_squared();
495    Distance3 { distance_squared, distance: None, nearest_a, nearest_b: point }
496  }
497
498  pub fn line_segment (line : frame::Line3 <S>, segment : Segment3 <S>) -> Self
499    where S : OrderedField
500  {
501    let ((_, nearest_a), (_, nearest_b)) = nearest_line3_segment3 (line, segment);
502    let distance_squared = (nearest_b - nearest_a).norm_squared();
503    Distance3 { distance_squared, distance: None, nearest_a, nearest_b }
504  }
505
506  pub fn line_line (line_a : frame::Line3 <S>, line_b : frame::Line3 <S>) -> Self
507    where S : OrderedField
508  {
509    let ((_, nearest_a), (_, nearest_b)) = nearest_line3_line3 (line_a, line_b);
510    let distance_squared = (nearest_b - nearest_a).norm_squared();
511    Distance3 { distance_squared, distance: None, nearest_a, nearest_b }
512  }
513
514  pub fn triangle_point (triangle : Triangle3 <S>, point : Point3 <S>) -> Self
515    where S : OrderedField
516  {
517    let (_, nearest_a) = nearest_triangle3_point3 (triangle, point);
518    let distance_squared = (point - nearest_a).norm_squared();
519    Distance3 { distance_squared, distance: None, nearest_a, nearest_b: point }
520  }
521
522  pub fn triangle_segment (triangle : Triangle3 <S>, segment : Segment3 <S>) -> Self
523    where S : Real + approx::RelativeEq <Epsilon=S>
524  {
525    let ((_, nearest_a), (_, nearest_b)) =
526      nearest_triangle3_segment3 (triangle, segment);
527    let distance_squared = (nearest_b - nearest_a).norm_squared();
528    Distance3 { distance_squared, distance: None, nearest_a, nearest_b }
529  }
530
531  pub fn triangle_line (triangle : Triangle3 <S>, line : frame::Line3 <S>) -> Self
532    where S : Real + approx::RelativeEq <Epsilon=S>
533  {
534    let ((_, nearest_a), (_, nearest_b)) = nearest_triangle3_line3 (triangle, line);
535    let distance_squared = (nearest_b - nearest_a).norm_squared();
536    Distance3 { distance_squared, distance: None, nearest_a, nearest_b }
537  }
538
539  pub fn triangle_triangle (triangle_a : Triangle3 <S>, triangle_b : Triangle3 <S>)
540    -> Self
541  where S : OrderedField {
542    let ((_, nearest_a), (_, nearest_b)) =
543      nearest_triangle3_triangle3 (triangle_a, triangle_b);
544    let distance_squared = (nearest_b - nearest_a).norm_squared();
545    Distance3 { distance_squared, distance: None, nearest_a, nearest_b }
546  }
547}
548
549#[cfg(test)]
550mod tests {
551  use super::*;
552
553  #[test]
554  fn nearest_line_segment_3d() {
555    let line = Segment3::noisy (
556      [0.0, 0.0, 0.0].into(),
557      [1.0, 1.0, 0.0].into()
558    ).affine_line();
559    let segment = Segment3::noisy (
560      [0.0, -1.0, 0.0].into(),
561      [1.0, -1.0, 0.0].into());
562    let ((s0, p_line), (s1, p_seg)) = nearest_line3_segment3 (line, segment);
563    assert_eq!(s0, -0.5);
564    assert_eq!(*s1, 0.0);
565    assert_eq!(p_line, [-0.5, -0.5, 0.0].into());
566    assert_eq!(p_seg, [0.0, -1.0, 0.0].into());
567    let segment = Segment3::noisy (
568      [0.0, -1.0, 0.0].into(),
569      [1.0,  0.0, 0.0].into());
570    let ((s0, p_line), (s1, p_seg)) = nearest_line3_segment3 (line, segment);
571    assert_eq!(s0, -0.5);
572    assert_eq!(*s1, 0.0);
573    assert_eq!(p_line, [-0.5, -0.5, 0.0].into());
574    assert_eq!(p_seg, [0.0, -1.0, 0.0].into());
575  }
576
577  #[test]
578  fn nearest_triangle_line_3d() {
579    let triangle = Triangle3::noisy (
580      [-1.0, -1.0, 0.0].into(),
581      [ 1.0, -1.0, 0.0].into(),
582      [ 0.0,  1.0, 0.0].into());
583    let line = Segment3::noisy (
584      [-2.0, -2.0, 0.0].into(),
585      [-2.0, -2.0, 1.0].into()
586    ).affine_line();
587    let (([t0, t1], p_tri), (s0, p_line)) = nearest_triangle3_line3 (triangle, line);
588    assert_eq!((*t0, *t1), (0.0, 0.0));
589    assert_eq!(p_tri, [-1.0, -1.0, 0.0].into());
590    assert_eq!(s0, 0.0);
591    assert_eq!(p_line, [-2.0, -2.0, 0.0].into());
592    let line = Segment3::noisy (
593      [ 2.0, -2.0, 0.0].into(),
594      [ 2.0, -2.0, 1.0].into()
595    ).affine_line();
596    let (([t0, t1], p_tri), (s0, p_line)) = nearest_triangle3_line3 (triangle, line);
597    assert_eq!((*t0, *t1), (1.0, 0.0));
598    assert_eq!(p_tri, [1.0, -1.0, 0.0].into());
599    assert_eq!(s0, 0.0);
600    assert_eq!(p_line, [2.0, -2.0, 0.0].into());
601    let line = Segment3::noisy (
602      [0.0, 2.0, 0.0].into(),
603      [0.0, 2.0, 1.0].into()
604    ).affine_line();
605    let (([t0, t1], p_tri), (s0, p_line)) = nearest_triangle3_line3 (triangle, line);
606    assert_eq!((*t0, *t1), (0.0, 1.0));
607    assert_eq!(p_tri, [0.0, 1.0, 0.0].into());
608    assert_eq!(s0, 0.0);
609    assert_eq!(p_line, [0.0, 2.0, 0.0].into());
610    let line = Segment3::noisy (
611      [0.0, -2.0, 0.0].into(),
612      [0.0, -2.0, 1.0].into()
613    ).affine_line();
614    let (([t0, t1], p_tri), (s0, p_line)) = nearest_triangle3_line3 (triangle, line);
615    assert_eq!((*t0, *t1), (0.5, 0.0));
616    assert_eq!(p_tri, [0.0, -1.0, 0.0].into());
617    assert_eq!(s0, 0.0);
618    assert_eq!(p_line, [0.0, -2.0, 0.0].into());
619  }
620}