从一点到圆上的相对切线画一条线? AS3 中的圆锥/楔形

发布于 2024-11-01 20:41:08 字数 703 浏览 1 评论 0原文

这应该是一些简单的几何图形:如何计算在下面的代码中绘制线条的点,以便它形成 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

更新:
谢谢大家,我应该提到我的目标不是绘制楔形,而是从随机点到现有圆的边缘绘制一条线。

如果您对代数比对动作脚本更熟悉,也许您可​​以看看这个图形并为我发布一个公式? 切线

This should be a bit of simple geometry: How do I calculate the points to draw the lines in the code below so that it makes a 2D cone or wedge shape?

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

UPDATE:
Thanks guys, I should have mentioned my aim is not to draw a wedge shape, but to draw a line from a random point to the edge of an existing circle.

If you're more comfortable with algebra than actionscript, maybe you could have a look at this graphic and post a formula for me?
tangents

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

南街女流氓 2024-11-08 20:41:08

您的问题是关于泰勒斯定理(请参阅http://en.wikipedia.org/wiki/Thales% 27_定理)。

以下是稍加修改以适用于 AS3 的定理。

导入 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);

最终产品:

在此处输入图像描述

绘制第二个圆圈(实际上不需要在第二个圆圈中绘制) ,您只需要它的中心点和半径)

在此处输入图像描述

查看以下 SWF 以查看实际效果(刷新即可查看不同的随机圆圈):

http://megaswf.com/serve/1097652

Your question is about Thales theorem (see http://en.wikipedia.org/wiki/Thales%27_theorem).

The following is the theorem modified slightly to work with 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);

The final product:

enter image description here

With the second circle drawn (you don't actually need to draw in the second circle, you just need its center point and radius)

enter image description here

Checkout the following SWF to see in action (refresh to see different random circles):

http://megaswf.com/serve/1097652

痴梦一场 2024-11-08 20:41:08

(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 个解决方案。如果 P 在圆,则为 0;如果 P 在圆,则为 1;如果 P 在圆,则为 2。

我不会在这里给出明确的解决方案,因为它是一个非常糟糕的公式,并且如果您将此处引入的变量映射到代码中的变量,则编写起来会容易得多:

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

祝您好运,因为我非常糟糕微积分,再加上现在是 04:00,所以你可以打赌,某处有错误,但它应该会让你走向正确的方向;)

Let (xP, yP) be the intersection of the tangents, (xC,yY) be the center of the circle, where you are looking for the coordinates (xT,yT) of the tangent points. Further more let T be the vector of the tangent and R be the vector of the radius. Since they are perpendicular, you have R . T = 0.

This gives us

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

Let r be the radius of the circle and let x:=xT-xC, y:=yT-yC, xp:=xP-xC, yp:=yP-yC (basically, we move the circle into (0,0)).
The tangent point is on the circle, so you have x²+y²=r² and thus also y=sqrt(r²-x²).

The variable substitution applied to the above equation gives us:

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

Using the circle information we have:

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

This is a quadratic equation with 0, 1 or 2 solutions. 0, if P is in the circle, 1, if P is on the circle and 2, if P is outside the circle.

I won't put the explicit solution here, since it's a hell of a formula and it's a lot easier to write, if you map the variables introduced here to variables in your code as:

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 of luck with this, because I am very bad with calculus, plus it's 04:00 here, so you can bet, there's a mistake somewhere, but it should get you in the right direction ;)

孤独岁月 2024-11-08 20:41:08

将点表示为 P,圆心表示为 M,圆上的切点表示为 X。 三角形 PMT 是直角三角形。当你浏览它时,你可能想在纸上画出草图,以便更容易理解。

X的位置就是M的位置加上X的径向向量,即边MX。接下来的计算就是计算向量 MX。

向量 MX 可以分解为两个垂直分量。一种与 MP 平行,另一种与 MP 垂直。首先要做的是获得这两个方向的单位向量。第一个很简单,因为它只是 MP 的标准化版本。通过交换分量并取反一个分量,可以在 2D 中轻松获得与此垂直的向量。您否定哪个分量在这里无关紧要,因为您最终需要两条切线。

现在我们有了两个单位向量,我们需要计算出每个单位向量需要多少来创建径向向量 MX。用 theta 表示角度 PMX,我们可以从简单的直角三角形得到 cos(theta)=r/|MP|其中 r 是圆的半径,|MP|是 MP 的长度(您已经计算出上面的单位向量)。

从 X 到 MP 的垂线会得到另一个涉及 theta 的直角三角形,其对边和邻边代表我们想要的两个分量。这些边的长度在 MP 方向上为 r * cos(theta),在垂直方向上为 r * sin(theta)。

因此,您的最终结果本质上是

X = M + r * cos(theta) * unit_MP + r * sin(theta) * unit_MP_perp_1

对于切点之一,并且

X = M + r * cos(theta) * unit_MP + r * sin (theta) * unit_MP_perp_2

为另一个。 Unit_MP 和unit_MP_perp_1/2 是我们之前计算出的单位向量。 perp 向量的 1/2 版本对应于交换后对第一或第二分量取反。

编辑

根据您添加的图表,方程变为

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

具有类似的方程 (x2,y2)。在这些方程中

cos(theta) = r / D
sin(theta) = 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

Denote your point as P, the circle centre as M, and the tangent point on the circle as X. Triangle PMT is a right-angled triangle. You might want to sketch this out on paper as you go through it to make it easier to follow.

The position of X is just the position of M plus the radial vector to X i.e. the edge MX. The calculation is then about computing the vector MX.

The vector MX can be decomposed into two perpendicular components. One that is parallel to MP and one that is perpendicular to MP. The first thing to do is obtain unit vectors in those two directions. The first is easy as it's just the normalised version of MP. A perpendicular vector to this is easily obtained in 2D by swapping the components and negating one component. Which component you negate is irrelevant here since you ultimately want both tangent lines.

Now that we have our two unit vectors we need to work out how much of each is required to create the radial vector MX. Denoting the angle PMX by theta we have from simple right-angled triangles that cos(theta)=r/|MP| where r is the radius of your circle and |MP| is the length of MP (which you already calculated to get your unit vector above).

Dropping a perpendicular from X to MP gives another right-angled triangle involving theta whose opposite and adjacent sides represent the two components we want. The lengths of these sides are just r * cos(theta) in the MP direction and r * sin(theta) in the perpendicular direction.

So your final result is essentially

X = M + r * cos(theta) * unit_MP + r * sin(theta) * unit_MP_perp_1

for one of the tangent points and

X = M + r * cos(theta) * unit_MP + r * sin(theta) * unit_MP_perp_2

for the other. Unit_MP and unit_MP_perp_1/2 are the unit vectors we worked out earlier. The 1/2 version of the perp vector correspond to negating either the first or second components after the swap.

Edit

In terms of the diagram you added, the equation becomes

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

with similar equations (x2,y2). In these equations

cos(theta) = r / D

sin(theta) = A / D

where D = sqrt( (px - cx )^2 + (py - cy)^2 )

and

Ux = (px -cx) / D

Uy = (py -cy) / D

and so

U1x = -Uy

U1y = Ux

The perpendicular unit vector for the other tangent point would be

U2x = Uy

U2y =-Ux

蓝颜夕 2024-11-08 20:41:08

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

在当前点和终点 (x,y) 之间绘制贝塞尔曲线,其中 control (x,y) 是曲线弯曲的点(例如Photoshop 中的钢笔工具)。设置为一半 delta X 并使用 Y 调整其强度。

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

Draws a Bézier between current point and end (x,y) with control (x,y) being the point the curve is bent towards (like the pen tool in Photoshop). Set to half delta X and use Y to adjust its strength.

网名女生简单气质 2024-11-08 20:41:08

这是绘制 2D 楔形形状的片段。您可以调整 startAngleangle 变量来控制楔形的角度。半径将决定形状的宽度。这应该在 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();

Here is a snippet for drawing a 2D Wedge shape. You can adjust the startAngle and angle vars to control the angle of the wedge. Radius will determine the width of the shape. This should be used within either a Shape, Sprite, MovieClip or some sub-class that has a graphics object.

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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文