fj_kernel/algorithms/intersect/
curve_edge.rs

1use fj_math::{Point, Segment};
2
3use crate::{geometry::curve::Curve, objects::HalfEdge};
4
5use super::LineSegmentIntersection;
6
7/// The intersection between a curve and a [`HalfEdge`]
8#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
9pub enum CurveEdgeIntersection {
10    /// The curve and edge intersect at a point
11    Point {
12        /// The intersection point, in curve coordinates on the curve
13        point_on_curve: Point<1>,
14    },
15
16    /// The edge lies on the curve
17    Coincident {
18        /// The end points of the edge, in curve coordinates on the curve
19        points_on_curve: [Point<1>; 2],
20    },
21}
22
23impl CurveEdgeIntersection {
24    /// Compute the intersection
25    ///
26    /// # Panics
27    ///
28    /// Currently, only intersections between lines and line segments can be
29    /// computed. Panics, if a different type of curve or [`HalfEdge`] is
30    /// passed.
31    pub fn compute(curve: &Curve, half_edge: &HalfEdge) -> Option<Self> {
32        let curve_as_line = match curve {
33            Curve::Line(line) => line,
34            _ => todo!("Curve-edge intersection only supports lines"),
35        };
36
37        let edge_as_segment = {
38            let edge_curve_as_line = match half_edge.curve() {
39                Curve::Line(line) => line,
40                _ => {
41                    todo!("Curve-edge intersection only supports line segments")
42                }
43            };
44
45            let edge_vertices = half_edge
46                .boundary()
47                .map(|point| edge_curve_as_line.point_from_line_coords(point));
48
49            Segment::from_points(edge_vertices)
50        };
51
52        let intersection =
53            LineSegmentIntersection::compute(curve_as_line, &edge_as_segment)?;
54
55        let intersection = match intersection {
56            LineSegmentIntersection::Point { point_on_line } => Self::Point {
57                point_on_curve: point_on_line,
58            },
59            LineSegmentIntersection::Coincident { points_on_line } => {
60                Self::Coincident {
61                    points_on_curve: points_on_line,
62                }
63            }
64        };
65
66        Some(intersection)
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use fj_math::Point;
73
74    use crate::{
75        geometry::curve::Curve, objects::HalfEdge, operations::BuildHalfEdge,
76        services::Services,
77    };
78
79    use super::CurveEdgeIntersection;
80
81    #[test]
82    fn compute_edge_in_front_of_curve_origin() {
83        let mut services = Services::new();
84
85        let curve = Curve::u_axis();
86        let half_edge =
87            HalfEdge::line_segment([[1., -1.], [1., 1.]], None, &mut services);
88
89        let intersection = CurveEdgeIntersection::compute(&curve, &half_edge);
90
91        assert_eq!(
92            intersection,
93            Some(CurveEdgeIntersection::Point {
94                point_on_curve: Point::from([1.])
95            })
96        );
97    }
98
99    #[test]
100    fn compute_edge_behind_curve_origin() {
101        let mut services = Services::new();
102
103        let curve = Curve::u_axis();
104        let half_edge = HalfEdge::line_segment(
105            [[-1., -1.], [-1., 1.]],
106            None,
107            &mut services,
108        );
109
110        let intersection = CurveEdgeIntersection::compute(&curve, &half_edge);
111
112        assert_eq!(
113            intersection,
114            Some(CurveEdgeIntersection::Point {
115                point_on_curve: Point::from([-1.])
116            })
117        );
118    }
119
120    #[test]
121    fn compute_edge_parallel_to_curve() {
122        let mut services = Services::new();
123
124        let curve = Curve::u_axis();
125        let half_edge = HalfEdge::line_segment(
126            [[-1., -1.], [1., -1.]],
127            None,
128            &mut services,
129        );
130
131        let intersection = CurveEdgeIntersection::compute(&curve, &half_edge);
132
133        assert!(intersection.is_none());
134    }
135
136    #[test]
137    fn compute_edge_on_curve() {
138        let mut services = Services::new();
139
140        let curve = Curve::u_axis();
141        let half_edge =
142            HalfEdge::line_segment([[-1., 0.], [1., 0.]], None, &mut services);
143
144        let intersection = CurveEdgeIntersection::compute(&curve, &half_edge);
145
146        assert_eq!(
147            intersection,
148            Some(CurveEdgeIntersection::Coincident {
149                points_on_curve: [Point::from([-1.]), Point::from([1.]),]
150            })
151        );
152    }
153}