diff --git a/ega/src/outermorphisms/mod.rs b/ega/src/outermorphisms/mod.rs index 0737bf9..2feb57a 100644 --- a/ega/src/outermorphisms/mod.rs +++ b/ega/src/outermorphisms/mod.rs @@ -1,5 +1,8 @@ mod matrix_4x4; +mod uniform_scale; + pub use matrix_4x4::Matrix4x4; +pub use uniform_scale::UniformScale; /// A linear mapping extended to multivectors pub trait Outermorphism { diff --git a/ega/src/outermorphisms/uniform_scale.rs b/ega/src/outermorphisms/uniform_scale.rs new file mode 100644 index 0000000..d664b03 --- /dev/null +++ b/ega/src/outermorphisms/uniform_scale.rs @@ -0,0 +1,210 @@ +use crate::*; + +#[derive(Debug, Copy, Clone)] +pub struct UniformScale { + pub scale: f32, +} + +impl UniformScale { + #[inline] + pub fn new(scale: f32) -> Self { + UniformScale { scale } + } +} + +macro_rules! impl_outermorphism { + ($morph_fn:ident: $morph:ty, $arg:ty => $ret:ty) => { + impl Outermorphism<$arg> for $morph { + fn morph(self, arg: $arg) -> $ret { + $morph_fn(self, arg) + } + } + }; +} + +impl_outermorphism! { return_empty: UniformScale, Empty => Empty } +impl_outermorphism! { uniform_scale_morph_scalar: UniformScale, Scalar => Scalar } +impl_outermorphism! { uniform_scale_morph_vector: UniformScale, Vector => Vector } +impl_outermorphism! { uniform_scale_morph_bivector: UniformScale, Bivector => Bivector } +impl_outermorphism! { uniform_scale_morph_trivector: UniformScale, Trivector => Trivector } +impl_outermorphism! { uniform_scale_morph_pseudo_scalar: UniformScale, Pseudoscalar => Pseudoscalar } +impl_outermorphism! { uniform_scale_morph_multivector: UniformScale, Multivector => Multivector } + +#[inline] +fn uniform_scale_morph_scalar(_: UniformScale, s: Scalar) -> Scalar { + s +} + +#[rustfmt::skip] +#[inline] +fn uniform_scale_morph_vector( + UniformScale { scale }: UniformScale, + Vector { mut e0, mut e1, mut e2, mut e3 }: Vector +) -> Vector { + + e0 *= scale; + e1 *= scale; + e2 *= scale; + e3 *= scale; + + Vector { e0, e1, e2, e3 } +} + +#[rustfmt::skip] +#[inline] +fn uniform_scale_morph_bivector( + UniformScale { scale }: UniformScale, + Bivector { + mut e23, mut e31, mut e12, + mut e01, mut e02, mut e03, + }: Bivector +) -> Bivector { + + let scale2 = scale*scale; + + e23 *= scale2; + e03 *= scale2; + e31 *= scale2; + e01 *= scale2; + e12 *= scale2; + e02 *= scale2; + + Bivector { e23, e31, e12, e01, e02, e03 } +} + +#[rustfmt::skip] +#[inline] +fn uniform_scale_morph_trivector( + UniformScale { scale }: UniformScale, + Trivector { mut e123, mut e032, mut e013, mut e021 }: Trivector +) -> Trivector { + + let scale3 = scale.powi(3); + + e123 *= scale3; + e032 *= scale3; + e013 *= scale3; + e021 *= scale3; + + Trivector { + e123, e032, e013, e021 + } +} + +#[rustfmt::skip] +#[inline] +fn uniform_scale_morph_pseudo_scalar( + UniformScale { scale }: UniformScale, + Pseudoscalar { + mut e0123 + }: Pseudoscalar, +) -> Pseudoscalar { + + e0123 *= scale.powi(4); + + Pseudoscalar { e0123 } +} + +#[rustfmt::skip] +#[inline] +fn uniform_scale_morph_multivector( + UniformScale { scale }: UniformScale, + Multivector { + mut e0, mut e1, mut e2, mut e3, + s, mut e23, mut e31, mut e12, + mut e01, mut e02, mut e03, mut e0123, + mut e123, mut e032, mut e013, mut e021, + }: Multivector, +) -> Multivector { + + let scale2 = scale*scale; + let scale3 = scale*scale2; + let scale4 = scale2*scale2; + + e0 *= scale; + e1 *= scale; + e2 *= scale; + e3 *= scale; + e23 *= scale2; + e03 *= scale2; + e31 *= scale2; + e01 *= scale2; + e12 *= scale2; + e02 *= scale2; + e123 *= scale3; + e032 *= scale3; + e013 *= scale3; + e021 *= scale3; + e0123 *= scale4; + + Multivector { + e0, e1, e2, e3, + s, e23, e31, e12, + e01, e02, e03, e0123, + e123, e032, e013, e021, + } +} + +#[cfg(any(test, doctest))] +mod tests { + use super::*; + use crate::test_values::*; + use ::approx::assert_ulps_eq; + + #[test] + fn morph_scalar() { + let scale = UniformScale::new(3.0); + + let result = scale.morph(SCALAR_A); + let expected = SCALAR_A; + assert_eq!(dbg!(result), dbg!(expected)); + } + + #[test] + #[rustfmt::skip] + fn morph_vector() { + let scale = UniformScale::new(3.0); + + let result = scale.morph(VECTOR_A); + let expected = Vector { + e0: 453., e1: 471., e2: 489., e3: 501., + }; + assert_ulps_eq!(dbg!(result), dbg!(expected), max_ulps = 2); + } + + #[test] + fn morph_bivector() { + let scale = UniformScale::new(3.0); + + let a = Meet::meet(scale.morph(VECTOR_A), scale.morph(VECTOR_B)); + let b = scale.morph(Meet::meet(VECTOR_A, VECTOR_B)); + assert_ulps_eq!(dbg!(a), dbg!(b), max_ulps = 90); + } + + #[test] + fn morph_trivector() { + let scale = UniformScale::new(3.0); + + let a = Meet::meet(scale.morph(VECTOR_A), scale.morph(BIVECTOR_A)); + let b = scale.morph(Meet::meet(VECTOR_A, BIVECTOR_A)); + assert_ulps_eq!(dbg!(a), dbg!(b), max_ulps = 2); + } + + #[test] + fn morph_pseudoscalar() { + let scale = UniformScale::new(3.0); + + let a = Meet::meet(scale.morph(VECTOR_A), scale.morph(TRIVECTOR_A)); + let b = scale.morph(Meet::meet(VECTOR_A, TRIVECTOR_A)); + assert_ulps_eq!(dbg!(a), dbg!(b), max_ulps = 1); + } + + #[test] + fn morph_multivector() { + let scale = UniformScale::new(3.0); + + let a = Meet::meet(scale.morph(MULTIVECTOR_A), scale.morph(MULTIVECTOR_B)); + let b = scale.morph(Meet::meet(MULTIVECTOR_A, MULTIVECTOR_B)); + assert_ulps_eq!(dbg!(a), dbg!(b), max_ulps = 10); + } +}