xmlgraphics-batik-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Bishop, Michael W. CONTR J9C880" <Michael.Bis...@je.jfcom.mil>
Subject RE: Extracting information from a transformation matrix
Date Thu, 01 Jun 2006 16:46:19 GMT
All right, this is great information.  I need to sit down and work through it with my SVG Matrix
algebra examples in front of me.  I do have a couple of questions:
- Assuming I already have the center poitns, I could derive all the values I wanted right?
 The rotate(t, x, y) command is a shortcut for translation if I remember right.  It's short
for translate(x,y) rotate(t) translate(-x,-y) isn't it?  Would I have to take that into account?
- Does the order matter?  In the app, you can scale, rotate, and translate in any order.
Michael Bishop


From: Andrew Plotkin [mailto:erkyrath@eblong.com]
Sent: Thu 6/1/2006 12:27 PM
To: batik-users@xmlgraphics.apache.org
Subject: RE: Extracting information from a transformation matrix

On Thu, 1 Jun 2006, Bishop, Michael W. CONTR J9C880 wrote:

> Wow, this is going to make me take another close look at the transformation matrix for
SVG.  Let's start with an example:
> transform="translate(x, y) scale(sx, sy) rotate(t, cx, cy)"
> The above is the only kind of transform I maintain in my application.
> If the user drags an element around the screen, it directly affects
> translate.
> If the user scales the element, it affects scale which indirectly
> affects translate.
> If the user rotates the element, I believe it affects scale which also
> affects translate.
> What I want to do is be able to break apart the above to find out the
> values I wanted before.  The first thing I need to go is get a
> representation of the above into the matrix values (a, b, c, d, e, f).

Ok, let's work through it.

Here is a simple routine that gets the transform of an object relative to
its parent:

function dump(id) {
   var el = document.getElementById(id);
   var parent = el.parentNode;
   var matrix = el.getTransformToElement(parent);
   alert(matrix.a + " " + matrix.c + " " + matrix.e
     + "\n" + matrix.b + " " + matrix.d + " " + matrix.f);

Some samples, in the standard format:
   a c e
   b d f

<ellipse id="none" rx="1" ry="2" />
   1 0 0
   0 1 0

<ellipse id="trans" transform="translate(4,4)" rx="1" ry="2" />
   1 0 4
   0 1 4

<ellipse id="scale" transform="scale(3)" rx="1" ry="2" />
   3 0 0
   0 3 0

<ellipse id="rot" transform="rotate(60)" rx="1" ry="2" />
   0.5 -0.8660253882408142 0
   0.8660253882408142 0.5 0

(Note that 0.8660253882408142 is sqrt(3)/2, or sin(60). 0.5 is cos(60).
Now you know where those numbers come from.)

So an object with a translate+scale+rotate:

<ellipse id="all" transform="translate(4,4) scale(3) rotate(60)" rx="1"
   ry="2" />
   1.5 -2.598076105117798 4
   2.598076105117798 1.5 4

Now this is easy to undo. We're going to pull the transforms off in
forwards order (the *same* order they're listed in the transform

Translate is the (e,f) values directly:
   translate = (4,4).

Now remove this by setting e and f to zero:

   1.5 -2.598076105117798 0
   2.598076105117798 1.5 0

The scale is the magnitude of (a,b). Or (c,d) or (a,c) -- all the same.
Pythagorean theorem:

   scale = sqrt(1.5*1.5 + -2.598076105117798*-2.598076105117798) = 3

Now remove this by dividing each element of the matrix by 3:

   0.5 -0.8660253882408142 0
   0.8660253882408142 0.5 0

What's left is the pure rotation -- you can see it's the same as the "rot"
matrix above. To get the angle out, you'll want to use an atan2 function;
in Javascript this is Math.atan2. The result of that is radians, so we
also have to convert to degrees:

   rotate = atan2(b,a) * 180 / 3.1415926 = 60

Now, the rotation in this example is a rotation around the origin. You
asked about the more complex rotation "rotate(t, cx, cy)". Unfortunately,
there's no way to get that information! If we consider the object

<ellipse id="sall" transform="translate(4,4) scale(3) rotate(60,1,2)"
   rx="1" ry="2" />

and apply the above procedure, you'll get the result:

Or, if you like,

<ellipse id="sall2" transform="translate(10.69615268,4.401909828) scale(3)
   rotate(60)" rx="1" ry="2" />

The problem is, this is the right answer! These two transforms produce the
*same* matrix -- the same a,b,c,d,e,f values. And there are an infinite
other number of "translate(x, y) scale(sx, sy) rotate(t, cx, cy)"
transforms that produce that matrix. To get a single solution, you *have*
to assume that cx and cy are zero. Otherwise you're trying to get
seven unknowns out of six variables, which is impossible.

(If you assume cx and cy are zero, you get five unknowns out of six
variable. The sixth unknown is skew, or stretching on an axis; the
procedure above assumes there's none of that either.)


"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
If the Bush administration hasn't shipped you to Syria for interrogation,
it's for one reason: they don't feel like it. Not because you're patriotic.

To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org

View raw message