1. 程式人生 > >三維空間兩直線/線段最短距離、線段計算算法 【轉】

三維空間兩直線/線段最短距離、線段計算算法 【轉】

發布 2.3 main position overflow 解析 get fix 三維

https://segmentfault.com/a/1190000006111226 技術分享


d(ls,lt)=|sjtj|=|s0t0+(becd)u? (aebd)v? acb d(ls,lt)=|sjtj|=|s0t0+(becd)u? (aebd)v? acb2|

技術分享

技術分享

具體實現代碼如下(C#實現):

public bool IsEqual(double d1, double d2)
{
    if (Math.Abs(d1 - d2) < 1e-7)
        return true;
    return false;
}
        
public double SqureDistanceSegmentToSegment(double x1, double y1, double z1,
                                            double x2, double y2, double z2,
                                            double x3, double y3, double z3,
                                            double x4, double y4, double z4)
{
    // 解析幾何通用解法,可以求出點的位置,判斷點是否在線段上
    // 算法描述:設兩條無限長度直線s、t,起點為s0、t0,方向向量為u、v
    // 最短直線兩點:在s1上為s0+sc*u,在t上的為t0+tc*v
    // 記向量w為(s0+sc*u)-(t0+tc*v),記向量w0=s0-t0
    // 記a=u*u,b=u*v,c=v*v,d=u*w0,e=v*w0——(a);
    // 由於u*w=、v*w=0,將w=-tc*v+w0+sc*u帶入前兩式得:
    // (u*u)*sc - (u*v)*tc = -u*w0  (公式2)
    // (v*u)*sc - (v*v)*tc = -v*w0  (公式3)
    // 再將前式(a)帶入可得sc=(be-cd)/(ac-b2)、tc=(ae-bd)/(ac-b2)——(b)
    // 註意到ac-b2=|u|2|v|2-(|u||v|cosq)2=(|u||v|sinq)2不小於0
    // 所以可以根據公式(b)判斷sc、tc符號和sc、tc與1的關系即可分辨最近點是否在線段內
    // 當ac-b2=0時,(公式2)(公式3)獨立,表示兩條直線平行。可令sc=0單獨解出tc
    // 最終距離d(L1、L2)=|(P0-Q0)+[(be-cd)*u-(ae-bd)v]/(ac-b2)|
    double ux = x2 - x1;
    double uy = y2 - y1;
    double uz = z2 - z1;

    double vx = x4 - x3;
    double vy = y4 - y3;
    double vz = z4 - z3;

    double wx = x1 - x3;
    double wy = y1 - y3;
    double wz = z1 - z3;

    double a = (ux * ux + uy * uy + uz * uz); //u*u
    double b = (ux * vx + uy * vy + uz * vz); //u*v
    double c = (vx * vx + vy * vy + vz * vz); //v*v
    double d = (ux * wx + uy * wy + uz * wz); //u*w 
    double e = (vx * wx + vy * wy + vz * wz); //v*w
    double dt = a * c - b * b;

    double sd = dt;
    double td = dt;

    double sn = 0.0;//sn = be-cd
    double tn = 0.0;//tn = ae-bd

    if (IsEqual(dt, 0.0))
    {
        //兩直線平行
        sn = 0.0;    //在s上指定取s0
        sd = 1.00;   //防止計算時除0錯誤

        tn = e;      //按(公式3)求tc
        td = c;
    }
    else
    {
        sn = (b * e - c * d);
        tn = (a * e - b * d);
        if (sn < 0.0)
        {
            //最近點在s起點以外,同平行條件
            sn = 0.0;
            tn = e;
            td = c;
        }
        else if (sn > sd)
        {
            //最近點在s終點以外(即sc>1,則取sc=1)
            sn = sd;
            tn = e + b; //按(公式3)計算
            td = c;
        }
    }
    if (tn < 0.0)
    {
        //最近點在t起點以外
        tn = 0.0;
        if (-d < 0.0) //按(公式2)計算,如果等號右邊小於0,則sc也小於零,取sc=0
            sn = 0.0;
        else if (-d > a) //按(公式2)計算,如果sc大於1,取sc=1
            sn = sd;
        else
        {
            sn = -d;
            sd = a;
        }
    }
    else if (tn > td)
    {
        tn = td;
        if ((-d + b) < 0.0)
            sn = 0.0;
        else if ((-d + b) > a)
            sn = sd;
        else
        {
            sn = (-d + b);
            sd = a;
        }
    }

    double sc = 0.0;
    double tc = 0.0;

    if (IsEqual(sn, 0.0))
        sc = 0.0;
    else
        sc = sn / sd;

    if (IsEqual(tn, 0.0))
        tc = 0.0;
    else
        tc = tn / td;

    double dx = wx + (sc * ux) - (tc * vx);
    double dy = wy + (sc * uy) - (tc * vy);
    double dz = wz + (sc * uz) - (tc * vz);
    return dx * dx + dy * dy + dz * dz;
}

參考文獻:http://geomalgorithms.com/a07-_distance.html

  • 2016年07月29日發布

三維空間兩直線/線段最短距離、線段計算算法 【轉】