从一点找到圆的切点

问题描述 投票:0回答:6

圆心:Cx,Cy

圆半径:a

我们需要绘制切线的点:Px,Py

根据上述所有内容,我需要公式来找到两条切线 (t1x, t1y) 和 (t2x,t2y)。

编辑: 有没有使用向量代数或其他东西的更简单的解决方案,而不是找到两条直线的方程,然后求解两条直线的方程以分别找到两条切线?另外这个问题并不是偏离主题,因为我需要编写一段代码来找到最佳答案

algorithm math geometry algebra
6个回答
12
投票

这是使用三角学的一种方法。如果您了解三角函数,这种方法很容易理解,尽管由于三角函数缺乏精确性,它可能无法给出准确的正确答案。

给出了点

C = (Cx, Cy)
P = (Px, Py)
,以及半径
a
。半径在我的图中显示了两次,即
a1
a2
。您可以轻松计算点
b
P
之间的距离
C
,并且可以看到线段
b
形成两个边长为
a
的直角三角形的斜边。角度
theta
(在我的图中也显示了两次)位于斜边和相邻边
a
之间,因此可以使用反余弦来计算。从点
C
到点
P
的向量的方向角也可以通过反正切很容易找到。切点的方向角是原始方向角与计算出的三角形角的和与差。最后,我们可以使用这些方向角和距离
a
来找到这些切点的坐标。

这是 Python 3 中的代码。

# Example values
(Px, Py) = (5, 2)
(Cx, Cy) = (1, 1)
a = 2

from math import sqrt, acos, atan2, sin, cos

b = sqrt((Px - Cx)**2 + (Py - Cy)**2)  # hypot() also works here
th = acos(a / b)  # angle theta
d = atan2(Py - Cy, Px - Cx)  # direction angle of point P from C
d1 = d + th  # direction angle of point T1 from C
d2 = d - th  # direction angle of point T2 from C

T1x = Cx + a * cos(d1)
T1y = Cy + a * sin(d1)
T2x = Cx + a * cos(d2)
T2y = Cy + a * sin(d2)

有一些明显的方法可以组合这些计算并使它们更加优化,但我将把它留给你。还可以使用三角学的角度加法和减法公式以及一些其他恒等式来从计算中完全删除三角函数。然而,结果更加复杂且难以理解。未经测试,我不知道哪种方法更“优化”,但这取决于您的目的。如果您需要这种其他方法,请告诉我,但这里的其他答案无论如何都会为您提供其他方法。

请注意,如果

a > b
acos(a / b)
将抛出异常,但这意味着点
P
位于圆内并且没有切点。如果a == b
,则点
P
位于
圆上,并且只有一个切点,即点P本身。我的代码适用于这种情况
a < b
。我将让您对其他情况进行编码,并确定所需的精度来确定
a
b
是否相等。
    


5
投票

p = c + r*a + d*I*a

重新整理

(r+I*d)*a = p-c

但是 a 的长度为 1,所以取我们得到的长度

|r+I*d| = |p-c|

除了 d 之外我们什么都知道,所以我们可以求解 d:

d = +- sqrt( |p-c|*|p-c| - r*r)

然后找到 a 和圆上的点,每个 d 值对应一个:

a = (p-c)/(r+I*d) q = c + r*a



1
投票

您可以利用您处于

2D

中的事实,就像在 2D 中垂直于向量 a(x,y) 的向量计算如下:


c = (-y, x) d = ( y,-x) c = -d

所以你交换 
x,y

并求反(哪一个决定垂直向量是

CW
还是 CCW)。这实际上是一个旋转公式,但当我们旋转 90 度时,cos,sin 只是
+1
-1

现在,圆上任意圆周点的法线

n

位于通过该点和圆心的直线上。因此,将所有这些放在一起,您的切线是:


// normal nx = Px-Cx ny = Py-Cy // tangent 1 tx = -ny ty = +nx // tangent 2 tx = +ny ty = -nx

如果你想要单位向量而不仅仅是除以半径
a

(不知道为什么你不像数学世界的其他部分那样称呼它

r
),那么:

// normal nx = (Px-Cx)/a ny = (Py-Cy)/a // tangent 1 tx = -ny ty = +nx // tangent 2 tx = +ny ty = -nx



0
投票

如你所见,如果正方形的内部是

剩下的就很简单了。拿着< 0 it's because the point is interior to the circumferemce. When the point is outside of the circumference there are two solutions, depending on the sign of the square.

atan(solution)

,小心这里的标志,你最好做一些检查。

使用 (2),然后撤消 (1) 变换,仅此而已。


0
投票

static void FindTangents(Vector2 point, Vector2 circle, float r, out Line l1, out Line l2) { var p = new Complex(point.x, point.y); var c = new Complex(circle.x, circle.y); var cp = p - c; var d = Math.Sqrt(cp.Real * cp.Real + cp.Imaginary * cp.Imaginary - r * r); var q = GetQ(r, cp, d, c); var q2 = GetQ(r, cp, -d, c); l1 = new Line(point, new Vector2((float) q.Real, (float) q.Imaginary)); l2 = new Line(point, new Vector2((float) q2.Real, (float) q2.Imaginary)); } static Complex GetQ(float r, Complex cp, double d, Complex c) { return c + r * (cp / (r + Complex.ImaginaryOne * d)); }



0
投票

function tangentCircle (cx, cy, cr, px, py) -- circle, point local dx = px-cx local dy = py-cy local dist = math.sqrt(dx*dx+dy*dy) if dist <= cr then return end -- point inside circle local a = math.atan2 (dy, dx) local b = math.acos (cr/dist) local x1 = cx + cr * math.cos (a-b) local y1 = cy + cr * math.sin (a-b) local x2 = cx + cr * math.cos (a+b) local y2 = cy + cr * math.sin (a+b) return x1, y1, x2, y2 end

示例:

print (tangentCircle (120, 100, 30, 20, 10)) -- result: -- x1, y1: 95.463995562856 117.26222715238 -- x2, y2: 134.59125305593 73.787496604524

© www.soinside.com 2019 - 2024. All rights reserved.