use cfg_if::cfg_if;
use core::ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign};
use num_traits::{ConstOne, ConstZero, MulAdd, MulAddAssign, One, Signed, Zero, float::FloatCore};
use crate::{MathConstants, Matrix2x2, Matrix3x3Math, Quaternion, QuaternionMath, SqrtMethods, Vector3d};
pub type Matrix3x3f32 = Matrix3x3<f32>;
pub type Matrix3x3f64 = Matrix3x3<f64>;
cfg_if! {
if #[cfg(feature = "no_align")] {
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Matrix3x3<T> {
pub(crate) a: [T; 9],
}
} else {
#[repr(C, align(32))]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Matrix3x3<T> {
pub(crate) a: [T; 9],
}
}
}
impl<T> Matrix3x3<T>
where
T: Copy,
{
#[inline]
pub const fn new(input: [T; 9]) -> Self {
Self { a: input }
}
}
impl<T> Zero for Matrix3x3<T>
where
T: Copy + Zero + PartialEq + Matrix3x3Math,
{
#[rustfmt::skip]
#[inline]
fn zero() -> Self {
Self {
a: [
T::zero(), T::zero(), T::zero(),
T::zero(), T::zero(), T::zero(),
T::zero(), T::zero(), T::zero(),
],
}
}
#[inline]
fn is_zero(&self) -> bool {
self.a.iter().all(|&x| x == T::zero())
}
}
impl<T> ConstZero for Matrix3x3<T>
where
T: Copy + ConstZero + PartialEq + Matrix3x3Math,
{
#[rustfmt::skip]
const ZERO: Self = Self {
a: [
T::ZERO, T::ZERO, T::ZERO,
T::ZERO, T::ZERO, T::ZERO,
T::ZERO, T::ZERO, T::ZERO,
]
};
}
impl<T> One for Matrix3x3<T>
where
T: Copy + Zero + One + PartialEq + Matrix3x3Math,
{
#[rustfmt::skip]
#[inline]
fn one() -> Self {
Self {
a: [
T::one(), T::zero(), T::zero(),
T::zero(), T::one(), T::zero(),
T::zero(), T::zero(), T::one()
]
}
}
#[rustfmt::skip]
#[inline]
fn is_one(&self) -> bool {
self.a == [
T::one(), T::zero(), T::zero(),
T::zero(), T::one(), T::zero(),
T::zero(), T::zero(), T::one(),
]
}
}
impl<T> ConstOne for Matrix3x3<T>
where
T: Copy + ConstZero + ConstOne + PartialEq + Matrix3x3Math,
{
#[rustfmt::skip]
const ONE: Self = Self {
a: [
T::ONE, T::ZERO, T::ZERO,
T::ZERO, T::ONE, T::ZERO,
T::ZERO, T::ZERO, T::ONE,
]
};
}
impl<T> Neg for Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
type Output = Self;
#[inline]
fn neg(self) -> Self {
T::m3x3_neg(self)
}
}
impl<T> Add for Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
type Output = Self;
#[inline]
fn add(self, other: Self) -> Self {
T::m3x3_add(self, other)
}
}
impl<T> AddAssign for Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
#[inline]
fn add_assign(&mut self, other: Self) {
*self = *self + other;
}
}
impl<T> MulAdd<T> for Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
type Output = Self;
#[inline]
fn mul_add(self, k: T, other: Self) -> Self {
T::m3x3_mul_add(self, k, other)
}
}
impl<T> MulAddAssign<T> for Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
#[inline]
fn mul_add_assign(&mut self, k: T, other: Self) {
*self = self.mul_add(k, other);
}
}
impl<T> Sub for Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self {
self + (-other)
}
}
impl<T> SubAssign for Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
#[inline]
fn sub_assign(&mut self, other: Self) {
*self = *self - other;
}
}
impl Mul<Matrix3x3<f32>> for f32 {
type Output = Matrix3x3<f32>;
#[inline]
fn mul(self, other: Matrix3x3<f32>) -> Matrix3x3<f32> {
f32::m3x3_mul_scalar(other, self)
}
}
impl Mul<Matrix3x3<f64>> for f64 {
type Output = Matrix3x3<f64>;
#[inline]
fn mul(self, other: Matrix3x3<f64>) -> Matrix3x3<f64> {
f64::m3x3_mul_scalar(other, self)
}
}
impl<T> Mul<T> for Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
type Output = Self;
#[inline]
fn mul(self, other: T) -> Self {
T::m3x3_mul_scalar(self, other)
}
}
impl<T> MulAssign<T> for Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
#[inline]
fn mul_assign(&mut self, other: T) {
*self = *self * other;
}
}
impl<T> Mul<Vector3d<T>> for Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
type Output = Vector3d<T>;
#[inline]
fn mul(self, other: Vector3d<T>) -> Vector3d<T> {
T::m3x3_mul_vector(self, other)
}
}
impl<T> Mul<Matrix3x3<T>> for Vector3d<T>
where
T: Copy + Matrix3x3Math,
{
type Output = Self;
#[inline]
fn mul(self, other: Matrix3x3<T>) -> Self {
T::m3x3_vector_mul(self, other)
}
}
impl<T> Mul<Matrix3x3<T>> for Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
type Output = Self;
#[inline]
fn mul(self, other: Self) -> Self {
T::m3x3_mul(self, other)
}
}
impl<T> MulAssign<Matrix3x3<T>> for Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
#[inline]
fn mul_assign(&mut self, other: Matrix3x3<T>) {
*self = *self * other;
}
}
impl<T> Div<T> for Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
type Output = Self;
#[inline]
fn div(self, other: T) -> Self {
T::m3x3_div_scalar(self, other)
}
}
impl<T> DivAssign<T> for Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
#[inline]
fn div_assign(&mut self, other: T) {
*self = *self / other;
}
}
impl<T> Index<usize> for Matrix3x3<T> {
type Output = T;
#[inline]
fn index(&self, index: usize) -> &T {
&self.a[index]
}
}
impl<T> IndexMut<usize> for Matrix3x3<T> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut T {
&mut self.a[index]
}
}
impl<T> Index<(usize, usize)> for Matrix3x3<T> {
type Output = T;
#[inline]
fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
&self.a[row * 3 + col]
}
}
impl<T> IndexMut<(usize, usize)> for Matrix3x3<T> {
#[inline]
fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut T {
&mut self.a[row * 3 + col]
}
}
impl<T> Matrix3x3<T>
where
T: Copy,
{
pub fn set_row(&mut self, row: usize, value: Vector3d<T>) {
match row {
0 => {
self.a[0] = value.x;
self.a[1] = value.y;
self.a[2] = value.z;
}
1 => {
self.a[3] = value.x;
self.a[4] = value.y;
self.a[5] = value.z;
}
_ => {
self.a[6] = value.x;
self.a[7] = value.y;
self.a[8] = value.z;
}
}
}
pub fn row(self, row: usize) -> Vector3d<T> {
match row {
0 => Vector3d::<T> { x: self.a[0], y: self.a[1], z: self.a[2] },
1 => Vector3d::<T> { x: self.a[3], y: self.a[4], z: self.a[5] },
_ => Vector3d::<T> { x: self.a[6], y: self.a[7], z: self.a[8] },
}
}
pub fn set_column(&mut self, column: usize, value: Vector3d<T>) {
match column {
0 => {
self.a[0] = value.x;
self.a[3] = value.y;
self.a[6] = value.z;
}
1 => {
self.a[1] = value.x;
self.a[4] = value.y;
self.a[7] = value.z;
}
_ => {
self.a[2] = value.x;
self.a[5] = value.y;
self.a[8] = value.z;
}
}
}
pub fn column(self, column: usize) -> Vector3d<T> {
match column {
0 => Vector3d::<T> { x: self.a[0], y: self.a[3], z: self.a[6] },
1 => Vector3d::<T> { x: self.a[1], y: self.a[4], z: self.a[7] },
_ => Vector3d::<T> { x: self.a[2], y: self.a[5], z: self.a[8] },
}
}
pub fn diagonal(self) -> Vector3d<T> {
Vector3d::<T> { x: self.a[0], y: self.a[4], z: self.a[8] }
}
}
impl<T> Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
#[inline]
pub fn abs(self) -> Self {
T::m3x3_abs(self)
}
#[inline]
pub fn abs_in_place(&mut self) -> &mut Self {
*self = T::m3x3_abs(*self);
self
}
}
impl<T> Matrix3x3<T>
where
T: Copy + FloatCore,
{
#[inline]
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]
pub fn clamp_in_place(&mut self, min: T, max: T) -> &mut Self {
*self = self.clamp(min, max);
self
}
}
impl<T> Matrix3x3<T>
where
T: Copy,
{
#[inline]
pub fn transpose(self) -> Self {
Self { a: [self.a[0], self.a[3], self.a[6], self.a[1], self.a[4], self.a[7], self.a[2], self.a[5], self.a[8]] }
}
#[inline]
pub fn transpose_in_place(&mut self) -> &mut Self {
*self = self.transpose();
self
}
}
impl<T> Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
#[inline]
pub fn adjugate(self) -> (Self, T) {
let (adjugate, determinant) = T::m3x3_adjugate(self);
(adjugate, determinant)
}
#[inline]
pub fn adjugate_in_place(&mut self) -> &mut Self {
*self = self.adjugate().0;
self
}
#[inline]
pub fn inverse(self) -> Self {
let (adjugate, determinant) = T::m3x3_adjugate(self);
adjugate / determinant
}
#[inline]
pub fn invert_in_place(&mut self) -> &mut Self {
let (adjugate, determinant) = T::m3x3_adjugate(*self);
*self = adjugate / determinant;
self
}
#[inline]
pub fn determinant(self) -> T {
T::m3x3_determinant(self)
}
#[inline]
pub fn trace(self) -> T {
T::m3x3_trace(self)
}
}
impl<T> Matrix3x3<T>
where
T: Copy + Zero + One + Matrix3x3Math + MathConstants + PartialOrd + Signed,
{
pub fn inverse_or_zero(self) -> Self {
let (adjugate, determinant) = self.adjugate();
if determinant.abs() < T::EPSILON {
return Self::zero();
}
adjugate / determinant
}
pub fn try_invert(self) -> Option<Self> {
let (adjugate, determinant) = self.adjugate();
if determinant.abs() < T::EPSILON {
return None;
}
Some(adjugate / determinant)
}
#[inline]
pub fn sum(self) -> T {
T::m3x3_sum(self)
}
#[inline]
pub fn mean(self) -> T {
T::m3x3_mean(self)
}
#[inline]
pub fn product(self) -> T {
T::m3x3_product(self)
}
#[inline]
pub fn trace_sum_squares(self) -> T {
T::m3x3_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
|| self.a[3].abs() > T::EPSILON
|| self.a[5].abs() > T::EPSILON
|| self.a[6].abs() > T::EPSILON
{
return false;
}
if (self.a[0] - T::one()).abs() > T::EPSILON
|| (self.a[4] - T::one()).abs() > T::EPSILON
|| (self.a[8] - T::one()).abs() > T::EPSILON
{
return false;
}
true
}
}
impl<T> From<[T; 9]> for Matrix3x3<T>
where
T: Copy,
{
#[inline]
fn from(input: [T; 9]) -> Self {
Self { a: input }
}
}
impl<T> From<[[T; 3]; 3]> for Matrix3x3<T>
where
T: Copy,
{
#[inline]
fn from(a: [[T; 3]; 3]) -> Self {
Self { a: [a[0][0], a[0][1], a[0][2], a[1][0], a[1][1], a[1][2], a[2][0], a[2][1], a[2][2]] }
}
}
impl<T> From<[Vector3d<T>; 3]> for Matrix3x3<T>
where
T: Copy,
{
#[inline]
fn from(v: [Vector3d<T>; 3]) -> Self {
Self { a: [v[0].x, v[0].y, v[0].z, v[1].x, v[1].y, v[1].z, v[2].x, v[2].y, v[2].z] }
}
}
impl<T> From<(Vector3d<T>, Vector3d<T>, Vector3d<T>)> for Matrix3x3<T> {
#[inline]
fn from(v: (Vector3d<T>, Vector3d<T>, Vector3d<T>)) -> Self {
Self { a: [v.0.x, v.0.y, v.0.z, v.1.x, v.1.y, v.1.z, v.2.x, v.2.y, v.2.z] }
}
}
impl<T> From<Matrix2x2<T>> for Matrix3x3<T>
where
T: Copy + Zero,
{
#[inline]
fn from(m: Matrix2x2<T>) -> Self {
Self { a: [m[0], m[1], T::zero(), m[2], m[3], T::zero(), T::zero(), T::zero(), T::zero()] }
}
}
impl<T> From<Matrix3x3<T>> for Matrix2x2<T>
where
T: Copy,
{
#[inline]
fn from(m: Matrix3x3<T>) -> Self {
Self { a: [m.a[0], m.a[1], m.a[3], m.a[4]] }
}
}
impl<T> From<Quaternion<T>> for Matrix3x3<T>
where
T: Copy + Zero + One + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
{
#[inline]
fn from(q: Quaternion<T>) -> Self {
let two = T::one() + T::one();
Self {
a: [
T::one() - (q.y * q.y + q.z * q.z) * two,
(q.x * q.y - q.w * q.z) * two,
(q.w * q.y + q.x * q.z) * two,
(q.w * q.z + q.x * q.y) * two,
T::one() - (q.x * q.x + q.z * q.z) * two,
(q.y * q.z - q.w * q.x) * two,
(q.x * q.z - q.w * q.y) * two,
(q.w * q.x + q.y * q.z) * two,
T::one() - (q.x * q.x + q.y * q.y) * two,
],
}
}
}
impl<T> From<Matrix3x3<T>> for Quaternion<T>
where
T: Copy + One + FloatCore + SqrtMethods + QuaternionMath,
{
fn from(m: Matrix3x3<T>) -> Self {
let half = T::one() / (T::one() + T::one());
if m.a[8] < T::zero() {
if m.a[0] > m.a[4] {
let t = T::one() + (m.a[0] - m.a[4]) - m.a[8]; let q = Self { w: m.a[7] - m.a[5], x: t, y: m.a[1] + m.a[3], z: m.a[6] + m.a[2] };
return q * t.sqrt_reciprocal() * half;
}
let t = T::one() - (m.a[0] - m.a[4]) - m.a[8]; let q = Self { w: m.a[2] - m.a[6], x: m.a[1] + m.a[3], y: t, z: m.a[5] + m.a[7] };
return q * t.sqrt_reciprocal() * half;
}
if m.a[0] < -m.a[4] {
let t = T::one() - m.a[0] - (m.a[4] - m.a[8]); let q = Self { w: m.a[3] - m.a[1], x: m.a[2] + m.a[6], y: m.a[5] + m.a[7], z: t };
return q * t.sqrt_reciprocal() * half;
}
let t = T::one() + m.a[0] + m.a[4] + m.a[8]; let q = Self { w: t, x: m.a[7] - m.a[5], y: m.a[2] - m.a[6], z: m.a[3] - m.a[1] };
q * t.sqrt_reciprocal() * half
}
}