sciimg/
matrix.rs

1use crate::{enums::Axis, error, vector::Vector};
2
3#[derive(Debug, Clone)]
4pub struct Matrix {
5    m: Vec<f64>,
6}
7
8impl Matrix {
9    pub fn default() -> Matrix {
10        Matrix {
11            m: vec![
12                0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
13            ],
14        }
15    }
16
17    pub fn identity() -> Matrix {
18        Matrix {
19            m: vec![
20                1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
21            ],
22        }
23    }
24
25    pub fn new_with_fill(f: f64) -> Matrix {
26        Matrix {
27            m: vec![f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f],
28        }
29    }
30
31    pub fn new_from_vec(m: &Vec<f64>) -> error::Result<Matrix> {
32        if m.len() == 16 {
33            Ok(Matrix { m: m.clone() })
34        } else {
35            panic!("Array size mismatch");
36        }
37    }
38
39    pub fn new_from_array(m: &[f64; 12]) -> Matrix {
40        Matrix { m: m.to_vec() }
41    }
42
43    pub fn new_with_values(
44        v00: f64,
45        v01: f64,
46        v02: f64,
47        v03: f64,
48        v10: f64,
49        v11: f64,
50        v12: f64,
51        v13: f64,
52        v20: f64,
53        v21: f64,
54        v22: f64,
55        v23: f64,
56        v30: f64,
57        v31: f64,
58        v32: f64,
59        v33: f64,
60    ) -> Matrix {
61        Matrix {
62            m: vec![
63                v00, v01, v02, v03, v10, v11, v12, v13, v20, v21, v22, v23, v30, v31, v32, v33,
64            ],
65        }
66    }
67
68    fn index(&self, x: usize, y: usize) -> usize {
69        y * 4 + x
70    }
71
72    pub fn set(&mut self, x: usize, y: usize, v: f64) {
73        let i = self.index(x, y);
74        if i < 16 {
75            self.m[i] = v;
76        } else {
77            panic!("Invalid pixel coordinates");
78        }
79    }
80
81    pub fn get(&self, x: usize, y: usize) -> f64 {
82        let i = self.index(x, y);
83        if i < 16 {
84            self.m[i]
85        } else {
86            panic!("Invalid pixel coordinates");
87        }
88    }
89
90    pub fn matmul4(a: &Matrix, b: &Matrix) -> Matrix {
91        let mut product = vec![
92            0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
93        ];
94
95        for row in 0..3 {
96            let ai0 = a.m[(0 << 2) + row];
97            let ai1 = a.m[(1 << 2) + row];
98            let ai2 = a.m[(2 << 2) + row];
99            let ai3 = a.m[(3 << 2) + row];
100
101            product[(0 << 2) + row] = ai0 * b.m[(0 << 2)]
102                + ai1 * b.m[(0 << 2) + 1]
103                + ai2 * b.m[(0 << 2) + 2]
104                + ai3 * b.m[(0 << 2) + 3];
105            product[(1 << 2) + row] = ai0 * b.m[(1 << 2)]
106                + ai1 * b.m[(1 << 2) + 1]
107                + ai2 * b.m[(1 << 2) + 2]
108                + ai3 * b.m[(1 << 2) + 3];
109            product[(2 << 2) + row] = ai0 * b.m[(2 << 2)]
110                + ai1 * b.m[(2 << 2) + 1]
111                + ai2 * b.m[(2 << 2) + 2]
112                + ai3 * b.m[(2 << 2) + 3];
113            product[(3 << 2) + row] = ai0 * b.m[(3 << 2)]
114                + ai1 * b.m[(3 << 2) + 1]
115                + ai2 * b.m[(3 << 2) + 2]
116                + ai3 * b.m[(3 << 2) + 3];
117        }
118
119        Matrix::new_from_vec(&product).unwrap()
120    }
121
122    pub fn multiply(&self, other: &Matrix) -> Matrix {
123        Matrix::matmul4(self, other)
124    }
125
126    pub fn multiply_vector(&self, other: &Vector) -> Vector {
127        let x = other.x * self.m[0] + other.y * self.m[4 + 0] + other.z * self.m[2 * 4 + 0];
128        let y = other.x * self.m[1] + other.y * self.m[4 + 1] + other.z * self.m[2 * 4 + 1];
129        let z = other.x * self.m[2] + other.y * self.m[4 + 2] + other.z * self.m[2 * 4 + 2];
130        Vector::new(x, y, z)
131    }
132
133    pub fn scale(&self, x: f64, y: f64, z: f64) -> Matrix {
134        Matrix {
135            m: vec![
136                self.m[0] * x,
137                self.m[1] * x,
138                self.m[2] * x,
139                self.m[4] * y,
140                self.m[5] * y,
141                self.m[6] * y,
142                self.m[8] * z,
143                self.m[9] * z,
144                self.m[10] * z,
145            ],
146        }
147    }
148
149    pub fn transpose_rotation(&self) -> Matrix {
150        let mut t = self.clone();
151        t.m[1] = self.m[4];
152        t.m[4] = self.m[1];
153
154        t.m[2] = self.m[8];
155        t.m[8] = self.m[2];
156
157        t.m[6] = self.m[9];
158        t.m[9] = self.m[6];
159
160        t
161    }
162
163    pub fn rotate(angle: f64, axis: Axis) -> Matrix {
164        let mut m = Matrix::identity();
165
166        let _a = if axis != Axis::YAxis {
167            angle
168        } else {
169            angle * -1.0
170        };
171
172        let c = _a.cos();
173        let s = _a.sin();
174
175        match axis {
176            Axis::XAxis => {
177                m.set(1, 1, c);
178                m.set(2, 2, c);
179                m.set(2, 1, -s);
180                m.set(1, 2, s);
181            }
182            Axis::YAxis => {
183                m.set(0, 0, c);
184                m.set(2, 2, c);
185                m.set(2, 0, s);
186                m.set(0, 2, -s);
187            }
188            Axis::ZAxis => {
189                m.set(0, 0, c);
190                m.set(1, 1, c);
191                m.set(0, 1, s);
192                m.set(1, 0, -s);
193            }
194        }
195
196        m
197    }
198}