From f9aa2d76aab6ed1dc2c31f485f20d6557cc86233 Mon Sep 17 00:00:00 2001 From: Tim Taubner Date: Thu, 31 Mar 2022 17:28:31 +0200 Subject: [PATCH 1/8] Start from random rotation in from_matrix to prevent issues when calling from_matrix on rotation matrices --- src/geometry/quaternion_construction.rs | 4 +++- src/geometry/rotation_specialization.rs | 10 +++++++--- tests/geometry/rotation.rs | 16 +++++++++++++++- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/geometry/quaternion_construction.rs b/src/geometry/quaternion_construction.rs index 6de21bd5..dbd1edbc 100644 --- a/src/geometry/quaternion_construction.rs +++ b/src/geometry/quaternion_construction.rs @@ -410,9 +410,11 @@ where /// This is an iterative method. See `.from_matrix_eps` to provide mover /// convergence parameters and starting solution. /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. + #[cfg(feature = "rand-no-std")] pub fn from_matrix(m: &Matrix3) -> Self where - T: RealField, + T: RealField + Scalar, + Standard: Distribution>, { Rotation3::from_matrix(m).into() } diff --git a/src/geometry/rotation_specialization.rs b/src/geometry/rotation_specialization.rs index 41405c87..b57eeb53 100644 --- a/src/geometry/rotation_specialization.rs +++ b/src/geometry/rotation_specialization.rs @@ -706,11 +706,15 @@ where /// This is an iterative method. See `.from_matrix_eps` to provide mover /// convergence parameters and starting solution. /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. + #[cfg(feature = "rand-no-std")] pub fn from_matrix(m: &Matrix3) -> Self where - T: RealField, + T: RealField + crate::Scalar, + Standard: Distribution>, { - Self::from_matrix_eps(m, T::default_epsilon(), 0, Self::identity()) + // Starting from a random rotation has almost zero likelihood to end up in a maximum if `m` is already a rotation matrix + let random_rotation: Rotation3 = rand::thread_rng().gen(); + Self::from_matrix_eps(m, T::default_epsilon(), 0, random_rotation) } /// Builds a rotation matrix by extracting the rotation part of the given transformation `m`. @@ -730,7 +734,7 @@ where T: RealField, { if max_iter == 0 { - max_iter = usize::max_value(); + max_iter = usize::MAX; } let mut rot = guess.into_inner(); diff --git a/tests/geometry/rotation.rs b/tests/geometry/rotation.rs index 84bba676..61af83d9 100644 --- a/tests/geometry/rotation.rs +++ b/tests/geometry/rotation.rs @@ -1,4 +1,5 @@ -use na::{Quaternion, RealField, UnitQuaternion, Vector2, Vector3}; +use std::f64::consts::PI; +use na::{Matrix3, Quaternion, RealField, Rotation3, UnitQuaternion, UnitVector3, Vector2, Vector3}; #[test] fn angle_2() { @@ -16,6 +17,19 @@ fn angle_3() { assert_eq!(a.angle(&b), 0.0); } +#[test] +fn from_rotation_matrix() { + // Test degenerate case when from_matrix_eps gets stuck in maximum + let identity = Rotation3::from_matrix(&Matrix3::new( + 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, + )); + assert_relative_eq!(identity, &Rotation3::identity(), epsilon = 0.001); + let rotated_z = Rotation3::from_matrix(&Matrix3::new( + 1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, -1.0, + )); + assert_relative_eq!(rotated_z, &Rotation3::from_axis_angle(&UnitVector3::new_unchecked(Vector3::new(1.0, 0.0, 0.0)), PI), epsilon = 0.001); +} + #[test] fn quaternion_euler_angles_issue_494() { let quat = UnitQuaternion::from_quaternion(Quaternion::new( From 257d95b3d34b07a1f322076e4e2ff8298679bc92 Mon Sep 17 00:00:00 2001 From: Tim Taubner Date: Thu, 31 Mar 2022 18:03:59 +0200 Subject: [PATCH 2/8] Add test case for issue 1078 --- tests/geometry/rotation.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/geometry/rotation.rs b/tests/geometry/rotation.rs index 61af83d9..369b5454 100644 --- a/tests/geometry/rotation.rs +++ b/tests/geometry/rotation.rs @@ -28,6 +28,10 @@ fn from_rotation_matrix() { 1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, -1.0, )); assert_relative_eq!(rotated_z, &Rotation3::from_axis_angle(&UnitVector3::new_unchecked(Vector3::new(1.0, 0.0, 0.0)), PI), epsilon = 0.001); + // Test that issue 1078 is fixed + let m = nalgebra::Matrix3::::new(0.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, 0.0); + assert_relative_ne!(identity, nalgebra::Rotation3::from_matrix(&m)); + assert_relative_eq!(nalgebra::Rotation3::from_matrix_unchecked(m.clone()), nalgebra::Rotation3::from_matrix(&m)); } #[test] From ac203fe4fd101e3ae0e0a542f175fcb23f7dabbe Mon Sep 17 00:00:00 2001 From: Tim Taubner Date: Thu, 31 Mar 2022 18:07:04 +0200 Subject: [PATCH 3/8] Add test case for issue 628 --- tests/geometry/rotation.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/geometry/rotation.rs b/tests/geometry/rotation.rs index 369b5454..661430a0 100644 --- a/tests/geometry/rotation.rs +++ b/tests/geometry/rotation.rs @@ -19,7 +19,7 @@ fn angle_3() { #[test] fn from_rotation_matrix() { - // Test degenerate case when from_matrix_eps gets stuck in maximum + // Test degenerate case when from_matrix gets stuck in Identity rotation let identity = Rotation3::from_matrix(&Matrix3::new( 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, )); @@ -28,10 +28,15 @@ fn from_rotation_matrix() { 1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, -1.0, )); assert_relative_eq!(rotated_z, &Rotation3::from_axis_angle(&UnitVector3::new_unchecked(Vector3::new(1.0, 0.0, 0.0)), PI), epsilon = 0.001); + // Test that issue 628 is fixed + let m_628 = nalgebra::Matrix3::::new(-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0); + assert_relative_ne!(identity, nalgebra::Rotation3::from_matrix(&m_628), epsilon = 0.01); + assert_relative_eq!(nalgebra::Rotation3::from_matrix_unchecked(m_628.clone()), nalgebra::Rotation3::from_matrix(&m_628), epsilon = 0.001); + // Test that issue 1078 is fixed - let m = nalgebra::Matrix3::::new(0.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, 0.0); - assert_relative_ne!(identity, nalgebra::Rotation3::from_matrix(&m)); - assert_relative_eq!(nalgebra::Rotation3::from_matrix_unchecked(m.clone()), nalgebra::Rotation3::from_matrix(&m)); + let m_1078 = nalgebra::Matrix3::::new(0.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, 0.0); + assert_relative_ne!(identity, nalgebra::Rotation3::from_matrix(&m_1078), epsilon = 0.01); + assert_relative_eq!(nalgebra::Rotation3::from_matrix_unchecked(m_1078.clone()), nalgebra::Rotation3::from_matrix(&m_1078), epsilon = 0.001); } #[test] From d515e4f1be71acc31eadb5f26133102e840403fe Mon Sep 17 00:00:00 2001 From: Tim Taubner Date: Fri, 1 Apr 2022 14:30:20 +0200 Subject: [PATCH 4/8] Perturbations to check for convergence into maximum. --- src/geometry/rotation_specialization.rs | 30 +++++++++++++++++++------ 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/geometry/rotation_specialization.rs b/src/geometry/rotation_specialization.rs index b57eeb53..304f5ee5 100644 --- a/src/geometry/rotation_specialization.rs +++ b/src/geometry/rotation_specialization.rs @@ -17,7 +17,7 @@ use std::ops::Neg; use crate::base::dimension::{U1, U2, U3}; use crate::base::storage::Storage; -use crate::base::{Matrix2, Matrix3, SMatrix, SVector, Unit, Vector, Vector1, Vector2, Vector3}; +use crate::base::{Matrix2, Matrix3, SMatrix, SVector, Unit, Vector, Vector1, Vector2, Vector3, UnitVector3}; use crate::geometry::{Rotation2, Rotation3, UnitComplex, UnitQuaternion}; @@ -706,15 +706,12 @@ where /// This is an iterative method. See `.from_matrix_eps` to provide mover /// convergence parameters and starting solution. /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. - #[cfg(feature = "rand-no-std")] pub fn from_matrix(m: &Matrix3) -> Self where - T: RealField + crate::Scalar, - Standard: Distribution>, + T: RealField, { // Starting from a random rotation has almost zero likelihood to end up in a maximum if `m` is already a rotation matrix - let random_rotation: Rotation3 = rand::thread_rng().gen(); - Self::from_matrix_eps(m, T::default_epsilon(), 0, random_rotation) + Self::from_matrix_eps(m, T::default_epsilon(), 0, Rotation3::identity()) } /// Builds a rotation matrix by extracting the rotation part of the given transformation `m`. @@ -737,6 +734,7 @@ where max_iter = usize::MAX; } + let mut perturbation_axes = UnitVector3::new_unchecked(Vector3::new(T::one(), T::zero(), T::zero())); let mut rot = guess.into_inner(); for _ in 0..max_iter { @@ -752,7 +750,25 @@ where if let Some((axis, angle)) = Unit::try_new_and_get(axisangle, eps.clone()) { rot = Rotation3::from_axis_angle(&axis, angle) * rot; } else { - break; + // Check if stuck in a maximum w.r.t. the norm (m - rot).norm() + let mut perturbed = rot.clone(); + let norm_squared = (m - &rot).norm_squared(); + let mut new_norm_squared: T; + // Perturb until the new norm is significantly different + loop { + perturbed *= Rotation3::from_axis_angle(&perturbation_axes, T::frac_pi_8()); + new_norm_squared = (m - &perturbed).norm_squared(); + if relative_ne!(norm_squared, new_norm_squared) { + break; + } + } + // If new norm is larger, it's a minimum + if norm_squared < new_norm_squared { + break; + } + // If not, continue from perturbed rotation, but use a different axes for the next perturbation + perturbation_axes = UnitVector3::new_unchecked(Vector3::new(perturbation_axes.y.clone(), perturbation_axes.z.clone(), perturbation_axes.x.clone())); + rot = perturbed; } } From 26e69863e1bbe6ccc4866dc34f944b49c03603ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Wed, 27 Jul 2022 09:45:54 +0200 Subject: [PATCH 5/8] Rotation from matrix: small code cleanups --- src/geometry/quaternion_construction.rs | 3 +-- src/geometry/rotation_specialization.rs | 15 ++++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/geometry/quaternion_construction.rs b/src/geometry/quaternion_construction.rs index dbd1edbc..18f7a65c 100644 --- a/src/geometry/quaternion_construction.rs +++ b/src/geometry/quaternion_construction.rs @@ -413,8 +413,7 @@ where #[cfg(feature = "rand-no-std")] pub fn from_matrix(m: &Matrix3) -> Self where - T: RealField + Scalar, - Standard: Distribution>, + T: RealField, { Rotation3::from_matrix(m).into() } diff --git a/src/geometry/rotation_specialization.rs b/src/geometry/rotation_specialization.rs index 304f5ee5..f00d8cd7 100644 --- a/src/geometry/rotation_specialization.rs +++ b/src/geometry/rotation_specialization.rs @@ -17,7 +17,9 @@ use std::ops::Neg; use crate::base::dimension::{U1, U2, U3}; use crate::base::storage::Storage; -use crate::base::{Matrix2, Matrix3, SMatrix, SVector, Unit, Vector, Vector1, Vector2, Vector3, UnitVector3}; +use crate::base::{ + Matrix2, Matrix3, SMatrix, SVector, Unit, UnitVector3, Vector, Vector1, Vector2, Vector3, +}; use crate::geometry::{Rotation2, Rotation3, UnitComplex, UnitQuaternion}; @@ -710,8 +712,7 @@ where where T: RealField, { - // Starting from a random rotation has almost zero likelihood to end up in a maximum if `m` is already a rotation matrix - Self::from_matrix_eps(m, T::default_epsilon(), 0, Rotation3::identity()) + Self::from_matrix_eps(m, T::default_epsilon(), 0, Self::identity()) } /// Builds a rotation matrix by extracting the rotation part of the given transformation `m`. @@ -734,7 +735,7 @@ where max_iter = usize::MAX; } - let mut perturbation_axes = UnitVector3::new_unchecked(Vector3::new(T::one(), T::zero(), T::zero())); + let mut perturbation_axes = Vector3::x_axis(); let mut rot = guess.into_inner(); for _ in 0..max_iter { @@ -754,20 +755,24 @@ where let mut perturbed = rot.clone(); let norm_squared = (m - &rot).norm_squared(); let mut new_norm_squared: T; + // Perturb until the new norm is significantly different loop { perturbed *= Rotation3::from_axis_angle(&perturbation_axes, T::frac_pi_8()); new_norm_squared = (m - &perturbed).norm_squared(); + if relative_ne!(norm_squared, new_norm_squared) { break; } } + // If new norm is larger, it's a minimum if norm_squared < new_norm_squared { break; } + // If not, continue from perturbed rotation, but use a different axes for the next perturbation - perturbation_axes = UnitVector3::new_unchecked(Vector3::new(perturbation_axes.y.clone(), perturbation_axes.z.clone(), perturbation_axes.x.clone())); + perturbation_axes = UnitVector3::new_unchecked(perturbation_axes.yzx()); rot = perturbed; } } From 18a8a3067101d294b82c95b65a34db5367ee36ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Wed, 27 Jul 2022 09:46:02 +0200 Subject: [PATCH 6/8] cargo fmt --- tests/geometry/rotation.rs | 44 +++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/tests/geometry/rotation.rs b/tests/geometry/rotation.rs index 661430a0..883d4c0b 100644 --- a/tests/geometry/rotation.rs +++ b/tests/geometry/rotation.rs @@ -1,5 +1,7 @@ +use na::{ + Matrix3, Quaternion, RealField, Rotation3, UnitQuaternion, UnitVector3, Vector2, Vector3, +}; use std::f64::consts::PI; -use na::{Matrix3, Quaternion, RealField, Rotation3, UnitQuaternion, UnitVector3, Vector2, Vector3}; #[test] fn angle_2() { @@ -20,23 +22,41 @@ fn angle_3() { #[test] fn from_rotation_matrix() { // Test degenerate case when from_matrix gets stuck in Identity rotation - let identity = Rotation3::from_matrix(&Matrix3::new( - 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, - )); + let identity = + Rotation3::from_matrix(&Matrix3::new(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)); assert_relative_eq!(identity, &Rotation3::identity(), epsilon = 0.001); - let rotated_z = Rotation3::from_matrix(&Matrix3::new( - 1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, -1.0, - )); - assert_relative_eq!(rotated_z, &Rotation3::from_axis_angle(&UnitVector3::new_unchecked(Vector3::new(1.0, 0.0, 0.0)), PI), epsilon = 0.001); + let rotated_z = + Rotation3::from_matrix(&Matrix3::new(1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, -1.0)); + assert_relative_eq!( + rotated_z, + &Rotation3::from_axis_angle(&UnitVector3::new_unchecked(Vector3::new(1.0, 0.0, 0.0)), PI), + epsilon = 0.001 + ); // Test that issue 628 is fixed let m_628 = nalgebra::Matrix3::::new(-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0); - assert_relative_ne!(identity, nalgebra::Rotation3::from_matrix(&m_628), epsilon = 0.01); - assert_relative_eq!(nalgebra::Rotation3::from_matrix_unchecked(m_628.clone()), nalgebra::Rotation3::from_matrix(&m_628), epsilon = 0.001); + assert_relative_ne!( + identity, + nalgebra::Rotation3::from_matrix(&m_628), + epsilon = 0.01 + ); + assert_relative_eq!( + nalgebra::Rotation3::from_matrix_unchecked(m_628.clone()), + nalgebra::Rotation3::from_matrix(&m_628), + epsilon = 0.001 + ); // Test that issue 1078 is fixed let m_1078 = nalgebra::Matrix3::::new(0.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, 0.0); - assert_relative_ne!(identity, nalgebra::Rotation3::from_matrix(&m_1078), epsilon = 0.01); - assert_relative_eq!(nalgebra::Rotation3::from_matrix_unchecked(m_1078.clone()), nalgebra::Rotation3::from_matrix(&m_1078), epsilon = 0.001); + assert_relative_ne!( + identity, + nalgebra::Rotation3::from_matrix(&m_1078), + epsilon = 0.01 + ); + assert_relative_eq!( + nalgebra::Rotation3::from_matrix_unchecked(m_1078.clone()), + nalgebra::Rotation3::from_matrix(&m_1078), + epsilon = 0.001 + ); } #[test] From 7aadbcf21d2feafbe282fcdcc6b6469bf60dc859 Mon Sep 17 00:00:00 2001 From: Tim Taubner Date: Wed, 27 Jul 2022 11:31:34 +0200 Subject: [PATCH 7/8] From_rotation_matrix: Use the larger of eps.sqrt() or eps*eps as disturbance. Add tests for eps > 1.0 --- src/geometry/quaternion_construction.rs | 1 - src/geometry/rotation_specialization.rs | 7 +++-- tests/geometry/rotation.rs | 40 ++++++++++++++++++------- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/geometry/quaternion_construction.rs b/src/geometry/quaternion_construction.rs index 18f7a65c..6de21bd5 100644 --- a/src/geometry/quaternion_construction.rs +++ b/src/geometry/quaternion_construction.rs @@ -410,7 +410,6 @@ where /// This is an iterative method. See `.from_matrix_eps` to provide mover /// convergence parameters and starting solution. /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. - #[cfg(feature = "rand-no-std")] pub fn from_matrix(m: &Matrix3) -> Self where T: RealField, diff --git a/src/geometry/rotation_specialization.rs b/src/geometry/rotation_specialization.rs index f00d8cd7..fc2c9b93 100644 --- a/src/geometry/rotation_specialization.rs +++ b/src/geometry/rotation_specialization.rs @@ -735,6 +735,8 @@ where max_iter = usize::MAX; } + // Using sqrt(eps) ensures we perturb with something larger than eps; clamp to eps to handle the case of eps > 1.0 + let eps_disturbance = eps.clone().sqrt().max(eps.clone() * eps.clone()); let mut perturbation_axes = Vector3::x_axis(); let mut rot = guess.into_inner(); @@ -758,10 +760,9 @@ where // Perturb until the new norm is significantly different loop { - perturbed *= Rotation3::from_axis_angle(&perturbation_axes, T::frac_pi_8()); + perturbed *= Rotation3::from_axis_angle(&perturbation_axes, eps_disturbance.clone()); new_norm_squared = (m - &perturbed).norm_squared(); - - if relative_ne!(norm_squared, new_norm_squared) { + if abs_diff_ne!(norm_squared, new_norm_squared, epsilon = T::default_epsilon()) { break; } } diff --git a/tests/geometry/rotation.rs b/tests/geometry/rotation.rs index 883d4c0b..f5a77b54 100644 --- a/tests/geometry/rotation.rs +++ b/tests/geometry/rotation.rs @@ -32,31 +32,51 @@ fn from_rotation_matrix() { &Rotation3::from_axis_angle(&UnitVector3::new_unchecked(Vector3::new(1.0, 0.0, 0.0)), PI), epsilon = 0.001 ); - // Test that issue 628 is fixed - let m_628 = nalgebra::Matrix3::::new(-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0); + // Test that issue 627 is fixed + let m_627 = Matrix3::::new(-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0); assert_relative_ne!( identity, - nalgebra::Rotation3::from_matrix(&m_628), + Rotation3::from_matrix(&m_627), epsilon = 0.01 ); assert_relative_eq!( - nalgebra::Rotation3::from_matrix_unchecked(m_628.clone()), - nalgebra::Rotation3::from_matrix(&m_628), + Rotation3::from_matrix_unchecked(m_627.clone()), + Rotation3::from_matrix(&m_627), epsilon = 0.001 ); - // Test that issue 1078 is fixed - let m_1078 = nalgebra::Matrix3::::new(0.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, 0.0); + let m_1078 = Matrix3::::new(0.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, 0.0); assert_relative_ne!( identity, - nalgebra::Rotation3::from_matrix(&m_1078), + Rotation3::from_matrix(&m_1078), epsilon = 0.01 ); assert_relative_eq!( - nalgebra::Rotation3::from_matrix_unchecked(m_1078.clone()), - nalgebra::Rotation3::from_matrix(&m_1078), + Rotation3::from_matrix_unchecked(m_1078.clone()), + Rotation3::from_matrix(&m_1078), epsilon = 0.001 ); + // Additional test cases for eps >= 1.0 + assert_relative_ne!( + identity, + Rotation3::from_matrix_eps(&m_627, 1.2, 0, Rotation3::identity()), + epsilon = 0.6 + ); + assert_relative_eq!( + Rotation3::from_matrix_unchecked(m_627.clone()), + Rotation3::from_matrix_eps(&m_627, 1.2, 0, Rotation3::identity()), + epsilon = 0.6 + ); + assert_relative_ne!( + identity, + Rotation3::from_matrix_eps(&m_1078, 1.0, 0, Rotation3::identity()), + epsilon = 0.1 + ); + assert_relative_eq!( + Rotation3::from_matrix_unchecked(m_1078.clone()), + Rotation3::from_matrix_eps(&m_1078, 1.0, 0, Rotation3::identity()), + epsilon = 0.1 + ); } #[test] From 0c2d9deac7da51c91cd5d2b8e08bcf05350cece0 Mon Sep 17 00:00:00 2001 From: Tim Taubner Date: Wed, 27 Jul 2022 11:44:42 +0200 Subject: [PATCH 8/8] cargo fmt --- src/geometry/rotation_specialization.rs | 9 +++++++-- tests/geometry/rotation.rs | 12 ++---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/geometry/rotation_specialization.rs b/src/geometry/rotation_specialization.rs index fc2c9b93..c9197fd6 100644 --- a/src/geometry/rotation_specialization.rs +++ b/src/geometry/rotation_specialization.rs @@ -760,9 +760,14 @@ where // Perturb until the new norm is significantly different loop { - perturbed *= Rotation3::from_axis_angle(&perturbation_axes, eps_disturbance.clone()); + perturbed *= + Rotation3::from_axis_angle(&perturbation_axes, eps_disturbance.clone()); new_norm_squared = (m - &perturbed).norm_squared(); - if abs_diff_ne!(norm_squared, new_norm_squared, epsilon = T::default_epsilon()) { + if abs_diff_ne!( + norm_squared, + new_norm_squared, + epsilon = T::default_epsilon() + ) { break; } } diff --git a/tests/geometry/rotation.rs b/tests/geometry/rotation.rs index f5a77b54..2e8d2482 100644 --- a/tests/geometry/rotation.rs +++ b/tests/geometry/rotation.rs @@ -34,11 +34,7 @@ fn from_rotation_matrix() { ); // Test that issue 627 is fixed let m_627 = Matrix3::::new(-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0); - assert_relative_ne!( - identity, - Rotation3::from_matrix(&m_627), - epsilon = 0.01 - ); + assert_relative_ne!(identity, Rotation3::from_matrix(&m_627), epsilon = 0.01); assert_relative_eq!( Rotation3::from_matrix_unchecked(m_627.clone()), Rotation3::from_matrix(&m_627), @@ -46,11 +42,7 @@ fn from_rotation_matrix() { ); // Test that issue 1078 is fixed let m_1078 = Matrix3::::new(0.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, 0.0); - assert_relative_ne!( - identity, - Rotation3::from_matrix(&m_1078), - epsilon = 0.01 - ); + assert_relative_ne!(identity, Rotation3::from_matrix(&m_1078), epsilon = 0.01); assert_relative_eq!( Rotation3::from_matrix_unchecked(m_1078.clone()), Rotation3::from_matrix(&m_1078),