Skip to main content

brep_kernel/geometry/
triangle.rs

1use crate::Vec3;
2
3/// Ericson Voronoi-region closest point, including degenerate triangle edges.
4pub fn closest_point_on_triangle(p: Vec3, a: Vec3, b: Vec3, c: Vec3) -> Vec3 {
5    let ab = b.sub(a);
6    let ac = c.sub(a);
7    if ab.cross(ac).length_squared() == 0.0 {
8        let mut best = a;
9        let mut best_distance = f64::INFINITY;
10        for (start, end) in [(a, b), (b, c), (c, a)] {
11            let edge = end.sub(start);
12            let length = edge.length_squared();
13            let t = if length > 0.0 { (p.sub(start).dot(edge) / length).clamp(0.0, 1.0) } else { 0.0 };
14            let point = start.add(edge.scale(t));
15            let distance = p.sub(point).length_squared();
16            if distance < best_distance {
17                best = point;
18                best_distance = distance;
19            }
20        }
21        return best;
22    }
23    let ap = p.sub(a);
24    let d1 = ab.dot(ap);
25    let d2 = ac.dot(ap);
26    if d1 <= 0.0 && d2 <= 0.0 {
27        return a;
28    }
29    let bp = p.sub(b);
30    let d3 = ab.dot(bp);
31    let d4 = ac.dot(bp);
32    if d3 >= 0.0 && d4 <= d3 {
33        return b;
34    }
35    let vc = d1 * d4 - d3 * d2;
36    if vc <= 0.0 && d1 >= 0.0 && d3 <= 0.0 {
37        let v = if (d1 - d3).abs() > 0.0 { d1 / (d1 - d3) } else { 0.0 };
38        return a.add(ab.scale(v));
39    }
40    let cp = p.sub(c);
41    let d5 = ab.dot(cp);
42    let d6 = ac.dot(cp);
43    if d6 >= 0.0 && d5 <= d6 {
44        return c;
45    }
46    let vb = d5 * d2 - d1 * d6;
47    if vb <= 0.0 && d2 >= 0.0 && d6 <= 0.0 {
48        let w = if (d2 - d6).abs() > 0.0 { d2 / (d2 - d6) } else { 0.0 };
49        return a.add(ac.scale(w));
50    }
51    let va = d3 * d6 - d5 * d4;
52    if va <= 0.0 && (d4 - d3) >= 0.0 && (d5 - d6) >= 0.0 {
53        let denom = (d4 - d3) + (d5 - d6);
54        let w = if denom > 0.0 { (d4 - d3) / denom } else { 0.0 };
55        return b.add(c.sub(b).scale(w));
56    }
57    let denom = 1.0 / (va + vb + vc);
58    let v = vb * denom;
59    let w = vc * denom;
60    a.add(ab.scale(v)).add(ac.scale(w))
61}
62