谷歌\必应瓦片地图部署解析

发布于 2023-08-11  141 次阅读


谷歌\必应瓦片地图部署解析

quadkey ——三维地图加载瓦片地图图片的键值

这个值是一个四进制的数字 如:132122221302231

和谷歌瓦片图不同的是,谷歌是xyz坐标系

如: "https://mts0.googleapis.com/vt?lyrs=y&hl=en&x=" +x +"&y=" + y + "&z=" + Number(z + 1);

如:http://mt2.google.cn/vt/lyrs=m@167000000&hl=zh-CN&gl=cn&x=420&y=193&z=9

谷歌地图图层说明:

h skeleton map light http://mt2.google.cn/vt/lyrs=h&hl=zh-CN&gl=cn&x=420&y=193&z=9
m 全地图 http://mt2.google.cn/vt/lyrs=m&hl=zh-CN&gl=cn&x=420&y=193&z=9
p terrain+map http://mt2.google.cn/vt/lyrs=p&hl=zh-CN&gl=cn&x=420&y=193&z=9
r skeleton map dark http://mt2.google.cn/vt/lyrs=r&hl=zh-CN&gl=cn&x=420&y=193&z=9
y hybrid satellite map http://mt1.google.cn/vt/lyrs=y&hl=zh-CN&gl=cn&x=420&y=193&z=9
t 地形图 http://mt0.google.cn/vt/lyrs=t&hl=zh-CN&gl=cn&x=420&y=193&z=9
s 卫星地图 http://mt3.google.cn/vt/lyrs=s&hl=zh-CN&gl=cn&x=420&y=193&z=9
也可以进行组合,例如:s,r 或者 t,h http://mt3.google.cn/vt/lyrs=t,h&hl=zh-CN&gl=cn&x=420&y=193&z=9

图片(x,y,z)像素(m,n)[注:像素坐标以左上角为原点,x轴向右,y轴向下]的经纬度[单位:度]与openmapstreet方法一致。

必应瓦片地图格式

特别注意!谷歌、leaflets的层级是0——18

必应的层级是1——18

所以转换的z要=谷歌z+1

https://ecn.t3.tiles.virtualearth.net/tiles/a132122221302231.jpeg?g=5000

转换方法

        var quadKey = "";
          for (var i = z; i > 0; i--) {
            var digit = "0";
            var mask = 1 << (i - 1);
            if ((x & mask) != 0) {
              digit++;
            }
            if ((y & mask) != 0) {
              digit++;
              digit++;
            }

            quadKey = quadKey + String(digit);
          }

———————————以下摘自必应地图官网———————————————————

计算图片img[img为图片的code码,img={0,1,2,3}]的像素(m,n)[注:像素坐标以左上角为原点,x轴向右,y轴向下]的经纬度

只需先计算出img与x,y,z的关系,然后再套用openstreetmap的公式,就可以得到。

z = img的位数

img

img


通过经纬度计算出xyz

s:一个正方形的区域

levelCollection需要下载(加载)的层级

      var flng = s.west;
      var flat = s.north;
      var slng = s.east; //右下经度
      var slat = s.south; //右下纬度
      var zomm = 1; //缩放级别
      var thread = 5; //下载线程数目
      var p;
      var p2;

      for (var z = 0; z <= levelCollection.length; z++) {
        zomm = levelCollection[z];
        p = this.LatLongToPixel(flat, flng, zomm); //将第一个点经纬度转换成平面2D坐标
        p2 = this.LatLongToPixel(slat, slng, zomm); //将第二个点经纬度转换成平面2D坐标

        // var startX = p.X / 256; //起始列
        // var endX = p2.X / 256; //结束列

        var startX = Math.floor(p.x / 256); //起始列
        var endX = Math.floor(p2.x / 256); //结束列
        if (endX == Math.pow(2, zomm)) {
          //结束列超出范围
          endX--;
        }

        var startY = Math.floor(p.y / 256); //起始行
        var endY = Math.floor(p2.y / 256); //结束行
        if (endY == Math.pow(2, zomm)) {
          //结束行超出范围
          endY--;
        } //以上由startX endX startY endY 围成的区域 即为待下载区域  该区域由许多256*256大小方块组成
        var _totalwidth = 0; //地图合并之后的宽度
        var _totalheight = 0; //地图合并之后的高度
        _totalwidth = (endX - startX + 1) * 256; //合并图的宽度
        _totalheight = (endY - startY + 1) * 256; //合并图的高度

        var serverId = 0;
        var threadId = 0;
        // alert(startY);
        // console.log("p2");
        // console.log(p2);

        // serverId = int.Parse(ServerNo.SelectedValue.ToString());

        for (var y = startY; y <= endY; y++) {
          // alert(y);
          // alert("------------");
          for (var x = startX; x <= endX; x++) {
            // setTimeout(() => {
            var ri = new Object();
            ri.serverId = serverId; //分别从不同的服务器下载
            ri.threadId = threadId; //分别由不同的线程下载
            // ri.url = BuildURL(serverId);
            ri.x = x;
            ri.y = y;
            ri.z = zomm;
            ri.bComplete = false;

            // var quadKey = "";
            // for (var i = z + 1; i > 0; i--) {
            //   var digit = "0";
            //   var mask = 1 << (i - 1);
            //   if ((x & mask) != 0) {
            //     digit++;
            //   }
            //   if ((y & mask) != 0) {
            //     digit++;
            //     digit++;
            //   }

            //   quadKey = quadKey + String(digit);
            // }

            /*
              谷歌XYZ坐标体系
            */
            // console.log("x" + x);
            // console.log("y" + y);
            // console.log("z" + (Number(z) + 1));
            // console.log(
            //   "https://mts0.googleapis.com/vt?lyrs=y&hl=en&x=" +
            //     x +
            //     "&y=" +
            //     y +
            //     "&z=" +
            //     Number(z + 1)
            // );

            /*
              必应四进制坐标体系
            */
            let quadKey = this.toQuad(Number(x), Number(y), Number(z));
            let url =
              "https://ecn.t3.tiles.virtualearth.net/tiles/a" +
              quadKey +
              ".jpeg?g=5000";
            console.log(url);

            // console.log("quadKey" + quadKey);

            let name = String(this.newName.trim()) + "_" + quadKey + ".jpg";

            this.downloadImage(url, name, x, y, Number(z));

            // let url =
            //   "https://mts0.googleapis.com/vt?lyrs=y&hl=en&x=" +
            //   x +
            //   "&y=" +
            //   y +
            //   "&z=" +
            //   Number(z + 1);

            // // alert(this.getBase64ImageUrl(url, "image/png"));

            // alert(/.*[\u4e00-\u9fa5]+.*$/.test(name));

            // var aTag = document.createElement("a");
            // var blob = new Blob([
            //   "https://mts0.googleapis.com/vt?lyrs=y&x=" +
            //     x +
            //     "&y=" +
            //     y +
            //     "&z=" +
            //     (Number(z) + 1)
            // ]);
            // console.log(URL.createObjectURL(blob));
            // aTag.download = "下载文件" + new Date() + ".jpg";
            // aTag.href = URL.createObjectURL(blob);
            // aTag.click();
            // URL.revokeObjectURL(blob);
            // }, 50 * (x + 1));
          }
        }
      }

一沙一世界,一花一天堂。君掌盛无边,刹那成永恒。