说明:本月的主要工作都是围绕制作矢量切片这一个核心问题进行的,所以2月的主题就以这个问题为主,目前分支出来的一些内容主要包括了TMS(Tile map service),OpenLayers3中的ProjectionResolution以及proj4js在OpenLayers3中的应用,这些在这篇文章之后会继续展开,作为本月的番外内容。

一、GIS数据与OGC标准地图服务 

  本节主要是介绍一些基础的数据概念以及基本的WebGIS地图服务,如对这些内容已经熟知,可直接跳过本节。

  1)GIS中的矢量与栅格数据

  熟悉GIS的人应该都知道,在GIS中的数据分类有很多种方式,其中最常用的一种是根据数据组织结构方式的不同而分类成矢量数据栅格数据的两种类型。其中栅格数据以二维矩阵的形式来表示地理空间信息的数据结构,其中数据的最小存在单元是以像素的形式存在,可以理解为和图片的组织结构类似,以分辨率等特征作为精度的定义标准。

                     

                 栅格数据                   矢量数据

  而矢量数据则是试图利用点、线、面等几何要素来表现这个世界,其数据结构紧凑精准,数据图形质量好,有利于地理信息检索与网络传输等。其中矢量数据的最小单元是以点的形式存在,点构成线,线组成面,面构造出体。所以,我个人看来矢量数据应该更贴近于信息的精准分析与计算,而栅格数据则偏重于信息的表达(主要受制于当前图像处理技术的瓶颈)。

  2)OGC地图服务

  在WebGIS中,访问数据是通过访问服务器端的数据库来获取数据,鉴于GIS数据的特殊性,在这一套标准的请求响应模型中引入了一套基于OGC标准的地图服务标准,在这里我只介绍几个与本文有关的服务(如果你需要了解一个完整的内容,在这里可以找到很多资料:http://blog.csdn.net/wildboy2001/article/details/7743350):

  - WMS(Web Map Service)

  Web地图服务,利用地理空间信息的数据输出地图,地图本身只是一张图片,其中包括了图片的宽高、坐标系统、图片格式以及渲染方式,也正是因为本身的简洁性,读取传输速度都比较快,要高于WFS

  //WMS请求实例

http://localhost:8080/geoserver/szdata/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image/png&TRANSPARENT=true
&LAYERS=szdata:DLZXX_2011_PL_10000_3857&SRS=EPSG:4326&STYLES=&WIDTH=1347&HEIGHT=336
&BBOX=113.68754425048829,22.5346435546875,114.61245574951172,22.7653564453125

  - WFS(Web Feature Service)

  Web要素服务,请求获取要素,最小单元是以要素的形式存在的,用户可以通过与——请求获得的矢量数据——在前端渲染绘制的几何图形进行交互,从而达到对矢量要素的控制。

  //WFS请求实例

http://localhost:8080/geoserver/wfs?service=WFS&request=GetFeature&version=1.1.0&outputFormat=application/json
&typename=szdata:DLZXX_2011_PL_10000_new3857

  - TMS(Tile Map Service)

  (详细内容见番外篇)

  所以,为了带来更好更快的用户体验,目前许多主流WebGIS应用都采用了栅格切片技术,通过缓存切片的形式使得地图数据的浏览体验更顺畅。打开你的浏览器,F12出控制台,进入任意一家地图供应商提供的地图应用,你会发现大部分的地图数据都是以切片的形式请求获得的,我在这里就不举例了。栅格地图的切片应用是很广泛,可在我们的日常工作中遇到的需求往往要比这些功能需求较浅的商业性地图复杂,有的时候用户甚至会提出需要地图配色的编辑修改功能这样的需求,这是商业主流地图所达不到的,因为栅格切片在完成切图之后,你所能控制的最小单位是一张图片,失去了对图片上地理信息的交互能力。

  总结来看,栅格切片存在以下的几个缺点:

  - 地图数据一次渲染,无法修改

  - 无交互能力

  那可否用WFS来替代呢?直接用WFS请求获取矢量数据,这样不就获得了交互能力吗?当然,如果在你的应用中矢量数据量不大的情况下,这样做也是可行的,但是当一旦数据量大了起来,前端对于数据的请求和响应处理渲染会提高客户端的硬件门槛,而频繁的交互操作也会对服务器产生压力。

  直接加载的矢量数据与对栅格地图进行切片这两种方式看起来好像有些互补,如果能将这二者结合起来的话应该会很美好: 矢量+切片=矢量切片

二、矢量切片

  1)什么是矢量切片?

  和栅格切片一样的思路,以金字塔的方式切割矢量数据,只不过切割的不是栅格图片,而是矢量数据的描述性文件,目前矢量切片主要有以下三种格式:GeoJSON,TopoJSON和MapbBox Vector Tile(MVT)。

栅格切图后文件存储形式

矢量切图后文件存储形式

切片中的数据结构

  从上面的两张图可以看出,其实思路是一致的,因此,矢量切图结合了矢量数据与栅格切图的优势互补:

  - 前端缓存切片,提高地图使用的体验

  - 粒度上来看,矢量切图继承了矢量数据的特性,以要素为单位进行管理,加强了细节上的把控能力

  - 在保证体验的前提下,为用户提供地图数据样式动态修改的功能,加强了地图定制化的程度

  - 数据的实时性

  2)如何生成矢量切片?

   目前就博主所知道的矢量切片生成方式共有以下几种:1)ArcGIS 系列产品:利用ArcGIS Pro生成矢量切片,然后发布在ArcGIS Online上;2)Mapbox,目前已经提出了一套开放的矢量切片标准,并被多个开源团队所接受,但具体的产品使用我并不熟悉,所以还请自行搜索资料,如果后期有接触到这方面,我会继续补充;3)GeoServer,在2.11beta版中出现了对矢量切片的支持,主要依赖于开源插件geoserver-2.11-SNAPSHOT-vectortiles-plugin以及内嵌的GeoWebcahce完成切片工作。4)自己编写切片工具,这主要针对于对这一套体系非常熟悉的GIS编程人员,我本人也属于入门级别,所以在此也没法提供更多详细的内容。本文主要采用的切片方式就是利用第3种方法,利用GeoServer作为GIS应用服务器生成矢量切片:

  2-1)切片前需要确认的环境配置:

  a) JAVA环境:GeoServer是一套基于JAVA环境下的开源项目,因此需要配置好JAVA环境,博主采用的是JAVA1.8,因为最新版的GeoServer文档中提出需要JAVA_8,低配版本(JAVA7)我也试过,但没有成功,所以为了稳妥起见,我推荐你使用JAVA8,特别要注意的是,GeoServer当前不支持JAVA9。

  b) Tomcat:Web容器,没有限制,按自己的技术方向选择。

  c) GeoServer 2.11以及其插件geoserver-2.11-SNAPSHOT-vectortiles-plugin

  d) 矢量数据:我在此使用的是 深圳道路【EPSG:4326】的矢量数据,请特别注意括号中的坐标系,在后面我会具体讲到相关的问题。

  2-2)切片过程

  a) 首先,我们将下载好的GeoServer2.11的war包直接放入/%TomcatHome%/WebAPP的文件夹中,启动Tomcat完毕后,访问以下链接: http://localhost:8080/geoserver, 如果出现以下页面则说明部署成功。

  b) 然后,我们将下载好的插件geoserver-2.11-SNAPSHOT-vectortiles-plugin进行解压,然后将其直接copy到tomcat中部署的GeoServer文件夹的WEB-INF的lib文件夹下,重启tomcat;

  c) 启动完成后,访问GeoServer主页中的数据菜单中的数据存储,在页面中选择添加新的数据存储,这些步骤和发布普通数据的步骤一致,在此就不赘述了。

  但是在发布过程中有一个编辑图层的步骤需要注意,在进入编辑图层的页面之后,记得点击选中Tile caching选项卡,你会发现Tile Image Foramt属性中多出了几种数据格式,这就说明你的插件生效了。

  d) 按照你的需求选中需要切片的格式,如果第一次切的话,我建议可以用GeoJSON作为入门,因为GeoJSON格式的数据可读性较强,能够给我们一个比较直观的认识。

  e) 从左边菜单栏点击进入Tile caching的Tile Layer子项,在Tile Layer列表中你可以看到已经被你发布成功的Tile Layer,通过preview的选择下拉框中的选项你可以发现,之前发布时被选中的格式都出现了,这就说明你的切片数据已经发布成功了!

   3)调用矢量切片

  调用矢量切片的方式有很多种,OpenLayers3,Leaflet等等都可以达到目的(不过听说好像LeafLet目前仅支持WGS84投影坐标系的矢量切片),因此在这里使用的调用请求工具是OpenLayers3,具体代码如下:

 var projection4326 = new ol.proj.Projection({
    code: 'EPSG:4326',
    units: 'degrees',
  });  
 var defaultView = new ol.View({
    projection: projection4326,
    center: [114.15, 22.65],
        //new ol.proj.fromLonLat([114.15, 22.65]),
    zoom: 11
  });  function loadVectorTile(){  
   //参数设置:图层名称 / 投影坐标系 / 初始化样式 
  var layerName = 'szdata:DLZXX_2011_PL_10000_4326';
  var layerProjection = '';
  var initStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'rgb(163,204,25)',
width: 5
})
});
//矢量切片图层
var vectorTile = new ol.layer.VectorTile({
title:"深圳道路-VectorTile",
style: initStyle,
projection: projection4326,
     //矢量切片数据
source: new ol.source.VectorTile({
       projeciton: projection4326,
format: new ol.format.GeoJSON(),

tileGrid: ol.tilegrid.createXYZ({
          extent: ol.proj.get('EPSG:4326').getExtent(),
          maxZoom: 22
}),
       tilePixelRatio:1,
       
//发出获取切片的请求
       tileUrlFunction: function(tileCoord){
                return '/geoserver/gwc/service/tms/1.0.0/'
+layerName+'@EPSG%3A'+layerProjection+'@geojson/'+(tileCoord[0]-1)
+ '/'+tileCoord[1] + '/' + (Math.pow(2,tileCoord[0]-1)+tileCoord[2]) + '.geojson';
}
      })
    });
   

   //构造Map对象

   //你需要在页面中提供一个id='map'的div
    map = new ol.Map({
        target: 'map',
        layers: [

          new ol.layer.Tile({
            source: new ol.source.OSM();
          }),

        ],
        view:defaultView,
        controls:[
            new ol.control.ScaleLine(),
            new ol.control.ZoomSlider(),
            new ol.control.LayerSwitcher(),
            new ol.control.OverviewMap(),
            new ol.control.Zoom()
        ],
      });

    map.addLayer(vectorTile);

}

//千万别忘记这是一个独立的JS文件,你需要将这一段JS代码以Onload的方式加载到页面中

  上述代码中,在vectorSource的属性tileUrlFunction中,我对coordinate(一个存储了XYZ参数的数组)进行了一些简单的处理,从而使EPSG:4326请求下的XYZ能够与切图结果相匹配,有一些拼凑的嫌疑,导致了这段代码并不具有普适性,所以,请读者根据自己的情况进行调整,但整个大体思路基本一致,主要是切片行列号的匹配方面需要额外注意。

  最后切片页面的效果如下(关于样式的问题,在OL3中你可以通过设置Layer的Style属性进行修改样式,和WFS请求获取的矢量数据处理方式一致,这也就实现了在完成切片缓存的前提下,得到了地图要素样式的控制权。):

矢量切片效果图

 控制台请求响应过程

   4)遇到的一些问题

  4-1)我想检查一下我的切片数据,在哪里能够找到呢?

  首先,你需要了解的是,完成切片工作的其实是GeoWebCache,而GeoWebCache的数据存储文件的默认路径一般为:

  C:\Users\%YOUR-PC-NAME%\AppData\Local\Temp\geowebcache

  你可以在这里面看到各个图层的切片数据,当你打开你的目标图层文件夹时,如果你发现是空的,千万不要着急,因为GeoWebCache中切片的生成本来就是一个动态的过程,

  若实在是不放心,你可以通过进入GeoServer的管理页面-->左侧菜单栏中的Tile caching-->子菜单Tile Layers-->图层列表中选择一个Preview的方式进行预览,然后在预览界面进行缩放,你会发现刚才的文件夹里多了很多数据文件,这下你就可以放心的进行下面的调用工作了。但有一点需要提到的是:GeoServer目前还不提供矢量切片的预览,你通过查看预览页面的源码就能发现,当前预览功能中的代码还是采用的OpenLayers2的老代码,所以当你选择预览vector tile时,只能看到一个个的红叉。

  4-2)我的切片数据调用不出来怎么办?

  在确认了你的数据是没有问题之后,采用OpenLayers3代码进行调用,但仍有可能会出现资源地址不存在(即404错误)或者请求响应都成功了可是矢量切片的图层仍未加载到地图上。这些问题都和一个很关键的属性有关系,就是我上面提到的Projection——投影坐标系。在OpenLayers3 中有这么一些类是需要你提供投影参数的:

  ol.View / ol.layer.Vector / ol.source.Vector

  a)404资源不存在:最有可能的原因就是,你在在创建vectorTileSource对象时,url中设置的请求参数Projection与你数据视图的Projection不一致,举个例子,如果你发出的请求是以900913(Web-mercator)为切图投影,而你发布的数据所采用的投影是4326(WGS 84):

'http://localhost:8080/geoserver/gwc/service/tms/1.0.0/shenzhenDL_4326@EPSG:900913@geojson/{z}/{x}/{-y}.geojson'

导致了切出来的矢量切片的行列号是在EPSG:900913下产生的,由于EPSG:4326和EPSG:900913之间的不匹配,导致了你用4326的行列号参数XY去请求实际生成的900913的行列号切片,导致了无法准确的访问资源。当然还有一个需要提到的小细节:在创建vectorTileSource对象时,有一个非常重要的属性——tileGrid【ol.tilegrid】,这是用来创建切片的,如果你所切的图层资源的投影坐标系不是默认的EPSG:3857(也就是EPSG:900913),你需要额外的为你的tilegrid限制一个范围Extent,如上述代码中所写道的一样。因为在OpenLayers3中的源码中可以看出(ol.source.XYZ),所有的默认的投影坐标都是EPSG:3857,所以当你使用其他坐标系的数据时,需要将默认的参数全部按照你的投影坐标系进行重新声明,而OL3中也提供了一系列的Projection的转换方法。

  b)请求响应都没有问题,但是图层并未加载出来:其实这个问题我暂时还没有完全解决,我的初步设想是因为我在GeoServer上发布数据时,原始数据的Projection并未被识别出来,导致了最终图层的无法加载,这可能与投影坐标的转换有关系,在后续我将继续完成这个问题的探索。

  4-3) 如果我发布的数据采用的坐标系既不是EPSG:4326(WGS84),又不是EPSG:900913(Web Mercator),而是其他坐标系该怎么办呢?

  之所以把这个问题列出来是因为在GeoServer中,默认的Tile grid切片格网只定义了4326和900913这两种类型,如果你需要更多其他投影坐标系下的切片,你需要在Geoserver的Tile Caching选项卡下的子选项tile grid中定义属于自己的切片格网,当然,OL3中也没有太多的投影可供你使用,与之相对应的,你需要利用Proj4js去定义你所需要的投影坐标系,然后在你的OL3代码中调用即可,具体关于Proj4js的内容,我会单列一篇文章进行介绍:矢量切片(Vector tile)番外一:Proj4js

   5)总结

  在这篇博客中,主要是简单地介绍了关于矢量切片的制作与使用方法,没有深入的去探索矢量切片的实现原理与算法,如果以后有时间,我会接着这篇博客继续学习关于切片算法以及实现过程的相关内容。

   其实第一次接触矢量切片的时候,我并没有太多的直观认识,而网络上的资料也十分有限,能够找到的博客也是寥寥无几,一来是因为GIS开发较少,二来矢量切片的技术还处于一个初步发展的阶段,基本上都是在开源上使用,ArcGIS系列产品虽有涉及,但也处于一个探索的过程中,所以我写这篇博客既是为了总结之前的学习,也是为了让更多的人能够少走一些弯路。

  以下附上我在学习过程中找到的比较有价值的资料:

  矢量切片的制作过程:http://blog.csdn.net/qingyafan/article/details/53367204,这个博客主要生产的内容是关于WebGIS这一块的,应该是为数不多的GIS技术博主,并保持着一定的更新频率,若你对WebGIS有兴趣的话可以follow一下。

  切片数据的初步研究: http://www.cnblogs.com/naaoveGIS/p/4982549.html,这个博客比较全面,GIS算法、数据库、中间件、Web以及开源都有涉及,风格也比较接地气,不过有些内容比较深入,不仅仅是停留在应用层面,所以读这个博客需要认真细致的去思考。

矢量切片(Vector tile)的更多相关文章

  1. 【GISER && Painter】矢量切片(Vector tile)

    说明:本月的主要工作都是围绕制作矢量切片这一个核心问题进行的,所以2月的主题就以这个问题为主,目前分支出来的一些内容主要包括了TMS(Tile map service),OpenLayers3中的Pr ...

  2. 使用GeoServer+OpenLayers发布和调用WMTS、Vector Tile矢量切片服务 | Publishing and Calling WMTS, Vector Tile Service Using GeoServer + OpenLayers

    Web GIS系列: 1.搭建简易Web GIS网站:使用GeoServer+PostgreSQL+PostGIS+OpenLayers3 2.使用GeoServer+QGIS发布WMTS服务 3.使 ...

  3. 矢量切片(Vector tile)番外一:Proj4js

    说明:番外篇是对正篇矢量切片(Vector tile)中提到的一些值得继续延伸的关注点继续进行探索和学习,所涉及的内容以解决实际问题为主要导向. 一.新的需求? 在完成了矢量切片的工作后,新的需求出现 ...

  4. 【GISER && Painter】矢量切片(Vector tile)番外一:Proj4js

    说明:番外篇是对正篇矢量切片(Vector tile)中提到的一些值得继续延伸的关注点继续进行探索和学习,所涉及的内容以解决实际问题为主要导向. 一.新的需求? 在完成了矢量切片的工作后,新的需求出现 ...

  5. 【转】10.4新特性-ArcGIS 10.4矢量切片介绍

    原文地址:http://zhihu.esrichina.com.cn/article/567 1.矢量切片简介GIS的底图一直使用金字塔技术进行切图,使用户能够快速访问指定级别的地图或者影像.但是切图 ...

  6. PostGIS计算矢量切片(一)--渲染数据

        没写错,是使用postgis计算出来矢量切片.在这之前先准备一个数据:一个GIS数据表(本例中数据为一百万的点数据,坐标:4326),并在表中添加x,y字段,方便后面的数据筛选.sql中用到了 ...

  7. ArcGIS Pro 自定义坐标系地图矢量切片制作

    ArcGIS Pro从1.4版本起就支持自定义坐标系统地图的矢量切片制作了. 步骤: 1. 将地图有全图范围缩小到屏幕像素大约10*10像素的范围,然后记录下地图的比例尺.这一步十分关键,不然系统要经 ...

  8. 使用tippecanoe把GeoJSON制作成供mapbox展示的矢量切片vectortile

    本文记录一下把geojson格式的数据制作成本地的矢量切片,并在mapbox中展示的过程. 1.切片 1.1 矢量数据需要先转换为geojson,如果是shp格式可以使用QGIS或者下载shp2gwo ...

  9. 矢量切片应用中geoserver与geowebcache分布式部署方案

    在进行GIS项目开发中,常使用Geoserver作为开源的地图服务器,Geoserver是一个JavaEE项目,常通过Tomcat进行部署.而GeoWebCache是一个采用Java实现用于缓存WMS ...

随机推荐

  1. (中等) POJ 1703 Find them, Catch them,带权并查集。

    Description The police office in Tadu City decides to say ends to the chaos, as launch actions to ro ...

  2. (简单) POJ 1321 棋盘问题,回溯。

    Description 在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别.要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子 ...

  3. 图片拉伸iOS

    - (UIImage *)stretchableImageWithLeftCapWidth:(NSInteger)leftCapWidth topCapHeight: (NSInteger)topCa ...

  4. mysql优化------2 查看系统性能(表大小,I/o性能)

    三:判断mysql I/0 性能的一种方式(网络搜集供参考) show global status like 'innodb_dblwr%'\G   如果innodb_dblwr_pages_writ ...

  5. iOS开发——Localizable.strings

    这篇写的不多,但是绝对诚意满满.不会像别人一样,要不不详细,要不罗里吧嗦一堆. 1.创建Localizable.strings文件 Command+N—>iOS—>Resource—> ...

  6. Java-JNA调用DLL(转)

    源:JNA调用DLL 介绍 给大家介绍一个最新的访问本机代码的Java框架—JNA. JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的J ...

  7. .NET中四种常用事物

    在一个MIS系统中,没有用事务那就绝对是有问题的,要么就只有一种情况:你的系统实在是太小了,业务业务逻辑有只要一步执行就可以完成了.因此掌握事务 处理的方法是很重要,进我的归类在.net中大致有以下4 ...

  8. eclipse中集成svn maven开发手册---创建提分支

    开发时,需要拉取分支进行修改等操作 右键项目,选择team->分支/标记 输入创建分支地址 注意: 1,创建分支路径时,最后一层文件名称为项目的名称 2,点击浏览按钮可能会出现无法选择,且ecl ...

  9. Selenium关于Page Objects

    介绍页面对象设计模式.一个页面对象表示在你测试的web页面用户交互的界面. 使用页面对象模式的有点: 创建可重用的代码可以在多个测试用例中使用 减少重复的代码量 如果用户界面改变,只需要修改一个地方 ...

  10. Linux内存布局

    在上一篇博文里,我们已经看到Linux如何有效地利用80x86的分段和分页硬件单元把逻辑地址转换为线性地址,在由线性地址转换到物理地址.那么我们的应用程序如何使用这些逻辑地址,整个内存的地址布局又是怎 ...