1use crate::*;
5use cgmath::{ElementWise, Vector3};
6use manifold_rs::{Manifold, Mesh};
7
8#[derive(Default, Clone)]
10pub struct TriangleMesh {
11 pub positions: Vec<Vector3<f32>>,
13 pub normals: Option<Vec<Vector3<f32>>>,
15 pub triangle_indices: Vec<Triangle<u32>>,
17}
18pub struct Triangles<'a> {
20 triangle_mesh: &'a TriangleMesh,
21 index: usize,
22}
23
24impl<'a> Iterator for Triangles<'a> {
25 type Item = Triangle<&'a Vector3<f32>>;
26
27 fn next(&mut self) -> Option<Self::Item> {
28 if self.index < self.triangle_mesh.triangle_indices.len() {
29 let t = self.triangle_mesh.triangle_indices[self.index];
30 self.index += 1;
31 Some(Triangle(
32 &self.triangle_mesh.positions[t.0 as usize],
33 &self.triangle_mesh.positions[t.1 as usize],
34 &self.triangle_mesh.positions[t.2 as usize],
35 ))
36 } else {
37 None
38 }
39 }
40}
41
42impl TriangleMesh {
43 pub fn is_empty(&self) -> bool {
45 self.positions.is_empty() || self.triangle_indices.is_empty()
46 }
47
48 pub fn clear(&mut self) {
50 self.positions.clear();
51 self.triangle_indices.clear();
52 }
53
54 pub fn fetch_triangles(&self) -> Vec<Triangle<Vector3<f32>>> {
56 self.triangle_indices
57 .iter()
58 .map(|t| {
59 Triangle(
60 self.positions[t.0 as usize],
61 self.positions[t.1 as usize],
62 self.positions[t.2 as usize],
63 )
64 })
65 .collect()
66 }
67
68 pub fn append(&mut self, other: &TriangleMesh) {
70 let offset = self.positions.len() as u32;
71 self.positions.append(&mut other.positions.clone());
72 self.triangle_indices.extend(
73 other
74 .triangle_indices
75 .iter()
76 .map(|t| Triangle(t.0 + offset, t.1 + offset, t.2 + offset)),
77 )
78 }
79
80 pub fn triangles(&'_ self) -> Triangles<'_> {
82 Triangles {
83 triangle_mesh: self,
84 index: 0,
85 }
86 }
87
88 pub fn to_manifold(&self) -> Manifold {
90 let vertices = self
91 .positions
92 .iter()
93 .flat_map(|v| vec![v.x, v.y, v.z])
94 .collect::<Vec<_>>();
95
96 let triangle_indices = self
97 .triangle_indices
98 .iter()
99 .flat_map(|t| vec![t.0, t.1, t.2])
100 .collect::<Vec<_>>();
101
102 assert_eq!(vertices.len(), self.positions.len() * 3);
103 assert_eq!(triangle_indices.len(), self.triangle_indices.len() * 3);
104
105 Manifold::from_mesh(Mesh::new(&vertices, &triangle_indices))
106 }
107
108 pub fn volume(&self) -> f64 {
110 self.triangles()
111 .map(|t| t.signed_volume() as f64)
112 .sum::<f64>()
113 .abs()
114 }
115
116 pub fn fetch_triangle(&self, tri: Triangle<u32>) -> Triangle<&Vector3<f32>> {
118 Triangle(
119 &self.positions[tri.0 as usize],
120 &self.positions[tri.1 as usize],
121 &self.positions[tri.2 as usize],
122 )
123 }
124
125 pub fn repair(&mut self, bounds: &Bounds3D) {
127 let min: Vector3<f32> = bounds.min.cast().expect("Successful cast");
130 let inv_size: Vector3<f32> = (1.0 / (bounds.max - bounds.min))
131 .cast()
132 .expect("Successful cast");
133
134 let quantize = |pos: &Vector3<f32>| {
136 let mapped = (pos - min).mul_element_wise(inv_size) * (u32::MAX as f32);
137 (
138 mapped.x.floor() as u32,
139 mapped.y.floor() as u32,
140 mapped.z.floor() as u32,
141 )
142 };
143
144 let mut vertex_map: std::collections::HashMap<(u32, u32, u32), u32> =
145 std::collections::HashMap::new();
146 let mut new_positions: Vec<Vector3<f32>> = Vec::with_capacity(self.positions.len());
147 let mut remap: Vec<u32> = vec![0; self.positions.len()];
148
149 for (i, position) in self.positions.iter().enumerate() {
150 let key = quantize(position);
151 if let Some(&existing_idx) = vertex_map.get(&key) {
152 remap[i] = existing_idx;
154 } else {
155 let new_idx = new_positions.len() as u32;
157 new_positions.push(*position);
158 vertex_map.insert(key, new_idx);
159 remap[i] = new_idx;
160 }
161 }
162
163 self.positions = new_positions;
164
165 let mut new_triangles = Vec::with_capacity(self.triangle_indices.len());
167
168 for tri in &self.triangle_indices {
169 let tri_idx = crate::Triangle(
170 remap[tri.0 as usize],
171 remap[tri.1 as usize],
172 remap[tri.2 as usize],
173 );
174
175 if tri_idx.is_degenerated() {
176 continue;
177 }
178
179 let tri = self.fetch_triangle(tri_idx);
181
182 if tri.area() < 1e-8 {
183 continue; }
185
186 new_triangles.push(tri_idx);
187 }
188
189 self.triangle_indices = new_triangles;
190 }
191}
192
193impl CalcBounds3D for TriangleMesh {
194 fn calc_bounds_3d(&self) -> Bounds3D {
195 self.positions
196 .iter()
197 .map(|positions| positions.cast::<f64>().expect("Successful cast"))
198 .collect()
199 }
200}
201
202impl From<Mesh> for TriangleMesh {
203 fn from(mesh: Mesh) -> Self {
204 let vertices = mesh.vertices();
205 let indices = mesh.indices();
206
207 TriangleMesh {
211 positions: (0..vertices.len())
212 .step_by(3)
213 .map(|i| Vector3::new(vertices[i], vertices[i + 1], vertices[i + 2]))
214 .collect(),
215 normals: None,
216 triangle_indices: (0..indices.len())
217 .step_by(3)
218 .map(|i| Triangle(indices[i], indices[i + 1], indices[i + 2]))
219 .collect(),
220 }
221 }
222}
223
224impl From<TriangleMesh> for Mesh {
225 fn from(mesh: TriangleMesh) -> Self {
226 let mut vertices = Vec::new();
227 let mut indices = Vec::new();
228
229 for v in &mesh.positions {
230 vertices.push(v.x);
231 vertices.push(v.y);
232 vertices.push(v.z);
233 }
234
235 for t in &mesh.triangle_indices {
236 indices.push(t.0);
237 indices.push(t.1);
238 indices.push(t.2);
239 }
240
241 Mesh::new(vertices.as_slice(), indices.as_slice())
242 }
243}
244
245impl From<Manifold> for TriangleMesh {
246 fn from(manifold: Manifold) -> Self {
247 TriangleMesh::from(manifold.to_mesh())
248 }
249}
250
251impl Transformed3D for TriangleMesh {
252 fn transformed_3d(&self, mat: &Mat4) -> Self {
253 let mat = mat.cast::<f32>().expect("Successful cast");
254 let normals = match &self.normals {
255 Some(normals) => {
256 let rot_mat = cgmath::Matrix3::from_cols(
257 mat.x.truncate(),
258 mat.y.truncate(),
259 mat.z.truncate(),
260 );
261 let normals = normals.iter().map(|n| rot_mat * n).collect();
262 Some(normals)
263 }
264 None => None,
265 };
266
267 Self {
268 positions: self
269 .positions
270 .iter()
271 .map(|v| (mat * v.extend(1.0)).truncate())
272 .collect(),
273 normals,
274 triangle_indices: self.triangle_indices.clone(),
275 }
276 }
277}
278
279impl WithBounds3D<TriangleMesh> {
280 pub fn repair(&mut self) {
282 self.update_bounds();
283 self.inner.repair(&self.bounds);
284 }
285}
286
287impl From<Geometry3D> for TriangleMesh {
288 fn from(geo: Geometry3D) -> Self {
289 match geo {
290 Geometry3D::Mesh(triangle_mesh) => triangle_mesh,
291 Geometry3D::Manifold(manifold) => manifold.to_mesh().into(),
292 Geometry3D::Collection(ref collection) => collection.into(),
293 }
294 }
295}
296
297impl From<&Geometries3D> for TriangleMesh {
298 fn from(geo: &Geometries3D) -> Self {
299 let mut mesh = TriangleMesh::default();
300 geo.iter()
301 .for_each(|geo| mesh.append(&geo.as_ref().clone().into()));
302 mesh
303 }
304}
305
306#[test]
307fn test_triangle_mesh_transform() {
308 let mesh = TriangleMesh {
309 positions: vec![
310 cgmath::Vector3::new(0.0, 0.0, 0.0),
311 cgmath::Vector3::new(1.0, 0.0, 0.0),
312 cgmath::Vector3::new(0.0, 1.0, 0.0),
313 ],
314 normals: None,
315 triangle_indices: vec![Triangle(0, 1, 2)],
316 };
317
318 let mesh = mesh.transformed_3d(&crate::Mat4::from_translation(Vec3::new(1.0, 2.0, 3.0)));
319
320 assert_eq!(mesh.positions[0], cgmath::Vector3::new(1.0, 2.0, 3.0));
321 assert_eq!(mesh.positions[1], cgmath::Vector3::new(2.0, 2.0, 3.0));
322 assert_eq!(mesh.positions[2], cgmath::Vector3::new(1.0, 3.0, 3.0));
323}