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: