andyherbert

Untitled

Jul 29th, 2020
360
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. use crate::{eq, tuple::Tuple};
  2.  
  3. #[derive(Debug, Clone)]
  4. pub struct Matrix {
  5.     pub size: usize,
  6.     pub data: Box<[f32]>,
  7. }
  8.  
  9. impl Matrix {
  10.     pub fn new(size: usize, data: Box<[f32]>) -> Matrix {
  11.         Matrix {
  12.             size,
  13.             data,
  14.         }
  15.     }
  16.  
  17.     pub fn new_2x2(data: [f32; 4]) -> Matrix {
  18.         Matrix {
  19.             size: 2,
  20.             data: Box::new(data),
  21.         }
  22.     }
  23.  
  24.     pub fn new_3x3(data: [f32; 9]) -> Matrix {
  25.         Matrix {
  26.             size: 3,
  27.             data: Box::new(data),
  28.         }
  29.     }
  30.  
  31.     pub fn new_4x4(data: [f32; 16]) -> Matrix {
  32.         Matrix {
  33.             size: 4,
  34.             data: Box::new(data),
  35.         }
  36.     }
  37.  
  38.     pub fn new_4x4_zeroed() -> Matrix {
  39.         Matrix {
  40.             size: 4,
  41.             data: Box::new([
  42.                 0.0, 0.0, 0.0, 0.0,
  43.                 0.0, 0.0, 0.0, 0.0,
  44.                 0.0, 0.0, 0.0, 0.0,
  45.                 0.0, 0.0, 0.0, 0.0,
  46.             ]),
  47.         }
  48.     }
  49.  
  50.     pub fn new_3x3_zeroed() -> Matrix {
  51.         Matrix {
  52.             size: 3,
  53.             data: Box::new([
  54.                 0.0, 0.0, 0.0,
  55.                 0.0, 0.0, 0.0,
  56.                 0.0, 0.0, 0.0,
  57.             ]),
  58.         }
  59.     }
  60.  
  61.     pub fn new_2x2_zeroed() -> Matrix {
  62.         Matrix {
  63.             size: 2,
  64.             data: Box::new([
  65.                 0.0, 0.0,
  66.                 0.0, 0.0,
  67.             ]),
  68.         }
  69.     }
  70.  
  71.     pub fn new_4x4_identity_matrix() -> Matrix {
  72.         Matrix {
  73.             size: 4,
  74.             data: Box::new([
  75.                 1.0, 0.0, 0.0, 0.0,
  76.                 0.0, 1.0, 0.0, 0.0,
  77.                 0.0, 0.0, 1.0, 0.0,
  78.                 0.0, 0.0, 0.0, 1.0,
  79.             ]),
  80.         }
  81.     }
  82.  
  83.     fn mul(&self, other: &Matrix) -> Matrix {
  84.         let mut answer = Matrix::new_4x4_zeroed();
  85.         for row_start in (0..16).step_by(4) {
  86.             for column in 0..4 {
  87.                 let answer_index = row_start + column;
  88.                 answer.data[answer_index] += self.data[row_start + 0] * other.data[0 + column];
  89.                 answer.data[answer_index] += self.data[row_start + 1] * other.data[4 + column];
  90.                 answer.data[answer_index] += self.data[row_start + 2] * other.data[8 + column];
  91.                 answer.data[answer_index] += self.data[row_start + 3] * other.data[12 + column];
  92.             }
  93.         }
  94.         answer
  95.     }
  96.  
  97.     fn mul_tuple(&self, tuple: Tuple) -> Tuple {
  98.         Tuple {
  99.             x: self.data[ 0] * tuple.x + self.data[ 1] * tuple.y + self.data[ 2] * tuple.z + self.data[ 3] * tuple.w,
  100.             y: self.data[ 4] * tuple.x + self.data[ 5] * tuple.y + self.data[ 6] * tuple.z + self.data[ 7] * tuple.w,
  101.             z: self.data[ 8] * tuple.x + self.data[ 9] * tuple.y + self.data[10] * tuple.z + self.data[11] * tuple.w,
  102.             w: self.data[12] * tuple.x + self.data[13] * tuple.y + self.data[14] * tuple.z + self.data[15] * tuple.w,
  103.         }
  104.     }
  105.  
  106.     fn transpose(&self) -> Matrix {
  107.         let mut answer = self.clone();
  108.         let mut src_index = 0;
  109.         for row in 0..self.size {
  110.             for column in 0..self.size {
  111.                 answer.data[src_index] = self.data[column * self.size + row];
  112.                 src_index += 1;
  113.             }
  114.         }
  115.         answer
  116.     }
  117.  
  118.     fn det(&self) -> f32 {
  119.         match self.size {
  120.             2 => self.data[0] * self.data[3] - self.data[1] * self.data[2],
  121.             3 => self.data[0] * self.cofac(0, 0) +
  122.                  self.data[1] * self.cofac(0, 1) +
  123.                  self.data[2] * self.cofac(0, 2),
  124.             4 => self.data[0] * self.cofac(0, 0) +
  125.                  self.data[1] * self.cofac(0, 1) +
  126.                  self.data[2] * self.cofac(0, 2) +
  127.                  self.data[3] * self.cofac(0, 3),
  128.             _ => panic!(),
  129.         }
  130.     }
  131.  
  132.     fn sub(&self, row: usize, column: usize) -> Matrix {
  133.         let mut answer = match self.size {
  134.             4 => Matrix::new_3x3_zeroed(),
  135.             3 => Matrix::new_2x2_zeroed(),
  136.             _ => panic!("Unsupported matrix size"),
  137.         };
  138.         let mut src_index = 0;
  139.         let mut dest_index = 0;
  140.         for src_row in 0..self.size {
  141.             for src_column in 0..self.size {
  142.                 if src_row != row && src_column != column {
  143.                     answer.data[dest_index] = self.data[src_index];
  144.                     dest_index += 1;
  145.                 }
  146.                 src_index += 1;
  147.             }
  148.         }
  149.         answer
  150.     }
  151.  
  152.     fn minor(&self, row: usize, column: usize) -> f32 {
  153.         self.sub(row, column).det()
  154.     }
  155.  
  156.     fn cofac(&self, row: usize, column: usize) -> f32 {
  157.         let min = self.minor(row, column);
  158.         if row % 2 == 0 {
  159.             if column % 2 == 0 {
  160.                 min
  161.             } else {
  162.                 -min
  163.             }
  164.         } else {
  165.             if column % 2 == 0 {
  166.                 -min
  167.             } else {
  168.                 min
  169.             }
  170.         }
  171.     }
  172.  
  173.     fn inv(&self) -> Option<Matrix> {
  174.         let mut answer = match self.size {
  175.             4 => Matrix::new_4x4_zeroed(),
  176.             3 => Matrix::new_3x3_zeroed(),
  177.             2 => Matrix::new_2x2_zeroed(),
  178.             _ => panic!(),
  179.         };
  180.         let det = self.det();
  181.         if det == 0.0 {
  182.             return None;
  183.         }
  184.         let mut index = 0;
  185.         for row in 0..self.size {
  186.             for column in 0..self.size {
  187.                 answer.data[index] = self.cofac(row, column) / det;
  188.                 index += 1;
  189.             }
  190.         }
  191.         Some(answer.transpose())
  192.     }
  193. }
  194.  
  195. impl PartialEq for Matrix {
  196.     fn eq(&self, other: &Matrix) -> bool {
  197.         if self.size == other.size && self.size == other.size {
  198.             for (index, value) in self.data.iter().enumerate() {
  199.                 if !eq!(value, other.data[index]) {
  200.                     return false;
  201.                 }
  202.             }
  203.             true
  204.         } else {
  205.             false
  206.         }
  207.     }
  208. }
  209.  
  210. #[cfg(test)]
  211. mod tests {
  212.     use super::*;
  213.     #[test]
  214.     fn equality() {
  215.         let a = Matrix::new_4x4([
  216.             1.0, 2.0, 3.0, 4.0,
  217.             5.5, 6.5, 7.5, 8.5,
  218.             9.0, 10.0, 11.0, 12.0,
  219.             13.5, 14.5, 15.5, 16.0,
  220.         ]);
  221.         let mut b = a.clone();
  222.         assert_eq!(a, b);
  223.         b.data[0] = 2.0;
  224.         assert_ne!(a, b);
  225.         b.data[0] = 1.000001;
  226.         assert_eq!(a, b);
  227.     }
  228.  
  229.     #[test]
  230.     fn create_2x2() {
  231.         let a = Matrix::new_2x2([
  232.             -3.0, 5.0,
  233.             1.0, -2.0,
  234.         ]);
  235.         let mut b = a.clone();
  236.         assert_eq!(a, b);
  237.         b.data[3] = 1.0;
  238.         assert_ne!(a, b);
  239.     }
  240.  
  241.     #[test]
  242.     fn create_3x3() {
  243.         let a = Matrix::new_3x3([
  244.             -3.0, 5.0, 0.0,
  245.             1.0, -2.0, -7.0,
  246.             0.0, 1.0, 1.0,
  247.         ]);
  248.         let mut b = a.clone();
  249.         assert_eq!(a, b);
  250.         b.data[3] = 1.0;
  251.         assert_eq!(a, b);
  252.     }
  253.  
  254.     #[test]
  255.     fn mul_4x4() {
  256.         let a = Matrix::new_4x4([
  257.             1.0, 2.0, 3.0, 4.0,
  258.             5.0, 6.0, 7.0, 8.0,
  259.             9.0, 8.0, 7.0, 6.0,
  260.             5.0, 4.0, 3.0, 2.0,
  261.         ]);
  262.         let b = Matrix::new_4x4([
  263.             -2.0, 1.0, 2.0, 3.0,
  264.             3.0, 2.0, 1.0, -1.0,
  265.             4.0, 3.0, 6.0, 5.0,
  266.             1.0, 2.0, 7.0, 8.0,
  267.         ]);
  268.         let c = Matrix::new_4x4([
  269.             20.0, 22.0, 50.0, 48.0,
  270.             44.0, 54.0, 114.0, 108.0,
  271.             40.0, 58.0, 110.0, 102.0,
  272.             16.0, 26.0, 46.0, 42.0,
  273.         ]);
  274.         assert_eq!(a.mul(&b), c);
  275.     }
  276.  
  277.     #[test]
  278.     fn mul_by_identity_matrix() {
  279.         let a = Matrix::new_4x4([
  280.             1.0, 2.0, 3.0, 4.0,
  281.             5.0, 6.0, 7.0, 8.0,
  282.             9.0, 8.0, 7.0, 6.0,
  283.             5.0, 4.0, 3.0, 2.0,
  284.         ]);
  285.         let b = Matrix::new_4x4_identity_matrix();
  286.         let c = a.clone();
  287.         assert_eq!(a.mul(&b), c);
  288.     }
  289.  
  290.     #[test]
  291.     fn mul_tuple() {
  292.         let a = Matrix::new_4x4([
  293.             1.0, 2.0, 3.0, 4.0,
  294.             2.0, 4.0, 4.0, 2.0,
  295.             8.0, 6.0, 4.0, 1.0,
  296.             0.0, 0.0, 0.0, 1.0,
  297.         ]);
  298.         let b = Tuple {x: 1.0, y: 2.0, z: 3.0, w: 1.0};
  299.         let c = Tuple {x: 18.0, y: 24.0, z: 33.0, w: 1.0};
  300.         assert_eq!(a.mul_tuple(b), c);
  301.     }
  302.  
  303.     #[test]
  304.     fn transpose() {
  305.         let a = Matrix::new_4x4([
  306.             0.0, 9.0, 3.0, 0.0,
  307.             9.0, 8.0, 0.0, 8.0,
  308.             1.0, 8.0, 5.0, 3.0,
  309.             0.0, 0.0, 5.0, 8.0,
  310.         ]);
  311.         let b = Matrix::new_4x4([
  312.             0.0, 9.0, 1.0, 0.0,
  313.             9.0, 8.0, 8.0, 0.0,
  314.             3.0, 0.0, 5.0, 5.0,
  315.             0.0, 8.0, 3.0, 8.0,
  316.         ]);
  317.         assert_eq!(a.transpose(), b);
  318.     }
  319.  
  320.     #[test]
  321.     fn determinant() {
  322.         let a = Matrix::new_2x2([
  323.             1.0, 5.0,
  324.             -3.0, 2.0,
  325.         ]);
  326.         assert_eq!(a.det(), 17.0);
  327.     }
  328.  
  329.     #[test]
  330.     fn sub_3x3() {
  331.         let a = Matrix::new_3x3([
  332.             1.0, 5.0, 0.0,
  333.             -3.0, 2.0, 7.0,
  334.             0.0, 6.0, -2.0,
  335.         ]);
  336.         let b = Matrix::new_2x2([
  337.             -3.0, 2.0,
  338.             0.0, 6.0,
  339.         ]);
  340.         assert_eq!(a.sub(0, 2), b);
  341.     }
  342.  
  343.     #[test]
  344.     fn sub_4x4() {
  345.         let a = Matrix::new_4x4([
  346.             -6.0, 1.0, 1.0, 6.0,
  347.             -8.0, 5.0, 8.0, 6.0,
  348.             -1.0, 0.0, 8.0, 2.0,
  349.             -7.0, 1.0, -1.0, 1.0,
  350.         ]);
  351.         let b = Matrix::new_3x3([
  352.             -6.0, 1.0, 6.0,
  353.             -8.0, 8.0, 6.0,
  354.             -7.0, -1.0, 1.0,
  355.         ]);
  356.         assert_eq!(a.sub(2, 1), b);
  357.     }
  358.  
  359.     #[test]
  360.     fn minor_3x3() {
  361.         let a = Matrix::new_3x3([
  362.             3.0, 5.0, 0.0,
  363.             2.0, -1.0, -7.0,
  364.             6.0, -1.0, 5.0,
  365.         ]);
  366.         assert_eq!(a.minor(1, 0), 25.0);
  367.     }
  368.  
  369.     #[test]
  370.     fn cofactor() {
  371.         let a = Matrix::new_3x3([
  372.             3.0, 5.0, 0.0,
  373.             2.0, -1.0, -7.0,
  374.             6.0, -1.0, 5.0,
  375.         ]);
  376.         assert_eq!(a.cofac(0, 0), -12.0);
  377.         assert_eq!(a.cofac(1, 0), -25.0);
  378.     }
  379.  
  380.     #[test]
  381.     fn determinant_3x3() {
  382.         let a = Matrix::new_3x3([
  383.             1.0, 2.0, 6.0,
  384.             -5.0, 8.0, -4.0,
  385.             2.0, 6.0, 4.0,
  386.         ]);
  387.         assert_eq!(a.det(), -196.0);
  388.     }
  389.  
  390.     #[test]
  391.     fn determinant_4x4() {
  392.         let a = Matrix::new_4x4([
  393.             -2.0, -8.0, 3.0, 5.0,
  394.             -3.0, 1.0, 7.0, 3.0,
  395.             1.0, 2.0, -9.0, 6.0,
  396.             -6.0, 7.0, 7.0, -9.0,
  397.         ]);
  398.         assert_eq!(a.det(), -4071.0);
  399.     }
  400.  
  401.     #[test]
  402.     fn not_inversable() {
  403.         let a = Matrix::new_4x4([
  404.             -4.0, 2.0, -2.0, -3.0,
  405.             9.0, 6.0, 2.0, 6.0,
  406.             0.0, -5.0, 1.0, -5.0,
  407.             0.0, 0.0, 0.0, 0.0,
  408.         ]);
  409.         assert_eq!(a.inv(), None);
  410.     }
  411.  
  412.     #[test]
  413.     fn inverse() {
  414.         let a = Matrix::new_4x4([
  415.             -5.0, 2.0, 6.0, -8.0,
  416.             1.0, -5.0, 1.0, 8.0,
  417.             7.0, 7.0, -6.0, -7.0,
  418.             1.0, -3.0, 7.0, 4.0,
  419.         ]);
  420.         let b = Matrix::new_4x4([
  421.             0.21805, 0.45113, 0.24060, -0.04511,
  422.             -0.80827, -1.45677, -0.44361, 0.52068,
  423.             -0.07895, -0.22368, -0.05263, 0.19737,
  424.             -0.52256, -0.81391, -0.30075, 0.30639,
  425.         ]);
  426.         assert_eq!(a.inv(), Some(b));
  427.     }
  428.  
  429.     #[test]
  430.     fn more_tests() {
  431.         let a = Matrix::new_4x4([
  432.             8.0, -5.0, 9.0, 2.0,
  433.             7.0, 5.0, 6.0, 1.0,
  434.             -6.0, 0.0, 9.0, 6.0,
  435.             -3.0, 0.0, -9.0, -4.0,
  436.         ]);
  437.         let b = Matrix::new_4x4([
  438.             -0.15385, -0.15385, -0.28205, -0.53846,
  439.             -0.07692, 0.12308, 0.02564, 0.03077,
  440.             0.35897, 0.35897, 0.43590, 0.92308,
  441.             -0.69231, -0.69231, -0.76923, -1.92308,
  442.         ]);
  443.         assert_eq!(a.inv(), Some(b));
  444.     }
  445.  
  446.     #[test]
  447.     fn mul_by_inv() {
  448.         let a = Matrix::new_4x4([
  449.             3.0, -9.0, 7.0, 3.0,
  450.             3.0, -8.0, 2.0, -9.0,
  451.             -4.0, 4.0, 4.0, 1.0,
  452.             -6.0, 5.0, -1.0, 1.0,
  453.         ]);
  454.         let b = Matrix::new_4x4([
  455.             8.0, 2.0, 2.0, 2.0,
  456.             3.0, -1.0, 7.0, 0.0,
  457.             7.0, 0.0, 5.0, 4.0,
  458.             6.0, -2.0, 0.0, 5.0,
  459.         ]);
  460.         let c = a.mul(&b);
  461.         assert_eq!(a, c.mul(&b.inv().unwrap()));
  462.     }
  463.  
  464. }
  465.  
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×