fj_kernel/algorithms/triangulate/
mod.rs1mod delaunay;
4mod polygon;
5
6use fj_interop::mesh::Mesh;
7use fj_math::Point;
8
9use self::polygon::Polygon;
10
11use super::approx::{face::FaceApprox, Approx, Tolerance};
12
13pub trait Triangulate: Sized {
15 fn triangulate(self) -> Mesh<Point<3>> {
17 let mut mesh = Mesh::new();
18 self.triangulate_into_mesh(&mut mesh);
19 mesh
20 }
21
22 fn triangulate_into_mesh(self, mesh: &mut Mesh<Point<3>>);
27}
28
29impl<T> Triangulate for (T, Tolerance)
30where
31 T: Approx,
32 T::Approximation: IntoIterator<Item = FaceApprox>,
33{
34 fn triangulate_into_mesh(self, mesh: &mut Mesh<Point<3>>) {
35 let (approx, tolerance) = self;
36
37 let approx = approx.approx(tolerance);
38
39 for approx in approx {
40 approx.triangulate_into_mesh(mesh);
41 }
42 }
43}
44
45impl Triangulate for FaceApprox {
46 fn triangulate_into_mesh(self, mesh: &mut Mesh<Point<3>>) {
47 let face_as_polygon = Polygon::new()
48 .with_exterior(
49 self.exterior
50 .points()
51 .into_iter()
52 .map(|point| point.local_form),
53 )
54 .with_interiors(self.interiors.iter().map(|interior| {
55 interior.points().into_iter().map(|point| point.local_form)
56 }));
57
58 let cycles = [self.exterior].into_iter().chain(self.interiors);
59 let mut triangles =
60 delaunay::triangulate(cycles, self.coord_handedness);
61 triangles.retain(|triangle| {
62 face_as_polygon
63 .contains_triangle(triangle.map(|point| point.point_surface))
64 });
65
66 let color = self.color.unwrap_or_default();
67
68 for triangle in triangles {
69 let points = triangle.map(|point| point.point_global);
70 mesh.push_triangle(points, color);
71 }
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use fj_interop::mesh::Mesh;
78 use fj_math::{Point, Scalar};
79
80 use crate::{
81 algorithms::approx::{Approx, Tolerance},
82 objects::{Cycle, Face},
83 operations::{BuildCycle, BuildFace, Insert, UpdateFace},
84 services::Services,
85 };
86
87 use super::Triangulate;
88
89 #[test]
90 fn simple() -> anyhow::Result<()> {
91 let mut services = Services::new();
92
93 let a = [0., 0.];
94 let b = [2., 0.];
95 let c = [2., 2.];
96 let d = [0., 1.];
97
98 let face =
99 Face::unbound(services.objects.surfaces.xy_plane(), &mut services)
100 .update_exterior(|_| {
101 Cycle::polygon([a, b, c, d], &mut services)
102 .insert(&mut services)
103 });
104 services.only_validate(&face);
105
106 let a = Point::from(a).to_xyz();
107 let b = Point::from(b).to_xyz();
108 let c = Point::from(c).to_xyz();
109 let d = Point::from(d).to_xyz();
110
111 let triangles = triangulate(face)?;
112
113 assert!(triangles.contains_triangle([a, b, d]));
114 assert!(triangles.contains_triangle([b, c, d]));
115 assert!(!triangles.contains_triangle([a, b, c]));
116 assert!(!triangles.contains_triangle([a, c, d]));
117
118 Ok(())
119 }
120
121 #[test]
122 fn simple_hole() -> anyhow::Result<()> {
123 let mut services = Services::new();
124
125 let a = [0., 0.];
126 let b = [4., 0.];
127 let c = [4., 4.];
128 let d = [0., 4.];
129
130 let e = [1., 1.];
131 let f = [1., 2.];
132 let g = [3., 3.];
133 let h = [3., 1.];
134
135 let surface = services.objects.surfaces.xy_plane();
136
137 let face = Face::unbound(surface.clone(), &mut services)
138 .update_exterior(|_| {
139 Cycle::polygon([a, b, c, d], &mut services)
140 .insert(&mut services)
141 })
142 .add_interiors([Cycle::polygon([e, f, g, h], &mut services)
143 .insert(&mut services)]);
144 services.only_validate(&face);
145
146 let triangles = triangulate(face)?;
147
148 let a = surface.geometry().point_from_surface_coords(a);
149 let b = surface.geometry().point_from_surface_coords(b);
150 let e = surface.geometry().point_from_surface_coords(e);
151 let f = surface.geometry().point_from_surface_coords(f);
152 let g = surface.geometry().point_from_surface_coords(g);
153 let h = surface.geometry().point_from_surface_coords(h);
154
155 assert!(triangles.contains_triangle([a, b, e]));
165 assert!(triangles.contains_triangle([b, e, h]));
166
167 assert!(!triangles.contains_triangle([e, f, g]));
169 assert!(!triangles.contains_triangle([e, g, h]));
170 assert!(!triangles.contains_triangle([e, f, h]));
171 assert!(!triangles.contains_triangle([f, g, h]));
172
173 Ok(())
174 }
175
176 #[test]
177 fn sharp_concave_shape() -> anyhow::Result<()> {
178 let mut services = Services::new();
179
180 let a = [1., 0.];
192 let b = [2., 8.];
193 let c = [2., 9.];
194 let d = [1., 1.];
195 let e = [0., 9.];
196
197 let surface = services.objects.surfaces.xy_plane();
198
199 let face = Face::unbound(surface.clone(), &mut services)
200 .update_exterior(|_| {
201 Cycle::polygon([a, b, c, d, e], &mut services)
202 .insert(&mut services)
203 });
204 services.only_validate(&face);
205
206 let triangles = triangulate(face)?;
207
208 let a = surface.geometry().point_from_surface_coords(a);
209 let b = surface.geometry().point_from_surface_coords(b);
210 let c = surface.geometry().point_from_surface_coords(c);
211 let d = surface.geometry().point_from_surface_coords(d);
212 let e = surface.geometry().point_from_surface_coords(e);
213
214 assert!(triangles.contains_triangle([a, b, d]));
215 assert!(triangles.contains_triangle([a, d, e]));
216 assert!(triangles.contains_triangle([b, c, d]));
217
218 Ok(())
219 }
220
221 fn triangulate(face: Face) -> anyhow::Result<Mesh<Point<3>>> {
222 let tolerance = Tolerance::from_scalar(Scalar::ONE)?;
223 Ok(face.approx(tolerance).triangulate())
224 }
225}