GPS трекер на Qt, карта и трек

    Решил попрактиковаться в программирование под 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

    Support the author
    Share post

    Comments 11

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

      Вобщем, довольно много вопросов возникает, если хочется сделать действительно удобное приложение.
        0
        Не в фоне. Нагрузку на проц не мерил. Точки записываются в бинарный лог. Лог файл создается через QTemporaryFile.
        Измерения собираю каждые 5 секунд, если координаты валидные и расстояние между точками больше 10 метров, то происходит добавление в трек.
        +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];
                    }
                }
            }
        }
        
          0
          А реализация з оффлайн картами возможна?
            0

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

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

              Разве что создавать тайлы из векторных данных на лету, но лично я воспринимаю это скорее как костыль чем API
                0
                Судя по wiki — уже есть возможность получить вращение и прочие плюшки через Mapbox.
                0
                0
                Спасибо. Ваш пост вышел очень вовремя и оказался очень полезным. А вы не знаете, почему потребовалось делать фокусы, вместо того, что написать что-то вроде activeMapType: Map.CustomMap?
                  0

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


                  activeMapType: MapType{
                     style: Map.CustomMap
                  }

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

                Only users with full accounts can post comments. Log in, please.