1use crate::math::Vec3;
4use std::path::Path;
5
6#[derive(Debug)]
8pub enum MeshError {
9 Io(std::io::Error),
10 Parse(String),
11}
12
13impl std::fmt::Display for MeshError {
14 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15 match self {
16 MeshError::Io(e) => write!(f, "erreur d'entrée/sortie: {e}"),
17 MeshError::Parse(e) => write!(f, "erreur de lecture du maillage: {e}"),
18 }
19 }
20}
21
22impl std::error::Error for MeshError {}
23
24impl From<std::io::Error> for MeshError {
25 fn from(e: std::io::Error) -> Self {
26 MeshError::Io(e)
27 }
28}
29
30#[derive(Clone, Debug, Default)]
32pub struct Mesh3D {
33 pub vertices: Vec<Vec3>,
34 pub triangles: Vec<[usize; 3]>,
35}
36
37impl Mesh3D {
38 pub fn new() -> Self {
40 Self::default()
41 }
42
43 pub fn from_raw(vertices: Vec<Vec3>, triangles: Vec<[usize; 3]>) -> Result<Self, MeshError> {
47 let n = vertices.len();
48 for tri in &triangles {
49 if tri.iter().any(|&i| i >= n) {
50 return Err(MeshError::Parse(format!(
51 "index de triangle hors bornes: {tri:?} (n_vertices={n})"
52 )));
53 }
54 }
55 Ok(Self { vertices, triangles })
56 }
57
58 #[cfg(feature = "stl")]
60 pub fn from_stl_file<P: AsRef<Path>>(path: P) -> Result<Self, MeshError> {
61 let mut file = std::fs::File::open(path)?;
62 let stl = stl_io::read_stl(&mut file).map_err(|e| MeshError::Parse(e.to_string()))?;
63
64 let vertices = stl.vertices.iter().map(|v| [v[0], v[1], v[2]]).collect();
65 let triangles = stl.faces.iter().map(|f| f.vertices).collect();
66
67 Ok(Self { vertices, triangles })
68 }
69
70 pub fn unit_cube(size: f32) -> Self {
73 let h = size * 0.5;
74 let vertices = vec![
75 [-h, -h, -h], [h, -h, -h], [h, h, -h], [-h, h, -h],
76 [-h, -h, h], [h, -h, h], [h, h, h], [-h, h, h],
77 ];
78 let triangles = vec![
79 [0, 1, 2], [0, 2, 3], [4, 6, 5], [4, 7, 6], [0, 4, 5], [0, 5, 1], [3, 2, 6], [3, 6, 7], [0, 3, 7], [0, 7, 4], [1, 5, 6], [1, 6, 2], ];
86 Self { vertices, triangles }
87 }
88
89 pub fn triangle_count(&self) -> usize {
90 self.triangles.len()
91 }
92}