Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ This project adheres to [Semantic Versioning](https://semver.org/).
**nalgebra-lapack change log** is found [here](https://github.com/dimforge/nalgebra/blob/main/nalgebra-lapack/CHANGELOG.md)
starting with `nalgebra-lapack` version `0.27.0`.

## Unreleased

### Fixed

- Clamp the `acos` argument in `Rotation3::euler_angles_ordered` so that rounding in the intermediate matrix products can no longer push the middle angle to `NaN` [#1481](https://github.com/dimforge/nalgebra/issues/1481).

## [0.35.0] (24 May 2026)

### Added
Expand Down
2 changes: 1 addition & 1 deletion src/geometry/rotation_specialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1098,7 +1098,7 @@ impl<T: SimdRealField> Rotation3<T> {
c1,
);
let o_t = c * self.matrix() * (c.transpose() * r1l);
angles[1] = o_t.m33.acos();
angles[1] = o_t.m33.clamp(-T::one(), T::one()).acos();

let safe1 = angles[1].abs() >= eps;
let safe2 = (angles[1] - T::pi()).abs() >= eps;
Expand Down
23 changes: 23 additions & 0 deletions tests/geometry/rotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,29 @@ fn quaternion_euler_angles_issue_494() {
assert_eq!(angs.2, 0.0);
}

#[test]
fn euler_angles_ordered_issue_1481() {
// A valid unit quaternion can yield a rotation matrix whose diagonal
// entry is slightly outside [-1, 1] due to rounding; feeding it to acos
// produced NaN before the clamp fix.
let q = UnitQuaternion::new_normalize(Quaternion::<f64>::new(
0.1045170328727042,
-0.6993398242910853,
0.10451703287270421,
0.6993398242910854,
));
let seq = [
UnitVector3::new_normalize(Vector3::z()),
UnitVector3::new_normalize(Vector3::y()),
UnitVector3::new_normalize(Vector3::x()),
];
let (angles, _observable) = q.to_rotation_matrix().euler_angles_ordered(seq, false);
assert!(
angles.iter().all(|a| a.is_finite()),
"euler angles must be finite, got {angles:?}"
);
}

#[cfg(feature = "proptest-support")]
mod proptest_tests {
use approx::AbsDiffEq;
Expand Down