1. 程式人生 > >【C#】點到線段最短距離的那條直線與線段的交點

【C#】點到線段最短距離的那條直線與線段的交點

/// <summary>
    ///  點到線段最短距離的那條直線與線段的交點,{x=...,y=...}
    /// </summary>
    /// <param name="x">線段外的點的x座標</param>
    /// <param name="y">線段外的點的y座標</param>
    /// <param name="x1">線段頂點1的x座標</param>
    /// <param name="y1">線段頂點1的y座標</param>
    /// <param name="x2">線段頂點2的x座標</param>
    /// <param name="y2">線段頂點2的y座標</param>
    /// <returns></returns>
    public Vector2 PointForPointToABLine(float x, float y, float x1, float y1, float x2, float y2)
    {
        Vector2 reVal = new Vector2();
        // 直線方程的兩點式轉換成一般式
        // A = Y2 - Y1
        // B = X1 - X2
        // C = X2*Y1 - X1*Y2
        float a1 = y2 - y1;
        float b1 = x1 - x2;
        float c1 = x2 * y1 - x1 * y2;
        float x3, y3;
        if (a1 == 0)
        {
            // 線段與x軸平行
            reVal = new Vector2(x, y1);
            x3 = x;
            y3 = y1;
        }
        else if (b1 == 0)
        {
            // 線段與y軸平行
            reVal = new Vector2(x1, y);
            x3 = x1;
            y3 = y;
        }
        else
        {
            // 普通線段
            float k1 = -a1 / b1;
            float k2 = -1 / k1;
            float a2 = k2;
            float b2 = -1;
            float c2 = y - k2 * x;
            // 直線一般式和二元一次方程的一般式轉換
            // 直線的一般式為 Ax+By+C=0
            // 二元一次方程的一般式為 Ax+By=C
            c1 = -c1;
            c2 = -c2;

            // 二元一次方程求解(Ax+By=C)
            // a=a1,b=b1,c=c1,d=a2,e=b2,f=c2;
            // X=(ce-bf)/(ae-bd)
            // Y=(af-cd)/(ae-bd)
            x3 = (c1 * b2 - b1 * c2) / (a1 * b2 - b1 * a2);
            y3 = (a1 * c2 - c1 * a2) / (a1 * b2 - b1 * a2);
        }
        // 點(x3,y3)作為點(x,y)到(x1,y1)和(x2,y2)組成的直線距離最近的點,那(x3,y3)是否在(x1,y1)和(x2,y2)的線段之內(包含(x1,y1)和(x2,y2))
        if (((x3 > x1) != (x3 > x2) || x3 == x1 || x3 == x2) && ((y3 > y1) != (y3 > y2) || y3 == y1 || y3 == y2))
        {
            // (x3,y3)線上段上
            reVal = new Vector2(x3, y3);
        }
        else
        {
            // (x3,y3)線上段外
            float d1_quadratic = (x - x1) * (x - x1) + (y - y1) * (y - y1);
            float d2_quadratic = (x - x2) * (x - x2) + (y - y2) * (y - y2);
            if (d1_quadratic <= d2_quadratic)
            {
                reVal = new Vector2(x1, y1);
            }
            else
            {
                reVal = new Vector2(x2, y2);
            }
        }
        return reVal;
    }