Qt Quick 2 Surface Multiseries Example

Using multiple series with Surface3D in a QML application.

The Qt Quick 2 surface example shows how to make a 3D surface plot displaying 3 layers using Surface3D with Qt Quick 2.

../_images/qmlsurfacelayers-example.png

The focus in this example is on generating a multiseries surface plot from 3 different height map images, so in this section we skip explaining the application creation. For a more detailed QML example documentation, see Qt Quick 2 Scatter Example .

Running the Example

To run the example from Qt Creator , open the Welcome mode and select the example from Examples . For more information, visit Building and Running an Example.

Adding Data to the Graph

This example shows how to add several surface series to one graph using using HeightMapSurfaceDataProxies and how to control their visibilities individually.

Let’s start by creating a specific gradient for each layer:

ColorGradient {
    id: layerOneGradient
    ColorGradientStop { position: 0.0; color: "black" }
    ColorGradientStop { position: 0.31; color: "tan" }
    ColorGradientStop { position: 0.32; color: "green" }
    ColorGradientStop { position: 0.40; color: "darkslategray" }
    ColorGradientStop { position: 1.0; color: "white" }
}

ColorGradient {
    id: layerTwoGradient
    ColorGradientStop { position: 0.315; color: "blue" }
    ColorGradientStop { position: 0.33; color: "white" }
}

ColorGradient {
    id: layerThreeGradient
    ColorGradientStop { position: 0.0; color: "red" }
    ColorGradientStop { position: 0.15; color: "black" }
}

Then we’ll create the series themselves. It happens simply by adding 3 separate Surface3DSeries to the Surface3D graph as children:

...

            Surface3DSeries {
                id: layerOneSeries
                baseGradient: layerOneGradient

                HeightMapSurfaceDataProxy {
                    heightMapFile: ":/heightmaps/layer_1.png"
                }
                flatShadingEnabled: false
                drawMode: Surface3DSeries.DrawSurface

                visible: layerOneToggle.checked // bind to checkbox state

            }

            Surface3DSeries {
                id: layerTwoSeries
                baseGradient: layerTwoGradient
                HeightMapSurfaceDataProxy {
                    heightMapFile: ":/heightmaps/layer_2.png"
                }
                flatShadingEnabled: false
                drawMode: Surface3DSeries.DrawSurface
                visible: layerTwoToggle.checked // bind to checkbox state
            }

            Surface3DSeries {
                id: layerThreeSeries
                baseGradient: layerThreeGradient
                HeightMapSurfaceDataProxy {
                    heightMapFile: ":/heightmaps/layer_3.png"
                }
                flatShadingEnabled: false
                drawMode: Surface3DSeries.DrawSurface
                visible: layerThreeToggle.checked // bind to checkbox state
            }
...

You’ll notice we added the created gradients to the baseGradient properties of the series. We could have added them to the baseGradients property of the Theme3D in Surface3D instead, but doing it this way ensures each gradient is applied to a correct series:

        Surface3DSeries {
            id: layerOneSeries
            baseGradient: layerOneGradient
...

Controlling the Graph

Let’s add some checkboxes to control the visibility of layers:

GroupBox {
    flat: true
    Layout.fillWidth: true
    Column {
        spacing: 10

        Label {
            font.pointSize: fontSize
            font.bold: true
            text: "Layer Selection"
        }

        CheckBox {
            id: layerOneToggle
            checked: true
            style: CheckBoxStyle {
                label: Label {
                    font.pointSize: fontSize
                    text: "Show Ground Layer"
                }
            }
        }

        CheckBox {
            id: layerTwoToggle
            checked: true
            style: CheckBoxStyle {
                label: Label {
                    font.pointSize: fontSize
                    text: "Show Sea Layer"
                }
            }
        }

        CheckBox {
            id: layerThreeToggle
            checked: true
            style: CheckBoxStyle {
                label: Label {
                    font.pointSize: fontSize
                    text: "Show Tectonic Layer"
                }
            }
        }
    }
}

We don’t need to do anything on the onCheckedChanged as we bound the checked state to the visible property of the series directly:

...
                visible: layerOneToggle.checked // bind to checkbox state
...

Let’s add some more checkboxes to control how the layers are displayed, when visible:

GroupBox {
    flat: true
    Layout.fillWidth: true
    Column {
        spacing: 10

        Label {
            font.pointSize: fontSize
            font.bold: true
            text: "Layer Style"
        }

        CheckBox {
            id: layerOneGrid
            style: CheckBoxStyle {
                label: Label {
                    font.pointSize: fontSize
                    text: "Show Ground as Grid"
                }
            }
            onCheckedChanged: {
                if (checked)
                    layerOneSeries.drawMode = Surface3DSeries.DrawWireframe
                else
                    layerOneSeries.drawMode = Surface3DSeries.DrawSurface
            }
        }

        CheckBox {
            id: layerTwoGrid
            style: CheckBoxStyle {
                label: Label {
                    font.pointSize: fontSize
                    text: "Show Sea as Grid"
                }
            }
            onCheckedChanged: {
                if (checked)
                    layerTwoSeries.drawMode = Surface3DSeries.DrawWireframe
                else
                    layerTwoSeries.drawMode = Surface3DSeries.DrawSurface
            }
        }

        CheckBox {
            id: layerThreeGrid
            style: CheckBoxStyle {
                label: Label {
                    font.pointSize: fontSize
                    text: "Show Tectonic as Grid"
                }
            }
            onCheckedChanged: {
                if (checked)
                    layerThreeSeries.drawMode = Surface3DSeries.DrawWireframe
                else
                    layerThreeSeries.drawMode = Surface3DSeries.DrawSurface
            }
        }
    }
}

In addition to these we have three buttons, one of which is of special interest to us. It is used to control whether we want to slice into only one layer, or all of them:

NewButton {
    id: sliceButton
    text: "Slice All Layers"
    fontSize: fontSize
    Layout.fillWidth: true
    Layout.minimumHeight: 40
    onClicked: {
        if (surfaceLayers.selectionMode & AbstractGraph3D.SelectionMultiSeries) {
            surfaceLayers.selectionMode = AbstractGraph3D.SelectionRow
                    | AbstractGraph3D.SelectionSlice
            text = "Slice All Layers"
        } else {
            surfaceLayers.selectionMode = AbstractGraph3D.SelectionRow
                    | AbstractGraph3D.SelectionSlice
                    | AbstractGraph3D.SelectionMultiSeries
            text = "Slice One Layer"
        }
    }
}

Example Contents