Quick Links

Education Edu

Simulations Sims

Math Tools Math

Games Games

Generative ArtArt

Actinoscript Prog

Farmville Farm




Affine Transformation

Click the above-left picture of the Affine Transformation applet to start the application.


Affine Transforms

Easy vs. Hard

If you've ever wanted to programmatically do more in actionscript 3 than just rotate or scale an object, you've probably bang-ed your head against the affine transform brick wall. In a manner similar to struggling with dynamic gradients, affine transformations can seem so easy when you're grabbing the mouse and skewing or scaling, but quite difficult when forced to come up with the actual numbers that accomplish the same effect in code. I previously created a gradient toolkit to make my life easier, so I decided to finally create the corresponding affine transform toolkit.

There are many tutorial discussions about affine transformation in actionscript 3, such as Senocular's, but I've always found that though these gave me quite a bit of information and many pretty pictures, they still left me scratching my head when it came to accomplishing my goals. Contrary to almost all other "tutorials" on the subject, I created a symbol that has definitively identifiable corners so that it would be easier to determine exactly how the transform has affected the symbol.

The Result

The finished product allows you to adjust the skew and scale of x and y and gives you the exact code to accomplish the same in your own code. Play around with this a bit and I'll explain the gotcha-s below. Here is a direct link so that you can stretch it.

Content on this page requires a newer version of Adobe Flash Player.

Get Adobe Flash player


Gotcha 1: Registration Point

If you create a symbol that doesn't have it's registration point in the center, it will behave differently when transformed. In the toolkit, I present nine versions of the same symbol, each one having it's registration point in one of the nine canonical positions: upper left, middle of top edge, upper right, middle of left edge, center, middle of right edge, lower left, middle of bottom edge, and lower right. When the transforms are performed, they are enacted in terms of the position of the registration point relative to the upper left corner of the stage (0,0). This applet forces it to respond relative to the registration point independent of the symbol's position. You'll notice that when a transform is applied that the registration points stay fixed in their grid.

To see this in effect, reset the applet and set the x scale to -1. Reset and then do it again for y scale. As expected the symbol flips about the x or y axis at its registration point. Only the center registered object retains it's original position.

There are supposedly a couple of solutions for this. One is to first move the symbol to (0,0), perform the transform, then move it back to its original location. Another method involves creating a parent class for the symbol which forces it's registration point to be in the center of is "body mass" horizontally and vertically. There are a handful of classes for this floating about the web. I've always found that if the object is strangely shaped, such automatic re-registration classes don't seem to get my symbol's registration where I want it and it requires some little bit of tweaking. I think it's easier just to begin with the original symbol forceably centered where you want.

I took the approach of accounting for offset from the origin by setting the other two matrix parameters, tx, ty, to take the position of the symbol itself. I haven't seen this in Adobe's documentation, but I've got to assume that this was what they intended. For this reason, there are no sliders to twiddle tx and ty in the matrix.

Nonetheless, this doesn't take into account the registration point. As far as I've been able to figure out, actionscript doesn't give you any way to read the registration point offset from the position of the symbol itself. Diehard coders may be able to determine it's actual position by a ridiculously convoluted method that I propose but am too lazy to do myself.

If you create a BitmapData object and use applyFilter to render an image of the symbol to the bitmap data, using a filter that has effectively no strength, and then flip the symbol horizontally (using the affine transforms) and render this to the same BitmapData object, you should get an image of the object reflected across it's registration point that permits you to determine its reflection's width. Half that width should be the position of the x coordinate of the registration point from the right edge of the symbol. A similar routine in the vertical direction should allow you to determine the y coordinate. In the unlikely event that someone reading this actually does this and gets a working class, please send me a copy. Thank you.

As it stands, these 9 symbols demonstrate the effect of performing the transforms without taking the registration point's offset into consideration. The moral of the story is center your symbols when you want to do affine transforms so that such issues don't crop up.

Gotcha 2: Parameters Deceive

X-scale means x-scale, right? Not when working with affine transforms. It is possible to fiddle with the parameters so that both the x and y scale are zero and yet the symbol remains visible. Reset the applet and set both scale-s to zero and the skews (x,y) to (0.5,-0.5). There are many other combinations of this possible. The result is that the skew parameters start to act like scale. When the two scales are zero, and the absolute value of the two skews is the same, then the skews behave as scale.

Gotcha 3: Mirrorred Images

If you ever end up with a negative scale value, any text in your symbol will either be reversed or upside down, depending on your skew parameters. Just something to look out for if you want it to be readable. Bear in mind that in order to affine transform text, you will need to embed the font. See how this is done at this post.

Using The Code

After playing with the slider to get the affect you desire, select the code and copy it into your own. If you're working in the timeline, the import isn't necessary. An assumption is made that you have some symbol with a linkage identifier of MySymbol, so change that accordingly. The "ms" isn't a tribute to Microsoft, just my symbol's initials. Also, the {xpos} and {ypos} represent real values that you fill in.

import flash.geom.Matrix;

var ms:MySymbol = new MySymbol();
var xMat:Matrix = new Matrix(
0.00, // x scale
1.00, // y skew
1.00, // x skew
0.00, // y scale
ms.x, // tx
ms.y); // ty

Other Notes

I think it's a lot easier to rotate using the rotation property rather than with affine transforms, but If you absolutely must, don't attempt to go beyond 90 degrees. It get's pretty confusing. 45 degree rotations are pretty easy, though, they always involve having values positive or negative 1. Importantly though, the scales start to act as rotation when they have the same value and the skews are set to positive/negative one.

Scale Skew Result
1.0 1.0 -1.0 1.0 45 degrees rotation
1.0 1.0 1.0 -1.0 -45 degrees rotation
1.0 1.0 -1.0 -1.0 symbol squished into a positively sloped 45 degree line
1.0 1.0 1.0 1.0 symbol squished into a negatively sloped 45 degree line
-0.5 -0.5 1.0 -1.0 -135 degrees rotation
-0.5 -0.5 -1.0 1.0 +135 degrees rotation
-0.2 -0.2 -1.0 -1.0 Barely smaller different rotation.

Effectively, the same scales result in rotation when the absolute value of the skews is 1.