Skip to content

Commit

Permalink
Add missing Rust matrix methods
Browse files Browse the repository at this point in the history
  • Loading branch information
andykswong committed Mar 11, 2024
1 parent 962ed3a commit dd7bbf5
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod quat;
pub mod float;
pub mod scalar;
pub mod transform;
pub mod transform2d;

pub use float::{FloatEq, FloatOps};
pub use matrix::Matrix;
Expand Down
41 changes: 41 additions & 0 deletions src/matrix_special.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,47 @@ impl<T: Copy + NumAssign, const R: usize> From<Vector<T, R>> for [T; R] {
}
}

impl<T: Copy + NumAssign> From<Mat2<T>> for Mat3<T> {
/// Augments a `Mat2` into a `Mat3`
/// The resulting `Mat3` contains the given `Mat2` on upper-left with the lower-right element = 1.
///
/// # Examples
/// ```
/// # use munum::{Mat2, Mat3};
/// let m = Mat3::from(Mat2::<i32>::from_slice(&[2, 3, 4, 5]));
/// assert_eq!(*m.as_ref(), [2, 3, 0, 4, 5, 0, 0, 0, 1]);
/// ```
fn from(m: Mat2<T>) -> Self {
let mut m3 = Self::identity();
for c in 0..2 {
for r in 0..2 {
m3[(r, c)] = m[(r, c)];
}
}
m3
}
}

impl<T: Copy + NumAssign> From<Mat3<T>> for Mat2<T> {
/// Creates a `Mat2` from the upper-left 2x2 of a `Mat3`
///
/// # Examples
/// ```
/// # use munum::{Mat2, Mat3};
/// let m = Mat2::from(Mat3::<i32>::from_slice(&[2, 3, 4, 5, 6, 7, 8, 9, 1]));
/// assert_eq!(*m.as_ref(), [2, 3, 5, 6]);
/// ```
fn from(m: Mat3<T>) -> Self {
let mut m2 = Self::default();
for c in 0..2 {
for r in 0..2 {
m2[(r, c)] = m[(r, c)];
}
}
m2
}
}

impl<T: Copy + NumAssign> From<Mat3<T>> for Mat4<T> {
/// Augments a `Mat3` into a `Mat4`
/// The resulting `Mat4` contains the given `Mat3` on upper-left with the lower-right element = 1.
Expand Down
90 changes: 90 additions & 0 deletions src/transform2d.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//! 2D transformation matrix functions.
use crate::{FloatOps, Mat3, Vec2};
use num::traits::NumAssign;

/// Creates a 3x3 transformation matrix that represents a translation of (x, y).
///
/// # Examples
/// ```
/// # use munum::{transform2d, vec2};
/// assert_eq!(*transform2d::translation(vec2(2_i32, 3)).as_ref(), [1, 0, 0, 0, 1, 0, 2, 3, 1]);
/// ```
pub fn translation<T: Copy + NumAssign>(v: Vec2<T>) -> Mat3<T> {
let mut result = Mat3::identity();
result[(0, 2)] = v[0];
result[(1, 2)] = v[1];
result
}

/// Creates a 3x3 transformation matrix that represents a scaling of (x, y).
///
/// # Examples
/// ```
/// # use munum::{transform2d, vec2};
/// assert_eq!(*transform2d::scaling(vec2(2_i32, 3)).as_ref(), [2, 0, 0, 0, 3, 0, 0, 0, 1]);
/// ```
pub fn scaling<T: Copy + NumAssign>(v: Vec2<T>) -> Mat3<T> {
let mut result = Mat3::identity();
result[(0, 0)] = v[0];
result[(1, 1)] = v[1];
result
}

/// Creates a 3x3 transformation matrix that represents a rotation in couterclockwise direction.
///
/// # Examples
/// ```
/// # use munum::{transform2d, assert_float_eq};
/// assert_float_eq!(
/// transform2d::rotation(core::f32::consts::FRAC_PI_6).as_ref(),
/// &[3_f32.sqrt()/2., 0.5, 0., -0.5, 3_f32.sqrt()/2., 0., 0., 0., 1.]
/// );
/// ```
#[inline]
pub fn rotation<T: Copy + FloatOps + NumAssign>(theta: T) -> Mat3<T> {
let mut result = Mat3::identity();
let cos_theta = theta.cos();
let sin_theta = theta.sin();
result[(0, 0)] = cos_theta;
result[(1, 0)] = sin_theta;
result[(0, 1)] = T::zero() - sin_theta;
result[(1, 1)] = cos_theta;
result
}

/// Creates a 3x3 matrix that represents a transformation in TRS order (= translation * rotation * scaling).
///
/// # Examples
/// ```
/// # use munum::{transform2d, vec2, assert_float_eq};
/// assert_float_eq!(
/// transform2d::transformation(
/// vec2(11., 13.),
/// core::f32::consts::FRAC_PI_6,
/// vec2(5., 7.),
/// ).as_ref(),
/// &[5.*3_f32.sqrt()/2., 2.5, 0., -3.5, 7.*3_f32.sqrt()/2., 0., 11., 13., 1.]
/// );
/// ```
pub fn transformation<T: Copy + FloatOps + NumAssign>(
translation: Vec2<T>,
rotation_angle: T,
scaling: Vec2<T>,
) -> Mat3<T> {
// Start with rotation
let mut result: Mat3<T> = rotation(rotation_angle);

// Post-multiply scaling
for c in 0..2 {
for r in 0..2 {
result[(r, c)] *= scaling[c];
}
}

// Apply translation
result[(0, 2)] = translation[0];
result[(1, 2)] = translation[1];

result
}
4 changes: 0 additions & 4 deletions wit/world.wit
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,6 @@ interface transform2d {
translation: func(out: pmat3, v: pvec2) -> pmat3;
scaling: func(out: pmat3, v: pvec2) -> pmat3;
rotation: func(out: pmat3, theta: f64) -> pmat3;
translation-of: func(out: pvec2, m: pmat3) -> pvec2;
scaling-of: func(out: pvec2, m: pmat3) -> pvec2;
rotation-of: func(m: pmat3) -> f64;

transformation: func(out: pmat3, translate: pvec2, rotate: f64, scale: pvec2) -> pmat3;
}

Expand Down

0 comments on commit dd7bbf5

Please sign in to comment.