平面中判斷線段與矩形是否相交

1. 原理

這個問題的算法思路挺簡單的。分成兩步來判斷:

  1. 判斷線段的兩個端點是否在矩形內,如果兩個端點至少有一個在矩形內,說明線段與矩形相交。
  2. 如果兩個端點都不在矩形內,那麼需要再判斷線段是否與矩形的對角線是否相交。因爲兩個端點都不在矩形內的線段有可能會切割矩形的角,這時會與矩形的對角線相交。

那麼關鍵就在於兩個子算法:判斷點在矩形內和判斷線段相交。判斷點在矩形內非常簡單,就是比較點是否在矩形的四至範圍就可以了;而判斷線段相交可以參考《空間或平面判斷兩線段相交(求交點)》這篇文章。

2. 實現

關鍵的C++實現代碼如下:

//空間直線
template <class T>
class LineSegment
{
public:
    Vec3<T> startPoint;
    Vec3<T> endPoint;
    Vec3<T> direction;

    Vec3<T> min;
    Vec3<T> max;

    LineSegment()
    {
    }

    LineSegment(Vec3<T> start, Vec3<T> end)
    {
        startPoint = start;
        endPoint = end;
        direction = end - start;      
    }

    inline void Set(Vec3<T> start, Vec3<T> end)
    {
        startPoint = start;
        endPoint = end;
        direction = end - start;      
    }

    //兩條線段相交
    inline static bool Intersection2D(LineSegment & line1, LineSegment & line2, Vec3<T>& insPoint)
    {
        double D = -line1.direction.x() * line2.direction.y() + line1.direction.y() * line2.direction.x();
        if(D == 0.0)
        {
            return false;
        }

        auto O12 = line2.startPoint - line1.startPoint;
        T D1 = -O12.x() * line2.direction.y() + O12.y() * line2.direction.x();
        T D2 = line1.direction.x() * O12.y() - line1.direction.y() * O12.x();

        T t1 = D1 / D;
        if(t1<0 || t1 > 1)
        {
            return false;
        }

        T t2 = D2 / D;
        if(t2<0 || t2 > 1)
        {
            return false;
        }

        insPoint = line1.startPoint + line1.direction * t1;     //這樣計算得到的Z值是不準確的

        return true;
    }

    //線段與矩形相交
    inline bool static IsIntersectsOrthogon2D(LineSegment & line, Orthogon<T> orthogon)
    {
        if (orthogon.IsContainsPoint(line.startPoint.x(), line.startPoint.y()) ||
                orthogon.IsContainsPoint(line.endPoint.x(), line.endPoint.y()))
        {
            return true;
        }

        LineSegment diagonal1(Vec3<T>(orthogon.minX(), orthogon.minY(), 0),
                              Vec3<T>(orthogon.maxX(), orthogon.maxY(), 0));
        LineSegment diagonal2(Vec3<T>(orthogon.minX(), orthogon.maxY(), 0),
                              Vec3<T>(orthogon.maxX(), orthogon.minY(), 0));

        Vec3<T> point(0,0,0);
        return Intersection2D(line, diagonal1, point) || Intersection2D(line, diagonal2, point);
    }
};

3. 參考

  1. 如何判斷一條線段和一個矩形或者圓相交? - 葉飛影的回答 - 知乎
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章