- From: L. David Baron <dbaron@dbaron.org>
- Date: Thu, 24 Jun 2010 23:18:48 -0700
- To: www-style@w3.org
http://dev.w3.org/csswg/css3-2d-transforms/#matrix-decomposition has the pseudo-code: # // At this point, the matrix (in rows) is orthonormal. # // Check for a coordinate system flip. If the determinant # // is -1, then negate the matrix and the scaling factors. # pdum3 = cross(row[1], row[2]) # if (dot(row[0], pdum3) < 0) # for (i = 0; i < 3; i++) { # scale[0] *= -1; # row[i][0] *= -1 # row[i][1] *= -1 # row[i][2] *= -1 Comparing to the original code in unmatrix.c, I think scale[0] should be scale[i]. However, that still leaves the question about what to do for this code for 2D transforms. In this case, the full 3D decomposition (when given 0 0 1 0 for the third row of the matrix) produces a scaleZ(-1) and a rotateX(180deg) in addition to the terms relevant to 2D. These two are equivalent to a scaleX(-1). In the 3D decomposition, the rotateX comes before the skewX, and therefore changes its sign. Or something like that. I haven't quite worked it out to my satisfaction. But in the end, I think there are two possibilities for what to do in the 2-D algorithm when the determinant is negative (I've tested these): (a) Invert scaleY and XYshear. (b) Invert scaleX, XYshear, A, B, C, and D. (so that the rotation, computed from A and B, ends up in the opposite quadrant). These appear to be the only options that produce correct decompositions for the intermediate stages of the transitions in http://dbaron.org/css/test/2010/transition-negative-determinant . And I'm not sure if either is really compatible with what 3D does, but I haven't yet worked that out. (At some point I could test which of the two behaviors is compatible with what Safari does.) In any case, that gives a 2D decomposition algorithm that looks something like: # For CSS 2D transforms, we have a 2D matrix with the bottom row constant: # # [ A C E ] # [ B D F ] # [ 0 0 1 ] # # For that case, I believe the algorithm in unmatrix reduces to: # # (1) If A * D - B * C == 0, the matrix is singular. Fail. # # (2) Set translation components (Tx and Ty) to the translation parts of # the matrix (E and F) and then ignore them for the rest of the time. # (For us, E and F each actually consist of three constants: a # length, a multiplier for the width, and a multiplier for the # height. This actually requires its own decomposition, but I'll # keep that separate.) # # (3) Let the X scale factor (Sx) be sqrt(A^2 + B^2). Then divide both A # and B by it. # # (4) Let the XY shear (K) be A * C + B * D. From C, subtract A times # the XY shear. From D, subtract B times the XY shear. # # (5) Let the Y scale (Sy) be sqrt(C^2 + D^2). Divide C, D, and the XY # shear (K) by it. # # (6a) At this point, A * D - B * C is either 1 or -1. If it is -1, # negate the XY shear (K) and the Y scale (Sy). # (or (6b) from above) # # (7) Let the rotation be R = atan2(B, A). # # Then the resulting decomposed transformation is: # # translate(Tx, Ty) rotate(R) skewX(atan(K)) scale(Sx, Sy) (I wonder also if it might be nice to use a decomposition that would be more likely to produce a scale(-1) than a rotate(180deg); this could be done by multiplying scaleX by the sign of A right after computing it, and likewise scaleY by the sign of D. But I'm not sure how to extend this idea into 3D, and it would be an incompatible change to the current algorithm.) -David -- L. David Baron http://dbaron.org/ Mozilla Corporation http://www.mozilla.com/
Received on Friday, 25 June 2010 06:19:21 UTC