背景
在地图公司工作过的朋友应该了解,我们的地图数据是不能直接用wgs84坐标系来存储或者表达的,必须做一定的转换,例如百度地图的bd09,或者国测局的gcj02。而我们的渲染引擎,例如cesium或者openlayer,正常情况下,使用的肯定是wgs84的。那么当gcj02的坐标,渲染到wgs84的框架下,为什么能正确渲染呢?
渲染引擎的地图原理
一个经纬度点渲染到地图上,需要经过几步转换:
经纬度坐标(lng,lat)->Web墨卡托平面坐标(x,y)->屏幕像素坐标(px,py)
那么,同一个经纬度坐标,无论是wgs84坐标系,或者gcj02坐标系,最后投影到屏幕上,都会对应同一个像素坐标。但是其在真实世界中表达的地理位置,是不同的。
因此,在相同的bbox范围内,wgs84和gcj02投影得到的地图是不同的。

如果我们的数据都是gcj02坐标系的,那么渲染到地图上,你任意点击一个位置,这个位置的经纬度坐标就是gcj02坐标系的。
gcj02和wgs84只是在经纬度上有所偏移,在web墨卡托投影和转像素坐标的公式是完全一致的。经纬度转墨卡托认为是正算,墨卡托转经纬度认为是反算,正反算是可逆的。这也是为什么我们的渲染引擎没有特殊处理,就能正确渲染gcj02坐标的原因。
gcj02的瓦片如何生成
国内的卫星图,按照规定,也是需要转换为gcj02坐标系的瓦片。如何生成?
在wgs84下,每一个层级的每一个瓦片,都有自己对应的经纬度范围。同理,gcj02表达同一片范围的经纬度应该经过偏移。

因此,我们应该先对原始数据做偏移,然后再切瓦片。这样,相同瓦片行列号得到的84和02的卫星图是不同的。
wgs84坐标系切出的瓦片如何放在gcj02的地图上
如果我们得到的是已经切好的84瓦片,但是国内地图必须是用gcj02的坐标系,如何才能对应上?
在Cesium中,ImageryLayer会接收一个imageryProvider,我们需要在这个imageryProvider上做文章,把瓦片的经纬度范围进行修改。
imageryProvider有一个变量是tilingScheme,这个变量控制了瓦片的坐标转换公式。

其中,projection遍历变量,就是坐标转换。其余的很多内置方法都调用了这个变量。我们需要重写坐标投影正算和反算的方法。

重写也很简单,正算时拿到的经纬度是gcj02的,只需要gcj02转wgs84,然后再做web墨卡托投影,得到墨卡托坐标即可。
反算时先通过墨卡托投影反算出wgs84坐标,再把wgs94转gcj02坐标输出即可。
注意,上述的前提是切出来的瓦片,也是以左上角为原点。如果是Google Earth的瓦片,瓦片原点以地球经纬度(0,0),那就需要重写positionToTileXY和tileXYToNativeRectangle、tileXYToRectangle方法。重点在于瓦片行列号的转换。

1万+

被折叠的 条评论
为什么被折叠?



