簡體   English   中英

如何確定直線與圓的交點?

[英]How to determine the intersection point between the straight line and circle?

我在圓內有一個點,在圓外有另一個點。 我想找到線與圓相交的點。 我怎么能在 Windows Phone 8 中做到這一點。請給我任何想法。

這是一個既簡單又復雜的問題,很大程度上取決於您的意思。 我從你的開篇文章中得知你在談論線段而不是真正的(無限)線。

在這種情況下,您有幾個案例需要解決。 只有一點在圓內,一點在圓外時,才會發生相交。 下面的算法沒有捕捉到以下情況

  1. 該線與圓相切
  2. 一個或兩個點正好在圓上
  3. 線在兩點相交

這些被歸入“無交集”結果。 這僅處理嚴格在圓內一點和圓外一點的情況。

首先你需要一些輔助功能。 這些使用基本幾何來確定點是在圓內還是圓外(圓上的點算作“外”),以及兩點是否形成與圓相交的線段。

private bool IsInsideCircle(Point CirclePos, float CircleRad, Point checkPoint)
{
    if (Math.Sqrt(Math.Pow((CirclePos.X - checkPoint.X), 2) +
                  Math.Pow((CirclePos.Y - checkPoint.Y), 2)) < CircleRad)
    { return true; } else return false;
}

private bool IsIntersecting(Point CirclePos, float CircleRad, Point LineStart, 
                                                              Point LineEnd)
{
    if (IsInsideCircle(CirclePos, CircleRad, LineStart) ^
        IsInsideCircle(CirclePos, CircleRad, LineEnd)) 
    { return true; } else return false;
}

請注意^ (異或)的使用 - 我們希望精確地在里面一點,在外面一點。

有了這個,我們可以處理更大的功能:

private int Intersect (Point CirclePos, float CircleRad, 
                       Point LineStart, Point LineEnd, ref Point Intersection)
{
    if (IsIntersecting(CirclePos, CircleRad, LineStart, LineEnd)) 
    {
        //Calculate terms of the linear and quadratic equations
        var M = (LineEnd.Y - LineStart.Y) / (LineEnd.X - LineStart.X);
        var B = LineStart.Y - M * LineStart.X;
        var a = 1 + M*M;
        var b = 2 * (M*B - M*CirclePos.Y - CirclePos.X);
        var c = CirclePos.X * CirclePos.X + B * B +  CirclePos.Y * CirclePos.Y -
                CircleRad * CircleRad - 2 * B * CirclePos.Y;
        // solve quadratic equation
        var sqRtTerm = Math.Sqrt(b * b - 4 * a * c);
        var x = ((-b) + sqRtTerm)/(2*a);
        // make sure we have the correct root for our line segment
       if ((x < Math.Min(LineStart.X, LineEnd.X) || 
          (x > Math.Max(LineStart.X, LineEnd.X)))) 
        { x = ((-b) - sqRtTerm) / (2 * a); }
        //solve for the y-component
        var y = M * x + B;
        // Intersection Calculated
        Intersection = new Point(x, y);
        return 0;
    } else {
        // Line segment does not intersect at one point.  It is either 
        // fully outside, fully inside, intersects at two points, is 
        // tangential to, or one or more points is exactly on the 
        // circle radius.
        Intersection = new Point(0, 0);
        return -1;
    }            
}

此函數將交點作為ref參數並返回-1 (無交點)或0 (找到交點)。 如果您想擴展它以區分邊緣情況,我使用了int返回值。 交點是從基本幾何計算的 - 請記住,一條線表示為(請參閱:斜率截距和點斜率表格

  • y = M*x + B

和一個圓(以(Cx, Cy)為中心,半徑為r )是

  • (x - Cx)^2 + (y - Cy)^2 - r^2 = 0

您可以通過替換來解決這個方程組:

  • (x - Cx)^2 + ((M*x + B) - Cy)^2 - r^2 = 0

擴展和收集您得到的術語:

  • (1+M^2)x^2 + 2*(M B - M C.y - Cx)x + (Cx^2 + Cy^2 + B^2 - r^2 - 2B*Cy) = 0

這是形式的標准二次方程

  • ax^2 + bx + c = 0
  • 在哪里 :
  • a = (1+M^2)
  • b = 2*(M B - M C.y - Cx)
  • c = (Cx^2 + Cy^2 + B^2 - r^2 - 2B*Cy)

這可以通過二次公式解決(參見: 二次公式):

  • x = (-b ± Sqrt(b^2 - 4ac))/(2a)

這為我們的線段所在的無限線提供了兩個根——我們在上面做了最后的檢查,以確保我們為我們的特定線段選擇了解決方案。

這就是為什么在數學課上專心很重要!

現在......取決於你在做什么,有很多方法可以優化它。 上面的解決方案概述了基本方法,但如果需要,當然還有空間可以更快地執行此操作。 顯然,還可以將參數調整為您使用的任何類型的點或對象。 我試圖使它盡可能通用。

此外,為了展示如何調用它的示例:

Point iPt = new Point();

var rslt = Intersect(new Point(2,3), 5.0f, new Point(2,2), 
                     new Point(8,6), ref iPt);

if (rslt == 0) {
    MessageBox.Show(String.Format("Intersection at: x = {0}, y = {1}",
                                   iPt.X, iPt.Y));
} 
else {
    MessageBox.Show("No Intersection");
}

數學上有一個小錯別字。 c# 代碼沒問題。

... r^2 - B*Cy) = 0

應該

... r^2 - 2B*Cy) = 0

還有 c = (Cx^2 + Cy^2 + B^2 - r^2 - 2B*Cy)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM