Решил попрактиковаться в программирование под Android на Qt. В качестве темы выбрал GPS трекер.
Набор функций этого трекера:


  • снимать измерения с GPS приемника;
  • экспортировать трек в GPX (GPS eXchange Format);
  • выводить трек на карту;
  • выводить время в пути, длину пути, среднюю скорость.

Под катом будет приведен пример работы с картой в QtQuick.



Plugin, PluginParameter и Map


Базовые типы находятся в модуле Qt Location. Qt Location в качестве бакенда может использовать:



Работа с конкретным поставщиком карт помещена в плагины(Plugin), которые настраиваются через параметры(PluginParameter).


Минимальный пример:


Plugin {
  id: plugin
  preferred: ["here", "osm"]
  required: Plugin.AnyMappingFeatures | Plugin.AnyGeocodingFeatures
}

Map {
    plugin: plugin

    width: ...
    height:...

}

Поначалу использовал просто Open Street Map:


Plugin {
     id: plugin
     name: "osm"
}

По умолчанию поставщиком OSM карт является MapQuest, который с недавних пор ввели ключ разработчика. Тут встал вопрос о переходе на что-то другое.


Open Street Map Plugin


В документации перечислены поддержка:


  • MapQuest;
  • ThunderForest;
  • OpenStreetMap и сообщество.

Для того, что бы воспользоваться последним пунктом нужно выполнить два условия:


Задать параметр osm.mapping.host:


Plugin {
     id: mapPlugin
     name: "osm"
     PluginParameter {
         name: "osm.mapping.host";
         value: "http://a.tile.openstreetmap.org/"
     }
}

Карте указать использовать тип карт MapType.CustomMap.
Для любителей магии:


Map {
    id: map
    plugin: mapPlugin
    activeMapType: map.supportedMapTypes[7]
}

Что бы не надеяться на позицию элемента в списке supportedMapTypes, можно сделать так:


Map {
    id: map

    plugin: mapPlugin
    zoomLevel: 16

    width: item.width
    height:item.height

    property MapPolyline track
}

Timer {
    interval: 100; running: true; repeat: false
    onTriggered: {
        for(var i = 0;
            i < map.supportedMapTypes.length;
            ++i){
            if(map.supportedMapTypes[i].style
                    === MapType.CustomMap){
                map.activeMapType = map.supportedMapTypes[i];
            }
        }
    }
}

Трек


Для рисования трека взял элемент MapPolyline, при этом создаю его динамически, для очищения карты:


function start() {
    mapItem.clearMapItems();
    mapItem.track = Qt.createQmlObject('import QtLocation 5.6; MapPolyline {}', item);
    mapItem.track.line.width = 6;
    mapItem.track.line.color = 'red';
    mapItem.addMapItem(mapItem.track);

}

function appendCoordinate(position){
    mapItem.center = position;
    mapItem.track.addCoordinate(position)
}

Map {
    id: mapItem

    plugin: mapPlugin
    zoomLevel: 16

    width: item.width
    height:item.height

    property MapPolyline track
}

При старте очищаю карту, создаю трек и помещаю на карту. При добавлении новой координаты центр карты перемещается в указанную позицию и удлиняется трек.


Результат:



Код доступен на GitHub

Поделиться с друзьями
-->

Комментарии (11)


  1. ittakir
    21.07.2016 11:29
    +1

    Трек записывается в фоне?
    Какая при этом нагрузка на проц?
    Где хранятся точки, и что будет, если приложение будет убито системой?
    Как часто пишем на диск?

    Вобщем, довольно много вопросов возникает, если хочется сделать действительно удобное приложение.


    1. RPG18
      21.07.2016 11:33

      Не в фоне. Нагрузку на проц не мерил. Точки записываются в бинарный лог. Лог файл создается через QTemporaryFile.
      Измерения собираю каждые 5 секунд, если координаты валидные и расстояние между точками больше 10 метров, то происходит добавление в трек.


  1. Zifix
    21.07.2016 15:30
    +1

    Статья полезная, но стиль кода местами старается собрать все возможные способы ухудшения читабельности:

    Timer {
        interval: 100; running: true; repeat: false
        onTriggered: {
            for(var i = 0;
                i < map.supportedMapTypes.length;
                ++i){
                if(map.supportedMapTypes[i].style
                        === MapType.CustomMap){
                    map.activeMapType = map.supportedMapTypes[i];
                }
            }
        }
    } 
    
    vs
    
    Timer {
        interval: 100
        running: true
    
        onTriggered: {
            var n = map.supportedMapTypes.length;
    
            for (var i = 0; i < n; ++i) {
                if (map.supportedMapTypes[i].style === MapType.CustomMap) {
                    map.activeMapType = map.supportedMapTypes[i];
                }
            }
        }
    }
    


  1. vasylll95
    21.07.2016 15:34

    А реализация з оффлайн картами возможна?


    1. RPG18
      21.07.2016 15:35

      По этой теме есть отдельная статья Кратко от том как сделать свой Qt geoservice plugin


      1. vasylll95
        21.07.2016 15:45

        Спасибо)


    1. Antervis
      22.07.2016 05:46

      скорее нет чем да. Qt карты поддерживают только тайлы, векторную реализацию проще с нуля сделать, чем через плагины Qt. В Qml Map нет даже поддержки вращения…

      Разве что создавать тайлы из векторных данных на лету, но лично я воспринимаю это скорее как костыль чем API


      1. Zifix
        22.07.2016 07:34

        Судя по wiki — уже есть возможность получить вращение и прочие плюшки через Mapbox.


    1. Zifix
      22.07.2016 07:43

  1. sundaywizard
    22.07.2016 21:12

    Спасибо. Ваш пост вышел очень вовремя и оказался очень полезным. А вы не знаете, почему потребовалось делать фокусы, вместо того, что написать что-то вроде activeMapType: Map.CustomMap?


    1. RPG18
      22.07.2016 21:15

      Пробовал по всякому, да же так:


      activeMapType: MapType{
         style: Map.CustomMap
      }

      Но что-то не получилось.