diff --git a/src/lib.rs b/src/lib.rs index 5673567..1ef2630 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; diff --git a/src/matrix_special.rs b/src/matrix_special.rs index d266603..bd36492 100644 --- a/src/matrix_special.rs +++ b/src/matrix_special.rs @@ -131,6 +131,47 @@ impl From> for [T; R] { } } +impl From> for Mat3 { + /// 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::::from_slice(&[2, 3, 4, 5])); + /// assert_eq!(*m.as_ref(), [2, 3, 0, 4, 5, 0, 0, 0, 1]); + /// ``` + fn from(m: Mat2) -> Self { + let mut m3 = Self::identity(); + for c in 0..2 { + for r in 0..2 { + m3[(r, c)] = m[(r, c)]; + } + } + m3 + } +} + +impl From> for Mat2 { + /// Creates a `Mat2` from the upper-left 2x2 of a `Mat3` + /// + /// # Examples + /// ``` + /// # use munum::{Mat2, Mat3}; + /// let m = Mat2::from(Mat3::::from_slice(&[2, 3, 4, 5, 6, 7, 8, 9, 1])); + /// assert_eq!(*m.as_ref(), [2, 3, 5, 6]); + /// ``` + fn from(m: Mat3) -> Self { + let mut m2 = Self::default(); + for c in 0..2 { + for r in 0..2 { + m2[(r, c)] = m[(r, c)]; + } + } + m2 + } +} + impl From> for Mat4 { /// Augments a `Mat3` into a `Mat4` /// The resulting `Mat4` contains the given `Mat3` on upper-left with the lower-right element = 1. diff --git a/src/transform2d.rs b/src/transform2d.rs new file mode 100644 index 0000000..7dfad9d --- /dev/null +++ b/src/transform2d.rs @@ -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(v: Vec2) -> Mat3 { + 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(v: Vec2) -> Mat3 { + 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(theta: T) -> Mat3 { + 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( + translation: Vec2, + rotation_angle: T, + scaling: Vec2, +) -> Mat3 { + // Start with rotation + let mut result: Mat3 = 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 +} diff --git a/wit/world.wit b/wit/world.wit index d4998d6..01fed70 100644 --- a/wit/world.wit +++ b/wit/world.wit @@ -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; }