dzahui/mesh/
mod.rs

1// Module declaration
2pub(crate) mod mesh_builder;
3
4// External dependencies
5use cgmath::Matrix4;
6use ndarray::Array1;
7use num::ToPrimitive;
8
9// Internal dependencies
10use crate::{
11    simulation::drawable::binder::{Binder, Bindable, Drawable},
12    Error,
13};
14use mesh_builder::MeshBuilder;
15
16/// # General Information
17///
18/// Representation of a plane figure / 3d body. Contains information to draw to screen and move/rotate mesh representation to final position.
19///
20/// # Fields
21///
22/// * `max_length` - Maximum length of figure. Used to center camera arround objective.
23/// * `model_matrix` - Translates and rotates object to final world position.
24/// * `binder` - vao, vbo and ebo variables bound to mesh drawable in GPU.
25/// * `indices` - Indices that map to vertices. Normally used in triads. Specified in gl configuration.
26/// * `vertices` -  Vertices in 3d space. Normally used in sextuples (coordinate and color). Specified in gl configuration.
27///
28#[allow(dead_code)]
29#[derive(Debug)]
30pub(crate) struct Mesh {
31    pub(crate) max_length: f64,
32    pub(crate) model_matrix: Matrix4<f32>,
33    pub(crate) boundary_indices: Option<Vec<u32>>,
34    binder: Binder,
35    pub(crate) indices: Array1<u32>,
36    pub(crate) vertices: Array1<f64>,
37}
38
39impl Mesh {
40    /// Getter for model_matrix
41    pub fn get_model_matrix(&self) -> &Matrix4<f32> {
42        &self.model_matrix
43    }
44
45    /// Creates new instance of builder
46    pub fn builder<B>(location: B) -> MeshBuilder
47    where
48        B: AsRef<str>,
49    {
50        MeshBuilder::new(location)
51    }
52
53    /// Filtering vertices to give to 1d solver. Temporal function. To be changed for better solution.
54    pub(crate) fn filter_for_solving_1d(&self) -> Array1<f64> {
55        // size of vertex is 6. There are double the vertices in 1d since a new pair is generated to draw a bar, therefore len is divided by 12.
56        let vertices_len = self.vertices.len() / 12;
57        self.vertices
58            .iter()
59            .enumerate()
60            .filter_map(|(idx, x)| {
61                if idx % 6 == 0 && idx < vertices_len * 6 {
62                    Some(*x)
63                } else {
64                    None
65                }
66            })
67            .collect()
68    }
69
70    /// Improvable solution to move gradient updating out of dzahui window. Probably will be changed in the future.
71    /// Obtains max and min of solution (normallly some sort of rate of change), divides every element by the difference and then multiplies them by
72    /// pi/2 so that, when calculating their sine and cosine, there's a mapping between max velocity <-> red and min velocity <-> blue
73    pub(crate) fn update_gradient_1d(&mut self, velocity_norm: Vec<f64>) {
74        let sol_max = velocity_norm
75            .iter()
76            .copied()
77            .fold(f64::NEG_INFINITY, f64::max);
78
79        let sol_min = velocity_norm.iter().copied().fold(f64::INFINITY, f64::min);
80        let vertices_len = self.vertices.len();
81        
82        for i in 0..(vertices_len / 12) {
83            let norm_sol =
84                (velocity_norm[i] - sol_min) / (sol_max - sol_min) * (std::f64::consts::PI / 2.);
85            self.vertices[6 * i + 3] = norm_sol.sin();
86            self.vertices[6 * i + 5] = norm_sol.cos();
87            self.vertices[6 * i + 3 + vertices_len / 2] = norm_sol.sin();
88            self.vertices[6 * i + 5 + vertices_len / 2] = norm_sol.cos();
89        }
90    }
91}
92
93impl Bindable for Mesh {
94    fn get_binder(&self) -> Result<&Binder, Error> {
95        Ok(&self.binder)
96    }
97
98    fn get_mut_binder(&mut self) -> Result<&mut Binder, Error> {
99        Ok(&mut self.binder)
100    }
101}
102
103impl Drawable for Mesh {
104    fn get_indices(&self) -> Result<&Array1<u32>, Error> {
105        Ok(&self.indices)
106    }
107
108    fn get_vertices(&self) -> Result<Array1<f32>, Error> {
109        Ok(Array1::from_vec(
110            self.vertices.iter().map(|x| -> Result<f32,Error> { x.to_f32().ok_or(Error::FloatConversion) })
111            .collect::<Result<Vec<f32>,_>>()?
112        ))
113    }
114
115    fn get_max_length(&self) -> Result<f32, Error> {
116        let max_len = self.max_length.to_f32();
117
118        match max_len {
119            Some(f) => {
120                if f.is_finite() {
121                    Ok(f)
122                } else {
123                    Err(Error::Overflow)
124                }
125            }
126            None => Err(Error::Unimplemented),
127        }
128    }
129}
130
131#[cfg(test)]
132mod test {
133    use super::Mesh;
134    use ndarray::Array1;
135
136    #[test]
137    fn parse_coordinates() {
138        let new_mesh = Mesh::builder("/home/Arthur/Tesis/Dzahui/assets/test.obj")
139            .build_mesh_3d()
140            .unwrap();
141        assert!(
142            new_mesh.vertices
143                == Array1::from_vec(vec![
144                    -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0,
145                    0.0, 0.0, 1.0
146                ])
147        );
148        assert!(new_mesh.indices == Array1::from_vec(vec![0, 1, 2]));
149    }
150
151    #[test]
152    fn is_max_distance() {
153        let new_mesh = Mesh::builder("/home/Arthur/Tesis/Dzahui/assets/test.obj")
154            .build_mesh_2d()
155            .unwrap();
156        assert!(new_mesh.max_length >= 1.90);
157        assert!(new_mesh.max_length <= 2.10);
158    }
159}