Qt 5.7 | Qt Data Visualization | Qt Quick 2 Surface Multiseries Example

Qt 5.7.1 Reference Documentation

# Qt Quick 2 Surface Multiseries Example

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

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.

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

Files:

- qmlsurfacelayers/qml/qmlsurfacelayers/NewButton.qml
- qmlsurfacelayers/qml/qmlsurfacelayers/main.qml
- qmlsurfacelayers/main.cpp
- qmlsurfacelayers/qmlsurfacelayers.pro
- qmlsurfacelayers/qmlsurfacelayers.qrc