axiolid_reference/
segment_triangle.rs1use axiolid_contracts::Sign;
8use axiolid_core::Point3;
9
10use crate::orient3d;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum SegmentTriangleRelation {
15 Disjoint,
17 Proper,
19 Touching,
21 Coplanar,
26 DegenerateSegment,
28 DegenerateTriangle,
30}
31
32#[must_use]
37pub fn segment_triangle_relation(
38 start: Point3,
39 end: Point3,
40 triangle: [Point3; 3],
41) -> SegmentTriangleRelation {
42 if start == end {
43 return SegmentTriangleRelation::DegenerateSegment;
44 }
45
46 let [a, b, c] = triangle;
47 if (b - a).cross(c - a).length_squared() == 0.0 {
48 return SegmentTriangleRelation::DegenerateTriangle;
49 }
50
51 let start_side = sign(orient3d(a, b, c, start));
52 let end_side = sign(orient3d(a, b, c, end));
53 if start_side == Sign::Zero && end_side == Sign::Zero {
54 return SegmentTriangleRelation::Coplanar;
55 }
56 if start_side != Sign::Zero && start_side == end_side {
57 return SegmentTriangleRelation::Disjoint;
58 }
59
60 let edge_signs = [
64 sign(orient3d(start, end, a, b)),
65 sign(orient3d(start, end, b, c)),
66 sign(orient3d(start, end, c, a)),
67 ];
68 let all_nonnegative = edge_signs.iter().all(|&value| value != Sign::Negative);
69 let all_nonpositive = edge_signs.iter().all(|&value| value != Sign::Positive);
70 if !all_nonnegative && !all_nonpositive {
71 return SegmentTriangleRelation::Disjoint;
72 }
73
74 if start_side == Sign::Zero || end_side == Sign::Zero || edge_signs.contains(&Sign::Zero) {
75 SegmentTriangleRelation::Touching
76 } else {
77 SegmentTriangleRelation::Proper
78 }
79}
80
81fn sign(value: axiolid_contracts::Certified) -> Sign {
82 value
84 .sign()
85 .expect("orient3d is a total certified predicate")
86}