1use iterator::FaceHalfedgeIterator;
2use iterator::FaceIterator;
3use mesh::Id;
4use mesh::Mesh;
5use util::*;
6
7pub trait Triangulate {
8 fn triangulate(&self) -> Self;
9}
10
11struct PolygonEdgeCounter {
12 pub polygon_edge_counts: Vec<usize>,
17}
18
19impl PolygonEdgeCounter {
20 pub fn new() -> Self {
21 Self {
22 polygon_edge_counts: Vec::new(),
23 }
24 }
25
26 pub fn add_polygon(&mut self, edge_count: usize) {
27 if edge_count >= self.polygon_edge_counts.len() {
28 self.polygon_edge_counts.resize(edge_count + 1, 0);
29 }
30 self.polygon_edge_counts[edge_count] += 1;
31 }
32}
33
34fn predict_triangle_count(pec: &PolygonEdgeCounter) -> usize {
35 let mut sum = 0;
36 for i in 3..pec.polygon_edge_counts.len() {
37 let polygons = pec.polygon_edge_counts[i];
38 sum += polygons * (i - 2);
39 }
40 sum
41}
42
43struct TriangulationPrediction {
44 vertex_count: usize,
45 triangle_count: usize,
46 halfedge_count: usize,
47 edge_count: usize,
48}
49
50impl TriangulationPrediction {
51 pub fn new(input: &Mesh) -> Self {
52 let mut pec = PolygonEdgeCounter::new();
53 for face_id in FaceIterator::new(input) {
54 let halfedge = input.face_first_halfedge_id(face_id).unwrap();
55 let count = FaceHalfedgeIterator::new(input, halfedge).count();
56 pec.add_polygon(count);
57 }
58 let triangle_count = predict_triangle_count(&pec);
59 let halfedge_count = triangle_count * 3;
60 Self {
61 triangle_count,
62 halfedge_count,
63 edge_count: halfedge_count / 2,
64 vertex_count: input.vertex_count,
65 }
66 }
67}
68
69impl Triangulate for Mesh {
70 fn triangulate(&self) -> Self {
72 let tp = TriangulationPrediction::new(self);
73 let mut tri_mesh = Mesh::new();
74 tri_mesh.vertices.reserve(tp.vertex_count);
75 tri_mesh.faces.reserve(tp.triangle_count);
76 tri_mesh.halfedges.reserve(tp.halfedge_count);
77 tri_mesh.edges.reserve(tp.edge_count);
78 let mut new_vertices: Vec<Option<Id>> =
79 vec![None; self.vertices.len() + 1];
80 let mut tri_faces = Vec::new();
81 tri_faces.reserve(tp.triangle_count);
82 let mut vertices = Vec::new();
83 for face_id in FaceIterator::new(self) {
84 vertices.clear();
85 let first_halfedge_id =
86 self.face_first_halfedge_id(face_id).unwrap();
87 for halfedge_id in
88 FaceHalfedgeIterator::new(self, first_halfedge_id)
89 {
90 let vertex = self.halfedge_start_vertex(halfedge_id).unwrap();
91 let new_vert = &mut new_vertices[vertex.id];
92 if new_vert.is_none() {
93 *new_vert = Some(tri_mesh.add_vertex(vertex.position));
94 }
95 vertices.push(vertex.id);
96 }
97 if vertices.len() > 3 {
98 let direct = self.face_norm(face_id);
99 while vertices.len() > 3 {
100 let mut new_face_generated = false;
101 for i in 0..vertices.len() {
102 let i_next = (i + 1) % vertices.len();
103 let enter = vertices[i];
104 let cone = vertices[i_next];
105 let leave = vertices[(i + 2) % vertices.len()];
106 let cone_v = self.vertex(cone).unwrap();
107 let enter_v = self.vertex(enter).unwrap();
108 let leave_v = self.vertex(leave).unwrap();
109 let angle = angle360(
110 cone_v.position - enter_v.position,
111 leave_v.position - cone_v.position,
112 direct,
113 );
114 if angle >= 1.0 && angle <= 179.0 {
115 let mut is_ear = true;
116 for j in 0..(vertices.len() - 3) {
117 let fourth =
118 vertices[(i + 3 + j) % vertices.len()];
119 let fourth_v = self.vertex(fourth).unwrap();
120 if point_in_triangle(
121 enter_v.position,
122 cone_v.position,
123 leave_v.position,
124 fourth_v.position,
125 ) {
126 is_ear = false;
127 break;
128 }
129 }
130 if is_ear {
131 tri_faces.push((enter, cone, leave));
132 vertices.remove(i_next);
133 new_face_generated = true;
134 break;
135 }
136 }
137 }
138 if !new_face_generated {
139 break;
140 }
141 }
142 }
143 if vertices.len() == 3 {
144 tri_faces.push((vertices[0], vertices[1], vertices[2]));
145 }
146 }
147 for tf in tri_faces {
148 let array = [
149 (tri_mesh.add_halfedge(), new_vertices[tf.0].unwrap()),
150 (tri_mesh.add_halfedge(), new_vertices[tf.1].unwrap()),
151 (tri_mesh.add_halfedge(), new_vertices[tf.2].unwrap()),
152 ];
153 tri_mesh.add_halfedges_and_vertices(&array);
154 }
155 tri_mesh
156 }
157}