use num::Float;
use crate::vector2::Vector2;
use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, Index, IndexMut, Add, Neg, Sub, Mul, Div};
pub struct Matrix2x2<T: Float> {
_elements: [T; 4],
}
pub type Matrix2x2F = Matrix2x2<f32>;
pub type Matrix2x2D = Matrix2x2<f64>;
impl<T: Float> Matrix2x2<T> {
pub fn new_default() -> Matrix2x2<T> {
return Matrix2x2 {
_elements: [T::one(), T::zero(), T::zero(), T::one()]
};
}
pub fn new_scalar(s: T) -> Matrix2x2<T> {
return Matrix2x2 {
_elements: [s, s, s, s]
};
}
pub fn new(m00: T, m01: T, m10: T, m11: T) -> Matrix2x2<T> {
return Matrix2x2 {
_elements: [m00, m01, m10, m11]
};
}
pub fn new_lst(lst: [[T; 2]; 2]) -> Matrix2x2<T> {
return Matrix2x2 {
_elements: [lst[0][0], lst[0][1], lst[1][0], lst[1][1]]
};
}
pub fn new_array(arr: [T; 4]) -> Matrix2x2<T> {
return Matrix2x2 {
_elements: arr
};
}
}
impl<T: Float> Matrix2x2<T> {
pub fn set_scalar(&mut self, s: T) {
self._elements[0] = s;
self._elements[1] = s;
self._elements[2] = s;
self._elements[3] = s;
}
pub fn set(&mut self, m00: T, m01: T, m10: T, m11: T) {
self._elements[0] = m00;
self._elements[1] = m01;
self._elements[2] = m10;
self._elements[3] = m11;
}
pub fn set_lst(&mut self, lst: [[T; 2]; 2]) {
self._elements[0] = lst[0][0];
self._elements[1] = lst[0][1];
self._elements[2] = lst[1][0];
self._elements[3] = lst[1][1];
}
pub fn set_self(&mut self, m: Matrix2x2<T>) {
self._elements = m._elements;
}
pub fn set_array(&mut self, arr: [T; 4]) {
self._elements = arr;
}
pub fn set_diagonal(&mut self, s: T) {
self._elements[0] = s;
self._elements[3] = s;
}
pub fn set_off_diagonal(&mut self, s: T) {
self._elements[1] = s;
self._elements[2] = s;
}
pub fn set_row(&mut self, i: usize, row: Vector2<T>) {
self._elements[2 * i] = row.x;
self._elements[2 * i + 1] = row.y;
}
pub fn set_column(&mut self, j: usize, col: Vector2<T>) {
self._elements[j] = col.x;
self._elements[j + 2] = col.y;
}
}
impl<T: Float> Matrix2x2<T> {
pub fn is_similar(&self, m: Matrix2x2<T>, tol: Option<T>) -> bool {
return (T::abs(self._elements[0] - m._elements[0]) < tol.unwrap_or(T::epsilon())) &&
(T::abs(self._elements[1] - m._elements[1]) < tol.unwrap_or(T::epsilon())) &&
(T::abs(self._elements[2] - m._elements[2]) < tol.unwrap_or(T::epsilon())) &&
(T::abs(self._elements[3] - m._elements[3]) < tol.unwrap_or(T::epsilon()));
}
pub fn is_square(&self) -> bool {
return true;
}
pub fn rows(&self) -> usize {
return 2;
}
pub fn cols(&self) -> usize {
return 2;
}
pub fn data_mut(&mut self) -> &mut [T; 4] {
return &mut self._elements;
}
pub fn data(&self) -> &[T; 4] {
return &self._elements;
}
}
impl<T: Float> Matrix2x2<T> {
pub fn add_scalar(&self, s: T) -> Matrix2x2<T> {
return Matrix2x2::new(self._elements[0] + s, self._elements[1] + s,
self._elements[2] + s, self._elements[3] + s);
}
pub fn add_mat(&self, m: Matrix2x2<T>) -> Matrix2x2<T> {
return Matrix2x2::new(self._elements[0] + m._elements[0], self._elements[1] + m._elements[1],
self._elements[2] + m._elements[2], self._elements[3] + m._elements[3]);
}
pub fn sub_scalar(&self, s: T) -> Matrix2x2<T> {
return Matrix2x2::new(self._elements[0] - s, self._elements[1] - s,
self._elements[2] - s, self._elements[3] - s);
}
pub fn sub_mat(&self, m: Matrix2x2<T>) -> Matrix2x2<T> {
return Matrix2x2::new(self._elements[0] - m._elements[0], self._elements[1] - m._elements[1],
self._elements[2] - m._elements[2], self._elements[3] - m._elements[3]);
}
pub fn mul_scalar(&self, s: T) -> Matrix2x2<T> {
return Matrix2x2::new(self._elements[0] * s, self._elements[1] * s,
self._elements[2] * s, self._elements[3] * s);
}
pub fn mul_vec(&self, v: Vector2<T>) -> Vector2<T> {
return Vector2::new(self._elements[0] * v.x + self._elements[1] * v.y,
self._elements[2] * v.x + self._elements[3] * v.y);
}
pub fn mul_mat(&self, m: Matrix2x2<T>) -> Matrix2x2<T> {
return Matrix2x2::new(
self._elements[0] * m._elements[0] + self._elements[1] * m._elements[2],
self._elements[0] * m._elements[1] + self._elements[1] * m._elements[3],
self._elements[2] * m._elements[0] + self._elements[3] * m._elements[2],
self._elements[2] * m._elements[1] + self._elements[3] * m._elements[3]);
}
pub fn div_scalar(&self, s: T) -> Matrix2x2<T> {
return Matrix2x2::new(self._elements[0] / s, self._elements[1] / s,
self._elements[2] / s, self._elements[3] / s);
}
}
impl<T: Float> Matrix2x2<T> {
pub fn radd_scalar(&self, s: T) -> Matrix2x2<T> {
return Matrix2x2::new(s + self._elements[0], s + self._elements[1],
s + self._elements[2], s + self._elements[3]);
}
pub fn radd_mat(&self, m: Matrix2x2<T>) -> Matrix2x2<T> {
return Matrix2x2::new(m._elements[0] + self._elements[0], m._elements[1] + self._elements[1],
m._elements[2] + self._elements[2], m._elements[3] + self._elements[3]);
}
pub fn rsub_scalar(&self, s: T) -> Matrix2x2<T> {
return Matrix2x2::new(s - self._elements[0], s - self._elements[1],
s - self._elements[2], s - self._elements[3]);
}
pub fn rsub_mat(&self, m: Matrix2x2<T>) -> Matrix2x2<T> {
return Matrix2x2::new(m._elements[0] - self._elements[0], m._elements[1] - self._elements[1],
m._elements[2] - self._elements[2], m._elements[3] - self._elements[3]);
}
pub fn rmul_scalar(&self, s: T) -> Matrix2x2<T> {
return Matrix2x2::new(s * self._elements[0], s * self._elements[1],
s * self._elements[2], s * self._elements[3]);
}
pub fn rmul_mat(&self, m: Matrix2x2<T>) -> Matrix2x2<T> {
return m.mul_mat(*self);
}
pub fn rdiv_scalar(&self, s: T) -> Matrix2x2<T> {
return Matrix2x2::new(s / self._elements[0], s / self._elements[1],
s / self._elements[2], s / self._elements[3]);
}
}
impl<T: Float> Matrix2x2<T> {
pub fn iadd_scalar(&mut self, s: T) {
self._elements[0] = self._elements[0] + s;
self._elements[1] = self._elements[1] + s;
self._elements[2] = self._elements[2] + s;
self._elements[3] = self._elements[3] + s;
}
pub fn iadd_mat(&mut self, m: Matrix2x2<T>) {
self._elements[0] = self._elements[0] + m._elements[0];
self._elements[1] = self._elements[1] + m._elements[1];
self._elements[2] = self._elements[2] + m._elements[2];
self._elements[3] = self._elements[3] + m._elements[3];
}
pub fn isub_scalar(&mut self, s: T) {
self._elements[0] = self._elements[0] - s;
self._elements[1] = self._elements[1] - s;
self._elements[2] = self._elements[2] - s;
self._elements[3] = self._elements[3] - s;
}
pub fn isub_mat(&mut self, m: Matrix2x2<T>) {
self._elements[0] = self._elements[0] - m._elements[0];
self._elements[1] = self._elements[1] - m._elements[1];
self._elements[2] = self._elements[2] - m._elements[2];
self._elements[3] = self._elements[3] - m._elements[3];
}
pub fn imul_scalar(&mut self, s: T) {
self._elements[0] = self._elements[0] * s;
self._elements[1] = self._elements[1] * s;
self._elements[2] = self._elements[2] * s;
self._elements[3] = self._elements[3] * s;
}
pub fn imul_mat(&mut self, m: Matrix2x2<T>) {
self.set_self(self.mul_mat(m));
}
pub fn idiv_scalar(&mut self, s: T) {
self._elements[0] = self._elements[0] / s;
self._elements[1] = self._elements[1] / s;
self._elements[2] = self._elements[2] / s;
self._elements[3] = self._elements[3] / s;
}
}
impl<T: Float> Matrix2x2<T> {
pub fn transpose(&mut self) {
let temp = self._elements[2];
self._elements[2] = self._elements[1];
self._elements[1] = temp;
}
pub fn invert(&mut self) {
let d = self.determinant();
let mut m = Matrix2x2::new_default();
m._elements[0] = self._elements[3];
m._elements[1] = -self._elements[1];
m._elements[2] = -self._elements[2];
m._elements[3] = self._elements[0];
m.idiv_scalar(d);
self.set_self(m);
}
}
impl<T: Float> Matrix2x2<T> {
pub fn sum(&self) -> T {
let mut s = T::zero();
for i in 0..4 {
s = s + self._elements[i];
}
return s;
}
pub fn avg(&self) -> T {
return self.sum() * T::from(0.25).unwrap();
}
pub fn min(&self) -> T {
return T::min(T::min(self._elements[0], self._elements[1]),
T::min(self._elements[2], self._elements[3]));
}
pub fn max(&self) -> T {
return T::max(T::max(self._elements[0], self._elements[1]),
T::max(self._elements[2], self._elements[3]));
}
pub fn absmin(&self) -> T {
return crate::math_utils::absmin(crate::math_utils::absmin(self._elements[0], self._elements[1]),
crate::math_utils::absmin(self._elements[2], self._elements[3]));
}
pub fn absmax(&self) -> T {
return crate::math_utils::absmax(crate::math_utils::absmax(self._elements[0], self._elements[1]),
crate::math_utils::absmax(self._elements[2], self._elements[3]));
}
pub fn trace(&self) -> T {
return self._elements[0] + self._elements[3];
}
pub fn determinant(&self) -> T {
return self._elements[0] * self._elements[3] - self._elements[1] * self._elements[2];
}
pub fn diagonal(&self) -> Matrix2x2<T> {
return Matrix2x2::new(self._elements[0], T::zero(),
T::zero(), self._elements[3]);
}
pub fn off_diagonal(&self) -> Matrix2x2<T> {
return Matrix2x2::new(T::zero(), self._elements[1],
self._elements[2], T::zero());
}
pub fn strict_lower_tri(&self) -> Matrix2x2<T> {
return Matrix2x2::new(T::zero(), T::zero(),
self._elements[2], T::zero());
}
pub fn strict_upper_tri(&self) -> Matrix2x2<T> {
return Matrix2x2::new(T::zero(), self._elements[1],
T::zero(), T::zero());
}
pub fn lower_tri(&self) -> Matrix2x2<T> {
return Matrix2x2::new(self._elements[0], T::zero(),
self._elements[2], self._elements[3]);
}
pub fn upper_tri(&self) -> Matrix2x2<T> {
return Matrix2x2::new(self._elements[0], self._elements[1],
T::zero(), self._elements[3]);
}
pub fn transposed(&self) -> Matrix2x2<T> {
return Matrix2x2::new(self._elements[0], self._elements[2],
self._elements[1], self._elements[3]);
}
pub fn inverse(&self) -> Matrix2x2<T> {
let mut m = *self;
m.invert();
return m;
}
pub fn frobenius_norm(&self) -> T {
return T::sqrt(self._elements[0] * self._elements[0] + self._elements[1] * self._elements[1] +
self._elements[2] * self._elements[2] + self._elements[3] * self._elements[3]);
}
}
impl<T: Float> Clone for Matrix2x2<T> {
fn clone(&self) -> Self {
return Matrix2x2 {
_elements: self._elements,
};
}
}
impl<T: Float> Copy for Matrix2x2<T> {}
impl<T: Float> AddAssign<T> for Matrix2x2<T> {
fn add_assign(&mut self, rhs: T) {
self.iadd_scalar(rhs);
}
}
impl<T: Float> AddAssign for Matrix2x2<T> {
fn add_assign(&mut self, rhs: Self) {
self.iadd_mat(rhs);
}
}
impl<T: Float> SubAssign<T> for Matrix2x2<T> {
fn sub_assign(&mut self, rhs: T) {
self.isub_scalar(rhs);
}
}
impl<T: Float> SubAssign for Matrix2x2<T> {
fn sub_assign(&mut self, rhs: Self) {
self.isub_mat(rhs);
}
}
impl<T: Float> MulAssign<T> for Matrix2x2<T> {
fn mul_assign(&mut self, rhs: T) {
self.imul_scalar(rhs);
}
}
impl<T: Float> MulAssign for Matrix2x2<T> {
fn mul_assign(&mut self, rhs: Self) {
self.imul_mat(rhs);
}
}
impl<T: Float> DivAssign<T> for Matrix2x2<T> {
fn div_assign(&mut self, rhs: T) {
self.idiv_scalar(rhs);
}
}
impl<T: Float> Index<usize> for Matrix2x2<T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
return &self._elements[index];
}
}
impl<T: Float> IndexMut<usize> for Matrix2x2<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
return &mut self._elements[index];
}
}
impl<T: Float> Index<(usize, usize)> for Matrix2x2<T> {
type Output = T;
fn index(&self, index: (usize, usize)) -> &Self::Output {
return &self._elements[2 * index.0 + index.1];
}
}
impl<T: Float> IndexMut<(usize, usize)> for Matrix2x2<T> {
fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
return &mut self._elements[2 * index.0 + index.1];
}
}
impl<T: Float> PartialEq for Matrix2x2<T> {
fn eq(&self, other: &Self) -> bool {
return self._elements[0] == other._elements[0] && self._elements[1] == other._elements[1] &&
self._elements[2] == other._elements[2] && self._elements[3] == other._elements[3];
}
}
impl<T: Float> Eq for Matrix2x2<T> {}
impl<T: Float> Matrix2x2<T> {
pub fn make_zero() -> Matrix2x2<T> {
return Matrix2x2::new(T::zero(), T::zero(), T::zero(), T::zero());
}
pub fn make_identity() -> Matrix2x2<T> {
return Matrix2x2::new(T::one(), T::zero(), T::zero(), T::one());
}
pub fn make_scale_matrix_scalar(sx: T, sy: T) -> Matrix2x2<T> {
return Matrix2x2::new(sx, T::zero(), T::zero(), sy);
}
pub fn make_scale_matrix_vec(s: Vector2<T>) -> Matrix2x2<T> {
return Matrix2x2::new(s.x, T::zero(), T::zero(), s.y);
}
pub fn make_rotation_matrix(rad: T) -> Matrix2x2<T> {
return Matrix2x2::new(T::cos(rad), -T::sin(rad),
T::sin(rad), T::cos(rad));
}
}
impl<T: Float> Neg for Matrix2x2<T> {
type Output = Matrix2x2<T>;
fn neg(self) -> Self::Output {
return Matrix2x2::new(-self._elements[0], -self._elements[1],
-self._elements[2], -self._elements[3]);
}
}
impl<T: Float> Add<T> for Matrix2x2<T> {
type Output = Matrix2x2<T>;
fn add(self, rhs: T) -> Self::Output {
return self.add_scalar(rhs);
}
}
impl<T: Float> Add for Matrix2x2<T> {
type Output = Matrix2x2<T>;
fn add(self, rhs: Self) -> Self::Output {
return self.add_mat(rhs);
}
}
impl<T: Float> Sub<T> for Matrix2x2<T> {
type Output = Matrix2x2<T>;
fn sub(self, rhs: T) -> Self::Output {
return self.sub_scalar(rhs);
}
}
impl<T: Float> Sub for Matrix2x2<T> {
type Output = Matrix2x2<T>;
fn sub(self, rhs: Self) -> Self::Output {
return self.sub_mat(rhs);
}
}
impl<T: Float> Mul<T> for Matrix2x2<T> {
type Output = Matrix2x2<T>;
fn mul(self, rhs: T) -> Self::Output {
return self.mul_scalar(rhs);
}
}
impl<T: Float> Mul<Vector2<T>> for Matrix2x2<T> {
type Output = Vector2<T>;
fn mul(self, rhs: Vector2<T>) -> Self::Output {
return self.mul_vec(rhs);
}
}
impl<T: Float> Mul for Matrix2x2<T> {
type Output = Matrix2x2<T>;
fn mul(self, rhs: Self) -> Self::Output {
return self.mul_mat(rhs);
}
}
impl<T: Float> Div<T> for Matrix2x2<T> {
type Output = Matrix2x2<T>;
fn div(self, rhs: T) -> Self::Output {
return self.div_scalar(rhs);
}
}