Skip to content

Map Coverage MultiPoint Interactive

In this guide you will learn how to check map coverage for a single lon,lat coordinate point, or a list of lon,lat coordinate points, interactively selected on the map by the user.

To see an example using programmatically defined coordinate points, see the l MapCoverageMultiPoint example.

Check if map tiles are on the device

Map coverage 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

Map coverage example

MapCoverageMultiPointInteractive demonstrates how easy it is to use MapView to display an interactive map, and add markers interactively by pressing and holding on the map until a list of nearby points of interest appears, and then either select one, or click outside the popup list to cancel. If a POI is selected, a marker appears at its coordinates, which is displayed as an icon on the map. The icon is a circle with transparency, so the map shows through it. Then the map coverage is checked for these coordinates, and the results are displayed on screen. Also, the markers can be used as waypoints for rendering a route.

There are two types of markers: sketches-type markers and regular markers.

The sketches-type markers cannot be grouped, and all of them are displayed regardless of the zoom level. A custom icon image can be configured for rendering the icons. If no image is configured, a blue filled circle will be used as the icon. Sketches-type markers are the type of markers used in this example. To see an example using both sketches-type (non-grouping) icons, and grouping marker icons, see the MarkersProgrammatic example.

Setting the custom icon image for sketches-type markers - see qml.qrc and main.qml:

markerRenderSettings.icon = ServicesManager.createIconFromFile("qrc:/violetcircle.png");

Alternatively, instead of using a custom icon image, sketches-type markers can also be rendered on the map using the predefined red- green- or blue- filled circles, specified by enum value - see main.qml:

markerRenderSettings.icon = ServicesManager.createIconFromId(Icon.GreenBall);

The custom icon images, such as png images, optionally with transparency, and map styles, if any, must be located in the project directory and configured in the qml.qrc file, shown below:

1<RCC>
2   <qresource prefix="/">
3      <file>main.qml</file>
4      <file>violetcircle.png</file>
5   </qresource>
6</RCC>

How it works

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

then browse to the MapCoverageMultiPointInteractive example folder and open MapCoverageMultiPointInteractive.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.

Adding markers to the map interactively

First, a LandmarkList is defined to hold the user-selected points:

1//the following block is used only to enable autocenter on landmark group
2//and to render a route between the individual landmarks/waypoints/icons;
3//also, the map coverage check uses this list of landmarks;
4
5LandmarkList {
6    id: routingWaypoints
7}

A SearchService is defined to carry out reverse geocoding, to find points of interest around the location that the user long-pressed on the map:

 1SearchService {
 2    // Reverse geocoding takes as input a location on the map (lon,lat coordinates),
 3    // in this case, interactively selected by the user, and gives as output a list
 4    // of points of interest located near the selected position, 3 items in this example.
 5
 6    id: reverseGeocoding
 7    searchMapPOIs: true
 8    searchAddresses: true
 9    limit: 10
10    thresholdDistance: 500
11
12    // The list of 3 points of interest located near the selected position
13    // is shown here in a popup, giving the user the option to select one of them
14    // to be added as a waypoint for a route, or simply click outside the popup to close it.
15
16    onSearchCompleted: addWaypointPopup.open()
17}

A TapHandler is used to obtain the coordinates of the location the user long-pressed on the map, implementing the e onLongPressed event, and carry out the reverse geocoding search, to find POIs around the selected coordinate. The onTapped event is also defined, to show on screen the x,y screen coordinates and the corresponding lon,lat coordinates of any point clicked on the map, for reference.

 1TapHandler {
 2    grabPermissions: PointerHandler.CanTakeOverFromAnything
 3    onTapped: {
 4        let coordinates = mapView.wgsForScreen(point.pressPosition);
 5        console.log("x,y (" + point.pressPosition.x + ", " + point.pressPosition.y + ")"
 6                    + " lon, lat " + coordinates.longitude + ", " + coordinates.latitude);
 7        lonlatPositionDisplay.text = "x,y (" + point.pressPosition.x + ", " + point.pressPosition.y + ")"
 8                + " lon, lat " + coordinates.longitude + ", " + coordinates.latitude;
 9    }
10    onLongPressed: {
11        if (!useReverseGeocoding.checked) {
12            // This adds a waypoint to the route by long-tapping
13            // (tapping and holding for about a second)
14            // a given location directly on the map.
15            // First, create a landmark that can hold a route waypoint.
16
17            //Creates a landmark that is owned by the routingWaypoints, for efficiency.
18            //This is required because
19            //routingWaypoints.append(lmk);
20            //will clone the landmark unless the owner is the routingWaypoints list itself.
21
22            let lmk = ServicesManager.createLandmark(routingWaypoints);
23
24            // Next, add the map coordinates from the tap location to the waypoint.
25
26            lmk.coordinates = mapView.wgsForScreen(point.pressPosition);
27
28            // Finally, add the waypoint to the list from which the route is generated.
29
30            console.log("Waypoint added #########");
31            routingWaypoints.append(lmk);
32            show_waypoint_landmarks_on_map();
33            return;
34        }
35        if (point.pressPosition.x + addWaypointPopup.width > mapView.width)
36            addWaypointPopup.x = point.pressPosition.x - addWaypointPopup.width;
37        else
38            addWaypointPopup.x = point.pressPosition.x
39
40        if (point.pressPosition.y + addWaypointPopup.height > mapView.height)
41            addWaypointPopup.y = point.pressPosition.y - addWaypointPopup.height;
42        else
43            addWaypointPopup.y = point.pressPosition.y
44
45        reverseGeocoding.coordinates = mapView.wgsForScreen(point.pressPosition);
46        reverseGeocoding.search();
47    }
48}

Finally, a Popup is shown, containing up to 3 points of interest found around the coordinates the user long-pressed on the map; if there are more than 3 points of interest, the popup list is scrollable. If one of the items in the list is clicked, it is added to the routingWaypoints otherwise the selection can be cancelled by clicking outside the popup, to try again in a different location:

 1Popup {
 2    // This shows the results of the reverse geocoding in a popup.
 3    id: addWaypointPopup
 4    modal: true
 5    focus: true
 6    closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
 7    width: 300
 8    height: 200
 9    ListView {
10        id: searchList
11        anchors.fill: parent
12        anchors.margins: 1
13        clip: true
14        model: reverseGeocoding
15        delegate: Item {
16            height: row.height
17            RowLayout {
18                id: row
19                IconView {
20                    iconSource: landmark.icon
21                    Layout.maximumHeight: row.height
22                    Layout.maximumWidth: row.height
23                    width: height
24                    height: row.height
25                }
26               ColumnLayout {
27                    Layout.fillHeight: true
28                    Layout.fillWidth: true
29                    Text {
30                        Layout.fillWidth: true
31                        text: landmark.name + " ("
32                        + distance(landmark.coordinates.distance(reverseGeocoding.coordinates)) + ")"
33                        wrapMode: Text.WrapAnywhere
34                    }
35                    Text {
36                        Layout.fillWidth: true
37                        text: landmark.description
38                        font.italic: true
39                        wrapMode: Text.WrapAnywhere
40                    }
41                }
42                TapHandler {
43                    target: row
44                    onTapped: {
45                        // This adds a waypoint to the route by selecting
46                        // an item from the popup list of reverse geocoding results.
47                        addWaypointPopup.close()
48                        routingWaypoints.append(landmark)
49                        show_waypoint_landmarks_on_map();
50                    }
51                }
52            }
53        }
54    }
55}
Map coverage example

Although the selected POI is added to the routingWaypoints it is not rendered on the map. To give visual feedback, the selected waypoints are added to a marker list which are then rendered on the map by setting the marker list in the sketches-type markers using the function show_waypoint_landmarks_on_map()

 1function show_waypoint_landmarks_on_map()
 2{
 3       //show landmarks on map as point markers
 4       //a markercoordlist is created, and the coordinates of each interactively selected
 5       //waypoint/landmark is added to the markercoordlist which is used to render the
 6       //sketches-type markers on the map for visual feedback;
 7       let markercoordlist = ServicesManager.createMarker();
 8       for (let n = 0; n < routingWaypoints.length; n++) {
 9           let lmkit = routingWaypoints.get(n)
10           markercoordlist.append(lmkit.coordinates);
11       }
12       //the marker render settings contain configuration such as size and icon image
13       let markerRenderSettings = ServicesManager.createMarkerRenderSettings();
14       //sketches-type markers - cannot be grouped;
15       //let marker = ServicesManager.createMarker();
16       markerRenderSettings.imageSize = 32;
17       //the following line sets a custom icon image;
18       //choose one icon image line and uncomment it;
19       //the icon image is configured in qml.qrc, and located in the project directory;
20       //if an icon image is not set, markers will be shown as blue dots;
21       markerRenderSettings.icon = ServicesManager.createIconFromFile("qrc:/violetcircle.png");
22       //markerRenderSettings.icon = ServicesManager.createIconFromId(Icon.RedBall);
23       //markerRenderSettings.icon = ServicesManager.createIconFromId(Icon.GreenBall);
24       //markerRenderSettings.icon = ServicesManager.createIconFromId(Icon.BlueBall);
25       console.log(markerRenderSettings);
26
27       //SKETCHES-type markers - cannot be grouped, all markers are rendered at all zoom levels;
28       //render on the map the coordinate points for which map coverage is checked
29       let sketchlist = mapView.markerCollection.getExtendedList(MarkerList.Type.Point);
30       sketchlist.clear(); //clear previous markers so list does not grow with duplicates
31       sketchlist.append(markercoordlist, markerRenderSettings);
32
33       //print some debug info to the console
34       console.log("marker sketchlist len:" + sketchlist.length + " icon coords:" + sketchlist.get(0).length);
35       console.log("marker len:"+markercoordlist.length+" renderset:"+markerRenderSettings);
36
37       //center on list of waypoints/landmarks
38       if (routingWaypoints.length > 1)
39       {
40           mapView.centerOnGeographicArea(routingWaypoints.boundingBox)
41       }
42       return markercoordlist;
43}

Single point map coverage

 1//////////////////////////////////////////////////////////////////////////////////
 2//check map coverage for one point - (latitude,longitude) coordinate
 3//////////////////////////////////////////////////////////////////////////////////
 4let onecoord = markercoordlist.get(0) //the first coord in the list, at index 0:lat,lon,alt
 5let mapcover = ServicesManager.mapDetails.coverage(onecoord);
 6let coverageResult = "Single coordinate point map coverage result: ";
 7switch ( mapcover )
 8{
 9case MapDetails.Unknown:
10    coverageResult = coverageResult + "MapDetails.Unknown"; break;
11case MapDetails.Offline:
12    coverageResult = coverageResult + "MapDetails.Offline"; break;
13case MapDetails.OnlineNoData:
14    coverageResult = coverageResult + "MapDetails.OnlineNoData"; break;
15case MapDetails.OnlineTile:
16    coverageResult = coverageResult + "MapDetails.OnlineTile"; break;
17default:
18    coverageResult = coverageResult + "default case - undefined"; break;
19}
20singleCoordMapCoverage.text = coverageResult;
21console.log(coverageResult);

To check map coverage at one specific lon,lat coordinate, define the coordinate, onecoord in this case, which simply takes the first user-selected point on the map (at index 0) and then call ServicesManager.mapDetails.coverage(onecoord);, and finally process the result as shown above. The coverage result is shown on screen (in blue text), and also logged in the console output.

Multiple point map coverage

Map coverage example

The coordinates are added to the routing waypoint list interactively as shown above, and then they are copied into a marker coordinate list:

let markercoordlist = show_waypoint_landmarks_on_map();

so they can be passed to the map coverage verification function.

 1//////////////////////////////////////////////////////////////////////////////////
 2//check map coverage for multiple coordinates
 3//////////////////////////////////////////////////////////////////////////////////
 4let mapcovermulti = ServicesManager.mapDetails.coverageCoordList(markercoordlist)
 5coverageResult = "Multiple coordinate points map coverage result: ";
 6switch ( mapcovermulti )
 7{
 8case MapDetails.Unknown:
 9    coverageResult = coverageResult + "MapDetails.Unknown"; break;
10case MapDetails.Offline:
11    coverageResult = coverageResult + "MapDetails.Offline"; break;
12case MapDetails.OnlineNoData:
13    coverageResult = coverageResult + "MapDetails.OnlineNoData"; break;
14case MapDetails.OnlineTile:
15    coverageResult = coverageResult + "MapDetails.OnlineTile"; break;
16default:
17    coverageResult = coverageResult + "default case - undefined"; break;
18}
19multiCoordsMapCoverage.text = coverageResult;
20console.log(coverageResult);

To check map coverage for a list of lon,lat coordinates, define the coordinate list using a marker as shown above, markercoordlist in this case, is copied from the interactively selected routing waypoint list, and then call ServicesManager.mapDetails.coverageCoordList(markercoordlist), and finally process the result as shown above. The coverage result is shown on screen (in blue text), and also logged in the console output.

Country code and map coverage

Map coverage example

The following for loop code block demonstrates how to get the country code from a lon,lat coordinate using ServicesManager.mapDetails.countryCode() and how to get country map coverage status from a country code using ServicesManager.mapDetails.countryCoverage() as well as the country name from the country code, and print the results along with the index and lon,lat coordinates to the application console output window.

 1//////////////////////////////////////////////////////////////////////////////////
 2// for each coordinate in the list, print in the console output:
 3// index, map coverage status, country code, coordinate(lon,lat), country name
 4//////////////////////////////////////////////////////////////////////////////////
 5let countrycode = "";
 6for (let idx = 0; idx < markercoordlist.length; idx++) {
 7    countrycode = ServicesManager.mapDetails.countryCode(markercoordlist.get(idx))
 8    let mapcountrycover = ServicesManager.mapDetails.countryCoverage(countrycode)
 9    coverageResult = "Country coverage result by coordinate point: ";
10    switch ( mapcountrycover )
11    {
12    case MapDetails.Unknown:
13        coverageResult = coverageResult + "MapDetails.Unknown"; break;
14    case MapDetails.Offline:
15        coverageResult = coverageResult + "MapDetails.Offline"; break;
16    case MapDetails.OnlineNoData:
17        coverageResult = coverageResult + "MapDetails.OnlineNoData"; break;
18    case MapDetails.OnlineTile:
19        coverageResult = coverageResult + "MapDetails.OnlineTile"; break;
20    default:
21        coverageResult = coverageResult + "default case - undefined"; break;
22    }
23    console.log("[" + idx + "] " + coverageResult + " " + countrycode + " ("
24        + markercoordlist.get(idx).longitude + ", " + markercoordlist.get(idx).latitude
25        + ") " + ServicesManager.mapDetails.countryName(countrycode))
26}

Sample console output:

1qml: Single coordinate point map coverage result: MapDetails.OnlineNoData
2qml: Multiple coordinate points map coverage result: MapDetails.OnlineNoData
3qml: [0] Country coverage result by coordinate point: MapDetails.OnlineNoData CHE (8.92530625, 46.074485) Switzerland
4qml: [1] Country coverage result by coordinate point: MapDetails.OnlineNoData ITA (9.2410453125, 46.173598125) Italy
5qml: [2] Country coverage result by coordinate point: MapDetails.OnlineNoData ITA (9.29047125, 46.0163665625) Italy

Rendering a route

Map coverage example

Optionally, a route can be rendered using the markers as waypoints, in the order in which they were added (interactively selected on the map).

 1RoutingService {
 2    id: routingService
 3    type: Route.Type.Fastest
 4    transportMode: Route.TransportMode.Car
 5    // The list of waypoints is made available to the routing service.
 6    waypoints: routingWaypoints
 7    onFinished: {
 8        map.routeCollection.set(routeList);
 9        map.centerOnRouteList(routeList);
10    }
11}

A RoutingService is defined, used in this example only to compute and render a route plotted using the list of waypoints/landmarks in the order in which they were added to the list; this block is not required to autocenter on the landmark group. Set internet connection to true in the Component.onCompleted block for route computation and rendering to work.

 1Button {
 2    anchors.left: parent.left
 3    anchors.bottom: parent.bottom
 4    enabled: routingWaypoints.length > 1
 5    text: qsTr("Render route")
 6    background: Rectangle {
 7        opacity: parent.hovered ? 1 : 0.5
 8        color: enabled ? parent.down ? "#aa00aa" :
 9               (parent.hovered ? "#0000ff" : "#2000ff") : "#aaaaaa"
10    }
11    palette { buttonText: "#ffffff"; }
12    onClicked: {
13        //render route when button is clicked only if there are min 2 waypoints in the list;
14        if (routingWaypoints.length > 1)
15        {
16            //compute and render a route plotted using list of waypoints/landmarks
17            //in the order in which they were added
18            //center on route plotted from list of waypoints/landmarks
19            routingService.update()
20        }
21    }
22}

Click the Render route button to compute and render the route, once at least 2 waypoints have been selected, because a route consists of at least 2 waypoints, where the first is the departure point and the last is the destination. Click the Clear route button to remove the route from the map.

Removing sketches-type markers

The route and/or sketches-type markers can be removed from the map separately.

 1Button {
 2    text: "Clear sketches-type markers/waypoints"
 3    background: Rectangle {
 4        opacity: parent.hovered ? 1 : 0.5
 5        color: enabled ? parent.down ? "#aa00aa" :
 6               (parent.hovered ? "#0000ff" : "#2000ff") : "#aaaaaa"
 7    }
 8    palette { buttonText: "#ffffff"; }
 9    onClicked: {
10        //show how to clear sketches-type marker icons from the map;
11        //clear the list of points used for centering on the bounding box
12        //containing all points/landmarks/waypoints/markers/icons;
13
14        routingWaypoints.clear();
15
16        //also clear the markerlist used for rendering the points on the map;
17        //the same set of coordinates is in each of these lists, so both must
18        //be cleared;
19
20        let sketchlist = mapView.markerCollection.getExtendedList(MarkerList.Type.Point);
21        sketchlist.clear();
22    }
23}

Removing the sketches-type markers is done by again getting a pointer to the built-in sketches-type marker list, and using the clear() function. The corresponding routingWaypoints list, used to render the route or center on the group of markers, or both, is also cleared. The same set of coordinates is in each of these lists, so both must be cleared. Also, the button changes color to blue and becomes opaque when the mouse hovers over it for visual feedback.

QML Examples

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