fj_kernel/algorithms/triangulate/
delaunay.rs1use std::collections::BTreeMap;
2
3use fj_math::{Point, Scalar, Triangle, Winding};
4use spade::HasPosition;
5
6use crate::{algorithms::approx::cycle::CycleApprox, objects::Handedness};
7
8pub fn triangulate(
10 cycles: impl IntoIterator<Item = CycleApprox>,
11 coord_handedness: Handedness,
12) -> Vec<[TriangulationPoint; 3]> {
13 use spade::Triangulation as _;
14
15 let mut triangulation = spade::ConstrainedDelaunayTriangulation::<_>::new();
16
17 let mut points = BTreeMap::new();
18
19 for cycle_approx in cycles {
20 let mut handle_prev = None;
21
22 for point in cycle_approx.points() {
23 let handle = match points.get(&point) {
24 Some(handle) => *handle,
25 None => {
26 let handle = triangulation
27 .insert(TriangulationPoint {
28 point_surface: point.local_form,
29 point_global: point.global_form,
30 })
31 .expect("Inserted invalid point into triangulation");
32
33 points.insert(point, handle);
34
35 handle
36 }
37 };
38
39 if let Some(handle_prev) = handle_prev {
40 triangulation.add_constraint(handle_prev, handle);
41 }
42
43 handle_prev = Some(handle);
44 }
45 }
46
47 let mut triangles = Vec::new();
48 for triangle in triangulation.inner_faces() {
49 let [v0, v1, v2] = triangle.vertices().map(|vertex| *vertex.data());
50 let triangle_winding = Triangle::<2>::from_points([
51 v0.point_surface,
52 v1.point_surface,
53 v2.point_surface,
54 ])
55 .expect("invalid triangle")
56 .winding();
57
58 let required_winding = match coord_handedness {
59 Handedness::LeftHanded => Winding::Cw,
60 Handedness::RightHanded => Winding::Ccw,
61 };
62
63 let triangle = if triangle_winding == required_winding {
64 [v0, v1, v2]
65 } else {
66 [v0, v2, v1]
67 };
68
69 triangles.push(triangle);
70 }
71
72 triangles
73}
74
75#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
76pub struct TriangulationPoint {
77 pub point_surface: Point<2>,
78 pub point_global: Point<3>,
79}
80
81impl HasPosition for TriangulationPoint {
83 type Scalar = Scalar;
84
85 fn position(&self) -> spade::Point2<Self::Scalar> {
86 spade::Point2 {
87 x: self.point_surface.u,
88 y: self.point_surface.v,
89 }
90 }
91}