Skip to main content

drew_sim/
mesh.rs

1//! Maillages triangulaires : stockage, primitives, chargement STL.
2
3use crate::math::Vec3;
4use std::path::Path;
5
6/// Erreurs pouvant survenir lors du chargement d'un maillage.
7#[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/// Maillage 3D : liste de sommets et de triangles (indices dans `vertices`).
31#[derive(Clone, Debug, Default)]
32pub struct Mesh3D {
33    pub vertices: Vec<Vec3>,
34    pub triangles: Vec<[usize; 3]>,
35}
36
37impl Mesh3D {
38    /// Construit un maillage vide.
39    pub fn new() -> Self {
40        Self::default()
41    }
42
43    /// Construit un maillage à partir de sommets et de triangles bruts.
44    ///
45    /// Retourne une erreur si un triangle référence un index hors bornes.
46    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    /// Charge dynamiquement un modèle depuis un fichier `.stl` (binaire ou ASCII).
59    #[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    /// Un cube unité centré à l'origine (arête de longueur `size`), utile pour
71    /// les tests et les exemples sans dépendre d'un fichier STL.
72    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], // arrière
80            [4, 6, 5], [4, 7, 6], // avant
81            [0, 4, 5], [0, 5, 1], // dessous
82            [3, 2, 6], [3, 6, 7], // dessus
83            [0, 3, 7], [0, 7, 4], // gauche
84            [1, 5, 6], [1, 6, 2], // droite
85        ];
86        Self { vertices, triangles }
87    }
88
89    pub fn triangle_count(&self) -> usize {
90        self.triangles.len()
91    }
92}