目录
一、基本思路
本文主要处理的是相交和不相交,因为地理数据保存较多,需要运用最小外接矩阵
1.根据radius_2_coordinate方法获得圆的最小外接矩阵
# 获取多边形的最小外接矩阵
max = np.max(num['polygonArr'], axis=0)
min = np.min(num['polygonArr'], axis=0)
2.筛选原矩阵与最小外接矩阵的交集
3.循环交集的内容,使用intersect_check_garden验证圆,使用intersect_check_polygon验证多边形
二、矩形和圆的关系
验证思路
圆和矩阵存在多种关系:圆在矩阵内,圆与矩阵相交,矩阵在圆内,圆与矩阵不相交。我的实际需求分析后发现,矩阵在园内与圆与矩阵相交可以同时验证。
1.圆在矩阵内
主要使用isInPolygon方法判断圆的圆心是否在矩阵内。
2.圆与矩阵相交,矩阵在圆内
运用的主要思路:计算圆心到矩阵四个边的最短距离,与圆的半径比较,存在小于半径的值,就是圆与矩阵相交,矩阵在圆内关系,反之,圆与矩阵不相交
import numpy as np
import math
from math import cos
def coordinate_2_radius(Longitude, Latitude):
'''
参考地址:https://blog.csdn.net/Dust_Evc/article/details/102847870?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-7.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-7.control
度数与弧度转化公式:1°=π/180°,1rad=180°/π。
地球半径:6371000M
地球周长:2 * 6371000M * π = 40030173
纬度38°地球周长:40030173 * cos38 = 31544206M
任意地球经度周长:40030173M
经度(东西方向)1M实际度:360°/31544206M=1.141255544679108e-5=0.00001141
纬度(南北方向)1M实际度:360°/40030173M=8.993216192195822e-6=0.00000899
'''
# R = 6371000
# L = 2 * math.pi * R
Lng_l = 40030173 # 当前经度地球周长
Lat_l = Lng_l * cos(Latitude * math.pi / 180) # 当前纬度地球周长,弧度转化为度数
# print(Lat_l)
Lat_C = Lat_l / 360
Lng_C = Lng_l / 360
Latitude_m = Latitude * Lat_C
Longitude_m = Longitude * Lng_C
return Latitude_m, Longitude_m
def radius_2_coordinate(Longitude, Latitude, radius):
'''
参考地址:https://blog.csdn.net/Dust_Evc/article/details/102847870?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-7.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-7.control
度数与弧度转化公式:1°=π/180°,1rad=180°/π。
地球半径:6371000M
地球周长:2 * 6371000M * π = 40030173
纬度38°地球周长:40030173 * cos38 = 31544206M
任意地球经度周长:40030173M
经度(东西方向)1M实际度:360°/31544206M=1.141255544679108e-5=0.00001141
纬度(南北方向)1M实际度:360°/40030173M=8.993216192195822e-6=0.00000899
'''
Lng_l = 40076000 # 当前经度地球周长
Lat_l = Lng_l * cos(Latitude * math.pi / 180) # 当前纬度地球周长,弧度转化为度数
Lat_C = Lat_l / 360
Lng_C = Lng_l / 360
radius_lat = radius / Lat_C
radius_lng = radius / Lng_C
# print(radius_lng, radius_lat)
return radius_lat, radius_lng
def isInPolygon(point, polygon): ## 检测点是否在多边形内,输入([x,y], polygon_list也就是点组成的list)
# 使用水平射线检测
x, y = point[0], point[1]
nCross = 0
for i in range(len(polygon)):
p1 = polygon[i]
p2 = polygon[(i + 1) % len(polygon)]
# 特殊情况:边界p1p2 与 y=p0.y平行,不计数
if (p1[1] == p2[1]): continue
# 交点在p1p2延长线上,注意是小于,不计数
if (y < min(p1[1], p2[1])): continue
# 交点在p1p2延长线上,注意是大于等于,不计数
if (y >= max(p1[1], p2[1])): continue
# 求交点的 X 坐标;根据相似三角形计算
crossx = (y - p1[1]) * (p2[0] - p1[0]) / (p2[1] - p1[1]) + p1[0]
# 只统计单边交点
if (crossx >= x):
nCross = nCross + 1
# min_dis = get_dis_point2polygon(point, polygon)
# if abs(min_dis)<1e-2: ## 求点到哪个边距离最小,是否为0,为0则表示在边界上
# return 1
return (nCross % 2 == 1)
def get_nearest_distance(point, line):
# 获取线段 与 点的最短距离
# print('get_nearest_distance')
def get_foot(point, line):
# 获取直线 与 点的垂足
start_x, start_y = line[0], line[1]
end_x, end_y = line[2], line[3]
pa_x, pa_y = point
p_foot = [0, 0]
if line[0] == line[3]:
p_foot[0] = line[0]
p_foot[1] = point[1]
return p_foot
k = (end_y - start_y) * 1.0 / (end_x - start_x)
a = k
b = -1.0
c = start_y - k * start_x
p_foot[0] = (b * b * pa_x - a * b * pa_y - a * c) / (a * a + b * b)
p_foot[1] = (a * a * pa_y - a * b * pa_x - b * c) / (a * a + b * b)
return p_foot
def get_nearest_point(point, line):
# 计算点到线段的最近点
pt1_x, pt1_y = line[0], line[1]
pt2_x, pt2_y = line[2], line[3]
point_x, point_y = point[0], point[1]
if (pt2_x - pt1_x) != 0:
k = (pt2_y - pt1_y) / (pt2_x - pt1_x)
# 该直线方程为:
# y = k* ( x - pt1_x) + pt1_y
# 其垂线的斜率为 - 1 / k,
# 垂线方程为:
# y = (-1/k) * (x - point_x) + point_y
# 联立两直线方程解得:
x = (k ** 2 * pt1_x + k * (point_y - pt1_y) + point_x) / (k ** 2 + 1)
y = k * (x - pt1_x) + pt1_y
return (x, y)
elif min(pt1_y, pt2_y) < point[1] < max(pt1_y, pt2_y):
return get_foot(point, line)
else:
l1 = np.hypot(pt1_y - point[1], pt1_x - point[0])
l2 = np.hypot(pt2_y - point[1], pt2_x - point[0])
return (pt1_x, pt1_y) if l1 < l2 else (pt2_x, pt2_y)
nearest_point = get_nearest_point(point, line)
# print(nearest_point)
x, y = coordinate_2_radius(nearest_point[0], nearest_point[1])
point_x, point_y = coordinate_2_radius(point[0], point[1])
distance = math.sqrt((x - point_x) * (x - point_x) + (y - point_y) * (y - point_y))
# print(nearest_point[0], nearest_point[1], point[0], point[1], distance)
return distance
def intersect_check_garden(point_lng, point_lat, radius, q1_x, q1_y, q2_x, q2_y, q3_x, q3_y, q4_x, q4_y):
"""
与园的相交检查
"""
# print('intersect_check_garden')
radius_lng, radius_lat = radius_2_coordinate(point_lng, point_lat, radius)
# point_lng_max = point_lng + radius_lng
# point_lng_min = point_lng - radius_lng
# point_lat_max = point_lat + radius_lat
# point_lat_min = point_lat - radius_lat
# # 1.圆在图形内
# xmin = min(q1_x, q2_x, q3_x, q4_x)
# xmax = max(q1_x, q2_x, q3_x, q4_x)
# ymin = min(q1_y, q2_y, q3_y, q4_y)
# ymax = max(q1_y, q2_y, q3_y, q4_y)
if isInPolygon([point_lng, point_lat], [[q1_x, q1_y], [q2_x, q2_y], [q3_x, q3_y], [q4_x, q4_y]]):
print("圆在图形内")
return True
# if xmin < point_lng_max < xmax and xmin < point_lng_min < xmax:
# return True
#
# if ymin < point_lat_max < ymax and ymin < point_lat_min < ymax:
# return True
# 2.圆与图形相交为True,圆在图形不想交相交为False,
distance1 = get_nearest_distance([point_lng, point_lat], [q1_x, q1_y, q2_x, q2_y])
if distance1 < radius:
return True
distance2 = get_nearest_distance([point_lng, point_lat], [q2_x, q2_y, q3_x, q3_y])
if distance2 < radius:
return True
distance3 = get_nearest_distance([point_lng, point_lat], [q3_x, q3_y, q4_x, q4_y])
if distance3 < radius:
return True
distance4 = get_nearest_distance([point_lng, point_lat], [q4_x, q4_y, q1_x, q1_y])
if distance4 < radius:
return True
distance5 = get_nearest_distance([point_lng, point_lat], [q1_x, q1_y, q3_x, q3_y])
if distance5 < radius:
return True
distance6 = get_nearest_distance([point_lng, point_lat], [q2_x, q2_y, q4_x, q4_y])
if distance6 < radius:
return True
return False
三、矩形和多边形的关系
本文主要处理的是相交和不相交,基本思路:
验证思路:
多边形和矩阵存在多种关系:多边形在矩阵内,多边形与矩阵相交,矩阵在多边形内,多边形与矩阵不相交。我的实际需求分析后发现,矩阵在多边形内和多边形与矩阵相交可以同时验证。
1.多边形在矩阵内
主要使用isInPolygon方法判断圆的圆心是否在矩阵内。
2.多边形与矩阵相交,矩阵在多边形内
思路:根据矩阵的4个点左边,生成4条线段,根据line_polygon方法判断线段与多边形的关系(根据实际需要等分,我这里是10等分,每个点计算与多边形的关系)
def intersect_check_polygon(polygon, q1_x, q1_y, q2_x, q2_y, q3_x, q3_y, q4_x, q4_y):
"""
与多边形的相交检查
polygon:多边形的list
"""
def get_points(start_x, start_y, end_x, end_y):
# print(start_x, start_y, end_x, end_y)
if end_x - start_x != 0:
k = (end_y - start_y) * 1.0 / (end_x - start_x)
# y = start_y + k * (x - start_x) # 2个点组成的直线
division = 10 # 线段切割次数
point_list = [] # 线段上点的集合
for i in range(0, division):
x = start_x * i / 10 + start_x
if x < end_x:
y = start_y + k * (x - start_x)
point_list.append([x, y])
return point_list
def line_polygon(polygon, start_x, start_y, end_x, end_y):
# 线段是否与多边形相交
points = get_points(start_x, start_y, end_x, end_y)
if points:
for point in get_points(start_x, start_y, end_x, end_y):
if isInPolygon(point, polygon):
return True
return False
# 1.多边形在图形内
if isInPolygon([polygon[0][0], polygon[0][1]], [[q1_x, q1_y], [q2_x, q2_y], [q3_x, q3_y], [q4_x, q4_y]]):
print("多边形在图形内")
return True
# 2.图形与多边的相交为True,其他为False
if line_polygon(polygon, q1_x, q1_y, q2_x, q2_y):
return True
if line_polygon(polygon, q2_x, q2_y, q3_x, q3_y):
return True
if line_polygon(polygon, q1_x, q1_y, q2_x, q2_y):
return True
if line_polygon(polygon, q3_x, q3_y, q4_x, q4_y):
return True
if line_polygon(polygon, q2_x, q2_y, q4_x, q4_y):
return True
if line_polygon(polygon, q1_x, q1_y, q3_x, q3_y):
return True
return False
参考链接:
python进行点和线段、直线、多边形的交点、距离,垂直等处理——代码_nature1949的博客-CSDN博客_python两点求直线方程