Python判断线段是否相交,快速排斥+叉乘

1、快速排斥

  判断线段是否相交,如果需要判断很多次,最好能有一种没什么计算量的判别方法先粗略的进行一次判断。具体来说,如果线段ab和线段cd不相交,那么以他们为斜线画出的矩形一定不相交,如图所示:

可以看出,只要满足ab的最大x坐标小于cd的最小x坐标(第三竖排),或者cd的最大x坐标小于ab的最小x坐标(第一竖排),或者ab的最大y坐标小于cd的最小y坐标(以左下角为坐标原点的话第一横排),或者cd的最大y坐标小于ab的最小y坐标(以左下角为坐标原点的话第三横排),ab与cd就一定不相交,因此可以写出python代码如下:

#快速排斥实验,判断线段ab和线段cd是否不相交,不相交返回False,不能判断不相交返回True
def quick_judge(a,b,c,d):
    if (max(a.x,b.x) < min(c.x,d.x) or
        max(c.x,d.x) < min(a.x,b.x) or
        max(a.y,b.y) < min(c.y,d.y) or
        max(c.y,d.y) < min(a.y,b.y)) :
        return False
    else:
        return True

其中a,b,c,d都是自己定义的Point类型。

class Point():
    def __init__(self,x,y):
        self.x = x
        self.y = y

2、叉乘

有a(a.x,a.y),b(b.x,b.y),c(c.x,c.y),d(d.x,d.y)四个点,

向量ab可以表示为vectorA(b.x-a.x,b.y-b.x)

向量cd可以表示为vectorB(d.x-c.x,d.y-c.y)

vectorA叉乘vectorB的结果是(vectorA.x * vectorB.y - vectorA.y * vectorB.x)

用python代码表达:

#求向量ab和向量cd的叉乘
def xmult(a,b,c,d):
    vectorAx = b.x - a.x
    vectorAy = b.y - a.y
    vectorBx = d.x - c.x
    vectorBy = d.y - c.y
    return (vectorAx * vectorBy - vectorAy * vectorBx)

利用叉乘,我们可以判断两个点是否在一条直线或者线段两端,进而判断两条线段是否相交,如果点a和点b在直线cd的两端,同时,点c和点d在直线ab的两端,那么线段ab和线段cd就相交,如图所示:

 如何判断ab在cd两侧呢?向量cd叉乘向量ca,结果的符号可以表示将cd旋转到ca所在的直线的最短移动路径的方向,图中也就是逆时针,如果ab不在cd两侧,向量cd旋转到ca和cb应当是相同方向(即都是顺时针或都是逆时针),只有在如图所示的情况,ab分布在cd两侧时,cd旋转到ca和旋转到cb的方向才会不同。

  如果方向相同,cd叉乘ca的结果xmult1,乘上cd叉乘cb的结果xmult2,结果应该为正。方向不同这个结果则为负,也就是说如果xmult1 * xmult2 <0,就可以认为ab在cd的两侧。同理,认为ab叉乘ac = xmult3,ab叉乘ad=xmult4,那么如果cd在ab两侧,xmult3*xmult4<0。

代码如下:先进行快速排斥,如果快速排斥无法得出ab和cd不相交,再利用叉乘进行判断

#判断线段ab和线段cd是否相交,相交返回True,不相交返回False
def cross(a,b,c,d):
    #先进行快速排斥,以减小计算量
    if not quick_judge(a,b,c,d):
        return False
    #若快速排斥无法判断,使用叉乘判断是否相交
    #以c为公共点,分别判断向量cd到向量ca与到向量cb的方向,记为xmult1和xmult2。
    #若ab分布于cd两侧,xmult1 * xmult2应小于0。
    #同理若cd分布于ab两侧,xmult3 * xmult4应小于0。
    xmult1 = xmult(c,d,c,a)
    xmult2 = xmult(c,d,c,b)
    xmult3 = xmult(a,b,a,c)
    xmult4 = xmult(a,b,a,d)
    if xmult1 * xmult2 < 0 and xmult3 * xmult4 < 0:
        return True
    else:
        return False

此方法不考虑ab和cd在一条直线上的情况,因为我的应用场景不会出现这种情况。如果会出现,可自行写一个特殊情况的判断代码。

另外,多段线段和多段线段的相交判别,可以逐段进行判断,转换成单段线段和单段线段的判别问题。

  • 9
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值