qgis / QGIS-Enhancement-Proposals

QEP's (QGIS Enhancement Proposals) are used in the process of creating and discussing new enhancements for QGIS
118 stars 37 forks source link

Support of 3D layered meshes #158

Closed PeterPetrik closed 4 years ago

PeterPetrik commented 5 years ago

QGIS Enhancement: Support of 3D layered meshes

Date 2019/10/16

Author Peter Petrik (@PeterPetrik)

Contact peter.petrik@lutraconsulting.co.uk

maintainer @PeterPetrik

Version QGIS 3.12

Summary

The initial implementation of mesh layer in QGIS supports only basic type of 2D irregular meshes with data defined on faces and vertices. The standard for mesh layers UGRID contains other mesh types that are not yet supported. This proposal describes the required steps to allow usage of 3D Layered Meshes for QGIS users.

Description

3D Layered Mesh consists of multiple stacked 2D unstructured meshes each extruded in the vertical direction (levels) by means of a vertical coordinate. The vertices and faces have the same topology in each vertical level. The mesh definition (vertical level extrusion) could in general change in time. The data is usually defined in volume centres or by some parametric function. Here is an example of regular mesh with 4 levels spaced by 1 meter.

Screenshot_2019-10-14_at_15 26 46

Here is an another example from TUFLOW FV that demonstrates one possible type of vertical layering. When water level increases or decreases the layering stretches or compresses, modifying the absolute elevation in time

tuflow fv hybrid z-sigma profile

The number of vertical levels can't change in time, but it can vary in spatial dimension

tuflow fv z profile

Commonly in meteorological/hydrology/geology numerical results, you may get tens of vertical levels and to be able to visualise in on 2D canvas, various averaging methods are used to derive 2D datasets. Also there should be possibility to display just one particular vertical level (see the green quantity on following figure (© Met.3D contributors 2017. CC Attribution 4.0 International License. met3d.wavestoweather.de))

3D mesh with variable vertical quantity - at different vertical levels

Example Data

There are data defined for each time, vertical level and volume. Volumes are contructed from base 2D mesh and vertical levels.

For example lets have simple 2D mesh with 2 quad elements F1 and F2 and 8 vertices V1 - V8.

mesh faces 2d

Imagine we measure air temperature above the ground. We define 3 levels in height 2500m, 1500m and 0m. Levels are stacked for each mesh element from from top to bottom. The height is absolute to datum.

LEVELS = [2500m, 1500m, 0m]

With 3 levels, we have 4 volumes, 2 volumes C1 and C2 above face F1 and two C3 and C4 above face F2

mesh volumes 3D

For each volume we measure air temperature in the volume's center during day (12:00) and night (24:00).

So we have in total (size(LEVELS)-1) * size(FACES) * size(TIMES) = (3-1) * 2 * 2 = 8 measured temperatures

Volume # Time 12:00
C1 (2000m) -2°C
C2 (750m) 10°C
C3 (2000m) 0°C
C4 (750m) 12°C
Volume # Time 24:00
C1 (2000m) -2°C
C2 (750m) 8 °C
C3 (2000m) 0°C
C4 (750m) 6°C

Changes in MDAL

We implement support for 3D Layered Meshes in MDAL. For formats that do not support meshes with vertical dimension, the API will be backward compatible. There will be new API on datasets to determine number of vertical levels for a given face on 2D base mesh frame. Also one would frequently need to determine first index of 3D volume from 2D face from base mesh frame (e.g. for identify tool to list vertical levels)

MDAL_EXPORT int MDAL_D_volumesCount( DatasetH dataset );

Also there will be 5 new enum options for retrieving data from MDAL_D_data

Data for volumes will be ordered from bottom to top in resulting array.

//! Populates buffer with values from the dataset
//! for nodata, returned is numeric_limits<double>::quiet_NaN
//!
//! \param dataset handle to dataset
//! \param indexStart index of face/vertex to start reading of values to the buffer
//! \param count number of values to be written to the buffer
//! \param dataType type of values to be written to the buffer
//! \returns number of values written to buffer. If return value != count requested, see MDAL_LastStatus() for error type
MDAL_EXPORT int MDAL_D_data( DatasetH dataset, int indexStart, int count, MDAL_DataType dataType, void *buffer );

To return to our example data from previous section the returns will be (note that dataset already defines which time you selected):

MDAL_M_volumesCount(ds) == 4
MDAL_D_data(ds, 0, 2, VERTICAL_LEVEL_COUNT_INTEGER, ...) == [3, 3]
MDAL_D_data(ds, 0, 6, VERTICAL_LEVEL_DOUBLE, ...) == [2500, 1500.0, 0.0, 2500, 1500.0, 0.0]
MDAL_D_data(ds, 0, 2, FACE_INDEX_TO_VOLUME_INDEX_INTEGER, ...) == [0, 2]
MDAL_D_data(ds, 0, 4, SCALAR_VOLUMES_DOUBLE, ...) == [-2.0, 10.0, 0.0, 12.0]

Also we will introduce new option so data can be defined on vertices, faces and volumes.

Changes in QGIS

On QGIS side, the QgsMeshLayer dataset's group tree will recognise that the dataset group consists of various vertical levels and group the stacked levels in subgroup. The root of the subgroup can be selected as an active contour/vector group. User can also select one particular level in subgroup and in that case the rendering is done same way as for other datasets

mesh group panel

To be able to visualise the subgroup with with various levels, we need to do averaging of the values in the levels to one single value to be displayed. We will use common methods described in this link. For example sigma method where you can calculate average with some levels excluded

sigma profile (TUFLOW)

and this would be corresponding QGIS widget

averaging qgis widget

Affected Files

most of the mesh related files and MDAL library

Performance Implications

None

Further Considerations/Improvements

Backwards Compatibility

For all formats that do not support layered mesh, the API will be backward compatible.

Issue Tracking ID(s)

nyalldawson commented 5 years ago

Sounds great to me!

pcav commented 5 years ago

Same here, cool stuff.

DelazJ commented 5 years ago

I don't fully understand what it's about but wanted to say it's great/pleasant to have handwritten items in the description

timlinux commented 5 years ago

Great stuff! Does the averaging take into account only the checked / enabled levels?

PeterPetrik commented 5 years ago

@timlinux there are multiple different averaging methods and we can add more on demand. I think basic methods just take average or you can exclude edge levels or so...

wonder-sk commented 5 years ago

@DelazJ hmm if you have problems understanding the QEP, then probably other people will have troubles as well. Anything we can improve in to proposal to make it easier to understand? Maybe expand the intro?

As a TL;DR summary, if you are familiar with 3D rasters, this QEP is about adding support for a similar thing for meshes, just more generic (extras: 1. data can change over time. 2. elevations can change over time).

NathanW2 commented 5 years ago

This sounds pretty bloody great.

saberraz commented 5 years ago

For those interested in 3D raster, how GRASS GIS supports it: https://grass.osgeo.org/grass76/manuals/raster3dintro.html

It would be good also to support 3D rasters (if it is supported by GDAL) in addition to the MDAL unstructured mesh formats.

andreasneumann commented 5 years ago

This sounds pretty bloody great.

agreed - looking forward to it!

PeterPetrik commented 5 years ago

** update 22nd October 2019: Generalize the QEP to allow "The number of vertical levels can't change in time, but it can vary in spatial dimension"