以前写过一个 leaflet 互联网地图纠偏插件,引用插件后一行代码都不用写,就能解决国内互联网地图瓦片的偏移问题。html
最近想对 mapboxgl 也写一个这样的插件。git
缘由是本身发布的OSM矢量瓦片地图精度不够高,当须要放大地图查看详细信息时,就能够拿百度、高德的栅格瓦片作个补充。而使用它们的第一步就是要先纠偏。github
去研究了 mapboxgl 的底层代码,发现不少都看不懂。因而去恶补了 webgl 的知识,再去看 mapboxgl 的源码,哈哈,万变不离其宗,GIS知识仍是那些,只是计算机绘制图形的方式变了而已。web
研究后,把目标锁定在了 transform.js 文件上,这个文件主要用来处理各类坐标转换问题,包括经纬度坐标、墨卡托坐标、屏幕坐标、webgl坐标等,还负责生成瓦片的编号。编程
文件中的 coveringTiles 方法就是用来计算瓦片的 x、y、z 编号的,它会返回当前比例尺和可视范围内的全部瓦片编号。webgl
根据 x、y、z 瓦片编号请求到互联网地图瓦片后,会在 calculatePosMatrix 方法里计算瓦片显示的屏幕位置。url
mapboxgl 和 leaflet 的显示原理不一样,mapboxgl 是三维坐标系,使用webgl绘图,增长了一个维度后,多出了不少东西要处理,二维坐标系加载瓦片时,只须要考虑瓦片的 x、y 位置,三维坐标系在此基础上还要考虑倾斜和透视。.net
webgl 的坐标都是经过位置变换矩阵来表示的,这一点和leaflet的差异很大。插件
上面的 calculatePosMatrix 方法就是根据瓦片的 x、y、z 编号,计算出瓦片在 webgl 中显示的位置变换矩阵。这里分别将瓦片的平移矩阵、缩放矩阵和视图+投影矩阵进行了相乘,获得了最终的位置变换矩阵。3d
> 看这个方法时我有些疑惑,它是如何根据瓦片的 x、y、z 编号来计算位置变换矩阵的,去研究了xyz协议后,才明白xyz坐标和经纬度坐标是有一套互转公式的,瓦片编号转经纬度时返回的坐标是瓦片左上角的经纬度。详见:https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
> 关于 webgl 变换矩阵的知识能够参考这篇文章 https://www.cnblogs.com/charlee44/p/11623502.html 或 《WebGL编程指南》,我更推荐后者,由于后者讲的更系统更容易理解。
不得不说,webgl 的位置变换矩阵计算仍是有一些复杂的,因此就想看看 mapboxgl 中有没有内置经纬度坐标和 webgl 坐标互转的方法,查看后发现,只有经纬度坐标、墨卡托坐标和屏幕坐标三者互转的方法,没有 webgl 的。
那就曲线救国,先将经纬度转成屏幕坐标,再本身写个方法把屏幕坐标转成 webgl 坐标。
实现思路:
- 根据瓦片编号和经纬度的互转公式,计算出瓦片左上角的经纬度
- 对瓦片左上角的经纬度进行纠偏,获得 wgs84 坐标的经纬度
- 将纠偏前、后的经纬度分别转为屏幕坐标,再将转换后的屏幕坐标相减,得出瓦片屏幕坐标的偏移量
- 将瓦片屏幕坐标的偏移量换算成 webgl 坐标的偏移量
- 在瓦片的平移矩阵中加上刚才计算出的 webgl 坐标偏移量,理论上就能实现对瓦片的纠偏
在实现过程当中,将 一、二、3 步搞定之后,由于暂时尚未想好怎么实现第4步,因而就先将第 3 步的结果屏幕坐标偏移量,直接加到了第 5 步的平移矩阵中,结果很让人意外。
实现代码:
实现效果:
以天安门国旗为参照,纠偏前
纠偏后
哈哈,难道就这么搞定了?
难道平移矩阵中的数值都是按屏幕像素来计算的?
至少目前看来是的。
正当我开心的不要不要时,咦?边上为何会有空白,瓦片没有请求过来?我接着放大地图,白边愈来愈大了
嗯~ 这个好解决,应该是由于 mapboxgl 只显示当前范围的瓦片,当屏幕边缘的瓦片被纠偏到屏幕中间时,边缘就会出现空隙。
只要将当前显示范围向外扩展一些就能搞定。
正当我在开心的研究如何向外扩展显示范围时,无心中把地图倾斜了一下,个人妈呀!这是什么鬼
看到这个,我当时的心情瞬间就很差了。
~~ 容我整理下心情 ~~
好了,我的猜测,缘由多是,在地图旋转时,瓦片根据 webgl 坐标的中心点计算要旋转的角度和移动的距离,如今瓦片纠偏后位置发生了偏移,但计算旋转坐标时,仍是根据webgl的中心点,因此旋转时就出问题了。
具体我也没想明白呢,感受仍是对瓦片纠偏后,须要对某个中心点也须要纠偏一下。若是有技术大牛看到这篇文章也能够给留言指导一下。
总结:
- 目前搞定了垂直视角下的瓦片纠偏
- 后续须要解决纠偏后屏幕边缘出现的空白区域问题。
- 地图倾斜和旋转时瓦片会出现错位,须要继续研究。
最后,mapboxgl纠偏插件尚未彻底搞定,就不放代码了,后续有新进展会再跟你们分享,等彻底搞定之后再向之前同样跟你们分享插件。
<br>
原文地址:http://gisarmory.xyz/blog/index.html?blog=mapboxglMapCorrection1
关注《GIS兵器库》, 第一时间得到更多高质量GIS文章。
本文章采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、从新发布,但务必保留文章署名《GIS兵器库》(包含连接: http://gisarmory.xyz/blog/),不得用于商业目的,基于本文修改后的做品务必以相同的许可发布。