1. 程式人生 > 其它 >使用DEM和向量資料繪製地圖

使用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檔案長這樣:

能看出來哪裡高哪裡低了,但是它看起來很平對吧。所以還需要多種資料疊加

建立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);
        });
    });
});

最終的結果是這樣的:

最近我負責的專案中有很多地圖需要渲染,使用了Mapnik進行批量處理,效果非常理想,而且Nodejs呼叫可以實現非同步,效率也很高,圓滿的完成了客戶的需求。

Mapbox公司的開源專案中還有基於mapnik的瓦片服務,功能也很強大,如果使用程式設計手段生成地圖的話,我認為Mapnik是比較理想的選擇。(https://gisbook.cn/data/china-dem

本作品採用知識共享署名-相同方式共享 4.0 國際許可協議進行許可。