libosmscout libosmscout.sf.net

Qt QML API

Part of this project is libosmscout-client-qt library that aims to provide simple API for applications using user interface in QML.

This page show usage of basic QML components that may helps you create your own application with mapping capabilities, like displaying map, search places, routing… Following examples are using Silica UI components, but code for other UI components (like QtQuick components), will be very similar.

Initialisation

Before using library from QML it is necessary to initialise it from C++.

OSMScoutQt::RegisterQmlTypes();

bool success=OSMScoutQt::NewInstance()
     .WithBasemapLookupDirectory(basemapDir)
     .WithStyleSheetDirectory(stylesheetDir)
     .WithStyleSheetFile(stylesheetFileName)
     .WithIconDirectory(iconDirectory)
     .WithMapLookupDirectories(mapLookupDirectories)
     .WithOnlineTileProviders(":/resources/online-tile-providers.json")
     .WithMapProviders(":/resources/map-providers.json")
     .Init();

if (!success){
  // terminate program, or just report error - something is really bad
  
}

// now it is possible to create QML window that is using the library

// release resources

OSMScoutQt::FreeInstance();

For detailed description see OSMScoutQtBuilder class and practival usage OSMScout2 demo source code.

To make components awailable in QML, you have to import it:

import net.sf.libosmscout.map 1.0

Note: when you are writting application for Sailfish OS (SFOS) and do you plan to distribute it via Harbour (official SFOS store), it is neccessary to change component uri to match the name of the application: OSMScoutQt::RegisterQmlTypes("harbour.<app-name>.map", 1, 0); Imported uri will be different then, but another code will be working without change.

Displaying map

When you want to display a map, it is very simple. Just use Map UI component:

Map {
  id: map
  renderingType: "tiled" // plane (default) or tiled
}

For all signals and slots, see MapWidget. You can choose one of two rendering types:

User input

Map component react on user touches with moving (or mouse drag) and zooming (multitouch gesture, double-click or scrolling of mouse wheel). Actions on simple click, or “holding” should be defined by application.

Map{
    onTap: {
        console.log("tap: " + screenX + "x" + screenY + " @ " + 
                    lat + " " + lon + " (map center "+ 
                    map.view.lat + " " + map.view.lon + ")");
    }
    onLongTap: {
        console.log("long tap: " + screenX + "x" + screenY + " @ " + 
                    lat + " " + lon + " (map center " + 
                    map.view.lat + " " + map.view.lon + ")");
    }
}

Display custom marks and ways

Map component supports to display few kinds of overlay objects.

Current position mark

Just allow it by showCurrentPosition property and update current position by locationChanged slot:

Map{
    id: map
    showCurrentPosition: true

    PositionSource {
        id: positionSource
        active: true
        onPositionChanged: {
            map.locationChanged(
                      position.latitudeValid && position.longitudeValid,
                      position.coordinate.latitude, position.coordinate.longitude,
                      position.horizontalAccuracyValid, position.horizontalAccuracy);
        }
    }
}

It will display small green dot (or red when position is not valid) with semitransparent circle representing horizontal accuracy:

Current position mark

Place mark

You can custom place mark by addPositionMark and remove it by removePositionMark.

Map{
  id: map
  property int markId: 0;
  onTap: {
      map.addPositionMark(markId++, lat, lon);
      if (markId>=10){
          map.removePositionMark(markId-10);
      }
  }
}

It will display red circle around position:

Place mark

Custom way, area or node

This overlay type is used for displaying routing result for example, but it may be used for displaying any custom object with any style defined in stylesheet.

Map{
  property var overlayWay: map.createOverlayWay("_route");
  onTap: {
    overlayWay.addPoint(lat, lon);
    map.addOverlayObject(0, overlayWay);
  }
}

Place mark

Overlay types that don’t exists in database, should be defined on library startup by OSMScoutQtBuilder::AddCustomPoiType method.

Custom map overlays

For some kind of applications, custom map objects don’t cover all requirements. For example when you want to display hill shades, traffic intensity or some kinds of heatmap, you can create own QML component with MapOverlay as base class and implement void paint(QPainter *painter) method to access full Qt rendering api.

Note: paint method is called in context of UI thread, execute CPU intensive tasks in this thread will cause UI lags!

You can take inspiration in TiledMapOverlay class that provides simple overlay based on online tile services. For example pre-rendered hill shades.

Map {
  id: map
  
  TiledMapOverlay {
      anchors.fill: parent
      view: map.view
      enabled: true
      opacity: 0.6
      // If you intend to use tiles from OpenMapSurfer services in your own applications please contact us.
      // https://korona.geog.uni-heidelberg.de/contact.html
      provider: {
            "id": "ASTER_GDEM",
            "name": "Hillshade",
            "servers": [
              "https://korona.geog.uni-heidelberg.de/tiles/asterh/x=%2&y=%3&z=%1"
            ],
            "maximumZoomLevel": 18,
            "copyright": "© IAT, METI, NASA, NOAA",
          }
  }
}

OSM Scout map with OpenMapSurfer hill shades overlay

QML overlay

There is also possible to use QML Canvas type for overlay. It is easy for proof of concept and may be suitable for some usecases.

Map {
  id: map

  Canvas {
    id: mapCanvas
    anchors.fill: parent

    Connections {
      target: map
      onViewChanged: {
          mapCanvas.requestPaint();
      }
    }

    onPaint: {
      try{
        var ctx = getContext("2d");

        ctx.clearRect(0, 0, mapCanvas.width, mapCanvas.height);

        ctx.lineWidth = 4;
        ctx.strokeStyle = "blue";
        ctx.fillStyle = Qt.rgba(0, 0, 0.8, 0.2);

        var p1 = map.screenPosition(50.4253, 14.5602);
        var p2 = map.screenPosition(50.4099, 14.5816);
        var p3 = map.screenPosition(50.4304, 14.6022);

        ctx.beginPath();
        ctx.moveTo(p1.x, p1.y);
        ctx.lineTo(p2.x, p2.y);
        ctx.lineTo(p3.x, p3.y);
        ctx.closePath();
        ctx.fill();

        ctx.stroke();
      }catch(e){
        console.log("error: "+e);
      }
    }
  }
}

OSM Scout map with QML Canvas overlay

Location info

LocationInfoModel provides description for place on map based on nearest POI object or address point. It it usual Qt model that may be presented by some ListView.

LocationInfoModel {
    id: locationInfoModel
    Component.onCompleted: {
        locationInfoModel.setLocation(50.08923, 14.49837);
    }
}
SilicaListView {
    id: locationInfoView
    model: locationInfoModel
    delegate: Column{
        Label {
            id: entryPoi
            text: poi
            visible: poi != ""
        }
        Label {
            id: entryAddress
            text: address
            visible: address != ""
        }
    }
}

Possible result:

Place description

Detailed description in LocationInfoModel class.

Search place

LocationListModel provides search in location (address) index and “fulltext” index of named objects. It is usual Qt model that may be presented by some ListView.

LocationListModel {
  id: suggestionModel
  Component.onCompleted: {
    suggestionModel.setPattern("Praha");
  }
}
SilicaListView {
  id: suggestionView
  model: suggestionModel
  delegate: Label {
    text: label
  }
}

Detailed description in LocationListModel class.

Search POI

NearPOIModel provide lookup of database objects (not limited to POI) by given coordinates and types. It is usual Qt model that may be presented by some ListView.

NearPOIModel {
  id: poiModel
  lat: 50.0923
  lon: 14.4827
  maxDistance: 1000
  types: ["amenity_restaurant", "amenity_restaurant_building"]
}
SilicaListView {
  id: suggestionView
  model: poiModel
  delegate: Label {
    text: label
  }
}

Detailed description in NearPOIModel class.

Routing

RoutingListModel{
  id: route
  Component.onCompleted: {
    var from=route.locationEntryFromPosition(50.0920, 14.4936);
    var to=route.locationEntryFromPosition(49.1949, 16.6345);
    route.setStartAndTarget(from, to);
  }
  onComputingChanged: {
    if (route.count>0){
        console.log("route length: " + route.length + " m");
        console.log("route commands: " + route.count);
        map.addOverlayObject(0,route.routeWay);
    }
  }
}
Map{
  id: map
}  

Computed route

Detailed description in RoutingListModel class.

Behind the scene

Client Qt library consists from three layers:

Qt API structure

QML components provides just limited set of capabilities now. But you may create your own data models or UI components easily. Just dive into source code and don’t worry to ask us on mailing list.