use std::fmt::{Display, Formatter, Result};
use std::ops::{Index, IndexMut, Mul};
use crate::tuple::Tuple;
#[derive(PartialEq, Debug, Clone)]
pub struct Matrix {
data: Vec<f64>,
}
impl Matrix {
pub fn new(data: &[f64; 16]) -> Self {
return Self {
data: data.to_vec(),
};
}
pub fn eye() -> Self {
return Self::new(&[
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 translation(x: f64, y: f64, z: f64) -> Self {
Self::new(&[
1.0, 0.0, 0.0, x, 0.0, 1.0, 0.0, y, 0.0, 0.0, 1.0, z, 0.0, 0.0, 0.0, 1.0,
])
}
pub fn scaling(x: f64, y: f64, z: f64) -> Self {
Self::new(&[
x, 0.0, 0.0, 0.0, 0.0, y, 0.0, 0.0, 0.0, 0.0, z, 0.0, 0.0, 0.0, 0.0, 1.0,
])
}
pub fn rotation_x(theta: f64) -> Self {
Self::new(&[
1.0,
0.0,
0.0,
0.0,
0.0,
theta.cos(),
-theta.sin(),
0.0,
0.0,
theta.sin(),
theta.cos(),
0.0,
0.0,
0.0,
0.0,
1.0,
])
}
pub fn rotation_y(theta: f64) -> Self {
Self::new(&[
theta.cos(),
0.0,
theta.sin(),
0.0,
0.0,
1.0,
0.0,
0.0,
-theta.sin(),
0.0,
theta.cos(),
0.0,
0.0,
0.0,
0.0,
1.0,
])
}
pub fn rotation_z(theta: f64) -> Self {
Self::new(&[
theta.cos(),
-theta.sin(),
0.0,
0.0,
theta.sin(),
theta.cos(),
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
])
}
pub fn shearing(xy: f64, xz: f64, yx: f64, yz: f64, zx: f64, zy: f64) -> Self {
Self::new(&[
1.0, xy, xz, 0.0, yx, 1.0, yz, 0.0, zx, zy, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
])
}
pub fn view_transform(from: Tuple, at: Tuple, up: Tuple) -> Self {
let forward = (at - from).normalized();
let up = up.normalized();
let left = forward.cross(up);
let up = left.cross(forward);
let orientation = Self::new(&[
left.x(),
left.y(),
left.z(),
0.0,
up.x(),
up.y(),
up.z(),
0.0,
-forward.x(),
-forward.y(),
-forward.z(),
0.0,
0.0,
0.0,
0.0,
1.0,
]);
orientation * &Matrix::translation(-from.x(), -from.y(), -from.z())
}
pub fn transpose(&self) -> Self {
let mut res = Self::default();
for row in 0..=3 {
for col in 0..=3 {
res[[row, col]] = self[[col, row]];
}
}
res
}
pub fn inverse(&self) -> Self {
let mut result = Self::default();
result.data[0] = self.data[5] * self.data[10] * self.data[15]
- self.data[5] * self.data[11] * self.data[14]
- self.data[9] * self.data[6] * self.data[15]
+ self.data[9] * self.data[7] * self.data[14]
+ self.data[13] * self.data[6] * self.data[11]
- self.data[13] * self.data[7] * self.data[10];
result.data[4] = -self.data[4] * self.data[10] * self.data[15]
+ self.data[4] * self.data[11] * self.data[14]
+ self.data[8] * self.data[6] * self.data[15]
- self.data[8] * self.data[7] * self.data[14]
- self.data[12] * self.data[6] * self.data[11]
+ self.data[12] * self.data[7] * self.data[10];
result.data[8] = self.data[4] * self.data[9] * self.data[15]
- self.data[4] * self.data[11] * self.data[13]
- self.data[8] * self.data[5] * self.data[15]
+ self.data[8] * self.data[7] * self.data[13]
+ self.data[12] * self.data[5] * self.data[11]
- self.data[12] * self.data[7] * self.data[9];
result.data[12] = -self.data[4] * self.data[9] * self.data[14]
+ self.data[4] * self.data[10] * self.data[13]
+ self.data[8] * self.data[5] * self.data[14]
- self.data[8] * self.data[6] * self.data[13]
- self.data[12] * self.data[5] * self.data[10]
+ self.data[12] * self.data[6] * self.data[9];
result.data[1] = -self.data[1] * self.data[10] * self.data[15]
+ self.data[1] * self.data[11] * self.data[14]
+ self.data[9] * self.data[2] * self.data[15]
- self.data[9] * self.data[3] * self.data[14]
- self.data[13] * self.data[2] * self.data[11]
+ self.data[13] * self.data[3] * self.data[10];
result.data[5] = self.data[0] * self.data[10] * self.data[15]
- self.data[0] * self.data[11] * self.data[14]
- self.data[8] * self.data[2] * self.data[15]
+ self.data[8] * self.data[3] * self.data[14]
+ self.data[12] * self.data[2] * self.data[11]
- self.data[12] * self.data[3] * self.data[10];
result.data[9] = -self.data[0] * self.data[9] * self.data[15]
+ self.data[0] * self.data[11] * self.data[13]
+ self.data[8] * self.data[1] * self.data[15]
- self.data[8] * self.data[3] * self.data[13]
- self.data[12] * self.data[1] * self.data[11]
+ self.data[12] * self.data[3] * self.data[9];
result.data[13] = self.data[0] * self.data[9] * self.data[14]
- self.data[0] * self.data[10] * self.data[13]
- self.data[8] * self.data[1] * self.data[14]
+ self.data[8] * self.data[2] * self.data[13]
+ self.data[12] * self.data[1] * self.data[10]
- self.data[12] * self.data[2] * self.data[9];
result.data[2] = self.data[1] * self.data[6] * self.data[15]
- self.data[1] * self.data[7] * self.data[14]
- self.data[5] * self.data[2] * self.data[15]
+ self.data[5] * self.data[3] * self.data[14]
+ self.data[13] * self.data[2] * self.data[7]
- self.data[13] * self.data[3] * self.data[6];
result.data[6] = -self.data[0] * self.data[6] * self.data[15]
+ self.data[0] * self.data[7] * self.data[14]
+ self.data[4] * self.data[2] * self.data[15]
- self.data[4] * self.data[3] * self.data[14]
- self.data[12] * self.data[2] * self.data[7]
+ self.data[12] * self.data[3] * self.data[6];
result.data[10] = self.data[0] * self.data[5] * self.data[15]
- self.data[0] * self.data[7] * self.data[13]
- self.data[4] * self.data[1] * self.data[15]
+ self.data[4] * self.data[3] * self.data[13]
+ self.data[12] * self.data[1] * self.data[7]
- self.data[12] * self.data[3] * self.data[5];
result.data[14] = -self.data[0] * self.data[5] * self.data[14]
+ self.data[0] * self.data[6] * self.data[13]
+ self.data[4] * self.data[1] * self.data[14]
- self.data[4] * self.data[2] * self.data[13]
- self.data[12] * self.data[1] * self.data[6]
+ self.data[12] * self.data[2] * self.data[5];
result.data[3] = -self.data[1] * self.data[6] * self.data[11]
+ self.data[1] * self.data[7] * self.data[10]
+ self.data[5] * self.data[2] * self.data[11]
- self.data[5] * self.data[3] * self.data[10]
- self.data[9] * self.data[2] * self.data[7]
+ self.data[9] * self.data[3] * self.data[6];
result.data[7] = self.data[0] * self.data[6] * self.data[11]
- self.data[0] * self.data[7] * self.data[10]
- self.data[4] * self.data[2] * self.data[11]
+ self.data[4] * self.data[3] * self.data[10]
+ self.data[8] * self.data[2] * self.data[7]
- self.data[8] * self.data[3] * self.data[6];
result.data[11] = -self.data[0] * self.data[5] * self.data[11]
+ self.data[0] * self.data[7] * self.data[9]
+ self.data[4] * self.data[1] * self.data[11]
- self.data[4] * self.data[3] * self.data[9]
- self.data[8] * self.data[1] * self.data[7]
+ self.data[8] * self.data[3] * self.data[5];
result.data[15] = self.data[0] * self.data[5] * self.data[10]
- self.data[0] * self.data[6] * self.data[9]
- self.data[4] * self.data[1] * self.data[10]
+ self.data[4] * self.data[2] * self.data[9]
+ self.data[8] * self.data[1] * self.data[6]
- self.data[8] * self.data[2] * self.data[5];
let det = 1.0
/ (self.data[0] * result.data[0]
+ self.data[1] * result.data[4]
+ self.data[2] * result.data[8]
+ self.data[3] * result.data[12]);
for i in 0..16 {
result.data[i] *= det;
}
return result;
}
}
impl Default for Matrix {
fn default() -> Self {
Self::eye()
}
}
impl Display for Matrix {
fn fmt(&self, f: &mut Formatter) -> Result {
unsafe {
writeln!(
f,
"/{} {} {} {}\\",
self.data.get_unchecked(0),
self.data.get_unchecked(1),
self.data.get_unchecked(2),
self.data.get_unchecked(3),
)?;
writeln!(
f,
"|{} {} {} {}|",
self.data.get_unchecked(4),
self.data.get_unchecked(5),
self.data.get_unchecked(6),
self.data.get_unchecked(7),
)?;
writeln!(
f,
"|{} {} {} {}|",
self.data.get_unchecked(8),
self.data.get_unchecked(9),
self.data.get_unchecked(10),
self.data.get_unchecked(11),
)?;
write!(
f,
"\\{} {} {} {}/",
self.data.get_unchecked(12),
self.data.get_unchecked(13),
self.data.get_unchecked(14),
self.data.get_unchecked(15),
)?;
Ok(())
}
}
}
impl Index<[usize; 2]> for Matrix {
type Output = f64;
fn index(&self, index: [usize; 2]) -> &Self::Output {
if index[0] > 3 {
panic!("Row index out of bounds for matrix, got {}", index[0]);
}
if index[1] > 3 {
panic!("Column index out of bounds for matrix, got {}", index[1]);
}
unsafe { self.data.get_unchecked(index[0] * 4 + index[1]) }
}
}
impl IndexMut<[usize; 2]> for Matrix {
fn index_mut(&mut self, index: [usize; 2]) -> &mut Self::Output {
if index[0] > 3 {
panic!("Row index out of bounds for matrix, got {}", index[0]);
}
if index[1] > 3 {
panic!("Column index out of bounds for matrix, got {}", index[1]);
}
unsafe { self.data.get_unchecked_mut(index[0] * 4 + index[1]) }
}
}
impl Mul<&Self> for Matrix {
type Output = Matrix;
fn mul(self, rhs: &Self) -> Self::Output {
let mut res = Matrix::default();
for row in 0..=3 {
for col in 0..=3 {
res[[row, col]] = self[[row, 0]] * rhs[[0, col]]
+ self[[row, 1]] * rhs[[1, col]]
+ self[[row, 2]] * rhs[[2, col]]
+ self[[row, 3]] * rhs[[3, col]];
}
}
res
}
}
impl Mul<Self> for &Matrix {
type Output = Matrix;
fn mul(self, rhs: Self) -> Self::Output {
let mut res = Matrix::default();
for row in 0..=3 {
for col in 0..=3 {
res[[row, col]] = self[[row, 0]] * rhs[[0, col]]
+ self[[row, 1]] * rhs[[1, col]]
+ self[[row, 2]] * rhs[[2, col]]
+ self[[row, 3]] * rhs[[3, col]];
}
}
res
}
}
impl Mul<Tuple> for &Matrix {
type Output = Tuple;
fn mul(self, rhs: Tuple) -> Tuple {
let x = self[[0, 0]] * rhs.x()
+ self[[0, 1]] * rhs.y()
+ self[[0, 2]] * rhs.z()
+ self[[0, 3]] * rhs.w();
let y = self[[1, 0]] * rhs.x()
+ self[[1, 1]] * rhs.y()
+ self[[1, 2]] * rhs.z()
+ self[[1, 3]] * rhs.w();
let z = self[[2, 0]] * rhs.x()
+ self[[2, 1]] * rhs.y()
+ self[[2, 2]] * rhs.z()
+ self[[2, 3]] * rhs.w();
let w = self[[3, 0]] * rhs.x()
+ self[[3, 1]] * rhs.y()
+ self[[3, 2]] * rhs.z()
+ self[[3, 3]] * rhs.w();
Tuple::new(x, y, z, w)
}
}