由于工作需要,硬着头皮啃了一些webgis的概念,对在线地图呈现在广大用户面前有了基本对认识,有些技术还是非常有意思的,和大家分享一下。
地图现状
现在的地图基本是这样的
平面的
多个比例 百度有16级比例
有路网、文字等附加标识
加载速度快,分格加载
墨卡托投影
地球是个接近与球形的物体,不适合在地图上展示。需要一些方法,将地球投影到平面上来,google、百度等主流厂商都使用墨卡托投影的方法。
墨卡托投影,是正轴等角圆柱投影。假想一个与地轴方向一致的圆柱切或割于地球,按等角条件,将经纬网投影到圆柱面上,将圆柱面展为平面后,就得到了平面投影,如下图所示。
这种方法能将经度、纬度网络投影到平面上,方便人们使用,缺点是离赤道越远,拉升越大,显示偏大。
但我们对地图使用的幅度是比较小的,基本不会影响我们使用。
瓦片与四叉树
由于地图的多比例,所以从最大比例到最小比例,数据是逐级递增的(底层分辨率越高),呈现倒金字塔形状。为了快速加载,呈现给用户的地图是栅格化的,逐格加载,然后将栅格矩阵拼装成一幅完整的地图。这个栅格也被称做为瓦片。
每个瓦片一般是256 x 256像素大小的正方形小块。由于在每个放大级别下的像素数量不一样,因此地图瓦片(Tile)的数量也不一样。每个Tile都有一个XY坐标值,从左上角的(0,0)至右下角的(2^level–1, 2^level–1)。例如在3级放大级别下,所有tile的坐标值范围为(0, 0)至(7, 7)。
已知一个像素的XY坐标值时,我们很容易得到这个像素所在的Tile的XY坐标值:
tileX = floor(pixelX/256)
tileY = floor(pixelY/256)
为了简化索引和存储地图图片,每个Tile的二维XY值被转换成一维字串,即四叉树键值(quardtree key,简称quadkey)。每个quadkey独立对应某个放大级别下的一个Tile,并且它可以被用作数据库中B-tree索引值。
为了将坐标值转换成quadkey,需要将Y和X坐标二进制值交错组合,并转换成4进制值及对应的字符串。例如,假设在放大级别为3时,Tile的XY坐标值为(3,5),quadkey计算如下:
tileX = 3 = 011(二进制)
tileY = 5 = 101(二进制)
TileXY 转quadkey的算法
public static string TileXYToQuadKey(int tileX, int tileY, int levelOfDetail)
{
StringBuilder quadKey = new StringBuilder();
for (int i = levelOfDetail; i > 0; i--)
{
char digit = '0';
int mask = 1 << (i - 1);
if ((tileX & mask) != 0)
{
digit++;
}
if ((tileY & mask) != 0)
{
digit++;
digit++;
}
quadKey.Append(digit);
}
return quadKey.ToString();
}
quadkey = 100111(二进制) = 213(四进制) = “213”
Quadkey还有其他一些有意思的特性。第一,quadkey的长度等于该tile所对应的放大级别;第二,每个tile的quadkey的前几位和其父Tile(上一放大级别所对应的tile)的quadkey相同,下图中,Tile 2是Tile 20至23的父Tile,Tile 13是Tile 130至133的父级:
基于这个原则,假设第一级地图有100个瓦片,那么倒最后一级就有 100 * 4的16次方,这个数据量是非常惊人的。
图层与矢量图
现在的地图不仅仅显示地图,还有标识、路网、poi等各种用户自定义的业务,一般采用多个图层实现。如下图(来自知乎)所示,最底层是底图,然后依次叠加路网层、标识层、poi层。
业务图一般是以矢量的方式附着在地图上,如POI点的图标,在不同级别的地图上显示的大小都是一样的。但是大比例情况下,有些图示不显示出来,随着地图缩放,显示的内容会有裁剪和增加。这个机制后续研究透了再聊。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。