1use std::vec;
2
3use fj_interop::ext::SliceExt;
4use fj_math::Point;
5
6use crate::{geometry::curve::Curve, objects::Face};
7
8use super::CurveEdgeIntersection;
9
10#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
12pub struct CurveFaceIntersection {
13 pub intervals: Vec<CurveFaceIntersectionInterval>,
15}
16
17impl CurveFaceIntersection {
18 pub fn from_intervals(
22 intervals: impl IntoIterator<
23 Item = impl Into<CurveFaceIntersectionInterval>,
24 >,
25 ) -> Self {
26 let intervals = intervals.into_iter().map(Into::into).collect();
27 Self { intervals }
28 }
29
30 pub fn compute(curve: &Curve, face: &Face) -> Self {
32 let half_edges = face.all_cycles().flat_map(|cycle| cycle.half_edges());
33
34 let mut intersections = Vec::new();
35
36 for half_edge in half_edges {
37 let intersection = CurveEdgeIntersection::compute(curve, half_edge);
38
39 if let Some(intersection) = intersection {
40 match intersection {
41 CurveEdgeIntersection::Point { point_on_curve } => {
42 intersections.push(point_on_curve);
43 }
44 CurveEdgeIntersection::Coincident { points_on_curve } => {
45 intersections.extend(points_on_curve);
46 }
47 }
48 }
49 }
50
51 assert!(intersections.len() % 2 == 0);
52
53 intersections.sort();
54
55 let intervals = intersections
56 .as_slice()
57 .array_chunks_ext()
58 .map(|&[start, end]| CurveFaceIntersectionInterval { start, end })
59 .collect();
60
61 Self { intervals }
62 }
63
64 pub fn merge(&self, other: &Self) -> Self {
69 let mut self_intervals = self.intervals.iter().copied();
70 let mut other_interval = other.intervals.iter().copied();
71
72 let mut next_self = self_intervals.next();
73 let mut next_other = other_interval.next();
74
75 let mut intervals = Vec::new();
76
77 while let (Some(self_), Some(other)) = (next_self, next_other) {
78 let overlap_start = self_.start.max(other.start);
85 let overlap_end = self_.end.min(other.end);
86
87 if overlap_start < overlap_end {
88 intervals.push(CurveFaceIntersectionInterval {
91 start: overlap_start,
92 end: overlap_end,
93 });
94 }
95
96 if self_.end <= overlap_end {
101 next_self = self_intervals.next();
104 }
105 if other.end <= overlap_end {
106 next_other = other_interval.next();
109 }
110 }
111
112 Self { intervals }
113 }
114
115 pub fn is_empty(&self) -> bool {
117 self.intervals.is_empty()
118 }
119}
120
121impl IntoIterator for CurveFaceIntersection {
122 type Item = CurveFaceIntersectionInterval;
123 type IntoIter = vec::IntoIter<Self::Item>;
124
125 fn into_iter(self) -> Self::IntoIter {
126 self.intervals.into_iter()
127 }
128}
129
130#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
132pub struct CurveFaceIntersectionInterval {
133 pub start: Point<1>,
135
136 pub end: Point<1>,
138}
139
140impl<P> From<[P; 2]> for CurveFaceIntersectionInterval
141where
142 P: Into<Point<1>>,
143{
144 fn from(interval: [P; 2]) -> Self {
145 let [start, end] = interval.map(Into::into);
146 Self { start, end }
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use crate::{
153 geometry::curve::Curve,
154 objects::{Cycle, Face},
155 operations::{BuildCycle, BuildFace, Insert, UpdateFace},
156 services::Services,
157 };
158
159 use super::CurveFaceIntersection;
160
161 #[test]
162 fn compute() {
163 let mut services = Services::new();
164
165 let (curve, _) = Curve::line_from_points([[-3., 0.], [-2., 0.]]);
166
167 #[rustfmt::skip]
168 let exterior_points = [
169 [-2., -2.],
170 [ 2., -2.],
171 [ 2., 2.],
172 [-2., 2.],
173 ];
174 #[rustfmt::skip]
175 let interior_points = [
176 [-1., -1.],
177 [-1., 1.],
178 [ 1., 1.],
179 [ 1., -1.],
180 ];
181
182 let face =
183 Face::unbound(services.objects.surfaces.xy_plane(), &mut services)
184 .update_exterior(|_| {
185 Cycle::polygon(exterior_points, &mut services)
186 .insert(&mut services)
187 })
188 .add_interiors([Cycle::polygon(
189 interior_points,
190 &mut services,
191 )
192 .insert(&mut services)]);
193
194 let expected =
195 CurveFaceIntersection::from_intervals([[[1.], [2.]], [[4.], [5.]]]);
196 assert_eq!(CurveFaceIntersection::compute(&curve, &face), expected);
197
198 services.only_validate(face);
199 }
200
201 #[test]
202 fn merge() {
203 let a = CurveFaceIntersection::from_intervals([
204 [[0.], [1.]], [[2.], [5.]], [[7.], [8.]], [[9.], [11.]], [[14.], [16.]], [[18.], [21.]], [[23.], [25.]], [[26.], [28.]], [[31.], [35.]], [[36.], [38.]], [[39.], [40.]], [[41.], [45.]], [[48.], [49.]], [[50.], [52.]], [[53.], [58.]], [[60.], [61.]], [[62.], [63.]], [[65.], [66.]], ]);
223 let b = CurveFaceIntersection::from_intervals([
224 [[0.], [1.]], [[3.], [4.]], [[6.], [9.]], [[10.], [12.]], [[13.], [15.]], [[17.], [19.]], [[20.], [22.]], [[24.], [27.]], [[30.], [32.]], [[33.], [34.]], [[37.], [41.]], [[42.], [43.]], [[44.], [46.]], [[47.], [51.]], [[54.], [55.]], [[56.], [57.]], [[59.], [64.]], ]);
242
243 let merged = a.merge(&b);
244
245 let expected = CurveFaceIntersection::from_intervals([
246 [[0.], [1.]], [[3.], [4.]], [[7.], [8.]], [[10.], [11.]], [[14.], [15.]], [[18.], [19.]], [[20.], [21.]], [[24.], [25.]], [[26.], [27.]], [[31.], [32.]], [[33.], [34.]], [[37.], [38.]], [[39.], [40.]], [[42.], [43.]], [[44.], [45.]], [[48.], [49.]], [[50.], [51.]], [[54.], [55.]], [[56.], [57.]], [[60.], [61.]], [[62.], [63.]], ]);
268 assert_eq!(merged, expected);
269 }
270}