Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Поворот объекта вокруг точки с помощью тригонометрических функций (http://www.flasher.ru/forum/showthread.php?t=175235)

Den_root 13.02.2012 01:00

Поворот объекта вокруг точки с помощью тригонометрических функций
 
Господа, есть ли способ повернуть объект с помощью свойства rotation, а затем вычислить его х и у координаты как будто бы он был повернут вокруг какой то точки?

Wolsh 13.02.2012 01:23

http://flasher.ru/forum/blog.php?b=378

Den_root 13.02.2012 01:58

Цитата:

Сообщение от Wolsh (Сообщение 1062451)

Не, там предлагаются матрицы и какой то совершенно костыльный способ, а без них можно обойтись?

Wolsh 13.02.2012 02:46

А так?
http://flasher.ru/forum/showthread.php?t=152684

Добавлено через 8 минут
http://flasher.ru/forum/showthread.php?t=146622

Den_root 14.02.2012 22:30

Использовал вашу функцию из второй темы- увы но при множественном вращении объект постепенно смещается к точке вращения. С матрицами - погрешности, без них - тоже. Это заговор какой то! :D
Код AS3:

public static function pointRotate (object:DisplayObject, center:Point, angle:Number) : void
                {
                var r:Number = angle * Math.PI / 180;
                var s:Number = Math.sin(r);
                var c:Number = Math.cos(r);
                var dX:Number = object.x - center.x;
                var dY:Number = object.y - center.y;
 
 
 
                object.rotation += angle;
                object.x = center.x + dX * c - dY * s;
                object.y = center.y + dX * s + dY * c;
                }


Wolsh 14.02.2012 23:03

Нет, почему заговор)) Там такой алгоритм, она не для множественного вращения, а для одного поворота. Перед другим поворотом надо возвращать (в первой теме, про "центр", та же история была - просто я писал эти функции для проекта, где нужно было вот так)) Для динамического поворота надо возвращать объект обратно и задавать новый угол. Возврат в дефолт как раз добавлен в теме про центральное вращение. Ну объедините как-нибудь)))

Добавлено через 6 минут
Вы происходящее представьте? Когда объект уже смещен и повернут, а Вы пытаетесь его снова повернуть вокруг той же точки – для него эта точка уже в другом месте, его система координат повернута и смещена относительно той точки.

Den_root 15.02.2012 00:12

То есть если:
1. Создали объект
2. Повернули его
3.Переместили его в точку Х
Для корректного вращения нужно:
1.Обнулить вращение
2.Переместить объект в кординаты на момент создания
3.Повернуть на новый, желаемый угол
4. Вернуть его в точку Х

Я вас правильно понял?

TanaTiX 15.02.2012 00:26

Цитата:

Честно говорю - выйдет что-то ужасное
Есть более достойная альтернатива помимо уже озвученных? С удовольствием взглянул бы на реализацию.

Wolsh 15.02.2012 00:28

Цитата:

4. Вернуть его в точку Х
Нет. Переместить в новую точку, естественно.

PlutDem 15.02.2012 01:04

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

-De- 15.02.2012 01:08

Ну в общем да, заговор, это твипсы. Т.е. реально object.x вы знаете с точностью до 0.05 только. Решение - хранить параллельно Point или что-то подобное, где будет более точное значение. Тут пацаны говорят что что-то куда-то возвращать надо, я этого не понял и у меня работает и так %) Я и собсно смещения не видел, если честно %) Но теоретически может быть вполне =) ну вот крутится, чо
Код AS3:

//если этот код кого-то научит плохому, то я не виноват. Нервных также просьба не читать.
public var spr:Sprite;
                public function Main():void
                {
                        //if (stage) init();
                        //else addEventListener(Event.ADDED_TO_STAGE, init);
 
                        //var obj:Object = { s:new Sprite(), coords:new Point() };
                        spr = new Sprite();
 
                        spr.graphics.lineStyle(0);
                        spr.graphics.drawEllipse( -10, -5, 20, 10);
 
                        spr.x = 100;
                        spr.y = 100;
                        addChild(spr);
 
 
                        addEventListener(Event.ENTER_FRAME, up);
                }
 
                public function up(e:Event):void {
                        pointRotate(spr, new Point(150, 250), 5.12345);
                }
 
                public static function pointRotate (object:DisplayObject, center:Point, angle:Number) : void
                {
                var r:Number = angle * Math.PI / 180;
                var s:Number = Math.sin(r);
                var c:Number = Math.cos(r);
                var dX:Number = object.x - center.x;
                var dY:Number = object.y - center.y;
 
 
                var rotDiff:Number = object.rotation;
                object.rotation += angle;
                rotDiff = object.rotation - rotDiff;
                object.x = center.x + dX * c - dY * s;
                object.y = center.y + dX * s + dY * c;
                trace(object.x, center.x + dX * c - dY * s);//feel the difference
                }

UPD: а, это наверное вечная тема про "смещение точки регистрации". Я бы использовал доп. матрицу, которая задает новую систему координат. Это в некотором роде аналог вставки во внешний контейнер. Ладно, раз влез блин, то вот...
Код AS3:

public var spr:Sprite;
                public var mInner:Matrix = new Matrix();//это наши внутренние координаты
                public var mOuter:Matrix = new Matrix();//это наши внешние координаты
                public function Main():void
                {
 
                        graphics.lineStyle(0);
                        graphics.drawCircle(200, 100, 0.5);//чтоб видеть вокруг чего крутимся
 
                        spr = new Sprite();
                        spr.graphics.lineStyle(0);
                        spr.graphics.drawEllipse( -10, -5, 20, 10);//точка регистрации в центре эллипса
 
                        spr.x = 200 - 10;
                        spr.y = 100 - 5;
                        addChild(spr);
 
                        mOuter = spr.transform.matrix;//изначально mOuter - трансформ обьекта, mInner - единичная
 
                        setRegPoint(200, 100);
 
                        //updateTransform();
 
                        addEventListener(Event.ENTER_FRAME, up);
                }
 
                public function setRegPoint(X:Number, Y:Number):void {//эта функция ставит опорку в нужную точку (графика при этом не смещается)
                        var dx:Number = X - mOuter.tx;
                        var dy:Number = Y - mOuter.ty;
                        var p:Point = new Point(dx, dy);
                        var m:Matrix = mOuter.clone();
                        m.invert();
                        m.tx = 0;
                        m.ty = 0;
                        p = m.transformPoint(p);
                        mInner.tx -= p.x;
                        mInner.ty -= p.y;
                        mOuter.tx = X;
                        mOuter.ty = Y;
                }
 
                public function updateTransform():void {//когда меняются матрицы надо вызвать эту функцию, чтоб она применила изменения к спрайту или что у вас там
                        var m:Matrix = mInner.clone();//лучше завести ещё одну постоянную матрицу, чтоб не выделять тут память динамически
                        m.concat(mOuter);
                        spr.transform.matrix = m;
                }
 
                public function up(e:Event):void {
                        pointRotate(5.12345);
                }
 
                public function pointRotate (angle:Number) : void
                {
                        angle *= Math.PI / 180;
                        var prevX:Number = mOuter.tx;
                        var prevY:Number = mOuter.ty;
                        mOuter.rotate(angle);
                        mOuter.tx = prevX;
                        mOuter.ty = prevY;//поворачиваем mOuter на angle не трогая её позицию
                        updateTransform();
                }


Den_root 15.02.2012 01:24

-De-
Как ни прискорбно, но смещение есть. Такое же как и в дрругих примерах.:(

Wolsh 15.02.2012 01:42

Я чето тоже не понял - rotDiff для чего, если он не используется в итоге?

expl 15.02.2012 01:43

Цитата:

Не, там предлагаются матрицы и какой то совершенно костыльный способ, а без них можно обойтись?
Хорошо, что Вас математики не слышат. Обозвать матрицы костылём!

Wolsh 15.02.2012 01:47

Здесь разделительное "и", если Вы не заметили. То есть матрицы И костыль – засовывание объекта в контейнер и поворот контейнера.

PlutDem 15.02.2012 22:58

-De- Сейчас если переместить объект, а потом повернуть, то он перемещается обратно в свои изначальные координаты. Можно ли этого избежать? Сейчас ваш способ ничем не отличается от №3+начальная матрица, только кода больше

-De- 15.02.2012 23:02

Чтобы переместить обьект надо сменить tx и/или ty у матрицы mOuter, а затем вызвать updateTransform(). Т.е. позиция обьекта - это не его x, y, а tx, ty матрицы mOuter. Наверное потому у вас возвращается.
№3 никак не меняет точку регистрации. Несколько разные задачи.

Wolsh 16.02.2012 00:22

Вложений: 1
Код AS3:

package  
{
    import flash.geom.Point;
    import flash.display.DisplayObject;
/* * * * * * * * * *
*                  *
*  @author wolsh  *
*                  *
\* * * * * * * * * */

 
    public function pointRotate(object:DisplayObject, center:Point, angle:Number) : void
    {
        // return to zero
        angle += object.rotation;
        var a0:Number = - object.rotation * Math.PI / 180;
        var s0:Number = Math.sin(a0);
        var c0:Number = Math.cos(a0);
        var dX0:Number = object.x - center.x;
        var dY0:Number = object.y - center.y;
 
        object.rotation = 0;
        object.x = Math.round(center.x + dX0 * c0 - dY0 * s0);
        object.y = Math.round(center.y + dX0 * s0 + dY0 * c0);
 
        // new rotation
        var r:Number = angle * Math.PI / 180;
        var s:Number = Math.sin(r);
        var c:Number = Math.cos(r);
        var dX:Number = object.x - center.x;
        var dY:Number = object.y - center.y;
 
        object.rotation += angle;
        object.x = center.x + dX * c - dY * s;
        object.y = center.y + dX * s + dY * c;
    }
 
}

CustomRotation.swf   (2.0 Кб)

Во вложении тестовая свфка просто.
Можно кликать и ставить точку, вокруг которой прямоугольник крутится.
Черная точка ставится в стейдже, а белая - внутри самого прямоугольника, чтобы наблюдать люфт.

TanaTiX 16.02.2012 00:34

Wolsh, можно создать простенькую игру - "Впиши вращающиеся фигуры в форму, меняя центр вращения/трансформаций";)

Wolsh 16.02.2012 00:35

да, я уже с полчасика поиграл)))

PlutDem 16.02.2012 00:56

Wolsh
Спасибо, добрый человек! А можно ли задавать точку вращения по локальной системе координат объекта, а то сейчас при при перемещении объекта точка, то на месте остается? Уже попробовал center = object.localToGlobal(center); и разумеется получил пресловутое смещение.:mad:

Wolsh 16.02.2012 01:03

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

PlutDem 16.02.2012 01:18

Wolsh
Нет, нет:) Перемещалась вместе с ним. Т.е. сейчас если поставить точку вращения в центр объекта, то он будет вращаться вокруг своего центра, а если его после этого переместить, то точка вращения будет уже не в центре объекта и , соответственно, вращаться он будет уже по другому.

Wolsh 16.02.2012 01:35

Вам надо поспать.
Поворот объекта вокруг точки это любое изменение положения объекта, при котором данная точка объекта не меняет своего положения.

PlutDem 16.02.2012 01:42

Wolsh
Так я же говорю не про вращение, а про перемещение объекта! Если объект переместить на новые координаты, а точка останется на прежнем месте, то ее положение относительно объекта измениться и вращение будет происходить уже по другому.

fish_r 16.02.2012 02:14

Если я правильно понял вам нужно положить вращающийся объект в контейнер, а потом уже перемещайте контейнер с объектом как душе угодно будет.

Wolsh 16.02.2012 07:11

PlutDem, так что Вам мешает-то прибавить одно и то же число к Х объекта и Х точки, Y объекта и Y точки?
fish_r, для этого обязательно нужен контейнер?))

fish_r 16.02.2012 14:17

Цитата:

Сообщение от Wolsh (Сообщение 1063278)
PlutDem, так что Вам мешает-то прибавить одно и то же число к Х объекта и Х точки, Y объекта и Y точки?
fish_r, для этого обязательно нужен контейнер?))

Да, а решение то простое ), не подумал.

PlutDem 04.03.2012 02:25

Wolsh
А зачем здесь использовать Math.round? У себя отключил, так как из за округления были проблемы, но черт его знает, может оно необходимо?
Код AS3:

object.x = Math.round(center.x + dX0 * c0 - dY0 * s0);
object.y = Math.round(center.y + dX0 * s0 + dY0 * c0);


Wolsh 04.03.2012 09:55

Разница безусловно есть, было бы терпение подождать. Но если у вас не критично, возникает ли люфт со временем (количеством) поворотов, то можете убрать – из-за необходимости обращения к Math здесь тратятся драгоценные миллисекунды.
MikroAcse Координаты на сцене округляются не до целых, и вкупе с погрешностями тригонометрии возникает накапливаемый люфт.
В данном месте делается попытка восстановить начальные координаты объекта, при его свойстве rotation, равном нулю. Предполагается, что его координаты были целыми.
Все это важно для множественных поворотов. Для одного-двух несущественно.

PlutDem 04.03.2012 17:20

Wolsh
Люфт? Что он из себя представляет? Вертел объект на 1 градус в цикле 360 000 раз и никакого изменения координат не было. Правда я храню координаты в отдельном Point и уже после всех манипуляций присваиваю его координаты объекту.

Wolsh 04.03.2012 19:51

Цитата:

Вертел объект на 1 градус в цикле 360 000 раз
В цикле? А при чем тут цикл? Покрути на 30° по ENTER_FRAME.
Надо было мне всетаки тест выложить, а не просто класс и SWF)) Скажем, если в этом тесте (SWF который я выложил) убрать из класса раунды, то через 2-5 секунд белая точка уползет из-под черной примерно на 5-10 пикселей.
Этот вопрос вообще такой неоднозначный оттого, что каждый тестит по-своему под свою задачу. Задачи действительно очень разные по смыслу. Кому-то надо один раз программно повернуть объект в момент отображения и так оставить. Кому-то надо постоянно крутить объект вокруг одной и той же точки, например стрелку часов. Кто-то представляет интерфейс как "rotation" а не "rotate", то есть считает удобным задать конечный угол "от нуля", а не "доворачивать" объект от его текущего состояния. Сажем, для инструмента в графическом редакторе, позволяющем поворачивать редактируемый объект относительно любой "центральной" точки (transformation point) необходим именно такой "доворот", поскольку он позволяет делать последовательное изменение положения и поворота относительно разных точек (см. SWF). Это наиболее общий по решаемой задаче код. Для конкретных ограниченных ситуаций он может быть сокращен и в три раза.

PlutDem 08.03.2012 13:42

После долгих раздумий решил вертеть так:
Код AS3:

public function objRotate(angle:Number) : void{
 
    var matrix:Matrix = bsMatrix.clone();
 
    matrix.translate( -objLocRotatingPoint.x, -objLocRotatingPoint.y );// смещаем начальную матрицу на локальные коордиаты
    matrix.rotate( (this.rotation+angle) * GL.RAD );// новое вращение = старое + доворот * Math.PI/180
    matrix.translate( objGlobRotatingPoint.x, objGlobRotatingPoint.y );//смещаем начальную матрицу на глобальные коордиаты
 
    this.transform.matrix = matrix;
}

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

Akopalipsis 15.01.2014 23:28

Вложений: 1
Целый день сегодня я пытался объяснить человеку, что мною позаимствованный в этой теме, код, работает без слётов, как часы. Но решив ускорить вращательный момент, чтобы приблизится к тому времени, по истечению которого, у человека, которому я пытался помочь, слетала картинка... И раз, она и вправду слетела. И теперь у меня точно такой же вопрос - правда чтоль не реально сделать вращение без слётов??)
Код использовал Wolsh'a.
rotate3.swf   (38.5 Кб)


Часовой пояс GMT +4, время: 05:37.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.