How to combine translate() and rotate() into matrix()

Discuss SVG code, accessible via the XML Editor.
Pander
Posts: 19
Joined: Tue Sep 08, 2009 7:46 pm

How to combine translate() and rotate() into matrix()

Postby Pander » Fri Sep 14, 2012 1:16 am

Hi all,

I have an SVG file with objects that have a translate(). I would like to rotate these objects but a combination of translate() and rotate() is not succesful. When I reverse engineer what Inkscape is doing, I see after rotation, around the objects center, a matrix() replace the translate(). The contraints on the 6 parameters I understand but am unable to reproducte these in correctly altering the SVG. Below are two examples of 45 degree rotations in both directions.

"node19" before rotation:

Code: Select all

    <g
       class="node"
       id="node19"
      transform="translate(4,321.187)">
      <title
         id="title129">qwertyasdf22</title>
      <ellipse
         style="fill:none;stroke:#000000"
         sodipodi:ry="18.3848"
         sodipodi:rx="79.195999"
         sodipodi:cy="-260.41699"
         sodipodi:cx="117.27"
         d="m 196.466,-260.41699 c 0,10.15364 -35.45726,18.3848 -79.196,18.3848 -43.738746,0 -79.196003,-8.23116 -79.196003,-18.3848 0,-10.15365 35.457257,-18.3848 79.196003,-18.3848 43.73874,0 79.196,8.23115 79.196,18.3848 z"
         id="ellipse131"
         ry="18.3848"
         rx="79.195999"
         cy="-260.41699"
         cx="117.27" />
      <text
         style="font-size:14px;text-anchor:middle;font-family:'Times Roman,serif'"
         id="text133"
         font-size="14.00"
         y="-256.81699"
         x="117.27">qwertyasdf22</text>
    </g>


"node19" after rotation:

Code: Select all

    <g
       class="node"
       id="node19"
      transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,222.49021,327.83504)">
      <title
         id="title129">qwertyasdf22</title>
      <ellipse
         style="fill:none;stroke:#000000"
         sodipodi:ry="18.3848"
         sodipodi:rx="79.195999"
         sodipodi:cy="-260.41699"
         sodipodi:cx="117.27"
         d="m 196.466,-260.41699 c 0,10.15364 -35.45726,18.3848 -79.196,18.3848 -43.738746,0 -79.196003,-8.23116 -79.196003,-18.3848 0,-10.15365 35.457257,-18.3848 79.196003,-18.3848 43.73874,0 79.196,8.23115 79.196,18.3848 z"
         id="ellipse131"
         ry="18.3848"
         rx="79.195999"
         cy="-260.41699"
         cx="117.27" />
      <text
         style="font-size:14px;text-anchor:middle;font-family:'Times Roman,serif'"
         id="text133"
         font-size="14.00"
         y="-256.81699"
         x="117.27">qwertyasdf22</text>
    </g>


"node33" before rotation:

Code: Select all

    <g
       class="node"
       id="node33"
      transform="translate(4,321.187)">
      <title
         id="title227">qwertyasdf43</title>
      <ellipse
         style="fill:none;stroke:#000000"
         sodipodi:ry="18.3848"
         sodipodi:rx="79.195999"
         sodipodi:cy="-121.323"
         sodipodi:cx="358.18701"
         d="m 437.38301,-121.323 c 0,10.15365 -35.45726,18.3848 -79.196,18.3848 -43.73874,0 -79.196,-8.23115 -79.196,-18.3848 0,-10.15364 35.45726,-18.3848 79.196,-18.3848 43.73874,0 79.196,8.23116 79.196,18.3848 z"
         id="ellipse229"
         ry="18.3848"
         rx="79.195999"
         cy="-121.323"
         cx="358.18701" />
      <text
         style="font-size:14px;text-anchor:middle;font-family:'Times Roman,serif'"
         id="text231"
         font-size="14.00"
         y="-117.723"
         x="358.18701">qwertyasdf43</text>
    </g>


"node33" after rotation

Code: Select all

    <g
       class="node"
       id="node33"
      transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,23.122232,32.375852)">
      <title
         id="title227">qwertyasdf43</title>
      <ellipse
         style="fill:none;stroke:#000000"
         sodipodi:ry="18.3848"
         sodipodi:rx="79.195999"
         sodipodi:cy="-121.323"
         sodipodi:cx="358.18701"
         d="m 437.38301,-121.323 c 0,10.15365 -35.45726,18.3848 -79.196,18.3848 -43.73874,0 -79.196,-8.23115 -79.196,-18.3848 0,-10.15364 35.45726,-18.3848 79.196,-18.3848 43.73874,0 79.196,8.23116 79.196,18.3848 z"
         id="ellipse229"
         ry="18.3848"
         rx="79.195999"
         cy="-121.323"
         cx="358.18701" />
      <text
         style="font-size:14px;text-anchor:middle;font-family:'Times Roman,serif'"
         id="text231"
         font-size="14.00"
         y="-117.723"
         x="358.18701">qwertyasdf43</text>
    </g>


As one can see the translate is identical to both nodes. How do I calculate the 'e' and 'f' parameters of both matrix() transformations. How do I use cy and cx for that? Since I assume I need to use these values somehow.

Thanks for your help,

Pander

User avatar
tomh
Posts: 218
Joined: Sat Feb 14, 2009 10:14 pm

Re: How to combine translate() and rotate() into matrix()

Postby tomh » Mon Sep 17, 2012 4:36 am

Well, it has been a while since I last had to do matrix maths, or looked into how it applies to svg,

Would either of my previous answers to this question help:
1) viewtopic.php?f=16&t=10550&p=39202#p39202
2) viewtopic.php?f=16&t=5398&p=23229#p23229

I must admit that it has been some time since I have looked at those, but if they don't answer your question then feel free to ask follow up questions.

Jelle
Posts: 78
Joined: Sat Nov 06, 2010 11:25 am

Re: How to combine translate() and rotate() into matrix()

Postby Jelle » Mon Sep 17, 2012 3:18 pm

Hi Pander,

The clever folks that cooked up SVG saw that one coming. There is a very nice javascript (and possibly other languages) function for that called getCTM. No need to do all the calculation yourself. Just do your translate and rotate and then use the function getCTM.

Basically what you need to do is

Code: Select all

Object = evt.target
CTM = Object.getCTM


Here is a good example for that
http://www.learnsvg.com/tutorials/tutor ... getCTM.svg

Pander
Posts: 19
Joined: Tue Sep 08, 2009 7:46 pm

Re: How to combine translate() and rotate() into matrix()

Postby Pander » Mon Sep 17, 2012 5:51 pm

In this case I need/want to calculate it myself because my script is inserting different rotations for different objects. I think I need to combine the translation of (x+4,y+321.187) in matrix form with the rotation to get the final matrix.

Code: Select all

[1 0   4    ] [0.707 -0.707 k] [0.707 -0.707 222.490]
[0 1 321.187]*[0.707  0.707 l]=[0.707  0.707 327.835]
[0 0   1    ] [0      0     1] [0      0       1    ]


So k = 222.490 - 4 = 218.490 and l = 327.835 - 321.178 = 6.657 If this is correct, how do I get these two values from cx and cy?

Pander
Posts: 19
Joined: Tue Sep 08, 2009 7:46 pm

Re: How to combine translate() and rotate() into matrix()

Postby Pander » Thu Nov 01, 2012 10:09 pm

Anyone?

chriswww
Posts: 383
Joined: Fri Nov 19, 2010 3:04 pm

Re: How to combine translate() and rotate() into matrix()

Postby chriswww » Mon Nov 05, 2012 2:51 pm

very rusty on matrix maths...however it might be noteworthy that numbers you plug into the transformation matrix for rotation are Sin of the angle and Cos of the angle, in radians. Any reference on matrix transformations should show the correct formula and you can confirm whether inkscape also does the same.

Pander
Posts: 19
Joined: Tue Sep 08, 2009 7:46 pm

Re: How to combine translate() and rotate() into matrix()

Postby Pander » Wed Dec 05, 2012 7:22 am

The rotation matrix I can follow, see also https://en.wikipedia.org/wiki/Rotation_matrix It is the cx and cy which are a mystery to me.

cmax
Posts: 4
Joined: Tue Dec 18, 2012 4:06 am

Re: How to combine translate() and rotate() into matrix()

Postby cmax » Tue Dec 18, 2012 6:11 am

edit: Please read my following post, because this answer is not correct.

Hi Pander,

a translation can't be expressed as a matrix (beside the zero translation).

If you multiply a matrix with a zero vector, you'll always get a zero vector. ==> no translation


Regards

max

cmax
Posts: 4
Joined: Tue Dec 18, 2012 4:06 am

Re: How to combine translate() and rotate() into matrix()

Postby cmax » Mon Dec 24, 2012 10:39 pm

Hi Pander,

my answer above was not correct. Due I'm new in SVG I have not noticed that the number of columns of the transformation matrix (3x3) is higher then the number of rows of the vectors / points (2x1) and the vector v = (x y)^T is replaced by (x y 1)^T in all calculations.

By this a translation is possible (^T = transpose):

You already know how to get a-d of the (3x3) matrix:

Code: Select all

a c e
b d f
0 0 1


Let t_o be the old translation vector,
c = (cx cy)^T,
R be the 2x2 rotation matrix =

Code: Select all

a c
b d


E be the 2x2 identity matrix =

Code: Select all

1 0
0 1


Then the new translation vector t_n = (e f)^T can be calculated by:

t_n = (E-R)*c + t_o


Merry Xmax

Max

littlegrassfolks
Posts: 23
Joined: Tue Mar 12, 2013 2:16 am

Re: How to combine translate() and rotate() into matrix()

Postby littlegrassfolks » Mon Apr 15, 2013 2:21 am

Translation can be expressed as a matrix. Of course it can. Apply this matrix to point [1; 1; 1] (this represents a point 1,1 in 2d the last element is just a place holder. The first two numbers are the x and y coordinates) and you will get the answer [2; 2; 1]. The matrix should be [1, 0, 1; 0, 1, 1; 0, 0, 1]. A comma means next element in the same row and semi colon means next row. This matrix will translate any point in 2d by 1,1.

cmax wrote:edit: Please read my following post, because this answer is not correct.

Hi Pander,

a translation can't be expressed as a matrix (beside the zero translation).

If you multiply a matrix with a zero vector, you'll always get a zero vector. ==> no translation


Regards

max


Return to “SVG / XML Code”