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 Runtime API for Qt is installed.
Steps
Get an access token
You need an access token to use the location services used in this tutorial.
-
Go to the Create an API key tutorial to obtain an access token using your ArcGIS Location Platform or ArcGIS Online account.
-
Ensure that the following privileges are enabled: Location services > Basemaps > Basemap styles service and Location services > Routing.
-
Copy the access token as it will be used in the next step.
To learn more about other ways to get an access token, go to Types of authentication.
Open the project in Qt Creator
-
To start this tutorial, complete the Display a map tutorial or download and unzip the solution.
-
Open the display_a_map project in Qt Creator.
-
In the Projects window, in the Sources folder, open the main.cpp file.
-
Modify the code to set the API key to the access token. Save and close the file.
main.cppUse dark colors for code blocks 43 44 45 46Change line // 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("");
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. Include the four classes shown.
Display_a_map.hUse dark colors for code blocks 22 23 24Add line. Add line. Add line. Add line. class Map; class MapQuickView; class Graphic; class GraphicsOverlay; class PictureMarkerSymbol; class RouteTask;
-
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 25 26 27 28 29 30 31 32Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. class Graphic; class GraphicsOverlay; class PictureMarkerSymbol; class RouteTask; } } enum RouteBuilderStatus { NotStarted, SelectedStart, SelectedStartAndEnd, }; #include "RouteParameters.h"
-
Use Q_PROPERTY to create a member variable
m
._directions Display_a_map.hUse dark colors for code blocks 47 48Add line. 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 56 57 58Add line. signals: void mapViewChanged(); void directionsChanged();
-
Declare the following private methods.
Display_a_map.hUse dark colors for code blocks 61 62 63 64 65Add line. Add line. Add line. private: Esri::ArcGISRuntime::MapQuickView* mapView() const; void setMapView(Esri::ArcGISRuntime::MapQuickView* mapView); void setupViewpoint(); void setupRouteTask(); void findRoute(); void resetState();
-
Declare and initialize the following pointers, object, and enumeration. Then save and close the file.
Display_a_map.hUse dark colors for code blocks 66 67 68 69 70 71 72Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. 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 display_a_map project, double click on Sources > Display_a_map.cpp to open the file. Include the six classes shown.
Display_a_map.cppUse dark colors for code blocks 16 17 18 19Add line. Add line. Add line. Add line. Add line. Add line. #include "ArcGISRuntimeEnvironment.h" #include "Map.h" #include "MapQuickView.h" #include "Point.h" #include "RouteTask.h" #include "RouteParameters.h" #include "SimpleLineSymbol.h" #include "SimpleMarkerSymbol.h" #include "Stop.h"
Update the constructor
-
Update the constructor as shown, to use a
Basemap
and to initialize theStyle Route
enumeration.Builder Status Display_a_map.cppUse dark colors for code blocks 31 32 33 35Change line Add line. Display_a_map::Display_a_map(QObject* parent /* = nullptr */): QObject(parent), m_map(new Map(BasemapStyle::ArcGISStreets, this)), m_currentState(RouteBuilderStatus::NotStarted)
-
Call the
setup
method within the constructor. This will be populated in a later step.Route Task() Display_a_map.cppUse dark colors for code blocks 31 32 33 34 35 36 37 38 39Add line. 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
-
In
setup
change the map'sViewpoint() Point
andViewpoint
to place the map over over downtown Los Angeles.Display_a_map.cppUse dark colors for code blocks 53 54 55Change line Change line 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
-
Add a
connect
statement tosetup
to detect user mouse clicks, set and display point graphics, respond to the first and second click (using theViewpoint() switch
statement) and callfind
on the second mouse click.Route Display_a_map.cppUse dark colors for code blocks 56 57 58 59 60Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. const Point center(-118.24532, 34.05398, SpatialReference::wgs84()); const Viewpoint viewpoint(center, 144447.638572); m_mapView->setViewpoint(viewpoint); connect(m_mapView, &MapQuickView::mouseClicked, this, [this](QMouseEvent mouse) { const Point mapPoint = m_mapView->screenToLocation(mouse.x(), mouse.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
-
Add code to
setup
to create the route's starting pointViewpoint() Graphic
, determined by the user's first mouse click. This consists of aSimple
, color blue, size 2, that outlines aLine Symbol Simple
, diamond shaped and orange in color.Marker Symbol -
Create the route's ending point
Graphic
, determined by the user's second mouse click. This consists of aSimple
, color red, size 2, that outlines aLine Symbol Simple
, square shaped and green in color.Markersymbol -
Create a line
Graphic
connecting the route's starting and ending points using aSimple
, color blue, size 4. Then append the starting point graphic, ending point graphic, and route line graphic to aLine Symbol Graphics
.Overlay Display_a_map.cppUse dark colors for code blocks 78 79 80 81 82 83Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. 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 Route
class to access a routing service.
Create a Route
with a string URL to reference the routing service.
-
Begin implementing the
set
method. Point theRoute Task() Route
to an online service. ThenTask connect
tocreate
and store the resulting route parameters.Default Parameters Completed Display_a_map.cppUse dark colors for code blocks Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. 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); // connect to createDefaultParametersCompleted signal connect(m_routeTask, &RouteTask::createDefaultParametersCompleted, this, [this](QUuid, RouteParameters routeParameters) { // Store the resulting route parameters m_routeParameters = routeParameters; });
-
Connect to
solve
. With the route completed, set the route graphic'sRoute Completed Geometry
and resetRoute
to prepare for a new route task. Then display the route directions. Outside ofBuilder Status connect
, configure theRoute
with default parameters.Task Display_a_map.cppUse dark colors for code blocks 112 113 114 115 116 117 118Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. // connect to createDefaultParametersCompleted signal connect(m_routeTask, &RouteTask::createDefaultParametersCompleted, this, [this](QUuid, RouteParameters routeParameters) { // Store the resulting route parameters m_routeParameters = routeParameters; }); // connect to solveRouteCompleted signal connect(m_routeTask, &RouteTask::solveRouteCompleted, this, [this](QUuid, 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 default parameters which will load the route task implicitly m_routeTask->createDefaultParameters(); }
Create the findRoute() method
-
Add code to first confirm that
Route
has loaded andTask Route
is not empty. Then setParameters Route
to return directions, and clear stops from previous routes.Parameters -
Then create
Stop
s for the route from the geometries of the start and end graphics, and pass those toRoute
. Finally, callParameters solve
, passing inRoute() Route
.Parameters Display_a_map.cppUse dark colors for code blocks Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. 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(m_startGraphic->geometry()); const Stop stop2(m_endGraphic->geometry()); m_routeParameters.setStops(QList<Stop> { stop1, stop2 }); // solve the route with the parameters m_routeTask->solveRoute(m_routeParameters); }
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.
-
Reset all graphics with empty
Point
s, setm
to_directions nullptr
, and resetRoute
. Then save the file.Builder Status Display_a_map.cppUse dark colors for code blocks Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. 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 display_a_map 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 14 15 16 17Add line. import QtQuick 2.6 import QtQuick.Controls 2.2 import Esri.display_a_map 1.0 import QtQuick.Shapes 1.12
-
Add the code highlighted below. This builds out the application GUI and displays the route and route directions.
display_a_mapForm.qmlUse dark colors for code blocks 31 32 33 34 35 36Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. // 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 } } } }
-
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: