use core::ops::{
Add, AddAssign, Deref, DerefMut, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Range, RangeFull,
RangeInclusive, Sub, SubAssign,
};
use core::slice::{ChunksExact, ChunksExactMut};
use num_traits::{ConstOne, ConstZero, MulAdd, MulAddAssign, One, Signed, Zero, float::FloatCore};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::{MathConstants, Matrix2x2, Matrix3x3Math, Quaternion, QuaternionMath, SqrtMethods, Vector3d};
pub type Matrix3x3f32 = Matrix3x3<f32>;
pub type Matrix3x3f64 = Matrix3x3<f64>;
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "no_align", repr(C))]
#[cfg_attr(not(feature = "no_align"), repr(C, align(64)))]
pub struct Matrix3x3<T> {
pub(crate) a: [T; 9],
}
impl<T> Matrix3x3<T> {
pub const SIZE: usize = 9;
pub const ROW_COUNT: usize = 3;
pub const COL_COUNT: usize = 3;
pub const M11: usize = 0;
pub const M12: usize = 1;
pub const M13: usize = 2;
pub const M21: usize = 3;
pub const M22: usize = 4;
pub const M23: usize = 5;
pub const M31: usize = 6;
pub const M32: usize = 7;
pub const M33: usize = 8;
}
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,
{
#[inline]
fn zero() -> Self {
Self { a: [T::zero(); 9] }
}
#[inline]
fn is_zero(&self) -> bool {
*self == Self::zero()
}
}
impl<T> ConstZero for Matrix3x3<T>
where
T: Copy + ConstZero + PartialEq + Matrix3x3Math,
{
const ZERO: Self = Self { a: [T::ZERO; 9] };
}
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()
]
}
}
#[inline]
fn is_one(&self) -> bool {
*self == Self::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> Matrix3x3<T>
where
T: Copy + Zero + One,
{
#[rustfmt::skip]
#[inline]
pub fn identity() -> 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> Matrix3x3<T>
where
T: Copy + Matrix3x3Math,
{
#[inline]
pub fn outer_product(col: Vector3d<T>, row: Vector3d<T>) -> Self {
T::m3x3_vector_outer_product(col, row)
}
}
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> AsRef<[T; 9]> for Matrix3x3<T> {
#[inline]
fn as_ref(&self) -> &[T; 9] {
&self.a
}
}
impl<T> AsMut<[T; 9]> for Matrix3x3<T> {
#[inline]
fn as_mut(&mut self) -> &mut [T; 9] {
&mut self.a
}
}
impl<T> Deref for Matrix3x3<T> {
type Target = [T];
#[inline]
fn deref(&self) -> &[T] {
&self.a
}
}
impl<T> DerefMut for Matrix3x3<T> {
#[inline]
fn deref_mut(&mut self) -> &mut [T] {
&mut self.a
}
}
impl<T> Index<usize> for Matrix3x3<T> {
type Output = T;
#[inline]
fn index(&self, index: usize) -> &T {
&self.a[index]
}
}
impl<T> Index<Range<usize>> for Matrix3x3<T> {
type Output = [T];
#[inline]
fn index(&self, index: Range<usize>) -> &[T] {
&self.a[index]
}
}
impl<T> Index<RangeFull> for Matrix3x3<T> {
type Output = [T];
#[inline]
fn index(&self, _index: RangeFull) -> &[T] {
&self.a
}
}
impl<T> Index<RangeInclusive<usize>> for Matrix3x3<T> {
type Output = [T];
#[inline]
fn index(&self, index: RangeInclusive<usize>) -> &[T] {
&self.a[index]
}
}
impl<T> Index<(usize, usize)> for Matrix3x3<T> {
type Output = T;
#[inline]
fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
assert!(row < 3 && col < 3, "Matrix index out of bounds: row={row}, col={col}");
&self.a[row * 3 + col]
}
}
impl<T> IndexMut<usize> for Matrix3x3<T> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut T {
&mut self.a[index]
}
}
impl<T> IndexMut<Range<usize>> for Matrix3x3<T> {
#[inline]
fn index_mut(&mut self, index: Range<usize>) -> &mut [T] {
&mut self.a[index]
}
}
impl<T> IndexMut<RangeFull> for Matrix3x3<T> {
#[inline]
fn index_mut(&mut self, _index: RangeFull) -> &mut [T] {
&mut self.a
}
}
impl<T> IndexMut<RangeInclusive<usize>> for Matrix3x3<T> {
#[inline]
fn index_mut(&mut self, index: RangeInclusive<usize>) -> &mut [T] {
&mut self.a[index]
}
}
impl<T> IndexMut<(usize, usize)> for Matrix3x3<T> {
#[inline]
fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut T {
assert!(row < 3 && col < 3, "Matrix index out of bounds: row={row}, col={col}");
&mut self.a[row * 3 + col]
}
}
impl<T> Matrix3x3<T>
where
T: Copy,
{
pub fn set_row(&mut self, row: usize, value: Vector3d<T>) {
let row_slice = &mut self.a[row * 3..(row + 1) * 3];
row_slice.copy_from_slice(&[value.x, value.y, 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>) {
if column >= 3 {
return;
}
let values = [value.x, value.y, value.z];
for (i, &val) in values.iter().enumerate() {
self.a[i * 3 + column] = val;
}
}
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_inverse(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> Matrix3x3<T> {
#[inline]
pub fn rows(&self) -> ChunksExact<'_, T> {
self.chunks_exact(3)
}
}
impl<T> Matrix3x3<T> {
#[inline]
pub fn rows_mut(&mut self) -> ChunksExactMut<'_, T> {
self.chunks_exact_mut(3)
}
}
impl<T> Matrix3x3<T> {
#[allow(clippy::many_single_char_names)]
#[inline]
pub fn into_rows(self) -> [[T; 3]; 3] {
let [a, b, c, d, e, f, g, h, i] = self.a;
[[a, b, c], [d, e, f], [g, h, i]]
}
}
impl<T> Matrix3x3<T>
where
T: Copy,
{
#[inline]
pub fn cols(&self) -> impl Iterator<Item = [T; 3]> {
(0..3).map(|c| {
[self.a[c], self.a[c + 3], self.a[c + 6]]
})
}
}
impl<'a, T> IntoIterator for &'a Matrix3x3<T> {
type Item = &'a [T];
type IntoIter = ChunksExact<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.chunks_exact(3)
}
}
impl<'a, T> IntoIterator for &'a mut Matrix3x3<T> {
type Item = &'a mut [T];
type IntoIter = ChunksExactMut<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.chunks_exact_mut(3)
}
}
impl<T> IntoIterator for Matrix3x3<T> {
type Item = [T; 3];
type IntoIter = core::array::IntoIter<[T; 3], 3>;
#[allow(clippy::many_single_char_names)]
#[inline]
fn into_iter(self) -> Self::IntoIter {
let [a, b, c, d, e, f, g, h, i] = self.a;
[[a, b, c], [d, e, f], [g, h, i]].into_iter()
}
}
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> {
#[rustfmt::skip]
#[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,
{
#[rustfmt::skip]
#[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,
{
#[rustfmt::skip]
#[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
}
}