Learn how to find a route and directions with the route service.
Routing is the process of finding the path from an origin to a destination in a street network. You can use the Routing service to find routes, get driving directions, calculate drive times, and solve complicated, multiple vehicle routing problems. To create a route, you typically define a set of stops (origin and one or more destinations) and use the service to find a route with directions. You can also use a number of additional parameters such as barriers and mode of travel to refine the results.
In this tutorial, you define an origin and destination by clicking on the map. These values are used to get a route and directions from the route service. The directions are also displayed on the map.
Prerequisites
Before starting this tutorial:
-
You need an ArcGIS Location Platform or ArcGIS Online account.
-
Your system meets the system requirements.
-
The ArcGIS Maps SDK for Qt, version 200.8.0 or later is installed.
-
The Qt 6.8.2 software development framework or later is installed.
Set up authentication
To access the secure ArcGIS location services used in this tutorial, you must implement API key authentication or user authentication using an ArcGIS Location Platform or an ArcGIS Online account.
You can implement API key authentication or user authentication in this tutorial. Compare the differences below:
API key authentication
- Users are not required to sign in.
- Requires creating an API key credential with the correct privileges.
- API keys are long-lived access tokens.
- Service usage is billed to the API key owner/developer.
- Simplest authentication method to implement.
- Recommended approach for new ArcGIS developers.
Learn more in API key authentication.
User authentication
- Users are required to sign in with an ArcGIS account.
- User accounts must have privilege to access the ArcGIS services used in application.
- Requires creating OAuth credentials.
- Application uses a redirect URL and client ID.
- Service usage is billed to the organization of the user signed into the application.
Learn more in User authentication.
To complete this tutorial, click on the tab in the switcher below for your authentication type of choice, either API key authentication or *User authentication.
Create a new API key access token with privileges to access the secure resources used in this tutorial.
-
Complete the Create an API key tutorial and create an API key with the following privilege(s):
- Privileges
- Location services > Basemaps
- Location services > Routing
- Privileges
-
Copy and paste the API key access token into a safe location. It will be used in a later step.
Develop or Download
You have two options for completing this tutorial:
Option 1: Develop the code
To start the tutorial, complete the Display a map tutorial. This creates a map to display the Santa Monica Mountains in California using the topographic basemap from the ArcGIS Basemap Styles service.
Open a Qt Creator project
- Open the project you created by completing the Display a map tutorial.
- Continue with the following instructions to find a route and directions with the ArcGIS Routing service.
Declare classes, functions, variables, enumerations and signals
-
In the Display_a_map project, double click on Headers > Display_a_map.h to open the file. Add the four class declarations shown.
Display_a_map.hUse dark colors for code blocks namespace Esri::ArcGISRuntime { class Map; class MapQuickView; class Graphic; class GraphicsOverlay; class PictureMarkerSymbol; class RouteTask; -
Continuing in the Display_a_map.h file, create an enum to monitor user route selections and maintain the route builder status. This will be initialized in Display_a_map.cpp in a later step.
Display_a_map.hUse dark colors for code blocks class Graphic; class GraphicsOverlay; class PictureMarkerSymbol; class RouteTask; } // namespace Esri::ArcGISRuntime enum RouteBuilderStatus { NotStarted, SelectedStart, SelectedStartAndEnd, }; -
Add an
#includestatement, class declaration, and a Meta Object Compiler (MOC) to add an include that exposes theQ.Abstract List Model Display_a_map.hUse dark colors for code blocks enum RouteBuilderStatus { NotStarted, SelectedStart, SelectedStartAndEnd, }; #include <QObject> #include "RouteParameters.h" class QAbstractListModel; Q_MOC_INCLUDE("QAbstractListModel") Q_MOC_INCLUDE("MapQuickView.h") -
Use
Qto create a member variable_PROPERTY m._directions Display_a_map.hUse dark colors for code blocks class Display_a_map : public QObject { Q_OBJECT Q_PROPERTY(Esri::ArcGISRuntime::MapQuickView* mapView READ mapView WRITE setMapView NOTIFY mapViewChanged) Q_PROPERTY(QAbstractListModel* directions MEMBER m_directions NOTIFY directionsChanged) -
Add the following signal declaration; this will be used to prompt updates to route directions.
Display_a_map.hUse dark colors for code blocks public: explicit Display_a_map(QObject* parent = nullptr); ~Display_a_map() override; signals: void mapViewChanged(); void directionsChanged(); -
Declare the following private methods.
Display_a_map.hUse dark colors for code blocks private: Esri::ArcGISRuntime::MapQuickView* mapView() const; void setMapView(Esri::ArcGISRuntime::MapQuickView* mapView); void setupViewpoint(); void setupRouteTask(); void findRoute(); void resetState(); -
Finally in the Display_a_map.h file, declare and initialize the following pointers, object, and enumeration. Then save the file.
Display_a_map.hUse dark colors for code blocks void setupRouteTask(); void findRoute(); void resetState(); Esri::ArcGISRuntime::Map* m_map = nullptr; Esri::ArcGISRuntime::MapQuickView* m_mapView = nullptr; Esri::ArcGISRuntime::GraphicsOverlay* m_graphicsOverlay = nullptr; Esri::ArcGISRuntime::RouteTask* m_routeTask = nullptr; Esri::ArcGISRuntime::Graphic* m_startGraphic = nullptr; Esri::ArcGISRuntime::Graphic* m_endGraphic = nullptr; Esri::ArcGISRuntime::Graphic* m_lineGraphic = nullptr; QAbstractListModel* m_directions = nullptr; Esri::ArcGISRuntime::RouteParameters m_routeParameters; RouteBuilderStatus m_currentState;
Include header files to access needed classes
-
In the Qt project, double click on Sources > Display_a_map.cpp to open the file. Add
#includestatements for the classes shown.Display_a_map.cppUse dark colors for code blocks #include "Display_a_map.h" #include "Map.h" #include "MapTypes.h" #include "MapQuickView.h" #include "Point.h" #include "Viewpoint.h" #include "SpatialReference.h" #include <QFuture> #include "DirectionManeuverListModel.h" #include "Graphic.h" #include "GraphicListModel.h" #include "GraphicsOverlay.h" #include "GraphicsOverlayListModel.h" #include "Polyline.h" #include "RouteTask.h" #include "RouteResult.h" #include "RouteParameters.h" #include "Route.h" #include "SimpleLineSymbol.h" #include "SimpleMarkerSymbol.h" #include "Stop.h" #include "Symbol.h" #include "SymbolTypes.h" #include <QGeoPositionInfoSource> #include <QList> #include <QUrl> #include <QUuid>
Update the constructor
-
Continuing to edit the Display_a_map.cpp file, update the constructor as shown. Set
BasemapStyletoArcGISand initialize theStreets Routeenumeration. Add an ending comma to the line for theBuilder Status mmember variable (yellow highlighted line) and add a new member variable for_map(new Map( Basemap Style ::ArcGIS Streets, this)) m(green highlighted line)._current State( Route Builder Status ::Not Started) Display_a_map.cppUse dark colors for code blocks Display_a_map::Display_a_map(QObject* parent /* = nullptr */): QObject(parent), m_map(new Map(BasemapStyle::ArcGISStreets, this)), m_currentState(RouteBuilderStatus::NotStarted) -
Call the
setupmethod within the constructor. This will be populated in a later step.Route Task() Display_a_map.cppUse dark colors for code blocks Display_a_map::Display_a_map(QObject* parent /* = nullptr */): QObject(parent), m_map(new Map(BasemapStyle::ArcGISStreets, this)), m_currentState(RouteBuilderStatus::NotStarted) { setupRouteTask();
Change the map's view point
-
Continuing to edit the Display_a_map.cpp file, in
setupmethod change the 2 lines for the map'sViewpoint() PointandViewpointto place the map over over downtown Los Angeles (highlighted in yellow).Display_a_map.cppUse dark colors for code blocks MapQuickView* Display_a_map::mapView() const { return m_mapView; } void Display_a_map::setupViewpoint() { const Point center(-118.24532, 34.05398, SpatialReference::wgs84()); const Viewpoint viewpoint(center, 144447.638572);
Change setupViewpoint() to respond to mouse clicks and find the route
-
Continuing to edit the Display_a_map.cpp file, add a
connectstatement tosetupto detect user mouse clicks, set and display point graphics, respond to the first and second click (using theViewpoint() switchstatement), and callfindon the second mouse click.Route Display_a_map.cppUse dark colors for code blocks void Display_a_map::setupViewpoint() { const Point center(-118.24532, 34.05398, SpatialReference::wgs84()); const Viewpoint viewpoint(center, 144447.638572); m_mapView->setViewpointAsync(viewpoint); connect(m_mapView, &MapQuickView::mouseClicked, this, [this](QMouseEvent& mouse) { const Point mapPoint = m_mapView->screenToLocation(mouse.position().x(), mouse.position().y()); switch (m_currentState) { case RouteBuilderStatus::NotStarted: resetState(); m_currentState = RouteBuilderStatus::SelectedStart; m_startGraphic->setGeometry(mapPoint); break; case RouteBuilderStatus::SelectedStart: m_currentState = RouteBuilderStatus::SelectedStartAndEnd; m_endGraphic->setGeometry(mapPoint); findRoute(); break; case RouteBuilderStatus::SelectedStartAndEnd: // Ignore touches while routing is in progress break; } });
Create route graphics
-
Continuing to edit the Display_a_map.cpp file, add code to
setupto create the route's starting pointViewpoint() Graphic, determined by the user's first mouse click. This consists of aSimpleLineSymbol, color blue, size 2, that outlines aSimpleMarkerSymbol, diamond shaped and orange in color. Create the route's ending pointGraphic, determined by the user's second mouse click. This consists of aSimpleLineSymbol, color red, size 2, that outlines aSimpleMarkerSymbol, square shaped and green in color. Create a lineGraphicconnecting the route's starting and ending points using aSimpleLineSymbol, color blue, size 4. Then append the starting point graphic, ending point graphic, and route line graphic to aGraphicsOverlay.Display_a_map.cppUse dark colors for code blocks case RouteBuilderStatus::SelectedStartAndEnd: // Ignore touches while routing is in progress break; } }); m_graphicsOverlay = new GraphicsOverlay(this); m_mapView->graphicsOverlays()->append(m_graphicsOverlay); SimpleLineSymbol* startOutlineSymbol = new SimpleLineSymbol(SimpleLineSymbolStyle::Solid, QColor("blue"), 2/*width*/, this); SimpleMarkerSymbol* startSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle::Diamond, QColor("orange"), 12/*width*/, this); startSymbol->setOutline(startOutlineSymbol); m_startGraphic = new Graphic(this); m_startGraphic->setSymbol(startSymbol); SimpleLineSymbol* endOutlineSymbol = new SimpleLineSymbol(SimpleLineSymbolStyle::Solid, QColor("red"), 2/*width*/, this); SimpleMarkerSymbol* endSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle::Square, QColor("green"), 12/*width*/, this); endSymbol->setOutline(endOutlineSymbol); m_endGraphic = new Graphic(this); m_endGraphic->setSymbol(endSymbol); SimpleLineSymbol* lineSymbol = new SimpleLineSymbol(SimpleLineSymbolStyle::Solid, QColor("blue"), 4/*width*/, this); m_lineGraphic = new Graphic(this); m_lineGraphic->setSymbol(lineSymbol); m_graphicsOverlay->graphics()->append(QList<Graphic*> {m_startGraphic, m_endGraphic, m_lineGraphic}); }
Create the setRouteTask() method
A task makes a request to a service and returns the results. Use the RouteTask class to access a routing service. Create a RouteTask with a string URL to reference the routing service.
-
Continuing to edit the Display_a_map.cpp file, implement the
setmethod. Point theRoute Task() RouteTaskto an online service. Call the create default parameters async method obtain the route parameters.Display_a_map.cppUse dark colors for code blocks void Display_a_map::setupRouteTask() { // create the route task pointing to an online service m_routeTask = new RouteTask(QUrl("https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World"), this); // Create the default parameters which will load the route task implicitly. m_routeTask->createDefaultParametersAsync().then(this,[this](const RouteParameters& routeParameters) { // Store the resulting route parameters. m_routeParameters = routeParameters; }); }
Create the findRoute() method
-
Continuing to edit the Display_a_map.cpp file, implement the
findmethod. Add code to first confirm thatRoute() RouteTaskhas loaded andRouteParametersis not empty. Then setRouteParametersto return directions, and clear stops from previous routes. Then createStopobjects for the route from the geometries of the start and end graphics, and pass those toRouteParameters. Callsolve, passing inRoute Async() RouteParameters. With the route completed, set the route graphic's geometry and resetRouteto prepare for a new route task. Then display the route directions.Builder Status Display_a_map.cppUse dark colors for code blocks void Display_a_map::findRoute() { if (m_routeTask->loadStatus() != LoadStatus::Loaded || m_routeParameters.isEmpty()) return; // Set parameters to return directions. m_routeParameters.setReturnDirections(true); // Clear previous stops from the parameters. m_routeParameters.clearStops(); // Set the stops to the parameters. const Stop stop1(Point(m_startGraphic->geometry())); const Stop stop2(Point(m_endGraphic->geometry())); m_routeParameters.setStops(QList<Stop> { stop1, stop2 }); // Solve the route with the parameters. m_routeTask->solveRouteAsync(m_routeParameters).then(this,[this](const RouteResult& routeResult) { // Add the route graphic once the solve completes. const Route generatedRoute = routeResult.routes().at(0); m_lineGraphic->setGeometry(generatedRoute.routeGeometry()); m_currentState = RouteBuilderStatus::NotStarted; // Set the direction maneuver list model. m_directions = generatedRoute.directionManeuvers(this); emit directionsChanged(); }); }
Create the resetState() method
This method resets all graphics and directions, and the Route enumeration. This happens at the beginning of every new route task.
-
Continuing to edit the Display_a_map.cpp file, reset all graphics with empty
Pointobjects, setmto_directions nullptr, and resetRoute. Then save the file.Builder Status Display_a_map.cppUse dark colors for code blocks void Display_a_map::resetState() { m_startGraphic->setGeometry(Point()); m_endGraphic->setGeometry(Point()); m_lineGraphic->setGeometry(Point()); m_directions = nullptr; m_currentState = RouteBuilderStatus::NotStarted; }
Create the GUI
-
In the Qt project, double click on Resources > qml\qml.qrc > /qml > Display_a_mapForm.qml to open the file. Add the following import.
display_a_mapForm.qmlUse dark colors for code blocks import QtQuick import QtQuick.Controls import Esri.Display_a_map import QtQuick.Shapes -
Add the code highlighted below in green. This builds out the application GUI and displays the route and route directions.
display_a_mapForm.qmlUse dark colors for code blocks // Declare the C++ instance which creates the map etc. and supply the view. Display_a_map { id: model mapView: view } // Create window for displaying the route directions. Rectangle { id: directionWindow anchors { right: parent.right top: parent.top margins: 5 } radius: 5 visible: model.directions width: Qt.platform.os === "ios" || Qt.platform.os === "android" ? 250 : 350 height: parent.height / 2 color: "#FBFBFB" clip: true ListView { id: directionsView anchors { fill: parent margins: 5 } header: Component { Text { height: 40 text: "Directions:" font.pixelSize: 22 } } // Set the model to the DirectionManeuverListModel returned from the route. model: model.directions delegate: directionDelegate } } Component { id: directionDelegate Rectangle { id: rect width: parent.width height: textDirections.height color: directionWindow.color // separator for directions Shape { height: 2 ShapePath { strokeWidth: 1 strokeColor: "darkgrey" strokeStyle: ShapePath.SolidLine startX: 20; startY: 0 PathLine { x: parent.width - 20 ; y: 0 } } } Text { id: textDirections text: qsTr("%1 (%2 miles)".arg(directionText).arg((length * 0.00062137).toFixed(2))) wrapMode: Text.WordWrap anchors { leftMargin: 5 left: parent.left right: parent.right } } } }
Set developer credentials
Now to complete this tutorial, click on the switcher for either API key authentication or User authentication options to use the correct authentication pattern to run the application.
You will need to supply the correct information for the authentication pattern you choose, this information was obtained when completing the Display a map tutorial.
Set the API Key
-
In the project Sources folder of Qt Creator, open the main.cpp file.
-
Modify the code to set the
accessusing your API key access token (highlighted in yellow).Token main.cppUse dark colors for code blocks // The following methods grant an access token: // 1. User authentication: Grants a temporary access token associated with a user's ArcGIS account. // To generate a token, a user logs in to the app with an ArcGIS account that is part of an // organization in ArcGIS Online or ArcGIS Enterprise. // 2. API key authentication: Get a long-lived access token that gives your application access to // ArcGIS location services. Go to the tutorial at https://links.esri.com/create-an-api-key. // Copy the API Key access token. const QString accessToken = QString(""); if (accessToken.isEmpty()) { qWarning() << "Use of ArcGIS location services, such as the basemap styles service, requires" << "you to authenticate with an ArcGIS account or set the API Key property."; } else { ArcGISRuntimeEnvironment::setApiKey(accessToken); } -
Save the main.cpp file.
Best Practice: The access token is stored directly in the code as a convenience for this tutorial. Do not store credentials directly in source code in a production environment.
Press Ctrl + R to run the app.
The map should support two clicks to create an origin and destination point and then use the route service to display the resulting route and turn-by-turn directions.
Alternatively, you can download the tutorial solution, as follows.
Option 2: Download the solution
-
Click the
Download solutionlink underSolutionand unzip the file to a location on your machine. -
Open the .pro project file in Qt Creator.
Since the downloaded solution does not contain authentication credentials, you must add the developer credentials that you created in the Set up authentication section.
Now to complete this tutorial, click on the switcher for either API key authentication or User authentication options to use the correct authentication pattern to run the application.
You will need to supply the correct information for the authentication pattern you choose, this information was obtained when completing the Display a map tutorial.
Set the API Key
-
In the project Sources folder of Qt Creator, open the main.cpp file.
-
Modify the code to set the
accessusing your API key access token (highlighted in yellow).Token main.cppUse dark colors for code blocks // The following methods grant an access token: // 1. User authentication: Grants a temporary access token associated with a user's ArcGIS account. // To generate a token, a user logs in to the app with an ArcGIS account that is part of an // organization in ArcGIS Online or ArcGIS Enterprise. // 2. API key authentication: Get a long-lived access token that gives your application access to // ArcGIS location services. Go to the tutorial at https://links.esri.com/create-an-api-key. // Copy the API Key access token. const QString accessToken = QString(""); if (accessToken.isEmpty()) { qWarning() << "Use of ArcGIS location services, such as the basemap styles service, requires" << "you to authenticate with an ArcGIS account or set the API Key property."; } else { ArcGISRuntimeEnvironment::setApiKey(accessToken); } -
Save main.cpp file.
Best Practice: The access token is stored directly in the code as a convenience for this tutorial. Do not store credentials directly in source code in a production environment.
Run the app
Press Ctrl + R to run the app.
The map should support two clicks to create an origin and destination point and then use the route service to display the resulting route and turn-by-turn directions.
What's next?
Learn how to use additional API features, ArcGIS location services, and ArcGIS tools in these tutorials: