// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, // refer to the Cargo.toml file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Column major, square matrix types and traits. use std::fmt; use std::mem; use std::ops::*; use rand::{Rand, Rng}; use rust_num::{Zero, One}; use rust_num::traits::cast; use angle::{Rad, sin, cos, sin_cos}; use approx::ApproxEq; use array::{Array1, Array2}; use num::{BaseFloat, BaseNum}; use point::{Point, Point3}; use quaternion::Quaternion; use vector::{Vector, EuclideanVector}; use vector::{Vector2, Vector3, Vector4}; /// A 2 x 2, column major matrix #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)] pub struct Matrix2 { pub x: Vector2, pub y: Vector2 } /// A 3 x 3, column major matrix #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)] pub struct Matrix3 { pub x: Vector3, pub y: Vector3, pub z: Vector3 } /// A 4 x 4, column major matrix #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)] pub struct Matrix4 { pub x: Vector4, pub y: Vector4, pub z: Vector4, pub w: Vector4 } impl Matrix2 { /// Create a new matrix, providing values for each index. #[inline] pub fn new(c0r0: S, c0r1: S, c1r0: S, c1r1: S) -> Matrix2 { Matrix2::from_cols(Vector2::new(c0r0, c0r1), Vector2::new(c1r0, c1r1)) } /// Create a new matrix, providing columns. #[inline] pub fn from_cols(c0: Vector2, c1: Vector2) -> Matrix2 { Matrix2 { x: c0, y: c1 } } } impl Matrix2 { /// Create a transformation matrix that will cause a vector to point at /// `dir`, using `up` for orientation. pub fn look_at(dir: &Vector2, up: &Vector2) -> Matrix2 { //TODO: verify look_at 2D Matrix2::from_cols(up.clone(), dir.clone()).transpose() } #[inline] pub fn from_angle(theta: Rad) -> Matrix2 { let cos_theta = cos(theta.clone()); let sin_theta = sin(theta.clone()); Matrix2::new(cos_theta.clone(), sin_theta.clone(), -sin_theta.clone(), cos_theta.clone()) } } impl> Matrix2 { /// Negate this `Matrix2` in-place. #[inline] pub fn neg_self(&mut self) { self[0].neg_self(); self[1].neg_self(); } } impl Matrix3 { /// Create a new matrix, providing values for each index. #[inline] pub fn new(c0r0:S, c0r1:S, c0r2:S, c1r0:S, c1r1:S, c1r2:S, c2r0:S, c2r1:S, c2r2:S) -> Matrix3 { Matrix3::from_cols(Vector3::new(c0r0, c0r1, c0r2), Vector3::new(c1r0, c1r1, c1r2), Vector3::new(c2r0, c2r1, c2r2)) } /// Create a new matrix, providing columns. #[inline] pub fn from_cols(c0: Vector3, c1: Vector3, c2: Vector3) -> Matrix3 { Matrix3 { x: c0, y: c1, z: c2 } } } impl Matrix3 { /// Create a transformation matrix that will cause a vector to point at /// `dir`, using `up` for orientation. pub fn look_at(dir: &Vector3, up: &Vector3) -> Matrix3 { let dir = dir.normalize(); let side = up.cross(&dir).normalize(); let up = dir.cross(&side).normalize(); Matrix3::from_cols(side, up, dir).transpose() } /// Create a matrix from a rotation around the `x` axis (pitch). pub fn from_angle_x(theta: Rad) -> Matrix3 { // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations let (s, c) = sin_cos(theta); Matrix3::new(S::one(), S::zero(), S::zero(), S::zero(), c.clone(), s.clone(), S::zero(), -s.clone(), c.clone()) } /// Create a matrix from a rotation around the `y` axis (yaw). pub fn from_angle_y(theta: Rad) -> Matrix3 { // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations let (s, c) = sin_cos(theta); Matrix3::new(c.clone(), S::zero(), -s.clone(), S::zero(), S::one(), S::zero(), s.clone(), S::zero(), c.clone()) } /// Create a matrix from a rotation around the `z` axis (roll). pub fn from_angle_z(theta: Rad) -> Matrix3 { // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations let (s, c) = sin_cos(theta); Matrix3::new( c.clone(), s.clone(), S::zero(), -s.clone(), c.clone(), S::zero(), S::zero(), S::zero(), S::one()) } /// Create a matrix from a set of euler angles. /// /// # Parameters /// /// - `x`: the angular rotation around the `x` axis (pitch). /// - `y`: the angular rotation around the `y` axis (yaw). /// - `z`: the angular rotation around the `z` axis (roll). pub fn from_euler(x: Rad, y: Rad, z: Rad) -> Matrix3 { // http://en.wikipedia.org/wiki/Rotation_matrix#General_rotations let (sx, cx) = sin_cos(x); let (sy, cy) = sin_cos(y); let (sz, cz) = sin_cos(z); Matrix3::new( cy * cz, cy * sz, -sy, -cx * sz + sx * sy * cz, cx * cz + sx * sy * sz, sx * cy, sx * sz + cx * sy * cz, -sx * cz + cx * sy * sz, cx * cy) } /// Create a matrix from a rotation around an arbitrary axis pub fn from_axis_angle(axis: &Vector3, angle: Rad) -> Matrix3 { let (s, c) = sin_cos(angle); let _1subc = S::one() - c; Matrix3::new(_1subc * axis.x * axis.x + c, _1subc * axis.x * axis.y + s * axis.z, _1subc * axis.x * axis.z - s * axis.y, _1subc * axis.x * axis.y - s * axis.z, _1subc * axis.y * axis.y + c, _1subc * axis.y * axis.z + s * axis.x, _1subc * axis.x * axis.z + s * axis.y, _1subc * axis.y * axis.z - s * axis.x, _1subc * axis.z * axis.z + c) } } impl> Matrix3 { /// Negate this `Matrix3` in-place. #[inline] pub fn neg_self(&mut self) { self[0].neg_self(); self[1].neg_self(); self[2].neg_self(); } } impl Matrix4 { /// Create a new matrix, providing values for each index. #[inline] pub fn new(c0r0: S, c0r1: S, c0r2: S, c0r3: S, c1r0: S, c1r1: S, c1r2: S, c1r3: S, c2r0: S, c2r1: S, c2r2: S, c2r3: S, c3r0: S, c3r1: S, c3r2: S, c3r3: S) -> Matrix4 { Matrix4::from_cols(Vector4::new(c0r0, c0r1, c0r2, c0r3), Vector4::new(c1r0, c1r1, c1r2, c1r3), Vector4::new(c2r0, c2r1, c2r2, c2r3), Vector4::new(c3r0, c3r1, c3r2, c3r3)) } /// Create a new matrix, providing columns. #[inline] pub fn from_cols(c0: Vector4, c1: Vector4, c2: Vector4, c3: Vector4) -> Matrix4 { Matrix4 { x: c0, y: c1, z: c2, w: c3 } } } impl Matrix4 { /// Create a translation matrix from a Vector3 #[inline] pub fn from_translation(v: &Vector3) -> Matrix4 { Matrix4::new(S::one(), S::zero(), S::zero(), S::zero(), S::zero(), S::one(), S::zero(), S::zero(), S::zero(), S::zero(), S::one(), S::zero(), v.x, v.y, v.z, S::one()) } } impl Matrix4 { /// Create a transformation matrix that will cause a vector to point at /// `dir`, using `up` for orientation. pub fn look_at(eye: &Point3, center: &Point3, up: &Vector3) -> Matrix4 { let f = (center - eye).normalize(); let s = f.cross(up).normalize(); let u = s.cross(&f); Matrix4::new(s.x.clone(), u.x.clone(), -f.x.clone(), S::zero(), s.y.clone(), u.y.clone(), -f.y.clone(), S::zero(), s.z.clone(), u.z.clone(), -f.z.clone(), S::zero(), -eye.dot(&s), -eye.dot(&u), eye.dot(&f), S::one()) } } impl> Matrix4 { /// Negate this `Matrix4` in-place. #[inline] pub fn neg_self(&mut self) { self[0].neg_self(); self[1].neg_self(); self[2].neg_self(); self[3].neg_self(); } } pub trait Matrix where Self: Array2< Element = <::ColumnRow as Vector>::Scalar, Column = ::ColumnRow, Row = ::ColumnRow, >, Self: ApproxEq::ColumnRow as Vector>::Scalar> + Sized, Self::Element: BaseFloat, // FIXME: blocked by rust-lang/rust#20671 // // for<'a, 'b> &'a Self: Add<&'b Self, Output = Self>, // for<'a, 'b> &'a Self: Sub<&'b Self, Output = Self>, // for<'a, 'b> &'a Self: Mul<&'b Self, Output = Self>, // for<'a, 'b> &'a Self: Mul<&'b V, Output = V>, // // for<'a> &'a Self: Mul, // for<'a> &'a Self: Div, // for<'a> &'a Self: Rem, { type ColumnRow: Vector; /// Create a new diagonal matrix using the supplied value. fn from_value(value: Self::Element) -> Self; /// Create a matrix from a non-uniform scale fn from_diagonal(diagonal: &Self::Column) -> Self; /// Create a matrix with all elements equal to zero. #[inline] fn zero() -> Self { Self::from_value(Self::Element::zero()) } /// Create a matrix where the each element of the diagonal is equal to one. #[inline] fn one() -> Self { Self::from_value(Self::Element::one()) } /// Multiply this matrix by a scalar, returning the new matrix. #[must_use] fn mul_s(&self, s: Self::Element) -> Self; /// Divide this matrix by a scalar, returning the new matrix. #[must_use] fn div_s(&self, s: Self::Element) -> Self; /// Take the remainder of this matrix by a scalar, returning the new /// matrix. #[must_use] fn rem_s(&self, s: Self::Element) -> Self; /// Add this matrix with another matrix, returning the new metrix. #[must_use] fn add_m(&self, m: &Self) -> Self; /// Subtract another matrix from this matrix, returning the new matrix. #[must_use] fn sub_m(&self, m: &Self) -> Self; /// Multiplay a vector by this matrix, returning a new vector. fn mul_v(&self, v: &Self::Column) -> Self::Column; /// Multiply this matrix by another matrix, returning the new matrix. #[must_use] fn mul_m(&self, m: &Self) -> Self; /// Multiply this matrix by a scalar, in-place. fn mul_self_s(&mut self, s: Self::Element); /// Divide this matrix by a scalar, in-place. fn div_self_s(&mut self, s: Self::Element); /// Take the remainder of this matrix, in-place. fn rem_self_s(&mut self, s: Self::Element); /// Add this matrix with another matrix, in-place. fn add_self_m(&mut self, m: &Self); /// Subtract another matrix from this matrix, in-place. fn sub_self_m(&mut self, m: &Self); /// Multiply this matrix by another matrix, in-place. #[inline] fn mul_self_m(&mut self, m: &Self) { *self = self.mul_m(m); } /// Transpose this matrix, returning a new matrix. #[must_use] fn transpose(&self) -> Self; /// Transpose this matrix in-place. fn transpose_self(&mut self); /// Take the determinant of this matrix. fn determinant(&self) -> Self::Element; /// Return a vector containing the diagonal of this matrix. fn diagonal(&self) -> Self::Column; /// Return the trace of this matrix. That is, the sum of the diagonal. #[inline] fn trace(&self) -> Self::Element { self.diagonal().sum() } /// Invert this matrix, returning a new matrix. `m.mul_m(m.invert())` is /// the identity matrix. Returns `None` if this matrix is not invertible /// (has a determinant of zero). #[must_use] fn invert(&self) -> Option; /// Invert this matrix in-place. #[inline] fn invert_self(&mut self) { *self = self.invert().expect("Attempted to invert a matrix with zero determinant."); } /// Test if this matrix is invertible. #[inline] fn is_invertible(&self) -> bool { !self.determinant().approx_eq(&Self::Element::zero()) } /// Test if this matrix is the identity matrix. That is, it is diagonal /// and every element in the diagonal is one. #[inline] fn is_one(&self) -> bool { self.approx_eq(&Self::one()) } /// Test if this is a diagonal matrix. That is, every element outside of /// the diagonal is 0. fn is_diagonal(&self) -> bool; /// Test if this matrix is symmetric. That is, it is equal to its /// transpose. fn is_symmetric(&self) -> bool; } impl Array2 for Matrix2 { type Element = S; type Column = Vector2; type Row = Vector2; #[inline] fn row(&self, r: usize) -> Vector2 { Vector2::new(self[0][r], self[1][r]) } #[inline] fn swap_rows(&mut self, a: usize, b: usize) { self[0].swap_elems(a, b); self[1].swap_elems(a, b); } } impl Array2 for Matrix3 { type Element = S; type Column = Vector3; type Row = Vector3; #[inline] fn row(&self, r: usize) -> Vector3 { Vector3::new(self[0][r], self[1][r], self[2][r]) } #[inline] fn swap_rows(&mut self, a: usize, b: usize) { self[0].swap_elems(a, b); self[1].swap_elems(a, b); self[2].swap_elems(a, b); } } impl Array2 for Matrix4 { type Element = S; type Column = Vector4; type Row = Vector4; #[inline] fn row(&self, r: usize) -> Vector4 { Vector4::new(self[0][r], self[1][r], self[2][r], self[3][r]) } #[inline] fn swap_rows(&mut self, a: usize, b: usize) { self[0].swap_elems(a, b); self[1].swap_elems(a, b); self[2].swap_elems(a, b); self[3].swap_elems(a, b); } } impl Matrix for Matrix2 { type ColumnRow = Vector2; #[inline] fn from_value(value: S) -> Matrix2 { Matrix2::new(value, S::zero(), S::zero(), value) } #[inline] fn from_diagonal(value: &Vector2) -> Matrix2 { Matrix2::new(value.x, S::zero(), S::zero(), value.y) } #[inline] fn mul_s(&self, s: S) -> Matrix2 { self * s } #[inline] fn div_s(&self, s: S) -> Matrix2 { self / s } #[inline] fn rem_s(&self, s: S) -> Matrix2 { self % s } #[inline] fn add_m(&self, m: &Matrix2) -> Matrix2 { self + m } #[inline] fn sub_m(&self, m: &Matrix2) -> Matrix2 { self - m } fn mul_m(&self, other: &Matrix2) -> Matrix2 { self * other } #[inline] fn mul_v(&self, v: &Vector2) -> Vector2 { self * v } #[inline] fn mul_self_s(&mut self, s: S) { self[0].mul_self_s(s); self[1].mul_self_s(s); } #[inline] fn div_self_s(&mut self, s: S) { self[0].div_self_s(s); self[1].div_self_s(s); } #[inline] fn rem_self_s(&mut self, s: S) { self[0].rem_self_s(s); self[1].rem_self_s(s); } #[inline] fn add_self_m(&mut self, m: &Matrix2) { self[0].add_self_v(&m[0]); self[1].add_self_v(&m[1]); } #[inline] fn sub_self_m(&mut self, m: &Matrix2) { self[0].sub_self_v(&m[0]); self[1].sub_self_v(&m[1]); } fn transpose(&self) -> Matrix2 { Matrix2::new(self[0][0], self[1][0], self[0][1], self[1][1]) } #[inline] fn transpose_self(&mut self) { self.swap_elems((0, 1), (1, 0)); } #[inline] fn determinant(&self) -> S { self[0][0] * self[1][1] - self[1][0] * self[0][1] } #[inline] fn diagonal(&self) -> Vector2 { Vector2::new(self[0][0], self[1][1]) } #[inline] fn invert(&self) -> Option> { let det = self.determinant(); if det.approx_eq(&S::zero()) { None } else { Some(Matrix2::new( self[1][1] / det, -self[0][1] / det, -self[1][0] / det, self[0][0] / det)) } } #[inline] fn is_diagonal(&self) -> bool { self[0][1].approx_eq(&S::zero()) && self[1][0].approx_eq(&S::zero()) } #[inline] fn is_symmetric(&self) -> bool { self[0][1].approx_eq(&self[1][0]) && self[1][0].approx_eq(&self[0][1]) } } impl Matrix for Matrix3 { type ColumnRow = Vector3; #[inline] fn from_value(value: S) -> Matrix3 { Matrix3::new(value, S::zero(), S::zero(), S::zero(), value, S::zero(), S::zero(), S::zero(), value) } #[inline] fn from_diagonal(value: &Vector3) -> Matrix3 { Matrix3::new(value.x, S::zero(), S::zero(), S::zero(), value.y, S::zero(), S::zero(), S::zero(), value.z) } #[inline] fn mul_s(&self, s: S) -> Matrix3 { self * s } #[inline] fn div_s(&self, s: S) -> Matrix3 { self / s } #[inline] fn rem_s(&self, s: S) -> Matrix3 { self % s } #[inline] fn add_m(&self, m: &Matrix3) -> Matrix3 { self + m } #[inline] fn sub_m(&self, m: &Matrix3) -> Matrix3 { self - m } fn mul_m(&self, other: &Matrix3) -> Matrix3 { self * other } #[inline] fn mul_v(&self, v: &Vector3) -> Vector3 { self * v} #[inline] fn mul_self_s(&mut self, s: S) { self[0].mul_self_s(s); self[1].mul_self_s(s); self[2].mul_self_s(s); } #[inline] fn div_self_s(&mut self, s: S) { self[0].div_self_s(s); self[1].div_self_s(s); self[2].div_self_s(s); } #[inline] fn rem_self_s(&mut self, s: S) { self[0].rem_self_s(s); self[1].rem_self_s(s); self[2].rem_self_s(s); } #[inline] fn add_self_m(&mut self, m: &Matrix3) { self[0].add_self_v(&m[0]); self[1].add_self_v(&m[1]); self[2].add_self_v(&m[2]); } #[inline] fn sub_self_m(&mut self, m: &Matrix3) { self[0].sub_self_v(&m[0]); self[1].sub_self_v(&m[1]); self[2].sub_self_v(&m[2]); } fn transpose(&self) -> Matrix3 { Matrix3::new(self[0][0], self[1][0], self[2][0], self[0][1], self[1][1], self[2][1], self[0][2], self[1][2], self[2][2]) } #[inline] fn transpose_self(&mut self) { self.swap_elems((0, 1), (1, 0)); self.swap_elems((0, 2), (2, 0)); self.swap_elems((1, 2), (2, 1)); } fn determinant(&self) -> S { self[0][0] * (self[1][1] * self[2][2] - self[2][1] * self[1][2]) - self[1][0] * (self[0][1] * self[2][2] - self[2][1] * self[0][2]) + self[2][0] * (self[0][1] * self[1][2] - self[1][1] * self[0][2]) } #[inline] fn diagonal(&self) -> Vector3 { Vector3::new(self[0][0], self[1][1], self[2][2]) } fn invert(&self) -> Option> { let det = self.determinant(); if det.approx_eq(&S::zero()) { None } else { Some(Matrix3::from_cols(&self[1].cross(&self[2]) / det, &self[2].cross(&self[0]) / det, &self[0].cross(&self[1]) / det).transpose()) } } fn is_diagonal(&self) -> bool { self[0][1].approx_eq(&S::zero()) && self[0][2].approx_eq(&S::zero()) && self[1][0].approx_eq(&S::zero()) && self[1][2].approx_eq(&S::zero()) && self[2][0].approx_eq(&S::zero()) && self[2][1].approx_eq(&S::zero()) } fn is_symmetric(&self) -> bool { self[0][1].approx_eq(&self[1][0]) && self[0][2].approx_eq(&self[2][0]) && self[1][0].approx_eq(&self[0][1]) && self[1][2].approx_eq(&self[2][1]) && self[2][0].approx_eq(&self[0][2]) && self[2][1].approx_eq(&self[1][2]) } } impl Matrix for Matrix4 { type ColumnRow = Vector4; #[inline] fn from_value(value: S) -> Matrix4 { Matrix4::new(value, S::zero(), S::zero(), S::zero(), S::zero(), value, S::zero(), S::zero(), S::zero(), S::zero(), value, S::zero(), S::zero(), S::zero(), S::zero(), value) } #[inline] fn from_diagonal(value: &Vector4) -> Matrix4 { Matrix4::new(value.x, S::zero(), S::zero(), S::zero(), S::zero(), value.y, S::zero(), S::zero(), S::zero(), S::zero(), value.z, S::zero(), S::zero(), S::zero(), S::zero(), value.w) } #[inline] fn mul_s(&self, s: S) -> Matrix4 { self * s } #[inline] fn div_s(&self, s: S) -> Matrix4 { self / s } #[inline] fn rem_s(&self, s: S) -> Matrix4 { self % s } #[inline] fn add_m(&self, m: &Matrix4) -> Matrix4 { self + m } #[inline] fn sub_m(&self, m: &Matrix4) -> Matrix4 { self - m } fn mul_m(&self, other: &Matrix4) -> Matrix4 { self * other } #[inline] fn mul_v(&self, v: &Vector4) -> Vector4 { self * v } #[inline] fn mul_self_s(&mut self, s: S) { self[0].mul_self_s(s); self[1].mul_self_s(s); self[2].mul_self_s(s); self[3].mul_self_s(s); } #[inline] fn div_self_s(&mut self, s: S) { self[0].div_self_s(s); self[1].div_self_s(s); self[2].div_self_s(s); self[3].div_self_s(s); } #[inline] fn rem_self_s(&mut self, s: S) { self[0].rem_self_s(s); self[1].rem_self_s(s); self[2].rem_self_s(s); self[3].rem_self_s(s); } #[inline] fn add_self_m(&mut self, m: &Matrix4) { self[0].add_self_v(&m[0]); self[1].add_self_v(&m[1]); self[2].add_self_v(&m[2]); self[3].add_self_v(&m[3]); } #[inline] fn sub_self_m(&mut self, m: &Matrix4) { self[0].sub_self_v(&m[0]); self[1].sub_self_v(&m[1]); self[2].sub_self_v(&m[2]); self[3].sub_self_v(&m[3]); } fn transpose(&self) -> Matrix4 { Matrix4::new(self[0][0], self[1][0], self[2][0], self[3][0], self[0][1], self[1][1], self[2][1], self[3][1], self[0][2], self[1][2], self[2][2], self[3][2], self[0][3], self[1][3], self[2][3], self[3][3]) } fn transpose_self(&mut self) { self.swap_elems((0, 1), (1, 0)); self.swap_elems((0, 2), (2, 0)); self.swap_elems((0, 3), (3, 0)); self.swap_elems((1, 2), (2, 1)); self.swap_elems((1, 3), (3, 1)); self.swap_elems((2, 3), (3, 2)); } fn determinant(&self) -> S { let m0 = Matrix3::new(self[1][1], self[2][1], self[3][1], self[1][2], self[2][2], self[3][2], self[1][3], self[2][3], self[3][3]); let m1 = Matrix3::new(self[0][1], self[2][1], self[3][1], self[0][2], self[2][2], self[3][2], self[0][3], self[2][3], self[3][3]); let m2 = Matrix3::new(self[0][1], self[1][1], self[3][1], self[0][2], self[1][2], self[3][2], self[0][3], self[1][3], self[3][3]); let m3 = Matrix3::new(self[0][1], self[1][1], self[2][1], self[0][2], self[1][2], self[2][2], self[0][3], self[1][3], self[2][3]); self[0][0] * m0.determinant() - self[1][0] * m1.determinant() + self[2][0] * m2.determinant() - self[3][0] * m3.determinant() } #[inline] fn diagonal(&self) -> Vector4 { Vector4::new(self[0][0], self[1][1], self[2][2], self[3][3]) } fn invert(&self) -> Option> { let det = self.determinant(); if det.approx_eq(&S::zero()) { None } else { let inv_det = S::one() / det; let t = self.transpose(); let cf = |i, j| { let mat = match i { 0 => Matrix3::from_cols(t.y.truncate_n(j), t.z.truncate_n(j), t.w.truncate_n(j)), 1 => Matrix3::from_cols(t.x.truncate_n(j), t.z.truncate_n(j), t.w.truncate_n(j)), 2 => Matrix3::from_cols(t.x.truncate_n(j), t.y.truncate_n(j), t.w.truncate_n(j)), 3 => Matrix3::from_cols(t.x.truncate_n(j), t.y.truncate_n(j), t.z.truncate_n(j)), _ => panic!("out of range"), }; let sign = if (i + j) & 1 == 1 { -S::one() } else { S::one() }; mat.determinant() * sign * inv_det }; Some(Matrix4::new(cf(0, 0), cf(0, 1), cf(0, 2), cf(0, 3), cf(1, 0), cf(1, 1), cf(1, 2), cf(1, 3), cf(2, 0), cf(2, 1), cf(2, 2), cf(2, 3), cf(3, 0), cf(3, 1), cf(3, 2), cf(3, 3))) } } fn is_diagonal(&self) -> bool { self[0][1].approx_eq(&S::zero()) && self[0][2].approx_eq(&S::zero()) && self[0][3].approx_eq(&S::zero()) && self[1][0].approx_eq(&S::zero()) && self[1][2].approx_eq(&S::zero()) && self[1][3].approx_eq(&S::zero()) && self[2][0].approx_eq(&S::zero()) && self[2][1].approx_eq(&S::zero()) && self[2][3].approx_eq(&S::zero()) && self[3][0].approx_eq(&S::zero()) && self[3][1].approx_eq(&S::zero()) && self[3][2].approx_eq(&S::zero()) } fn is_symmetric(&self) -> bool { self[0][1].approx_eq(&self[1][0]) && self[0][2].approx_eq(&self[2][0]) && self[0][3].approx_eq(&self[3][0]) && self[1][0].approx_eq(&self[0][1]) && self[1][2].approx_eq(&self[2][1]) && self[1][3].approx_eq(&self[3][1]) && self[2][0].approx_eq(&self[0][2]) && self[2][1].approx_eq(&self[1][2]) && self[2][3].approx_eq(&self[3][2]) && self[3][0].approx_eq(&self[0][3]) && self[3][1].approx_eq(&self[1][3]) && self[3][2].approx_eq(&self[2][3]) } } impl ApproxEq for Matrix2 { type Epsilon = S; #[inline] fn approx_eq_eps(&self, other: &Matrix2, epsilon: &S) -> bool { self[0].approx_eq_eps(&other[0], epsilon) && self[1].approx_eq_eps(&other[1], epsilon) } } impl ApproxEq for Matrix3 { type Epsilon = S; #[inline] fn approx_eq_eps(&self, other: &Matrix3, epsilon: &S) -> bool { self[0].approx_eq_eps(&other[0], epsilon) && self[1].approx_eq_eps(&other[1], epsilon) && self[2].approx_eq_eps(&other[2], epsilon) } } impl ApproxEq for Matrix4 { type Epsilon = S; #[inline] fn approx_eq_eps(&self, other: &Matrix4, epsilon: &S) -> bool { self[0].approx_eq_eps(&other[0], epsilon) && self[1].approx_eq_eps(&other[1], epsilon) && self[2].approx_eq_eps(&other[2], epsilon) && self[3].approx_eq_eps(&other[3], epsilon) } } impl> Neg for Matrix2 { type Output = Matrix2; #[inline] fn neg(self) -> Matrix2 { Matrix2::from_cols(-self.x, -self.y) } } impl> Neg for Matrix3 { type Output = Matrix3; #[inline] fn neg(self) -> Matrix3 { Matrix3::from_cols(-self.x, -self.y, -self.z) } } impl> Neg for Matrix4 { type Output = Matrix4; #[inline] fn neg(self) -> Matrix4 { Matrix4::from_cols(-self.x, -self.y, -self.z, -self.w) } } macro_rules! impl_scalar_binary_operator { ($Binop:ident :: $binop:ident, $MatrixN:ident { $($field:ident),+ }) => { impl<'a, S: BaseNum> $Binop for &'a $MatrixN { type Output = $MatrixN; #[inline] fn $binop(self, s: S) -> $MatrixN { $MatrixN { $($field: self.$field.$binop(s)),+ } } } } } impl_scalar_binary_operator!(Mul::mul, Matrix2 { x, y }); impl_scalar_binary_operator!(Mul::mul, Matrix3 { x, y, z }); impl_scalar_binary_operator!(Mul::mul, Matrix4 { x, y, z, w }); impl_scalar_binary_operator!(Div::div, Matrix2 { x, y }); impl_scalar_binary_operator!(Div::div, Matrix3 { x, y, z }); impl_scalar_binary_operator!(Div::div, Matrix4 { x, y, z, w }); impl_scalar_binary_operator!(Rem::rem, Matrix2 { x, y }); impl_scalar_binary_operator!(Rem::rem, Matrix3 { x, y, z }); impl_scalar_binary_operator!(Rem::rem, Matrix4 { x, y, z, w }); macro_rules! impl_binary_operator { ($Binop:ident :: $binop:ident, $MatrixN:ident { $($field:ident),+ }) => { impl<'a, 'b, S: BaseNum> $Binop<&'a $MatrixN> for &'b $MatrixN { type Output = $MatrixN; #[inline] fn $binop(self, other: &'a $MatrixN) -> $MatrixN { $MatrixN { $($field: self.$field.$binop(&other.$field)),+ } } } } } impl_binary_operator!(Add::add, Matrix2 { x, y }); impl_binary_operator!(Add::add, Matrix3 { x, y, z }); impl_binary_operator!(Add::add, Matrix4 { x, y, z, w }); impl_binary_operator!(Sub::sub, Matrix2 { x, y }); impl_binary_operator!(Sub::sub, Matrix3 { x, y, z }); impl_binary_operator!(Sub::sub, Matrix4 { x, y, z, w }); impl<'a, 'b, S: BaseNum> Mul<&'a Vector2> for &'b Matrix2 { type Output = Vector2; fn mul(self, v: &'a Vector2) -> Vector2 { Vector2::new(self.row(0).dot(v), self.row(1).dot(v)) } } impl<'a, 'b, S: BaseNum> Mul<&'a Vector3> for &'b Matrix3 { type Output = Vector3; fn mul(self, v: &'a Vector3) -> Vector3 { Vector3::new(self.row(0).dot(v), self.row(1).dot(v), self.row(2).dot(v)) } } impl<'a, 'b, S: BaseNum> Mul<&'a Vector4> for &'b Matrix4 { type Output = Vector4; fn mul(self, v: &'a Vector4) -> Vector4 { Vector4::new(self.row(0).dot(v), self.row(1).dot(v), self.row(2).dot(v), self.row(3).dot(v)) } } impl<'a, 'b, S: BaseNum> Mul<&'a Matrix2> for &'b Matrix2 { type Output = Matrix2; fn mul(self, other: &'a Matrix2) -> Matrix2 { Matrix2::new(self.row(0).dot(&other[0]), self.row(1).dot(&other[0]), self.row(0).dot(&other[1]), self.row(1).dot(&other[1])) } } impl<'a, 'b, S: BaseNum> Mul<&'a Matrix3> for &'b Matrix3 { type Output = Matrix3; fn mul(self, other: &'a Matrix3) -> Matrix3 { Matrix3::new(self.row(0).dot(&other[0]),self.row(1).dot(&other[0]),self.row(2).dot(&other[0]), self.row(0).dot(&other[1]),self.row(1).dot(&other[1]),self.row(2).dot(&other[1]), self.row(0).dot(&other[2]),self.row(1).dot(&other[2]),self.row(2).dot(&other[2])) } } impl<'a, 'b, S: BaseNum> Mul<&'a Matrix4> for &'b Matrix4 { type Output = Matrix4; fn mul(self, other: &'a Matrix4) -> Matrix4 { // Using self.row(0).dot(other[0]) like the other matrix multiplies // causes the LLVM to miss identical loads and multiplies. This optimization // causes the code to be auto vectorized properly increasing the performance // around ~4 times. macro_rules! dot_matrix4 { ($A:expr, $B:expr, $I:expr, $J:expr) => { ($A[0][$I]) * ($B[$J][0]) + ($A[1][$I]) * ($B[$J][1]) + ($A[2][$I]) * ($B[$J][2]) + ($A[3][$I]) * ($B[$J][3]) }; }; Matrix4::new(dot_matrix4!(self, other, 0, 0), dot_matrix4!(self, other, 1, 0), dot_matrix4!(self, other, 2, 0), dot_matrix4!(self, other, 3, 0), dot_matrix4!(self, other, 0, 1), dot_matrix4!(self, other, 1, 1), dot_matrix4!(self, other, 2, 1), dot_matrix4!(self, other, 3, 1), dot_matrix4!(self, other, 0, 2), dot_matrix4!(self, other, 1, 2), dot_matrix4!(self, other, 2, 2), dot_matrix4!(self, other, 3, 2), dot_matrix4!(self, other, 0, 3), dot_matrix4!(self, other, 1, 3), dot_matrix4!(self, other, 2, 3), dot_matrix4!(self, other, 3, 3)) } } macro_rules! index_operators { ($MatrixN:ident<$S:ident>, $n:expr, $Output:ty, $I:ty) => { impl<$S> Index<$I> for $MatrixN<$S> { type Output = $Output; #[inline] fn index<'a>(&'a self, i: $I) -> &'a $Output { let v: &[[$S; $n]; $n] = self.as_ref(); From::from(&v[i]) } } impl<$S> IndexMut<$I> for $MatrixN<$S> { #[inline] fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output { let v: &mut [[$S; $n]; $n] = self.as_mut(); From::from(&mut v[i]) } } } } index_operators!(Matrix2, 2, Vector2, usize); index_operators!(Matrix3, 3, Vector3, usize); index_operators!(Matrix4, 4, Vector4, usize); // index_operators!(Matrix2, 2, [Vector2], Range); // index_operators!(Matrix3, 3, [Vector3], Range); // index_operators!(Matrix4, 4, [Vector4], Range); // index_operators!(Matrix2, 2, [Vector2], RangeTo); // index_operators!(Matrix3, 3, [Vector3], RangeTo); // index_operators!(Matrix4, 4, [Vector4], RangeTo); // index_operators!(Matrix2, 2, [Vector2], RangeFrom); // index_operators!(Matrix3, 3, [Vector3], RangeFrom); // index_operators!(Matrix4, 4, [Vector4], RangeFrom); // index_operators!(Matrix2, 2, [Vector2], RangeFull); // index_operators!(Matrix3, 3, [Vector3], RangeFull); // index_operators!(Matrix4, 4, [Vector4], RangeFull); macro_rules! fixed_array_conversions { ($MatrixN:ident <$S:ident> { $($field:ident : $index:expr),+ }, $n:expr) => { impl<$S> Into<[[$S; $n]; $n]> for $MatrixN<$S> { #[inline] fn into(self) -> [[$S; $n]; $n] { match self { $MatrixN { $($field),+ } => [$($field.into()),+] } } } impl<$S> AsRef<[[$S; $n]; $n]> for $MatrixN<$S> { #[inline] fn as_ref(&self) -> &[[$S; $n]; $n] { unsafe { mem::transmute(self) } } } impl<$S> AsMut<[[$S; $n]; $n]> for $MatrixN<$S> { #[inline] fn as_mut(&mut self) -> &mut [[$S; $n]; $n] { unsafe { mem::transmute(self) } } } impl<$S: Copy> From<[[$S; $n]; $n]> for $MatrixN<$S> { #[inline] fn from(m: [[$S; $n]; $n]) -> $MatrixN<$S> { // We need to use a copy here because we can't pattern match on arrays yet $MatrixN { $($field: From::from(m[$index])),+ } } } impl<'a, $S> From<&'a [[$S; $n]; $n]> for &'a $MatrixN<$S> { #[inline] fn from(m: &'a [[$S; $n]; $n]) -> &'a $MatrixN<$S> { unsafe { mem::transmute(m) } } } impl<'a, $S> From<&'a mut [[$S; $n]; $n]> for &'a mut $MatrixN<$S> { #[inline] fn from(m: &'a mut [[$S; $n]; $n]) -> &'a mut $MatrixN<$S> { unsafe { mem::transmute(m) } } } // impl<$S> Into<[$S; ($n * $n)]> for $MatrixN<$S> { // #[inline] // fn into(self) -> [[$S; $n]; $n] { // // TODO: Not sure how to implement this... // unimplemented!() // } // } impl<$S> AsRef<[$S; ($n * $n)]> for $MatrixN<$S> { #[inline] fn as_ref(&self) -> &[$S; ($n * $n)] { unsafe { mem::transmute(self) } } } impl<$S> AsMut<[$S; ($n * $n)]> for $MatrixN<$S> { #[inline] fn as_mut(&mut self) -> &mut [$S; ($n * $n)] { unsafe { mem::transmute(self) } } } // impl<$S> From<[$S; ($n * $n)]> for $MatrixN<$S> { // #[inline] // fn from(m: [$S; ($n * $n)]) -> $MatrixN<$S> { // // TODO: Not sure how to implement this... // unimplemented!() // } // } impl<'a, $S> From<&'a [$S; ($n * $n)]> for &'a $MatrixN<$S> { #[inline] fn from(m: &'a [$S; ($n * $n)]) -> &'a $MatrixN<$S> { unsafe { mem::transmute(m) } } } impl<'a, $S> From<&'a mut [$S; ($n * $n)]> for &'a mut $MatrixN<$S> { #[inline] fn from(m: &'a mut [$S; ($n * $n)]) -> &'a mut $MatrixN<$S> { unsafe { mem::transmute(m) } } } } } fixed_array_conversions!(Matrix2 { x:0, y:1 }, 2); fixed_array_conversions!(Matrix3 { x:0, y:1, z:2 }, 3); fixed_array_conversions!(Matrix4 { x:0, y:1, z:2, w:3 }, 4); impl From> for Matrix3 { /// Clone the elements of a 2-dimensional matrix into the top-left corner /// of a 3-dimensional identity matrix. fn from(m: Matrix2) -> Matrix3 { Matrix3::new(m[0][0], m[0][1], S::zero(), m[1][0], m[1][1], S::zero(), S::zero(), S::zero(), S::one()) } } impl From> for Matrix4 { /// Clone the elements of a 2-dimensional matrix into the top-left corner /// of a 4-dimensional identity matrix. fn from(m: Matrix2) -> Matrix4 { Matrix4::new(m[0][0], m[0][1], S::zero(), S::zero(), m[1][0], m[1][1], S::zero(), S::zero(), S::zero(), S::zero(), S::one(), S::zero(), S::zero(), S::zero(), S::zero(), S::one()) } } impl From> for Matrix4 { /// Clone the elements of a 3-dimensional matrix into the top-left corner /// of a 4-dimensional identity matrix. fn from(m: Matrix3) -> Matrix4 { Matrix4::new(m[0][0], m[0][1], m[0][2], S::zero(), m[1][0], m[1][1], m[1][2], S::zero(), m[2][0], m[2][1], m[2][2], S::zero(), S::zero(), S::zero(), S::zero(), S::one()) } } impl From> for Quaternion { /// Convert the matrix to a quaternion fn from(mat: Matrix3) -> Quaternion { // http://www.cs.ucr.edu/~vbz/resources/quatut.pdf let trace = mat.trace(); let half: S = cast(0.5f64).unwrap(); if trace >= S::zero() { let s = (S::one() + trace).sqrt(); let w = half * s; let s = half / s; let x = (mat[1][2] - mat[2][1]) * s; let y = (mat[2][0] - mat[0][2]) * s; let z = (mat[0][1] - mat[1][0]) * s; Quaternion::new(w, x, y, z) } else if (mat[0][0] > mat[1][1]) && (mat[0][0] > mat[2][2]) { let s = (half + (mat[0][0] - mat[1][1] - mat[2][2])).sqrt(); let w = half * s; let s = half / s; let x = (mat[0][1] - mat[1][0]) * s; let y = (mat[2][0] - mat[0][2]) * s; let z = (mat[1][2] - mat[2][1]) * s; Quaternion::new(w, x, y, z) } else if mat[1][1] > mat[2][2] { let s = (half + (mat[1][1] - mat[0][0] - mat[2][2])).sqrt(); let w = half * s; let s = half / s; let x = (mat[0][1] - mat[1][0]) * s; let y = (mat[1][2] - mat[2][1]) * s; let z = (mat[2][0] - mat[0][2]) * s; Quaternion::new(w, x, y, z) } else { let s = (half + (mat[2][2] - mat[0][0] - mat[1][1])).sqrt(); let w = half * s; let s = half / s; let x = (mat[2][0] - mat[0][2]) * s; let y = (mat[1][2] - mat[2][1]) * s; let z = (mat[0][1] - mat[1][0]) * s; Quaternion::new(w, x, y, z) } } } impl fmt::Debug for Matrix2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[[{:?}, {:?}], [{:?}, {:?}]]", self[0][0], self[0][1], self[1][0], self[1][1]) } } impl fmt::Debug for Matrix3 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[[{:?}, {:?}, {:?}], [{:?}, {:?}, {:?}], [{:?}, {:?}, {:?}]]", self[0][0], self[0][1], self[0][2], self[1][0], self[1][1], self[1][2], self[2][0], self[2][1], self[2][2]) } } impl fmt::Debug for Matrix4 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[[{:?}, {:?}, {:?}, {:?}], [{:?}, {:?}, {:?}, {:?}], [{:?}, {:?}, {:?}, {:?}], [{:?}, {:?}, {:?}, {:?}]]", self[0][0], self[0][1], self[0][2], self[0][3], self[1][0], self[1][1], self[1][2], self[1][3], self[2][0], self[2][1], self[2][2], self[2][3], self[3][0], self[3][1], self[3][2], self[3][3]) } } impl Rand for Matrix2 { #[inline] fn rand(rng: &mut R) -> Matrix2 { Matrix2{ x: rng.gen(), y: rng.gen() } } } impl Rand for Matrix3 { #[inline] fn rand(rng: &mut R) -> Matrix3 { Matrix3{ x: rng.gen(), y: rng.gen(), z: rng.gen() } } } impl Rand for Matrix4 { #[inline] fn rand(rng: &mut R) -> Matrix4 { Matrix4{ x: rng.gen(), y: rng.gen(), z: rng.gen(), w: rng.gen() } } }