Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use crate::{eq, tuple::Tuple};
- #[derive(Debug, Clone)]
- pub struct Matrix {
- pub size: usize,
- pub data: Box<[f32]>,
- }
- impl Matrix {
- pub fn new(size: usize, data: Box<[f32]>) -> Matrix {
- Matrix {
- size,
- data,
- }
- }
- pub fn new_2x2(data: [f32; 4]) -> Matrix {
- Matrix {
- size: 2,
- data: Box::new(data),
- }
- }
- pub fn new_3x3(data: [f32; 9]) -> Matrix {
- Matrix {
- size: 3,
- data: Box::new(data),
- }
- }
- pub fn new_4x4(data: [f32; 16]) -> Matrix {
- Matrix {
- size: 4,
- data: Box::new(data),
- }
- }
- pub fn new_4x4_zeroed() -> Matrix {
- Matrix {
- size: 4,
- data: Box::new([
- 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,
- ]),
- }
- }
- pub fn new_3x3_zeroed() -> Matrix {
- Matrix {
- size: 3,
- data: Box::new([
- 0.0, 0.0, 0.0,
- 0.0, 0.0, 0.0,
- 0.0, 0.0, 0.0,
- ]),
- }
- }
- pub fn new_2x2_zeroed() -> Matrix {
- Matrix {
- size: 2,
- data: Box::new([
- 0.0, 0.0,
- 0.0, 0.0,
- ]),
- }
- }
- pub fn new_4x4_identity_matrix() -> Matrix {
- Matrix {
- size: 4,
- data: Box::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,
- ]),
- }
- }
- fn mul(&self, other: &Matrix) -> Matrix {
- let mut answer = Matrix::new_4x4_zeroed();
- for row_start in (0..16).step_by(4) {
- for column in 0..4 {
- let answer_index = row_start + column;
- answer.data[answer_index] += self.data[row_start + 0] * other.data[0 + column];
- answer.data[answer_index] += self.data[row_start + 1] * other.data[4 + column];
- answer.data[answer_index] += self.data[row_start + 2] * other.data[8 + column];
- answer.data[answer_index] += self.data[row_start + 3] * other.data[12 + column];
- }
- }
- answer
- }
- fn mul_tuple(&self, tuple: Tuple) -> Tuple {
- Tuple {
- x: self.data[ 0] * tuple.x + self.data[ 1] * tuple.y + self.data[ 2] * tuple.z + self.data[ 3] * tuple.w,
- y: self.data[ 4] * tuple.x + self.data[ 5] * tuple.y + self.data[ 6] * tuple.z + self.data[ 7] * tuple.w,
- z: self.data[ 8] * tuple.x + self.data[ 9] * tuple.y + self.data[10] * tuple.z + self.data[11] * tuple.w,
- w: self.data[12] * tuple.x + self.data[13] * tuple.y + self.data[14] * tuple.z + self.data[15] * tuple.w,
- }
- }
- fn transpose(&self) -> Matrix {
- let mut answer = self.clone();
- let mut src_index = 0;
- for row in 0..self.size {
- for column in 0..self.size {
- answer.data[src_index] = self.data[column * self.size + row];
- src_index += 1;
- }
- }
- answer
- }
- fn det(&self) -> f32 {
- match self.size {
- 2 => self.data[0] * self.data[3] - self.data[1] * self.data[2],
- 3 => self.data[0] * self.cofac(0, 0) +
- self.data[1] * self.cofac(0, 1) +
- self.data[2] * self.cofac(0, 2),
- 4 => self.data[0] * self.cofac(0, 0) +
- self.data[1] * self.cofac(0, 1) +
- self.data[2] * self.cofac(0, 2) +
- self.data[3] * self.cofac(0, 3),
- _ => panic!(),
- }
- }
- fn sub(&self, row: usize, column: usize) -> Matrix {
- let mut answer = match self.size {
- 4 => Matrix::new_3x3_zeroed(),
- 3 => Matrix::new_2x2_zeroed(),
- _ => panic!("Unsupported matrix size"),
- };
- let mut src_index = 0;
- let mut dest_index = 0;
- for src_row in 0..self.size {
- for src_column in 0..self.size {
- if src_row != row && src_column != column {
- answer.data[dest_index] = self.data[src_index];
- dest_index += 1;
- }
- src_index += 1;
- }
- }
- answer
- }
- fn minor(&self, row: usize, column: usize) -> f32 {
- self.sub(row, column).det()
- }
- fn cofac(&self, row: usize, column: usize) -> f32 {
- let min = self.minor(row, column);
- if row % 2 == 0 {
- if column % 2 == 0 {
- min
- } else {
- -min
- }
- } else {
- if column % 2 == 0 {
- -min
- } else {
- min
- }
- }
- }
- fn inv(&self) -> Option<Matrix> {
- let mut answer = match self.size {
- 4 => Matrix::new_4x4_zeroed(),
- 3 => Matrix::new_3x3_zeroed(),
- 2 => Matrix::new_2x2_zeroed(),
- _ => panic!(),
- };
- let det = self.det();
- if det == 0.0 {
- return None;
- }
- let mut index = 0;
- for row in 0..self.size {
- for column in 0..self.size {
- answer.data[index] = self.cofac(row, column) / det;
- index += 1;
- }
- }
- Some(answer.transpose())
- }
- }
- impl PartialEq for Matrix {
- fn eq(&self, other: &Matrix) -> bool {
- if self.size == other.size && self.size == other.size {
- for (index, value) in self.data.iter().enumerate() {
- if !eq!(value, other.data[index]) {
- return false;
- }
- }
- true
- } else {
- false
- }
- }
- }
- #[cfg(test)]
- mod tests {
- use super::*;
- #[test]
- fn equality() {
- let a = Matrix::new_4x4([
- 1.0, 2.0, 3.0, 4.0,
- 5.5, 6.5, 7.5, 8.5,
- 9.0, 10.0, 11.0, 12.0,
- 13.5, 14.5, 15.5, 16.0,
- ]);
- let mut b = a.clone();
- assert_eq!(a, b);
- b.data[0] = 2.0;
- assert_ne!(a, b);
- b.data[0] = 1.000001;
- assert_eq!(a, b);
- }
- #[test]
- fn create_2x2() {
- let a = Matrix::new_2x2([
- -3.0, 5.0,
- 1.0, -2.0,
- ]);
- let mut b = a.clone();
- assert_eq!(a, b);
- b.data[3] = 1.0;
- assert_ne!(a, b);
- }
- #[test]
- fn create_3x3() {
- let a = Matrix::new_3x3([
- -3.0, 5.0, 0.0,
- 1.0, -2.0, -7.0,
- 0.0, 1.0, 1.0,
- ]);
- let mut b = a.clone();
- assert_eq!(a, b);
- b.data[3] = 1.0;
- assert_eq!(a, b);
- }
- #[test]
- fn mul_4x4() {
- let a = Matrix::new_4x4([
- 1.0, 2.0, 3.0, 4.0,
- 5.0, 6.0, 7.0, 8.0,
- 9.0, 8.0, 7.0, 6.0,
- 5.0, 4.0, 3.0, 2.0,
- ]);
- let b = Matrix::new_4x4([
- -2.0, 1.0, 2.0, 3.0,
- 3.0, 2.0, 1.0, -1.0,
- 4.0, 3.0, 6.0, 5.0,
- 1.0, 2.0, 7.0, 8.0,
- ]);
- let c = Matrix::new_4x4([
- 20.0, 22.0, 50.0, 48.0,
- 44.0, 54.0, 114.0, 108.0,
- 40.0, 58.0, 110.0, 102.0,
- 16.0, 26.0, 46.0, 42.0,
- ]);
- assert_eq!(a.mul(&b), c);
- }
- #[test]
- fn mul_by_identity_matrix() {
- let a = Matrix::new_4x4([
- 1.0, 2.0, 3.0, 4.0,
- 5.0, 6.0, 7.0, 8.0,
- 9.0, 8.0, 7.0, 6.0,
- 5.0, 4.0, 3.0, 2.0,
- ]);
- let b = Matrix::new_4x4_identity_matrix();
- let c = a.clone();
- assert_eq!(a.mul(&b), c);
- }
- #[test]
- fn mul_tuple() {
- let a = Matrix::new_4x4([
- 1.0, 2.0, 3.0, 4.0,
- 2.0, 4.0, 4.0, 2.0,
- 8.0, 6.0, 4.0, 1.0,
- 0.0, 0.0, 0.0, 1.0,
- ]);
- let b = Tuple {x: 1.0, y: 2.0, z: 3.0, w: 1.0};
- let c = Tuple {x: 18.0, y: 24.0, z: 33.0, w: 1.0};
- assert_eq!(a.mul_tuple(b), c);
- }
- #[test]
- fn transpose() {
- let a = Matrix::new_4x4([
- 0.0, 9.0, 3.0, 0.0,
- 9.0, 8.0, 0.0, 8.0,
- 1.0, 8.0, 5.0, 3.0,
- 0.0, 0.0, 5.0, 8.0,
- ]);
- let b = Matrix::new_4x4([
- 0.0, 9.0, 1.0, 0.0,
- 9.0, 8.0, 8.0, 0.0,
- 3.0, 0.0, 5.0, 5.0,
- 0.0, 8.0, 3.0, 8.0,
- ]);
- assert_eq!(a.transpose(), b);
- }
- #[test]
- fn determinant() {
- let a = Matrix::new_2x2([
- 1.0, 5.0,
- -3.0, 2.0,
- ]);
- assert_eq!(a.det(), 17.0);
- }
- #[test]
- fn sub_3x3() {
- let a = Matrix::new_3x3([
- 1.0, 5.0, 0.0,
- -3.0, 2.0, 7.0,
- 0.0, 6.0, -2.0,
- ]);
- let b = Matrix::new_2x2([
- -3.0, 2.0,
- 0.0, 6.0,
- ]);
- assert_eq!(a.sub(0, 2), b);
- }
- #[test]
- fn sub_4x4() {
- let a = Matrix::new_4x4([
- -6.0, 1.0, 1.0, 6.0,
- -8.0, 5.0, 8.0, 6.0,
- -1.0, 0.0, 8.0, 2.0,
- -7.0, 1.0, -1.0, 1.0,
- ]);
- let b = Matrix::new_3x3([
- -6.0, 1.0, 6.0,
- -8.0, 8.0, 6.0,
- -7.0, -1.0, 1.0,
- ]);
- assert_eq!(a.sub(2, 1), b);
- }
- #[test]
- fn minor_3x3() {
- let a = Matrix::new_3x3([
- 3.0, 5.0, 0.0,
- 2.0, -1.0, -7.0,
- 6.0, -1.0, 5.0,
- ]);
- assert_eq!(a.minor(1, 0), 25.0);
- }
- #[test]
- fn cofactor() {
- let a = Matrix::new_3x3([
- 3.0, 5.0, 0.0,
- 2.0, -1.0, -7.0,
- 6.0, -1.0, 5.0,
- ]);
- assert_eq!(a.cofac(0, 0), -12.0);
- assert_eq!(a.cofac(1, 0), -25.0);
- }
- #[test]
- fn determinant_3x3() {
- let a = Matrix::new_3x3([
- 1.0, 2.0, 6.0,
- -5.0, 8.0, -4.0,
- 2.0, 6.0, 4.0,
- ]);
- assert_eq!(a.det(), -196.0);
- }
- #[test]
- fn determinant_4x4() {
- let a = Matrix::new_4x4([
- -2.0, -8.0, 3.0, 5.0,
- -3.0, 1.0, 7.0, 3.0,
- 1.0, 2.0, -9.0, 6.0,
- -6.0, 7.0, 7.0, -9.0,
- ]);
- assert_eq!(a.det(), -4071.0);
- }
- #[test]
- fn not_inversable() {
- let a = Matrix::new_4x4([
- -4.0, 2.0, -2.0, -3.0,
- 9.0, 6.0, 2.0, 6.0,
- 0.0, -5.0, 1.0, -5.0,
- 0.0, 0.0, 0.0, 0.0,
- ]);
- assert_eq!(a.inv(), None);
- }
- #[test]
- fn inverse() {
- let a = Matrix::new_4x4([
- -5.0, 2.0, 6.0, -8.0,
- 1.0, -5.0, 1.0, 8.0,
- 7.0, 7.0, -6.0, -7.0,
- 1.0, -3.0, 7.0, 4.0,
- ]);
- let b = Matrix::new_4x4([
- 0.21805, 0.45113, 0.24060, -0.04511,
- -0.80827, -1.45677, -0.44361, 0.52068,
- -0.07895, -0.22368, -0.05263, 0.19737,
- -0.52256, -0.81391, -0.30075, 0.30639,
- ]);
- assert_eq!(a.inv(), Some(b));
- }
- #[test]
- fn more_tests() {
- let a = Matrix::new_4x4([
- 8.0, -5.0, 9.0, 2.0,
- 7.0, 5.0, 6.0, 1.0,
- -6.0, 0.0, 9.0, 6.0,
- -3.0, 0.0, -9.0, -4.0,
- ]);
- let b = Matrix::new_4x4([
- -0.15385, -0.15385, -0.28205, -0.53846,
- -0.07692, 0.12308, 0.02564, 0.03077,
- 0.35897, 0.35897, 0.43590, 0.92308,
- -0.69231, -0.69231, -0.76923, -1.92308,
- ]);
- assert_eq!(a.inv(), Some(b));
- }
- #[test]
- fn mul_by_inv() {
- let a = Matrix::new_4x4([
- 3.0, -9.0, 7.0, 3.0,
- 3.0, -8.0, 2.0, -9.0,
- -4.0, 4.0, 4.0, 1.0,
- -6.0, 5.0, -1.0, 1.0,
- ]);
- let b = Matrix::new_4x4([
- 8.0, 2.0, 2.0, 2.0,
- 3.0, -1.0, 7.0, 0.0,
- 7.0, 0.0, 5.0, 4.0,
- 6.0, -2.0, 0.0, 5.0,
- ]);
- let c = a.mul(&b);
- assert_eq!(a, c.mul(&b.inv().unwrap()));
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement