写点什么

使用 DEM 和矢量数据绘制地图

用户头像
gisbook
关注
发布于: 2 小时前

要生成一副图片地图,可以使用 ArcGIS、QGIS 等工具,也可以使用代码实现。我这里介绍的当然是用代码实现,而且是利用开源软件。毕竟桌面版 GIS 工具的介绍太多了,大家的地图都做的很漂亮。


用代码渲染地图就不得不提到 GDAL 和 Mapnik。GDAL 是处理 GIS 数据最常用的库,这里我们就要用到 gdaldem 处理 DEM 数据。Mapnik 是渲染地图的最基本工具,我们要使用它来生成地图。


要绘制一个地图首先需要定义清楚绘制什么样的地图,是地形图还是街道图还是卫星影像图,然后根据地图内容的需求将需要的各种类型空间数据准备好,有了这些数据才能绘制出地图。


在这里我介绍的是如何绘制一个地形图,需要使用到的是 DEM(数字高程模型)数据,和矢量数据。DEM 数据是用来表示地形的高低起伏,一般来说 DEM 数据是存储为 GeoTiff 格式的。矢量数据我在这里主要是绘制水系,格式是 Shape file。这次的重点是如何绘制地图,因此有关数据就不多做解释了,如果对这两种数据不了解可以自行查询一下。


接下来就是具体的过程介绍了。


第一步,我们需要对 DEM 数据进行简单的处理。主要目的是为了得到三种数据,第一种是色彩,主要是表现地形的高低,不同的颜色代表不同的海拔高度,可以直观的看出高度情况。第二种是山影,主要是为了让渲染出来的地图更具有立体性。第三种是坡度,不同的颜色可以代表地形的陡峭程度,当然还可以叠加上坡向的表示。


渲染色彩图首先需要创建一个配置文件,在使用 gdaldem 命令生成色彩数据的时候需要用到它。


比如创建一个空的配置文件叫做: color-relief.cfg,内容如下:


0 110 220 110900 240 250 1601300 230 220 1701900 220 220 2202500 250 250 250nv   255  255   255   0
复制代码


其中每一行代表了一个海拔高度值对应的颜色是什么,第一列的数字是海拔高度值,后面 3 列是 RGB 颜色色值。这里需要注意的是最后的 nv 代表 nodata-value,如果不配置这一项的话,没有数据的部分就会被渲染成黑色,这一行最后一列多了一个 0,是它的透明度值,0 代表完全透明,100 代表完全不透明。


然后使用 gdaldem 创建色彩数据


gdaldem color-relief dem.tif color_relief.cfg color_relief.tif  -alpha
复制代码


color_relief.tif文件长这样:



能看出来哪里高哪里低了,但是它看起来很平对吧。所以还需要多种数据叠加


创建color_slope.cfg,用于产生坡度数据


0 255 255 25590 0 0 0
复制代码


这个文件中每一行代表一个坡度对应什么颜色,第一列是坡度,后面 3 列是 RGB 色值。在这个例子中,产生的坡度数据会自动从 0-90 度填充从白色到黑色的渐变色。


产生坡度数据同样使用 gdaldem 命令


gdaldem slope dem.tif slope.tifgdaldem color-relief slope.tif color_slope.txt slopeshade.tif  -alpha
复制代码


现在只缺少山影数据了


gdaldem hillshade dem.tif hillshade.tif
复制代码


我还准备了一个矢量数据,其中包含了河流和水库等水域信息,这个数据不需要单独处理,在Mapnik的地图样式配置文件中,可以同时使用多种不同的数据格式配图。


数据准备工作都已经完成,接下来就需要创建Mapnik渲染地图所需的地图样式配置文件了,我的配置文件terrain_lake.xml是这样的:


<Map srs="+proj=longlat +datum=WGS84 +no_defs" background-color="transparent">  <Style name="color relief style">    <Rule>      <RasterSymbolizer mode="normal" />    </Rule>  </Style>  <Style name="slopeshade style">    <Rule>      <RasterSymbolizer opacity="0.1" mode="multiply" scaling="bilinear" />    </Rule>  </Style>  <Style name="hillshade style">    <Rule>      <RasterSymbolizer opacity="0.3" mode="multiply" scaling="bilinear" />    </Rule>  </Style>  <Style name="lake style">    <Rule>      <PolygonSymbolizer fill="rgb(180,210,230)" />      <Filter>[type] = 'Waters'</Filter>    </Rule>  </Style>
<Layer name="color relief"> <StyleName>color relief style</StyleName> <Datasource> <Parameter name="type">gdal</Parameter> <Parameter name="file">color_relief.tif</Parameter> </Datasource> </Layer> <Layer name="slopeshade"> <StyleName>hillshade style</StyleName> <Datasource> <Parameter name="type">gdal</Parameter> <Parameter name="file">slopeshade.tif</Parameter> </Datasource> </Layer> <Layer name="hillshade"> <StyleName>hillshade style</StyleName> <Datasource> <Parameter name="type">gdal</Parameter> <Parameter name="file">hillshade.tif</Parameter> </Datasource> </Layer> <Layer name="lake" status="on" srs="+proj=longlat +datum=WGS84 +no_defs"> <StyleName>lake style</StyleName> <Datasource> <Parameter name="type">shape</Parameter> <Parameter name="file">land_use_utf8.shp</Parameter> </Datasource> </Layer>
</Map>
复制代码


在这个配置文件中,可以针对不同数据定义多种样式和多个图层,每个图层可以指定不同的样式,非常方便使用。准备好配置文件后,我这里使用的是 nodejs 版本的 binding 调用 mapnik 渲染,代码如下:


var mapnik = require("mapnik");var fs = require("fs");mapnik.register_default_fonts();mapnik.register_default_input_plugins();var map = new mapnik.Map(300, 300);map.load("./terrain_lake.xml", function(err, map) {    map.zoomAll();    var im = new mapnik.Image(300, 300);    map.render(im, function(err, im) {        im.encode("png", function(err, buffer) {            fs.writeFile("map.png", buffer);        });    });});
复制代码


最终的结果是这样的:


最近我负责的项目中有很多地图需要渲染,使用了 Mapnik 进行批量处理,效果非常理想,而且 Nodejs 调用可以实现异步,效率也很高,圆满的完成了客户的需求。


Mapbox 公司的开源项目中还有基于 mapnik 的瓦片服务,功能也很强大,如果使用编程手段生成地图的话,我认为 Mapnik 是比较理想的选择。(https://gisbook.cn/data/china-dem


本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。



用户头像

gisbook

关注

通过分享,让技术和数据发挥出更大价值。 2021.09.01 加入

gisbook是一个专业的GIS开发团队,多年来积攒了很多GIS相关技术和数据知识,我们想通过分享让技术和数据发挥出更大的价值。

评论

发布
暂无评论
使用DEM和矢量数据绘制地图