前言:前四篇博文我们讨论了如何搭建GeoServer开发环境,如何调试,以及如何支持自定义插件。我们的最终目的是将MongoDB中影像切片发布出来,使其支持wms、wmts、tms,有了前几篇的铺垫,相信读者或多或少也会有了一些收获。本篇我们就讨论一下,要实现最终的目的,我们还需要做哪些工作。
首先我觉得还是要说一说tms的分类,因为这涉及到我们要做的转换。tms有两种,一种是osgeo这个组织出的,这种tms的原点在左下角。mbtiles中存的影像切片,就是osgeo tms 标准的切片。
另一种是google公司出的,这种tms的原点在左上角,和ogc的标准协议wmts的原点是一致的。所以Google、Open Street Maps、ESRI等等,都采用的是这种。
通过上面两张图的对比,读者可以发现,行号反了,所以交换一下就行。假设原始osgeo tms的行号为 ** y**,层级为zoom。因为只是y值反了,那么只要计算出新的y值,假设为Y。
第一步首先要计算出总行数,假设总行数为:RowSum。
综上所述, 最后的转换公式为:
Y=RowSum-y-1 注意:不论行号还是列号,都是从0开始编号的
这里要声明,EPSG:4326和EPSG:3857每一级的行列号总数是不一样的。因为我们本期不是讲分辨率,所以就不展开细讲了,就直接给出结论。
每一级都是正方形,每一级都是瓦片个数都是4n,所以每一级行列总数都是2n ,所以
第0级 1行1列,
第1级 2行2列
第2级 4行4列
第3级 8行8列
。。。
第0级只有一块瓦片,从第1级开始,每一级都是矩形,每一级瓦片个数都是n行m列,m=2*n,所以:
第0级 1行1列,
第1级 1行2列
第2级 2行4列
第3级 4行8列
。。。
所以从第1级开始,每一级总行数都是2n-1 ,总列数都是2 * 2n-1
多提一句,熟悉cesium ion平台上 terrain 的同学都知道,cesium 的 terrain 规则就类似于这种规则,但是它稍稍有点不同,即舍弃掉了原本的第0级,把第1级作为第0级,很巧妙。
首先我们来回顾一下wms的访问流程:
以上就是整个wms的请求过程,为什么要专门说这里呢?因为坐标原点的不同会导致切片在画布上拼接时,画布y坐标的计算的不同。下面我们来详细讲。
要讲明白切片的拼接,首先就要能理解怎么根据经纬度计算行列号,其实计算行列号的原理很简单,那就是 总距离除以每一块切片所能表示的距离,我们以4326为例,即:
EPSG:4326所表示的经度范围为【-180,180】,纬度范围为【-90,90】
坐标原点是在左上角,即【-180,90】,我们切片大小是256 * 256 像素,那么,行列号就可以表示为:
distance /(256 * resolution)
distance: 当前经度到-180的距离,或者,当前纬度到90的距离
resolution: 分辨率,即每一个像素代表的实际地理距离
256 * resolution: 一块切片所能表示的地理距离
所以,这两个距离相除,得到的比值,就是行号或者列号
理解上面的原理至关重要,没理解的同学可以多读两遍。有了上面的铺垫,明白了原理,我们就能计算出来行列号的范围,即 leftTile,rightTile,bottomTile,topTile 的值。
有了上面的值,我们就能通过简单的加减乘除,来计算出某一切片在画布上的位置了。假如某一切片的行列号为x,y,它在画布上的位置为Px,Py,那么:
Px = (x - leftTile) * 256
Py = (topTile - y) * 256
两层 for 循环嵌套,不就拼接出来一个画布了吗?
for(int i=leftTile;i<rightTile;i++){
for(int j=bottomTile;j<topTile;j++){
//计算在画布上的位置
int Px=(i-leftTile) * 256;
int Py=(topTile-j) * 256
//在画布上赋值略
。。。
}
}
如果是osgeo tms,确实是上面这样计算的,但我们是google tms,行号和osgeo tms的行号是反的,所以,我们首先要交换行号:
bottomTile = row_number - 1 - bottomTile;
topTile = row_number- 1 - topTile;
然后,再来拼接画布,代码也要做出修改。
for(int i=leftTile;i<rightTile;i++){
for(int j=topTle;j<bottomTile;j++){
//计算在画布上的位置
int Px=(i-leftTile) * 256;
int Py=(j-bottomTile) * 256
//在画布上赋值略
。。。
}
}
本节在理解上是有一些难度的,希望不明白的同学能够仔细揣摩,多读几遍,这样才会有收获。有些人可能会有疑问,本文标题不是写的要支持 wms、wmts、tms 吗,为什么只讲了 wms ,而没有讲 wmts 和 tms?那是因为,wms 是在后端动态拼接(渲染)的,wmts 和 tms 后端只是负责根据行列号和层级查找并返回给前端,具体的拼接(渲染)过程是在前端完成的。因为如果你明白了wms的过程,那么 wmts 和 tms 自然也就明白了,所以这里就不啰嗦了。
到这里,我们的开发工作基本都完事了,所以下一篇我会讲讲 GeoServer 源码如何打包发布,回见~。