Map using DEM and vector data

To generate a picture map, you can use ArcGIS, QGIS and other tools, or code. What I introduce here is, of course, implemented in code and using open source software. After all, there are too many introductions of desktop GIS tools, and everyone's maps are very beautiful.

If you render a map in code, you have to mention GDAL and mapnik. GDAL is the most commonly used library for processing GIS data. Here we will use gdaldem to process DEM data. Mapnik is the most basic tool for rendering maps. We want to use it to generate maps.

To draw a map, you first need to define what kind of map to draw, whether it is a topographic map, a street map or a satellite image map, and then prepare various types of spatial data according to the needs of map content. With these data, you can draw a map.

Here I introduce how to draw a topographic map, which needs DEM (digital elevation model) data and vector data. DEM data is used to represent the ups and downs of terrain. Generally speaking, DEM data is stored in GeoTiff format. Vector data here is mainly used to draw water system in Shape file format. The focus of this time is how to draw the map, so there is no more explanation for the relevant data. If you don't understand these two kinds of data, you can query them yourself.

The next step is to introduce the specific process.

In the first step, we need to simply process DEM data. The main purpose is to obtain three kinds of data. The first is color, which mainly shows the height of terrain. Different colors represent different altitudes, which can intuitively see the height. The second is mountain shadow, which is mainly to make the rendered map more three-dimensional. The third is the slope. Different colors can represent the steepness of the terrain. Of course, they can also be superimposed with the upward slope direction.

To render a color map, you first need to create a configuration file, which is needed when using the gdaldem command to generate color data.

For example, create an empty configuration file called color-relief.cfg, which is as follows:

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

Each row represents the color corresponding to an altitude value. The number in the first column is the altitude value, and the following three columns are RGB color values. It should be noted here that the last nv represents NoData value. If this item is not configured, the part without data will be rendered black. The last column of this row has an additional 0, which is its transparency value. 0 represents complete transparency and 100 represents complete opacity.

Then use gdaldem to create color data

gdaldem color-relief dem.tif color_relief.cfg color_relief.tif  -alpha

color_ The relief.tif file is as follows:

You can see where it's high and where it's low, but it looks flat, right. Therefore, a variety of data superposition is required

Create color_slope.cfg, used to generate slope data

0 255 255 255
90 0 0 0

Each line in this file represents the corresponding color of a slope. The first column is the slope, and the last three columns are RGB color values. In this example, the resulting slope data is automatically filled with a gradient from white to black from 0-90 degrees.

The gdaldem command is also used to generate slope data

gdaldem slope dem.tif slope.tif
gdaldem color-relief slope.tif color_slope.txt slopeshade.tif  -alpha

Now only Shanying data is missing

gdaldem hillshade dem.tif hillshade.tif

I also prepared a vector data, which contains water area information such as rivers and reservoirs. This data does not need to be processed separately. In Mapnik's map style configuration file, a variety of different data formats can be used for map matching at the same time.

The data preparation has been completed. Next, you need to create the map style configuration file required by Mapnik to render the map, my configuration file terrain_lake.xml is like this:

<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>

In this configuration file, you can define multiple styles and layers for different data. Each layer can specify different styles, which is very convenient to use. After the configuration file is ready, I use nodejs binding to call mapnik rendering. The code is as follows:

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

The final result is as follows:

Recently, many maps in my project need to be rendered. Mapnik is used for batch processing, and the effect is very ideal. Moreover, Nodejs calls can be asynchronous and efficient, which successfully meets the needs of customers.

Mapbox's open source project also has a tile service based on mapnik, which is also very powerful. If you use programming to generate maps, I think mapnik is an ideal choice. ( https://gisbook.cn/data/china-dem)

This work adopts Knowledge sharing Attribution - sharing 4.0 international license agreement in the same way License.

Tags: gis map

Posted on Sat, 18 Sep 2021 21:35:28 -0400 by smashita