Провести линию от точки к противоположным касательным по кругу?Форма конуса / клина в AS3 - PullRequest
8 голосов
/ 16 апреля 2011

Это должна быть простая геометрия: как рассчитать точки для рисования линий в приведенном ниже коде, чтобы получить 2D-конус или форму клина?

import flash.geom.Point;

//draw circle
var mc=new Sprite()
mc.graphics.lineStyle(0,0)
mc.graphics.drawCircle(0,0,30)
mc.x=mc.y=Math.random()*300+100
addChild(mc)

//draw lines:
graphics.lineStyle(0,0)
var p=new Point(Math.random()*500,Math.random()*400)
graphics.moveTo(p.x, p.y)
graphics.lineTo(mc.x,mc.y) // << should be point on edge of circle
graphics.moveTo(p.x, p.y)
graphics.lineTo(mc.x,mc.y) // << should be point on opposite edge of circle

ОБНОВЛЕНИЕ:
Спасибо, ребята, я должен был упомянуть, что моя цель не нарисовать форму клина, а нарисовать линию от случайной точки до края существующего круга.

Если вам удобнее с алгеброй, чемActionscript, может, вы могли бы взглянуть на этот рисунок и опубликовать формулу для меняtangents

Ответы [ 5 ]

2 голосов
/ 16 апреля 2011

Ваш вопрос о теореме Фалеса (см. http://en.wikipedia.org/wiki/Thales%27_theorem).

Ниже приведена немного измененная теорема для работы с AS3.

import flash.geom.Point;

// The radius of the circle
var r1:Number = 30;
// The center point of the circle
var cp:Number = Math.random() * 300+100;
var c:Point = new Point(cp, cp);

// draw circle
var mc=new Sprite();
mc.graphics.lineStyle(0,0);
mc.graphics.drawCircle(0,0,r1);
mc.x = mc.y = cp;
addChild(mc);

// The point
var p = new Point(Math.random() * 500, Math.random() * 400);

// Calculate points for intesecting circle
var c2:Point = Point.interpolate(c, p, 0.5);
var r2:Number = Point.distance(c2, c);
var d:Number = Point.distance(c, c2);

// Remove comment below to see intersecting circle
//graphics.beginFill(0xFF0000, 0.25);
//graphics.drawCircle(c2.x, c2.y, r2);

var a:Number = (r1*r1 - r2*r2 + d*d) / (2*d);
var p2x:Number = c.x + a * ( c2.x - c.x ) / d;
var p2y:Number = c.y + a * ( c2.y - c.y ) / d;
var h:Number = Math.sqrt(r1*r1 - a*a);

var d1x:Number = p2x + h * ( c2.y - c.y ) / d;
var d1y:Number = p2y - h * ( c2.x - c.x ) / d;
var d2x:Number = p2x - h * ( c2.y - c.y ) / d;
var d2y:Number = p2y + h * ( c2.x - c.x ) / d;

// Draw lines
graphics.lineStyle(1, 0xFF00FF, 0.5);
graphics.moveTo(p.x, p.y);
graphics.lineTo(d1x, d1y);
graphics.moveTo(p.x, p.y);
graphics.lineTo(d2x, d2y);

Конечный продукт:

enter image description here

С нарисованным вторым кругом (на самом деле вам не нужно рисовать во втором круге, вам просто нужны его центральная точка и радиус)

enter image description here

Извлеките следующий SWF-файл, чтобы увидеть его в действии (обновите, чтобы увидеть разные случайные круги):

http://megaswf.com/serve/1097652

1 голос
/ 16 апреля 2011

Пусть (xP, yP) будет пересечением касательных, (xC,yY) будет центром круга, где вы ищите координаты (xT,yT) точек касания.Далее, пусть T будет вектором касательной, а R будет вектором радиуса.Поскольку они перпендикулярны, у вас есть R . T = 0.

Это дает нам

(xT-xC,yT-yC) . (xT-xP, yT-yP) = 0

Пусть r - радиус круга, и пусть x:=xT-xC, y:=yT-yC, xp:=xP-xC, yp:=yP-yC(в основном, мы перемещаем круг в (0,0)).Точка касания находится на круге, поэтому у вас есть x²+y²=r² и, следовательно, также y=sqrt(r²-x²).

Подстановка переменной, примененная к приведенному выше уравнению, дает нам:

(x,y) . (x-xp, y-yp) = 0
x²-xp*x + y²-yp*y = 0

Использование кругаинформация, которую мы имеем:

r² -xp*x - yp*sqrt(r²-x²) = 0
r² -xp*x = yp*sqrt(r²-x²)
r^4 - 2*r²*xp*x + xp²*x² = yp²*(r²-x²)
(yp²+xp²)*x² - 2*r²*xp*x + r^4-yp²*r² = 0

now let a:=yp²+xp², b:=2*r²*xp, c:= (r²-yp²)*r²
=> ax² + bx + c = 0

Это квадратное уравнение с 0, 1 или 2 решениями.0, если P равно в круге, 1, если P равно на круге и 2, если P равно вне круга.

Я не буду помещать здесь явное решение, так как это адская формула, и ее гораздо проще написать, если вы сопоставите введенные здесь переменные с переменными в вашем коде как:

var sq:Function = function (f:Number) { return f*f; }, sqrt:Function = Math.sqrt;
var xp:Number = xP-xC, yp:Number = yP-yC,
    a:Number = sq(xp)+sq(yp), b:Number = 2*sq(r)*xp, c:Number = sq(r)*(sq(r)-sq(yp));
var x1:Number = (-b+sqrt(sq(b)-4*a*c)) / (2 * a),
    x2:Number = (-b+sqrt(sq(b)-4*a*c)) / (2 * a);
if (isNan(x1)) return [];
var p1:Point = new Point(x1+cX, sqrt(sq(r)-sq(x1))+cY),//calculate y and undo shift
    p2:Point = new Point(x2+cX, sqrt(sq(r)-sq(x2))+cY);
return p1.equals(p2) ? [p1] : [p1, p2];

Bestудачи в этом, потому что я очень плохо разбираюсь, плюс здесь 04:00, так что вы можете поспорить, где-то есть ошибка, но это должно привести вас в правильном направлении;)

1 голос
/ 16 апреля 2011

Обозначим вашу точку как P, центр круга как M, а точку касания на круге как X. Треугольник PMT - это прямоугольный треугольник. Возможно, вы захотите набросать это на бумаге, когда будете проходить через него, чтобы было легче следить за ним.

Положение X - это просто положение M плюс радиальный вектор к X, то есть к краю MX. Расчет тогда о вычислении вектора MX.

Вектор MX можно разложить на две перпендикулярные составляющие. Тот, который параллелен MP, и тот, который перпендикулярен MP. Первое, что нужно сделать, это получить единичные векторы в этих двух направлениях. Первое легко, поскольку это просто нормализованная версия MP. Перпендикулярный вектор к этому легко получить в 2D, поменяв местами компоненты и отрицая один компонент. Какой компонент вы отрицаете, здесь не имеет значения, поскольку в конечном итоге вам нужны обе касательные линии.

Теперь, когда у нас есть два единичных вектора, нам нужно выяснить, сколько каждого из них требуется для создания радиального вектора MX. Обозначая угол PMX через тета, мы имеем из простых прямоугольных треугольников, которые cos (theta) = r / | MP | где r - радиус вашего круга и | MP | это длина MP (которую вы уже рассчитали, чтобы получить свой вектор единиц выше).

Отбрасывание перпендикуляра от X к MP дает еще один прямоугольный треугольник, включающий тэту, противоположные и смежные стороны которого представляют две нужные нам компоненты. Длины этих сторон просто r * cos (тета) в направлении MP и r * sin (тета) в перпендикулярном направлении.

Итак, ваш окончательный результат по сути

X = M + r * cos (тета) * unit_MP + r * sin (тета) * unit_MP_perp_1

для одной из касательных точек и

X = M + r * cos (тета) * unit_MP + r * sin (тета) * unit_MP_perp_2

для других. Unit_MP и unit_MP_perp_1 / 2 - это векторы модулей, которые мы разработали ранее. Версия вектора perp 1/2 соответствует отрицанию первого или второго компонентов после обмена.

Редактировать

В терминах диаграммы, которую вы добавили, уравнение становится

x1 = cx + R * cos (тета) * Ux + R * sin (тета) * U1x
y1 = cy + R * cos (тета) * Uy + R * sin (тета) * U1y

с аналогичными уравнениями (x2, y2). В этих уравнениях

cos (theta) = r / D
грех (тета) = A / D

где D = sqrt ((px - cx) ^ 2 + (py - cy) ^ 2)

и

Ux = (px -cx) / D
Uy = (py -cy) / D

и так

U1x = -Uy
U1y = Ux

Перпендикулярный единичный вектор для другой точки касания будет

U2x = Uy
U2y = -Ux

0 голосов
/ 16 апреля 2011

Вот фрагмент для рисования 2D-формы клина. Вы можете настроить переменные startAngle и angle, чтобы контролировать угол клина. Радиус будет определять ширину формы. Это следует использовать в Shape, Sprite, MovieClip или в каком-либо подклассе с графическим объектом.

var i:int;
var p:Point = new Point();
var g:Graphics = graphics;
var radius:Number = 100;
var startAngle:Number = 130;
var angle:Number = 280;
var segments:Number = 40;
var degrees:Number = ( startAngle + ( angle - startAngle ) ) / segments;

g.beginFill( 0xFF0000, 1 );
for( i = 0; i <= segments; i++ ) 
{
    p.x = Math.cos( ( ( degrees * i ) + startAngle ) * Math.PI / 180 ) * radius;
    p.y = Math.sin( ( ( degrees * i ) + startAngle ) * Math.PI / 180 ) * radius;
    g.lineTo( p.x, p.y );
}
g.endFill();
0 голосов
/ 16 апреля 2011

graphics.curveTo(controlX,ControlY,endX,endY);

Рисует Безье между текущей точкой и концом (x, y) с элементом управления (x, y), являющимся точкой, к которой согнута кривая (подобно инструменту пера в Photoshop). Установите половину дельты X и используйте Y, чтобы отрегулировать его силу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...