通过经纬度计算不同模型图瓦片坐标

1,墨卡托投影

使用经纬度表示位置的大地坐标系虽然可以描述地球上点的位置,但是对于地图地理数据在二维平面内展示的场景,需要通过投影的方式将三维空间中的点映射到二维空间中。地图投影需要建立地球表面点与投影平面点的一一对应关系,在互联网地图中常使用墨卡托投影。墨卡托投影是荷兰地理学家墨卡托于1569年提出的一种地球投影方法,该方法是圆柱投影的一种。

墨卡托投影如下:

2,瓦片切割和瓦片坐标

对于经过墨卡托投影为平面的世界地图,在不同的地图分辨率(整个世界地图的像素大小)下,通过切割的方式将世界地图划分为地图单元,划分成的每一块地图单元称为地图瓦片。
地图瓦片具有以下特点:

 --具有唯一的瓦片等级(Level)和瓦片坐标编号(X, Y)。

 --瓦片分辨率为256*256。

 --最小的地图等级是0,此时世界地图只由一张瓦片组成。

 --瓦片等级越高,组成世界地图的瓦片数越多,可以展示的地图越详细。

 --某一瓦片等级地图的瓦片是由低一级的各瓦片切割成的4个瓦片组成,形成了瓦片金字塔。

3,高德地图瓦片坐标与坐标系定义

高德地图瓦片坐标与Google Map、Open Street Map相同。高德地图的墨卡托投影截取了纬度(约85.05ºS, 约85.05ºN)之间部分的地球,使得投影后的平面地图水平方向和垂直方向长度相等。将墨卡托投影地图的左上角作为瓦片坐标系起点,往左方向为X轴,X轴与北纬85.05º重合且方向向左;往下方向为Y轴,Y轴与东经180º(亦为西经180º)重合且方向向下。瓦片坐标最小等级为0级,此时平面地图是一个像素为256*256的瓦片。在某一瓦片层级Level下,瓦片坐标的X轴和Y轴各有2^Level个瓦片编号,瓦片地图上的瓦片总数为2^Level*2^Level。

高德地图Level=2的瓦片坐标编号情况:

 4,通过经纬度计算瓦片坐标

公式:(参考:Slippy map tilenames

经纬度坐标(lon, lat)转瓦片坐标(x, y),z为瓦片层级:

 java代码实现:

  /** 功能描述: <br>
    * 〈高德地图,Google Map、Open Street Map 经纬度 转 瓦片坐标〉
    * @Param: [lon(经度), lat(维度), level(瓦片层级)]
    * @return: int[]
    * @author: zl
    * @date: 2021/12/23 14:18
    */
    public static int[] getTileNumber(double lon, double lat, int level) {
        int xtile = (int)Math.floor( (lon + 180) / 360 * (1<<level) ) ;

        double ln = Math.log( Math.tan(lat*Math.PI/180) + (1 / Math.cos(lat*Math.PI/180)) );
        int pow = (1<<(level-1));
        int ytile = (int)Math.floor( (1 - ln/Math.PI) *pow );
        if (xtile < 0) {
            xtile=0;
        }
        if (xtile >= (1<<level)) {
            xtile=((1<<level)-1);
        }
        if (ytile < 0) {
            ytile=0;
        }
        if (ytile >= (1<<level)) {
            ytile=((1<<level)-1);
        }
        return new int[]{xtile,ytile};
    }

5,百度地图瓦片坐标与坐标系定义

百度地图的瓦片坐标系定义与高德地图并不相同,其墨卡托投影的参数也不同。百度地图瓦片坐标以墨卡托投影地图中赤道与0º经线相交位置为原点,沿着赤道往左方向为X轴,沿着0º经线向上方向为Y轴。
百度瓦片坐标定义了另一种二维坐标系,称为百度平面坐标系。百度平面坐标系的坐标原点与百度瓦片坐标原点相同,以瓦片等级18级为基准,规定18级时百度平面坐标的一个单位等于屏幕上的一个像素。平面坐标与地图所展示的级别没有关系,也就是说在1级和18级下,同一个经纬度坐标的百度平面坐标都是一致的。

百度地图Level=2的瓦片坐标编号情况:

 此时X方向和Y方向各有4个瓦片编号,但是外围的某些瓦片只有部分区域有地图或完全没有地图。没有地图的区域也可以认为其瓦片是无效的,即百度地图中X方向或Y方向的有效瓦片不一定达到2^{Level}个。
中国大概位于百度瓦片坐标的(0,0)中。

百度经纬度坐标与百度平面坐标的相互转换,并没有公开的公式,需要通过百度地图的API实现。

参考链接(这里

6,其他投影模型和坐标系定义(天地图)

天地图的切片规则是这样的,l=1时,整幅地图(全球地图)被切为两片,如图(l=1):

当l=2即以后,每个瓦片将被切位4片,如图(l=2):

 

 天地图经纬度计算瓦片坐标java实现:

/** 功能描述: <br>
     * 〈天地图 经纬度 转 瓦片坐标〉
     * @Param: [rectPts(左上角经纬度rectPts[0],rectPts[1] 和 左下角经纬度rectPts[2],rectPts[3])也就是两个点, level(瓦片层级)]
     * @return: double[]
     * @author: zl
     * @date: 2021/12/23 14:18
     */
    public static double[] getTileNumber2(double[] rectPts, int level) {

        //瓦片的级别分辨率(1-18)
        double[] resolution = {5.36441802978515E-06,
                1.07288360595703E-05,
                2.1457672119140625E-05,
                4.29153442382814E-05,
                8.58306884765629E-05,
                0.000171661376953125,
                0.00034332275390625,
                0.0006866455078125,
                0.001373291015625,
                0.00274658203125,
                0.0054931640625,
                0.010986328125,
                0.02197265625,
                0.0439453125,
                0.087890625,
                0.17578125,
                0.3515625,
                0.703125};


        double startX = Math.floor((rectPts[0] + 180.0) / (resolution[18 - level] * 256));
        double startY = Math.floor((90.0 - rectPts[1]) / (resolution[18 - level] * 256));
        double endX = Math.ceil((rectPts[2] + 180.0) / (resolution[18 - level] * 256));
        double endY = Math.ceil((90.0 - rectPts[3]) / (resolution[18 - level] * 256));
        //左上角瓦片坐标和左下角瓦片坐标
        double[] result = new double[]{startX, startY, endX, endY};
        return result;

    }

7:,注意

  • 虽然最小的瓦片等级是0,但是部分地图并不提供0级或其他较小瓦片等级的地图,因为此时的世界地图将会很小,不能铺满用户设备窗口。
  • 墨卡托投影并不是一种坐标系,而是为了在二维平面上展示三维地球而进行的一种空间映射。所以在GIS地图和互联网地图中,虽然用户看到的地图经过了墨卡托投影,但依然使用经纬度坐标来表示地球上点的位置。在地图绘制和地图可视化时,就需要将地图数据使用投影的方式来呈现。

8,参考链接

https://www.cnblogs.com/mymhj/p/7416773.html

https://blog.csdn.net/yhj101096/article/details/118760410

心有所想,必有回响
原文地址:https://www.cnblogs.com/zhulei2/p/15724801.html