Description
When we do interpolation on two rotate3d functions, the spec in [css-transforms-2] says:
For interpolations with the primitive rotate3d, the direction vectors of the transform functions get normalized first. If the normalized vectors are not equal and both rotation angles are non-zero the transform functions get converted into 4x4 matrices first and interpolated as defined in section Interpolation of Matrices afterwards.
We normalize the direction vectors first, and check if they are equal. However, we are trying to compare two vectors with floating-point numbers, so I'd like to know should they be equal exactly, or within a suitable tolerance?
It seems different browsers use different ways:
In WebKit, it just checks the equality directly.:
fromNormalizedVector == toNormalizedVector
In Blink, it uses the formula, A.B = |A||B|cosθ
, and compute the θ
, the angle between two vectors, within a epsilon, 1e-4
:
double dot = gfx::DotProduct(a.axis, b.axis);
if (dot < 0)
return false;
double a_squared = a.axis.LengthSquared();
double b_squared = b.axis.LengthSquared();
double error = std::abs(1 - (dot * dot) / (a_squared * b_squared));
if (error > kAngleEpsilon)
return false;
}
In Gecko, it checks the equality but with a machine epsilon:
fv.approx_eq(&tv)
I noticed this when fixing this test in Gecko:
test_composition({
property: 'rotate',
underlying: '1 2 3 40deg',
addFrom: '2 4 6 10deg',
addTo: '3 6 9 50deg',
comparisonFunction: compareRotations
}, [
{at: -1, expect: '0.27 0.53 0.8 10deg'},
{at: 0, expect: '0.27 0.53 0.8 50deg'},
{at: 0.25, expect: '0.27 0.53 0.8 60deg'},
{at: 0.75, expect: '0.27 0.53 0.8 80deg'},
{at: 1, expect: '0.27 0.53 0.8 90deg'},
{at: 2, expect: '0.27 0.53 0.8 130deg'},
]);
In this test, the axis (1, 2, 3)
is normalized as (0.26726124, 0.5345225, 0.8017837)
. However, the axis (3, 6, 9)
is normalized as (0.26726124, 0.5345225, 0.80178374)
. The 3rd component is different, 0.8017837
vs 0.80178374
, so Gecko failed this test. This is definitely a potential issue because we are comparing the normalized vectors. It seems Blink uses a smarter way and has a tolerance on the angle. However, Gecko uses a machine epsilon on each vector components.
These different implementation might have behavior-difference in the future. Should we define which way we should use to determine the equality between two normalized direction vectors? Or it doesn't matter?