如何确定直线和圆之间的交点?

时间:2013-06-08 09:29:39

标签: c# windows-phone-8 geometry

我在圆圈内有一个点,圆圈外有另一个点。我想找到线与圆相交的点。我怎么能在Windows Phone 8中这样做。请给我任何想法。

2 个答案:

答案 0 :(得分:7)

这既是一个简单而又复杂的问题,很大程度上取决于你的意思。我从你的开场白中说你正在谈论线段而不是真正的(无限)线。

在这种情况下,你有几个案例需要解决。交点仅在一个点位于圆内并且一个点位于圆外时发生。下面的算法没有捕获

的情况
  1. 该线与圆圈相切
  2. 一个或两个点正好在圆圈上
  3. 该线在两点相交
  4. 这些被归结为“无交叉”结果。这仅处理内部严格一个点和圆外一个点的情况。

    首先你需要一些辅助功能。它们使用基本几何来确定点是在圆内还是在圆外(圆上的点被计为“外部”),以及两个点是否形成与圆相交的线段。

    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返回值,以防您想要扩展它以区分边缘情况。交点是从基本几何计算的 - 记住一条线表示为(参见:Slope Intercept and Point Slope Form

    • y = M * x + B

    和一个圆圈(以(C.x, C.y)为中心,半径为r

    • (x - C.x)^ 2 +(y - C.y)^ 2 - r ^ 2 = 0

    您可以通过替换来解决这个方程组:

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

    扩展和收集您获得的条款:

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

    这是形式

    的标准二次方程
    • ax ^ 2 + bx + c = 0
    • 其中:
    • a =(1 + M ^ 2)
    • b = 2 *(M * B-M * C.y-C.x)
    • c =(C.x ^ 2 + C.y ^ 2 + B ^ 2 - r ^ 2 - B * C.y)

    可以通过二次公式求解(参见:Quadratic Formula):

    • 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");
    }
    

答案 1 :(得分:0)

数学中有一个小错字。 c#代码没问题。

... r ^ 2 - B * C.y)= 0

应该是

... r ^ 2 - 2B * C.y)= 0

也 c =(C.x ^ 2 + C.y ^ 2 + B ^ 2 - r ^ 2 - 2B * C.y)