基于GPS坐标数据,如何用Python+Matplotlib绘制斜向椭圆形赛道?
斜向椭圆赛道绘制及轨迹约束实现方案
问题背景
我手头有数百条包含X、Y值的GPS坐标字典数据,转换后得到了MaxX、MaxY、MinX、MinY四个极值。已经用Matplotlib画出了极值红点和特定选手的运动轨迹绿点,需要绘制内外斜向椭圆赛道,要求轨迹绿点既不超出外椭圆边界,也不进入内椭圆区域,但一开始搞不懂斜向椭圆的计算和绘制方法,后来在Brock Brown的帮助下搞定了需求。
1. 斜向椭圆的核心逻辑
斜向椭圆就是标准椭圆经过平移+旋转变换后的结果,关键参数计算如下:
- 中心坐标:取极值的中点,
center_x = (MaxX + MinX)/2,center_y = (MaxY + MinY)/2 - 半轴长度:外椭圆基于极值差放大5%(避免轨迹贴边),内椭圆取外椭圆半轴的90%;比如外椭圆长半轴
a_outer = (MaxX - MinX)/2 * 1.05,短半轴b_outer = (MaxY - MinY)/2 * 1.05 - 旋转角度:根据极值点的分布方向计算,用
np.arctan2(MaxY - MinY, MaxX - MinX)得到弧度后转成角度即可
2. Matplotlib绘制斜向椭圆代码
直接用Matplotlib的Ellipse类就能实现,它原生支持旋转参数:
import matplotlib.pyplot as plt import numpy as np # 替换成你的实际极值数据 MaxX, MinX = 100, 0 MaxY, MinY = 80, 20 # 计算椭圆核心参数 center = ((MaxX + MinX)/2, (MaxY + MinY)/2) # 外椭圆半轴(放大5%预留边界) a_outer = (MaxX - MinX)/2 * 1.05 b_outer = (MaxY - MinY)/2 * 1.05 # 内椭圆半轴(缩小10%形成赛道区域) a_inner = a_outer * 0.9 b_inner = b_outer * 0.9 # 旋转角度(弧度转成Matplotlib需要的角度值) rotate_angle = np.degrees(np.arctan2(MaxY - MinY, MaxX - MinX)) # 创建画布 fig, ax = plt.subplots(figsize=(8,8)) # 绘制外椭圆(灰色半透明填充,黑色边框) outer_ellipse = plt.matplotlib.patches.Ellipse( center, 2*a_outer, 2*b_outer, angle=rotate_angle, facecolor='#cccccc', alpha=0.3, edgecolor='black', linewidth=1.5 ) ax.add_patch(outer_ellipse) # 绘制内椭圆(白色填充覆盖背景,形成赛道区域) inner_ellipse = plt.matplotlib.patches.Ellipse( center, 2*a_inner, 2*b_inner, angle=rotate_angle, facecolor='white', edgecolor='black', linewidth=1.5 ) ax.add_patch(inner_ellipse) # 绘制极值红点 ax.scatter([MaxX, MinX, MaxX, MinX], [MaxY, MinY, MinY, MaxY], color='red', s=60, zorder=3) # 绘制选手轨迹绿点(替换成你的实际轨迹数据) np.random.seed(42) track_x = np.random.uniform(MinX+5, MaxX-5, 120) track_y = np.random.uniform(MinY+5, MaxY-5, 120) ax.scatter(track_x, track_y, color='green', s=30, zorder=2) # 配置坐标轴,保证椭圆比例正确 ax.set_xlim(MinX - 10, MaxX + 10) ax.set_ylim(MinY - 10, MaxY + 10) ax.set_aspect('equal') plt.title('斜向椭圆赛道与选手轨迹') plt.show()
3. 轨迹点的约束验证
要确保轨迹点落在内外椭圆之间的赛道区域,可以通过坐标变换代入标准椭圆方程判断:
def check_point_valid(x, y, center, outer_a, outer_b, rotate_angle): # 平移到椭圆中心 dx = x - center[0] dy = y - center[1] # 逆旋转,将点转换到椭圆的局部坐标系 rad = np.radians(rotate_angle) dx_rot = dx * np.cos(rad) + dy * np.sin(rad) dy_rot = -dx * np.sin(rad) + dy * np.cos(rad) # 验证是否在外椭圆内、内椭圆外(允许微小误差) in_outer = (dx_rot/outer_a)**2 + (dy_rot/outer_b)**2 <= 1.01 out_inner = (dx_rot/(outer_a*0.9))**2 + (dy_rot/(outer_b*0.9))**2 >= 0.99 return in_outer and out_inner # 批量验证轨迹点 valid_count = 0 for x, y in zip(track_x, track_y): if check_point_valid(x, y, center, a_outer, b_outer, rotate_angle): valid_count +=1 print(f"符合赛道约束的轨迹点数量:{valid_count}/{len(track_x)}")
内容的提问来源于stack exchange,提问作者SocketLearner1302
相关产品推荐
相关产品推荐

