How to scale rotated objects properly in Actionscript 3?

Posted by Tom on Stack Overflow See other posts from Stack Overflow or by Tom
Published on 2010-03-17T12:00:52Z Indexed on 2010/03/17 13:11 UTC
Read the original article Hit count: 254

This is unfortunately a quite complex issue to explain, so please don't get discouraged by the wall of text - it's there for a reason. ;)

I'm working on a transformation manager for flash, written with Actionscript 3. Users can place objects on the screen, for example a rectangle.

This rectangle can then be selected and transformed: move, scale or rotate.

Because flash by default rotates around the top left point of the object, and I want it to rotate around the center, I created a wrapper setup for each display object (eg. a rectangle).

This is how the wrappers are setup:

//the position wrapper makes sure that we do get the top left position when we access x and y
var positionWrapper:Sprite = new Sprite();
positionWrapper.x = renderObject.x;
positionWrapper.y = renderObject.y;

//set the render objects location to center at the rotation wrappers top left
renderObject.x = 0 - renderObject.width / 2;
renderObject.y = 0 - renderObject.height / 2;

//now create a rotation wrapper, at the center of the display object
var rotationWrapper:Sprite = new Sprite();
rotationWrapper.x = renderObject.width / 2;
rotationWrapper.y = renderObject.height / 2;

//put the rotation wrapper inside the position wrapper and the render object inside the rotation wrapper
positionWrapper.addChild(rotationWrapper);
rotationWrapper.addChild(renderObject);

Now, the x and y of the object can be accessed and set directly: mainWrapper.x or mainWrapper.y. The rotation can be set and accessed from the child of this main wrapper: mainWrapper.getChildAt(0).rotation. Finally, the width and height of the display object can be retreived and set by getting the child of the rotation wrapper and accessing the display object directly.

An example on how I access them:

//get wrappers and render object
var positionWrapper:Sprite = currentSelection["render"];
var rotationWrapper:Sprite = positionWrapper.getChildAt(0) as Sprite;
var renderObject:DisplayObject = rotationWrapper.getChildAt(0);

This works perfectly for all initial transformations: moving, scaling and rotating.

However, the problem arises when you first rotate an object (eg. 45 degrees) and then scale it. The scaled object is getting out of shape and doesn't scale as it should.

This for example happens when you scale to the left. Scaling left is basically adding n width to the object and then reduce the x coord of the position wrapper by n too:

renderObject.width -= diffX;
positionWrapper.x += diffX;

This works when the object is not rotated. However, when it is, the position wrapper won't be rotated as it is a parent of the rotation wrapper. This will make the position wrapper move left horizontally while the width of the object is increased diagonally.

I hope this makes any sense, if not, please tell me and I'll try to elaborate more.

Now, to the question: should I use a different kind of setup, system or structure? Should I maybe use matrixes, if so, how would you keep a static width/height after rotation? Or how do I fix my current wrapper system for scaling after rotation? Any help is appreciated.

© Stack Overflow or respective owner

Related posts about transform

Related posts about algorithm