Love2D渲染OSM地图出现垂直压缩变形,求修正方法
解决Love2D中OSM地图垂直压缩的正确纬度转换方法
你的核心问题是误用了反墨卡托投影函数处理原始纬度,导致转换逻辑完全颠倒,这才出现高纬度区域变形的问题。下面是正确的实现步骤和代码:
1. 正确的墨卡托投影公式
墨卡托投影的核心是将地理纬度转换为等角平面坐标,正确的正向转换(从纬度到投影Y坐标)公式为:
$$ Y = \ln\left(\tan\left(\frac{\pi}{4} + \frac{\text{lat}_\text{rad}}{2}\right)\right) $$
对应的Lua实现:
-- 输入:十进制纬度lat、十进制经度lon -- 输出:墨卡托投影后的x, y坐标 local function mercatorProject(lat, lon) local radLat = math.rad(lat) -- 计算墨卡托Y坐标 local y = math.log(math.tan(math.pi / 4 + radLat / 2)) -- 经度直接作为X坐标(墨卡托X与经度线性对应) return lon, y end
你之前写的mercatorY函数是反墨卡托转换(把投影Y坐标转回地理纬度),用来处理原始纬度自然会导致变形。
2. 调整OSM渲染流程
修改原处理步骤,适配正确的投影逻辑:
- 步骤1:解析XML提取nodes和ways(保持不变)
- 步骤2:对每个node的
lat和lon,用上述mercatorProject函数转换为投影后的(x, y)坐标 - 步骤3:基于投影后的坐标计算边界框(minX, maxX, minY, maxY),再计算统一缩放因子:
-- screenW、screenH为Love2D窗口的宽高 local xRange = maxX - minX local yRange = maxY - minY -- 取宽高方向的最小缩放比例,保证地图完整显示且比例正确 local scale = math.min(screenW / xRange, screenH / yRange) - 步骤4:计算坐标偏移,将投影后的坐标平移到屏幕可视区域后绘制:
-- 先平移到以minX、minY为原点,再缩放,最后居中显示 local offsetX = (screenW - xRange * scale) / 2 - minX * scale local offsetY = (screenH - yRange * scale) / 2 - minY * scale -- 绘制时应用坐标转换 love.graphics.push() love.graphics.translate(offsetX, offsetY) love.graphics.scale(scale, scale) -- 遍历ways绘制线条 for _, way in ipairs(ways) do local points = {} for _, nodeId in ipairs(way.nodeIds) do local node = nodes[nodeId] table.insert(points, node.projX) table.insert(points, node.projY) end love.graphics.line(points) end love.graphics.pop()
3. 关键注意事项
- 墨卡托投影在纬度接近±90°时,Y坐标会趋向无穷大,若OSM文件包含极地区域,需提前裁剪边界
- 投影后的Y坐标在南半球为负、北半球为正,缩放和平移会自动处理该符号问题,无需额外调整
- 墨卡托是等角投影,局部形状会保持正确,但高纬度区域的面积会被放大——这是该投影的固有特性,符合OpenStreetMap的原生标准
内容的提问来源于stack exchange,提问作者darkfrei
相关产品推荐
相关产品推荐

