找到圆上的切点?

时间:2009-08-29 15:52:01

标签: math geometry line

给定具有第一个端点P(x1,y1)的线,另一个端点是未知的,与位于原点的圆相交,半径R仅在一个点(切线)T(x2,y2)处。谁知道如何得到点T?提前谢谢!

9 个答案:

答案 0 :(得分:34)

  

给定具有第一个端点P(x1,y1)的线,另一个端点是未知的,与位于原点的圆相交,半径R仅在一个点(切线)T(x2,y2)处。任何人都知道如何得到点T?

其他一些解决方案看起来有点像矫枉过正。我认为最简单的方法就是注意这是一个直角三角形,顶点为P,T和O(原点)。角度PTO是直角,因为切线始终与半径成直角。

你知道TO的长度,因为它的长度为r并且在原点有一个顶点;您知道OP,因为您知道OP的位置。给定直角三角形的两边,很容易找到第三边的长度和方向。这是家庭作业,所以我将把剩下的作为练习留给读者。

                    __...------__    T(x2, y2)                      
               _.-''             -(+)
            ,-'                   |----             
          ,'                     |     ----
        ,'                      |       '  ----
       /                       |         `     ----       
      /                       |           `.       ----   
     /                       |             \           ----
    |                       |               |              ----
    |                      |                 |                  ----
    |                     |                  |                      ----
    |                   (+)---------------------------------------------(+) P (x1,y1)
    |                                        .'        
    |                    O                   |         
     |                                      .'         
      \                                     /          
       \                                  ,'           
        `                                /             
         '.                            ,'              
           '-.                      _,'             
              '-._              _,(+)  T'(x3, y3)                   
                  '`--......---'                       

TO有两种可能的方向,因为点T'也是一个有效的切点,所以你将有两个全等三角形。

答案 1 :(得分:14)

您需要的只是dmckee的答案,但如果您关心某些代码,请使用Javascript和HTML画布检查此实现。

完整示例: http://jsfiddle.net/zxqCw/1/

// find tangents
dx = cx - px;
dy = cy - py;
dd = Math.sqrt(dx * dx + dy * dy);
a = Math.asin(radius / dd);
b = Math.atan2(dy, dx);

t = b - a
ta = { x:radius * Math.sin(t), y:radius * -Math.cos(t) };

t = b + a
tb = { x:radius * -Math.sin(t), y:radius * Math.cos(t) };

答案 2 :(得分:9)

R作为圆的半径,D将外部点与圆心的距离设为D > R

tanget线和\alpha的角度与连接外部点和中心的线相交,其中

\alpha = arcsin(R/D)

连接外部点(P)和中心(C)的线与水平面成一个角度

\beta = arctan((C_y - P_y)/(C_x - P_x))

它为您提供切线与水平线的角度

\theta = \beta +/- \alpha

注意歧义。

切线段的长度为

L = sqrt(D^2 - R^2)

这就是你所需要的一切。

答案 3 :(得分:5)

imbrizi的回答是假设圆圈的中心是(0,0)。

这是目标C中的正确答案:

- (NSArray *)pointsTangentToCircleWithCenter:(CGPoint)centerPoint
                                      radius:(CGFloat)radius
                                  outerPoint:(CGPoint)outerPoint {

    float dx = centerPoint.x - outerPoint.x;
    float dy = centerPoint.y - outerPoint.y;
    float dd = sqrt(dx*dx + dy*dy);
    float a = asinf(radius / dd);
    float b = atan2f(dy, dx);
    float t1 = b - a;
    CGPoint tangentPoint1 = CGPointMake(centerPoint.x + radius*sinf(t1), 
                                        centerPoint.y + radius*-cosf(t1));

    float t2 = b + a;
    CGPoint tangentPoint2 = CGPointMake(centerPoint.x + radius*-sinf(t2), 
                                        centerPoint.y + radius*cosf(t2));

    NSArray *points = @[
                        [NSValue valueWithCGPoint:tangentPoint1],
                        [NSValue valueWithCGPoint:tangentPoint2]
                        ];
    return points;
}

答案 4 :(得分:3)

  1. 如果按角度 alpha 旋转矢量 DO ,您可以找到矢量 DX 方向 (角度alpha被发现为 asin(len(OX)/ len(DO)),这只是半径超过斜边的弧度)

  2. 您可以轻松找到矢量 DX 长度,如下所示: sqrt(len(DO)* len(DO) - len(OX) )* LEN(OX))

  3. 考虑到向量 DX 的方向和长度,您可以找到 point X 的值。一种方法是将 DX 标准化并将其乘以它的长度。

  4. auto dist = D.Distance(O);
    auto side = sqrt(dist*dist - rad*rad)
    auto line = Vector2D(D, O);
    line.Rotate(asin(rad / dist)); //get the direction
    line.Normalize();              //set length to 1
    line*=side;                    //we have the direction, now get length
    Point2D X = D + line;
    

    P.S。请注意,还有第二个切线,可以通过 DO 旋转减去 alpha

    来找到

    Image demonstrating the algo

答案 5 :(得分:2)

对我而言,这是作业是不明显的,但我确实喜欢直角三角形的定义。即便如此,也会有一些代数来解决这个问题。

另一种似乎可行的方法是简单地将问题定义为两个未知数中两个方程的解。也就是说,以(0,0)为中心的半径为R的圆的等式是

x^2 + y^2 = R^2

通过点(xt,yt),具有(未知)斜率S的线的等式是

(y - yt) = S*(x - xt)

求解交点的两个方程组。根据S的值,这对方程将有零个,一个或两个解。事实证明,S有两个值,使得解决方案是唯一的。解决使得解决方案唯一的S的两个值,然后恢复交点(xt,yt)。如果这是作业,我不会深入研究实际的解决方案,但那部分是琐碎的代数。

我的观点是,这种代数方法是另一种查看计算几何问题解决方案的方法。它突出了一个有趣的观点,即有两条线在一个切点处与圆相交,当一条线在一个切点处相交时,就会有一个交点。

这种方法的缺陷是由于某些问题的单一性而失败。即,当具有斜率S的线是垂直的时,则S是未定义的。依赖于简单距离和毕达哥拉斯定理的其他方法对于该事件是稳健的。

答案 6 :(得分:1)

使用交叉方程的x,y坐标(圆的一个和线之一)。这就是重点。

如果您只有一个绘制线的终点,则会得到两个不同的点,因为会有两条不同的切线,一条向上,一条向下。

答案 7 :(得分:1)

我通常使用Maple软件来解决这些问题。它甚至可以从这些方程中生成C代码。

enter image description here

这是输出:

t1 = v_x * v_x;
t2 = t1 * t1;
t3 = v_y * v_y;
t6 = sqrt(t1 * t3 - t1 + t2);
t7 = v_y + t6;
t9 = 0.1e1 / (t1 + t3);
t13 = 0.1e1 / v_x;
x1 = -(t7 * t9 * v_y - 0.1e1) * t13;
y1 = t7 * t9;
t16 = (-v_y + t6) * t9;
x2 = -(-t16 * v_y - 0.1e1) * t13;
y2 = -t16;

显然,你需要在变量中添加float或double,在取平方根之前也要检查负值。

答案 8 :(得分:0)

另一种解决方案;不如dmindreader的优雅,但也许更容易理解:

您知道点T位于圆圈上,而OT线垂直于线PT

给你

abs(O - T) = R
dotProduct(O - T, P - T) = 0