Как получить неповернутую ширину/высоту экранного объекта повернутого экранного объекта?

Если я создаю прямоугольник с 100 пкс шириной и 100 пкс высотой и затем поворачиваю его, размер "поля" элемента увеличится.

С 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;

Конечно, должен быть лучший и более эффективный путь. Как я должен получить "нормализованную" ширину и высоту displayobject, иначе размер, когда это не было повернуто?

5
задан Tom 31 January 2010 в 19:58
поделиться

3 ответа

Наилучшим подходом, вероятно, было бы использовать код, помещенный в вопрос, т.е. отменить поворот объекта, проверить его ширину, а затем повторно повернуть его. Вот почему.

Во-первых, простота . Очевидно, что делается и почему это работает. У любого, кто придет позже, не должно быть проблем с пониманием.

Во-вторых, точность . Из любопытства я закодировал все три предложения в настоящее время в этом потоке, и я не был действительно удивлен, обнаружив, что для произвольно масштабированного объекта, они дают три немного разные ответы. Причина этого, в двух словах, заключается в том, что внутренние элементы визуализации 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 ]); }
}

И мой вывод:

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

Удивительно, а? Но здесь есть важный урок о разработке Flash. Я нарисую Закон Флэш Лень Фена:

По возможности избегайте сложной математики, заставляя рендера делать это за вас.

Это не только делает вас быстрее, по моему опыту, это обычно приводит к выигрышу производительности в любом случае. Рад оптимизации!

12
ответ дан 18 December 2019 в 07:08
поделиться

Вы должны получить границы вашего квадрата в координатном пространстве вашего объекта (что означает отсутствие вращений).

например,

var b:Sprite = new Sprite();
b.graphics.lineStyle(0.1);
b.graphics.drawRect(0,0,100,100);
b.rotation = 10;
trace('global coordinate bounds: ' + b.getBounds(this));//prints global coordinate bounds: (x=-17.35, y=0, w=115.85, h=115.85);
trace('local coordinate bounds: ' + b.getBounds(b));//prints local coordinate bounds: (x=0, y=0, w=100, h=100)

HTH, Джордж

3
ответ дан 18 December 2019 в 07:08
поделиться

Вот алгоритмический подход и его вывод.

Во-первых, давайте решим противоположную задачу: для прямоугольника без вращения ширина 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 , каковы ширина и высота без поворота?

Нам нужно решить приведенные выше уравнения для h и w . Пусть c представляет абс (cos ( r )), а s представляет абс (sin ( r )). Если мои ржавые навыки алгебры все еще работают, то приведенные выше уравнения можно решить с помощью:

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

7
ответ дан 18 December 2019 в 07:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: