Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Affine Transform really work in Java?

I have been using Affine Transform to rotate a String in my java project, and I am not an experienced programmer yet, so it has taking me a long time to do a seemingly small task.. To rotate a string.

Now I have finally gotten it to work more or less as I had hoped, except it is not as precisely done as I want... yet.

Since it took a lot of trial and error and reading the description of the affine transform I am still not quite sure what it really does. What I think I know at the moment, is that I take a string, and define the center of the string (or the point which I want to rotate around), but where does matrices come into this? (Apparently I do not know that hehe)

Could anyone try and explain to me how affine transform works, in other words than the java doc? Maybe it can help me tweak my implementation and also, I just would really like to know :)

Thanks in advance.

like image 266
Simon Langhoff Avatar asked Apr 14 '11 21:04

Simon Langhoff


3 Answers

To understand what is affine transform and how it works see the wikipedia article.

In general, it is a linear transformation (like scaling or reflecting) which can be implemented as a multiplication by specific matrix, and then followed by translation (moving) which is done by adding a vector. So to calculate for each pixel [x,y] its new location you need to multiply it by specific matrix (do the linear transform) and then add then add a specific vector (do the translation).

like image 186
Michał Šrajer Avatar answered Sep 18 '22 15:09

Michał Šrajer


In addition to the other answers, a higher level view:

  • Points on the screen have a x and a y coordinate, i.e. can be written as a vector (x,y). More complex geometric objects can be thought of being described by a collection of points.

  • Vectors (point) can be multiplied by a matrix and the result is another vector (point).

  • There are special (ie cleverly constructed) matrices that when multiplied with a vector have the effect that the resulting vector is equivalent to a rotation, scaling, skewing or with a bit of trickery translation of the input point.

That's all there is to it, basically. There are a few more fancy features of this approach:

  • If you multiply 2 matrices you get a matrix again (at least in this case; stop nit-picking ;-) ).
  • If you multiply 2 matrices that are equivalent to 2 geometric transformations, the resulting matrix is equivalent to doing the 2 geometric transformations one after the other (the order matters btw).
  • This means you can encode an arbitrary chain of these geometric transformations in a single matrix. And you can create this matrix by multiplying the individual matrices.
  • Btw this also works in 3D.

For more details see the other answers.

like image 35
Carsten Avatar answered Sep 22 '22 15:09

Carsten


Apart from the answers already given by other I want to show a practical tip namely a pattern I usually apply when rotating strings or other objects:

  1. move the point of rotation (x,y) to the origin of space by applying translate(-x,-y).
  2. do the rotation rotate(angle) (possible also scaling will be done here)
  3. move everything back to the original point by translate(x,y).

Remember that you have to apply these steps in reverse order (see answer of trashgod).

For strings with the first translation I normally move the center of the bounding box to the origin and with the last translate move the string to the actual point on screen where the center should appear. Then I can simply draw the string at whatever position I like.

Rectangle2D r = g.getFontMetrics().getStringBounds(text, g);
g.translate(final_x, final_y);
g.rotate(-angle);
g.translate(-r.getCenterX(), -r.getCenterY());
g.drawString(text, 0, 0);

or alternatively

Rectangle2D r = g.getFontMetrics().getStringBounds(text, g);
AffineTransform trans = AffineTransform.getTranslateInstance(final_x, final_y);
trans.concatenate(AffineTransform.getRotateInstance(-angle));
trans.concatenate(AffineTransform.getTranslateInstance(-r.getCenterX(), -r.getCenterY()));
g.setTransform(trans);
g.drawString(text, 0, 0);
like image 24
Howard Avatar answered Sep 20 '22 15:09

Howard