Fix Euler angle to matrix conversion
The equations were written with rows horizontally instead of vertically and some signs were wrong.
This commit is contained in:
parent
b56119a42f
commit
c11371794f
3 changed files with 121 additions and 10 deletions
|
@ -8,8 +8,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Fix quaternion to Euler angles and Euler angles to quaternion conversion. The axes are now
|
- Fix Euler angles to quaternion and quaternion to Euler angles conversion. The axes are now
|
||||||
correct, and the order the angles are applied is XYZ.
|
correct, and the order the angles are applied is XYZ. The conversion now matches the conversion
|
||||||
|
from axis angle.
|
||||||
|
- Fix Euler angles to matrix conversion.
|
||||||
|
|
||||||
## [v0.9.1] - 2016-04-20
|
## [v0.9.1] - 2016-04-20
|
||||||
|
|
||||||
|
|
|
@ -1000,14 +1000,14 @@ impl<A> From<Euler<A>> for Matrix3<<A as Angle>::Unitless> where
|
||||||
A: Angle + Into<Rad<<A as Angle>::Unitless>>,
|
A: Angle + Into<Rad<<A as Angle>::Unitless>>,
|
||||||
{
|
{
|
||||||
fn from(src: Euler<A>) -> Matrix3<A::Unitless> {
|
fn from(src: Euler<A>) -> Matrix3<A::Unitless> {
|
||||||
// http://en.wikipedia.org/wiki/Rotation_matrix#General_rotations
|
// Page A-2: http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf
|
||||||
let (sx, cx) = Rad::sin_cos(src.x.into());
|
let (sx, cx) = Rad::sin_cos(src.x.into());
|
||||||
let (sy, cy) = Rad::sin_cos(src.y.into());
|
let (sy, cy) = Rad::sin_cos(src.y.into());
|
||||||
let (sz, cz) = Rad::sin_cos(src.z.into());
|
let (sz, cz) = Rad::sin_cos(src.z.into());
|
||||||
|
|
||||||
Matrix3::new(cy * cz, cy * sz, -sy,
|
Matrix3::new(cy * cz, cx * sz + sx * sy * cz, sx * sz - cx * sy * cz,
|
||||||
-cx * sz + sx * sy * cz, cx * cz + sx * sy * sz, sx * cy,
|
-cy * sz, cx * cz - sx * sy * sz, sx * cz + cx * sy * sz,
|
||||||
sx * sz + cx * sy * cz, -sx * cz + cx * sy * sz, cx * cy)
|
sy, -sx * cy, cx * cy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1015,14 +1015,14 @@ impl<A> From<Euler<A>> for Matrix4<<A as Angle>::Unitless> where
|
||||||
A: Angle + Into<Rad<<A as Angle>::Unitless>>,
|
A: Angle + Into<Rad<<A as Angle>::Unitless>>,
|
||||||
{
|
{
|
||||||
fn from(src: Euler<A>) -> Matrix4<A::Unitless> {
|
fn from(src: Euler<A>) -> Matrix4<A::Unitless> {
|
||||||
// http://en.wikipedia.org/wiki/Rotation_matrix#General_rotations
|
// Page A-2: http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf
|
||||||
let (sx, cx) = Rad::sin_cos(src.x.into());
|
let (sx, cx) = Rad::sin_cos(src.x.into());
|
||||||
let (sy, cy) = Rad::sin_cos(src.y.into());
|
let (sy, cy) = Rad::sin_cos(src.y.into());
|
||||||
let (sz, cz) = Rad::sin_cos(src.z.into());
|
let (sz, cz) = Rad::sin_cos(src.z.into());
|
||||||
|
|
||||||
Matrix4::new(cy * cz, cy * sz, -sy, A::Unitless::zero(),
|
Matrix4::new(cy * cz, cx * sz + sx * sy * cz, sx * sz - cx * sy * cz, A::Unitless::zero(),
|
||||||
-cx * sz + sx * sy * cz, cx * cz + sx * sy * sz, sx * cy, A::Unitless::zero(),
|
-cy * sz, cx * cz - sx * sy * sz, sx * cz + cx * sy * sz, A::Unitless::zero(),
|
||||||
sx * sz + cx * sy * cz, -sx * cz + cx * sy * sz, cx * cy, A::Unitless::zero(),
|
sy, -sx * cy, cx * cy, A::Unitless::zero(),
|
||||||
A::Unitless::zero(), A::Unitless::zero(), A::Unitless::zero(), A::Unitless::one())
|
A::Unitless::zero(), A::Unitless::zero(), A::Unitless::zero(), A::Unitless::one())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
109
tests/matrix.rs
109
tests/matrix.rs
|
@ -398,6 +398,115 @@ pub mod matrix3 {
|
||||||
#[test] fn test_neg_1() { check_from_axis_angle_z(rad(-1.0)); }
|
#[test] fn test_neg_1() { check_from_axis_angle_z(rad(-1.0)); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod rotate_from_euler {
|
||||||
|
use cgmath::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_x() {
|
||||||
|
let vec = vec3(0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
let rot = Matrix3::from(Euler::new(deg(90.0).into(), rad(0.0), rad(0.0)));
|
||||||
|
assert_approx_eq!(vec3(0.0, -1.0, 0.0), rot * vec);
|
||||||
|
|
||||||
|
let rot = Matrix3::from(Euler::new(deg(-90.0).into(), rad(0.0), rad(0.0)));
|
||||||
|
assert_approx_eq!(vec3(0.0, 1.0, 0.0), rot * vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_y() {
|
||||||
|
let vec = vec3(0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
let rot = Matrix3::from(Euler::new(rad(0.0), deg(90.0).into(), rad(0.0)));
|
||||||
|
assert_approx_eq!(vec3(1.0, 0.0, 0.0), rot * vec);
|
||||||
|
|
||||||
|
let rot = Matrix3::from(Euler::new(rad(0.0), deg(-90.0).into(), rad(0.0)));
|
||||||
|
assert_approx_eq!(vec3(-1.0, 0.0, 0.0), rot * vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_z() {
|
||||||
|
let vec = vec3(1.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
let rot = Matrix3::from(Euler::new(rad(0.0), rad(0.0), deg(90.0).into()));
|
||||||
|
assert_approx_eq!(vec3(0.0, 1.0, 0.0), rot * vec);
|
||||||
|
|
||||||
|
let rot = Matrix3::from(Euler::new(rad(0.0), rad(0.0), deg(-90.0).into()));
|
||||||
|
assert_approx_eq!(vec3(0.0, -1.0, 0.0), rot * vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// tests that the Y rotation is done after the X
|
||||||
|
#[test]
|
||||||
|
fn test_x_then_y() {
|
||||||
|
let vec = vec3(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
let rot = Matrix3::from(Euler::new(deg(90.0).into(), deg(90.0).into(), rad(0.0)));
|
||||||
|
assert_approx_eq!(vec3(0.0, 0.0, 1.0), rot * vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tests that the Z rotation is done after the Y
|
||||||
|
#[test]
|
||||||
|
fn test_y_then_z() {
|
||||||
|
let vec = vec3(0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
let rot = Matrix3::from(Euler::new(rad(0.0), deg(90.0).into(), deg(90.0).into()));
|
||||||
|
assert_approx_eq!(vec3(1.0, 0.0, 0.0), rot * vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod rotate_from_axis_angle {
|
||||||
|
use cgmath::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_x() {
|
||||||
|
let vec = vec3(0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
let rot = Matrix3::from_angle_x(deg(90.0).into());
|
||||||
|
println!("x mat: {:?}", rot);
|
||||||
|
assert_approx_eq!(vec3(0.0, -1.0, 0.0), rot * vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_y() {
|
||||||
|
let vec = vec3(0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
let rot = Matrix3::from_angle_y(deg(90.0).into());
|
||||||
|
assert_approx_eq!(vec3(1.0, 0.0, 0.0), rot * vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_z() {
|
||||||
|
let vec = vec3(1.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
let rot = Matrix3::from_angle_z(deg(90.0).into());
|
||||||
|
assert_approx_eq!(vec3(0.0, 1.0, 0.0), rot * vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_xy() {
|
||||||
|
let vec = vec3(0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
let rot = Matrix3::from_axis_angle(vec3(1.0, 1.0, 0.0).normalize(), deg(90.0).into());
|
||||||
|
assert_approx_eq!(vec3(2.0f32.sqrt() / 2.0, -2.0f32.sqrt() / 2.0, 0.0), rot * vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_yz() {
|
||||||
|
let vec = vec3(1.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
let rot = Matrix3::from_axis_angle(vec3(0.0, 1.0, 1.0).normalize(), deg(-90.0).into());
|
||||||
|
assert_approx_eq!(vec3(0.0, -2.0f32.sqrt() / 2.0, 2.0f32.sqrt() / 2.0), rot * vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_xz() {
|
||||||
|
let vec = vec3(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
let rot = Matrix3::from_axis_angle(vec3(1.0, 0.0, 1.0).normalize(), deg(90.0).into());
|
||||||
|
assert_approx_eq!(vec3(-2.0f32.sqrt() / 2.0, 0.0, 2.0f32.sqrt() / 2.0), rot * vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod matrix4 {
|
pub mod matrix4 {
|
||||||
|
|
Loading…
Reference in a new issue