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