Bug 1459403: Cleanup and add references to Quaternion::animate. r?hiro draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Sat, 26 May 2018 23:40:45 +0200
changeset 800290 25e43f6e6f55d1c81c8961e247aa4336c1258173
parent 800289 f4840aba0f83041c356072ae80bcda1d8f341909
child 800291 3772fedcd0c39122426fd886e4c50bdd3eaa3cf2
child 800296 c8eac18672b21fbee7b32ec6a4cce12b0da7b434
push id111313
push userbmo:emilio@crisal.io
push dateSat, 26 May 2018 22:11:01 +0000
reviewershiro
bugs1459403
milestone62.0a1
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
servo/components/style/properties/helpers/animated_properties.mako.rs
--- 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: