golang实现Web墨卡托投影坐标转换的插件库Web-Mercator-Projection
Web Mercator Projection
一个用于探索Web墨卡托投影坐标转换的Go语言项目。
项目功能
在示例项目main.go
中,包含以下功能:
- 将
LonLat
(经纬度)转换为Point
(像素坐标)或反向转换 - 在地图图像上添加红色标记的功能(坐标需要在代码中手动设置)
转换结果将保存在data
文件夹中。
示例输出:
LonLat: {-74.92010258781309 11.045882360336755}
Point: {298.8939304168872 480.38414652354516 2}
Tile: {1 1 2}
LonLat from Point: {-74.9201025878131 11.045882360336744}
数据结构定义
LonLat
: 使用角度度数表示的地图位置Point
: 特定缩放级别下的地图像素坐标Tile
: 表示Point或LonLat所在的瓦片/区块
完整示例代码
package main
import (
"fmt"
"log"
"github.com/jorelosorio/web-mercator-projection"
)
func main() {
// 示例坐标
lonLat := projection.LonLat{
Lon: -74.92010258781309,
Lat: 11.045882360336755,
}
// 转换为像素坐标(缩放级别2)
zoom := 2
point := projection.LonLatToPoint(lonLat, zoom)
// 获取瓦片坐标
tile := projection.PointToTile(point)
// 反向转换回经纬度
lonLatFromPoint := projection.PointToLonLat(point)
// 打印结果
fmt.Printf("LonLat: %v\n", lonLat)
fmt.Printf("Point: %v\n", point)
fmt.Printf("Tile: %v\n", tile)
fmt.Printf("LonLat from Point: %v\n", lonLatFromPoint)
// 在地图上添加标记
err := projection.AddMarkerToMap(lonLat, "data/map_with_marker.png")
if err != nil {
log.Fatal(err)
}
}
开发工具
- Go 1.17+
- Docker
- ImageMagick 6.9.11-60
- Visual Studio Code (可选)
开发环境搭建
- 安装Go: 从官网下载
- 安装ImageMagick
- 构建可执行文件:
go build ./examples/main.go
注意:二进制文件依赖assets
文件夹来构建地图,确保它们在同一目录下。
许可证
- OpenStreetMap数据使用ODbL许可证
- 红色标记图标使用CC BY 3.0许可证
更多关于golang实现Web墨卡托投影坐标转换的插件库Web-Mercator-Projection的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang实现Web墨卡托投影坐标转换的插件库Web-Mercator-Projection的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Web墨卡托投影坐标转换的Golang实现
Web墨卡托投影(又称球形墨卡托投影)是Web地图(如Google Maps、OpenStreetMap等)常用的投影方式。下面我将介绍如何使用Golang实现Web墨卡托投影的坐标转换。
基本概念
Web墨卡托投影有以下特点:
- 将地球视为完美的球体
- 经度直接映射为X坐标
- 纬度使用墨卡托公式转换为Y坐标
- 坐标范围:经度[-180,180],纬度[-85.05112878, 85.05112878]
核心实现代码
package mercator
import (
"math"
)
const (
earthRadius = 6378137.0 // WGS84椭球体长半轴
maxLatitude = 85.05112877980659 // 最大纬度(弧度)
)
// LonLatToMeters 将经纬度转换为Web墨卡托投影坐标(单位:米)
func LonLatToMeters(lon, lat float64) (x, y float64) {
// 确保纬度在有效范围内
if lat > maxLatitude {
lat = maxLatitude
} else if lat < -maxLatitude {
lat = -maxLatitude
}
x = lon * earthRadius * math.Pi / 180.0
y = math.Log(math.Tan((90.0+lat)*math.Pi/360.0)) * earthRadius
return x, y
}
// MetersToLonLat 将Web墨卡托投影坐标转换回经纬度
func MetersToLonLat(x, y float64) (lon, lat float64) {
lon = (x / earthRadius) * 180.0 / math.Pi
lat = (math.Atan(math.Exp(y/earthRadius)) * 360.0 / math.Pi) - 90.0
return lon, lat
}
// LonLatToPixels 将经纬度转换为像素坐标(基于缩放级别和瓦片大小)
func LonLatToPixels(lon, lat float64, zoom int, tileSize int) (x, y float64) {
xMeters, yMeters := LonLatToMeters(lon, lat)
resolution := (2 * math.Pi * earthRadius) / (float64(tileSize) * math.Exp2(float64(zoom)))
x = (xMeters + (math.Pi * earthRadius)) / resolution
y = ((math.Pi * earthRadius) - yMeters) / resolution
return x, y
}
// PixelsToLonLat 将像素坐标转换回经纬度
func PixelsToLonLat(x, y float64, zoom int, tileSize int) (lon, lat float64) {
resolution := (2 * math.Pi * earthRadius) / (float64(tileSize) * math.Exp2(float64(zoom)))
xMeters := x*resolution - (math.Pi * earthRadius)
yMeters := (math.Pi * earthRadius) - y*resolution
return MetersToLonLat(xMeters, yMeters)
}
使用示例
package main
import (
"fmt"
"yourmodulepath/mercator"
)
func main() {
// 经纬度坐标(天安门)
lon, lat := 116.391275, 39.906217
// 转换为墨卡托坐标(米)
x, y := mercator.LonLatToMeters(lon, lat)
fmt.Printf("墨卡托坐标(米): x=%.2f, y=%.2f\n", x, y)
// 转换回经纬度
lon2, lat2 := mercator.MetersToLonLat(x, y)
fmt.Printf("转换回经纬度: lon=%.6f, lat=%.6f\n", lon2, lat2)
// 转换为像素坐标(缩放级别12, 瓦片大小256)
zoom := 12
tileSize := 256
px, py := mercator.LonLatToPixels(lon, lat, zoom, tileSize)
fmt.Printf("像素坐标: x=%.2f, y=%.2f\n", px, py)
// 从像素坐标转换回经纬度
lon3, lat3 := mercator.PixelsToLonLat(px, py, zoom, tileSize)
fmt.Printf("从像素转换回经纬度: lon=%.6f, lat=%.6f\n", lon3, lat3)
}
扩展功能
如果需要更完整的功能,可以考虑添加以下方法:
// TileToLonLat 计算瓦片的左上角经纬度
func TileToLonLat(x, y, zoom int) (lon, lat float64) {
n := math.Pi - 2.0*math.Pi*float64(y)/math.Exp2(float64(zoom))
lon = float64(x)/math.Exp2(float64(zoom))*360.0 - 180.0
lat = 180.0 / math.Pi * math.Atan(0.5*(math.Exp(n)-math.Exp(-n)))
return lon, lat
}
// LonLatToTile 计算包含给定经纬度的瓦片坐标
func LonLatToTile(lon, lat float64, zoom int) (x, y int) {
x = int(math.Floor((lon + 180.0) / 360.0 * math.Exp2(float64(zoom))))
y = int(math.Floor((1.0 - math.Log(math.Tan(lat*math.Pi/180.0)+1.0/math.Cos(lat*math.Pi/180.0))/math.Pi) / 2.0 * math.Exp2(float64(zoom))))
return x, y
}
注意事项
- Web墨卡托投影在高纬度地区会有较大变形,因此纬度范围被限制在约±85.05度
- 对于需要更高精度的应用,可以考虑使用椭球体模型而非球体模型
- 在实际地图应用中,通常还需要处理瓦片坐标系统和像素坐标系统
这个实现提供了Web墨卡托投影的核心功能,可以满足大多数Web地图应用的需求。如果需要更复杂的功能,可以考虑在此基础上进行扩展。