liujiusheng / blog

个人博客,blog
19 stars 0 forks source link

地图瓦片行列号与经纬度计算规则(JS版&GO版) #246

Open liujiusheng opened 2 years ago

liujiusheng commented 2 years ago

经纬度与瓦片行列号互转方案1(已验证可行)

JavaScript版

源代码:https://blog.csdn.net/wangshuminjava/article/details/117767563?spm=1001.2014.3001.5502

// 经纬度转瓦片编号
function lon2tile(lon, zoom) {
    return (Math.floor((lon+180)/360*Math.pow(2,zoom)));
}

function lat2tile(lat, zoom) {
    return (Math.floor(1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI/2 * Math.pow(2, zoom)));
}

// 瓦片编号转经纬度,计算的是瓦片左上角的经纬度坐标,即西北方向,如果要计算东南方向的坐标则x和y各加1就行了
function tile2lon(x, z) {
    return (x/Math.pow(2,z)*360-180);
}

function tile2lat(y, z) {
    const n = Math.PI-2*Math.PI*y/Math.pow(2,z);
    return (180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n))));
}

Go语言版


// 经度转瓦片编号
func lon2tile(lon float64, zoom float64) float64 {
    result := math.Floor((lon + 180) / 360 * math.Pow(2, zoom))
    return result
}

// 纬度转瓦片编号
func lat2tile(lat float64, zoom float64) float64{
    result := math.Floor(1-math.Log(math.Tan(lat*math.Pi/180) + 1/math.Cos(lat*math.Pi/180))/math.Pi/2*math.Pow(2, zoom))
    return result
}

// 瓦片编号转经度
func tile2lon(x float64, z float64) float64{
    return x/math.Pow(2,z)*360-180
}

// 瓦片编号转纬度
func tile2lat(y float64, z float64) float64{
    n := math.Pi-2*math.Pi*y/math.Pow(2,z)
    return 180/math.Pi*math.Atan(0.5*(math.Exp(n)-math.Exp(-n)))
}

计算瓦片的经纬度范围方案2(待验证)

javaScript版

源代码出处:https://blog.csdn.net/yangyoung4/article/details/124103032

function calculate(z, x, y) {
    // 层级
    const level = Number(z);
    // 瓦片x坐标
    const tileX = Number(x);
    // 瓦片y坐标
    const tileY = Number(y);
    // 像素坐标
    const pixelX = {
        pixel_left_X: 0,
        pixel_left_Y: 255 // 左下角坐标,像素坐标系为东向,南向
    };
    const pixelY = {
        pixel_right_X: 255,
        pixel_right_Y: 0
    };
    // 左下经纬度
    const left_lng_lat = pixelToLnglat(pixelX.pixel_left_X, pixelX.pixel_left_Y, tileX, tileY, level);
    const right_lng_lat = pixelToLnglat(pixelY.pixel_right_X, pixelY.pixel_right_Y, tileX, tileY, level);
    return [left_lng_lat.lng, left_lng_lat.lat, right_lng_lat.lng, right_lng_lat.lat];
}

function _Math_sinh(x) {
    return (Math.exp(x) - Math.exp(-x)) / 2;
}

// 某一瓦片等级下瓦片地图X轴(Y轴)上的瓦片数目
function _getMapSize(level) {
    return Math.pow(2, level);
}

function _pixelXTolng(pixelX, tileX, level) {
    const pixelXToTileAddition = pixelX / 256.0;
    const lngitude = (tileX + pixelXToTileAddition) / _getMapSize(level) * 360 - 180;
    return lngitude;
}

function _pixelYToLat(pixelY, tileY, level) {
    const pixelYToTileAddition = pixelY / 256.0;
    const latitude = Math.atan(_Math_sinh(Math.PI * (1 - 2 * (tileY + pixelYToTileAddition) / _getMapSize(level)))) * 180 / Math.PI;
    // let latitude = Math.atan(_Math_sinh(Math.PI*(-1+2*(tileY+1-pixelYToTileAddition)/ _getMapSize(level))))*180.0/Math.PI; //osm坐标
    return latitude;
}

// 从某一瓦片的某一像素点到经纬度
function pixelToLnglat(pixelX, pixelY, tileX, tileY, level) {
    const lng = _pixelXTolng(pixelX, tileX, level);
    const lat = _pixelYToLat(pixelY, tileY, level);
    return {
        lng,
        lat
    };
}

GO版本

等会儿再写......

计算公式:

https://en.wikipedia.org/wiki/Mercator_projection