[csswg-drafts] [css-transforms] Inconsistencies in 2D and 3D matrix decomposition (#3713)

kevers-google has just created a new issue for https://github.com/w3c/csswg-drafts:

== [css-transforms] Inconsistencies in 2D and 3D matrix decomposition ==
2D spec: https://drafts.csswg.org/css-transforms/#decomposing-a-2d-matrix
3D spec: https://drafts.csswg.org/css-transforms-2/#decomposing-a-3d-matrix

A minor tweak to a transformation matrix that alters the transform from 2D to 3D, or vice versa, should not radically alter the interpolation path.

In the 2D case, the decomposed matrix has a total of 9 parameters: 2 translate, 2 scale, an angle and a 2x2 matrix that corresponds to the skew.  This feels over-specified as the skew should be expressible with at most 2 parameters.

Here is an alternative, which is more consistent with the 3D matrix decomposition:

```
Input:  
    matrix      ; a 4x4 matrix
Output: 
    translation ; a 2 component vector
    scale       ; a 2 component vector
    skew        ; X skew
    angle       ; rotation
Returns false if the matrix cannot be decomposed, true if it can

m11 = matrix[0][0]
m12 = matrix[0][1]
m21 = matrix[1][0]
m22 = matrix[1][1]

determinant = m11 * m22 - m12 * m21;
if (determinant == 0)
    return false;

translate[0] = matrix[3][0]
translate[1] = matrix[3][1]

scale[0] = 1;
scale[1] = 1;
if (determinant < 0)
    // If the determinant is negative, we need to flip either the x or y scale.
    // Flipping both is equivalent to rotating by 180 degrees.
    if (m11 < m22)
        scale[0] = -1
    else
        scale[1] = -1

scale[0] *= sqrt(m11 * m11 + m12 * m12)
m11 /= scale[0]
m12 /= scale[0]

scaledShear = m11 * m21 + m12 * m22
m21 -= m11 * scaledShear
m22 -= m12 * scaledShear

scale[1] *= sqrt(m21 * m21 + m22 * m22)
m21 /= scale[1]
m22 /= scale[1]
skew = scaledShear / scale[1]
angle = atan2(m12, m11)
```

The inconsistency in handling negative determinants is files as https://github.com/w3c/csswg-drafts/issues/3712.

The 3D counterpart to this 2D decomposition is:

decomp3d.scale = [decomp2d.scale[0], decomp2d.scale[1], 1]
decomp3d.translate = [decomp2d.translate[0], decomp2d.translate[1], 0]
decomp3d.skew = [decomp2d.skew, 0, 0]
decomp3d.perspective = [0, 0, 0, 1]
decomp3d.quaternion = [0, 0, sin(decomp2d.angle/2), cos(decomp2d.angle/2)]

Having this simple mapping facilitates blending a 2D and 3D transformation matrix.  










Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/3713 using your GitHub account

Received on Wednesday, 6 March 2019 21:57:20 UTC