使用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 國際許可協議進行許可。