Skip to content

Landmark List

In this guide you will learn how to dynamically select a departure and destination for your route on the map, from interactive user input, using LandmarkList and then draw the route on the map, and finally start a navigation/simulation along the route.

See the Routing and Navigation Example for a guide on how to calculate a route, and simulate navigation along that route, between preset or programmatically selected start (departure) and end (destination) points.

See the GPX Routing and Navigation guide on how to calculate a route based on GPX data, and simulate navigation along that route.

Interactive Routing and Navigation

QML interactive routing and navigation example

First, get an API key token, see the Getting Started guide.

Qt should be installed to continue.

The Maps SDK for Qt should be installed, see the Setup Maps SDK for Qt guide.

Overview

The most important part of this example is to demonstrate generating a route from a departure location to a destination location (with optional waypoint(s) in between) which are interactively selected by the user on the map. This shows how to use the Maps SDK for Qt in a real world use case.

What you will learn in this guide:

  • How to interactively select a departure and destination for your route, and optional waypoints.

  • Select any location on the map to add as a waypoint for your route.

  • Select a reverse geocoding result from a popup to add as a waypoint for your route.

  • Compute and draw the interactively selected route.

  • Simulate navigation on the route.

  • Interactively reverse geocode, that is, click on the map to see points of interest near the clicked location.

LandmarkList holds the departure and destination locations, which are selected interactively by the user on the map with a long tap (click and hold for about a second).

At least 2 points have to be selected, one for departure and the second one for destination. If more than 2 points are selected, then the first one is the departure location, the last one is the destination location, and the intermediate points are waypoints along the route, in order from departure point to destination point.

QML interactive routing and navigation departure

In the above image, the departure point is selected by long tap/click and hold.

If the [x]Show reverse geocoding list checkbox at the top is checked, then the reverse geolocation menu pops up, showing 3 points of interest (POIs) near the selected position. To actually set the departure point, click one of the three options.

Or, click elsewhere on the map, outside the popup menu to close it, and then long tap/click and hold another location on the map to see other options.

If the [ ]Show reverse geocoding list checkbox at the top is not checked, then a long tap/click and hold will automatically add that location to the route.

Once a location has been added, the Clear waypoints button at the lower right will no longer be greyed out, indicating that at least one waypoint has been added.

QML interactive routing and navigation destination

In the above image, the destination point is selected by long tap/click and hold.

The Compute route(s) button at the lower left will no longer be greyed out, indicating that at least two waypoints have been added - the departure and the destination points in this case. More waypoints can be added if so desired. The route will be calculated from the first waypoint (departure) to the last waypoint (destination) in the order in which the points were added.

To change the order, click Clear waypoints and start again. The Clear waypoints button is inactive if no waypoint has been added.

QML interactive routing and navigation route

After adding at least 2 waypoints for the route, click the Compute route(s) button in the lower left of the map view to see the computed route drawn in blue between the selected departure and destination locations. The Compute route(s) button is inactive if less than 2 waypoints have been added.

QML interactive routing and navigation simulation

Next, click the Start simulation button to simulate navigation along the route.

How it works

In Qt, go to the File menu and select Open File or Project…

QML interactive routing and navigation open

then browse to the LandmarkList example folder and open LandmarkList.pro

You may want to have a look at Setting your API Key to see how to open and configure a project and set your API Key.

In main.qml, we import the GeneralMagic QML plugin. Next, we need to make sure we allow online access, and that we are using the latest data.

 1import QtQuick.Window 2.12
 2import GeneralMagic 2.0
 3
 4Window
 5{
 6 visible: true
 7 width: 640
 8 height: 480
 9 title: qsTr("Interactive LandmarkList Routing and Navigation Example")
10
11 Component.onCompleted:
12 {
13  ServicesManager.settings.token = __my_secret_token;
14
15  ServicesManager.settings.allowInternetConnection = true;
16
17  var updater = ServicesManager.contentUpdater(ContentItem.Type.RoadMap);
18  updater.autoApplyWhenReady = true;
19  updater.update();
20 }
21}

The __my_secret_token property in the above QML code is set in C++ like this.

1// C++ code
2QQmlApplicationEngine engine;
3//...
4//! [Set API Key token safely]
5// go to https://developer.magiclane.com to get your token
6engine.rootContext()->setContextProperty("__my_secret_token", "YOUR_TOKEN");
7//! [Set API Key token safely]
8
9engine.load(url);

In this example, in main.cpp, replace YOUR_TOKEN with your actual Magic Lane Maps API key token.

And this is how to render an interactive map using a MapView

 1MapView
 2{
 3  id: mapView
 4  anchors.fill: parent
 5  viewAngle: 25
 6  preferences.cursorVisibility: false
 7
 8  onRouteSelected:
 9  {
10    preferences.routeCollection.mainRoute = route;
11    centerOnRoute(route);
12  }
13}
QML interactive routing and navigation map

To start a simulation/navigation using a route generated from interactively selected waypoints, there are three steps involved:

Select the waypoints for the route

QML interactive routing and navigation departure

The waypoints can be selected by clicking on the map, when the [X] Show reverse geocoding list checkbox at the top of the map is checked, and then selecting one of the points of interest from the popup that appears. Or click outside the popup to close it and select a different location on the map.

 1SearchService
 2{
 3  // Reverse geocoding takes as input a location on the map (lon,lat coordinates),
 4  // in this case, interactively selected by the user, and gives as output a list
 5  // of points of interest located near the selected position, 3 items in this example.
 6
 7  id: reverseGeocoding
 8  preferences
 9  {
10    searchMapPOIs: true
11    searchAddresses: true
12    limit: 10
13    thresholdDistance: 500
14  }
15
16  // The list of 3 points of interest located near the selected position
17  // is shown here in a popup, giving the user the option to select one of them
18  // to be added as a waypoint for a route, or simply click outside the popup to close it.
19
20  onSearchCompleted: addWaypointPopup.open()
21}
22
23Popup
24{
25  // This shows the results of the reverse geocoding in a popup.
26
27  id: addWaypointPopup
28  modal: true
29  focus: true
30  closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
31  width: 300
32  height: 200
33
34  ListView
35  {
36    id: searchList
37    anchors.fill: parent
38    anchors.margins: 1
39    clip: true
40    model: reverseGeocoding
41
42    delegate: Item
43    {
44      height: row.height
45
46      RowLayout
47      {
48        id: row
49
50        IconView
51        {
52          iconSource: landmark.icon
53          Layout.maximumHeight: row.height
54          Layout.maximumWidth: row.height
55          width: height
56          height: row.height
57        }
58        ColumnLayout
59        {
60          Layout.fillHeight: true
61          Layout.fillWidth: true
62
63          Text
64          {
65            Layout.fillWidth: true
66            text: landmark.name + " (" + distance(
67              landmark.coordinates.distance(reverseGeocoding.coordinates)) + ")"
68            wrapMode: Text.WrapAnywhere
69          }
70          Text
71          {
72            Layout.fillWidth: true
73            text: landmark.description
74            font.italic: true
75            wrapMode: Text.WrapAnywhere
76          }
77        }
78        TapHandler
79        {
80          target: row
81          onTapped:
82          {
83
84            // This adds a waypoint to the route by selecting
85            // an item from the popup list of reverse geocoding results.
86
87            routingWaypoints.append(landmark)
88            addWaypointPopup.close()
89          }
90        }
91      }
92    }
93  }
94}
QML interactive routing and navigation destination

Waypoints can also be selected directly by tapping and holding on the map for about one second.

 1Label
 2{
 3  id: infoLabel
 4  anchors.top: parent.top
 5  anchors.horizontalCenter: parent.horizontalCenter
 6  text: "Long press to add a waypoint"
 7}
 8CheckBox
 9{
10  id: useReverseGeocoding
11  anchors.top: infoLabel.bottom
12  anchors.horizontalCenter: parent.horizontalCenter
13
14  checked: true
15  text: "Show reverse geocoding list"
16}
17
18TapHandler
19{
20  grabPermissions: PointerHandler.CanTakeOverFromAnything
21  onLongPressed:
22  {
23    if (!useReverseGeocoding.checked)
24    {
25      // This adds a waypoint to the route by long-tapping
26      // (tapping and holding for about a second)
27      // a given location directly on the map.
28      // First, create a landmark that can hold a route waypoint.
29
30      var lmk = landmarkComponent.createObject(routingWaypoints);
31
32      // Next, add the map coordinates from the tap location to the waypoint.
33
34      lmk.coordinates = mapView.wgsForScreen(point.pressPosition);
35
36      // Finally, add the waypoint to the list from which the route is generated.
37
38      routingWaypoints.append(lmk);
39
40      console.log("Waypoint added");
41      return;
42    }
43
44    if (point.pressPosition.x + addWaypointPopup.width > mapView.width)
45      addWaypointPopup.x = point.pressPosition.x - addWaypointPopup.width;
46    else
47      addWaypointPopup.x = point.pressPosition.x
48
49    if (point.pressPosition.y + addWaypointPopup.height > mapView.height)
50      addWaypointPopup.y = point.pressPosition.y - addWaypointPopup.height;
51    else
52      addWaypointPopup.y = point.pressPosition.y
53
54    reverseGeocoding.coordinates = mapView.wgsForScreen(point.pressPosition);
55    reverseGeocoding.search();
56  }
57}

At least 2 waypoints must be selected for a route.

Compute the route(s)

QML interactive routing and navigation route

In the second step, declare a RoutingService

 1LandmarkList
 2{
 3  // This is the waypoint list for the route,
 4  // including the departure and destination.
 5
 6  id: routingWaypoints
 7}
 8
 9Component
10{
11  // This is used for creating a waypoint to be added
12  // to the route from a location tapped on the map.
13
14  id: landmarkComponent
15  Landmark {}
16}
17
18RoutingService
19{
20  id: routingService
21  preferences
22  {
23      type: RoutePreferences.Type.Fastest
24      transportMode: RoutePreferences.TransportMode.Car
25  }
26
27  // The list of waypoints is made available to the routing service.
28
29  waypoints: routingWaypoints
30  onCompleted:
31  {
32      mapView.preferences.routeCollection.set(routes);
33      mapView.centerOnRoutes(routes);
34  }
35}

and then use it to calculate route(s).

 1Button
 2{
 3  text: "Compute route(s)"
 4  enabled: ServicesManager.settings.connected && !navigation.active && routingWaypoints.length > 1
 5  onClicked: routingService.update()
 6}
 7Button
 8{
 9  enabled: mapView.preferences.routeCollection.mainRoute.valid
10  text: navigation.active ? "Stop simulation" : "Start simulation"
11  onClicked: navigation.active = !navigation.active
12}

Do simulation/navigation

The third step is to declare a NavigationService for real or simulated turn-by-turn navigation, to start the simulation/navigation.

 1function distance(meters)
 2{
 3  return meters >= 1000 ? (meters / 1000.).toFixed(3) + " Km" :  meters.toFixed(0) + " m";
 4}
 5
 6NavigationService
 7{
 8  id: navigation
 9  route: mapView.preferences.routeCollection.mainRoute
10  simulation: true // change it to false (default) to perform real turn by turn navigation
11  onActiveChanged:
12  {
13    if (active)
14    {
15      mapView.startFollowingPosition();
16      mapView.preferences.routeCollection.clear();
17      mapView.preferences.routeCollection.add(mapView.preferences.routeCollection.mainRoute);
18    }
19  }
20  navigationListener: NavigationListener
21  {
22    onWaypointReached: console.log("WaypointReached :" + waypoint.name);
23    onDestinationReached: mapView.preferences.routeCollection.clear();
24    onNavigationError:
25    {
26      console.log("NavigationError :" + error);
27      mapView.preferences.routeCollection.clear();
28    }
29    onRouteChanged:
30    {
31      console.log("RouteUpdated :" + route.summary);
32      mapView.preferences.routeCollection.clear();
33      mapView.preferences.routeCollection.add(route);
34    }
35    onNavigationInstructionUpdated:
36    {
37      nextTurnIcon.iconSource = navigationInstruction.nextTurnDynamicIcon;
38      nextTurnInfo.text = navigationInstruction.nextStreetName + " ("
39      + distance(navigationInstruction.distanceToNextTurn) + ")";
40    }
41  }
42}

QML Examples

Maps SDK for Qt Examples can be downloaded or cloned with Git