我们首先将问题分成如下几个小问题讨论


ios 判断线段相交 判断两条线段相交_ios 判断线段相交


首先要解决的第一个问题是判断直线是否平行 ,我们首先假设四个点的坐标为

前两个点为a(x1, y1), b(x2, y2) 后两个点为 c(x3, y3), d(x4, y4),求出两个直线的方向向量e1→=(x1−x2,y1−y2) , e2→=(x3−x4,y3−y4)。

通过e1→, e2→求得e1→×e2→=theta=(e1xe2y−e1ye2x) ,如果theta为0则表示平行。接着我们要判断是否共线,很简单,我们求出这两之间的任意向量,如e3→=(x1 - x3, y1 - y3),求e1→×e3→=beta=(e1xe3y−e1ye3x)

如果两个线段不平行的话,等于分成了3种情况。首先我们判断是否跨交。也就是判断a,b是不是在c,d两边,c,d同时是不是也在a,b的两边。我们可以求m⃗ =(x1−x3,y1−y3),n⃗ =(x1−x4,y1−y4),k⃗ =(x2−x4,y2−y4)


ios 判断线段相交 判断两条线段相交_ios 判断线段相交_02


通过判断m⃗ ×e1→与n⃗ ×e1→是否异号就可以判断出c,d是否在a,b两侧,如果异号说明在两边,如果同号则不在。另外判断a,b是否在c,d两侧同理可得。

如果跨交的话求交点。

设交点为(x0, y0),则下列方程组必然成立:

  • x0-x1=k1(x2-x1)
  • y0-y1=k1(y2-y1)
  • x0-x3=k2(x4-x3)
  • y0-y3=k2(y4-y3)

其中k1和k2为任意不为0的常数(若为0,则说明有重合的端点,这种情况在上面已经被排除了)。1式与2式联系,3式与4式联立,消去k1和k2可得:

  • x0(y2-y1)-x1(y2-y1)=y0(x2-x1)-y1(x2-x1)
  • x0(y4-y3)-x3(y4-y3)=y0(x4-x3)-y3(x4-x3)

将含有未知数x0和y0的项移到左边,常数项移动到右边,得:

  • (y2-y1)x0+(x1-x2)y0=(y2-y1)x1+(x1-x2)y1
  • (y4-y3)x0+(x3-x4)y0=(y4-y3)x3+(x3-x4)y3

设两个常数项分别为b1和b2:

  • a1=(y2-y1)x1+(x1-x2)y1
  • a2=(y4-y3)x3+(x3-x4)y3

系数行列式的值为theta,用a1和a2替换x0的系数所得系数行列式的值为theta1,替换y0的系数所得系数行列式的值为D2,则有:

  • theta=(x2-x1)(y4-y3)-(x4-x3)(y2-y1)
  • theta1=a2(x2-x1)-a1(x4-x3)
  • theta2=a2(y2-y1)-a1(y4-y3)

由此,可求得交点坐标为:

  • x0=|theta1|/|theta|, y0=|theta2|/|theta|

如果是交于端点的话通过判断集合位置关系就可以判断出来了。

下面是代码:

#include <iostream>
#include <cmath>

//判断两个像素是否相等
bool equal(double x, double y)
{
    return std::abs(x - y) < 1e-7;
}
class point
{
public:
    point(double x = 0.0, double y = 0.0) :x(x), y(y) {}
    bool operator==(const point& rhs) const;
    bool operator!=(const point& rhs) const;
    bool operator<(const point& rhs) const;
    bool operator>(const point& rhs) const;
    point operator-(const point& rhs) const;
    point operator+(const point& rhs) const;
    static double cross_product(const point& p1, const point& p2);
    double pointX() { return this->x; }
    double pointY() { return this->y; }
private:
    double x, y;
};
bool point::operator==(const point & rhs) const
{
    return equal(x, rhs.x) && equal(y, rhs.y);
}

bool point::operator!=(const point & rhs) const
{
    return (x != rhs.x)&&(y != rhs.y);
}

bool point::operator<(const point & rhs) const
{
    return false;
}

bool point::operator>(const point & rhs) const
{
    return false;
}

point point::operator-(const point & rhs) const
{
    return point(x - rhs.x, y - rhs.y);
}

point point::operator+(const point & rhs) const
{
    return point(x + rhs.x, y + rhs.y);
}

double point::cross_product(const point & p1, const point & p2)
{
    return (p1.x*p2.y - p2.x*p1.y);
}


//判断两个线段是否相交
//相交返回1,重合返回2,不相交返回3
//出错返回-1
//www.coordinate.wang
int cross(point& a, point& b, point& c, point& d, point& f)//a,b表示一个线段;c,d表示一个线段, f表示交点坐标
{
    //如果线段长度为0,则退出
    if (a == b || c == d)
    {
        return -1;
    }
//判断两个是否平行
//得到线段的向量x, y
    point x = a - b;
    point y = c - d;
    //计算差乘
    double theta = point::cross_product(x, y);
    if (a > b)
    {
        std::swap(a, b);
    }
    if (c > d)
    {
        std::swap(c, d);
    }
    if (equal(theta, 0))
    {
        //平行时
        point m = a - c;
        point n = b - a;
        double beta = point::cross_product(m, n);//计算是否共线
        if (equal(beta, 0))
        {
            //平行共线
            //通过判断坐标关系确定是否重合
            if ((a < c && c < d) || (d < b && a < d))
            {
                //重合
                return 2;
            }
            else if (b == c)
            {
                f = b;
                return 1;
            }
            else if (a == d)
            {
                f = a;
                return 1;
            }
            else
            {
                //不重合
                return 3;
            }
        }
        else
        {
            //平行不共线且无交点
            return 3;
        }
    }
    else
    {//不平行时
        point m = a - c;
        point n = b - c;
        point k = b - d;
        double gama1 = point::cross_product(m, y);
        double gama2 = point::cross_product(n, y);
        double gama3 = point::cross_product(n, x);
        double gama4 = point::cross_product(k, x);
        //不平行且相交
        if (((gama1 > 0 && gama2 < 0) || (gama1 < 0 && gama2 > 0)) &&
            ((gama3 > 0 && gama4 < 0) || (gama3 < 0 && gama4 > 0)))
        {
            double a1 = (b.pointY() - a.pointY())*a.pointX() + (a.pointX() - b.pointX())*a.pointY();
            double a2 = (d.pointY() - c.pointY())*c.pointX() + (c.pointX() - d.pointX())*c.pointY();
            double theta1 = (b.pointX() - a.pointX())*a2 - (d.pointX() - c.pointX())*a1;
            double theta2 = (b.pointY() - a.pointY())*a2 - (d.pointY() - c.pointY())*a1;
            double px = std::abs(theta1) / std::abs(theta);
            double py = std::abs(theta2) / std::abs(theta);
            f = point(px, py);
            return 1;
        }
        else if (b == c)//不平行交于端点
        {
            f = b;
            return 1;
        }
        else if (a == d)
        {
            f = a;
            return 1;
        }
        else
        {
            //不平行不相交
            return 3;
        }       
    }   
}
int main()
{
    point p1(0, 0), p2(2, 2), p3(1, 1), p4(3, 3), f;
    int n = cross(p1, p2, p3, p4, f);
    system("pause");
}