圆心:Cx,Cy
圆半径:a
我们需要绘制一条切线的点:Px,Py
在上述所有情况下,我需要公式来找到两个切线(t1x,t1y)和(t2x,t2y)。
编辑:有没有更简单的解决方案使用矢量代数或其他东西,而不是找到两条直线的方程,然后求解两条直线的方程,分别找到两条切线?此问题也不是偏离主题的,因为我需要编写一个代码来找到最佳的
答案 0 :(得分:4)
这是使用复数的另一种方式。 如果a是中心c上圆上切点的方向(长度为1的复数),d是沿切线得到p的(实际)长度,那么(因为切线的方向是I * A)
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 :(得分:3)
这是使用三角法的一种方法。如果你理解trig,这个方法很容易理解,但由于trig函数缺乏准确性,它可能无法在可能的情况下给出正确的答案。
给出了点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)
有很明显的方法可以将这些计算结合起来并使它们更加优化,但我会把它留给你。也可以使用具有一些其他身份的三角学的角度加法和减法公式来从计算中完全去除trig函数。但是,结果更复杂且难以理解。没有测试我不知道哪种方法更多"优化"但这取决于你的目的。如果您需要这种其他方法,请告诉我,但其他答案在此提供了其他方法。
请注意,如果a > b
然后acos(a / b)
会抛出异常,但这意味着点P
在圆圈内并且没有相切点。如果a == b
然后点P
on ,则只有一个相切点,即点P
本身。我的代码适用于案例a < b
。我会留给您编写其他案例的代码,并决定确定a
和b
是否相等所需的精确度。
答案 2 :(得分:0)
嗯,这不是一个算法问题(人们往往会误解算法和方程式)如果你想写一个代码然后做(你没有指定语言,也没有什么阻止你做这个,这是关闭投票的原因)..没有这个信息,你的OP只是要求数学方程式,这在这里确实是偏离主题的,并且通过回答我的风险(右 - 完全)向下投票(但这是/在这里被问了很少的信息和4重新开始投票反对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
答案 3 :(得分:0)
如您所见,如果广场的内部是&lt; 0这是因为该点在圆周的内部。当该点在圆周之外时,根据方形的符号,有两种解决方案。
其余的很容易。拿atan(solution)
并注意这些标志,你最好做一些检查。
使用(2)然后撤消(1)转换,这就是全部。
答案 4 :(得分:0)
dmuir答案的c#实现:
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));
}
答案 5 :(得分:-1)