Skip to content

Commit 098e140

Browse files
committed
fix(deep_causality_num): The slerp implementation has been corrected by removing the incorrect special case for antipodal quaternions and adding a check for nearly identical quaternions to use linear interpolation, preventing division by
zero. The corresponding test case has been updated to reflect the new behavior. All tests pass. Signed-off-by: Marvin Hansen <[email protected]>
1 parent dc30f13 commit 098e140

File tree

3 files changed

+9
-17
lines changed

3 files changed

+9
-17
lines changed

deep_causality_num/src/quaternion/arithmetic.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ impl<F: Float> Div<F> for Quaternion<F> {
191191
y: self.y * inv_scalar,
192192
z: self.z * inv_scalar,
193193
}
194-
}}
194+
}
195+
}
195196

196197
// Rem (Placeholder for now, as quaternion remainder is not standard)
197198
impl<F: Float> Rem for Quaternion<F> {

deep_causality_num/src/quaternion/rotation.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -134,25 +134,16 @@ where
134134

135135
let mut dot = q1.dot(&q2);
136136

137-
// If the quaternions are very close (dot product near 1 or -1)
138-
if dot.abs() > F::one() - F::epsilon() {
139-
// If they are antipodal and t = 0.5, return identity
140-
if dot < F::zero() && t == F::from(0.5).unwrap() {
141-
return Quaternion::identity();
142-
}
143-
// Otherwise, they are either identical or antipodal but t is not 0.5.
144-
// In either case, linear interpolation is a good approximation.
145-
return (q1 * (F::one() - t) + q2 * t).normalize();
146-
}
147-
148-
// If the dot product is negative, the quaternions are "opposite"
149-
// and slerp will take the long way around.
150137
// We can negate one of the quaternions to take the short way.
151138
if dot < F::zero() {
152139
q2 = -q2;
153140
dot = -dot;
154141
}
155142

143+
// If the quaternions are very close, use linear interpolation to avoid division by zero.
144+
if dot > F::one() - F::epsilon() {
145+
return (q1 * (F::one() - t) + q2 * t).normalize();
146+
}
156147
// Clamp dot to avoid NaN from acos due to floating point inaccuracies
157148
dot = dot.clamp(-F::one(), F::one());
158149
let theta = dot.acos();

deep_causality_num/tests/quaternion/rotation_tests.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,11 @@ fn test_slerp_antipodal() {
179179
let q4 = Quaternion::new(0.0, 0.0, 0.0, -1.0); // -180 deg around Z
180180
let slerp_opposite = q3.slerp(&q4, 0.5);
181181

182-
// Should be identity or very close to it
183-
assert!((slerp_opposite.w - 1.0).abs() < EPSILON);
182+
// Should be q3 (0,0,0,1) after negation and linear interpolation
183+
assert!((slerp_opposite.w - 0.0).abs() < EPSILON);
184184
assert!((slerp_opposite.x - 0.0).abs() < EPSILON);
185185
assert!((slerp_opposite.y - 0.0).abs() < EPSILON);
186-
assert!((slerp_opposite.z - 0.0).abs() < EPSILON);
186+
assert!((slerp_opposite.z - 1.0).abs() < EPSILON);
187187
}
188188

189189
#[test]

0 commit comments

Comments
 (0)