MS RFC 85: Vector Contour Rendering (CONNECTIONTYPE CONTOUR)¶
aboudreault at mapgears.com
This is a proposal to add the ability to compute and render contour layers on the fly in MapServer from a raster source. The source is one band of raster data, which represents a digital elevation model (DEM). More info about DEMs at: http://en.wikipedia.org/wiki/Digital_elevation_model
Contours can already be rendered today using a standard vector layer but this requires an extra processing step with gdal_contour to pre-generate the contours from the raster source. Plus this also implies some overhead for the gdal_contour files management, etc.
2. The proposed solution¶
This RFC proposes the addition of a new type of layer in MapServer: CONNECTIONTYPE CONTOUR. The new type is a hybrid layer, which has a raster data source as input and vector features as output. Initially, only the line representation of those vector features will be supported.
Since the internal layer is of type vector, queries will be supported and operate on the vectors (not on the raw raster source). In the future we might see a need to add a query mode that queries the raster source, but this is not included in this phase of work.
To render a contour layer, we need to define a layer in the mapfile with the following options:
Set the layer TYPE to LINE.
Set CONNECTIONTYPE to CONTOUR.
Set the DATA to the raster file that contains the elevation band.
Specify the band to use as elevation using PROCESSING "BANDS", same as regular raster.
Specify one or more classes and styles to render the line features.
These options should be specified at layer level:
CONTOUR_INTERVAL: elevation interval between contours
CONTOUR_LEVELS: comma-separated list of one or more 'fixed levels' to extract
CONTOUR_ITEM: provides a name for the item (attribute) in which to put the elevation. (optional)
You can also provide explicit min/max scaledenom in the CONTOUR_iNTERVAL or CONTOUR_LEVELS values if you wish to use scale-dependent contour spacing. This is done by adding an optional "miscaledenom,maxscaledenom:" prefix to the value or list of values. See the example below.
Example of a simple layer definition:
LAYER NAME "my_contour_layer" TYPE LINE STATUS DEFAULT CONNECTIONTYPE CONTOUR DATA /mnt/data/raster/grib/dem.grib PROCESSING "BANDS=1" PROCESSING "CONTOUR_ITEM=elevation" PROCESSING "CONTOUR_INTERVAL=10" CLASS STYLE WIDTH 2 COLOR 255 0 0 END END END #layer
Example of a layer definition with scale-dependent contour ranges:
LAYER NAME "my_contour_layer" TYPE LINE STATUS DEFAULT CONNECTIONTYPE CONTOUR DATA /mnt/data/raster/grib/dem.grib PROCESSING "BANDS=1" PROCESSING "CONTOUR_ITEM=elevation" PROCESSING "CONTOUR_INTERVAL=0,25000:5" # interval of 5 for scales of 25000 or less PROCESSING "CONTOUR_INTERVAL=25000,500000:10" # interval of 10 for scales in the 25000 to 500000 range PROCESSING "CONTOUR_LEVELS=500000,0:10,25,50,100" # explicit list of levels for scales of 500000 and up LABELITEM "elevation" CLASS STYLE WIDTH 2 COLOR 255 0 0 END LABEL ... END END END #layer
3. Implementation Details¶
Internally, a CONTOUR layer will have its own renderer/driver code. It's an hybrid layer because it reads the raster source and creates a vector dataset from it. It uses the internal GDAL function GDALContourGenerate(). All other functions behave like a vector layer. The layer can be drawn as a normal line layer using whichShape, GetShape etc.
Basic internal draw process of a CONTOUR layer:
whichShape() is called: the raster data source is read using the internal GDAL functions, an OGR dataset is stored in the internal layer structure.
getShape() is called: loop through the OGR dataset and return the shapeObj (Line).
MapServer draws its line feature as any other vector layer.
More info about GDAlContourGenerate algorithm at: https://gdal.org/api/gdal_alg.html#_CPPv419GDALContourGenerate15GDALRasterBandHddiPdidPvii16GDALProgressFuncPv
3.1 OGR Input driver¶
Once the raster source will be processed with gdal raster/contour functions, a OGR DataSource will be stored internally using the "Memory" driver. Since mapserver has already an OGR input-driver, it will be used to avoid unnecessary code duplication and maintenance. A layerObj with connectiontype=MS_OGR will be used internally to render/query the vector features.
A OGR Datasource using the "Memory" driver cannot be reopened and can only be created. The msOGRLayerOpen() function will try to open the dataset. In this case, our datasource is already opened. To solve this minor issue, the connection pooling API will be used.
3.2 Resample and Reprojection¶
The raster resample and layer reprojection will be supported. It will be done in one of the two ways:
In GDAL functions during the raster processing. (resample + reprojection)
In MapServer, like any other vector layer. (reprojection)
Since the layer is a line vector layer internally, the labeling is not affected and will be rendered as normal.
3.4 Tile boundaries¶
After some review of the GDALContourGenerate algorithm, it has been determined that the tile boundaries of the line should match properly. So this shouldn't be an issue but will have to be tested.
3.5 Files affected¶
The following files will be modified/created by this RFC:
mapserver.h/mapfile.c (Connection type CONTOUR support in the mapfile) mapcontour.c (new file for the CONTOUR renderer) maplayer.c (new layer type handling, virtual tables init etc.) maplexer.l (add additional CONTOUR keyword)
No issue for any MapScript bindings. The CONTOUR layer is handled/rendered internally as any other layer.
3.7 Backwards Compatibility Issues¶
This change provides a new functionality with no backwards compatibility issues being considered.
msautotest will be modified to add some tests related to that new layer type rendering and queries.
5. Bug ID¶
6. Voting history¶
+1 from Perry, Tamas, Daniel, Steve, Thomas, Jeff, Tom, Michael and Stephen