// // Transformation of vectors in a given coordinate system... // // Georg Hopp // // Copyright © 2019 Georg Hopp // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // use std::ops::{Add, Sub, Neg, Mul, Div}; use std::fmt::Debug; use crate::Vector; use crate::trigonometry::Trig; #[derive(Debug, Clone, Copy)] pub struct TMatrix( (T, T, T, T) , (T, T, T, T) , (T, T, T, T) , (T, T, T, T) ) where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From + Copy; pub fn unit() -> TMatrix where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From + Copy { TMatrix( (1.into(), 0.into(), 0.into(), 0.into()) , (0.into(), 1.into(), 0.into(), 0.into()) , (0.into(), 0.into(), 1.into(), 0.into()) , (0.into(), 0.into(), 0.into(), 1.into()) ) } pub fn translate(v :Vector) -> TMatrix where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From + Copy { let Vector(x, y, z) = v; TMatrix( (1.into(), 0.into(), 0.into(), x) , (0.into(), 1.into(), 0.into(), y) , (0.into(), 0.into(), 1.into(), z) , (0.into(), 0.into(), 0.into(), 1.into()) ) } pub fn rotate_x(a :i32) -> TMatrix where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From + Copy { let sin :T = Trig::sin(a); let cos :T = Trig::cos(a); TMatrix( (1.into(), 0.into(), 0.into(), 0.into()) , (0.into(), cos , -sin , 0.into()) , (0.into(), sin , cos , 0.into()) , (0.into(), 0.into(), 0.into(), 1.into()) ) } pub fn rotate_y(a :i32) -> TMatrix where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From + Copy { let sin :T = Trig::sin(a); let cos :T = Trig::cos(a); TMatrix( (cos , 0.into(), sin , 0.into()) , (0.into(), 1.into(), 0.into(), 0.into()) , (-sin , 0.into(), cos , 0.into()) , (0.into(), 0.into(), 0.into(), 1.into()) ) } pub fn rotate_z(a :i32) -> TMatrix where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From + Copy { let sin :T = Trig::sin(a); let cos :T = Trig::cos(a); TMatrix( (cos , -sin , 0.into(), 0.into()) , (sin , cos , 0.into(), 0.into()) , (0.into(), 0.into(), 1.into(), 0.into()) , (0.into(), 0.into(), 0.into(), 1.into()) ) } pub fn rotate_v(v :&Vector, a :i32) -> TMatrix where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From + Copy { let Vector(x, y, z) = *v; let sin :T = Trig::sin(a); let cos :T = Trig::cos(a); let zero :T = 0.into(); let one :T = 1.into(); TMatrix( ( (one - cos) * x * x + cos , (one - cos) * x * y - sin * z , (one - cos) * x * z + sin * y , zero ) , ( (one - cos) * x * y + sin * z , (one - cos) * y * y + cos , (one - cos) * y * z - sin * x , zero ) , ( (one - cos) * x * z - sin * y , (one - cos) * y * z + sin * x , (one - cos) * z * z + cos , zero ) , (0.into(), 0.into(), 0.into(), 1.into()) ) } pub fn scale(v :Vector) -> TMatrix where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From + Copy { let Vector(x, y, z) = v; TMatrix( ( x, 0.into(), 0.into(), 0.into()) , (0.into(), y, 0.into(), 0.into()) , (0.into(), 0.into(), z, 0.into()) , (0.into(), 0.into(), 0.into(), 1.into()) ) } impl TMatrix where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From + Copy { pub fn new( r1 :(T, T, T, T) , r2 :(T, T, T, T) , r3 :(T, T, T, T) , r4 :(T, T, T, T) ) -> TMatrix { TMatrix(r1, r2, r3, r4) } pub fn combine(mi :I) -> TMatrix where I: IntoIterator> { mi.into_iter().fold(unit(), |acc, x| x * acc) } pub fn apply(&self, v :&Vector) -> Vector { let TMatrix( (a11, a12, a13, a14) , (a21, a22, a23, a24) , (a31, a32, a33, a34) , (a41, a42, a43, a44) ) = *self; let Vector(x, y, z) = *v; let v = Vector( a11 * x + a12 * y + a13 * z + a14 , a21 * x + a22 * y + a23 * z + a24 , a31 * x + a32 * y + a33 * z + a34 ); let w = a41 * x + a42 * y + a43 * z + a44; v.mul(&w.recip()) } } impl Mul for TMatrix where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From + Copy { type Output = Self; // ATTENTION: This is not commutative, nor assoziative. fn mul(self, other :Self) -> Self { let TMatrix( (a11, a12, a13, a14) , (a21, a22, a23, a24) , (a31, a32, a33, a34) , (a41, a42, a43, a44) ) = self; let TMatrix( (b11, b12, b13, b14) , (b21, b22, b23, b24) , (b31, b32, b33, b34) , (b41, b42, b43, b44) ) = other; TMatrix( ( a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41 , a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42 , a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43 , a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44 ) , ( a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41 , a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42 , a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43 , a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44 ) , ( a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41 , a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42 , a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43 , a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44 ) , ( a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41 , a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42 , a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43 , a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44 ) ) } }