From 956079578d065441375fdb7d189eb8eb5adbfc9c Mon Sep 17 00:00:00 2001 From: nlevy Date: Mon, 24 May 2021 14:19:24 +0200 Subject: [PATCH 1/4] Replace xz by zx in Bivec3 --- src/bivec.rs | 32 ++++---- src/interp.rs | 34 +++++++- src/rotor.rs | 205 ++++++++++++++++++++++++++++++++++-------------- src/vec/vec3.rs | 2 +- 4 files changed, 194 insertions(+), 79 deletions(-) diff --git a/src/bivec.rs b/src/bivec.rs index fc2aae4..ef33754 100644 --- a/src/bivec.rs +++ b/src/bivec.rs @@ -307,21 +307,21 @@ macro_rules! bivec3s { #[repr(C)] pub struct $bn { pub xy: $t, - pub xz: $t, + pub zx: $t, pub yz: $t, } impl EqualsEps for $bn { fn eq_eps(self, other: Self) -> bool { - self.xy.eq_eps(other.xy) && self.xz.eq_eps(other.xz) && self.yz.eq_eps(other.yz) + self.xy.eq_eps(other.xy) && self.zx.eq_eps(other.zx) && self.yz.eq_eps(other.yz) } } impl $bn { #[inline] - pub const fn new(xy: $t, xz: $t, yz: $t) -> Self { + pub const fn new(xy: $t, zx: $t, yz: $t) -> Self { Self { - xy, xz, yz + xy, zx, yz } } @@ -334,7 +334,7 @@ macro_rules! bivec3s { /// normalized 'axis vector' #[inline] pub fn from_normalized_axis(v: $vt) -> Self { - Self::new(v.z, -v.y, v.x) + Self::new(v.z, v.y, v.x) } #[inline] @@ -343,7 +343,7 @@ macro_rules! bivec3s { } #[inline] - pub fn unit_xz() -> Self { + pub fn unit_zx() -> Self { Self::new($t::splat(0.0), $t::splat(1.0), $t::splat(0.0)) } @@ -354,7 +354,7 @@ macro_rules! bivec3s { #[inline] pub fn mag_sq(&self) -> $t { - (self.xy * self.xy) + (self.xz * self.xz) + (self.yz * self.yz) + (self.xy * self.xy) + (self.zx * self.zx) + (self.yz * self.yz) } #[inline] @@ -366,7 +366,7 @@ macro_rules! bivec3s { pub fn normalize(&mut self) { let mag = self.mag(); self.xy /= mag; - self.xz /= mag; + self.zx /= mag; self.yz /= mag; } @@ -380,7 +380,7 @@ macro_rules! bivec3s { #[inline] pub fn dot(&self, rhs: Self) -> $t { - (self.xy * rhs.xy) + (self.xz * rhs.xz) + (self.yz * rhs.yz) + (self.xy * rhs.xy) + (self.zx * rhs.zx) + (self.yz * rhs.yz) } #[inline] @@ -463,7 +463,7 @@ macro_rules! bivec3s { #[inline] fn add_assign(&mut self, rhs: $bn) { self.xy += rhs.xy; - self.xz += rhs.xz; + self.zx += rhs.zx; self.yz += rhs.yz; } } @@ -481,7 +481,7 @@ macro_rules! bivec3s { #[inline] fn sub_assign(&mut self, rhs: $bn) { self.xy -= rhs.xy; - self.xz -= rhs.xz; + self.zx -= rhs.zx; self.yz -= rhs.yz; } } @@ -517,7 +517,7 @@ macro_rules! bivec3s { #[inline] fn mul_assign(&mut self, rhs: Self) { self.xy *= rhs.xy; - self.xz *= rhs.xz; + self.zx *= rhs.zx; self.yz *= rhs.yz; } } @@ -526,7 +526,7 @@ macro_rules! bivec3s { #[inline] fn mul_assign(&mut self, rhs: $t) { self.xy *= rhs; - self.xz *= rhs; + self.zx *= rhs; self.yz *= rhs; } } @@ -553,7 +553,7 @@ macro_rules! bivec3s { #[inline] fn div_assign(&mut self, rhs: $bn) { self.xy /= rhs.xy; - self.xz /= rhs.xz; + self.zx /= rhs.zx; self.yz /= rhs.yz; } } @@ -562,7 +562,7 @@ macro_rules! bivec3s { #[inline] fn div_assign(&mut self, rhs: $t) { self.xy /= rhs; - self.xz /= rhs; + self.zx /= rhs; self.yz /= rhs; } } @@ -572,7 +572,7 @@ macro_rules! bivec3s { #[inline] fn neg(mut self) -> Self { self.xy = -self.xy; - self.xz = -self.xz; + self.zx = -self.zx; self.yz = -self.yz; self } diff --git a/src/interp.rs b/src/interp.rs index b464881..0ee3011 100644 --- a/src/interp.rs +++ b/src/interp.rs @@ -100,7 +100,7 @@ macro_rules! impl_slerp_rotor3 { n.s = (c * self.s) + (s * v2.s); n.bv.xy = (c * self.bv.xy) + (s * v2.bv.xy); - n.bv.xz = (c * self.bv.xz) + (s * v2.bv.xz); + n.bv.zx = (c * self.bv.zx) + (s * v2.bv.zx); n.bv.yz = (c * self.bv.yz) + (s * v2.bv.yz); n @@ -151,7 +151,7 @@ macro_rules! impl_slerp_rotor3_wide { n.s = (c * self.s) + (s * v2.s); n.bv.xy = (c * self.bv.xy) + (s * v2.bv.xy); - n.bv.xz = (c * self.bv.xz) + (s * v2.bv.xz); + n.bv.zx = (c * self.bv.zx) + (s * v2.bv.zx); n.bv.yz = (c * self.bv.yz) + (s * v2.bv.yz); n @@ -218,3 +218,33 @@ impl_slerp_gen!( f64x2 => (DVec2x2, DVec3x2, DVec4x2, DBivec2x2, DBivec3x2, DRotor2x2), f64x4 => (DVec2x4, DVec3x4, DVec4x4, DBivec2x4, DBivec3x4, DRotor2x4) ); + +#[cfg(test)] +mod test { + use super::*; + use crate::util::EqualsEps; + use std::f32::consts::*; + #[test] + pub fn slerp_in_xy_plane() { + let rotation = Rotor3::from_rotation_xy(2. * FRAC_PI_3); + + // Expected to be a rotation by angle PI/6 + let interpolated = Rotor3::identity().slerp(rotation, 1. / 4.); + + let rotated = Vec3::unit_x().rotated_by(interpolated); + let expected = Vec3::new(3f32.sqrt() / 2., 0.5, 0.); + assert!(rotated.eq_eps(expected)) + } + + #[test] + pub fn slerp_in_zx_plane() { + let rotation = Rotor3::from_rotation_zx(2. * FRAC_PI_3); + + // Expected to be a rotation by angle PI/6 + let interpolated = Rotor3::identity().slerp(rotation, 1. / 4.); + + let rotated = Vec3::unit_z().rotated_by(interpolated); + let expected = Vec3::new(0.5, 0., 3f32.sqrt() / 2.); + assert!(rotated.eq_eps(expected)) + } +} diff --git a/src/rotor.rs b/src/rotor.rs index 3080587..c6612f0 100644 --- a/src/rotor.rs +++ b/src/rotor.rs @@ -420,11 +420,11 @@ macro_rules! rotor3s { Self::from_angle_plane(angle, $bt::unit_xy()) } - /// Create new Rotor from a rotation in the xz plane (also known as + /// Create new Rotor from a rotation in the zx plane (also known as /// "around the y axis"). #[inline] - pub fn from_rotation_xz(angle: $t) -> Self { - Self::from_angle_plane(angle, $bt::unit_xz()) + pub fn from_rotation_zx(angle: $t) -> Self { + Self::from_angle_plane(angle, $bt::unit_zx()) } /// Create new Rotor from a rotation in the yz plane (also known as @@ -438,10 +438,10 @@ macro_rules! rotor3s { /// /// - Roll is rotation inside the xy plane ("around the z axis") /// - Pitch is rotation inside the yz plane ("around the x axis") - /// - Yaw is rotation inside the xz plane ("around the y axis") + /// - Yaw is rotation inside the zx plane ("around the y axis") #[inline] pub fn from_euler_angles(roll: $t, pitch: $t, yaw: $t) -> Self { - Self::from_angle_plane(yaw, $bt::unit_xz()) + Self::from_angle_plane(yaw, $bt::unit_zx()) * Self::from_angle_plane(pitch, $bt::unit_yz()) * Self::from_angle_plane(roll, $bt::unit_xy()) } @@ -461,7 +461,7 @@ macro_rules! rotor3s { let mag = self.mag(); self.s /= mag; self.bv.xy /= mag; - self.bv.xz /= mag; + self.bv.zx /= mag; self.bv.yz /= mag; } @@ -507,31 +507,31 @@ macro_rules! rotor3s { let two = $t::splat(2.0); let sa2 = a.s * a.s; let baxy2 = a.bv.xy * a.bv.xy; - let baxz2 = a.bv.xz * a.bv.xz; + let bazx2 = a.bv.zx * a.bv.zx; let bayz2 = a.bv.yz * a.bv.yz; let sa_baxy = a.s * a.bv.xy; - let sa_baxz = a.s * a.bv.xz; + let sa_bazx = a.s * a.bv.zx; let sa_bayz = a.s * a.bv.yz; - let baxy_baxz = a.bv.xy * a.bv.xz; + let baxy_bazx = a.bv.xy * a.bv.zx; let baxy_bayz = a.bv.xy * a.bv.yz; - let baxz_bayz = a.bv.xz * a.bv.yz; + let bazx_bayz = a.bv.zx * a.bv.yz; let two_bbxy = two * b.bv.xy; - let two_bbxz = two * b.bv.xz; + let two_bbzx = two * b.bv.zx; let two_bbyz = two * b.bv.yz; - self.s = (sa2 + baxy2 + baxz2 + bayz2) * b.s; + self.s = (sa2 + baxy2 + bazx2 + bayz2) * b.s; - self.bv.xy = (sa2 + baxy2 - baxz2 - bayz2) * b.bv.xy - + (baxy_baxz + sa_bayz) * two_bbxz - + (baxy_bayz - sa_baxz) * two_bbyz; + self.bv.xy = (sa2 + baxy2 - bazx2 - bayz2) * b.bv.xy + + (baxy_bazx + sa_bayz) * two_bbzx + + (baxy_bayz - sa_bazx) * two_bbyz; - self.bv.xz = (sa2 - baxy2 + baxz2 - bayz2) * b.bv.xz - + (baxy_baxz - sa_bayz) * two_bbxy - + (baxz_bayz + sa_baxy) * two_bbyz; + self.bv.zx = (sa2 - baxy2 + bazx2 - bayz2) * b.bv.zx + + (baxy_bazx - sa_bayz) * two_bbxy + + (bazx_bayz + sa_baxy) * two_bbyz; - self.bv.yz = (sa2 - baxy2 - baxz2 + bayz2) * b.bv.yz - + (baxy_bayz + sa_baxz) * two_bbxy - + (baxz_bayz - sa_baxy) * two_bbxz; + self.bv.yz = (sa2 - baxy2 - bazx2 + bayz2) * b.bv.yz + + (baxy_bayz + sa_bazx) * two_bbxy + + (bazx_bayz - sa_baxy) * two_bbzx; } /// Rotates this rotor by another rotor and returns the result. Note that if you @@ -555,15 +555,15 @@ macro_rules! rotor3s { pub fn rotate_vec(self, vec: &mut $vt) { // see derivation/rotor3_rotate_vec_derivation for a derivation // f = geometric product of (self)(vec) - let fx = self.s * vec.x + self.bv.xy * vec.y + self.bv.xz * vec.z; + let fx = self.s * vec.x + self.bv.xy * vec.y - self.bv.zx * vec.z; let fy = self.s * vec.y - self.bv.xy * vec.x + self.bv.yz * vec.z; - let fz = self.s * vec.z - self.bv.xz * vec.x - self.bv.yz * vec.y; - let fw = self.bv.xy * vec.z - self.bv.xz * vec.y + self.bv.yz * vec.x; + let fz = self.s * vec.z + self.bv.zx * vec.x - self.bv.yz * vec.y; + let fw = self.bv.xy * vec.z + self.bv.zx * vec.y + self.bv.yz * vec.x; // result = geometric product of (f)(self~) - vec.x = self.s * fx + self.bv.xy * fy + self.bv.xz * fz + self.bv.yz * fw; - vec.y = self.s * fy - self.bv.xy * fx - self.bv.xz * fw + self.bv.yz * fz; - vec.z = self.s * fz + self.bv.xy * fw - self.bv.xz * fx - self.bv.yz * fy; + vec.x = self.s * fx + self.bv.xy * fy - self.bv.zx * fz + self.bv.yz * fw; + vec.y = self.s * fy - self.bv.xy * fx + self.bv.zx * fw + self.bv.yz * fz; + vec.z = self.s * fz + self.bv.xy * fw + self.bv.zx * fx - self.bv.yz * fy; } /// Rotates multiple vectors by this rotor. @@ -575,26 +575,26 @@ macro_rules! rotor3s { pub fn rotate_vecs(self, vecs: &mut [$vt]) { let s2 = self.s * self.s; let bxy2 = self.bv.xy * self.bv.xy; - let bxz2 = self.bv.xz * self.bv.xz; + let bzx2 = self.bv.zx * self.bv.zx; let byz2 = self.bv.yz * self.bv.yz; let s_bxy = self.s * self.bv.xy; - let s_bxz = self.s * self.bv.xz; + let s_bzx = self.s * self.bv.zx; let s_byz = self.s * self.bv.yz; - let bxz_byz = self.bv.xz * self.bv.yz; + let bzx_byz = self.bv.zx * self.bv.yz; let bxy_byz = self.bv.xy * self.bv.yz; - let bxy_bxz = self.bv.xy * self.bv.xz; + let bxy_bzx = self.bv.xy * self.bv.zx; - let xa = s2 - bxy2 - bxz2 + byz2; - let xb = s_bxy - bxz_byz; - let xc = s_bxz + bxy_byz; + let xa = s2 - bxy2 - bzx2 + byz2; + let xb = -(s_bxy + bzx_byz); + let xc = -s_bzx + bxy_byz; - let ya = -(bxz_byz + s_bxy); - let yb = s2 - bxy2 + bxz2 - byz2; - let yc = s_byz - bxy_bxz; + let ya = bzx_byz - s_bxy; + let yb = s2 - bxy2 + bzx2 - byz2; + let yc = -(s_byz + bxy_bzx); - let za = bxy_byz - s_bxz; - let zb = bxy_bxz + s_byz; - let zc = -(s2 + bxy2 - bxz2 - byz2); + let za = -(bxy_byz + s_bzx); + let zb = bxy_bzx - s_byz; + let zc = s2 + bxy2 - bzx2 - byz2; for vec in vecs { let two_vx = vec.x + vec.x; @@ -603,7 +603,7 @@ macro_rules! rotor3s { vec.x = vec.x * xa + two_vy * xb + two_vz * xc; vec.y = two_vx * ya + vec.y * yb + two_vz * yc; - vec.z = two_vx * za - two_vy * zb - vec.z * zc; + vec.z = two_vx * za + two_vy * zb + vec.z * zc; } } @@ -611,31 +611,31 @@ macro_rules! rotor3s { pub fn into_matrix(self) -> $mt { let s2 = self.s * self.s; let bxy2 = self.bv.xy * self.bv.xy; - let bxz2 = self.bv.xz * self.bv.xz; + let bzx2 = self.bv.zx * self.bv.zx; let byz2 = self.bv.yz * self.bv.yz; let s_bxy = self.s * self.bv.xy; - let s_bxz = self.s * self.bv.xz; + let s_bzx = self.s * self.bv.zx; let s_byz = self.s * self.bv.yz; - let bxz_byz = self.bv.xz * self.bv.yz; + let bzx_byz = self.bv.zx * self.bv.yz; let bxy_byz = self.bv.xy * self.bv.yz; - let bxy_bxz = self.bv.xy * self.bv.xz; + let bxy_bzx = self.bv.xy * self.bv.zx; let two = $t::splat(2.0); $mt::new( $vt::new( - s2 - bxy2 - bxz2 + byz2, - -two * (bxz_byz + s_bxy), - two * (bxy_byz - s_bxz)), + s2 - bxy2 - bzx2 + byz2, + -two * (bzx_byz + s_bxy), + two * (bxy_byz - s_bzx)), $vt::new( - two * (s_bxy - bxz_byz), - s2 - bxy2 + bxz2 - byz2, - -two * (s_byz + bxy_bxz) + two * (s_bxy - bzx_byz), + s2 - bxy2 + bzx2 - byz2, + -two * (s_byz + bxy_bzx) ), $vt::new( - two * (s_bxz + bxy_byz), - two * (s_byz - bxy_bxz), - s2 + bxy2 - bxz2 - byz2 + -two * (s_bzx + bxy_byz), + two * (s_byz - bxy_bzx), + s2 + bxy2 - bzx2 - byz2 ) ) } @@ -644,7 +644,7 @@ macro_rules! rotor3s { /// `[vector, scalar]`. #[inline] pub fn into_quaternion_array(self) -> [$t; 4] { - [-self.bv.yz, self.bv.xz, -self.bv.xy, self.s] + [-self.bv.yz, self.bv.zx, -self.bv.xy, self.s] } /// Convert an array that represents a quaternion in the form `[vector, scalar]` into a @@ -684,11 +684,11 @@ macro_rules! rotor3s { #[inline] fn mul(self, q: Self) -> Self { Self { - s: self.s * q.s - self.bv.xy * q.bv.xy - self.bv.xz * q.bv.xz - self.bv.yz * q.bv.yz, + s: self.s * q.s - self.bv.xy * q.bv.xy - self.bv.zx * q.bv.zx - self.bv.yz * q.bv.yz, bv: $bt { - xy: self.bv.xy * q.s + self.s * q.bv.xy + self.bv.yz * q.bv.xz - self.bv.xz * q.bv.yz, - xz: self.bv.xz * q.s + self.s * q.bv.xz - self.bv.yz * q.bv.xy + self.bv.xy * q.bv.yz, - yz: self.bv.yz * q.s + self.s * q.bv.yz + self.bv.xz * q.bv.xy - self.bv.xy * q.bv.xz, + xy: self.bv.xy * q.s + self.s * q.bv.xy - self.bv.yz * q.bv.zx + self.bv.zx * q.bv.yz, + zx: self.bv.zx * q.s + self.s * q.bv.zx + self.bv.yz * q.bv.xy - self.bv.xy * q.bv.yz, + yz: self.bv.yz * q.s + self.s * q.bv.yz - self.bv.zx * q.bv.xy + self.bv.xy * q.bv.zx, } } } @@ -799,6 +799,90 @@ rotor3s!( mod test { use super::*; + #[test] + pub fn rotation_plane_xy() { + use std::f32::consts::*; + let rotation = Rotor3::from_rotation_xy(FRAC_PI_3); + let rotated = Vec3::unit_x().rotated_by(rotation); + let expected = Vec3::new(0.5, 3f32.sqrt() / 2., 0.); + assert!(rotated.eq_eps(expected)) + } + + #[test] + pub fn rotation_plane_zx() { + use std::f32::consts::*; + let rotation = Rotor3::from_rotation_zx(FRAC_PI_3); + let rotated = Vec3::unit_z().rotated_by(rotation); + let expected = Vec3::new(3f32.sqrt() / 2., 0., 0.5); + assert!(rotated.eq_eps(expected)) + } + + #[test] + pub fn rotation_plane_yz() { + use std::f32::consts::*; + let rotation = Rotor3::from_rotation_yz(FRAC_PI_3); + let rotated = Vec3::unit_y().rotated_by(rotation); + let expected = Vec3::new(0., 0.5, 3f32.sqrt() / 2.); + assert!(rotated.eq_eps(expected)) + } + + #[test] + pub fn rotation_plane_xy_by_matrix() { + use std::f32::consts::*; + let rotation = Rotor3::from_rotation_xy(FRAC_PI_3); + let rotated = rotation.into_matrix() * Vec3::unit_x(); + let expected = Vec3::new(0.5, 3f32.sqrt() / 2., 0.); + assert!(rotated.eq_eps(expected)) + } + + #[test] + pub fn rotation_plane_zx_by_matrix() { + use std::f32::consts::*; + let rotation = Rotor3::from_rotation_zx(FRAC_PI_3); + let rotated = rotation.into_matrix() * Vec3::unit_z(); + let expected = Vec3::new(3f32.sqrt() / 2., 0., 0.5); + assert!(rotated.eq_eps(expected)) + } + + #[test] + pub fn rotation_plane_yz_by_matrix() { + use std::f32::consts::*; + let rotation = Rotor3::from_rotation_yz(FRAC_PI_3); + let rotated = rotation.into_matrix() * Vec3::unit_y(); + let expected = Vec3::new(0., 0.5, 3f32.sqrt() / 2.); + assert!(rotated.eq_eps(expected)) + } + + #[test] + pub fn rotate_vecs_plane_xy() { + use std::f32::consts::*; + let rotation = Rotor3::from_rotation_xy(FRAC_PI_3); + let mut vecs = vec![Vec3::new(1., 0., 12.)]; + rotation.rotate_vecs(&mut vecs); + let expected = Vec3::new(0.5, 3f32.sqrt() / 2., 12.); + assert!(vecs[0].eq_eps(expected)) + } + + #[test] + pub fn rotate_vecs_plane_zx() { + use std::f32::consts::*; + let rotation = Rotor3::from_rotation_zx(FRAC_PI_3); + let mut vecs = vec![Vec3::new(0., 12., 1.)]; + rotation.rotate_vecs(&mut vecs); + let expected = Vec3::new(3f32.sqrt() / 2., 12., 0.5); + assert!(vecs[0].eq_eps(expected)) + } + + #[test] + pub fn rotate_vecs_plane_yz() { + use std::f32::consts::*; + let rotation = Rotor3::from_rotation_yz(FRAC_PI_3); + let mut vecs = vec![Vec3::new(12., 1., 0.)]; + rotation.rotate_vecs(&mut vecs); + let expected = Vec3::new(12., 0.5, 3f32.sqrt() / 2.); + assert!(vecs[0].eq_eps(expected)) + } + #[test] pub fn rotate_vector_roundtrip() { let a = Vec3::new(1.0, 2.0, -5.0).normalized(); @@ -836,9 +920,10 @@ mod test { let c = Vec3::new(-3.0, 0.0, -1.0).normalized(); let rotor_ab = Rotor3::from_rotation_between(a, b); let rotor_bc = Rotor3::from_rotation_between(b, c); + let rotor_ac = Rotor3::from_rotation_between(a, c); let rotor_abbc = rotor_bc * rotor_ab; let res = rotor_abbc * a; - println!("{:#?} {:#?}", rotor_abbc, res); + println!("{:#?} {:#?} {:#?}", rotor_abbc, rotor_ac, res); assert!(c.eq_eps(res)); } diff --git a/src/vec/vec3.rs b/src/vec/vec3.rs index eab9af4..d504849 100644 --- a/src/vec/vec3.rs +++ b/src/vec/vec3.rs @@ -91,7 +91,7 @@ macro_rules! vec3s { pub fn wedge(&self, other: $n) -> $bn { $bn::new( (self.x * other.y) - (self.y * other.x), - (self.x * other.z) - (self.z * other.x), + (self.z * other.x) - (self.x * other.z), (self.y * other.z) - (self.z * other.y), ) } From 45191ecaa0cae2b61024f0fb62e4b8edd64852f8 Mon Sep 17 00:00:00 2001 From: nlevy Date: Mon, 24 May 2021 14:32:15 +0200 Subject: [PATCH 2/4] Fix serde implementation --- src/impl_serde.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/impl_serde.rs b/src/impl_serde.rs index ba9579f..ab5647e 100644 --- a/src/impl_serde.rs +++ b/src/impl_serde.rs @@ -1165,7 +1165,7 @@ impl Serialize for Bivec3 { { let mut state = serializer.serialize_struct("Bivec3", 3)?; state.serialize_field("xy", &self.xy)?; - state.serialize_field("xz", &self.xz)?; + state.serialize_field("zx", &self.zx)?; state.serialize_field("yz", &self.yz)?; state.end() } From f3720e03fd8b5eb594a929df1ecfdd346b1322c9 Mon Sep 17 00:00:00 2001 From: nlevy Date: Mon, 24 May 2021 15:45:21 +0200 Subject: [PATCH 3/4] Fix mat3 <-> rotor3 conversions --- src/mat.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++++----- src/rotor.rs | 43 +++++++++++++++++++------- 2 files changed, 111 insertions(+), 18 deletions(-) diff --git a/src/mat.rs b/src/mat.rs index d0f3352..0898a4a 100644 --- a/src/mat.rs +++ b/src/mat.rs @@ -963,9 +963,9 @@ macro_rules! impl_mat3 { s.copysign(self[2][1] - self[1][2]) }; - let xz = { + let zx = { let s = ($t::splat(1.0) - self[0][0] + self[1][1] - self[2][2]).max($t::splat(0.0)).sqrt() * $t::splat(0.5); - s.copysign(self[2][0] - self[0][2]) + s.copysign(self[0][2] - self[2][0]) }; let xy = { @@ -973,7 +973,7 @@ macro_rules! impl_mat3 { s.copysign(self[1][0] - self[0][1]) }; - $rt::new(w, $bt::new(xy, xz, yz)) + $rt::new(w, $bt::new(xy, zx, yz)) } })+ } @@ -1001,9 +1001,9 @@ macro_rules! impl_mat3_wide { s.flip_signs(self[2][1] - self[1][2]) }; - let xz = { + let zx = { let s = ($t::splat(1.0) - self[0][0] + self[1][1] - self[2][2]).max($t::splat(0.0)).sqrt() * $t::splat(0.5); - s.flip_signs(self[2][0] - self[0][2]) + s.flip_signs(self[0][2] - self[2][0]) }; let xy = { @@ -1011,7 +1011,7 @@ macro_rules! impl_mat3_wide { s.flip_signs(self[1][0] - self[0][1]) }; - $rt::new(w, $bt::new(xy, xz, yz)) + $rt::new(w, $bt::new(xy, zx, yz)) } })+ } @@ -1890,7 +1890,79 @@ mod test { let iso = Isometry3::new(c, r_ab); let iso_mat4 = iso.into_homogeneous_matrix(); let iso_ = iso_mat4.into_isometry(); + println!("{:#?}, {:#?}", r_ab.into_matrix(), iso_mat4); + println!("{:#?}, {:#?}", r_ab, iso_.rotation); assert!(iso_.translation.eq_eps(c)); - assert!(iso_.rotation.eq_eps(r_ab)); + assert!(a.rotated_by(iso_.rotation).eq_eps(b)); + } + + #[test] + pub fn matrix_to_rotor_roundtrip() { + let a = Vec3::new(1.0, 2.0, -5.0).normalized(); + let b = Vec3::new(1.0, 1.0, 1.0).normalized(); + let r_ab = Rotor3::from_rotation_between(a, b); + assert!(a.rotated_by(r_ab).eq_eps(b)); + let mat_ab = r_ab.into_matrix(); + assert!((mat_ab * a).eq_eps(b)); + + let r_ab_2 = mat_ab.into_rotor3(); + assert!(a.rotated_by(r_ab_2).eq_eps(b)); + } + + #[test] + pub fn rotation_plane_xy() { + use std::f32::consts::*; + let matrix = Mat3::from_rotation_z(FRAC_PI_3); + let rotated = matrix * Vec3::unit_x(); + let expected = Vec3::new(0.5, 3f32.sqrt() / 2., 0.); + assert!(rotated.eq_eps(expected)) + } + + #[test] + pub fn rotation_plane_zx() { + use std::f32::consts::*; + let matrix = Mat3::from_rotation_y(FRAC_PI_3); + let rotated = matrix * Vec3::unit_z(); + let expected = Vec3::new(3f32.sqrt() / 2., 0., 0.5); + assert!(rotated.eq_eps(expected)) + } + + #[test] + pub fn rotation_plane_yz() { + use std::f32::consts::*; + let matrix = Mat3::from_rotation_x(FRAC_PI_3); + let rotated = matrix * Vec3::unit_y(); + let expected = Vec3::new(0., 0.5, 3f32.sqrt() / 2.); + assert!(rotated.eq_eps(expected)) + } + + #[test] + pub fn rotation_plane_xy_by_rotor() { + use std::f32::consts::*; + let matrix = Mat3::from_rotation_z(FRAC_PI_3); + let rotor = matrix.into_rotor3(); + let rotated = Vec3::unit_x().rotated_by(rotor); + let expected = Vec3::new(0.5, 3f32.sqrt() / 2., 0.); + assert!(rotated.eq_eps(expected)) + } + + #[test] + pub fn rotation_plane_zx_by_rotor() { + use std::f32::consts::*; + let matrix = Mat3::from_rotation_y(FRAC_PI_3); + let rotor = matrix.into_rotor3(); + let rotated = Vec3::unit_z().rotated_by(rotor); + let expected = Vec3::new(3f32.sqrt() / 2., 0., 0.5); + assert!(rotated.eq_eps(expected)) + } + + #[test] + pub fn rotation_plane_yz_by_rotor() { + use std::f32::consts::*; + let matrix = Mat3::from_rotation_x(FRAC_PI_3); + let rotor = matrix.into_rotor3(); + let rotated = Vec3::unit_y().rotated_by(rotor); + let expected = Vec3::new(0., 0.5, 3f32.sqrt() / 2.); + assert!(rotated.eq_eps(expected)) } } diff --git a/src/rotor.rs b/src/rotor.rs index c6612f0..3ea1ce8 100644 --- a/src/rotor.rs +++ b/src/rotor.rs @@ -585,14 +585,14 @@ macro_rules! rotor3s { let bxy_bzx = self.bv.xy * self.bv.zx; let xa = s2 - bxy2 - bzx2 + byz2; - let xb = -(s_bxy + bzx_byz); + let xb = s_bxy + bzx_byz; let xc = -s_bzx + bxy_byz; let ya = bzx_byz - s_bxy; let yb = s2 - bxy2 + bzx2 - byz2; - let yc = -(s_byz + bxy_bzx); + let yc = s_byz + bxy_bzx; - let za = -(bxy_byz + s_bzx); + let za = bxy_byz + s_bzx; let zb = bxy_bzx - s_byz; let zc = s2 + bxy2 - bzx2 - byz2; @@ -625,16 +625,16 @@ macro_rules! rotor3s { $mt::new( $vt::new( s2 - bxy2 - bzx2 + byz2, - -two * (bzx_byz + s_bxy), - two * (bxy_byz - s_bzx)), + two * (bzx_byz - s_bxy), + two * (bxy_byz + s_bzx)), $vt::new( - two * (s_bxy - bzx_byz), + two * (s_bxy + bzx_byz), s2 - bxy2 + bzx2 - byz2, - -two * (s_byz + bxy_bzx) + two * (-s_byz + bxy_bzx) ), $vt::new( - -two * (s_bzx + bxy_byz), - two * (s_byz - bxy_bzx), + two * (-s_bzx + bxy_byz), + two * (s_byz + bxy_bzx), s2 + bxy2 - bzx2 - byz2 ) ) @@ -644,14 +644,14 @@ macro_rules! rotor3s { /// `[vector, scalar]`. #[inline] pub fn into_quaternion_array(self) -> [$t; 4] { - [-self.bv.yz, self.bv.zx, -self.bv.xy, self.s] + [-self.bv.yz, -self.bv.zx, -self.bv.xy, self.s] } /// Convert an array that represents a quaternion in the form `[vector, scalar]` into a /// rotor. #[inline] pub fn from_quaternion_array(array: [$t; 4]) -> Self { - Self::new(array[3], $bt::new(-array[2], array[1], -array[0])) + Self::new(array[3], $bt::new(-array[2], -array[1], -array[0])) } #[inline] @@ -901,6 +901,27 @@ mod test { assert!(rot_abc.eq_eps(c)); } + #[test] + pub fn rotate_vector_roundtrip_with_rotate_vecs() { + let a = Vec3::new(1.0, 2.0, -5.0).normalized(); + let b = Vec3::new(1.0, 1.0, 1.0).normalized(); + let c = Vec3::new(2.0, 3.0, -3.0).normalized(); + let rotor_ab = Rotor3::from_rotation_between(a, b); + let rotor_bc = Rotor3::from_rotation_between(b, c); + let mut arg_ab = vec![a.clone()]; + rotor_ab.rotate_vecs(&mut arg_ab); + let mut arg_bc = vec![b.clone()]; + rotor_bc.rotate_vecs(&mut arg_bc); + let mut arg_abc = vec![rotor_ab * a]; + rotor_bc.rotate_vecs(&mut arg_abc); + println!("{:?} = {:?}", arg_ab[0], b); + println!("{:?} = {:?}", arg_bc[0], c); + println!("{:?} = {:?}", arg_abc[0], c); + assert!(arg_ab[0].eq_eps(b)); + assert!(arg_bc[0].eq_eps(c)); + assert!(arg_abc[0].eq_eps(c)); + } + #[test] pub fn rotate_rotor_trivial() { let a = Vec3::new(1.0, 2.0, -5.0).normalized(); From 8a9210a14ecfb49daf00468fc7e853046bfca812 Mon Sep 17 00:00:00 2001 From: nlevy Date: Mon, 24 May 2021 15:53:53 +0200 Subject: [PATCH 4/4] Add an other test for mat3 <-> rotor3 conversions --- src/rotor.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/rotor.rs b/src/rotor.rs index 3ea1ce8..48c5cb8 100644 --- a/src/rotor.rs +++ b/src/rotor.rs @@ -922,6 +922,24 @@ mod test { assert!(arg_abc[0].eq_eps(c)); } + #[test] + pub fn rotate_vector_roundtrip_with_matrices() { + let a = Vec3::new(1.0, 2.0, -5.0).normalized(); + let b = Vec3::new(1.0, 1.0, 1.0).normalized(); + let c = Vec3::new(2.0, 3.0, -3.0).normalized(); + let rotor_ab = Rotor3::from_rotation_between(a, b).into_matrix(); + let rotor_bc = Rotor3::from_rotation_between(b, c).into_matrix(); + let rot_ab = rotor_ab * a; + let rot_bc = rotor_bc * b; + let rot_abc = rotor_bc * (rotor_ab * a); + println!("{:?} = {:?}", rot_ab, b); + println!("{:?} = {:?}", rot_bc, c); + println!("{:?} = {:?}", rot_abc, c); + assert!(rot_ab.eq_eps(b)); + assert!(rot_bc.eq_eps(c)); + assert!(rot_abc.eq_eps(c)); + } + #[test] pub fn rotate_rotor_trivial() { let a = Vec3::new(1.0, 2.0, -5.0).normalized();