transform.rs 5.22 KB
//
// Transformation of vectors in a given coordinate system...
//
// Georg Hopp <georg@steffers.org>
//
// 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 <http://www.gnu.org/licenses/>.
//
use std::ops::{Mul};
use crate::{Fractional, cos, sin, Vector};

pub struct TMatrix( (Fractional, Fractional, Fractional, Fractional)
                  , (Fractional, Fractional, Fractional, Fractional)
                  , (Fractional, Fractional, Fractional, Fractional)
                  , (Fractional, Fractional, Fractional, Fractional) );

pub fn translate(v :Vector) -> TMatrix {
    let Vector(x, y, z) = v;

    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())
           , (       x,        y,        z, 1.into()) )
}

pub fn rotate_x(a :i32) -> TMatrix {
    TMatrix( (1.into(), 0.into(), 0.into(), 0.into())
           , (0.into(),   cos(a),  -sin(a), 0.into())
           , (0.into(),   sin(a),   cos(a), 0.into())
           , (0.into(), 0.into(), 0.into(), 1.into()) )
}

pub fn rotate_y(a :i32) -> TMatrix {
    TMatrix( (  cos(a), 0.into(),   sin(a), 0.into())
           , (0.into(), 1.into(), 0.into(), 0.into())
           , ( -sin(a), 0.into(),   cos(a), 0.into())
           , (0.into(), 0.into(), 0.into(), 1.into()) )
}

pub fn rotate_z(a :i32) -> TMatrix {
    TMatrix( (  cos(a),  -sin(a), 0.into(), 0.into())
           , (  sin(a),   cos(a), 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 {
    let Vector(x, y, z) = *v;

    let zero :Fractional = 0.into();
    let one  :Fractional = 1.into();

    TMatrix( ( (one - cos(a)) * x * x + cos(a)
             , (one - cos(a)) * x * y - sin(a) * z
             , (one - cos(a)) * x * z + sin(a) * y
             , zero )
           , ( (one - cos(a)) * x * y + sin(a) * z
             , (one - cos(a)) * y * y + cos(a)
             , (one - cos(a)) * y * z - sin(a) * x
             , zero )
           , ( (one - cos(a)) * x * z - sin(a) * y
             , (one - cos(a)) * y * z + sin(a) * x
             , (one - cos(a)) * z * z + cos(a)
             , zero )
           , (0.into(), 0.into(), 0.into(), 1.into()) )
}

pub fn scale(v :Vector) -> TMatrix {
    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 {
    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 + a21 * y + a31 * z + a41
                      , a12 * x + a22 * y + a32 * z + a42
                      , a13 * x + a23 * y + a33 * z + a43 );
        let Fractional(wn, wd) = a14 * x + a24 * y + a34 * z + a44;

        v.mul(&Fractional(wd, wn))
    }
}

impl Mul for TMatrix {
    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 ) )
    }
}