如何获得旋转显示对象的未旋转显示对象宽度/高度?

Tom*_*Tom 5 algorithm math size rotation actionscript-3

如果我创建一个宽度为100px且高度为100px的矩形然后旋转它,则元素"box"的大小将会增加.

旋转45度,大小约为143x143(从100x100).

有时做cos(angleRad) * currentWidth似乎适合45转,但对于其他更大的角度它不会.

目前我这样做:

var currentRotation = object.rotation;
object.rotation = 0;
var normalizedWidth = object.width;
var normalizedHeight = object.height;
object.rotation = currentRotation;
Run Code Online (Sandbox Code Playgroud)

当然,必须有一种更好,更有效的方式.我应该如何获得显示对象的"标准化"宽度和高度,即未旋转时的尺寸?

fen*_*mas 12

最好的方法可能是使用问题中张贴的代码 - 即取消旋转对象,检查其宽度,然后重新旋转它.这就是原因.

首先,简单.很明显正在做什么,为什么它有效.任何后来出席的人都应该毫不费力地理解它.

第二,准确性.出于好奇,我编写了当前这个帖子中的所有三个建议,并且我发现对于任意缩放的对象,他们给出了三个稍微不同的答案,我并不感到惊讶.这样做的原因,简而言之,就是Flash的渲染内部被高度优化,以及除其他事项外,widthheight没有为彩车内部存储.它们被存储为地面上的"缇"(二十分之一像素),进一步的精确度在视觉上是无关紧要的.

无论如何,如果这三种方法给出不同的答案,哪个最准确?对于我的钱,最正确的答案是Flash认为对象的宽度是什么时候它没有旋转,这就是简单的方法给我们的.此外,这种方法是唯一一个总是将答案舍入到最接近的1/20的方法,我猜测(虽然我猜测)意味着它可能等于内部存储的值,而不是计算值.

最后,速度.我认为这会让你感到惊讶,但是当我编写这三种方法时,简单的方法是最快的.(不要过多地阅读它们 - 它们都非常接近,如果你调整我的代码,一个不同的方法可能会占据领先地位.重点是它们非常可比.)

您可能希望简单的方法更慢,理由是更改对象的旋转会导致许多其他事情被重新计算,从而产生开销.但是当您更改旋转时,所有真正发生的事情是对象的变换矩阵获得一些新值.在下次在屏幕上绘制对象之前,Flash对该矩阵的作用并不大.至于当你读取对象的宽度/高度时会发生什么数学,很难说.但值得注意的是,简单方法中发生的任何数学都是由玩家大量优化的内部结构完成的,而不是像代数方法那样在AS3中完成.

无论如何,我邀请你试用示例代码,我想你会发现简单直接的方法至少不比其他方法慢.这加上简单使它成为我的选择.


这是我使用的代码:

// 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 ]); }
}
Run Code Online (Sandbox Code Playgroud)

我的输出:

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
Run Code Online (Sandbox Code Playgroud)

令人惊讶,是吗?但是这里有一个关于Flash开发的重要教训.我特此命名芬的闪光懒惰定律:

只要有可能,通过让渲染器为您执行此操作来避免棘手的数学运算.

它不仅可以让您更快地完成任务,根据我的经验,它通常会导致性能获胜.快乐优化!


Chi*_*Uni 7

这是算法方法及其推导.

首先,让我们做相反的问题:给定一个未旋转宽度w的矩形,未旋转的高度h和旋转r,旋转的宽度和高度是多少?

w r = abs(sin(r))*h + abs(cos(r))*w
h r = abs(sin(r))*w + abs(cos(r))*h

现在,尝试给出的问题:给定一个旋转宽度为w r,旋转高度h r和旋转r的矩形,未旋转的宽度和高度是多少?

我们需要为hw求解上述等式.设c代表abs(cos(r)),s代表abs(sin(r)).如果我的生锈代数技能仍然有效,那么上述方程可以用以下方法解决:

w =(w r*c - h r*s)/(c 2 - s 2)
h =(h r*c - w r*s)/(c 2 - s 2)