#![cfg(all(feature = "mat3", feature = "quat"))]
use gemath::*;
use crate::vec3::{Vec3, Meters, Pixels, World, Local, Screen};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mat3_new() {
let m: Mat3<(),()> = Mat3::new(
Vec3::new(1.0, 2.0, 3.0),
Vec3::new(4.0, 5.0, 6.0),
Vec3::new(7.0, 8.0, 9.0),
);
assert_eq!(m.x_col, Vec3::new(1.0, 2.0, 3.0));
assert_eq!(m.y_col, Vec3::new(4.0, 5.0, 6.0));
assert_eq!(m.z_col, Vec3::new(7.0, 8.0, 9.0));
}
#[test]
fn test_mat3_zero() {
let m: Mat3<(),()> = Mat3::ZERO;
assert_eq!(m.x_col, Vec3::ZERO);
assert_eq!(m.y_col, Vec3::ZERO);
assert_eq!(m.z_col, Vec3::ZERO);
}
#[test]
fn test_mat3_identity() {
let m: Mat3<(),()> = Mat3::IDENTITY;
assert_eq!(m.x_col, Vec3::new(1.0, 0.0, 0.0));
assert_eq!(m.y_col, Vec3::new(0.0, 1.0, 0.0));
assert_eq!(m.z_col, Vec3::new(0.0, 0.0, 1.0));
}
#[test]
fn test_mat3_from_cols_array() {
let data = [1., 2., 3., 4., 5., 6., 7., 8., 9.];
let m: Mat3<(),()> = Mat3::from_cols_array(&data);
assert_eq!(m.x_col, Vec3::new(1., 2., 3.));
assert_eq!(m.y_col, Vec3::new(4., 5., 6.));
assert_eq!(m.z_col, Vec3::new(7., 8., 9.));
}
#[test]
fn test_mat3_from_rows() {
let m: Mat3<(),()> = Mat3::from_rows(1., 4., 7., 2., 5., 8., 3., 6., 9.);
assert_eq!(m.x_col, Vec3::new(1., 2., 3.));
assert_eq!(m.y_col, Vec3::new(4., 5., 6.));
assert_eq!(m.z_col, Vec3::new(7., 8., 9.));
}
#[test]
fn test_mat3_determinant() {
let m: Mat3<(),()> = Mat3::from_rows(1.0, 2.0, 3.0, 0.0, 1.0, 4.0, 5.0, 6.0, 0.0);
assert_eq!(m.determinant(), 1.0);
let m_singular: Mat3<(),()> = Mat3::from_rows(
1.0, 2.0, 3.0, 2.0, 4.0, 6.0, 0.0, 1.0, 0.0,
);
assert_eq!(m_singular.determinant(), 0.0);
}
#[test]
fn test_mat3_transpose() {
let m: Mat3<(),()> = Mat3::from_rows(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
let mt = m.transpose();
assert_eq!(mt.x_col, Vec3::new(1.0, 2.0, 3.0));
assert_eq!(mt.y_col, Vec3::new(4.0, 5.0, 6.0));
assert_eq!(mt.z_col, Vec3::new(7.0, 8.0, 9.0));
}
#[test]
fn test_mat3_inverse() {
let m: Mat3<(),()> = Mat3::from_rows(1.0, 2.0, 3.0, 0.0, 1.0, 4.0, 5.0, 6.0, 0.0);
let det = m.determinant();
assert!((det - 1.0).abs() < 1e-6, "Determinant should be 1.0");
let m_inv = m.inverse().unwrap();
let expected_m_inv = Mat3::new(
Vec3::new(-24.0, 20.0, -5.0),
Vec3::new(18.0, -15.0, 4.0),
Vec3::new(5.0, -4.0, 1.0),
);
assert_eq!(m_inv, expected_m_inv);
let id = m * m_inv;
assert!((id.x_col.x - 1.0).abs() < 1e-5);
assert!((id.y_col.y - 1.0).abs() < 1e-5);
assert!((id.z_col.z - 1.0).abs() < 1e-5);
}
#[test]
fn test_mat3_try_inverse_alias() {
let m: Mat3<(),()> = Mat3::IDENTITY;
assert_eq!(m.try_inverse(), m.inverse());
let m_singular: Mat3<(),()> = Mat3::from_rows(
1.0, 2.0, 3.0,
2.0, 4.0, 6.0, 0.0, 1.0, 0.0,
);
assert_eq!(m_singular.try_inverse(), None);
}
#[test]
fn test_mat3_eq() {
let m1: Mat3<(),()> = Mat3::new(
Vec3::new(1., 2., 3.),
Vec3::new(4., 5., 6.),
Vec3::new(7., 8., 9.),
);
let m2: Mat3<(),()> = Mat3::new(
Vec3::new(1., 2., 3.),
Vec3::new(4., 5., 6.),
Vec3::new(7., 8., 9.),
);
let m3: Mat3<(),()> = Mat3::new(
Vec3::new(0., 0., 0.),
Vec3::new(4., 5., 6.),
Vec3::new(7., 8., 9.),
);
assert_eq!(m1, m2);
assert_ne!(m1, m3);
}
#[test]
fn test_mat3_add() {
let m1: Mat3<(),()> = Mat3::from_rows(1., 0., 0., 0., 1., 0., 0., 0., 1.);
let m2: Mat3<(),()> = Mat3::from_rows(1., 2., 3., 4., 5., 6., 7., 8., 9.);
let expected: Mat3<(),()> = Mat3::from_rows(2., 2., 3., 4., 6., 6., 7., 8., 10.);
assert_eq!(m1 + m2, expected);
}
#[test]
fn test_mat3_sub() {
let m1: Mat3<(),()> = Mat3::from_rows(2., 2., 3., 4., 6., 6., 7., 8., 10.);
let m2: Mat3<(),()> = Mat3::from_rows(1., 2., 3., 4., 5., 6., 7., 8., 9.);
let expected: Mat3<(),()> = Mat3::from_rows(1., 0., 0., 0., 1., 0., 0., 0., 1.);
assert_eq!(m1 - m2, expected);
}
#[test]
fn test_mat3_mul_scalar() {
let m: Mat3<(),()> = Mat3::from_rows(1., 2., 3., 4., 5., 6., 7., 8., 9.);
let expected: Mat3<(),()> = Mat3::from_rows(2., 4., 6., 8., 10., 12., 14., 16., 18.);
assert_eq!(m * 2.0, expected);
assert_eq!(2.0 * m, expected);
}
#[test]
fn test_mat3_mul_vec3() {
let m: Mat3<(),()> = Mat3::from_rows(
1.0, 2.0,
3.0, 0.0, 1.0, 4.0, 5.0, 6.0, 0.0, );
let v = Vec3::new(1.0, 1.0, 1.0);
let expected = Vec3::new(6.0, 5.0, 11.0);
assert_eq!(m * v, expected);
}
#[test]
fn test_mat3_mul_mat3() {
let m1: Mat3<(),()> = Mat3::from_rows(1., 2., 3., 4., 5., 6., 7., 8., 9.); let m2: Mat3<(),()> = Mat3::IDENTITY;
assert_eq!(m1 * m2, m1);
let m_a: Mat3<(),()> = Mat3::from_rows(1., 0., 5., 2., 1., 6., 3., 4., 0.); let m_b: Mat3<(),()> = Mat3::from_rows(1., 0., 0., 0., 1., 0., 0., 0., 1.); assert_eq!(m_a * m_b, m_a);
let ma: Mat3<(),()> = Mat3::from_rows(1., 2., 0., 3., 4., 0., 0., 0., 1.);
let mb: Mat3<(),()> = Mat3::from_rows(5., 6., 0., 7., 8., 0., 0., 0., 1.);
let expected_res_x = Vec3::new(
1. * 5. + 2. * 7.,
3. * 5. + 4. * 7.,
0. * 5. + 0. * 7. + 1. * 0.,
); let expected_res_y = Vec3::new(
1. * 6. + 2. * 8.,
3. * 6. + 4. * 8.,
0. * 6. + 0. * 8. + 1. * 0.,
); let expected_res_z = Vec3::new(
1. * 0. + 2. * 0. + 0. * 1.,
3. * 0. + 4. * 0. + 0. * 1.,
0. * 0. + 0. * 0. + 1. * 1.,
);
let res = ma * mb;
assert_eq!(res.x_col, expected_res_x);
assert_eq!(res.y_col, expected_res_y);
assert_eq!(res.z_col, expected_res_z);
}
#[test]
fn test_mat3_row_col_accessors() {
let mut m: Mat3<(),()> = Mat3::from_rows(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
assert_eq!(m.col(0), Some(Vec3::new(1.0, 4.0, 7.0)));
assert_eq!(m.col(1), Some(Vec3::new(2.0, 5.0, 8.0)));
assert_eq!(m.col(2), Some(Vec3::new(3.0, 6.0, 9.0)));
assert_eq!(m.row(0), Some(Vec3::new(1.0, 2.0, 3.0)));
assert_eq!(m.row(1), Some(Vec3::new(4.0, 5.0, 6.0)));
assert_eq!(m.row(2), Some(Vec3::new(7.0, 8.0, 9.0)));
m.set_col(0, Vec3::new(9.0, 8.0, 7.0));
assert_eq!(m.col(0), Some(Vec3::new(9.0, 8.0, 7.0)));
m.set_row(1, Vec3::new(6.0, 5.0, 4.0));
assert_eq!(m.row(1), Some(Vec3::new(6.0, 5.0, 4.0)));
}
#[test]
fn test_mat3_is_orthonormal() {
let m: Mat3<(),()> = Mat3::IDENTITY;
assert!(m.is_orthonormal());
let m2: Mat3<(),()> = Mat3::from_rows(0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0); assert!(m2.is_orthonormal());
let m3: Mat3<(),()> = Mat3::from_rows(2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0); assert!(!m3.is_orthonormal());
}
#[test]
fn test_mat3_from_shear() {
let m: Mat3<(),()> = Mat3::from_shear(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
assert_eq!(m.x_col, Vec3::new(1.0, 3.0, 5.0));
assert_eq!(m.y_col, Vec3::new(1.0, 1.0, 6.0));
assert_eq!(m.z_col, Vec3::new(2.0, 4.0, 1.0));
}
#[test]
fn test_mat3_from_quat_and_to_quat() {
use gemath::quat::Quat;
let angle = std::f32::consts::FRAC_PI_2;
let q = Quat::from_axis_angle_radians(
Vec3::new(0.0, 0.0, 1.0),
gemath::angle::Radians(angle),
);
let m: Mat3<(),()> = Mat3::from_quat(q);
let v = Vec3::new(1.0, 0.0, 0.0);
let v_rot = m * v;
assert!((v_rot - Vec3::new(0.0, 1.0, 0.0)).length() < 1e-5);
let q2 = m.to_quat();
assert!((q2.normalize().dot(q.normalize())).abs() > 0.999);
}
#[test]
fn test_mat3_from_scale() {
let m: Mat3<(),()> = Mat3::from_scale(Vec3::new(2.0, 3.0, 4.0));
let v = Vec3::new(1.0, 1.0, 1.0);
assert_eq!(m * v, Vec3::new(2.0, 3.0, 4.0));
}
#[test]
fn test_mat3_from_axis_angle_matches_quat() {
use gemath::quat::Quat;
let angle = std::f32::consts::FRAC_PI_2;
let axis = Vec3::new(0.0, 0.0, 1.0);
let m_axis: Mat3<(),()> = Mat3::from_axis_angle_radians(axis, gemath::angle::Radians(angle));
let m_quat: Mat3<(),()> =
Mat3::from_quat(Quat::from_axis_angle_radians(axis, gemath::angle::Radians(angle)));
assert!(((m_axis.x_col - m_quat.x_col).length()) < 1e-6);
assert!(((m_axis.y_col - m_quat.y_col).length()) < 1e-6);
assert!(((m_axis.z_col - m_quat.z_col).length()) < 1e-6);
}
}
const _CONST_MAT3_ID: Mat3 = Mat3::IDENTITY;
const _CONST_MAT3_ZERO: Mat3 = Mat3::ZERO;
const _CONST_MAT3_NEW: Mat3 = Mat3::new(
Vec3::new(1.0, 2.0, 3.0),
Vec3::new(4.0, 5.0, 6.0),
Vec3::new(7.0, 8.0, 9.0),
);
const _CONST_MAT3_COLS: Mat3 = Mat3::from_cols_array(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]);
const _CONST_MAT3_ROWS: Mat3 = Mat3::from_rows(1.0, 4.0, 7.0, 2.0, 5.0, 8.0, 3.0, 6.0, 9.0);
const _CONST_MAT3_DET: f32 = _CONST_MAT3_COLS.determinant();
const _CONST_MAT3_TRANSPOSE: Mat3 = _CONST_MAT3_COLS.transpose();
const _CONST_MAT3_SHEAR: Mat3 = Mat3::from_shear(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
const _CONST_MAT3_ROW0: Option<Vec3> = _CONST_MAT3_COLS.row(0);
const _CONST_MAT3_ROW1: Option<Vec3> = _CONST_MAT3_COLS.row(1);
const _CONST_MAT3_ROW2: Option<Vec3> = _CONST_MAT3_COLS.row(2);
const _CONST_MAT3_COL0: Option<Vec3> = _CONST_MAT3_COLS.col(0);
const _CONST_MAT3_COL1: Option<Vec3> = _CONST_MAT3_COLS.col(1);
const _CONST_MAT3_COL2: Option<Vec3> = _CONST_MAT3_COLS.col(2);
const _: () = {
assert!(_CONST_MAT3_ID.x_col.x == 1.0 && _CONST_MAT3_ID.y_col.y == 1.0 && _CONST_MAT3_ID.z_col.z == 1.0);
assert!(_CONST_MAT3_ZERO.x_col.x == 0.0 && _CONST_MAT3_ZERO.y_col.y == 0.0 && _CONST_MAT3_ZERO.z_col.z == 0.0);
assert!(_CONST_MAT3_NEW.x_col.x == 1.0 && _CONST_MAT3_NEW.x_col.y == 2.0 && _CONST_MAT3_NEW.x_col.z == 3.0);
assert!(_CONST_MAT3_NEW.y_col.x == 4.0 && _CONST_MAT3_NEW.y_col.y == 5.0 && _CONST_MAT3_NEW.y_col.z == 6.0);
assert!(_CONST_MAT3_NEW.z_col.x == 7.0 && _CONST_MAT3_NEW.z_col.y == 8.0 && _CONST_MAT3_NEW.z_col.z == 9.0);
assert!(_CONST_MAT3_COLS.x_col.x == 1.0 && _CONST_MAT3_COLS.x_col.y == 2.0 && _CONST_MAT3_COLS.x_col.z == 3.0);
assert!(_CONST_MAT3_COLS.y_col.x == 4.0 && _CONST_MAT3_COLS.y_col.y == 5.0 && _CONST_MAT3_COLS.y_col.z == 6.0);
assert!(_CONST_MAT3_COLS.z_col.x == 7.0 && _CONST_MAT3_COLS.z_col.y == 8.0 && _CONST_MAT3_COLS.z_col.z == 9.0);
assert!(_CONST_MAT3_ROWS.x_col.x == 1.0 && _CONST_MAT3_ROWS.x_col.y == 2.0 && _CONST_MAT3_ROWS.x_col.z == 3.0);
assert!(_CONST_MAT3_ROWS.y_col.x == 4.0 && _CONST_MAT3_ROWS.y_col.y == 5.0 && _CONST_MAT3_ROWS.y_col.z == 6.0);
assert!(_CONST_MAT3_ROWS.z_col.x == 7.0 && _CONST_MAT3_ROWS.z_col.y == 8.0 && _CONST_MAT3_ROWS.z_col.z == 9.0);
assert!(_CONST_MAT3_DET == 0.0);
assert!(_CONST_MAT3_TRANSPOSE.x_col.x == 1.0 && _CONST_MAT3_TRANSPOSE.x_col.y == 4.0 && _CONST_MAT3_TRANSPOSE.x_col.z == 7.0);
assert!(_CONST_MAT3_TRANSPOSE.y_col.x == 2.0 && _CONST_MAT3_TRANSPOSE.y_col.y == 5.0 && _CONST_MAT3_TRANSPOSE.y_col.z == 8.0);
assert!(_CONST_MAT3_TRANSPOSE.z_col.x == 3.0 && _CONST_MAT3_TRANSPOSE.z_col.y == 6.0 && _CONST_MAT3_TRANSPOSE.z_col.z == 9.0);
assert!(_CONST_MAT3_SHEAR.x_col.x == 1.0 && _CONST_MAT3_SHEAR.x_col.y == 3.0 && _CONST_MAT3_SHEAR.x_col.z == 5.0);
assert!(_CONST_MAT3_SHEAR.y_col.x == 1.0 && _CONST_MAT3_SHEAR.y_col.y == 1.0 && _CONST_MAT3_SHEAR.y_col.z == 6.0);
assert!(_CONST_MAT3_SHEAR.z_col.x == 2.0 && _CONST_MAT3_SHEAR.z_col.y == 4.0 && _CONST_MAT3_SHEAR.z_col.z == 1.0);
match _CONST_MAT3_ROW0 { Some(v) => assert!(v.x == 1.0 && v.y == 4.0 && v.z == 7.0), None => panic!("row0") }
match _CONST_MAT3_ROW1 { Some(v) => assert!(v.x == 2.0 && v.y == 5.0 && v.z == 8.0), None => panic!("row1") }
match _CONST_MAT3_ROW2 { Some(v) => assert!(v.x == 3.0 && v.y == 6.0 && v.z == 9.0), None => panic!("row2") }
match _CONST_MAT3_COL0 { Some(v) => assert!(v.x == 1.0 && v.y == 2.0 && v.z == 3.0), None => panic!("col0") }
match _CONST_MAT3_COL1 { Some(v) => assert!(v.x == 4.0 && v.y == 5.0 && v.z == 6.0), None => panic!("col1") }
match _CONST_MAT3_COL2 { Some(v) => assert!(v.x == 7.0 && v.y == 8.0 && v.z == 9.0), None => panic!("col2") }
};
const _CONST_MAT3_METERS: Mat3<Meters, ()> = Mat3 {
x_col: Vec3::<Meters, ()>::new(1.0, 2.0, 3.0),
y_col: Vec3::<Meters, ()>::new(4.0, 5.0, 6.0),
z_col: Vec3::<Meters, ()>::new(7.0, 8.0, 9.0),
_unit: core::marker::PhantomData,
_space: core::marker::PhantomData,
};
const _CONST_MAT3_PIXELS: Mat3<Pixels, ()> = Mat3 {
x_col: Vec3::<Pixels, ()>::new(10.0, 20.0, 30.0),
y_col: Vec3::<Pixels, ()>::new(40.0, 50.0, 60.0),
z_col: Vec3::<Pixels, ()>::new(70.0, 80.0, 90.0),
_unit: core::marker::PhantomData,
_space: core::marker::PhantomData,
};
const fn _make_mat3_meters() -> Mat3<Meters, ()> {
Mat3 {
x_col: Vec3::<Meters, ()>::new(1.0, 2.0, 3.0),
y_col: Vec3::<Meters, ()>::new(4.0, 5.0, 6.0),
z_col: Vec3::<Meters, ()>::new(7.0, 8.0, 9.0),
_unit: core::marker::PhantomData,
_space: core::marker::PhantomData,
}
}
const fn _make_mat3_pixels() -> Mat3<Pixels, ()> {
Mat3 {
x_col: Vec3::<Pixels, ()>::new(10.0, 20.0, 30.0),
y_col: Vec3::<Pixels, ()>::new(40.0, 50.0, 60.0),
z_col: Vec3::<Pixels, ()>::new(70.0, 80.0, 90.0),
_unit: core::marker::PhantomData,
_space: core::marker::PhantomData,
}
}
const _CONST_MAT3_METERS2: Mat3<Meters, ()> = _make_mat3_meters();
const _CONST_MAT3_PIXELS2: Mat3<Pixels, ()> = _make_mat3_pixels();
const _CONST_MAT3_WORLD: Mat3<(), World> = Mat3 {
x_col: Vec3::<(), World>::new(1.0, 2.0, 3.0),
y_col: Vec3::<(), World>::new(4.0, 5.0, 6.0),
z_col: Vec3::<(), World>::new(7.0, 8.0, 9.0),
_unit: core::marker::PhantomData,
_space: core::marker::PhantomData,
};
const _CONST_MAT3_LOCAL: Mat3<(), Local> = Mat3 {
x_col: Vec3::<(), Local>::new(11.0, 12.0, 13.0),
y_col: Vec3::<(), Local>::new(14.0, 15.0, 16.0),
z_col: Vec3::<(), Local>::new(17.0, 18.0, 19.0),
_unit: core::marker::PhantomData,
_space: core::marker::PhantomData,
};
const _CONST_MAT3_SCREEN: Mat3<(), Screen> = Mat3 {
x_col: Vec3::<(), Screen>::new(21.0, 22.0, 23.0),
y_col: Vec3::<(), Screen>::new(24.0, 25.0, 26.0),
z_col: Vec3::<(), Screen>::new(27.0, 28.0, 29.0),
_unit: core::marker::PhantomData,
_space: core::marker::PhantomData,
};
const _: () = {
assert!(_CONST_MAT3_METERS.x_col.x == 1.0 && _CONST_MAT3_METERS.z_col.z == 9.0);
assert!(_CONST_MAT3_PIXELS.x_col.x == 10.0 && _CONST_MAT3_PIXELS.z_col.z == 90.0);
assert!(_CONST_MAT3_METERS2.x_col.x == 1.0 && _CONST_MAT3_METERS2.z_col.z == 9.0);
assert!(_CONST_MAT3_PIXELS2.x_col.x == 10.0 && _CONST_MAT3_PIXELS2.z_col.z == 90.0);
assert!(_CONST_MAT3_WORLD.x_col.x == 1.0 && _CONST_MAT3_WORLD.z_col.z == 9.0);
assert!(_CONST_MAT3_LOCAL.x_col.x == 11.0 && _CONST_MAT3_LOCAL.z_col.z == 19.0);
assert!(_CONST_MAT3_SCREEN.x_col.x == 21.0 && _CONST_MAT3_SCREEN.z_col.z == 29.0);
};