判断两线段是否相交并计算交点坐标

本文详细介绍了如何使用矢量运算来判断两条线段是否相交,并提供了实现代码。同时,还展示了如何求解两条线段的交点坐标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

判断两条线段是否相交

跨立试验

如果两线段相交,则两线段必然相互跨立对方。若P1P2跨立Q1Q2 ,则矢量 ( P1 - Q1 )和( P2 - Q1 )位于矢量( Q2 - Q1 ) 的两侧,即( P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) < 0。上式可改写成( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) > 0。当 ( P1 - Q1 ) × ( Q2 - Q1 ) = 0 时,说明 ( P1 - Q1 ) 和 ( Q2 - Q1 )共线,但是因为已经通过快速排斥试验,所以 P1 一定在线段 Q1Q2上;同理,( Q2 - Q1 ) ×(P2 - Q1 ) = 0 说明 P2 一定在线段 Q1Q2上。所以判断P1P2跨立Q1Q2的依据是:( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 -Q1 ) >= 0。同理判断Q1Q2跨立P1P2的依据是:( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) >= 0。

实现代码如下:

bool intersection_exists(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)

    {
        // It's less expensive but you can't control the
        // boundary conditions: Less or LessEqual
        double dx1 = x2 - x1;
        double dy1 = y2 - y1;
        double dx2 = x4 - x3;
        double dy2 = y4 - y3;
        return ((x3 - x2) * dy1 - (y3 - y2) * dx1 < 0.0) !=
            ((x4 - x2) * dy1 - (y4 - y2) * dx1 < 0.0) &&
            ((x1 - x4) * dy2 - (y1 - y4) * dx2 < 0.0) !=
            ((x2 - x4) * dy2 - (y2 - y4) * dx2 < 0.0);

        // It's is more expensive but more flexible
        // in terms of boundary conditions.
        //--------------------
        //double den  = (x2-x1) * (y4-y3) - (y2-y1) * (x4-x3);
        //if(fabs(den) < intersection_epsilon) return false;
        //double nom1 = (x4-x3) * (y1-y3) - (y4-y3) * (x1-x3);
        //double nom2 = (x2-x1) * (y1-y3) - (y2-y1) * (x1-x3);
        //double ua = nom1 / den;
        //double ub = nom2 / den;
        //return ua >= 0.0 && ua <= 1.0 && ub >= 0.0 && ub <= 1.0;

    }

求两线段的交点

如果存在交点,则返回true,交点坐标为(x, y);否则返回false。

bool calc_intersection(double ax, double ay, double bx, double by, double cx, double cy, double dx, double dy, double* x, double* y)
    {
        double num = (ay-cy) * (dx-cx) - (ax-cx) * (dy-cy);
        double den = (bx-ax) * (dy-cy) - (by-ay) * (dx-cx);
        double intersection_epsilon = 1.0e-30;
        if(fabs(den) < intersection_epsilon) return false;
        double r = num / den;
        *x = ax + r * (bx-ax);
        *y = ay + r * (by-ay);
        return true;
    }

代码摘自:agg_math.h

### 判断两条线是否相交计算交点 为了确定两条线是否相交,可以采用几何方法来解决这个问题。具体来说,可以通过向量叉积的方式来检测两线是否有交叉。 #### 向量叉积法 对于给定的两个端点分别为 \((x_1, y_1)\),\((x_2, y_2)\) 的第一条线段 \(L_1\) 和另一条具有不同端点 \((x_3, y_3)\),\((x_4, y_4)\) 的第二条线段 \(L_2\) ,如果这两条线相交,则意味着存在某个时刻一条线段上的任意一点到另外一条线段两端点所形成的三角形方向相反[^1]。 通过计算四个叉乘值: \[ d1 = direction(p3, p4, p1); \] \[ d2 = direction(p3, p4, p2); \] \[ d3 = direction(p1, p2, p3); \] \[ d4 = direction(p1, p2, p4); \] 其中 `direction` 函数定义如下: ```cpp double direction(Point pi, Point pj, Point pk){ return (pj.x - pi.x)*(pk.y - pi.y)-(pk.x - pi.x)*(pj.y - pi.y); } ``` 当满足条件 `(d1 * d2 < 0)` `(d3 * d4 < 0)` 时,说明两条线确实发生了交叉。 #### 计算交点坐标 一旦确认了两条直线会相交之后,就可以利用参数方程解具体的交点了。设第一个线段的方向向量为 \(\vec{v}=(dx1=x_2-x_1,\ dy1=y_2-y_1)\),第二个线段的方向向量为 \(\vec{w}=(dx2=x_4-x_3,\ dy2=y_4-y_3)\)。 令 t 表示沿着 L1 移动的比例因子;u 表示沿 L2 移动的比例因子。那么可以根据下面公式得到交点位置: \[ u=((x_1-x_3)*(dy1)-(y_1-y_3)*(dx1))/((dx2*dy1-dx1*dy2)) \] \[ x=x_3+u*dx2; \] \[ y=y_3+u*dy2; \] 这里需要注意的是,在实际编程实现过程中应该考虑除数可能为零的情况(即平行或共线),此时应返回不相交的结果。 ```cpp Point getIntersection(Point p1, Point p2, Point p3, Point p4){ double dx1=p2.x-p1.x; double dy1=p2.y-p1.y; double dx2=p4.x-p3.x; double dy2=p4.y-p3.y; double denom=dx2*dy1-dx1*dy2; if(denom==0){ // parallel or collinear throw std::invalid_argument("Lines do not intersect"); } double ua=((p3.x-p1.x)*dy2-(p3.y-p1.y)*dx2)/denom; double ub=((p2.x-p1.x)*dy1-(p2.y-p1.y)*dx1)/denom; if(ua>=0 && ua<=1 && ub>=0 && ub<=1){ return {p1.x+ua*(p2.x-p1.x), p1.y+ua*(p2.y-p1.y)}; }else{ throw std::invalid_argument("Lines do not intersect within segment bounds"); } } ``` 上述算法能够有效地判断两条线之间是否存在交集,能精确地定位出交点的位置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值