彻底搞懂瓦片地图拼接原理并附具体实现

图片像素、DPI、图片分辨率、Scale、Resolution?

1.图片像素是指由图像的小方格组成的,这些小方块都有一个明确的位置和被分配的色彩数值,小方格颜色和位置就决定该图像所呈现出来的样子。
2.DPI是指一英寸内的像素点数。
3.图片分辨率是指图片的像素个数。
4.Scale表示的是比例尺,即地图上的1m代表着实际上的多少m。例如地图上1m代表实地距离500千米,可写成:1 ∶ 50,000,0或写成:1/50,000,0。
5.Resolution是分辨率,即表示1像素代表多少地图单位,地图单位是根据数据本身来确定的,可能是度也可能是米。

地图上1像素代表的实际距离是多少(这个就叫影像的地面分辨率)?

(1)坐标单位是米的时候:
在计算瓦片的行列号之前,我们需要得到图上一像素代表实际距离多少米。现在假设地图的坐标单位是米,dpi为96 ;
1英寸=2.54厘米;
1英寸=96像素;
最终换算的单位是米;
如果当前地图比例尺为1:125000000,则代表图上1米等于实地125000000米;
米和像素间的换算公式:
1英寸=0.0254米=96像素
1像素=0.0254/96 米
则根据1:125000000比例尺,图上1像素代表实地距离是 125000000*0.0254/96 = 33072.9166666667米。
在这里插入图片描述
(2)坐标单位是度的时候:
如果地理坐标系是wgs84,地图的单位是度,dpi为96
度和米之间的换算参数:1度约等于 111194.872221777米
接下来就需要进行度和像素间的换算:
当比例尺为1:64000000米时,相当于1像素 = 64000000 * 0.0254000508/96 = 16933.3672米 ,再将米转换为度 16933.3672/111194.872221777 =0.1522855043731385度 因此当地图单位为度时,近似计算在1:64000000 对应的Resolution为0.1522855043731385度。
Scale = 1 : (96 * 2 * Math.PI * 6378137 * resolution / 360 / 0.0254);
在这里插入图片描述

瓦片行列号换算原理?

直接丢出大佬博客:https://www.cnblogs.com/naaoveGIS/p/3899821.html
个人总结一下步骤:

  1. 首先要确定一个要展示的地图的中心点,这个中心点随便找一个经纬度坐标即可。
  2. 根据中心点、cavans的宽高、resolutions、TileSize、FullExtent等来计算出当前cavans视图范围所对应的真实地理范围
  3. 计算瓦片的起始行列号以及x方向的瓦片个数、y方向的瓦片个数
  4. 计算扩展瓦片的真实地理范围位置
  5. 计算瓦片偏移量
  6. 根据偏移量、行列号、resolutions、TileSize计算每张瓦片在cavans中的像素坐标位置
  7. 根据瓦片个数循环遍历,拼接瓦片地址,请求瓦片,绘制到cavans中

各大厂商瓦片编码规范?

谷歌XYZ:Z表示缩放层级,Z=zoom;XY的原点在左上角,X从左向右,Y从上向下。
TMS:开源产品的标准,Z的定义与谷歌相同;XY的原点在左下角,X从左向右,Y从下向上。
QuadTree:微软Bing地图使用的编码规范,Z的定义与谷歌相同,同一层级的瓦片不用XY两个维度表示,而只用一个整数表示,该整数服从四叉树编码规则
百度XYZ:Z从1开始,在最高级就把地图分为四块瓦片;XY的原点在经度为0纬度为0的位置,X从左向右,Y从下向上。
**高德地图:**遵循谷歌XYZ的编码规范,高德地图范围是85°N~85°S之间,x轴为85°N纬线,y轴为180°经线。

瓦片拼接具体实现代码?

<canvas width="1000px" height="700px" id="mapcv" style="margin: 10px;"></canvas>
function lonlatTomercator(lonlat) {
      var mercator = { x: 0, y: 0 };
      var x = lonlat.x * 20037508.34 / 180;
      var y = Math.log(Math.tan((90 + lonlat.y) * Math.PI / 360)) / (Math.PI / 180);
      y = y * 20037508.34 / 180;
      mercator.x = x;
      mercator.y = y;
      return mercator;
  }

  var MapConfig = {
      RootDir: 'http://t2.tianditu.gov.cn/DataServer?T=img_w&tk=af7560c213f145a1a52db53ca8c3fb5e',
      ViewHeight: 700,
      ViewWidth: 1000,
      TitlePix: 256,
      Resolution: [156543.033928, 78271.5169639999, 39135.7584820001, 19567.8792409999,
          9783.93962049996, 4891.96981024998, 2445.98490512499, 1222.99245256249,
          611.49622628138, 305.748113140558, 152.874056570411, 76.4370282850732,
          38.2185141425366, 19.1092570712683, 9.55462853563415, 4.77731426794937,
          2.38865713397468, 1.19432856685505],
      Scale: [591657527.591555, 295828763.795777, 147914381.897889, 73957190.948944,
          36978595.474472, 18489297.737236, 9244648.868618, 4622324.434309, 2311162.217155,
          1155581.108577, 577790.554289, 288895.277144, 144447.638572, 72223.819286,
          36111.909643, 18055.954822, 9027.977411, 4513.988705],
      FullExtent: {
          xmin: -20037508.3427892,
          ymin: -20037508.3427892,
          xmax: 20037508.3427892,
          ymax: 20037508.3427892,
          spatialReference: {
              wkid: 3857
          }
      }
  };

  moveX = 0;
  moveY = 0;
  TitlesArry = [];
  //设置将要现实的地图中心点
  centerGeoPoint = {
      x: 116.337737,
      y: 39.912465
  };
  centerGeoPoint = lonlatTomercator(centerGeoPoint);
  level = 6;
  //当前窗口显示的范围
  minX = centerGeoPoint.x - (MapConfig.Resolution[level] * MapConfig.ViewWidth / 2);
  maxX = centerGeoPoint.x + (MapConfig.Resolution[level] * MapConfig.ViewWidth / 2);
  minY = centerGeoPoint.y - (MapConfig.Resolution[level] * MapConfig.ViewHeight / 2);
  maxY = centerGeoPoint.y + (MapConfig.Resolution[level] * MapConfig.ViewHeight / 2);
  //左上角开始的行列号
  leftTopTitleRow = Math.floor(Math.abs(maxY - MapConfig.FullExtent.ymax) / MapConfig.Resolution[level] / MapConfig.TitlePix);
  leftTopTitleCol = Math.floor(Math.abs(minX - MapConfig.FullExtent.xmin) / MapConfig.Resolution[level] / MapConfig.TitlePix);
  //实际地理范围
  realMinX = MapConfig.FullExtent.xmin + leftTopTitleCol * MapConfig.TitlePix * MapConfig.Resolution[level];
  realMaxY = MapConfig.FullExtent.ymax - leftTopTitleRow * MapConfig.TitlePix * MapConfig.Resolution[level];
  //计算左上角偏移像素
  offSetX = (realMinX - minX) / MapConfig.Resolution[level];
  offSetY = (maxY - realMaxY) / MapConfig.Resolution[level];
  //计算瓦片个数
  xClipNum = Math.ceil((MapConfig.ViewHeight + Math.abs(offSetY)) / MapConfig.TitlePix);
  yClipNum = Math.ceil((MapConfig.ViewWidth + Math.abs(offSetX)) / MapConfig.TitlePix);
  //右下角行列号
  rightBottomTitleRow = leftTopTitleRow + xClipNum - 1;
  rightBottomTitleCol = leftTopTitleCol + yClipNum - 1;
  realMaxX = MapConfig.FullExtent.xmin + (rightBottomTitleCol + 1) * MapConfig.TitlePix * MapConfig.Resolution[level];
  realMinY = MapConfig.FullExtent.ymax - (rightBottomTitleRow + 1) * MapConfig.TitlePix * MapConfig.Resolution[level];
  var mapcv = document.getElementById("mapcv");
  var myctx = mapcv.getContext("2d");
  for (var i = 0; i < xClipNum; i++) {
      for (var j = 0; j < yClipNum; j++) {
          var beauty = new Image();
          beauty.src = MapConfig.RootDir + "&X=" + (leftTopTitleCol + j) + "&Y=" + (leftTopTitleRow + i) + "&L=" + level;
          var TitleImg = {
              img: null,
              x: 0,
              y: 0
          };
          TitleImg.img = beauty;
          TitleImg.x = offSetX + (j * MapConfig.TitlePix);
          TitleImg.y = offSetY + (i * MapConfig.TitlePix);
          TitlesArry.push(TitleImg);
          myctx.drawImage(TitleImg.img, TitleImg.x, TitleImg.y);
      }
  }
  • 4
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值