Display directions for a route between two points.

Use case
Find routes with driving directions between any number of locations. You might use the ArcGIS platform to create a custom network for routing on a private roads.
How to use the sample
For simplicity, the sample comes loaded with a start and end stop. You can click on the Find Route to display a route between these stops. Once the route is generated, turn-by-turn directions are shown in a list.
How it works
- Create a
RouteTaskusing a URL to an online route service. - Generate default
RouteParametersusingrouteTask::createDefaultParametersAsync(). - Set
returnStopsandreturnDirectionson the parameters to true. - Add
Stops to the parametersstopscollection for each destination. - Solve the route using
routeTask::solveRouteAsync(routeParameters)to get aRouteResult. - Iterate through the result’s
Routes. To display the route, create a graphic using the geometry fromroute::routeGeometry(). To display directions, useroute::directionManeuvers()and apply the list model to the UI.
Relevant API
- DirectionManeuver
- Route
- RouteParameters
- RouteResult
- RouteTask
- Stop
Tags
directions, driving, navigation, network, network analysis, route, routing, shortest path, turn-by-turn
Sample Code
// [WriteFile Name=FindRoute, Category=Routing]// [Legal]// Copyright 2016 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
#ifdef PCH_BUILD#include "pch.hpp"#endif // PCH_BUILD
// sample headers#include "FindRoute.h"
// ArcGIS Maps SDK headers#include "ArcGISVectorTiledLayer.h"#include "Basemap.h"#include "DirectionManeuverListModel.h"#include "Graphic.h"#include "GraphicListModel.h"#include "GraphicsOverlay.h"#include "GraphicsOverlayListModel.h"#include "Map.h"#include "MapQuickView.h"#include "MapTypes.h"#include "PictureMarkerSymbol.h"#include "Point.h"#include "Polyline.h"#include "Route.h"#include "RouteParameters.h"#include "RouteResult.h"#include "RouteTask.h"#include "SimpleLineSymbol.h"#include "SimpleRenderer.h"#include "SpatialReference.h"#include "Stop.h"#include "SymbolTypes.h"#include "Viewpoint.h"
// Qt headers#include <QFuture>#include <QUuid>
using namespace Esri::ArcGISRuntime;
FindRoute::FindRoute(QQuickItem* parent) : QQuickItem(parent){}
FindRoute::~FindRoute() = default;
void FindRoute::init(){ qmlRegisterType<MapQuickView>("Esri.Samples", 1, 0, "MapView"); qmlRegisterUncreatableType<QAbstractListModel>("Esri.Samples", 1, 0, "AbstractListModel", "AbstractListModel is uncreateable"); qmlRegisterType<FindRoute>("Esri.Samples", 1, 0, "FindRouteSample");}
void FindRoute::componentComplete(){ QQuickItem::componentComplete();
// find QML MapView component m_mapView = findChild<MapQuickView*>("mapView");
// create a new basemap instance Basemap* basemap = new Basemap(BasemapStyle::ArcGISNavigation, this);
// create a new map instance m_map = new Map(basemap, this); m_map->setInitialViewpoint(Viewpoint(Point(-13041154, 3858170, SpatialReference(3857)), 1e5));
// set map on the map view m_mapView->setMap(m_map);
// create initial graphics overlays m_routeGraphicsOverlay = new GraphicsOverlay(this); SimpleLineSymbol* simpleLineSymbol = new SimpleLineSymbol(SimpleLineSymbolStyle::Solid, QColor("cyan"), 4, this); SimpleRenderer* simpleRenderer = new SimpleRenderer(simpleLineSymbol, this); m_routeGraphicsOverlay->setRenderer(simpleRenderer); m_stopsGraphicsOverlay = new GraphicsOverlay(this); m_mapView->graphicsOverlays()->append(m_routeGraphicsOverlay); m_mapView->graphicsOverlays()->append(m_stopsGraphicsOverlay);
// connect to loadStatusChanged signal connect(m_map, &Map::loadStatusChanged, this, [this](LoadStatus loadStatus) { if (loadStatus == LoadStatus::Loaded) { addStopGraphics(); setupRouteTask(); } });}
void FindRoute::addStopGraphics(){ //! [FindRoute cpp addStopGraphics] // create the stop graphics' geometry Point stop1Geometry(-13041171, 3860988, SpatialReference(3857)); Point stop2Geometry(-13041693, 3856006, SpatialReference(3857));
// create the stop graphics' symbols PictureMarkerSymbol* stop1Symbol = getPictureMarkerSymbol(QUrl("qrc:/Samples/Routing/FindRoute/pinA.png")); PictureMarkerSymbol* stop2Symbol = getPictureMarkerSymbol(QUrl("qrc:/Samples/Routing/FindRoute/pinB.png"));
// create the stop graphics Graphic* stop1Graphic = new Graphic(stop1Geometry, stop1Symbol, this); Graphic* stop2Graphic = new Graphic(stop2Geometry, stop2Symbol, this);
// add to the overlay m_stopsGraphicsOverlay->graphics()->append(stop1Graphic); m_stopsGraphicsOverlay->graphics()->append(stop2Graphic); //! [FindRoute cpp addStopGraphics]}
// Helper function for creating picture marker symbolsPictureMarkerSymbol* FindRoute::getPictureMarkerSymbol(QUrl imageUrl){ PictureMarkerSymbol* pictureMarkerSymbol = new PictureMarkerSymbol(imageUrl, this); pictureMarkerSymbol->setWidth(32); pictureMarkerSymbol->setHeight(32); pictureMarkerSymbol->setOffsetY(16); return pictureMarkerSymbol;}
void FindRoute::setupRouteTask(){ //! [FindRoute new RouteTask] // create the route task pointing to an online service m_routeTask = new RouteTask(QUrl("https://sampleserver6.arcgisonline.com/arcgis/rest/services/NetworkAnalysis/SanDiego/NAServer/Route"), this);
//! [FindRoute connect RouteTask signals] // connect to loadStatusChanged signal connect(m_routeTask, &RouteTask::loadStatusChanged, this, [this](LoadStatus loadStatus) { if (loadStatus == LoadStatus::Loaded) { // Request default parameters once the task is loaded m_routeTask->createDefaultParametersAsync().then(this, [this](const RouteParameters& routeParameters) { // Store the resulting route parameters m_routeParameters = routeParameters; }); } });
// load the route task m_routeTask->load();}
QAbstractListModel* FindRoute::directions(){ return m_directions;}
//! [FindRoute solveRoute]void FindRoute::solveRoute(){ if (m_routeTask->loadStatus() == LoadStatus::Loaded) { if (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 Stop stop1(geometry_cast<Point>(m_stopsGraphicsOverlay->graphics()->at(0)->geometry())); stop1.setName("Origin"); Stop stop2(geometry_cast<Point>(m_stopsGraphicsOverlay->graphics()->at(1)->geometry())); stop2.setName("Destination"); m_routeParameters.setStops(QList<Stop> { stop1, stop2 }); //! [FindRoute new RouteTask] // 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 Route generatedRoute = routeResult.routes().at(0); Graphic* routeGraphic = new Graphic(generatedRoute.routeGeometry(), this); m_routeGraphicsOverlay->graphics()->append(routeGraphic);
// set the direction maneuver list model m_directions = generatedRoute.directionManeuvers(this); emit directionsChanged();
// emit that the route has solved successfully emit solveRouteComplete(); }); //! [FindRoute connect RouteTask signals] }}//! [FindRoute solveRoute]// [WriteFile Name=FindRoute, Category=Routing]// [Legal]// Copyright 2016 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
#ifndef FIND_ROUTE_H#define FIND_ROUTE_H
// Qt headers#include <QQuickItem>#include <QUrl>
// STL headers#include <RouteParameters.h>
namespace Esri::ArcGISRuntime{ class Map; class MapQuickView; class GraphicsOverlay; class PictureMarkerSymbol; class RouteTask;}
class QAbstractListModel;Q_MOC_INCLUDE("QAbstractListModel")
class FindRoute : public QQuickItem{ Q_OBJECT
Q_PROPERTY(QAbstractListModel* directions READ directions NOTIFY directionsChanged)
public: explicit FindRoute(QQuickItem* parent = nullptr); ~FindRoute() override;
void componentComplete() override; static void init(); Q_INVOKABLE void solveRoute();
signals: void directionsChanged(); void solveRouteComplete();
private: void addStopGraphics(); void setupRouteTask(); QAbstractListModel* directions(); Esri::ArcGISRuntime::PictureMarkerSymbol* getPictureMarkerSymbol(QUrl imageUrl);
private: Esri::ArcGISRuntime::Map* m_map = nullptr; Esri::ArcGISRuntime::MapQuickView* m_mapView = nullptr; Esri::ArcGISRuntime::GraphicsOverlay* m_routeGraphicsOverlay = nullptr; Esri::ArcGISRuntime::GraphicsOverlay* m_stopsGraphicsOverlay = nullptr; Esri::ArcGISRuntime::RouteTask* m_routeTask = nullptr; Esri::ArcGISRuntime::RouteParameters m_routeParameters; QAbstractListModel* m_directions = nullptr;};
#endif // FIND_ROUTE_H// [WriteFile Name=FindRoute, Category=Routing]// [Legal]// Copyright 2016 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
import QtQuickimport QtQuick.Controlsimport Esri.Samples
FindRouteSample { id: findRouteSample width: 800 height: 600
onSolveRouteComplete: solveButton.visible = false
// Create window for displaying the route directions Rectangle { id: directionWindow anchors { right: parent.right top: parent.top bottom: parent.bottom } visible: false width: Qt.platform.os === "ios" || Qt.platform.os === "android" ? 250 : 350 color: "#FBFBFB"
//! [FindRoute cpp ListView directionsView] 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: findRouteSample.directions delegate: directionDelegate } //! [FindRoute cpp ListView directionsView] }
// add a mapView component MapView { id: mapView anchors.fill: parent objectName: "mapView"
Component.onCompleted: { // Set the focus on MapView to initially enable keyboard navigation forceActiveFocus(); }
// set the transform to animate showing the direction window transform: Translate { id: translate x: 0 Behavior on x { NumberAnimation { duration: 300; easing.type: Easing.OutQuad } } }
// Create the solve button to solve the route Rectangle { id: solveButton property bool pressed: false anchors { horizontalCenter: parent.horizontalCenter bottom: mapView.attributionTop bottomMargin: 5 }
width: 130 height: 30 color: pressed ? "#959595" : "#D6D6D6" radius: 5 border { color: "#585858" width: 1 }
Text { id: routeButtonText anchors.centerIn: parent text: "Solve route" font.pixelSize: 14 color: "#35352E" }
MouseArea { anchors.fill: parent onPressed: solveButton.pressed = true onReleased: solveButton.pressed = false onClicked: { findRouteSample.solveRoute(); } } }
// Create a button to show the direction window Rectangle { id: directionButton
property bool pressed: false
visible: !solveButton.visible anchors { right: parent.right bottom: parent.bottom rightMargin: 10 bottomMargin: 40 }
width: 45 height: width color: pressed ? "#959595" : "#D6D6D6" radius: 100 border { color: "#585858" width: 1.5 }
Image { anchors.centerIn: parent width: 35 height: width source: "qrc:/Samples/Routing/FindRoute/directions.png" }
MouseArea { anchors.fill: parent onPressed: directionButton.pressed = true onReleased: directionButton.pressed = false onClicked: { // Show the direction window when it is clicked translate.x = directionWindow.visible ? 0 : (directionWindow.width * -1); directionWindow.visible = !directionWindow.visible; } } } }
Component { id: directionDelegate Rectangle { id: rect width: parent.width height: 35 color: directionWindow.color
Rectangle { anchors { top: parent.top; left: parent.left; right: parent.right; topMargin: -8 leftMargin: 20 rightMargin: 20 } color: "darkgrey" height: 1 }
Text { text: directionText anchors { fill: parent leftMargin: 5 } elide: Text.ElideRight font.pixelSize: 14 } } }}// [Legal]// Copyright 2015 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
// sample headers#include "FindRoute.h"
// ArcGIS Maps SDK headers#include "ArcGISRuntimeEnvironment.h"
// Qt headers#include <QCommandLineParser>#include <QDir>#include <QGuiApplication>#include <QQmlEngine>#include <QQuickView>#include <QSettings>
// Platform specific headers#ifdef Q_OS_WIN#include <Windows.h>#endif
#define STRINGIZE(x) #x#define QUOTE(x) STRINGIZE(x)
int main(int argc, char *argv[]){ Esri::ArcGISRuntime::ArcGISRuntimeEnvironment::setUseLegacyAuthentication(false); QGuiApplication app(argc, argv); app.setApplicationName(QString("FindRoute"));
// Use of ArcGIS location services, such as basemap styles, geocoding, and routing services, // requires an access token. For more information see // https://links.esri.com/arcgis-runtime-security-auth.
// 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 { Esri::ArcGISRuntime::ArcGISRuntimeEnvironment::setApiKey(accessToken); }
// Initialize the sample FindRoute::init();
// Initialize application view QQuickView view; view.setResizeMode(QQuickView::SizeRootObjectToView);
// Add the import Path view.engine()->addImportPath(QDir(QCoreApplication::applicationDirPath()).filePath("qml"));
QString arcGISRuntimeImportPath = QUOTE(ARCGIS_RUNTIME_IMPORT_PATH);
#if defined(LINUX_PLATFORM_REPLACEMENT) // on some linux platforms the string 'linux' is replaced with 1 // fix the replacement paths which were created QString replaceString = QUOTE(LINUX_PLATFORM_REPLACEMENT); arcGISRuntimeImportPath = arcGISRuntimeImportPath.replace(replaceString, "linux", Qt::CaseSensitive); #endif
// Add the Runtime and Extras path view.engine()->addImportPath(arcGISRuntimeImportPath);
// Set the source view.setSource(QUrl("qrc:/Samples/Routing/FindRoute/FindRoute.qml"));
view.show();
return app.exec();}