use core::ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign};
use num_traits::{MulAdd, MulAddAssign, One, Signed, Zero, float::FloatCore};
use crate::{MathConstants, Matrix2x2Math, Vector2d};
pub type Matrix2x2f32 = Matrix2x2<f32>;
pub type Matrix2x2f64 = Matrix2x2<f64>;
#[repr(C, align(16))]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Matrix2x2<T> {
pub(crate) a: [T; 4],
}
impl<T> Matrix2x2<T>
where
T: Copy,
{
#[inline(always)]
pub const fn new(input: [T; 4]) -> Self {
Self { a: input }
}
}
impl<T> Zero for Matrix2x2<T>
where
T: Copy + Zero + PartialEq + Matrix2x2Math,
{
#[inline(always)]
fn zero() -> Self {
Self { a: [T::zero(), T::zero(), T::zero(), T::zero()] }
}
#[inline(always)]
fn is_zero(&self) -> bool {
self.a.iter().all(|&x| x == T::zero())
}
}
impl<T> One for Matrix2x2<T>
where
T: Copy + Zero + One + PartialEq + Matrix2x2Math,
{
#[inline(always)]
fn one() -> Self {
Self { a: [T::one(), T::zero(), T::zero(), T::one()] }
}
#[inline(always)]
fn is_one(&self) -> bool {
self.a == [T::one(), T::zero(), T::zero(), T::one()]
}
}
impl<T> Neg for Matrix2x2<T>
where
T: Copy + Matrix2x2Math,
{
type Output = Self;
#[inline(always)]
fn neg(self) -> Self {
T::m2x2_neg(self)
}
}
impl<T> Add for Matrix2x2<T>
where
T: Copy + Matrix2x2Math,
{
type Output = Self;
#[inline(always)]
fn add(self, other: Self) -> Self {
T::m2x2_add(self, other)
}
}
impl<T> AddAssign for Matrix2x2<T>
where
T: Copy + Matrix2x2Math,
{
#[inline(always)]
fn add_assign(&mut self, other: Self) {
*self = *self + other;
}
}
impl<T> MulAdd<T> for Matrix2x2<T>
where
T: Copy + Matrix2x2Math,
{
type Output = Self;
#[inline(always)]
fn mul_add(self, k: T, other: Self) -> Self {
T::m2x2_mul_add(self, k, other)
}
}
impl<T> MulAddAssign<T> for Matrix2x2<T>
where
T: Copy + Matrix2x2Math,
{
#[inline(always)]
fn mul_add_assign(&mut self, k: T, other: Self) {
*self = self.mul_add(k, other);
}
}
impl<T> Sub for Matrix2x2<T>
where
T: Copy + Matrix2x2Math,
{
type Output = Self;
#[inline(always)]
fn sub(self, other: Self) -> Self {
self + (-other)
}
}
impl<T> SubAssign for Matrix2x2<T>
where
T: Copy + Matrix2x2Math,
{
#[inline(always)]
fn sub_assign(&mut self, other: Self) {
*self = *self - other;
}
}
impl Mul<Matrix2x2<f32>> for f32 {
type Output = Matrix2x2<f32>;
#[inline(always)]
fn mul(self, other: Matrix2x2<f32>) -> Matrix2x2<f32> {
f32::m2x2_mul_scalar(other, self)
}
}
impl Mul<Matrix2x2<f64>> for f64 {
type Output = Matrix2x2<f64>;
#[inline(always)]
fn mul(self, other: Matrix2x2<f64>) -> Matrix2x2<f64> {
f64::m2x2_mul_scalar(other, self)
}
}
impl<T> Mul<T> for Matrix2x2<T>
where
T: Copy + Matrix2x2Math,
{
type Output = Self;
#[inline(always)]
fn mul(self, other: T) -> Self {
T::m2x2_mul_scalar(self, other)
}
}
impl<T> MulAssign<T> for Matrix2x2<T>
where
T: Copy + Matrix2x2Math,
{
#[inline(always)]
fn mul_assign(&mut self, other: T) {
*self = *self * other;
}
}
impl<T> Mul<Vector2d<T>> for Matrix2x2<T>
where
T: Copy + Matrix2x2Math,
{
type Output = Vector2d<T>;
#[inline(always)]
fn mul(self, other: Vector2d<T>) -> Vector2d<T> {
T::m2x2_mul_vector(self, other)
}
}
impl<T> Mul<Matrix2x2<T>> for Vector2d<T>
where
T: Copy + Matrix2x2Math,
{
type Output = Self;
#[inline(always)]
fn mul(self, other: Matrix2x2<T>) -> Self {
T::m2x2_vector_mul(self, other)
}
}
impl<T> Mul<Matrix2x2<T>> for Matrix2x2<T>
where
T: Copy + Matrix2x2Math,
{
type Output = Self;
#[inline(always)]
fn mul(self, other: Self) -> Self {
T::m2x2_mul(self, other)
}
}
impl<T> MulAssign<Matrix2x2<T>> for Matrix2x2<T>
where
T: Copy + Matrix2x2Math,
{
#[inline(always)]
fn mul_assign(&mut self, other: Matrix2x2<T>) {
*self = *self * other;
}
}
impl<T> Div<T> for Matrix2x2<T>
where
T: Copy + Matrix2x2Math,
{
type Output = Self;
#[inline(always)]
fn div(self, other: T) -> Self {
T::m2x2_div_scalar(self, other)
}
}
impl<T> DivAssign<T> for Matrix2x2<T>
where
T: Copy + Matrix2x2Math,
{
#[inline(always)]
fn div_assign(&mut self, other: T) {
*self = *self / other;
}
}
impl<T> Index<usize> for Matrix2x2<T> {
type Output = T;
#[inline(always)]
fn index(&self, index: usize) -> &T {
&self.a[index]
}
}
impl<T> IndexMut<usize> for Matrix2x2<T> {
#[inline(always)]
fn index_mut(&mut self, index: usize) -> &mut T {
&mut self.a[index]
}
}
impl<T> Index<(usize, usize)> for Matrix2x2<T> {
type Output = T;
#[inline(always)]
fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
&self.a[row * 2 + col]
}
}
impl<T> IndexMut<(usize, usize)> for Matrix2x2<T> {
#[inline(always)]
fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut T {
&mut self.a[row * 2 + col]
}
}
impl<T> Matrix2x2<T>
where
T: Copy,
{
pub fn set_row(&mut self, row: usize, value: Vector2d<T>) {
if row == 0 {
self.a[0] = value.x;
self.a[1] = value.y;
} else {
self.a[2] = value.x;
self.a[3] = value.y;
}
}
pub fn row(self, row: usize) -> Vector2d<T> {
match row {
0 => Vector2d::<T> { x: self.a[0], y: self.a[1] },
_ => Vector2d::<T> { x: self.a[2], y: self.a[3] },
}
}
pub fn set_column(&mut self, column: usize, value: Vector2d<T>) {
if column == 0 {
self.a[0] = value.x;
self.a[3] = value.y;
} else {
self.a[1] = value.x;
self.a[2] = value.y;
}
}
pub fn column(self, column: usize) -> Vector2d<T> {
match column {
0 => Vector2d::<T> { x: self.a[0], y: self.a[2] },
_ => Vector2d::<T> { x: self.a[1], y: self.a[3] },
}
}
pub fn diagonal(self) -> Vector2d<T> {
Vector2d::<T> { x: self.a[0], y: self.a[3] }
}
}
impl<T> Matrix2x2<T>
where
T: Copy + Matrix2x2Math,
{
#[inline(always)]
pub fn abs(self) -> Self {
T::m2x2_abs(self)
}
#[inline(always)]
pub fn abs_in_place(&mut self) -> &mut Self {
*self = T::m2x2_abs(*self);
self
}
}
impl<T> Matrix2x2<T>
where
T: Copy + FloatCore,
{
#[inline(always)]
pub fn clamp(self, min: T, max: T) -> Self {
let mut a = self.a;
for it in &mut a {
*it = it.clamp(min, max);
}
Self { a }
}
#[inline(always)]
pub fn clamp_in_place(&mut self, min: T, max: T) -> &mut Self {
*self = self.clamp(min, max);
self
}
}
impl<T> Matrix2x2<T>
where
T: Copy,
{
#[inline(always)]
pub fn transpose(self) -> Self {
Self { a: [self.a[0], self.a[2], self.a[1], self.a[3]] }
}
#[inline(always)]
pub fn transpose_in_place(&mut self) -> &mut Self {
*self = self.transpose();
self
}
}
impl<T> Matrix2x2<T>
where
T: Copy + Matrix2x2Math,
{
#[inline(always)]
pub fn adjugate(self) -> Self {
T::m2x2_adjugate(self)
}
#[inline(always)]
pub fn adjugate_in_place(&mut self) -> &mut Self {
*self = self.adjugate();
self
}
#[inline(always)]
pub fn inverse(self) -> Self {
let adjugate = self.adjugate();
let determinant = self.determinant();
adjugate / determinant
}
#[inline(always)]
pub fn invert_in_place(&mut self) -> &mut Self {
let adjugate = self.adjugate();
let determinant = self.determinant();
*self = adjugate / determinant;
self
}
#[inline(always)]
pub fn determinant(self) -> T {
T::m2x2_determinant(self)
}
#[inline(always)]
pub fn trace(self) -> T {
T::m2x2_trace(self)
}
}
impl<T> Matrix2x2<T>
where
T: Copy + Zero + One + Matrix2x2Math + MathConstants + PartialOrd + Signed,
{
pub fn inverse_or_zero(self) -> Self {
let determinant = self.determinant();
if determinant.abs() < T::EPSILON {
return Self::zero();
}
let adjugate = self.adjugate();
adjugate / determinant
}
pub fn try_invert(self) -> Option<Self> {
let determinant = self.determinant();
if determinant.abs() < T::EPSILON {
return None;
}
let adjugate = self.adjugate();
Some(adjugate / determinant)
}
#[inline(always)]
pub fn sum(self) -> T {
T::m2x2_sum(self)
}
#[inline(always)]
pub fn mean(self) -> T {
T::m2x2_mean(self)
}
#[inline(always)]
pub fn product(self) -> T {
T::m2x2_product(self)
}
#[inline(always)]
pub fn trace_sum_squares(self) -> T {
T::m2x2_trace_sum_squares(self)
}
pub fn is_near_zero(self) -> bool {
for a in &self.a {
if a.abs() > T::EPSILON {
return false;
}
}
true
}
pub fn is_near_identity(self) -> bool {
if self.a[1].abs() > T::EPSILON || self.a[2].abs() > T::EPSILON {
return false;
}
if (self.a[0] - T::one()).abs() > T::EPSILON || (self.a[3] - T::one()).abs() > T::EPSILON {
return false;
}
true
}
}
impl<T> From<[T; 4]> for Matrix2x2<T>
where
T: Copy,
{
#[inline(always)]
fn from(input: [T; 4]) -> Self {
Self { a: input }
}
}
impl<T> From<[[T; 2]; 2]> for Matrix2x2<T>
where
T: Copy,
{
#[inline(always)]
fn from(a: [[T; 2]; 2]) -> Self {
Self { a: [a[0][0], a[0][1], a[1][0], a[1][1]] }
}
}
impl<T> From<[Vector2d<T>; 2]> for Matrix2x2<T>
where
T: Copy,
{
#[inline(always)]
fn from(v: [Vector2d<T>; 2]) -> Self {
Self { a: [v[0].x, v[0].y, v[1].x, v[1].y] }
}
}
impl<T> From<(Vector2d<T>, Vector2d<T>)> for Matrix2x2<T> {
#[inline(always)]
fn from(v: (Vector2d<T>, Vector2d<T>)) -> Self {
Self { a: [v.0.x, v.0.y, v.1.x, v.1.y] }
}
}