The best approach would probably be to use the code posted in the question - i.e. to unrotate the object, check its width, and then re-rotate it. Here's why.
First, simplicity. It's obvious what's being done, and why it works. Anyone coming along later should have no trouble understanding it.
Second, accuracy. Out of curiosity I coded up all three suggestions currently in this thread, and I was not really surprised to find that for an arbitrarily scaled object, they give three slightly different answers. The reason for this, in a nutshell, is that Flash's rendering internals are heavily optimized, and among other things, width
and height
are not stored internally as floats. They're stored as "twips" (twentieths of a pixel) on the ground that further accuracy is visually irrelevant.
Anyway, if the three methods give different answers, which is the most accurate? For my money, the most correct answer is what Flash thinks the width of the object is when it's unrotated, which is what the simple method gives us. Also, this method is the only one that always give answers rounded to the nearest 1/20, which I surmise (though I'm guessing) to mean it's probably equal to the value being stored internally, as opposed to being a calculated value.
Finally, speed. I assume this will surprise you, but when I coded the three methods up, the simple approach was the fastest by a small margin. (Don't read too much into that - they were all very close, and if you tweak my code, a different method might edge into the lead. The point is they're very comparable.)
You probably expected the simple method to be slower on the grounds that changing an object's rotation would cause lots of other things to be recalculated, incurring overhead. But all that really happens immediately when you change the rotation is that the object's transform matrix gets some new values. Flash doesn't really do much with that matrix until it's next time to draw the object on the screen. As for what math occurs when you then read the object's width/height, it's difficult to say. But it's worth noting that whatever math takes place in the simple method is done by the Player's heavily optimized internals, rather than being done in AS3 like the algebraic method.
Anyway I invite you to try out the sample code, and I think you'll find that the simple straightforward method is, at the least, no slower than any other. That plus simplicity makes it the one I'd go with.
Here's the code I used:
// init
var clip:MovieClip = new MovieClip();
clip.graphics.lineStyle( 10 );
clip.graphics.moveTo( 12.345, 37.123 ); // arbitrary
clip.graphics.lineTo( 45.678, 29.456 ); // arbitrary
clip.scaleX = .87; // arbitrary
clip.scaleY = 1.12; // arbitrary
clip.rotation = 47.123; // arbitrary
// run the test
var iterations:int = 1000000;
test( method1, iterations );
test( method2, iterations );
test( method3, iterations );
function test( fcn:Function, iter:int ) {
var t0:uint = getTimer();
for (var i:int=0; i<iter; i++) {
fcn( clip, i==0 );
}
trace(["Elapsed time", getTimer()-t0]);
}
// the "simple" method
function method1( m:MovieClip, traceSize:Boolean ) {
var rot:Number = m.rotation;
m.rotation = 0;
var w:Number = m.width;
var h:Number = m.height;
m.rotation = rot;
if (traceSize) { trace([ "method 1", w, h ]); }
}
// the "algebraic" method
function method2( m:MovieClip, traceSize:Boolean ) {
var r:Number = m.rotation * Math.PI/180;
var c:Number = Math.abs( Math.cos( r ) );
var s:Number = Math.abs( Math.sin( r ) );
var denominator:Number = (c*c - s*s); // an optimization
var w:Number = (m.width * c - m.height * s) / denominator;
var h:Number = (m.height * c - m.width * s) / denominator;
if (traceSize) { trace([ "method 2", w, h ]); }
}
// the "getBounds" method
function method3( m:MovieClip, traceSize:Boolean ) {
var r:Rectangle = m.getBounds(m);
var w:Number = r.width*m.scaleX;
var h:Number = r.height*m.scaleY;
if (traceSize) { trace([ "method 3", w, h ]); }
}
And my output:
method 1,37.7,19.75
Elapsed time,1416
method 2,37.74191378925391,19.608455916982187
Elapsed time,1703
method 3,37.7145,19.768000000000004
Elapsed time,1589
Surprising, eh? But there's an important lesson here about Flash development. I hereby christen Fen's Law of Flash Laziness:
Whenever possible, avoid tricky math by getting the renderer to do it for you.
It not only gets you done quicker, in my experience it usually results in a performance win anyway. Happy optimizing!