AlecMcE.com

Coding on the Flash Platform

Gotcha – transform.matrix and scaleX/Y

View Comments

I came across this gotcha for the first time today. Praise-be to ASUnit, without which this could have been extremely difficult to unearth:

// given two sprites called "a" and "b"...

a.transform.matrix = new Matrix(-.5, 0, 0, -.5, a.x, a.y);
b.scaleX = b.scaleY = -.5;

trace(a.scaleX, a.scaleY, b.scaleX, b.scaleY); // outputs: 0.5, 0.5, -0.5, -0.5

Both clips have been scaled by -0.5, but because the transform was used to produce the scale for a, the scaleX/Y variables do not reflect the object’s true scale.

Now, just to confuse yourself, add a third sprite to the stage:

// given another sprite called "c"...

c.transform.matrix = new Matrix(-.5, 0, 0, -.5, c.x, c.y);
c.scaleX = c.scaleY = -.5;

Curiouser and curiouser! This needed a more complete experimentation…

The Flash plugin is required to view this object.

The source for this experiment can be found here: scaleAndTransform. The buttons call the following methods:

function onGo(event:Event):void
{
	a.transform.matrix = new Matrix(-.5, 0, 0, -.5, a.x, a.y);

	b.scaleX = b.scaleY = -.5;

	c.transform.matrix = new Matrix(-.5, 0, 0, -.5, c.x, c.y);
	c.scaleX = c.scaleY = -.5;
}

function onResetScale(event:Event):void
{
	a.scaleX = a.scaleY = 1;
	b.scaleX = b.scaleY = 1;
	c.scaleX = c.scaleY = 1;
}

function onResetTransform(event:Event):void
{
	a.transform.matrix = new Matrix(1, 0, 0, 1, a.x, a.y);
	b.transform.matrix = new Matrix(1, 0, 0, 1, b.x, b.y);
	c.transform.matrix = new Matrix(1, 0, 0, 1, c.x, c.y);
}

What Is Going On?

If you apply a transformation matrix then a scale, the magnitude of the scale is applied, but the direction is determined by the product of the transformation and the scalar… which is to say that:

a.realScaleX = (a.transform.matrix.a * a.scaleX > 0 ? 1 : -1) * a.scaleX;

If however you apply a scale then a transformation, the scale is defined by the transformation only!

a.realScaleX = a.transform.matrix.a;

Bug?

Does this qualify as a bug? I haven’t thought about this for long enough. The conditions in which a transformation matrix rotates and skews the MovieClip confuse me; how would I define scaleX and scaleY in that scenario? I need to give this some thought; perhaps you the community can give me some help! I am reluctant to call anything a bug immediately now, after my experience with my The Problem With Vector.<T> post, where I was just plain wrong!

A similar bug exists in Adobe JIRA: UIComponent.scaleX, scaleY differ from transform.matrix.a,d. You’ll need an account to look at this – it’s free, and once you’ve got it you can pester Adobe with your bugs too.

Written by alec

February 23rd, 2010 at 9:00 am

Posted in as3,gotcha,math,tdd

  • http://twitter.com/robpenner robpenner

    If you also trace out the rotation and matrix for a, b and c, you can solve the mystery:

    trace(a.scaleX, a.scaleY, a.rotation, a.transform.matrix);
    trace(b.scaleX, b.scaleY, b.rotation, b.transform.matrix);
    trace(c.scaleX, c.scaleY, c.rotation, c.transform.matrix);

    0.5 0.5 180 (a=-0.5, b=0, c=0, d=-0.5, tx=125, ty=173)
    -0.5 -0.5 0 (a=-0.5, b=0, c=0, d=-0.5, tx=250, ty=173)
    -0.5 -0.5 180 (a=0.5, b=0, c=0, d=0.5, tx=375, ty=173.45)

    Scaling x or y by -1 is equivalent to flipping on that axis. Scaling x and y by -1 at the same time is equivalent to rotating by 180 degrees. Decomposing a matrix into scale and skew/rotation requires an interpretation that is ambiguous, at times.

    For a and b, the matrices are identical in scale. However, the interpretation appears to be swayed by the whether the scaleX and scaleY properties are set. Flash seems to cache scaleX and scaleY, rather than doing a fresh decompose every time. That's my guess.

    c is interesting because it is both doubly negative and rotated, which cancel out.

  • http://alecmce.com alecmce

    Thanks Robert for your analysis. On reflection this should have been reasonably apparent, but I've been a little busy of late. You are right, of course.

  • http://pulse.yahoo.com/_PTYBDR6MTFEVR2YFI2WJJ4SPH4 Niko Nami

    hey your post leaded me to the solution, by raising the issue to my conscious :)

    actually Adobe has described the issue in the FP9 release notes:
    http://www.adobe.com/support/documentation/en/f...

    Transform Matrix transformations are not reflected in respective MovieClip/DisplayObject properties. Properties like scaleX, scaleY, and rotation are not changed as the result of changes to a DisplayObject’s transformation matrix (flash.geom.Transform, flash.geom.Matrix).

    they suggest to use Matrix-Transformations instead to solve the scaleX / scaleY function.

    which i found solved in the “fl.motion.MatrixTransformer” – which again you can find in the Flash CS3 IDE path:
    [Program Files]AdobeAdobe Flash CS3deConfigurationActionScript 3.0Classesflmotion

blog comments powered by Disqus