diff --git a/src/lib.rs b/src/lib.rs index 789847a..627e20f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ // except according to those terms. #![cfg_attr(feature = "unstable", feature(asm, repr_simd, test, augmented_assignments, op_assign_traits))] +#![cfg_attr(feature = "unstable", feature(deprecated))] #![cfg_attr(feature = "plugins", feature(custom_derive, plugin))] #![cfg_attr(feature = "plugins", plugin(heapsize_plugin))] @@ -31,6 +32,7 @@ extern crate num as num_lib; pub use matrix::Matrix4; pub use matrix2d::Matrix2D; +pub use matrix4d::Matrix4D; pub use point::{Point2D, Point3D, Point4D}; pub use rect::Rect; #[cfg(feature = "unstable")] @@ -43,9 +45,11 @@ pub mod approxeq; pub mod length; pub mod matrix; pub mod matrix2d; +pub mod matrix4d; pub mod num; pub mod point; pub mod rect; pub mod scale_factor; pub mod side_offsets; pub mod size; +mod trig; diff --git a/src/matrix.rs b/src/matrix.rs index 69d6b59..6823f6d 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -7,322 +7,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use approxeq::ApproxEq; -use point::{Point2D, Point4D}; +#[cfg(test)] +use point::{Point2D}; +use matrix4d::Matrix4D; - -#[derive(Debug, Copy, Clone, PartialEq)] -#[cfg_attr(feature = "plugins", derive(HeapSizeOf, Deserialize, Serialize))] -pub struct Matrix4 { - pub m11: f32, pub m12: f32, pub m13: f32, pub m14: f32, - pub m21: f32, pub m22: f32, pub m23: f32, pub m24: f32, - pub m31: f32, pub m32: f32, pub m33: f32, pub m34: f32, - pub m41: f32, pub m42: f32, pub m43: f32, pub m44: f32, -} - -impl Matrix4 { - #[inline] - pub fn new( - m11: f32, m12: f32, m13: f32, m14: f32, - m21: f32, m22: f32, m23: f32, m24: f32, - m31: f32, m32: f32, m33: f32, m34: f32, - m41: f32, m42: f32, m43: f32, m44: f32) - -> Matrix4 { - Matrix4 { - m11: m11, m12: m12, m13: m13, m14: m14, - m21: m21, m22: m22, m23: m23, m24: m24, - m31: m31, m32: m32, m33: m33, m34: m34, - m41: m41, m42: m42, m43: m43, m44: m44 - } - } - - pub fn ortho(left: f32, right: f32, - bottom: f32, top: f32, - near: f32, far: f32) -> Matrix4 { - let tx = -((right + left) / (right - left)); - let ty = -((top + bottom) / (top - bottom)); - let tz = -((far + near) / (far - near)); - - Matrix4::new(2.0 / (right - left), - 0.0, - 0.0, - 0.0, - - 0.0, - 2.0 / (top - bottom), - 0.0, - 0.0, - - 0.0, - 0.0, - -2.0 / (far - near), - 0.0, - - tx, - ty, - tz, - 1.0) - } - - #[inline] - pub fn identity() -> Matrix4 { - Matrix4::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 approx_eq(&self, other: &Matrix4) -> bool { - self.m11.approx_eq(&other.m11) && self.m12.approx_eq(&other.m12) && - self.m13.approx_eq(&other.m13) && self.m14.approx_eq(&other.m14) && - self.m21.approx_eq(&other.m21) && self.m22.approx_eq(&other.m22) && - self.m23.approx_eq(&other.m23) && self.m24.approx_eq(&other.m24) && - self.m31.approx_eq(&other.m31) && self.m32.approx_eq(&other.m32) && - self.m33.approx_eq(&other.m33) && self.m34.approx_eq(&other.m34) && - self.m41.approx_eq(&other.m41) && self.m42.approx_eq(&other.m42) && - self.m43.approx_eq(&other.m43) && self.m44.approx_eq(&other.m44) - } - - pub fn mul(&self, m: &Matrix4) -> Matrix4 { - Matrix4::new(m.m11*self.m11 + m.m12*self.m21 + m.m13*self.m31 + m.m14*self.m41, - m.m11*self.m12 + m.m12*self.m22 + m.m13*self.m32 + m.m14*self.m42, - m.m11*self.m13 + m.m12*self.m23 + m.m13*self.m33 + m.m14*self.m43, - m.m11*self.m14 + m.m12*self.m24 + m.m13*self.m34 + m.m14*self.m44, - m.m21*self.m11 + m.m22*self.m21 + m.m23*self.m31 + m.m24*self.m41, - m.m21*self.m12 + m.m22*self.m22 + m.m23*self.m32 + m.m24*self.m42, - m.m21*self.m13 + m.m22*self.m23 + m.m23*self.m33 + m.m24*self.m43, - m.m21*self.m14 + m.m22*self.m24 + m.m23*self.m34 + m.m24*self.m44, - m.m31*self.m11 + m.m32*self.m21 + m.m33*self.m31 + m.m34*self.m41, - m.m31*self.m12 + m.m32*self.m22 + m.m33*self.m32 + m.m34*self.m42, - m.m31*self.m13 + m.m32*self.m23 + m.m33*self.m33 + m.m34*self.m43, - m.m31*self.m14 + m.m32*self.m24 + m.m33*self.m34 + m.m34*self.m44, - m.m41*self.m11 + m.m42*self.m21 + m.m43*self.m31 + m.m44*self.m41, - m.m41*self.m12 + m.m42*self.m22 + m.m43*self.m32 + m.m44*self.m42, - m.m41*self.m13 + m.m42*self.m23 + m.m43*self.m33 + m.m44*self.m43, - m.m41*self.m14 + m.m42*self.m24 + m.m43*self.m34 + m.m44*self.m44) - } - - pub fn invert(&self) -> Matrix4 { - let det = self.determinant(); - - if det == 0.0 { - return Matrix4::identity(); - } - - // todo(gw): this could be made faster by special casing - // for simpler matrix types. - let m = Matrix4::new( - self.m23*self.m34*self.m42 - self.m24*self.m33*self.m42 + - self.m24*self.m32*self.m43 - self.m22*self.m34*self.m43 - - self.m23*self.m32*self.m44 + self.m22*self.m33*self.m44, - - self.m14*self.m33*self.m42 - self.m13*self.m34*self.m42 - - self.m14*self.m32*self.m43 + self.m12*self.m34*self.m43 + - self.m13*self.m32*self.m44 - self.m12*self.m33*self.m44, - - self.m13*self.m24*self.m42 - self.m14*self.m23*self.m42 + - self.m14*self.m22*self.m43 - self.m12*self.m24*self.m43 - - self.m13*self.m22*self.m44 + self.m12*self.m23*self.m44, - - self.m14*self.m23*self.m32 - self.m13*self.m24*self.m32 - - self.m14*self.m22*self.m33 + self.m12*self.m24*self.m33 + - self.m13*self.m22*self.m34 - self.m12*self.m23*self.m34, - - self.m24*self.m33*self.m41 - self.m23*self.m34*self.m41 - - self.m24*self.m31*self.m43 + self.m21*self.m34*self.m43 + - self.m23*self.m31*self.m44 - self.m21*self.m33*self.m44, - - self.m13*self.m34*self.m41 - self.m14*self.m33*self.m41 + - self.m14*self.m31*self.m43 - self.m11*self.m34*self.m43 - - self.m13*self.m31*self.m44 + self.m11*self.m33*self.m44, - - self.m14*self.m23*self.m41 - self.m13*self.m24*self.m41 - - self.m14*self.m21*self.m43 + self.m11*self.m24*self.m43 + - self.m13*self.m21*self.m44 - self.m11*self.m23*self.m44, - - self.m13*self.m24*self.m31 - self.m14*self.m23*self.m31 + - self.m14*self.m21*self.m33 - self.m11*self.m24*self.m33 - - self.m13*self.m21*self.m34 + self.m11*self.m23*self.m34, - - self.m22*self.m34*self.m41 - self.m24*self.m32*self.m41 + - self.m24*self.m31*self.m42 - self.m21*self.m34*self.m42 - - self.m22*self.m31*self.m44 + self.m21*self.m32*self.m44, - - self.m14*self.m32*self.m41 - self.m12*self.m34*self.m41 - - self.m14*self.m31*self.m42 + self.m11*self.m34*self.m42 + - self.m12*self.m31*self.m44 - self.m11*self.m32*self.m44, - - self.m12*self.m24*self.m41 - self.m14*self.m22*self.m41 + - self.m14*self.m21*self.m42 - self.m11*self.m24*self.m42 - - self.m12*self.m21*self.m44 + self.m11*self.m22*self.m44, - - self.m14*self.m22*self.m31 - self.m12*self.m24*self.m31 - - self.m14*self.m21*self.m32 + self.m11*self.m24*self.m32 + - self.m12*self.m21*self.m34 - self.m11*self.m22*self.m34, - - self.m23*self.m32*self.m41 - self.m22*self.m33*self.m41 - - self.m23*self.m31*self.m42 + self.m21*self.m33*self.m42 + - self.m22*self.m31*self.m43 - self.m21*self.m32*self.m43, - - self.m12*self.m33*self.m41 - self.m13*self.m32*self.m41 + - self.m13*self.m31*self.m42 - self.m11*self.m33*self.m42 - - self.m12*self.m31*self.m43 + self.m11*self.m32*self.m43, - - self.m13*self.m22*self.m41 - self.m12*self.m23*self.m41 - - self.m13*self.m21*self.m42 + self.m11*self.m23*self.m42 + - self.m12*self.m21*self.m43 - self.m11*self.m22*self.m43, - - self.m12*self.m23*self.m31 - self.m13*self.m22*self.m31 + - self.m13*self.m21*self.m32 - self.m11*self.m23*self.m32 - - self.m12*self.m21*self.m33 + self.m11*self.m22*self.m33 - ); - - m.mul_s(1.0 / det) - } - - pub fn determinant(&self) -> f32 { - self.m14 * self.m23 * self.m32 * self.m41 - - self.m13 * self.m24 * self.m32 * self.m41 - - self.m14 * self.m22 * self.m33 * self.m41 + - self.m12 * self.m24 * self.m33 * self.m41 + - self.m13 * self.m22 * self.m34 * self.m41 - - self.m12 * self.m23 * self.m34 * self.m41 - - self.m14 * self.m23 * self.m31 * self.m42 + - self.m13 * self.m24 * self.m31 * self.m42 + - self.m14 * self.m21 * self.m33 * self.m42 - - self.m11 * self.m24 * self.m33 * self.m42 - - self.m13 * self.m21 * self.m34 * self.m42 + - self.m11 * self.m23 * self.m34 * self.m42 + - self.m14 * self.m22 * self.m31 * self.m43 - - self.m12 * self.m24 * self.m31 * self.m43 - - self.m14 * self.m21 * self.m32 * self.m43 + - self.m11 * self.m24 * self.m32 * self.m43 + - self.m12 * self.m21 * self.m34 * self.m43 - - self.m11 * self.m22 * self.m34 * self.m43 - - self.m13 * self.m22 * self.m31 * self.m44 + - self.m12 * self.m23 * self.m31 * self.m44 + - self.m13 * self.m21 * self.m32 * self.m44 - - self.m11 * self.m23 * self.m32 * self.m44 - - self.m12 * self.m21 * self.m33 * self.m44 + - self.m11 * self.m22 * self.m33 * self.m44 - } - - pub fn mul_s(&self, x: f32) -> Matrix4 { - Matrix4::new(self.m11 * x, self.m12 * x, self.m13 * x, self.m14 * x, - self.m21 * x, self.m22 * x, self.m23 * x, self.m24 * x, - self.m31 * x, self.m32 * x, self.m33 * x, self.m34 * x, - self.m41 * x, self.m42 * x, self.m43 * x, self.m44 * x) - } - - pub fn scale(&self, x: f32, y: f32, z: f32) -> Matrix4 { - Matrix4::new(self.m11 * x, self.m12, self.m13, self.m14, - self.m21 , self.m22 * y, self.m23, self.m24, - self.m31 , self.m32, self.m33 * z, self.m34, - self.m41 , self.m42, self.m43, self.m44) - } - - /// Returns the given point transformed by this matrix. - #[inline] - pub fn transform_point(&self, p: &Point2D) -> Point2D { - Point2D::new(p.x * self.m11 + p.y * self.m21 + self.m41, - p.x * self.m12 + p.y * self.m22 + self.m42) - } - - #[inline] - pub fn transform_point4d(&self, p: &Point4D) -> Point4D { - let x = p.x * self.m11 + p.y * self.m21 + p.z * self.m31 + self.m41; - let y = p.x * self.m12 + p.y * self.m22 + p.z * self.m32 + self.m42; - let z = p.x * self.m13 + p.y * self.m23 + p.z * self.m33 + self.m43; - let w = p.x * self.m14 + p.y * self.m24 + p.z * self.m34 + self.m44; - Point4D::new(x, y, z, w) - } - - pub fn to_array(&self) -> [f32; 16] { - [ - self.m11, self.m12, self.m13, self.m14, - self.m21, self.m22, self.m23, self.m24, - self.m31, self.m32, self.m33, self.m34, - self.m41, self.m42, self.m43, self.m44 - ] - } - - pub fn translate(&self, x: f32, y: f32, z: f32) -> Matrix4 { - let matrix = Matrix4::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, - x, y, z, 1.0); - - return self.mul(&matrix); - } - - /// Create a 3d translation matrix - pub fn create_translation(x: f32, y: f32, z: f32) -> Matrix4 { - Matrix4::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, - x, y, z, 1.0) - } - - /// Create a 3d scale matrix - pub fn create_scale(x: f32, y: f32, z: f32) -> Matrix4 { - Matrix4::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) - } - - /// Create a 3d rotation matrix from an angle / axis. - /// The supplied axis must be normalized. - pub fn create_rotation(x: f32, y: f32, z: f32, theta: f32) -> Matrix4 { - let xx = x * x; - let yy = y * y; - let zz = z * z; - - let half_theta = theta * 0.5; - let sc = half_theta.sin() * half_theta.cos(); - let sq = half_theta.sin() * half_theta.sin(); - - Matrix4::new( - 1.0 - 2.0 * (yy + zz) * sq, - 2.0 * (x * y * sq - z * sc), - 2.0 * (x * z * sq + y * sc), - 0.0, - - 2.0 * (x * y * sq + z * sc), - 1.0 - 2.0 * (xx + zz) * sq, - 2.0 * (y * z * sq - x * sc), - 0.0, - - 2.0 * (x * z * sq - y * sc), - 2.0 * (y * z * sq + x * sc), - 1.0 - 2.0 * (xx + yy) * sq, - 0.0, - - 0.0, - 0.0, - 0.0, - 1.0 - ) - } - - /// Create a 2d skew matrix. - /// https://drafts.csswg.org/css-transforms/#funcdef-skew - pub fn create_skew(alpha: f32, beta: f32) -> Matrix4 { - let (sx, sy) = (beta.tan(), alpha.tan()); - Matrix4::new(1.0, sx, 0.0, 0.0, - sy, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0) - } - - /// Create a simple perspective projection matrix - pub fn create_perspective(d: f32) -> Matrix4 { - Matrix4::new(1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, -1.0 / d, - 0.0, 0.0, 0.0, 1.0) - } -} +#[cfg_attr(feature = "unstable", deprecated(note = "Use matrix4d::Matrix4D instead"))] +pub type Matrix4 = Matrix4D; #[test] pub fn test_ortho() { diff --git a/src/matrix4d.rs b/src/matrix4d.rs new file mode 100644 index 0000000..20cf8a4 --- /dev/null +++ b/src/matrix4d.rs @@ -0,0 +1,350 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use approxeq::ApproxEq; +use trig::Trig; +use point::{Point2D, Point4D}; +use num::{One, Zero}; +use std::ops::{Add, Mul, Sub, Div, Neg}; + +#[derive(Debug, Copy, Clone, PartialEq)] +#[cfg_attr(feature = "plugins", derive(HeapSizeOf, Deserialize, Serialize))] +pub struct Matrix4D { + pub m11: T, pub m12: T, pub m13: T, pub m14: T, + pub m21: T, pub m22: T, pub m23: T, pub m24: T, + pub m31: T, pub m32: T, pub m33: T, pub m34: T, + pub m41: T, pub m42: T, pub m43: T, pub m44: T, +} + +impl + + ApproxEq + + Copy + + Clone + + Div + + Mul + + Neg + + One + + PartialOrd + + Sub + + Trig + + Zero> Matrix4D { + + #[inline] + pub fn new( + m11: T, m12: T, m13: T, m14: T, + m21: T, m22: T, m23: T, m24: T, + m31: T, m32: T, m33: T, m34: T, + m41: T, m42: T, m43: T, m44: T) + -> Matrix4D { + Matrix4D { + m11: m11, m12: m12, m13: m13, m14: m14, + m21: m21, m22: m22, m23: m23, m24: m24, + m31: m31, m32: m32, m33: m33, m34: m34, + m41: m41, m42: m42, m43: m43, m44: m44 + } + } + + pub fn ortho(left: T, right: T, + bottom: T, top: T, + near: T, far: T) -> Matrix4D { + let tx = -((right + left) / (right - left)); + let ty = -((top + bottom) / (top - bottom)); + let tz = -((far + near) / (far - near)); + + let (_0, _1): (T, T) = (Zero::zero(), One::one()); + let _2 = _1 + _1; + Matrix4D::new(_2 / (right - left), + _0, + _0, + _0, + + _0, + _2 / (top - bottom), + _0, + _0, + + _0, + _0, + -_2 / (far - near), + _0, + + tx, + ty, + tz, + _1) + } + + #[inline] + pub fn identity() -> Matrix4D { + let (_0, _1): (T, T) = (Zero::zero(), One::one()); + Matrix4D::new(_1, _0, _0, _0, + _0, _1, _0, _0, + _0, _0, _1, _0, + _0, _0, _0, _1) + } + + pub fn approx_eq(&self, other: &Matrix4D) -> bool { + self.m11.approx_eq(&other.m11) && self.m12.approx_eq(&other.m12) && + self.m13.approx_eq(&other.m13) && self.m14.approx_eq(&other.m14) && + self.m21.approx_eq(&other.m21) && self.m22.approx_eq(&other.m22) && + self.m23.approx_eq(&other.m23) && self.m24.approx_eq(&other.m24) && + self.m31.approx_eq(&other.m31) && self.m32.approx_eq(&other.m32) && + self.m33.approx_eq(&other.m33) && self.m34.approx_eq(&other.m34) && + self.m41.approx_eq(&other.m41) && self.m42.approx_eq(&other.m42) && + self.m43.approx_eq(&other.m43) && self.m44.approx_eq(&other.m44) + } + + pub fn mul(&self, m: &Matrix4D) -> Matrix4D { + Matrix4D::new(m.m11*self.m11 + m.m12*self.m21 + m.m13*self.m31 + m.m14*self.m41, + m.m11*self.m12 + m.m12*self.m22 + m.m13*self.m32 + m.m14*self.m42, + m.m11*self.m13 + m.m12*self.m23 + m.m13*self.m33 + m.m14*self.m43, + m.m11*self.m14 + m.m12*self.m24 + m.m13*self.m34 + m.m14*self.m44, + m.m21*self.m11 + m.m22*self.m21 + m.m23*self.m31 + m.m24*self.m41, + m.m21*self.m12 + m.m22*self.m22 + m.m23*self.m32 + m.m24*self.m42, + m.m21*self.m13 + m.m22*self.m23 + m.m23*self.m33 + m.m24*self.m43, + m.m21*self.m14 + m.m22*self.m24 + m.m23*self.m34 + m.m24*self.m44, + m.m31*self.m11 + m.m32*self.m21 + m.m33*self.m31 + m.m34*self.m41, + m.m31*self.m12 + m.m32*self.m22 + m.m33*self.m32 + m.m34*self.m42, + m.m31*self.m13 + m.m32*self.m23 + m.m33*self.m33 + m.m34*self.m43, + m.m31*self.m14 + m.m32*self.m24 + m.m33*self.m34 + m.m34*self.m44, + m.m41*self.m11 + m.m42*self.m21 + m.m43*self.m31 + m.m44*self.m41, + m.m41*self.m12 + m.m42*self.m22 + m.m43*self.m32 + m.m44*self.m42, + m.m41*self.m13 + m.m42*self.m23 + m.m43*self.m33 + m.m44*self.m43, + m.m41*self.m14 + m.m42*self.m24 + m.m43*self.m34 + m.m44*self.m44) + } + + pub fn invert(&self) -> Matrix4D { + let det = self.determinant(); + + if det == Zero::zero() { + return Matrix4D::identity(); + } + + // todo(gw): this could be made faster by special casing + // for simpler matrix types. + let m = Matrix4D::new( + self.m23*self.m34*self.m42 - self.m24*self.m33*self.m42 + + self.m24*self.m32*self.m43 - self.m22*self.m34*self.m43 - + self.m23*self.m32*self.m44 + self.m22*self.m33*self.m44, + + self.m14*self.m33*self.m42 - self.m13*self.m34*self.m42 - + self.m14*self.m32*self.m43 + self.m12*self.m34*self.m43 + + self.m13*self.m32*self.m44 - self.m12*self.m33*self.m44, + + self.m13*self.m24*self.m42 - self.m14*self.m23*self.m42 + + self.m14*self.m22*self.m43 - self.m12*self.m24*self.m43 - + self.m13*self.m22*self.m44 + self.m12*self.m23*self.m44, + + self.m14*self.m23*self.m32 - self.m13*self.m24*self.m32 - + self.m14*self.m22*self.m33 + self.m12*self.m24*self.m33 + + self.m13*self.m22*self.m34 - self.m12*self.m23*self.m34, + + self.m24*self.m33*self.m41 - self.m23*self.m34*self.m41 - + self.m24*self.m31*self.m43 + self.m21*self.m34*self.m43 + + self.m23*self.m31*self.m44 - self.m21*self.m33*self.m44, + + self.m13*self.m34*self.m41 - self.m14*self.m33*self.m41 + + self.m14*self.m31*self.m43 - self.m11*self.m34*self.m43 - + self.m13*self.m31*self.m44 + self.m11*self.m33*self.m44, + + self.m14*self.m23*self.m41 - self.m13*self.m24*self.m41 - + self.m14*self.m21*self.m43 + self.m11*self.m24*self.m43 + + self.m13*self.m21*self.m44 - self.m11*self.m23*self.m44, + + self.m13*self.m24*self.m31 - self.m14*self.m23*self.m31 + + self.m14*self.m21*self.m33 - self.m11*self.m24*self.m33 - + self.m13*self.m21*self.m34 + self.m11*self.m23*self.m34, + + self.m22*self.m34*self.m41 - self.m24*self.m32*self.m41 + + self.m24*self.m31*self.m42 - self.m21*self.m34*self.m42 - + self.m22*self.m31*self.m44 + self.m21*self.m32*self.m44, + + self.m14*self.m32*self.m41 - self.m12*self.m34*self.m41 - + self.m14*self.m31*self.m42 + self.m11*self.m34*self.m42 + + self.m12*self.m31*self.m44 - self.m11*self.m32*self.m44, + + self.m12*self.m24*self.m41 - self.m14*self.m22*self.m41 + + self.m14*self.m21*self.m42 - self.m11*self.m24*self.m42 - + self.m12*self.m21*self.m44 + self.m11*self.m22*self.m44, + + self.m14*self.m22*self.m31 - self.m12*self.m24*self.m31 - + self.m14*self.m21*self.m32 + self.m11*self.m24*self.m32 + + self.m12*self.m21*self.m34 - self.m11*self.m22*self.m34, + + self.m23*self.m32*self.m41 - self.m22*self.m33*self.m41 - + self.m23*self.m31*self.m42 + self.m21*self.m33*self.m42 + + self.m22*self.m31*self.m43 - self.m21*self.m32*self.m43, + + self.m12*self.m33*self.m41 - self.m13*self.m32*self.m41 + + self.m13*self.m31*self.m42 - self.m11*self.m33*self.m42 - + self.m12*self.m31*self.m43 + self.m11*self.m32*self.m43, + + self.m13*self.m22*self.m41 - self.m12*self.m23*self.m41 - + self.m13*self.m21*self.m42 + self.m11*self.m23*self.m42 + + self.m12*self.m21*self.m43 - self.m11*self.m22*self.m43, + + self.m12*self.m23*self.m31 - self.m13*self.m22*self.m31 + + self.m13*self.m21*self.m32 - self.m11*self.m23*self.m32 - + self.m12*self.m21*self.m33 + self.m11*self.m22*self.m33 + ); + + let _1: T = One::one(); + m.mul_s(_1 / det) + } + + pub fn determinant(&self) -> T { + self.m14 * self.m23 * self.m32 * self.m41 - + self.m13 * self.m24 * self.m32 * self.m41 - + self.m14 * self.m22 * self.m33 * self.m41 + + self.m12 * self.m24 * self.m33 * self.m41 + + self.m13 * self.m22 * self.m34 * self.m41 - + self.m12 * self.m23 * self.m34 * self.m41 - + self.m14 * self.m23 * self.m31 * self.m42 + + self.m13 * self.m24 * self.m31 * self.m42 + + self.m14 * self.m21 * self.m33 * self.m42 - + self.m11 * self.m24 * self.m33 * self.m42 - + self.m13 * self.m21 * self.m34 * self.m42 + + self.m11 * self.m23 * self.m34 * self.m42 + + self.m14 * self.m22 * self.m31 * self.m43 - + self.m12 * self.m24 * self.m31 * self.m43 - + self.m14 * self.m21 * self.m32 * self.m43 + + self.m11 * self.m24 * self.m32 * self.m43 + + self.m12 * self.m21 * self.m34 * self.m43 - + self.m11 * self.m22 * self.m34 * self.m43 - + self.m13 * self.m22 * self.m31 * self.m44 + + self.m12 * self.m23 * self.m31 * self.m44 + + self.m13 * self.m21 * self.m32 * self.m44 - + self.m11 * self.m23 * self.m32 * self.m44 - + self.m12 * self.m21 * self.m33 * self.m44 + + self.m11 * self.m22 * self.m33 * self.m44 + } + + pub fn mul_s(&self, x: T) -> Matrix4D { + Matrix4D::new(self.m11 * x, self.m12 * x, self.m13 * x, self.m14 * x, + self.m21 * x, self.m22 * x, self.m23 * x, self.m24 * x, + self.m31 * x, self.m32 * x, self.m33 * x, self.m34 * x, + self.m41 * x, self.m42 * x, self.m43 * x, self.m44 * x) + } + + pub fn scale(&self, x: T, y: T, z: T) -> Matrix4D { + Matrix4D::new(self.m11 * x, self.m12, self.m13, self.m14, + self.m21 , self.m22 * y, self.m23, self.m24, + self.m31 , self.m32, self.m33 * z, self.m34, + self.m41 , self.m42, self.m43, self.m44) + } + + /// Returns the given point transformed by this matrix. + #[inline] + pub fn transform_point(&self, p: &Point2D) -> Point2D { + Point2D::new(p.x * self.m11 + p.y * self.m21 + self.m41, + p.x * self.m12 + p.y * self.m22 + self.m42) + } + + #[inline] + pub fn transform_point4d(&self, p: &Point4D) -> Point4D { + let x = p.x * self.m11 + p.y * self.m21 + p.z * self.m31 + self.m41; + let y = p.x * self.m12 + p.y * self.m22 + p.z * self.m32 + self.m42; + let z = p.x * self.m13 + p.y * self.m23 + p.z * self.m33 + self.m43; + let w = p.x * self.m14 + p.y * self.m24 + p.z * self.m34 + self.m44; + Point4D::new(x, y, z, w) + } + + pub fn to_array(&self) -> [T; 16] { + [ + self.m11, self.m12, self.m13, self.m14, + self.m21, self.m22, self.m23, self.m24, + self.m31, self.m32, self.m33, self.m34, + self.m41, self.m42, self.m43, self.m44 + ] + } + + pub fn translate(&self, x: T, y: T, z: T) -> Matrix4D { + let (_0, _1): (T, T) = (Zero::zero(), One::one()); + let matrix = Matrix4D::new(_1, _0, _0, _0, + _0, _1, _0, _0, + _0, _0, _1, _0, + x, y, z, _1); + self.mul(&matrix) + } + + /// Create a 3d translation matrix + pub fn create_translation(x: T, y: T, z: T) -> Matrix4D { + let (_0, _1): (T, T) = (Zero::zero(), One::one()); + Matrix4D::new(_1, _0, _0, _0, + _0, _1, _0, _0, + _0, _0, _1, _0, + x, y, z, _1) + } + + /// Create a 3d scale matrix + pub fn create_scale(x: T, y: T, z: T) -> Matrix4D { + let (_0, _1): (T, T) = (Zero::zero(), One::one()); + Matrix4D::new( x, _0, _0, _0, + _0, y, _0, _0, + _0, _0, z, _0, + _0, _0, _0, _1) + } + + /// Create a 3d rotation matrix from an angle / axis. + /// The supplied axis must be normalized. + pub fn create_rotation(x: T, y: T, z: T, theta: T) -> Matrix4D { + let (_0, _1): (T, T) = (Zero::zero(), One::one()); + let _2 = _1 + _1; + + let xx = x * x; + let yy = y * y; + let zz = z * z; + + let half_theta = theta / _2; + let sc = half_theta.sin() * half_theta.cos(); + let sq = half_theta.sin() * half_theta.sin(); + + Matrix4D::new( + _1 - _2 * (yy + zz) * sq, + _2 * (x * y * sq - z * sc), + _2 * (x * z * sq + y * sc), + _0, + + _2 * (x * y * sq + z * sc), + _1 - _2 * (xx + zz) * sq, + _2 * (y * z * sq - x * sc), + _0, + + _2 * (x * z * sq - y * sc), + _2 * (y * z * sq + x * sc), + _1 - _2 * (xx + yy) * sq, + _0, + + _0, + _0, + _0, + _1 + ) + } + + /// Create a 2d skew matrix. + /// https://drafts.csswg.org/css-transforms/#funcdef-skew + pub fn create_skew(alpha: T, beta: T) -> Matrix4D { + let (_0, _1): (T, T) = (Zero::zero(), One::one()); + let (sx, sy) = (beta.tan(), alpha.tan()); + Matrix4D::new(_1, sx, _0, _0, + sy, _1, _0, _0, + _0, _0, _1, _0, + _0, _0, _0, _1) + } + + /// Create a simple perspective projection matrix + pub fn create_perspective(d: T) -> Matrix4D { + let (_0, _1): (T, T) = (Zero::zero(), One::one()); + Matrix4D::new(_1, _0, _0, _0, + _0, _1, _0, _0, + _0, _0, _1, -_1 / d, + _0, _0, _0, _1) + } +} diff --git a/src/trig.rs b/src/trig.rs new file mode 100644 index 0000000..6f3f348 --- /dev/null +++ b/src/trig.rs @@ -0,0 +1,50 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +/// Trait for basic trigonometry functions, so they can be used on generic numeric types +pub trait Trig { + fn sin(self) -> Self; + fn cos(self) -> Self; + fn tan(self) -> Self; +} + +impl Trig for f32 { + #[inline] + fn sin(self) -> f32 { + self.sin() + } + + #[inline] + fn cos(self) -> f32 { + self.cos() + } + + #[inline] + fn tan(self) -> f32 { + self.tan() + } +} + +impl Trig for f64 { + #[inline] + fn sin(self) -> f64 { + self.sin() + } + + #[inline] + fn cos(self) -> f64 { + self.cos() + } + + #[inline] + fn tan(self) -> f64 { + self.tan() + } +}