两个线段距离的一个定理证明 和代码实现.
复杂度O(1)
#计算两个线段之间的最短距离:
#暴力遍历两边所有点求点之间距离最小速度N方.
import cv2,math
def jiajiao(line1, line2):
line1with_x_axis=math.atan((-line1[3]+line1[1])/(line1[2]-line1[0]))/math.pi*180 if line1[2]!=line1[0] else 90
line2with_x_axis=math.atan((-line2[3]+line2[1])/(line2[2]-line2[0]))/math.pi*180 if line2[2]!=line2[0] else 90
aaa= abs(line1with_x_axis-line2with_x_axis)
return aaa if aaa<90 else 180-aaa
pass
pass
def cross_point(line1, line2): # 计算交点函数======双点型直线.
#是否存在交点
point_is_exist=False
x=0
y=0
x1 = line1[0] # 取四点坐标
y1 = line1[1]
x2 = line1[2]
y2 = line1[3]
x3 = line2[0]
y3 = line2[1]
x4 = line2[2]
y4 = line2[3]
if (x2 - x1) == 0:
k1 = None
else:
k1 = (y2 - y1) * 1.0 / (x2 - x1) # 计算k1,由于点均为整数,需要进行浮点数转化
b1 = y1 * 1.0 - x1 * k1 * 1.0 # 整型转浮点型是关键
if (x4 - x3) == 0: # L2直线斜率不存在操作
k2 = None
b2 = 0
else:
k2 = (y4 - y3) * 1.0 / (x4 - x3) # 斜率存在操作
b2 = y3 * 1.0 - x3 * k2 * 1.0
if k1 is None:
if not k2 is None:
x = x1
y = k2 * x1 + b2
point_is_exist=True
elif k2 is None:
x=x3
y=k1*x3+b1
elif not k2==k1:
x = (b2 - b1) * 1.0 / (k1 - k2)
y = k1 * x * 1.0 + b1 * 1.0
point_is_exist=True
return point_is_exist,[x, y]
def cross_point_of_line_and_point(line1,point):
#给一个线段和一个点.计算他们之间的最短距离.
#思路: 算点到直线的距离,看交点是否在线段上,不在线段上,就算2次两点距离就完事了.
#计算点斜式.
x1 = line1[0] # 取四点坐标
y1 = line1[1]
x2 = line1[2]
y2 = line1[3]
if (x2 - x1) == 0:
k1 = None #竖直的直线.
else:
k1 = (y2 - y1) * 1.0 / (x2 - x1) # 计算k1,由于点均为整数,需要进行浮点数转化
if not k1:
k2=0
else:
k2=-1/k1
line2=[point[0],point[1],point[0]+1,point[1]+k2]
point_is_exist,[x, y]=cross_point(line1,line2)
return [x,y]
def distance_of_line_and_point(line1,point):
#给一个线段和一个点.计算他们之间的最短距离.
#思路: 算点到直线的距离,看交点是否在线段上,不在线段上,就算2次两点距离就完事了.
#计算点斜式.
x1 = line1[0] # 取四点坐标
y1 = line1[1]
x2 = line1[2]
y2 = line1[3]
if (x2 - x1) == 0:
k1 = None #竖直的直线.
else:
k1 = (y2 - y1) * 1.0 / (x2 - x1) # 计算k1,由于点均为整数,需要进行浮点数转化
if not k1:
k2=0
else:
k2=-1/k1
line2=[point[0],point[1],point[0]+1,point[1]+k2]
point_is_exist,[x, y]=cross_point(line1,line2)
return ((point[0]-x)**2+ (point[1]-y)**2 )**0.5
def distance_of_point_and_segment_line(line1,point):
#给一个线段和一个点.计算他们之间的最短距离.
#思路: 算点到直线的距离,看交点是否在线段上,不在线段上,就算2次两点距离就完事了.
#计算点斜式.
x1 = line1[0] # 取四点坐标
y1 = line1[1]
x2 = line1[2]
y2 = line1[3]
if (x2 - x1) == 0:
k1 = None #竖直的直线.
else:
k1 = (y2 - y1) * 1.0 / (x2 - x1) # 计算k1,由于点均为整数,需要进行浮点数转化
if not k1:
k2=0
else:
k2=-1/k1
line2=[point[0],point[1],point[0]+1,point[1]+k2]
point_is_exist,[x, y]=cross_point(line1,line2)
if x>=min(line1[0],line1[2]) and x<=max(line1[0],line1[2]): #交点在直线上.
disc= ((point[0]-x)**2+ (point[1]-y)**2 )**0.5
return disc
else:
disc1=((point[0]-line1[0])**2+ (point[1]-line1[1])**2 )**0.5
disc2=((point[0]-line1[2])**2+ (point[1]-line1[3])**2 )**0.5
return min(disc1,disc2)
def compute_dis_of_two_segment_line(line1,line2):
# line1: [x1,y1,x2,y2] 用2个端点,四个数来表示一个直线
disc1=distance_of_point_and_segment_line(line1,[line2[0],line2[1]])
disc2=distance_of_point_and_segment_line(line1,[line2[2],line2[3]])
disc3=distance_of_point_and_segment_line(line2,[line1[0],line1[1]])
disc4=distance_of_point_and_segment_line(line2,[line1[2],line1[3]])
return min(disc1,disc2,disc3,disc4)
pass
if __name__ =='__main__':
print('测试两条直线的夹角',jiajiao([1,2,3,4],[6,2,8,5]))
print('测试点跟直线的交点',cross_point_of_line_and_point([1,2,3,4],[0,0]))
print('测试点跟直线的距离',distance_of_line_and_point([1,2,3,4],[0,0]))
print('测试点跟线段的距离',distance_of_point_and_segment_line([1,2,3,4],[0,0]))
#=========根据我博客上面的定理, 两个线段之间的距离等价于四个点到直线的距离取min即可.
print('测试线段跟线段的距离',compute_dis_of_two_segment_line([1,2,3,4],[6,2,8,5]))
测试两条直线的夹角 11.309932474020215
测试点跟直线的交点 [-0.5, 0.5]
测试点跟直线的距离 0.7071067811865476
测试点跟线段的距离 2.23606797749979
测试线段跟线段的距离 3.605551275463989