Bug 1459403: Cleanup and add references to Quaternion::animate. r?hiro
No functional change, but I did this while searching for the bug.
MozReview-Commit-ID: KsJxFoYaOq1
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -1816,22 +1816,25 @@ impl Quaternion {
}
}
impl Animate for Quaternion {
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
use std::f64;
let (this_weight, other_weight) = procedure.weights();
- debug_assert!((this_weight + other_weight - 1.0f64).abs() <= f64::EPSILON ||
- other_weight == 1.0f64 || other_weight == 0.0f64,
- "animate should only be used for interpolating or accumulating transforms");
+ debug_assert!(
+ (this_weight + other_weight - 1.0f64).abs() <= f64::EPSILON ||
+ other_weight == 1.0f64 || other_weight == 0.0f64,
+ "animate should only be used for interpolating or accumulating transforms",
+ );
- // We take a specialized code path for accumulation (where other_weight is 1)
- if other_weight == 1.0 {
+ // We take a specialized code path for accumulation (where other_weight
+ // is 1).
+ if let Procedure::Accumulate { .. } = procedure {
if this_weight == 0.0 {
return Ok(*other);
}
let clamped_w = self.3.min(1.0).max(-1.0);
// Determine the scale factor.
let mut theta = clamped_w.acos();
@@ -1852,42 +1855,49 @@ impl Animate for Quaternion {
return Ok(Quaternion(
a.3 * b.0 + a.0 * b.3 + a.1 * b.2 - a.2 * b.1,
a.3 * b.1 - a.0 * b.2 + a.1 * b.3 + a.2 * b.0,
a.3 * b.2 + a.0 * b.1 - a.1 * b.0 + a.2 * b.3,
a.3 * b.3 - a.0 * b.0 - a.1 * b.1 - a.2 * b.2,
));
}
- let mut product = self.0 * other.0 +
- self.1 * other.1 +
- self.2 * other.2 +
- self.3 * other.3;
+ // Straight from gfxQuaternion::Slerp.
+ //
+ // Dot product, clamped between -1 and 1.
+ let dot =
+ (self.0 * other.0 +
+ self.1 * other.1 +
+ self.2 * other.2 +
+ self.3 * other.3)
+ .min(1.0).max(-1.0);
- // Clamp product to -1.0 <= product <= 1.0
- product = product.min(1.0);
- product = product.max(-1.0);
-
- if product == 1.0 {
+ if dot == 1.0 {
return Ok(*self);
}
- let theta = product.acos();
- let w = (other_weight * theta).sin() * 1.0 / (1.0 - product * product).sqrt();
+ let theta = dot.acos();
+ let rsintheta = 1.0 / (1.0 - dot * dot).sqrt();
+
+ let right_weight = (other_weight * theta).sin() * rsintheta;
+ let left_weight = (other_weight * theta).cos() - dot * right_weight;
- let mut a = *self;
- let mut b = *other;
- let mut result = Quaternion(0., 0., 0., 0.,);
+ let mut left = *self;
+ let mut right = *other;
% for i in range(4):
- a.${i} *= (other_weight * theta).cos() - product * w;
- b.${i} *= w;
- result.${i} = a.${i} + b.${i};
+ left.${i} *= left_weight;
+ right.${i} *= right_weight;
% endfor
- Ok(result)
+ Ok(Quaternion(
+ left.0 + right.0,
+ left.1 + right.1,
+ left.2 + right.2,
+ left.3 + right.3,
+ ))
}
}
impl ComputeSquaredDistance for Quaternion {
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
// Use quaternion vectors to get the angle difference. Both q1 and q2 are unit vectors,
// so we can get their angle difference by: