GIS 矢量切片(Vector Tile)-地图定制化的时代已经悄悄来临

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qingyafan/article/details/53367204

前言

切片技术的简单介绍,以及传统栅格图片切片的不足

现在最流行的地图底图技术是栅格切片底图,它们本质上是将空间数据分别渲染为不同缩放级别的地图图片,然后将各个级别的图片按照一定规则切分,按照一定的 “规则组织”,存储到硬盘或数据库中,构成一幅完整的地图。

图片来自微软必应
图1 切片概念图

相对于其他技术,切片地图有其优越性,例如有效减少了传输数据体积,多级缩放等。然而,栅格地图也有一些短处,缺乏灵活性、实时性,数据完整性受损是比较突出的问题,这正是栅格数据的问题:

  • 缺乏灵活性,切片一旦渲染切分,样式不可定制,要在渲染前提前定制好;
  • 缺乏实时性,由于栅格切片是在服务器端预先渲染好,当现实世界地物有变化时,并不能实时显示到地图中,需要经过再次渲染;
  • 数据完整性受损,渲染切片过程是将地理坐标数据转换为图片的过程,若要查询图片的多边形的属性,需要到服务器重新请求。

GIS 中数据按照存储格式可以分为矢量和栅格,矢量不同于栅格数据,比较灵活,数据完整,因此综合矢量数据和栅格切片地图的优势,会是一个比较不错的方案,boom,这就是 “矢量切片”。

矢量切片

矢量切片的特点、优势,以及用到的技术细节

矢量切片可以以三种形式呈现:GeoJSON、TopoJSON 和 MapBox Vector Tile(.mvt),矢量切片技术继承了矢量数据和切片地图的双重优势,有如下优点:

  • 对于栅格切片,更灵活,更细粒度的数据划分,要素级别;
  • 数据信息接近无损,但体积更小,请求指定地物的信息,直接在客户端获取,无需再次请求服务器;
  • 样式可改变和定制(重点),矢量切片可以在客户端或者服务器端渲染,可以按照用户赋予的样式渲染;
  • 对于原始矢量数据,更小巧,采用了重新编码,并进行了切分,只返回请求区域和相应级别的数据;
  • 数据更新快,或者说是实时的,当数据库中的空间数据变化后,再次请求的数据是改变后的,在客户端渲染后既是最新的情况;
  • 更灵活,可以只是返回每个专题数据的图层,而不是像栅格切片把很多专题数据渲染在一个底图中。

不可编辑

需要注意的是不要被矢量切片的矢量误导,虽然是矢量格式,并不意味者你可以编辑它们,矢量切片是为了读取和渲染优化的格式,如果你想在客户端编辑要素,最适合的是使用 OGC 的 WFS。

切片过程

切片生成过程,实际是空间数据到图片数据的转换过程,空间坐标消失了,转而形成屏幕坐标,图片没有空间参考(.geotiff 除外,但其体积过大,一般不用于切片格式),通过编号来表示排列次序。

矢量切片也是类似的,且因其为原始数据,体积较大,设计初衷是便于存储且存储结构清晰,并没有为网络传输优化,因此需要重新编码(我们这里称‘组织数据结构’为编码)。矢量数据一般分为空间坐标和属性数据,因此编码分为空间坐标和属性数据两部分的编码,重新编码的中心思想就是不损失元数据细节的情况下,尽量减小冗余,缩小数据体积。

GeoJSON、TopoJSON和.mvt 格式其实都是对数据的重新组织,一般来说 .mvt 压缩率更高,体积更小,GeoJSON 是比较可读的,比较容易让人看懂,TopoJSON 的可读性比较差,现实中根据实际需求选取矢量切片的格式。下面说说 MapBox 的矢量切片规范规定的编码过程。

编码过程

编码空间坐标数据涉及到从地理坐标到屏幕坐标的映射,MapBox 矢量切片规范采用的屏幕坐标是右方向+x,向下+y,左上角为坐标原点,在编码的过程中还会考虑简化要素坐标;编码属性过程类似,将所有属性key记录,所有的value 记录,分别编号,原数据中相应的 key 和 value 用编号代替。

另外,编码多边形时要注意线行进方向,一个简单的多边形时逆时针的,如果包含环,那么内边界必须是顺时针的,也就是说内边和外边方向是相反的。

在编码过程中,是有坐标简化过程的,根据不同的缩放级别和细节,适当调节简化的程度,类似我在 GIS算法之道格拉斯-普克算法 中提到的阈值,根据阈值来决定简化的程度。这里就是矢量切片技术相对于 WFS的优势,如果有10000个点距离很近,而且地图缩放级别很小,根本没有必要把所有数据都返回,WFS 会返回所有点,传输数据都要很长时间,渲染也会卡顿,矢量切片就会在服务器端简化数据再返回。

体验矢量切片

通过 GeoServer 发布矢量切片服务,并通过 OpenLayers 调用

使用 GeoServer 发布矢量切片图层

GeoServer 本身并不支持矢量切片的发布,至少目前的稳定版本 2.10 不支持,处于开发过程中的 2.11 中也是以扩展插件形式存在的。接下来我们就使用 GeoServer 来发布矢量切片服务,并使用 OpenLayers3 来调用,体验一下矢量切片的魅力。

配置 GeoServer 环境

GeoServer 是基于 Java 的,因此使用前需要你的机器中有安装 Java的环境,安装 JDK 和 jre,GeoServer 目前不支持 Java 1.9 及其以上版本。具体步骤如下:

  • 配置 Java 环境;
  • 配置 Tomcat 环境;
  • 下载 2.11 版本的开发版 GeoServer,我下载的是 .war 版本,放置在 Tomcat 的 webapps 目录,下载地址见附录;
  • 下载 2.11 版本的矢量切片插件:vectortiles-plugin,解压,并将其中四个 .jar 文件 copy 到 GeoServer 的 WEB-INF/lib 目录下,下载地址见附录;

准备矢量数据

这里我使用了成都市的简单河流矢量数据,并将其导入到 PostgreSQL 数据库中。

发布矢量切片

启动 Tomcat,进入 GeoServer 管理界面。像发布一般图层一样,只是多了一步在 Tile Caching 选项卡勾选 application/json;type=geojsonapplication/json;type=topojsonapplication/x-protobuf;type=mapbox-vector,你可以请求三种矢量切片格式的任意一种。只需要多做这一步,你就可以支持矢量切片格式了,当然如果你也可以同时支持 image/pngimage/jpeg

这里写图片描述
图2 GeoServer 配置

这里我发布了北京市的行政区划和河流数据。

OpenLayers3 请求矢量切片

OpenLayers3 中有一个数据源ol.source.VectorTile 专门用来请求适量切片数据源。我们使用这个类来加载刚刚发布的北京市的行政区划和河流数据。

行政区划图层:

// 行政区划图层
var vectortileAdminLayer = new ol.layer.VectorTile({
  // 矢量切片的数据源
  source: new ol.source.VectorTile({
    format: new ol.format.MVT(),
    tileGrid: ol.tilegrid.createXYZ({maxZoom: 22}),
    tilePixelRatio: 1,
    // 矢量切片服务地址
    url: 'http://127.0.0.1:8080/geoserver/gwc/service/tms/1.0.0/' +
    'china:beijing_china_osm_admin_3857@EPSG%3A900913@pbf/{z}/{x}/{-y}.pbf'
  }),
  // 对矢量切片数据应用的样式
  style: new ol.style.Style({
    fill: new ol.style.Fill({
      color: 'rgb(140,137,129)'
    }),
    stroke: new ol.style.Stroke({
      color: 'rgb(220, 220, 220)',
      width: 1
    })
  })
});

河流图层:

// 河流图层
var vectortileLayer = new ol.layer.VectorTile({
  // 矢量切片的数据源
  source: new ol.source.VectorTile({
    format: new ol.format.MVT(),
    tileGrid: ol.tilegrid.createXYZ({maxZoom: 22}),
    tilePixelRatio: 1,
    // 矢量切片服务地址
    url: 'http://127.0.0.1:8080/geoserver/gwc/service/tms/1.0.0/' +
      'china:beijing_china_osm_waterways_3857@EPSG%3A900913@pbf/{z}/{x}/{-y}.pbf'
  }),
  // 对矢量切片数据应用的样式
  style: new ol.style.Style({
    stroke: new ol.style.Stroke({
      color: 'rgb(163,204,255)',
      width: 3
    })
  })
});

把这两个图层添加到地图中,效果是这样的:

这里写图片描述
图3 更改样式之前

更改河流图层的样式,

style: new ol.style.Style({
  stroke: new ol.style.Stroke({
    color: 'rgb(163,204,25)',
    width: 5
  })
})

最终的效果如下:

这里写图片描述
图4 更改样式之后

虽然只演示了线的样式定制,点和面同样的可以定制。这里矢量切片给了我们一个可能,地图供应商提供数据,客户可以定制同一套数据下的不同样式地图,这就是说:地图定制化 的时代已经悄悄来临,不是么?

总结

本文首先介绍了现存切片技术的不足,然后介绍了矢量切片相对于现存切片技术的优势,以及矢量切片技术规范中的一些关键技术步骤,最后使用 GeoServer 配合 OpenLayers 实验了矢量切片。如果你想深入了解规范,在自己的地图服务器中实现自己的矢量切片服务,让自己的客户定制自己的地图,可以去附录中的 MapBox 矢量切片规范看看。

好了,就写到这里,文中的代码可以到我的 GitHub 中查看。

参考与附录

MapBox 的矢量切片规范:https://www.mapbox.com/vector-tiles/specification/
GeoServer 2.11 下载地址:http://geoserver.org/release/master/
GeoServer Vector Tiles plugin 下载地址:http://ares.boundlessgeo.com/geoserver/master/ext-latest/

阅读更多

没有更多推荐了,返回首页