Форум 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=206358)

vorodis2 30.01.2014 00:41

окружность вписанная в эллипс?
 
Есть эллипс, в него вписан круг, круг таскается мышкой, круг не должен вылазить за пределы эллипса. http://prntscr.com/2npnz9
Может кто за делиться кодом, либо хорошей ссылке по теме.

GBee 30.01.2014 01:25

http://ru.wikipedia.org/wiki/%DD%EB%EB%E8%EF%F1 :о)

Добавлено через 9 минут
Я бы попробовал так. Из центра эллипса вектор в центр окружности, находим радиус эллипса через этот вектор. Если радиус эллипса больше, чем длина отрезка между центрами сущностей + радиус окружности, то все ок.
Но думаю, бывалые скажут лучше.

Akopalipsis 30.01.2014 01:36

Меня с недавнего времени волнует тема с пересечениями и мне хочется спросить, чтобы, как многие говорят, не выдумывать велосипеды - есть ли смысл в проверки на принадлежность точки фигуре или, как в данном случаи, проверка на вписанность, прибегать к геометрии? Или проще и менее затратно работать с BMD и проверять по пикселям?

Добавлено через 1 минуту
В жизни Вам вообще эти алгоритмы помогали? Или в жизни, когда делаешь что-то большое, не пользуешься самописными проверками?)

Aquahawk 30.01.2014 01:38

Нормальная геометрия почти всегда быстрее и точнее. Это задача должны быть очень изощрённой чтобы по пикселям было быстрее.

vorodis2 30.01.2014 01:54

GBee
Спасибо, звучит очень хорошо, но что то сейчас не особо могу переварить, с утра за компом. А с математикой/геометрией сейчас голова отказываеться работать)) Мне бы кода))

Да и как я понял у меня задача усложнилась, когда я сделал ограничения на коробку http://prntscr.com/2nqhsy то есть в дебаг не эллипс а прямоугольник, мне стало понятно, что когда вожу мышь за пределами допустимой области, то мне надо что бы кружок двигался по максимальной допустимой границы эллипса.

Akopalipsis 30.01.2014 01:59

Aquahawk Спасибо! Вы вроде не чего не сказали, а даже представить не можете, как мне помогли.

Wolsh 30.01.2014 06:07

Вложений: 1
GBee, это в окружности любая прямая, проходящая через центр, перпендикулярна окружности. В эллипсе — только оси. Так что придется искать перпендикуляр (кратчайшее расстояние) из центра окружности к дуге эллипса и сверять его с радиусом окружности.

Вложение 30421

GBee 30.01.2014 09:59

Wolsh, я же в голове рисовал :D

bav 30.01.2014 10:12

Можно решить систему уравнений окружности и эллипса, если все корни комплексные, значит окружность не пересекает эллипс. Вот примеры для наглядности:
1) Пересечение в четырех точках (4 вещественных корня)
2) Пересечение в двух точках (2 вещественных корня)
3) Еще раз пересечение в двух точках (2 вещественных + 2 комплексных корня)
4) Нет пересечения (4 комплексных корня)
5) Еще раз нет пересечения (4 комплексных корня)
6) Одна точка пересечения (1 вещественный + 2 комплексных корня)

KumoKairo 30.01.2014 11:25

Вложений: 1
А у меня другая идея - уменьшить оба радиуса эллипса (обе полуоси) на радиус окружности и вычислять радиус в точке, в которой находится центр круга по формуле
Вложение 30424
Если расстояние до центра эллипса меньше, чем вычисленное значение радиуса, то круг внутри эллипса

a и b - это большая и малая полуось эллипса. угол фи находится через арктангенс координат центра круга, функция Math.atan2()

Я правда не знаю точно, приведет ли уменьшение полуосей эллипса на радиус к тому, что круг будет всегда внутри эллипса, но по идее должно работать.

Если поворачивать эллипс, то можно заперентить его на какой нибудь ДО, и повернуть родительский ДО. Тогда дочерние ДО (эллипс и круг) будут иметь локальные координаты, как будто горизонтально, без поворота

Плюсы - быстро, модно, молодежно, без уравнений и корней
Минусы - при повороте эллипса придется либо формулы менять, либо вешать внутрь какого-либо родительского ДО для поворота этого родительского ДО

--UPD
Или стоп, можно изначально не уменьшать полуоси, а потом после вычисления радиуса по формуле вычесть из него. Вот тогда точно будет работать

Korchy 30.01.2014 11:29

Практически ваша задача
http://www.gamedev.ru/code/forum/?id=72507

silin 30.01.2014 12:03

если устроит не совсем элипс, а скорее овал из кривых, то с помощью безьевых утилит Дембицкого можно
Код AS3:

package
{
        import flash.display.Graphics;
        import flash.display.Shape;
        import flash.display.Sprite;
        import flash.events.MouseEvent;
        import flash.geom.Bezier;
        import flash.geom.Point;
 
 
        public class Main extends Sprite
        {
                private var ball:Circle = new Circle(30);
                private var segments:Array = [];
                private var cX:Number = 300;
                private var cY:Number = 300;
                private var rX:Number = 200;
                private var rY:Number = 100;
 
 
                private var mX:Number;
                private var mY:Number;
 
                public function Main():void
                {
 
                        ball.x = cX;
                        ball.y = cY;
                        addChild(ball);
 
                        graphics.lineStyle(2);
 
                        // типа 'элипс' из четырех безье
                        for (var i:int = 0; i < 4; i++)
                        {
                                var a:Number = Math.PI * i / 2;
 
                                var sP:Point = new Point(cX + Math.cos(a) * rX, cY + Math.sin(a) * rY);
                                a += 0.5 * Math.PI;
                                var eP:Point = new Point(cX + Math.cos(a) * rX, cY + Math.sin(a) * rY);
                                var cP:Point = i % 2 ? new Point(eP.x, sP.y) : new Point(sP.x, eP.y);
                                var segm:Bezier = new Bezier(sP, cP, eP);
                                segments.push(segm);
 
                                if (!i) graphics.moveTo(sP.x, sP.y);
                                graphics..curveTo(cP.x, cP.y, eP.x, eP.y);
 
                        }
 
                        ball.addEventListener(MouseEvent.MOUSE_DOWN, ball_mouseDown);
 
                }
 
                private function ball_mouseDown(e:MouseEvent):void
                {
                        mX = stage.mouseX;
                        mY = stage.mouseY;
                        stage.addEventListener(MouseEvent.MOUSE_UP, stage_mouseUp);
                        stage.addEventListener(MouseEvent.MOUSE_MOVE, stage_mouseMove);
 
                }
 
                private function stage_mouseUp(e:MouseEvent):void
                {
                        stage.removeEventListener(MouseEvent.MOUSE_UP, stage_mouseUp);
                        stage.removeEventListener(MouseEvent.MOUSE_MOVE, stage_mouseMove);
                }
 
                private function stage_mouseMove(e:MouseEvent):void
                {
                        // двигаем
                        ball.x += stage.mouseX - mX;
                        ball.y += stage.mouseY - mY;
                        mX = stage.mouseX;
                        mY = stage.mouseY;
 
 
                        // проверка и коррекция
                        var dir:Number = Math.PI + Math.atan2(cY - ball.y, cX - ball.x);
                        var segm:Bezier = segments[Math.floor(2 * dir / Math.PI) % 4];
 
                        var t:Number = segm.getClosest(new Point(ball.x, ball.y));
                        var tP:Point = segm.getPoint(t);
 
                        if (Point.distance(new Point(ball.x, ball.y), tP) < ball.radius)
                        {
                                dir = Math.atan2(tP.y - ball.y, tP.x - ball.x);
                                ball.x = tP.x - ball.radius * Math.cos(dir);
                                ball.y = tP.y - ball.radius * Math.sin(dir);
                        }
                }
 
        }
 
}
 
import flash.display.Sprite;
 
class Circle extends Sprite
{
 
        public var radius:Number;
 
        public function Circle(r:Number)
        {
                super();
                radius = r;
                graphics.beginFill(0x808080);
                graphics.drawCircle(0, 0, r);
 
        }
}

Добавлено через 35 минут
а можно и не связываться с безье, а строить просто отрезками и брать ближайший по наименьшему расстоянию, тогда и эллипс будет как эллипс
Код AS3:

package
{
        import flash.display.Graphics;
        import flash.display.Shape;
        import flash.display.Sprite;
        import flash.events.MouseEvent;
 
        import flash.geom.Point;
 
 
        public class Main extends Sprite
        {
                private var ball:Circle = new Circle(30);
                private var segments:Array = [];
                private var cX:Number = 300;
                private var cY:Number = 300;
                private var rX:Number = 200;
                private var rY:Number = 100;
 
                private var mX:Number;
                private var mY:Number;
 
                public function Main():void
                {
 
                        ball.x = cX;
                        ball.y = cY;
                        addChild(ball);
 
                        graphics.lineStyle(2);
 
                        // элипс из отрезков
                        var n:Number = 60;
                        var dA:Number = 2 * Math.PI / n;
                        var a:Number = 0;
                        for (var i:int = 0; i < n; i++)
                        {
 
                                var sP:Point = new Point(cX + Math.cos(a) * rX, cY + Math.sin(a) * rY);
                                a += dA;
                                var eP:Point = new Point(cX + Math.cos(a) * rX, cY + Math.sin(a) * rY);
                                var mid:Point = Point.interpolate(sP, eP, 0.5);
 
                                segments.push(mid);
 
                                if (!i) graphics.moveTo(sP.x, sP.y);
                                graphics.lineTo(eP.x, eP.y);
 
                        }
 
                        ball.addEventListener(MouseEvent.MOUSE_DOWN, ball_mouseDown);
 
                }
 
                private function ball_mouseDown(e:MouseEvent):void
                {
                        mX = stage.mouseX;
                        mY = stage.mouseY;
                        stage.addEventListener(MouseEvent.MOUSE_UP, stage_mouseUp);
                        stage.addEventListener(MouseEvent.MOUSE_MOVE, stage_mouseMove);
 
                }
 
                private function stage_mouseUp(e:MouseEvent):void
                {
                        stage.removeEventListener(MouseEvent.MOUSE_UP, stage_mouseUp);
                        stage.removeEventListener(MouseEvent.MOUSE_MOVE, stage_mouseMove);
                }
 
                private function stage_mouseMove(e:MouseEvent):void
                {
                        // двигаем
                        ball.x += stage.mouseX - mX;
                        ball.y += stage.mouseY - mY;
                        mX = stage.mouseX;
                        mY = stage.mouseY;
 
                        // проверка и коррекция
                        var tP:Point;
                        var min:Number = Number.MAX_VALUE;
                        for (var i:int = 0; i < segments.length; i++)
                        {
                                var d:Number = Point.distance(new Point(ball.x, ball.y), segments[i]);
                                if ( d< min)
                                {
                                        tP = segments[i];
                                        min = d;
                                }
                        }
 
                        var dir:Number = Math.PI + Math.atan2(cY - ball.y, cX - ball.x);
                        if (Point.distance(new Point(ball.x, ball.y), tP) < ball.radius)
                        {
                                dir = Math.atan2(tP.y - ball.y, tP.x - ball.x);
                                ball.x = tP.x - ball.radius * Math.cos(dir);
                                ball.y = tP.y - ball.radius * Math.sin(dir);
                        }
                }
 
        }
 
}
 
import flash.display.Sprite;
 
class Circle extends Sprite
{
 
        public var radius:Number;
 
        public function Circle(r:Number)
        {
                super();
                radius = r;
                graphics.beginFill(0x808080);
                graphics.drawCircle(0, 0, r);
 
        }
}


vorodis2 30.01.2014 21:42

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

Котяра 31.01.2014 02:45

Цитата:

stage_mouseMove
интересная конвенция..
это сам придумал или есть где?
по стандартной
Код AS3:

stage_mouseMoveHandler

но мне очень нравится
onStage_mouseMove

MikroAcse 31.01.2014 02:51

Цитата:

stage_mouseMoveHandler
Как по мне:
1. Зачем "_" в названиях функций? Очень некрасиво.
2. Лишний постфикс "Handler" к каждому хендлеру?
Это то же самое, что и писать:
Код AS3:

var myNumber:Number;

Я пишу onObjectEvent, и настроил это в FD, например:
Код AS3:

function onStageMouseMove()

Ничего лишнего.

Но это всё ИМХО. Не стоит спорить по этому поводу :)

silin 31.01.2014 09:47

Цитата:

Сообщение от Котяра (Сообщение 1158525)
интересная конвенция..
это сам придумал или есть где?
по стандартной
Код AS3:

stage_mouseMoveHandler

но мне очень нравится
onStage_mouseMove

target_eventName - привычная для C#, во всяком случае VS такие генерит по умолчанию

vorodis2 02.02.2014 21:27

Во как получилось
http://vorodis2.com/test/debagElips/
Изюминка в том что надо было искать не край а центр, эллипса меньше на радиус круга. Правда при плоских эллипсах немного круг вылазит, но для моей задачи это не критично.

Кому надо, вот исходник.
http://vorodis2.com/test/debagElips/debagElips.rar

KumoKairo 02.02.2014 22:16

Выбрали мой метод! Урещщии!


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

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