如何用Python实现多边形中心向边界绘制等夹角辐条
原有代码问题
你写的代码存在三个核心错误,导致结果不符合预期:
- 中心点计算逻辑错误:取的是多边形外接矩形的几何中心,不是多边形本身的形心,不规则多边形下偏移明显
- 角度传参错误:预先生成了等间隔角度数组
theta,但循环计算端点时用的是循环索引i代入三角函数,完全没有用到预生成的等间隔角度 - 端点计算逻辑错误:直接取中心到最远顶点的距离作为辐条长度,端点落在多边形外部,没有计算射线和多边形边界的真实交点
正确实现方案
实现等夹角辐条的核心逻辑分4步:
- 计算多边形的真实形心作为辐条公共起点
- 生成0到2π范围内n个等间隔的角度值,保证相邻辐条夹角为
2π/n - 对每个角度,构造从形心出发、长度足够穿出多边形的射线
- 计算每条射线和多边形边的第一个交点,作为辐条的外端点,连接形心和该交点即为符合要求的辐条
首先安装依赖库:pip install shapely matplotlib numpy
完整可运行代码如下:
import math import numpy as np import matplotlib.pyplot as plt from shapely.geometry import Polygon, LineString def draw_equal_angle_spokes(polygon_coords, n_spokes=8): # 构造多边形对象并自动闭合 poly = Polygon(polygon_coords) # 计算多边形真实形心 center = np.array([poly.centroid.x, poly.centroid.y]) xc, yc = center # 生成n个等间隔角度,不包含终点避免0度和360度重合 angles = np.linspace(0, 2*math.pi, n_spokes, endpoint=False) # 取多边形外接矩形长边的1.5倍作为射线初始长度,保证能穿出多边形 ray_length = max(poly.bounds[2]-poly.bounds[0], poly.bounds[3]-poly.bounds[1]) * 1.5 spokes = [] spoke_endpoints = [] for theta in angles: # 构造射线远端临时点 ray_temp_end = np.array([ xc + ray_length * math.cos(theta), yc + ray_length * math.sin(theta) ]) ray = LineString([center, ray_temp_end]) # 计算射线和多边形边界的交点 intersection = ray.intersection(poly.boundary) # 取离中心最近的交点作为辐条外端点 if intersection.geom_type == 'MultiPoint': closest_pt = min(intersection.geoms, key=lambda p: math.hypot(p.x-xc, p.y-yc)) end_pt = np.array([closest_pt.x, closest_pt.y]) elif intersection.geom_type == 'Point': end_pt = np.array([intersection.x, intersection.y]) else: # 跳过射线与边重合的极端特殊情况 continue spokes.append(LineString([center, end_pt])) spoke_endpoints.append(end_pt) return center, np.array(spoke_endpoints), spokes, poly if __name__ == "__main__": poly_coords = [(4.494258, 7.935927), (4.916178, 9.410432), (7.957516, 9.331792), (7.922356, 6.500743), (9.768255, 7.346126), (9.961635, 2.765333), (8.045416, 1.074568), (7.834456, 3.885956), (6.428057, 1.172868), (0.644241, 2.745672), (2.402240, 5.203180), (1.241961, 5.812641), (2.138540, 8.211168)] center, endpoints, spokes, poly = draw_equal_angle_spokes(poly_coords, n_spokes=12) # 结果可视化 plt.figure(figsize=(8,8)) # 绘制多边形边界 x, y = poly.exterior.xy plt.plot(x, y, c='black', linewidth=1, label='多边形边界') # 绘制所有辐条 for spoke in spokes: sx, sy = spoke.xy plt.plot(sx, sy, c='royalblue', linewidth=1.5) # 绘制标记点 plt.scatter(np.array(poly_coords)[:,0], np.array(poly_coords)[:,1], c='r', s=15, label='多边形顶点') plt.scatter(center[0], center[1], c='green', s=50, marker='*', label='多边形形心') plt.scatter(endpoints[:,0], endpoints[:,1], c='orange', s=20, marker='x', label='辐条端点') plt.axis('equal') plt.legend() plt.show()
效果说明
运行代码可得到符合要求的结果:
- 所有辐条从多边形真实形心出发,端点全部落在多边形边界上
- 任意相邻两根辐条的夹角完全相等,可通过修改
n_spokes参数自由调整辐条数量 - 不会出现原有代码中中心点偏移、角度错位、端点落在多边形外的问题
内容的提问来源于stack exchange,提问作者Masoumeh
相关产品推荐
相关产品推荐

