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

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

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

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

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

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

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

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

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

0 110 220 110
900 240 250 160
1300 230 220 170
1900 220 220 220
2500 250 250 250
nv 	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文件长这样:

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

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

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

0 255 255 255
90 0 0 0

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

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

gdaldem slope dem.tif slope.tif
gdaldem 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);
        });
    });
});

最终的结果是这样的:

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

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

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

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

上一篇:不用插件,如何将tif格式的影像精准导入到CAD中?


下一篇:python glob.glob()