Skip to content

Commit

Permalink
Check that rotation extraction is valid.
Browse files Browse the repository at this point in the history
When creating a quaternion from a matrix or extracting Euler angles from
a matrix we do not support handling matrices that contain non-rotation
transformations. Make that clear in the doc comments and add glam
asserts that check inputs in these cases.
  • Loading branch information
bitshifter committed Jul 9, 2024
1 parent 7870854 commit ba14205
Show file tree
Hide file tree
Showing 21 changed files with 452 additions and 14 deletions.
17 changes: 17 additions & 0 deletions codegen/templates/mat.rs.tera
Original file line number Diff line number Diff line change
Expand Up @@ -525,9 +525,17 @@ impl {{ self_t }} {
}

/// Extract Euler angles with the given Euler rotation order.
///
/// Note if the input matrix contains scales, shears, or other non-rotation transformations then
/// the resulting Euler angles will be ill-defined.
///
/// # Panics
///
/// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn to_euler(&self, order: EulerRot) -> ({{ scalar_t }}, {{ scalar_t }}, {{ scalar_t }}) {
glam_assert!(self.x_axis.is_normalized() && self.y_axis.is_normalized() && self.z_axis.is_normalized());
self.to_euler_angles(order)
}

Expand Down Expand Up @@ -863,9 +871,18 @@ impl {{ self_t }} {
}

/// Extract Euler angles with the given Euler rotation order.
///
/// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
/// then the resulting Euler angles will be ill-defined.
///
/// # Panics
///
/// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
/// `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn to_euler(&self, order: EulerRot) -> ({{ scalar_t }}, {{ scalar_t }}, {{ scalar_t }}) {
glam_assert!(self.x_axis.is_normalized() && self.y_axis.is_normalized() && self.z_axis.is_normalized());
self.to_euler_angles(order)
}

Expand Down
42 changes: 40 additions & 2 deletions codegen/templates/quat.rs.tera
Original file line number Diff line number Diff line change
Expand Up @@ -298,10 +298,18 @@ impl {{ self_t }} {
}

/// From the columns of a 3x3 rotation matrix.
///
/// Note if the input axes contain scales, shears, or other non-rotation transformations then
/// the output of this function is ill-defined.
///
/// # Panics
///
/// Will panic if any axis is not normalized when `glam_assert` is enabled.
#[inline]
#[must_use]
pub(crate) fn from_rotation_axes(x_axis: {{ vec3_t }}, y_axis: {{ vec3_t }}, z_axis: {{ vec3_t }}) -> Self {
// Based on https://github.com/microsoft/DirectXMath `XM$quaternionRotationMatrix`
glam_assert!(x_axis.is_normalized() && y_axis.is_normalized() && z_axis.is_normalized());
// Based on https://github.com/microsoft/DirectXMath `XMQuaternionRotationMatrix`
let (m00, m01, m02) = x_axis.into();
let (m10, m11, m12) = y_axis.into();
let (m20, m21, m22) = z_axis.into();
Expand Down Expand Up @@ -359,6 +367,13 @@ impl {{ self_t }} {
}

/// Creates a quaternion from a 3x3 rotation matrix.
///
/// Note if the input matrix contain scales, shears, or other non-rotation transformations then
/// the resulting quaternion will be ill-defined.
///
/// # Panics
///
/// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn from_mat3(mat: &{{ mat3_t }}) -> Self {
Expand All @@ -371,6 +386,13 @@ impl {{ self_t }} {

{% if scalar_t == "f32" %}
/// Creates a quaternion from a 3x3 SIMD aligned rotation matrix.
///
/// Note if the input matrix contain scales, shears, or other non-rotation transformations then
/// the resulting quaternion will be ill-defined.
///
/// # Panics
///
/// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn from_mat3a(mat: &Mat3A) -> Self {
Expand All @@ -382,7 +404,15 @@ impl {{ self_t }} {
}
{% endif %}

/// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix.
/// Creates a quaternion from the upper 3x3 rotation matrix inside a homogeneous 4x4 matrix.
///
/// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
/// then the resulting quaternion will be ill-defined.
///
/// # Panics
///
/// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
/// `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn from_mat4(mat: &{{ mat4_t }}) -> Self {
Expand Down Expand Up @@ -1113,6 +1143,14 @@ impl {{ self_t }} {
}

/// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform.
///
/// Note if the input affine matrix contain scales, shears, or other non-rotation
/// transformations then the resulting quaternion will be ill-defined.
///
/// # Panics
///
/// Will panic if any input affine matrix column is not normalized when `glam_assert` is
/// enabled.
#[inline]
#[must_use]
pub fn from_affine3(a: &crate::{{ affine3_t }}) -> Self {
Expand Down
12 changes: 12 additions & 0 deletions src/f32/coresimd/mat3a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,21 @@ impl Mat3A {
}

/// Extract Euler angles with the given Euler rotation order.
///
/// Note if the input matrix contains scales, shears, or other non-rotation transformations then
/// the resulting Euler angles will be ill-defined.
///
/// # Panics
///
/// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
glam_assert!(
self.x_axis.is_normalized()
&& self.y_axis.is_normalized()
&& self.z_axis.is_normalized()
);
self.to_euler_angles(order)
}

Expand Down
13 changes: 13 additions & 0 deletions src/f32/coresimd/mat4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,9 +390,22 @@ impl Mat4 {
}

/// Extract Euler angles with the given Euler rotation order.
///
/// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
/// then the resulting Euler angles will be ill-defined.
///
/// # Panics
///
/// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
/// `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
glam_assert!(
self.x_axis.is_normalized()
&& self.y_axis.is_normalized()
&& self.z_axis.is_normalized()
);
self.to_euler_angles(order)
}

Expand Down
42 changes: 40 additions & 2 deletions src/f32/coresimd/quat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,18 @@ impl Quat {
}

/// From the columns of a 3x3 rotation matrix.
///
/// Note if the input axes contain scales, shears, or other non-rotation transformations then
/// the output of this function is ill-defined.
///
/// # Panics
///
/// Will panic if any axis is not normalized when `glam_assert` is enabled.
#[inline]
#[must_use]
pub(crate) fn from_rotation_axes(x_axis: Vec3, y_axis: Vec3, z_axis: Vec3) -> Self {
// Based on https://github.com/microsoft/DirectXMath `XM$quaternionRotationMatrix`
glam_assert!(x_axis.is_normalized() && y_axis.is_normalized() && z_axis.is_normalized());
// Based on https://github.com/microsoft/DirectXMath `XMQuaternionRotationMatrix`
let (m00, m01, m02) = x_axis.into();
let (m10, m11, m12) = y_axis.into();
let (m20, m21, m22) = z_axis.into();
Expand Down Expand Up @@ -240,20 +248,42 @@ impl Quat {
}

/// Creates a quaternion from a 3x3 rotation matrix.
///
/// Note if the input matrix contain scales, shears, or other non-rotation transformations then
/// the resulting quaternion will be ill-defined.
///
/// # Panics
///
/// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn from_mat3(mat: &Mat3) -> Self {
Self::from_rotation_axes(mat.x_axis, mat.y_axis, mat.z_axis)
}

/// Creates a quaternion from a 3x3 SIMD aligned rotation matrix.
///
/// Note if the input matrix contain scales, shears, or other non-rotation transformations then
/// the resulting quaternion will be ill-defined.
///
/// # Panics
///
/// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn from_mat3a(mat: &Mat3A) -> Self {
Self::from_rotation_axes(mat.x_axis.into(), mat.y_axis.into(), mat.z_axis.into())
}

/// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix.
/// Creates a quaternion from the upper 3x3 rotation matrix inside a homogeneous 4x4 matrix.
///
/// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
/// then the resulting quaternion will be ill-defined.
///
/// # Panics
///
/// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
/// `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn from_mat4(mat: &Mat4) -> Self {
Expand Down Expand Up @@ -714,6 +744,14 @@ impl Quat {
}

/// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform.
///
/// Note if the input affine matrix contain scales, shears, or other non-rotation
/// transformations then the resulting quaternion will be ill-defined.
///
/// # Panics
///
/// Will panic if any input affine matrix column is not normalized when `glam_assert` is
/// enabled.
#[inline]
#[must_use]
pub fn from_affine3(a: &crate::Affine3A) -> Self {
Expand Down
12 changes: 12 additions & 0 deletions src/f32/mat3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,21 @@ impl Mat3 {
}

/// Extract Euler angles with the given Euler rotation order.
///
/// Note if the input matrix contains scales, shears, or other non-rotation transformations then
/// the resulting Euler angles will be ill-defined.
///
/// # Panics
///
/// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
glam_assert!(
self.x_axis.is_normalized()
&& self.y_axis.is_normalized()
&& self.z_axis.is_normalized()
);
self.to_euler_angles(order)
}

Expand Down
12 changes: 12 additions & 0 deletions src/f32/neon/mat3a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,21 @@ impl Mat3A {
}

/// Extract Euler angles with the given Euler rotation order.
///
/// Note if the input matrix contains scales, shears, or other non-rotation transformations then
/// the resulting Euler angles will be ill-defined.
///
/// # Panics
///
/// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
glam_assert!(
self.x_axis.is_normalized()
&& self.y_axis.is_normalized()
&& self.z_axis.is_normalized()
);
self.to_euler_angles(order)
}

Expand Down
13 changes: 13 additions & 0 deletions src/f32/neon/mat4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,9 +390,22 @@ impl Mat4 {
}

/// Extract Euler angles with the given Euler rotation order.
///
/// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
/// then the resulting Euler angles will be ill-defined.
///
/// # Panics
///
/// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
/// `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
glam_assert!(
self.x_axis.is_normalized()
&& self.y_axis.is_normalized()
&& self.z_axis.is_normalized()
);
self.to_euler_angles(order)
}

Expand Down
42 changes: 40 additions & 2 deletions src/f32/neon/quat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,18 @@ impl Quat {
}

/// From the columns of a 3x3 rotation matrix.
///
/// Note if the input axes contain scales, shears, or other non-rotation transformations then
/// the output of this function is ill-defined.
///
/// # Panics
///
/// Will panic if any axis is not normalized when `glam_assert` is enabled.
#[inline]
#[must_use]
pub(crate) fn from_rotation_axes(x_axis: Vec3, y_axis: Vec3, z_axis: Vec3) -> Self {
// Based on https://github.com/microsoft/DirectXMath `XM$quaternionRotationMatrix`
glam_assert!(x_axis.is_normalized() && y_axis.is_normalized() && z_axis.is_normalized());
// Based on https://github.com/microsoft/DirectXMath `XMQuaternionRotationMatrix`
let (m00, m01, m02) = x_axis.into();
let (m10, m11, m12) = y_axis.into();
let (m20, m21, m22) = z_axis.into();
Expand Down Expand Up @@ -245,20 +253,42 @@ impl Quat {
}

/// Creates a quaternion from a 3x3 rotation matrix.
///
/// Note if the input matrix contain scales, shears, or other non-rotation transformations then
/// the resulting quaternion will be ill-defined.
///
/// # Panics
///
/// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn from_mat3(mat: &Mat3) -> Self {
Self::from_rotation_axes(mat.x_axis, mat.y_axis, mat.z_axis)
}

/// Creates a quaternion from a 3x3 SIMD aligned rotation matrix.
///
/// Note if the input matrix contain scales, shears, or other non-rotation transformations then
/// the resulting quaternion will be ill-defined.
///
/// # Panics
///
/// Will panic if any input matrix column is not normalized when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn from_mat3a(mat: &Mat3A) -> Self {
Self::from_rotation_axes(mat.x_axis.into(), mat.y_axis.into(), mat.z_axis.into())
}

/// Creates a quaternion from a 3x3 rotation matrix inside a homogeneous 4x4 matrix.
/// Creates a quaternion from the upper 3x3 rotation matrix inside a homogeneous 4x4 matrix.
///
/// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
/// then the resulting quaternion will be ill-defined.
///
/// # Panics
///
/// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
/// `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn from_mat4(mat: &Mat4) -> Self {
Expand Down Expand Up @@ -742,6 +772,14 @@ impl Quat {
}

/// Creates a quaternion from a 3x3 rotation matrix inside a 3D affine transform.
///
/// Note if the input affine matrix contain scales, shears, or other non-rotation
/// transformations then the resulting quaternion will be ill-defined.
///
/// # Panics
///
/// Will panic if any input affine matrix column is not normalized when `glam_assert` is
/// enabled.
#[inline]
#[must_use]
pub fn from_affine3(a: &crate::Affine3A) -> Self {
Expand Down
Loading

0 comments on commit ba14205

Please sign in to comment.