判斷線段是否相交

# -*- coding: utf-8 -*- # @Time : 2019-09-18 16:55 # @Author : Jayce Wong # @ProjectName : job # @FileName : segment_cross.py # @Blog : https://blog.51cto.com/jayce1111 # @Github : https://github.com/SysuJayce """ Q:給定兩個線段的座標(也就是四個點的直角座標系座標),判斷這兩個線段是否相交 ### 判斷線段是否相交可以利用向量的叉乘 ### 假定輸入爲P1、P2、Q1、Q2四個點的座標,P1P2爲一條線段,Q1Q2爲另一條線段 兩條線段相交只有兩種情況 1. 其中一條線段的某一端點在另一條線段上; 2. 兩條線段形成X形。 首先判斷這四個點是否在另一條線段上,也就是說,判斷P1是否在線段Q1Q2上,P2是否在線段Q1Q2上... 如果上述判斷爲真,那麼這兩條線段相交。【解決了第一種情況】 如果沒有點在另一條線段上,那麼進行叉乘判斷。 先固定線段Q1Q2,然後以Q1爲軸,計算Q1P1和Q1Q2、Q1P2和Q1Q2的叉乘是否異號; 然後固定線段P1P2,然後以P1爲軸,計算P1Q1和P1P2、P1Q2和P1P2的叉乘是否異號。 當上述的叉乘都異號的時候,兩條線段相交。 【解決了第二種情況】 """ class Point: def __init__(self, x, y): self.x = x self.y = y def __sub__(self, other): return Point(self.x - other.x, self.y - other.y) class Segment: def __init__(self, point1, point2): self.point1 = point1 self.point2 = point2 self.x = point1.x - point2.x self.y = point1.y - point2.y def crossProduct(v1, v2): return v1.x * v2.y - v2.x * v1.y def onSegment(p, seg): """ 判斷點在不在一條線段上,關鍵在於: 1. 三點是否共線 2. 點p是否在線段的延長線上。 只要滿足了三點共線,且點p不在延長線上,那麼點p就在線段上。 判斷三點共線可以用向量的叉乘,三點共線即兩個向量平行,也就是叉乘結果爲零向量(對應到二維就是零) 當點p的橫縱座標都在線段端點之間的時候,點p不在延長線上。 :param p: :param seg: :return: """ # 先確保點p不在延長線上 if min(seg.point1.x, seg.point2.x) <= p.x <= max(seg.point1.x, seg.point2.x)\ and min(seg.point1.y, seg.point2.y) <= p.y <= max(seg.point1.y, seg.point2.y): # 然後確保這三個點形成的向量兩兩平行,這裏只要這三個向量中任意兩個平行,第三個一定也平行 if crossProduct(p - seg.point1, p - seg.point2) == 0: return True else: return False else: return False def isCross(p1, p2, q1, q2): p1p2 = Segment(p1, p2) q1q2 = Segment(q1, q2) p1q1 = Segment(p1, q1) p1q2 = Segment(p1, q2) q1p1 = Segment(q1, p1) q1p2 = Segment(q1, p2) # 判斷是否存在端點位於另一條線段上,是的話則兩條線段相交 if any([onSegment(p1, q1q2), onSegment(p2, q1q2), onSegment(q1, p1p2), onSegment(q2, p1p2)]): return True # 否則固定線段P1P2,判斷Q1和Q2是否在P1P2的兩側(計算叉乘) # 然後固定線段Q1Q2,判斷P1和P2是否在Q1Q2的兩側 # 如果上面的判斷均爲真,那麼這兩條線段形成一個X return (crossProduct(p1p2, p1q1) * crossProduct(p1p2, p1q2) < 0)\ and (crossProduct(q1q2, q1p1) * crossProduct(q1q2, q1p2) < 0) def main(): p1 = Point(0, 0) p2 = Point(2, 2) q1 = Point(1, 1) q2 = Point(0, 2) if isCross(p1, p2, q1, q2): print('Yes') else: print('No') if __name__ == '__main__': main()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章