Python 如何检查两个给定的线段是否相交(How to check if two given line segments intersect)

给定两条线段(p1, q1)和(p2, q2),判断给定的线段是否相交。
在讨论解决方案之前,让我们先定义方向的概念。平面中有序点三元组的方向可以是 
–逆时针 
–顺时针 
–共线 

下图显示了(a,b,c) 的不同可能方向

 方向在这里有什么用处? 
两条线段(p1,q1)和(p2,q2)相交,当且仅当以下两个条件之一得到验证时

1. 一般情况: 
– ( p1 , q1 , p2 ) 和 ( p1 , q1 , q2 ) 具有不同的方向,并且 
– ( p2 , q2 ,  p1 ) 和 ( p2 , q2 ,  q1 ) 具有不同的方向。

例子:  

2.特殊情况 
– ( p1 , q1 , p2 )、( p1 , q1 , q2 )、( p2 , q2 , p1 ) 和 ( p2 , q2 , q1 ) 均为共线,且 – ( p1 , q1 ) 和 ( p2 , q2 ) 
的 x 投影相交 – ( p1 , q1 ) 和 ( p2 , q2 )的 y 投影相交

例子:  

以下是基于上述想法的实现:

# A Python3 program to find if 2 given line segments intersect or not 
  
class Point: 
    def __init__(self, x, y): 
        self.x = x 
        self.y = y 
  
# Given three collinear points p, q, r, the function checks if  
# point q lies on line segment 'pr'  
def onSegment(p, q, r): 
    if ( (q.x <= max(p.x, r.x)) and (q.x >= min(p.x, r.x)) and 
           (q.y <= max(p.y, r.y)) and (q.y >= min(p.y, r.y))): 
        return True
    return False
  
def orientation(p, q, r): 
    # to find the orientation of an ordered triplet (p,q,r) 
    # function returns the following values: 
    # 0 : Collinear points 
    # 1 : Clockwise points 
    # 2 : Counterclockwise 
      
    # See https://www.geeksforgeeks.org/orientation-3-ordered-points/amp/  
    # for details of below formula.  
      
    val = (float(q.y - p.y) * (r.x - q.x)) - (float(q.x - p.x) * (r.y - q.y)) 
    if (val > 0): 
          
        # Clockwise orientation 
        return 1
    elif (val < 0): 
          
        # Counterclockwise orientation 
        return 2
    else: 
          
        # Collinear orientation 
        return 0
  
# The main function that returns true if  
# the line segment 'p1q1' and 'p2q2' intersect. 
def doIntersect(p1,q1,p2,q2): 
      
    # Find the 4 orientations required for  
    # the general and special cases 
    o1 = orientation(p1, q1, p2) 
    o2 = orientation(p1, q1, q2) 
    o3 = orientation(p2, q2, p1) 
    o4 = orientation(p2, q2, q1) 
  
    # General case 
    if ((o1 != o2) and (o3 != o4)): 
        return True
  
    # Special Cases 
  
    # p1 , q1 and p2 are collinear and p2 lies on segment p1q1 
    if ((o1 == 0) and onSegment(p1, p2, q1)): 
        return True
  
    # p1 , q1 and q2 are collinear and q2 lies on segment p1q1 
    if ((o2 == 0) and onSegment(p1, q2, q1)): 
        return True
  
    # p2 , q2 and p1 are collinear and p1 lies on segment p2q2 
    if ((o3 == 0) and onSegment(p2, p1, q2)): 
        return True
  
    # p2 , q2 and q1 are collinear and q1 lies on segment p2q2 
    if ((o4 == 0) and onSegment(p2, q1, q2)): 
        return True
  
    # If none of the cases 
    return False
  
# Driver program to test above functions: 
p1 = Point(1, 1) 
q1 = Point(10, 1) 
p2 = Point(1, 2) 
q2 = Point(10, 2) 
  
if doIntersect(p1, q1, p2, q2): 
    print("Yes") 
else: 
    print("No") 
  
p1 = Point(10, 0) 
q1 = Point(0, 10) 
p2 = Point(0, 0) 
q2 = Point(10,10) 
  
if doIntersect(p1, q1, p2, q2): 
    print("Yes") 
else: 
    print("No") 
  
p1 = Point(-5,-5) 
q1 = Point(0, 0) 
p2 = Point(1, 1) 
q2 = Point(10, 10) 
  
if doIntersect(p1, q1, p2, q2): 
    print("Yes") 
else: 
    print("No") 
      
# This code is contributed by Ansh Riyal  

 输出: 

No
Yes
No

时间复杂度: O(1)

空间复杂度:O(1)

资料来源: 
http://www.dcs.gla.ac.uk/~pat/52233/slides/Geometry1x1.pdf   

《算法导论》第三版,作者:Clifford Stein、Thomas H. Cormen、Charles E. Leiserson、Ronald L. Rivest

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值