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
RouteTask
using a URL to an online route service. - Generate default
RouteParameters
usingrouteTask::createDefaultParametersAsync()
. - Set
returnStops
andreturnDirections
on the parameters to true. - Add
Stop
s to the parametersstops
collection for each destination. - Solve the route using
routeTask::solveRouteAsync(routeParameters)
to get aRouteResult
. - Iterate through the result's
Route
s. 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 symbols
PictureMarkerSymbol* 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]