The img32 transform convention is reversed with regard to SVG #85
Replies: 8 comments
-
What has confused me is that compound transformations in SVG images are processed in reverse order (see comments in Example 5 here), even though the visual appareance[sic] is as if processed left to right. And this still isn't making sense to me since ... this SVG ...
will scale the path horizontally before rotating, and will be rendered (in Image32 and in browsers) exactly like the following image ...
|
Beta Was this translation helpful? Give feedback.
-
I swear, this comment is not intended to add confusions:) SVG: The System-transformation (matrix-building (CTM = A * B * C * ... )) goes from left to right (postmultiply), Image32: Fortunately there is no real bug (but rather inconvenience), because image32 is producing the correct result. MatrixMultiply( img32GlobalMatrix, img32LocalMatrix) implements premultiply by transposed local matrix (TMatrixD): matrix_addLocalRotate( img32CurrentMatrix, angle) implements premultiply by transposed local matrix (TMatrixD): So image32 could have some functions (matrix_addLocalRotate() and alike) to abstract away the internal implementation: |
Beta Was this translation helpful? Give feedback.
-
Too bad, you did🤣. |
Beta Was this translation helpful? Give feedback.
-
What is missing in my first comment, longer expressions: SVG: Postmultiply by nontransposed local matrix: ABC = A * B * C Reversed calling sequence with existing image32 function: SVG sequence with existing image32 function: matrixMultiply() is already SVG compliant, but not so the specific functions: MatrixRotate(), ... |
Beta Was this translation helpful? Give feedback.
-
Tom, I suspect I still haven't addressed this in my most recent commit. |
Beta Was this translation helpful? Give feedback.
-
No quick/easy fix, but a possible long-term strategy: procedure PrependTransform( const GM: TMatrixD; var matrix: TMatrixD); inline;
begin matrixMultiply( matrix, GM); end; // SVG: prepend global matrix: CTM := GM * CTM
procedure AppendTransform( var matrix: TMatrixD; const LM: TMatrixD); inline;
begin matrixMultiply2( LM, matrix); end; // SVG: append local matrix: CTM := CTM * LM Or simpler than this wrapping, just rename both matrixMultiply-functions and reverse their params. procedure AppendRotate( var matrix: TMatrixD; angle: double);
// CTM := CTM * R; is a subcase of current ParseTransform():
var mat: TMatrixD;
begin
mat := identityMatrix;
MatrixRotate( mat, NullPointD, angle);
AppendTransform( matrix, mat); // matrixMultiply2( mat, matrix);
end; AppendRotate() works, although this is not the most efficient, because MatrixRotate( mat, angle) Beyond of this, a few places already use sequences of such PrependTransform() calls. SVG chains start with most global ctmA (current transform matrix A), which is the docking site for the local chain (BCD). SVG: start with global ctmA (shortname A), then append LOCAL transforms:
Old sequence, less readable, but the same result:
|
Beta Was this translation helpful? Give feedback.
-
Thanks Tom. I do appreciate the effort you've made trying to explain this to me. |
Beta Was this translation helpful? Give feedback.
-
I've converted this to a Discussion topic since I don't think there's strictly a bug here. |
Beta Was this translation helpful? Give feedback.
-
Your code (matrixRotate(); matrixScale()) is equivalent with: svgScale(); svgRotate();
SVG adds systems from left (parent) to right (child) to produce the same current matrix,
Your example corresponds to my extraction method (M = Z2 * Q).
So Z2 would deliver the userdefined scalefactor (sy = 1),
Extraction method (M = Q * Z) delivers the visual (sy = 2), which is Ok as well.
svgRotate() with current code would be:
Originally posted by @tomwiel in #70 (comment)
Beta Was this translation helpful? Give feedback.
All reactions