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