算法描述:
将文件中线段两端点的坐标储存在两个多边形列表内,分别判断各边有无交点,若无交点,分别计算:(1)多边形A的点到多边形B的点的距离(2)多边形A的点到多边形B的边的距离(3)多边形B的点到多边形A的边的距离,计算点到线段的距离时,先过点作垂直于线段的直线,并判断直线与线段是否相交,若相交,则利用距离公式计算,否则此距离为无效距离,予以舍弃,最后取最小距离作为两个多边形的距离。
#判断两个封闭多边形的关系,并求其最小间距
def Readf():#读取文件
ls = []
ls1 = []
ls2 = []
lines = open("Polygon.txt").readlines()
for line in lines:
line = line.strip('\n').split(',')
if line[0] == 'A1':
ls1.append([(eval(line[1]),eval(line[2])),(eval(line[3]),eval(line[4]))])
elif line[0] == 'A2':
ls2.append([(eval(line[1]),eval(line[2])),(eval(line[3]),eval(line[4]))])
return ls1, ls2
def Ltol(line1, line2):#判断两线段相交
x1,y1 = line1[0][0],line1[0][1]
x2,y2 = line1[1][0],line1[1][1]
x3,y3 = line2[0][0],line2[0][1]
x4,y4 = line2[1][0],line2[1][1]
if x1 > x2:#将x坐标小的点放在第一项
x1,y1,x2,y2 = x2,y2,x1,y1
if x3 > x4:
x3,y3,x4,y4 = x4,y4,x3,y3
if (x1>x4) or (x2<x3):#无公共区间则无交点
return 0
xmin, xmax = max(x1, x3), min(x2, x4)#求公共区间
try:
k1 = (y1-y2)/(x1-x2)#计算斜率
except:#l1斜率无穷
k1 = 0#不改变端点取值
try:
k2 = (y3-y4)/(x3-x4)
except:#l2斜率无穷
k2 = 0
y1 = y1 + k1 * (xmax - x1) #求出区间端点值
y2 = y2 + k1 * (xmin - x2)
y3 = y3 + k2 * (xmax - x3)
y4 = y4 + k2 * (xmin - x4)
if (x1==x2 and x3==x4):#处理斜率无穷大,若有一条线段斜率有限,变换后将成为一点
if (max(y1,y2)<min(y3,y4)) or (min(y1,y2)>max(y3,y4)):
return 0
else:
return 1
if (max(y1,y2)<min(y3,y4)) or (min(y1,y2)>max(y3,y4)):#根据端点值判断相交
return 0
else:
return 1
def Potopo(po1, po2):#判断两多边形相交
for l1 in po1:
for l2 in po2:
if Ltol(l1, l2):
return 1
return 0
def Dpp(p1, p2):#计算两点距离
d = pow(p1[0]-p2[0],2) + pow(p1[1]-p2[1],2)
d = pow(d,0.5)
return d
def Dpl(p, l):#计算点到线段距离
l_p = 10000#当线段长度超过此值时看作直线
x1,y1 = l[0][0],l[0][1]
x2,y2 = l[1][0],l[1][1]
if (x1 == x2):#线段竖直
if (p[1]>=min(y1,y2)) and (p[1]<=max(y1,y2)):
return abs(p[0]-x1)
else:
return l_p#无效距离
if (y1 == y2):#线段水平
if (p[0]>=min(x1,x2)) and (p[0]<=max(x1,x2)):
return abs(p[1]-y1)
else:
return l_p#无效距离
A = y2 - y1#求线段参数
B = x1 - x2
C = x1*(y1-y2) + y1*(x2-x1)
k = B/A#过点作与线段垂直的直线
line = [[p[0]-l_p,p[1]-k*l_p],[p[0]+l_p,p[1]+k*l_p]]
if Ltol(line, l):
return abs(A*p[0]+B*p[1]+C)/pow(A*A+B*B,0.5)
else:
return l_p #若直线与线段不相交则为无效距离
ls1, ls2 = Readf()
if Potopo(ls1, ls2):
print("两多边形相交")
else:
dmin = Dpp(ls1[0][0], ls2[0][0])
for l1 in ls1:
for l2 in ls2:
d1 = Dpp(l1[0], l2[0])#多边形A点到多边形B点的距离
d2 = Dpl(l1[0], l2)#多边形A点到多边形B边的距离
d3 = Dpl(l2[0], l1)#多边形B点到多边形A边的距离
if min(d1, d2, d3) < dmin:
dmin = min(d1, d2, d3)
if dmin:
print("两多边形不相交,最小间距{:.2f}".format(dmin))
else:
print("两多边形相交")