前言
在上一篇文章中我讲了如何直接将Geotiff文件发布为TMS服务,在其中只讲了单幅Geotiff的操作,其实单幅这种量级的数据对Geotrellis来说就是杀鸡焉用牛刀,Geotrellis针对的是大数据量的操作。在进行完单幅Geotiff的操作后,就去出差了一周,这一周也没闲着,稍有空隙便在思索这个问题,并抽空写那么两行,回来一调试果然可以,于是就有了本文。下面我来介绍如何对大量Geotiff实时进行TMS服务化操作。
一、总体效果
上次使用的是北京首都国际机场影像数据,这次我又下载了部分北京市区影像数据,来看一下总体显示效果。
二、实现方案
总体思路如下:
- 判断当前请求瓦片的范围。
- 判断在此范围下有无Tiff文件。
- 若有则切割此Tiff文件并返回对应的瓦片。
2.1 判断当前请求瓦片范围
每次请求,前台会向后台发送一个需要的瓦片编号,包含zoom、x、y,根据这三个值以及当前地图的投影方式我们就能算出此瓦片的空间范围。代码如下:
val key = SpatialKey(x, y)val layoutScheme = ZoomedLayoutScheme(crs, tileSize = 256)val layout = layoutScheme.levelForZoom(zoom)val extent = MapKeyTransform(crs, LayoutLevel(zoom, layout.layout))(key)
其中crs表示地图投影,多为WebMercator,最终得到的extent即位该瓦片在此投影下的空间范围。
2.2 判断在此范围下有无Tiff文件
显而易见,如果此范围下有Tiff文件我们才需要进行切割,否则不进行操作,那么这里就牵涉三点:
- 获取所有需要切割的Tiff文件。
- 获取Tiff文件空间范围。
- 将上面得到的extent与每一幅tiff的范围进行相交判断,若有交集则切割此瓦片。
- 获取所有tiff文件。
文件存储在HDFS中,传入路径,获取其下所有文件即可。代码如下:
val hdfsPath = new org.apache.hadoop.fs.Path(path)val fs = FileSystem.get(new Configuration())val files = fs.listStatus(hdfsPath)
其中path为HDFS中的目录路径。这样就能得到该路径下所有文件。
- 获取Tiff文件空间范围。
每一个Tiff文件都有一个范围, 普通方式可以直接读取Tiff文件的角点坐标等信息,在此我使用Geotrellis的方式来读取。代码如下:
val rdd = HadoopGeoTiffRDD.spatialMultiband(path)val sm = rdd .map { case (key, grid) => val ProjectedExtent(extent, crs) = key.getComponent[ProjectedExtent] // Bounds are return to set the non-spatial dimensions of the KeyBounds; // the spatial KeyBounds are set outside this call. val boundsKey = key.translate(SpatialKey(0,0)) val cellSize = CellSize(extent, grid.cols, grid.rows) HashMap(crs -> RasterCollection(crs, grid.cellType, cellSize, extent, KeyBounds(boundsKey, boundsKey), 1)) } .reduce { (m1, m2) => m1.merged(m2){ case ((k,v1), (_,v2)) => (k,v1 combine v2) } } .values.toSeq.head