[轉載]判斷兩線段是否相交,並求交點

首先, 上個示意圖.

.這裏寫圖片描述

根據圖示, 線段a表示爲端點a1和a2, 線段b表示爲端點b1和b2. 爲了利用向量的叉乘關係, 將線段的端點看成四個向量, 下面用粗體表示向量. 根據向量運算可知
a=a2-a1,
b=b2-b1.

將線段表示爲參數方程:
a=a1 + t a
b=b1 + u b

其中參數t,u取值 [0,1]

兩條線段相交具有如下關係:
a1 + t a=b1 + u b
將上式兩邊同時叉乘b, 得到:
(a1+t a) x b=(b1+u b) x b
由於b x b=0, 可得
a1 x b + t a x b=b1 x b
解出參數t
t=(b1-a1)x b/(a x b)
同理,解出參數u
u=a x (a1-b1)/(a x b)

當0<=t<=1,且0<=u<=1時,兩線段有交點.
代入線段a的參數方程中, 即可得到線段交點座標:
a1+t a
將上式中的中間變量用原始的線段端點表示, 即可得到根據線段端點表示的交點.

code 1

// Returns 1 if the lines intersect, otherwise 0. In addition, if the lines 
// intersect the intersection point may be stored in the floats i_x and i_y.
char get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y, 
    float p2_x, float p2_y, float p3_x, float p3_y, float *i_x, float *i_y)
{
    float s1_x, s1_y, s2_x, s2_y;
    s1_x = p1_x - p0_x;     s1_y = p1_y - p0_y;
    s2_x = p3_x - p2_x;     s2_y = p3_y - p2_y;

    float s, t;
    s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
    t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);

    if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
    {
        // Collision detected
        if (i_x != NULL)
            *i_x = p0_x + (t * s1_x);
        if (i_y != NULL)
            *i_y = p0_y + (t * s1_y);
        return 1;
    }

    return 0; // No collision
}



code 2

優化版本,排除線段平行情況,避免精度誤差

int get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y, 
    float p2_x, float p2_y, float p3_x, float p3_y, float *i_x, float *i_y)
{
    float s02_x, s02_y, s10_x, s10_y, s32_x, s32_y, s_numer, t_numer, denom, t;
    s10_x = p1_x - p0_x;
    s10_y = p1_y - p0_y;
    s32_x = p3_x - p2_x;
    s32_y = p3_y - p2_y;

    denom = s10_x * s32_y - s32_x * s10_y;
    if (denom == 0)//平行或共線
        return 0; // Collinear
    bool denomPositive = denom > 0;

    s02_x = p0_x - p2_x;
    s02_y = p0_y - p2_y;
    s_numer = s10_x * s02_y - s10_y * s02_x;
    if ((s_numer < 0) == denomPositive)//參數是大於等於0且小於等於1的,分子分母必須同號且分子小於等於分母
        return 0; // No collision

    t_numer = s32_x * s02_y - s32_y * s02_x;
    if ((t_numer < 0) == denomPositive)
        return 0; // No collision

    if (fabs(s_numer) > fabs(denom) || fabs(t_numer) > fabs(denom))
        return 0; // No collision
    // Collision detected
    t = t_numer / denom;
    if (i_x != NULL)
        *i_x = p0_x + (t * s10_x);
    if (i_y != NULL)
        *i_y = p0_y + (t * s10_y);

    return 1;
}



方法來源於stack overflow的帖子:geometry - How do you detect where two line segments intersect?
————————————————
版權聲明:本文爲CSDN博主「Away-Far」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/wcl0617/article/details/78654944

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章