fj_kernel/algorithms/intersect/
face_face.rs1use fj_interop::ext::ArrayExt;
2use iter_fixed::IntoIteratorFixed;
3
4use crate::{geometry::curve::Curve, objects::Face};
5
6use super::{CurveFaceIntersection, SurfaceSurfaceIntersection};
7
8#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
10pub struct FaceFaceIntersection {
11 pub intersection_curves: [Curve; 2],
18
19 pub intersection_intervals: CurveFaceIntersection,
23}
24
25impl FaceFaceIntersection {
26 pub fn compute(faces: [&Face; 2]) -> Option<Self> {
28 let surfaces = faces.map(|face| face.surface().clone());
29
30 let intersection_curves =
31 match SurfaceSurfaceIntersection::compute(surfaces) {
32 Some(intersection) => intersection.intersection_curves,
33 None => return None,
34 };
35
36 let curve_face_intersections = intersection_curves
37 .each_ref_ext()
38 .into_iter_fixed()
39 .zip(faces)
40 .map(|(curve, face)| CurveFaceIntersection::compute(curve, face))
41 .collect::<[_; 2]>();
42
43 let intersection_intervals = {
44 let [a, b] = curve_face_intersections;
45 a.merge(&b)
46 };
47
48 if intersection_intervals.is_empty() {
49 return None;
50 }
51
52 Some(Self {
53 intersection_curves,
54 intersection_intervals,
55 })
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use pretty_assertions::assert_eq;
62
63 use crate::{
64 algorithms::intersect::CurveFaceIntersection,
65 geometry::curve::Curve,
66 objects::{Cycle, Face},
67 operations::{BuildCycle, BuildFace, Insert, UpdateFace},
68 services::Services,
69 };
70
71 use super::FaceFaceIntersection;
72
73 #[test]
74 fn compute_no_intersection() {
75 let mut services = Services::new();
76
77 #[rustfmt::skip]
78 let points = [
79 [1., 1.],
80 [2., 1.],
81 [2., 2.],
82 [1., 2.],
83 ];
84 let [a, b] = [
85 services.objects.surfaces.xy_plane(),
86 services.objects.surfaces.xz_plane(),
87 ]
88 .map(|surface| {
89 Face::unbound(surface, &mut services).update_exterior(|_| {
90 Cycle::polygon(points, &mut services).insert(&mut services)
91 })
92 });
93
94 let intersection = FaceFaceIntersection::compute([&a, &b]);
95 assert!(intersection.is_none());
96
97 services.only_validate([a, b]);
98 }
99
100 #[test]
101 fn compute_one_intersection() {
102 let mut services = Services::new();
103
104 #[rustfmt::skip]
105 let points = [
106 [-1., -1.],
107 [ 1., -1.],
108 [ 1., 1.],
109 [-1., 1.],
110 ];
111 let surfaces = [
112 services.objects.surfaces.xy_plane(),
113 services.objects.surfaces.xz_plane(),
114 ];
115 let [a, b] = surfaces.clone().map(|surface| {
116 Face::unbound(surface, &mut services).update_exterior(|_| {
117 Cycle::polygon(points, &mut services).insert(&mut services)
118 })
119 });
120
121 let intersection = FaceFaceIntersection::compute([&a, &b]);
122
123 let expected_curves = surfaces.map(|_| {
124 let (path, _) = Curve::line_from_points([[0., 0.], [1., 0.]]);
125 path
126 });
127 let expected_intervals =
128 CurveFaceIntersection::from_intervals([[[-1.], [1.]]]);
129 assert_eq!(
130 intersection,
131 Some(FaceFaceIntersection {
132 intersection_curves: expected_curves,
133 intersection_intervals: expected_intervals
134 })
135 );
136
137 services.only_validate([a, b]);
138 }
139}