这道题也是一道经典的面试题,即分别给出两条线段在平面直角坐标系下的端点坐标,判断这两条线段是否相交(这里的相交定义为有且只有一个公共点)。
这道题如果用传统的解析几何思维,那就是求出这两条线段所在直线的方程,判断是否平行,若不平行,再算出两直线的交点,最后计算交点是否在线段上。这样做思路比较简单,但是实现起来可能会遇到各种各样的问题,例如若线段所在直线倾角等于或接近90°,在计算过程中会出现除数等于0或非常接近0的情况,这种情况下可能会出现较大的精度损失,不是一种明智的方法。
对于两条线段,如果相交则有以上两种情况:
1)每条线段都分别跨越了另一条线段所在直线,即两个端点分别在该直线两侧;
2)一条线段的端点恰好在另一条线段上。
这里我们可以用向量叉积来判断跨立条件,如下图所示,如果线段ab跨立了线段cd所在的直线,那么作向量ca、cd和cb,其中ca×cd和cb×cd的正负号应该是不同的。即满足
ca×cd和cb×cd < 0
考虑到情况2),上式等于0的情况也成立,因此,判断线段ab跨立线段cd所在直线的的条件为
ca×cd和cb×cd <= 0

因此,两线段相交的充要条件应该是彼此跨立。
下面附上Python实现的代码,用Python是因为可以用matplotlib画图检验。
import matplotlib.pyplot as plt
def multiply(v1, v2):
"""
计算两个向量的叉积
"""
return v1.x*v2.y - v2.x*v1.y
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __sub__(self, other):
"""
重载减法运算,计算两点之差,实际上返回的表示该点到另一点的向量
:param other: 另一个点
:return: 该点到另一点的向量
"""
return Point(self.x-other.x, self.y-other.y)
class Segment:
def __init__(self, point1, point2):
self.point1 = point1
self.point2 = point2
def straddle(self, another_segment):
"""
:param another_segment: 另一条线段
:return: 如果另一条线段跨立该线段,返回True;否则返回False
"""
v1 = another_segment.point1 - self.point1
v2 = another_segment.point2 - self.point1
vm = self.point2 - self.point1
if multiply(v1, vm) * multiply(v2, vm) <= 0:
return True
else:
return False
def is_cross(self, another_segment):
"""
:param another_segment: 另一条线段
:return: 如果两条线段相互跨立,则相交;否则不相交
"""
if self.straddle(another_segment) and another_segment.straddle(self):
return True
else:
return False
def cross(self, another_segment):
if self.is_cross(another_segment):
print('两线段相交.')
else:
print('两线段不相交.')
plt.plot([self.point1.x, self.point2.x], [self.point1.y, self.point2.y])
plt.plot([another_segment.point1.x, another_segment.point2.x],
[another_segment.point1.y, another_segment.point2.y])
plt.show()测试样例1(相交的情况2):
A = Point(0, 0)
B = Point(2, 2)
C = Point(1, 1)
D = Point(0, 2)
AB = Segment(A, B)
CD = Segment(C, D)
AB.cross(CD)输出结果:
两线段相交.

本文探讨如何利用向量叉积判断两条线段在平面直角坐标系中是否相交,包括线段相交的两种情况,并提供Python实现代码进行验证。

6364

被折叠的 条评论
为什么被折叠?



