1use crate::{
5 traits::{TotalMemory, VertexCount},
6 *,
7};
8use cgmath::{ElementWise, Vector3};
9use manifold_rs::{Manifold, Mesh};
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 Manifold::from_mesh(Mesh::new(&vertices, &triangle_indices))
111 }
112
113 pub fn volume(&self) -> f64 {
115 self.triangles()
116 .map(|t| t.signed_volume() as f64)
117 .sum::<f64>()
118 .abs()
119 }
120
121 pub fn fetch_triangle(&self, tri: Triangle<u32>) -> Triangle<&Vector3<f32>> {
123 Triangle(
124 &self.positions[tri.0 as usize],
125 &self.positions[tri.1 as usize],
126 &self.positions[tri.2 as usize],
127 )
128 }
129
130 pub fn repair(&mut self, bounds: &Bounds3D) {
132 let min: Vector3<f32> = bounds.min.cast().expect("Successful cast");
135 let inv_size: Vector3<f32> = (1.0 / (bounds.max - bounds.min))
136 .cast()
137 .expect("Successful cast");
138
139 let quantize = |pos: &Vector3<f32>| {
141 let mapped = (pos - min).mul_element_wise(inv_size) * (u32::MAX as f32);
142 (
143 mapped.x.floor() as u32,
144 mapped.y.floor() as u32,
145 mapped.z.floor() as u32,
146 )
147 };
148
149 let mut vertex_map: HashMap<(u32, u32, u32), u32> = HashMap::default();
150 let mut new_positions: Vec<Vector3<f32>> = Vec::with_capacity(self.positions.len());
151 let remap: Vec<u32> = self
152 .positions
153 .iter()
154 .map(|position| {
155 let key = quantize(position);
156 if let Some(&existing_idx) = vertex_map.get(&key) {
157 existing_idx
159 } else {
160 let new_idx = new_positions.len() as u32;
162 new_positions.push(*position);
163 vertex_map.insert(key, new_idx);
164 new_idx
165 }
166 })
167 .collect();
168
169 self.positions = new_positions;
170
171 let mut new_triangles = Vec::with_capacity(self.triangle_indices.len());
173
174 for tri in &self.triangle_indices {
175 let tri_idx = crate::Triangle(
176 remap[tri.0 as usize],
177 remap[tri.1 as usize],
178 remap[tri.2 as usize],
179 );
180
181 if tri_idx.is_degenerated() {
182 continue;
183 }
184
185 let tri = self.fetch_triangle(tri_idx);
187
188 if tri.area() < 1e-8 {
189 continue; }
191
192 new_triangles.push(tri_idx);
193 }
194
195 self.triangle_indices = new_triangles;
196 }
197}
198
199impl CalcBounds3D for TriangleMesh {
200 fn calc_bounds_3d(&self) -> Bounds3D {
201 self.positions
202 .iter()
203 .map(|positions| positions.cast::<f64>().expect("Successful cast"))
204 .collect()
205 }
206}
207
208impl From<Mesh> for TriangleMesh {
209 fn from(mesh: Mesh) -> Self {
210 let vertices = mesh.vertices();
211 let indices = mesh.indices();
212
213 TriangleMesh {
217 positions: (0..vertices.len())
218 .step_by(3)
219 .map(|i| Vector3::new(vertices[i], vertices[i + 1], vertices[i + 2]))
220 .collect(),
221 normals: None,
222 triangle_indices: (0..indices.len())
223 .step_by(3)
224 .map(|i| Triangle(indices[i], indices[i + 1], indices[i + 2]))
225 .collect(),
226 }
227 }
228}
229
230impl From<TriangleMesh> for Mesh {
231 fn from(mesh: TriangleMesh) -> Self {
232 Mesh::new(
233 &mesh
234 .positions
235 .iter()
236 .flat_map(|v| [v.x, v.y, v.z])
237 .collect::<Vec<_>>(),
238 &mesh
239 .triangle_indices
240 .iter()
241 .flat_map(|t| [t.0, t.1, t.2])
242 .collect::<Vec<_>>(),
243 )
244 }
245}
246
247impl From<Manifold> for TriangleMesh {
248 fn from(manifold: Manifold) -> Self {
249 TriangleMesh::from(manifold.to_mesh())
250 }
251}
252
253impl Transformed3D for TriangleMesh {
254 fn transformed_3d(&self, mat: &Mat4) -> Self {
255 let mat = mat.cast::<f32>().expect("Successful cast");
256 let normals = match &self.normals {
257 Some(normals) => {
258 let rot_mat = cgmath::Matrix3::from_cols(
259 mat.x.truncate(),
260 mat.y.truncate(),
261 mat.z.truncate(),
262 );
263 let normals = normals.iter().map(|n| rot_mat * n).collect();
264 Some(normals)
265 }
266 None => None,
267 };
268
269 Self {
270 positions: self
271 .positions
272 .iter()
273 .map(|v| (mat * v.extend(1.0)).truncate())
274 .collect(),
275 normals,
276 triangle_indices: self.triangle_indices.clone(),
277 }
278 }
279}
280
281impl WithBounds3D<TriangleMesh> {
282 pub fn repair(&mut self) {
284 self.update_bounds();
285 self.inner.repair(&self.bounds);
286 }
287}
288
289impl TotalMemory for TriangleMesh {
290 fn heap_memory(&self) -> usize {
291 self.positions.heap_memory()
292 + self.triangle_indices.heap_memory()
293 + match &self.normals {
294 Some(normals) => normals.heap_memory(),
295 None => 0,
296 }
297 }
298}
299
300impl VertexCount for TriangleMesh {
301 fn vertex_count(&self) -> usize {
302 self.positions.len()
303 }
304}
305
306impl From<Geometry3D> for TriangleMesh {
307 fn from(geo: Geometry3D) -> Self {
308 match geo {
309 Geometry3D::Mesh(triangle_mesh) => triangle_mesh,
310 Geometry3D::Manifold(manifold) => manifold.to_mesh().into(),
311 Geometry3D::Collection(ref collection) => collection.into(),
312 }
313 }
314}
315
316impl From<&Geometry3D> for TriangleMesh {
317 fn from(geo: &Geometry3D) -> Self {
318 match geo {
319 Geometry3D::Mesh(triangle_mesh) => triangle_mesh.clone(),
320 Geometry3D::Manifold(manifold) => manifold.to_mesh().into(),
321 Geometry3D::Collection(collection) => collection.into(),
322 }
323 }
324}
325
326impl From<&Geometries3D> for TriangleMesh {
327 fn from(geo: &Geometries3D) -> Self {
328 geo.boolean_op(&BooleanOp::Union).to_mesh().into()
329 }
330}
331
332#[test]
333fn test_triangle_mesh_transform() {
334 let mesh = TriangleMesh {
335 positions: vec![
336 cgmath::Vector3::new(0.0, 0.0, 0.0),
337 cgmath::Vector3::new(1.0, 0.0, 0.0),
338 cgmath::Vector3::new(0.0, 1.0, 0.0),
339 ],
340 normals: None,
341 triangle_indices: vec![Triangle(0, 1, 2)],
342 };
343
344 let mesh = mesh.transformed_3d(&crate::Mat4::from_translation(Vec3::new(1.0, 2.0, 3.0)));
345
346 assert_eq!(mesh.positions[0], cgmath::Vector3::new(1.0, 2.0, 3.0));
347 assert_eq!(mesh.positions[1], cgmath::Vector3::new(2.0, 2.0, 3.0));
348 assert_eq!(mesh.positions[2], cgmath::Vector3::new(1.0, 3.0, 3.0));
349}