use crate::modules::matrix3::Matrix3;
use wasm_bindgen::prelude::*;
use serde::{Serialize, Deserialize};
#[wasm_bindgen]
#[derive(Clone, Serialize, Deserialize)]
pub struct Matrix4 {
elements: Vec<f64>,
}
#[wasm_bindgen]
impl Matrix4 {
#[wasm_bindgen(getter)]
pub fn elements(&self) -> Vec<f64> {
self.elements.clone()
}
#[wasm_bindgen(constructor)]
pub fn new() -> Matrix4 {
Matrix4 {
elements: vec![
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,
],
}
}
pub fn set(
m0: f64, m1: f64, m2: f64, m3: f64,
m4: f64, m5: f64, m6: f64, m7: f64,
m8: f64, m9: f64, m10: f64, m11: f64,
m12: f64, m13: f64, m14: f64, m15: f64,
) -> Matrix4 {
let mut column_major_elements: Vec<f64> = vec![0.0; 16];
column_major_elements[0] = m0; column_major_elements[4] = m1; column_major_elements[8] = m2; column_major_elements[12] = m3;
column_major_elements[1] = m4; column_major_elements[5] = m5; column_major_elements[9] = m6; column_major_elements[13] = m7;
column_major_elements[2] = m8; column_major_elements[6] = m9; column_major_elements[10] = m10; column_major_elements[14] = m11;
column_major_elements[3] = m12; column_major_elements[7] = m13; column_major_elements[11] = m14; column_major_elements[15] = m15;
Matrix4 {
elements: column_major_elements,
}
}
pub fn clone(&self) -> Matrix4 {
Matrix4 {
elements: self.elements.clone(),
}
}
pub fn identity(&mut self) {
self.elements = vec![
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,
];
}
pub fn determinant(&self) -> f64 {
let mut det = 0.0;
for i in 0..4 {
let mut minor = [[0.0; 3]; 3];
for j in 1..4 {
for k in 0..4 {
if k < i {
minor[j - 1][k] = self.elements[j * 4 + k];
} else if k > i {
minor[j - 1][k - 1] = self.elements[j * 4 + k];
}
}
}
let minor_vec: Vec<f64> = minor.iter().flat_map(|row| row.iter()).cloned().collect();
let mut minor_matrix = Matrix3::new();
minor_matrix.set(
minor_vec[0], minor_vec[1], minor_vec[2],
minor_vec[3], minor_vec[4], minor_vec[5],
minor_vec[6], minor_vec[7], minor_vec[8],
);
det += if i % 2 == 0 { self.elements[i] } else { -self.elements[i] } * minor_matrix.determinant();
}
det
}
pub fn adjucate(&self) -> Matrix4 {
let mut adj = Matrix4::new();
for i in 0..4 {
for j in 0..4 {
let mut sub_matrix = [[0.0; 3]; 3];
for m in 0..4 {
for n in 0..4 {
if m != i && n != j {
let sub_i = if m < i { m } else { m - 1 };
let sub_j = if n < j { n } else { n - 1 };
sub_matrix[sub_i][sub_j] = self.elements[m * 4 + n];
}
}
}
let mut sub_matrix3 = Matrix3::new();
let sub_matrix_vec: Vec<f64> = sub_matrix.iter().flat_map(|row| row.iter()).cloned().collect();
sub_matrix3.set(
sub_matrix_vec[0], sub_matrix_vec[1], sub_matrix_vec[2],
sub_matrix_vec[3], sub_matrix_vec[4], sub_matrix_vec[5],
sub_matrix_vec[6], sub_matrix_vec[7], sub_matrix_vec[8],
);
adj.elements[i * 4 + j] = if (i + j) % 2 == 0 { 1.0 } else { -1.0 } * sub_matrix3.determinant();
}
}
adj
}
pub fn inverse(&self) -> Matrix4 {
let det = self.determinant();
if det == 0.0 {
return Matrix4::new();
}
let adj = self.adjucate();
let mut inv = Matrix4::new();
for i in 0..16 {
inv.elements[i] = adj.elements[i] / det;
}
inv
}
pub fn multiply(&self, other: &Matrix4) -> Matrix4 {
let mut result = vec![0.0; 16];
for i in 0..4 {
for j in 0..4 {
result[i * 4 + j] =
self.elements[i * 4 + 0] * other.elements[0 * 4 + j] +
self.elements[i * 4 + 1] * other.elements[1 * 4 + j] +
self.elements[i * 4 + 2] * other.elements[2 * 4 + j] +
self.elements[i * 4 + 3] * other.elements[3 * 4 + j];
}
}
Matrix4 { elements: result }
}
pub fn add(&self, incoming: &Matrix4) -> Matrix4 {
let mut result = vec![0.0; 16];
for i in 0..4 {
for j in 0..4 {
result[i * 4 + j] = self.elements[i * 4 + j] + incoming.elements[i * 4 + j];
}
}
Matrix4 { elements: result }
}
pub fn subtract(&self, incoming: &Matrix4) -> Matrix4 {
let mut result = vec![0.0; 16];
for i in 0..4 {
for j in 0..4 {
result[i * 4 + j] = self.elements[i * 4 + j] - incoming.elements[i * 4 + j];
}
}
Matrix4 { elements: result }
}
pub fn flatten(&self) -> Vec<f64> {
self.elements.clone()
}
pub fn get_element_at(&self, index: usize) -> Option<f64> {
let flat = self.flatten();
if index < flat.len() {
Some(flat[index])
} else {
None
}
}
pub fn is_zero(&self) -> bool {
self.elements.iter().all(|&x| x == 0.0)
}
pub fn is_identity(&self) -> bool {
self.elements == vec![
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,
]
}
pub fn transpose(&self) -> Matrix4 {
let mut transposed = vec![0.0; 16];
for i in 0..4 {
for j in 0..4 {
transposed[j * 4 + i] = self.elements[i * 4 + j];
}
}
Matrix4 { elements: transposed }
}
}