Get driving directions

This topic walks you through the development of an application using the ArcGIS Runtime SDK for Qt. The application provides users with the ability to specify a route start point and end point on a basemap and determine an optimal route between the selected points on any device to which the application is deployed.

Developing a Qt map application

Complete the following steps to create an ArcGIS Runtime SDK for Qt mapping application using an application template:

  1. In a location of your choice, create a folder named RoutingExercise.
  2. Start Qt Creator and create a new project using the ArcGIS Runtime Qt Quick application template.
  3. Specify the following project name to ensure consistency with relative paths in steps you will encounter later in this exercise: PointToPointRouting_Example.
  4. For the location, browse to the RoutingExercise folder you created earlier.
  5. Click Next and select your targeted platform(s) from the list of installed kits.
  6. Click Next again and set the Title and Description for your project. You do not need to supply a Client ID at this time. This is only required when Licencing your app.
  7. Click Finish to create the project.

Include a basemap as a local tiled layer

The template includes an online basemap. This needs to be replaced with a local tiled layer in order for the application to be used offline. Add the SanFrancisco.tpk to the map using the ArcGISLocalTiledLayer component. The map should now default to the extent of the local tiled layer.

Map {
        id: map
        anchors.fill: parent
        wrapAroundEnabled: true

        ArcGISLocalTiledLayer {
            path: ArcGISRuntime.installDirectory + "/sdk/samples/data/tpks/SanFrancisco.tpk"
        }
    }

Change the extent of the basemap

To make it easier for the user to select start and end points of their route, change the extent of the map to a smaller area of San Francisco using an Envelope component.

Map {
        id: map
        anchors.fill: parent
        wrapAroundEnabled: true
        extent: sanFrancisco

        ArcGISLocalTiledLayer {
            path: ArcGISRuntime.installDirectory + "/sdk/samples/data/tpks/SanFrancisco.tpk"
        }
    }

    Envelope {
        id: sanFrancisco
        xMin: -122.520
        yMin: 37.8365
        xMax: -122.3023
        yMax: 37.6985
        spatialReference: map.spatialReference
    }

Building the application's user interface

The user interface (UI) for your point-to-point routing application will have three buttons. One will allow the user to specify the route's starting point; the second will be used to establish the route's end point, and the third button will solve the problem and identify an optimal route between the designated points. Using an ExclusiveGroup ensures that only one button can be checked at a time.

When adding UI elements, QML code works from top to bottom, drawing the last items on the top. So the code that we provide must be placed below the map, otherwise the controls will not draw on top of the map.

Complete the following steps to define the UI for your application:

Rectangle {
        id: controlsBackground
        color: "black"
        radius: 5
        opacity: 0.75
        anchors {
        fill: controls
        margins: -10
        }
    }

    Column {
        id: controls
        spacing: 20
        anchors {
            top: parent.top
            left: parent.left
            margins: 20
        }

        Button {
            id: startPointButton
            text: "Start Point"
            checkable: true
            exclusiveGroup: routeButtons
        }

        Button {
            id: endPointButton
            text: "End Point"
            width: startPointButton.width
            checkable: true
            exclusiveGroup: routeButtons
        }

        Button {
            id: solveButton
            text: "Solve"
            width: startPointButton.width
        }

    }

    ExclusiveGroup {
        id: routeButtons
    }

Add the graphics for the start point, end point and route

A graphics layer provides your application's users with a set of simple vector graphics with which they can interact. The route start point, end point, and the route itself will all be rendered as simple vector graphics. Include a NAFeaturesAsFeatures to hold the features to be used for the routing task. Complete the following steps to modify your application's code within Qt Creator.

  1. Declare NAFeaturesAsFeatures and graphics layers, including renderers, in the map.
    NAFeaturesAsFeature {
                id: routePoints
            }
    
            GraphicsLayer {
                id: startGraphics
                renderer: SimpleRenderer {
                    SimpleMarkerSymbol {
                        style: Enums.SimpleMarkerSymbolStyleSquare
                        size: 10
                        color: "green"
                    }
                }
            }
    
            GraphicsLayer {
                id: endGraphics
                renderer: SimpleRenderer {
                    SimpleMarkerSymbol {
                        style: Enums.SimpleMarkerSymbolStyleSquare
                        size: 10
                        color: "red"
                    }
                }
            }
    
            GraphicsLayer {
                id: routeGraphics
                renderer: SimpleRenderer {
                    SimpleLineSymbol {
                        style: Enums.SimpleLineSymbolStyleSolid
                        width: 3
                        color: "turquoise"
                    }
                }
            }
  2. Add the logic to create graphics for each layer and add features to NAFeaturesAsFeatures using the map.onMouseClicked event. This code is a signal handler for the map's mouseClicked signal and therefore should be inside the map code. Setting conditions to only add points if the graphics layer has no graphics will restrict the input of each layer to a single feature.
    onMouseClicked: {
        var graphic = ArcGISRuntime.createObject("Graphic");
        graphic.geometry = mouse.mapPoint;
        
        if (startPointButton.checked) {
            if (startGraphics.numberOfGraphics === 0)
                startGraphics.addGraphic(graphic);
        }
        else if (endPointButton.checked) {
            if (endGraphics.numberOfGraphics === 0)
                endGraphics.addGraphic(graphic);
        }
        var routeGraphic = graphic.clone();
        routePoints.addFeature(routeGraphic);
    }

Add a Local Route Task

To create a route, the LocalRouteTask, which references the local database, needs to be passed LocalRouteTaskParameters, including the stops from NAFeaturesAsFeatures. Declare these components in the map, using property binding to link them to each other.

  1. Declare the components in the map.
    LocalRouteTask {
                id: localRouteTask
                network: "Streets_ND"
                database: ArcGISRuntime.installDirectory + "/sdk/samples/data/disconnected/route/SanFrancisco/RuntimeSanFrancisco.geodatabase"
            }
    
            LocalRouteTaskParameters {
                id: routeTaskParameters
                task: localRouteTask
                returnDirections: true
                outSpatialReference: map.spatialReference
            }
  2. Delcare the stops for the RouteTaskParameters and call the solve function for the LocalRouteTask using the onClicked event on the Solve button.
    Button {
                id: solveButton
                text: "Solve"
                width: startPointButton.width
    
                onClicked: {
                    routeTaskParameters.stops = routePoints;
                    localRouteTask.solve(routeTaskParameters);
                }
            }
  3. Create the route result and handle any errors using the onSolveStatusChanged signal on the LocalRouteTask. Add the result to the GraphicsLayer for the route.
    onSolveStatusChanged: {
        console.log("solving")
        if (solveStatus === Enums.SolveStatusCompleted){
            for (var index = 0; index < solveResult.routes.length; index++)
            {
                var route = solveResult.routes[index];
                var graphic = route.route;
                routeGraphics.addGraphic(graphic);
            }
        }
        else if (solveStatus === Enums.SolveStatusErrored){
            console.log(solveError.message);
        }
    }

Run your application

If you've completed each step in this exercise, you'll have a functional point-to-point application that can then be licensed and deployed to any device supporting applications developed for Qt.

  1. Run your application from within Qt Creator.
  2. Zoom to the center of San Francisco and click the Start Point button.
  3. Click a point on the map display to designate a route start point.
  4. Click the End Point button and select a route end point on the map.
  5. Click the Solve button and wait a few seconds for the task to complete.

The local route task executes and the resulting route is added to the map.