You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python Folium中绘制符合墨卡托投影变形的曲线?

解决方案:在Folium中绘制沿地球曲面的曲线(大圆航线投影)

Folium默认绘制的是平面直线(直接连接经纬度点的直线,并非地球曲面大圆航线的投影曲线),要实现需求,核心是生成大圆航线的中间点,再通过连接这些点模拟自然曲线。以下是两种可行方案:

方法一:球面插值生成大圆航线点集(高效准确)

这是你提到的XYZ坐标转换思路的具体实现,通过球面线性插值(SLERP)生成地球曲面上的等距点,再转回经纬度连接,效率和准确性都优于贝塞尔曲线方案。

代码实现

import numpy as np
import folium

def latlon_to_xyz(lat, lon):
    # 经纬度转三维笛卡尔坐标(单位球模型)
    lat_rad = np.radians(lat)
    lon_rad = np.radians(lon)
    x = np.cos(lat_rad) * np.cos(lon_rad)
    y = np.cos(lat_rad) * np.sin(lon_rad)
    z = np.sin(lat_rad)
    return x, y, z

def xyz_to_latlon(x, y, z):
    # 三维坐标转回经纬度
    lon = np.degrees(np.arctan2(y, x))
    lat = np.degrees(np.arcsin(z))
    return lat, lon

def generate_great_circle_points(start_lat, start_lon, end_lat, end_lon, num_points=50):
    # 生成大圆航线的中间插值点
    start_x, start_y, start_z = latlon_to_xyz(start_lat, start_lon)
    end_x, end_y, end_z = latlon_to_xyz(end_lat, end_lon)
    
    t = np.linspace(0, 1, num_points)
    dot_product = start_x*end_x + start_y*end_y + start_z*end_z
    theta = np.arccos(dot_product)
    sin_theta = np.sin(theta)
    
    # 处理两点重合的特殊情况
    if sin_theta < 1e-6:
        return [(start_lat, start_lon)] * num_points
    
    # 球面线性插值计算中间点
    x = np.sin((1-t)*theta) * start_x / sin_theta + np.sin(t*theta) * end_x / sin_theta
    y = np.sin((1-t)*theta) * start_y / sin_theta + np.sin(t*theta) * end_y / sin_theta
    z = np.sin((1-t)*theta) * start_z / sin_theta + np.sin(t*theta) * end_z / sin_theta
    
    latitudes, longitudes = xyz_to_latlon(x, y, z)
    return list(zip(latitudes, longitudes))

# 示例:绘制北京到纽约的大圆航线
m = folium.Map(location=[30, 120], zoom_start=3)
start_point = (39.9042, 116.4074)
end_point = (40.7128, -74.0060)
route_points = generate_great_circle_points(start_point[0], start_point[1], end_point[0], end_point[1], num_points=100)
folium.PolyLine(route_points, color='blue', weight=2).add_to(m)
m.save('great_circle_route.html')

说明

  • num_points可根据精度调整,50-100个点就能在墨卡托投影下呈现自然的曲面曲线;
  • 该方法基于球面几何计算,完全贴合地球曲面的航线路径,比贝塞尔曲线更准确。

方法二:调用Leaflet原生大圆航线功能

Folium底层依赖Leaflet.js,而Leaflet内置L.GreatCircle类可直接绘制大圆航线,无需手动计算插值点,适合快速实现需求。

代码实现

import folium

m = folium.Map(location=[30, 120], zoom_start=3)
# 注入Leaflet原生JS代码绘制大圆航线
custom_js = """
var start = L.latLng(39.9042, 116.4074);
var end = L.latLng(40.7128, -74.0060);
L.greatCircle(start, end, {color: 'red', weight: 2}).addTo(map);
"""
folium.Html(f'<script>{custom_js}</script>', script=True).add_to(m)
m.save('great_circle_leaflet.html')

说明

  • 直接利用Leaflet的原生能力,无需处理复杂数学计算;
  • 注意Folium生成的地图在JS中的实例名为map,若自定义了地图变量名需对应修改。

关于贝塞尔曲线方案的补充

贝塞尔曲线属于平面曲线,要匹配墨卡托投影下的大圆曲线,需要结合投影变形公式计算控制点,过程复杂且精度难以保证,同时生成曲线的效率远低于球面插值方案,不推荐使用。


内容的提问来源于stack exchange,提问作者Matthew H.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 19:23:12