一、WMTS简介
WMTS,即Web地图瓦片服务(Web Map Tile Service),由OGC(开放地理信息联盟)制定。根据WMTS标准,可以使我们轻松的访问瓦片数据。
WMTS提供了一种采用预定义地图瓦片发布数字地图服务的标准化解决方案,它最重要的特征是采用瓦片缓存技术缓解WebGIS服务器端数据处理的压力,提高前后端交互响应速度。
WMS(Web地图服务)提供可定制地图的服务,是一个动态数据或用户定制地图(需结合SLD-Style Layer Descriptor)的理想解决方法。例如,可以在GeoServer中通过修改SLD样式文件来随时自定义地图样式:
随时都可以修改,而且一修改在客户端就能实时渲染出变化。根本原因是WMS的地图数据并没有通过切片放置到硬盘中,它的地图数据是实时处理并传输到客户端的。
而WMTS标准需要地图数据切片后放置在硬盘中,然后再调用数据传输到客户端。
WMTS牺牲了提供定制地图的灵活性,代之以通过提供静态数据(瓦片地图)来增强伸缩性,这些静态数据的范围框和比例尺被限定在瓦片坐标系(前面文章已经介绍过)中。这些固定的瓦片地图数据集使得对WMTS服务的实现可以使用一个仅简单返回已有文件的Web服务器即可,同时使得可以利用一些标准诸如分布式缓存的网络机制实现伸缩性。
二、WMTS的接口
WMTS服务支持RESTful和KVP访问,其接口包括:GetCapabilities —— 获取服务元数据,元数据描述该服务的功能和包含的信息
GetTile —— 获取地图瓦片
GetFeatureInfo(鸡肋功能,不常用) —— 通过在WMTS图层上指定一定的条件,返回指定的地图瓦片内容对应的要素信息
2.1、GetCapabilities(获取服务元数据)
GetCapabilities操作的参数:
示例:
ArcGIS Online发布的美国地图WMTS服务的基地址是:
http://services.arcgisonline.com/arcgis/rest/services/Demographics/USA_Population_Density/MapServer/WMTS/
那么要查询它的元数据,就可以使用以下URL:
http://services.arcgisonline.com/arcgis/rest/services/Demographics/USA_Population_Density/MapServer/WMTS/?Service=GetCapabilities
查询结果如下所示(节选):
2.2、GetTile(获取地图瓦片)
GetTile的参数:
示例:
要查询以上ArcGIS Online发布的美国地图WMTS服务的层级为4,列号为3,行号为5的一块瓦片,可以这样请求:
http://services.arcgisonline.com/arcgis/rest/services/Demographics/USA_Population_Density/MapServer/WMTS/?tilematrixset=EPSG:3857&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image/png&TileMatrix=4&TileCol=3&TileRow=5
请求结果:
2.3、GetFeatureInfo
GetFeatureInfo的参数:
查询要素信息一般使用OGC的WFS(Web Feature Service),所以就不详细介绍WMTS的GetFeatureInfo这个接口了
三、加载ArcGIS产品发布的WMTS服务数据
3.1、加载ArcGIS Online发布的WMTS服务数据
ArcGIS Online中的美国地图的WMTS服务基地址为:
http://services.arcgisonline.com/arcgis/rest/services/Demographics/USA_Population_Density/MapServer/WMTS/
可以使用OpenLayers中的ol.layer.Tile类 + ol.source.WMTS类来加载WMTS服务数据。
效果:
代码:
ArcGISOnline_WMTS_Map.html:
加载ArcGIS Online发布的WMTS服务数据// 首先设置好WMTS瓦片地图的瓦片坐标系 let projection = ol.proj.get('EPSG:3857'); // 获取web墨卡托投影坐标系 let projectionExtent = projection.getExtent(); // web墨卡托投影坐标系的四至 let width = ol.extent.getWidth(projectionExtent); // web墨卡托投影坐标系的水平宽度,单位米 let resolutions = []; // 瓦片分辨率 let matrixIds = []; // 可以在元数据中找到 for(let z = 0; z < 14; z++){
resolutions[z] = width / (256 * Math.pow(2, z));
matrixIds[z] = z;
}
let wmtsTileGrid = new ol.tilegrid.WMTS({
origin: ol.extent.getTopLeft(projectionExtent), // 原点(左上角) resolutions: resolutions, // 分辨率数组 matrixIds: matrixIds // 矩阵ID,就是瓦片坐标系z维度各个层级的标识 });
// WMTS数据源与地图 let wmtsSource = new ol.source.WMTS({
url: "Folder: /" +
"Demographics/USA_Population_Density/MapServer/WMTS/",
matrixSet: 'EPSG:3857', // 投影坐标系参数矩阵集 format: 'image/png', // 图片格式 projection: projection, // 投影坐标系 // 投影坐标系 tileGrid: wmtsTileGrid
});
let wmtsLayer = new ol.layer.Tile({
source: wmtsSource
});
let map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.Stamen({
layer: 'terrain'
})
}),
wmtsLayer
],
view: new ol.View({
center: [0, 0],
zoom: 3
})
});
可以发现并不是那么容易,需要我们自己定义瓦片坐标系,也就是自定义初始化ol.tilegrid.WMTS类。
关键的地方就是生成分辨率resolutions,即首先得到Web墨卡托投影坐标系的宽度值(单位米),然后除以瓦片坐标系对应层级的瓦片总宽度就得到对应层级的分辨率了。前面的文章也都讲过相关的原理。
3.2、加载ArcGIS Server发布的WMTS服务数据
我这里使用ArcGIS Server发布了广东省路网shp数据,其WMTS基地址为:
https://localhost:6443/arcgis/rest/services/gd_roads/MapServer/WMTS
效果:
代码:
加载ArcGIS Server发布的WMTS服务数据// 首先设置好WMTS瓦片地图的瓦片坐标系 let projection = ol.proj.get('EPSG:3857'); // 获取web墨卡托投影坐标系 let projectionExtent = projection.getExtent(); // web墨卡托投影坐标系的四至 let width = ol.extent.getWidth(projectionExtent); // web墨卡托投影坐标系的水平宽度,单位米 let resolutions = []; // 瓦片分辨率 let matrixIds = [];
for(let z = 0; z < 14; z++){
resolutions[z] = width / (256 * Math.pow(2, z));
matrixIds[z] = z;
}
let wmtsTileGrid = new ol.tilegrid.WMTS({
origin: ol.extent.getTopLeft(projectionExtent), // 原点(左上角) resolutions: resolutions, // 分辨率数组 matrixIds: matrixIds // 矩阵ID,就是瓦片坐标系z维度各个层级的标识 });
// WMTS数据源与地图 let wmtsSource = new ol.source.WMTS({
url: "https://localhost:6443/arcgis/rest/services/gd_roads/MapServer/WMTS",
layer: 'gd_roads', // 图层名 version: '1.0.0', // WMTS版本 // 投影坐标系矩阵集,一定要和WMTS capabilities文档中一致,否则会加载失败 matrixSet: 'default028mm',
format: 'image/png', // 图片格式 projection: projection, // 投影坐标系 requestEncoding: 'KVP', // 请求的编码方式,默认就是'KVP' // 在WMTS capabilities文档中对应的样式名,一定要写,否则会加载失败 style: 'default',
tileGrid: wmtsTileGrid // 投影坐标系 });
let wmtsLayer = new ol.layer.Tile({
source: wmtsSource
});
let map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.Stamen({
layer: 'terrain'
})
}),
wmtsLayer
],
view: new ol.View({
center: [0, 0],
zoom: 3
})
});
一个经验之谈就是:如果加载失败,请先检查参数是否与WMTS GetCapabilities文档里的参数一致,一定要严格一致!
四、加载GeoServer发布的WMTS服务数据
GeoServer同样也支持WMTS标准,使用OpenLayers同样也能加载GeoServer发布的WMTS服务数据。
我这里使用GeoServer发布了广东省路网shp数据,其WMTS基地址为:
http://localhost:8080/geoserver/gwc/service/wmts
效果:
代码:
加载GeoServer发布的WMTS服务数据// 首先设置好WMTS瓦片地图的瓦片坐标系 let projection = ol.proj.get('EPSG:900913'); // 获取web墨卡托投影坐标系 let projectionExtent = projection.getExtent(); // web墨卡托投影坐标系的四至范围 let width = ol.extent.getWidth(projectionExtent); // web墨卡托投影坐标系的水平宽度,单位米 let resolutions = []; // 瓦片地图分辨率 let matrixIds = []; //矩阵ID for(let z = 0; z < 10; z++){
resolutions[z] = width / (256 * Math.pow(2, z));
matrixIds[z] = "EPSG:900913:" + z; // 注意这里的matrixId的格式为EPSG:900913:z }
let wmtsTileGrid = new ol.tilegrid.WMTS({
origin: ol.extent.getTopLeft(projectionExtent), // 原点(左上角) resolutions: resolutions, // 瓦片地图分辨率 matrixIds: matrixIds // 矩阵ID,就是瓦片坐标系z维度各个层级的标识 });
// WMTS数据源与地图 let wmtsSource = new ol.source.WMTS({
url: "http://localhost:8080/geoserver/gwc/service/wmts",
layer: "guangdong:gd_roads", // 对应的图层 matrixSet: 'EPSG:900913', // 投影坐标系参数矩阵集 format: 'image/png', // 图片格式 projection: projection, // 投影坐标系 // 投影坐标系 tileGrid: wmtsTileGrid
});
let wmtsLayer = new ol.layer.Tile({
source: wmtsSource
});
let map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.Stamen({
layer: 'terrain'
})
}),
wmtsLayer
],
view: new ol.View({
center: [0, 0],
zoom: 3
})
});
这里需要注意的是matrixId的格式为EPSG:900913:z,而不再是和上面一样单纯的数字了。
五、加载天地图的WMTS服务数据
天地图的大部分地理数据都是依据WMTS规范发布:
现在来加载天地图发布的影像底图:
效果:
源代码:
加载天地图发布的WMTS影像服务数据// 首先设置好WMTS瓦片地图的瓦片坐标系 let projection = ol.proj.get('EPSG:900913'); // 获取web墨卡托投影坐标系 let projectionExtent = projection.getExtent(); // web墨卡托投影坐标系的四至范围 let width = ol.extent.getWidth(projectionExtent); // web墨卡托投影坐标系的水平宽度,单位米 let resolutions = []; // 瓦片地图分辨率 let matrixIds = [];
for(let z = 1; z < 18; z++){
resolutions[z] = width / (256 * Math.pow(2, z));
matrixIds[z] = z;
}
let wmtsTileGrid = new ol.tilegrid.WMTS({
origin: ol.extent.getTopLeft(projectionExtent), // 原点(左上角) resolutions: resolutions, // 瓦片分辨率 matrixIds: matrixIds // 矩阵ID,就是瓦片坐标系z维度各个层级的标识 });
// WMTS数据源与地图 let wmtsSource = new ol.source.WMTS({
url: "http://t0.tianditu.gov.cn/img_w/wmts?tk=你的天地图key", // 天地图key去官网很容易申请 layer: 'img', // 图层名 version: '1.0.0', // WMTS版本 // 投影坐标系矩阵集,一定要和WMTS capabilities文档中一致,否则会加载失败 matrixSet: 'w',
format: 'tiles', // 图片格式 projection: projection, // 投影坐标系 requestEncoding: 'KVP', // 请求的编码方式,默认就是'KVP' // 在WMTS capabilities文档中对应的样式名,一定要写,否则会加载失败 style: 'default',
tileGrid: wmtsTileGrid // 投影坐标系 });
let wmtsLayer = new ol.layer.Tile({
source: wmtsSource
});
let map = new ol.Map({
target: 'map',
layers: [
wmtsLayer
],
view: new ol.View({
center: [0, 0],
zoom: 1
})
});
以后开发就可以基于WMTS规范来加载天地图的各种底图了,非常方便!
六、总结
其实掌握加载WMTS服务数据非常简单,就是首先要基于WMTS服务的基地址查询对应的元数据,然后根据元数据文档里写的参数去请求瓦片数据就好了。
关键就是参数要正确!