我使用 thunderforest API 在地图上绘制点。我想出了如何使用 this 缩放经度轴以使其适合地图。基本上我知道我的地图的宽度(以像素为单位),并且我知道每个缩放级别的 256 像素对应多少经度。这样我就可以算出我的地图的经度有多宽。
我的地图的像素高和宽一样(即 1100x1100)。因此,在缩放级别为 14 时,1100 像素的宽度对应于 0.09453125° 经度。我现在假设 1100 像素的高度对应于 0.09453125° 纬度。但这是错误的。 正如您在此地图中所看到的,这些点应该是围绕启动点的一个圆圈。但它们的形状更像是椭圆形。
我在 openstreetmap 网站上找到了这个。
“米/像素”列中列出的值给出了 256 像素宽图块在该缩放级别下每像素的米数。这些“米/像素”值是根据地球半径 6372.7982 公里计算的,并保持在赤道;对于其他纬度,这些值必须乘以纬度的余弦(近似假设大地水准面的完美球形)。
但我不知道什么我需要乘以cos(纬度)。有人可以帮我弄清楚在这里该怎么做吗?
我的完整代码:
# data
launch_latitude = np.degrees(TOTAL_DATA[0]['TYPE_LATITUDE'][0][0])
launch_longitude = np.degrees(TOTAL_DATA[0]['TYPE_LONGITUDE'][0][0])
# variabels
zoom_level = 14 # 0 <= int <= 20
map_width_pixel = 1100 # max: 2560
save_fig = True
plot_name = 'name'
plot_title = 'NAME'
img_name = f'z{zoom_level}_w{map_width_pixel}_{launch_latitude}N_{launch_longitude}E.png'
img_path = f'../env/images/{img_name}'
tile_width_at_zoom_level = {0:360,1:180,2:90,3:45,4:22.5,5:11.25,6:5.625,7:2.813,8:1.406,9:0.703,10:0.352,11:0.176,12:0.088,13:0.044,14:0.022,15:0.011,16:0.005,17:0.003,18:0.001,19:0.0005,20:0.00025}
map_width_deg = tile_width_at_zoom_level[zoom_level]/256 * map_width_pixel
padding_long = map_width_deg/2
padding_lat = map_width_deg/2
BBox = [launch_longitude - padding_long, launch_longitude + padding_long, launch_latitude - padding_lat, launch_latitude + padding_lat]
# download map, if image doesn't allready exist.
if not os.path.isfile(img_path):
# get URL
zoom = zoom_level
style = 'Landscape'
apikey = '--- API KEY ---'
lon, lat = launch_longitude, launch_latitude
width, height = map_width_pixel, map_width_pixel
URL = f'https://tile.thunderforest.com/static/{style}/{lon},{lat},{zoom}/{width}x{height}.png?apikey={apikey}'
# save img
r = requests.get(URL, stream=True)
r.raw.decode_content = True
with open(img_path,'wb') as f:
shutil.copyfileobj(r.raw, f)
# plot
fig, ax = plt.subplots(figsize = (18,7))
map_img = plt.imread(img_path)
attribution = 'Maps © www.thunderforest.com, Data © www.osm.org/copyright'
ax.imshow(map_img, zorder=0, extent = BBox, aspect= 'equal')
ax.scatter(launch_longitude, launch_latitude, zorder=4, marker='^', color='black', label='Launch')
for zorder, raw_data, label in zip([1,2,3], TOTAL_DATA, ['Nominal Flight', 'No Main', 'No Parachute']):
land_latitude = [np.degrees(flight[-1]) for flight in raw_data['TYPE_LATITUDE']]
land_longitude = [np.degrees(flight[-1]) for flight in raw_data['TYPE_LONGITUDE']]
ax.scatter(land_longitude, land_latitude, zorder=zorder, marker='x', label=label)
ax.set_title(f'{plot_title} Dropzone Analysis')
ax.set_xlim(BBox[0],BBox[1])
ax.set_ylim(BBox[2],BBox[3])
ax.set_xlabel('Longitude [WGS84]')
ax.set_ylabel('Latitude [WGS84]')
ax.text(x=1, y=0.01, s=attribution, horizontalalignment='right', verticalalignment='bottom', rotation='vertical', fontsize=8, color='gray', alpha=0.9, transform=ax.transAxes)
ax.legend()
if save_fig:
plt.savefig(f'../results/{plot_name}_dropzone_analysis.pdf')
plt.show()
纬度的缩放方式与现实生活中的经度不同。这与 Thunderforest 或 openstreetmap 无关。
在北极时,要穿越 180⁰ 纬度,您需要向南(或向北、向西,或者任何您想要的直线方向)步行 20000 公里。
要行驶 180⁰ 经度,只需掉头即可。如果你碰巧是一名托钵僧,你可以在几秒钟内穿越数千度的经度。对纬度执行同样的操作需要花费很长时间。
仅在赤道(大致),纬度和经度的缩放方式相同。
更准确地说,由于您的屏幕截图显示了纬度,我可以告诉您,1100 个像素对应于
0.09453125°xcos(39.44) = 0.073
纬度,如果它们代表 0.09453125° 经度,那么您所在的位置。
看图:
沿着“垂直”圆,即经线(穿过两极的子午线),1 度纬度(以与“水平”圆(平行线)的交点为标志)始终具有相同的距离。这些经线只是按纬度扇区均匀划分的圆圈。
这些经线都具有相同的直径(即地球直径)。
因此,沿子午线(沿南北方向)的 1⁰ 始终是地球周长的 1/360。
经度不一样。经度是您在“水平”圆(平行线)之一内的位置。它们的间距也均匀。因此,沿平行线的 1⁰,又称为经度 1⁰,也是圆的周长的 1/360。但并非所有这些圆,并非所有平行圆都具有相同的直径,因此它们不具有相同的周长。
如果你想一下这些圆的直径是多少,那就很容易了。看看那个扁平的图像(请原谅我的法语,乱七八糟):
您会看到,如图所示,一旦投影成平面,每条平行线的直径就是线的长度。因此,纬度 40⁰ 处的平行半径就是该图像上标记为 40⁰ 的线的长度。这个长度很容易计算。它是 x 轴(又名赤道)的长度乘以 cos(40)。
就您而言,您位于纬度 39.44 度的平行线上。所以平行线的直径是 cos(39.44) 乘以赤道的直径。所以平行线 39.44 的周长也是 cos(39.44) 赤道的周长。由于赤道的周长(大致)是子午线的周长,因此您可以得出结论,平行线在 39.44 处的周长是 cos(39.44) 子午线的周长。
因此,该平行线的弧(0.09 度)也是 cos(39.44) 同一位置处子午线 0.09 度的弧的大小。