一、概述
本文主要介绍Cesium对WMS地图服务GetFeatureInfo接口的调用过程。
示例中介绍的WMS地图服务采用GeoServer发布。
二、WMS地图服务
Web地图服务(Web Map Service,简称WMS)将地理信息动态生成空间参考数据的地图。
WMS提供了一个简单的HTTP接口,用于从一个或多个分布式地理空间数据库请求地图图像。
WMS请求定义了要处理的地理图层和感兴趣的区域。对请求的响应是一个或多个可以在浏览器应用中显示的地图图像(以JPEG、PNG等格式返回)。
WMS地图服务定义的三个接口是GetCapabilities、GetMap和GetFeatureInfo,其中GetFeatureInfo是可选的。
GetCapabilities接口的目的是获取服务元数据。GetMap接口返回一张地图。GetFeatureInfo接口用于获取地图指定空间位置的要素信息。
三、GetMap
GetMap接口根据请求的图层和空间范围返回一张指定像素大小图片。请求参数如下:
四、GetFeatureInfo
GetFeatureInfo接口旨在为WMS的客户端提供有关先前地图请求返回的地图图片中的特征的更多信息。
GetFeatureInfo的典型用例是,用户看到映射请求的响应,并在map上选择一个点(I,J)来获取更多信息。
因为WMS协议是无状态的,GetFeatureInfo请求通过包括大多数原始GetMap请求参数(除版本和请求外)。
从空间语境看GetMap请求中的信息(BBOX、CRS、宽度、高度),以及用户选择的I、J位置,WMS可以(可能)返回有关该位置的其他信息。
五、Cesium调用GetFeatureInfo流程
Cesium JS 封装了多个影像地图服务调用,其中包括了对WMS地图服务的支持。
WMS相关的类包括ImageryLayerCollection、WebMapServiceImageryProvider、UrlTemplateImageryProvider、GeographicTilingScheme、GeographicProjection、Resource等。
Cesium通过四叉树方式对全球地形数据进行网格化剖分,然后再根据每一个地形瓦片网格请求加载影像瓦片数据。
总体流程是:
1)根据当前查询位置得到所在的影像瓦片行列号X,Y和层级Level,
2)然后计算出瓦片对应的四至范围Rectangle,
3)然后再根据请求的位置在Rectangle的相对位置和瓦片像素大小width和height计算出I和J,即请求的空间位置在瓦片内的水平和垂直方向上的偏移像素,
4)最后,所有查询参数齐备后向服务端发起请求获取要素值。
具体流程是:
1)在查询给定空间位置P时候,调用ImageryLayerCollection. pickImageryLayerFeatures方法,获取当前屏幕范围内三维球的所有地形瓦片,
然后判断P在哪个瓦片内,再获取该瓦片内的所有影像瓦片数据,然后再判断P所在的影像瓦片,并获取瓦片对应的影像图层,
因此得到了查询位置P所在的影像瓦片的行列号X,Y和层级Level,
2)然后调用WebMapServiceImageryProvider. pickFeatures方法,由于WebMapServiceImageryProvider内部实际也是包装的UrlTemplateImageryProvider,
因此会继续调用UrlTemplateImageryProvider. pickFeatures,
3)然后在该函数内部调用buildPickFeaturesResource计算GetFeatureInfo的所有查询参数,
4)最后调用Resource.ResourcefetchJson()完成GetFeatureInfo服务请求(返回json的情况,也可xml的等)。
六、相关Cesium源码
七、测试代码
var viewer = init3D("cesiumContainer"); var scene = viewer.scene; var tileCorr = new Cesium.TileCoordinatesImageryProvider(); viewer.imageryLayers.addImageryProvider(tileCorr); function addLayer() { let baseUrl = 'http://localhost:9001/geoserver/hnny/wms'; var provider = new Cesium.WebMapServiceImageryProvider({ url: baseUrl, enablePickFeatures:true, rectangle: Cesium.Rectangle.fromDegrees(115.9595781, 33.70809, 116.648063, 34.298223), layers: 'hnny:Growth_2019', parameters: { TRANSPARENT: true, format: 'image/png', } }); var layer = viewer.imageryLayers.addImageryProvider(provider); viewer.flyTo(layer, { duration: 2 }); } var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas); handler.setInputAction(function(event) { viewer.selectedEntity=undefined; var pickRay = viewer.camera.getPickRay(event.position); var featuresPromise = viewer.imageryLayers.pickImageryLayerFeatures(pickRay, viewer.scene); if (!Cesium.defined(featuresPromise)) { console.log('No features picked.'); } else { Cesium.when(featuresPromise, function(features) { // This function is called asynchronously when the list if picked features is available. console.log('Number of features: ' + features.length); alert('Number of features: ' + features.length); if (features.length > 0) { console.log('First feature name: ' + features[0].name); alert('First feature name: ' + features[0].name); } }); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK);