Programming Guide

This guide demonstrates how to use the qt-test application components in your own applications to communicate with SitePoint GPS devices.

The examples follow a progressive approach: starting with basic device connection, then adding NTRIP corrections, and finally accessing configuration data.

Basic BLE Connection

The BLEManager class provides the complete Bluetooth Low Energy interface to SitePoint GPS receivers.

Minimal Connection Example

This example shows the minimum code needed to connect to a SitePoint device and receive GPS position updates:

#include "BLEManager.h"
#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    // Create BLE manager instance
    BLEManager *bleManager = new BLEManager(&app);

    // Connect to device discovery signal
    QObject::connect(bleManager, &BLEManager::deviceDiscovered,
        [bleManager](const QString &name, const QString &address) {
            qDebug() << "Discovered:" << name << "at" << address;

            // Auto-connect to first SitePoint device
            if (name.contains("SitePoint")) {
                bleManager->connectToDevice(address);
            }
        });

    // Connect to connection status signal
    QObject::connect(bleManager, &BLEManager::deviceConnected, []() {
        qDebug() << "Connected successfully";
    });

    // Connect to position data signal
    QObject::connect(bleManager, &BLEManager::llaDataChanged,
        [bleManager]() {
            SqspLla_t lla = bleManager->getLlaData();
            qDebug() << "Position:" << lla.latitude << ","
                     << lla.longitude << "Alt:" << lla.hMSL << "m";
        });

    // Start scanning
    bleManager->startScan();

    return app.exec();
}

Output:

Discovered: "SitePoint-1234" at "12:34:56:78:9A:BC"
Connected successfully
Position: 37.7749 , -122.4194 Alt: 15.2 m
Position: 37.7749 , -122.4194 Alt: 15.3 m

Key Concepts

Signal-Driven Architecture:

The BLEManager uses Qt signals to notify your application of events. Connect to the signals you need and ignore the rest.

Change Detection:

Position data arrives at 8-10 Hz, but llaDataChanged() only fires when the data actually changes (see Theory of Operation for details).

Asynchronous Connection:

connectToDevice() is asynchronous. Use deviceConnected() signal to know when connection is ready.

Adding NTRIP Corrections

For RTK positioning, the device needs correction data from an NTRIP caster. The NTRIPManager class handles the network connection, and BLEManager transmits the corrections to the device.

Complete NTRIP Example

#include "BLEManager.h"
#include "NTRIPManager.h"
#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    BLEManager *bleManager = new BLEManager(&app);
    NTRIPManager *ntripManager = new NTRIPManager(&app);

    // Configure NTRIP connection
    QString host = "rtk.example.com";
    quint16 port = 2101;
    QString mountpoint = "RTCM3";
    QString username = "user";
    QString password = "pass";

    // Connect NTRIP data to BLE transmission
    QObject::connect(ntripManager, &NTRIPManager::rtcmDataReceived,
        [bleManager](const QByteArray &rtcmData) {
            bleManager->queueRTCMMessage(rtcmData);
        });

    // Monitor NTRIP connection status
    QObject::connect(ntripManager, &NTRIPManager::connectionStatusChanged,
        [](bool connected) {
            qDebug() << "NTRIP" << (connected ? "connected" : "disconnected");
        });

    // Monitor device status for correction age
    QObject::connect(bleManager, &BLEManager::statusDataChanged,
        [bleManager]() {
            SqspStatus_t status = bleManager->getStatusData();
            qDebug() << "Satellites:" << status.numSatellites
                     << "Correction age:" << status.correctionAge << "ms";

            // Check if RTK corrections are active
            if (status.aidingBins & (1 << 4)) {
                qDebug() << "RTK corrections active";
            }
        });

    // Start BLE scan
    bleManager->startScan();

    // Auto-connect to NTRIP when device is connected
    QObject::connect(bleManager, &BLEManager::deviceConnected,
        [ntripManager, host, port, mountpoint, username, password]() {
            ntripManager->connectToNtrip(host, port, mountpoint,
                                         username, password);
        });

    return app.exec();
}

Understanding RTCM Transmission

RTCM messages are queued and transmitted automatically by the BLEManager:

  1. NTRIP caster sends RTCM v3 messages (typically 1 Hz)

  2. NTRIPManager receives and emits rtcmDataReceived() signal

  3. Your code calls queueRTCMMessage() to add message to transmission queue

  4. BLEManager’s FSM paces transmission to match BLE connection interval

  5. Messages are fragmented if they exceed MTU size

  6. GPS device receives corrections and improves position accuracy

Important: The RTCM queue has a capacity of 50 messages. For typical NTRIP streams, this provides ample buffering. If messages are dropped, reduce the correction data rate at the caster.

Device Configuration and Modes

The GPS device can operate in several modes, each optimized for different use cases.

Changing Device Mode

#include "BLEManager.h"
#include "sqsp.h"  // For DEVICE_MODE_* constants

// Set device to rover mode with NTRIP corrections
bleManager->sendModeChangeCommand(DEVICE_MODE_ROVER_NTRIP);

// Set device to fixed base station mode
bleManager->sendModeChangeCommand(DEVICE_MODE_FIXED_BASE);

Available Modes:

  • DEVICE_MODE_ROVER - Standard rover, no corrections, ~2m accuracy

  • DEVICE_MODE_ROVER_NTRIP - Rover with NTRIP corrections via BLE, ~2cm accuracy

  • DEVICE_MODE_ROVER_NEAREST - Rover with Tripod network corrections, ~2cm accuracy

  • DEVICE_MODE_FIXED_BASE - Fixed base station, broadcasts corrections

  • DEVICE_MODE_FIXED_BASE_BROADCAST - Fixed base with wider broadcast range

See Device Configuration for detailed mode descriptions and use cases.

Accessing Configuration Data

The device configuration includes base station position and survey duration:

QObject::connect(bleManager, &BLEManager::configDataChanged,
    [bleManager]() {
        SqspLbConfig_t config = bleManager->getConfigData();

        qDebug() << "Base station position:";
        qDebug() << "  Latitude:" << config.latitude;
        qDebug() << "  Longitude:" << config.longitude;
        qDebug() << "  Height MSL:" << config.hMSL << "m";
        qDebug() << "  Survey duration:" << config.duration << "seconds";
    });

Working with Position Data

The SqspLla_t structure contains comprehensive position and accuracy information.

Accessing Position Fields

SqspLla_t lla = bleManager->getLlaData();

// Position in degrees
double latitude = lla.latitude;   // -90 to +90
double longitude = lla.longitude; // -180 to +180

// Height measurements in meters
double heightWGS84 = lla.height;  // Height above WGS84 ellipsoid
double heightMSL = lla.hMSL;      // Height above mean sea level

// Accuracy estimates in meters
float horizontalAccuracy = lla.hAcc;  // Horizontal accuracy
float verticalAccuracy = lla.vAcc;    // Vertical accuracy

// Solution quality indicator
uint8_t quality = lla.solutionType;

Solution Type Values:

  • 0 - No fix

  • 1 - Autonomous GPS (no corrections)

  • 2 - DGPS / SBAS

  • 4 - RTK Fixed (cm-level accuracy)

  • 5 - RTK Float (dm-level accuracy)

High-Performance Data Access

For applications that need high-frequency position access (e.g., real-time mapping at 8-10 Hz), use direct extern access to avoid function call overhead:

#include "sqsp.h"

// Declare extern global (defined in BLEManager.cpp)
extern SqspLla_t myLla;

// Direct access - no function call overhead
double lat = myLla.latitude;
double lon = myLla.longitude;
float acc = myLla.hAcc;

Performance Comparison:

  • Function call: bleManager->getLlaData() - Returns copy, ~100ns overhead

  • Direct access: myLla.latitude - Direct memory access, ~5ns

For 8-10 Hz updates in performance-critical code (rendering, logging), use direct access. For occasional access (UI updates, user queries), use the function call for better encapsulation.

Working with Status Data

The SqspStatus_t structure provides real-time device status information.

Monitoring Satellite Tracking

SqspStatus_t status = bleManager->getStatusData();

qDebug() << "Satellites tracked:" << status.numSatellites;
qDebug() << "HDOP:" << status.hdop;  // Horizontal dilution of precision
qDebug() << "VDOP:" << status.vdop;  // Vertical dilution of precision

HDOP/VDOP Interpretation:

  • < 2.0 - Excellent geometry

  • 2.0 - 5.0 - Good geometry

  • 5.0 - 10.0 - Moderate geometry

  • > 10.0 - Poor geometry

Checking Correction Status

SqspStatus_t status = bleManager->getStatusData();

// Correction age in milliseconds
uint32_t age = status.correctionAge;

if (age < 30000) {
    qDebug() << "Corrections fresh:" << age << "ms";
} else {
    qDebug() << "Corrections stale:" << age << "ms";
}

// Check aiding data availability
uint32_t aiding = status.aidingBins;

if (aiding & (1 << 0)) qDebug() << "Ephemeris available";
if (aiding & (1 << 1)) qDebug() << "Almanac available";
if (aiding & (1 << 2)) qDebug() << "UTC model available";
if (aiding & (1 << 3)) qDebug() << "Ionosphere model available";
if (aiding & (1 << 4)) qDebug() << "RTCM corrections active";

Correction Age Guidelines:

  • < 10 seconds - Optimal RTK performance

  • 10-30 seconds - Good RTK performance

  • > 30 seconds - Degraded RTK performance

  • > 60 seconds - RTK solution may drop to float

Error Handling

Handling Connection Errors

QObject::connect(bleManager, &BLEManager::errorOccurred,
    [](const QString &errorMessage) {
        qCritical() << "BLE Error:" << errorMessage;

        // Common errors:
        // - "Bluetooth adapter not available"
        // - "Device not found"
        // - "Connection timeout"
        // - "Service discovery failed"
    });

QObject::connect(bleManager, &BLEManager::deviceDisconnected,
    [bleManager]() {
        qWarning() << "Device disconnected unexpectedly";

        // Attempt reconnection after delay
        QTimer::singleShot(5000, bleManager, &BLEManager::reconnectToLastDevice);
    });

Handling NTRIP Errors

QObject::connect(ntripManager, &NTRIPManager::errorOccurred,
    [](const QString &errorMessage) {
        qCritical() << "NTRIP Error:" << errorMessage;

        // Common errors:
        // - "Network unreachable"
        // - "Authentication failed"
        // - "Invalid mountpoint"
        // - "Connection timeout"
    });

Complete Application Example

This complete example demonstrates a full RTK GPS application with error handling, status monitoring, and data logging:

#include <QCoreApplication>
#include <QTimer>
#include <QFile>
#include <QTextStream>
#include <QDebug>
#include "BLEManager.h"
#include "NTRIPManager.h"

class RTKLogger : public QObject
{
    Q_OBJECT

public:
    RTKLogger(QObject *parent = nullptr) : QObject(parent)
    {
        bleManager = new BLEManager(this);
        ntripManager = new NTRIPManager(this);

        setupConnections();
        openLogFile();
    }

private slots:
    void onDeviceDiscovered(const QString &name, const QString &address)
    {
        if (name.contains("SitePoint") && targetAddress.isEmpty()) {
            qDebug() << "Found SitePoint device:" << address;
            targetAddress = address;
            bleManager->connectToDevice(address);
        }
    }

    void onDeviceConnected()
    {
        qDebug() << "Device connected, starting NTRIP...";
        ntripManager->connectToNtrip("rtk.example.com", 2101, "RTCM3",
                                     "user", "pass");
    }

    void onLlaDataChanged()
    {
        SqspLla_t lla = bleManager->getLlaData();
        SqspStatus_t status = bleManager->getStatusData();

        // Log position with timestamp
        QString logLine = QString("%1,%2,%3,%4,%5,%6\n")
            .arg(QDateTime::currentDateTime().toString(Qt::ISODate))
            .arg(lla.latitude, 0, 'f', 8)
            .arg(lla.longitude, 0, 'f', 8)
            .arg(lla.hMSL, 0, 'f', 3)
            .arg(lla.hAcc, 0, 'f', 3)
            .arg(status.numSatellites);

        if (logFile.isOpen()) {
            QTextStream stream(&logFile);
            stream << logLine;
            stream.flush();
        }

        qDebug() << "Logged position:" << lla.latitude << ","
                 << lla.longitude << "Sats:" << status.numSatellites;
    }

    void onRtcmDataReceived(const QByteArray &rtcmData)
    {
        bleManager->queueRTCMMessage(rtcmData);
        rtcmMessageCount++;

        if (rtcmMessageCount % 10 == 0) {
            qDebug() << "RTCM messages transmitted:" << rtcmMessageCount;
        }
    }

private:
    void setupConnections()
    {
        connect(bleManager, &BLEManager::deviceDiscovered,
                this, &RTKLogger::onDeviceDiscovered);
        connect(bleManager, &BLEManager::deviceConnected,
                this, &RTKLogger::onDeviceConnected);
        connect(bleManager, &BLEManager::llaDataChanged,
                this, &RTKLogger::onLlaDataChanged);
        connect(ntripManager, &NTRIPManager::rtcmDataReceived,
                this, &RTKLogger::onRtcmDataReceived);

        connect(bleManager, &BLEManager::errorOccurred,
                [](const QString &error) {
                    qCritical() << "BLE Error:" << error;
                });
        connect(ntripManager, &NTRIPManager::errorOccurred,
                [](const QString &error) {
                    qCritical() << "NTRIP Error:" << error;
                });
    }

    void openLogFile()
    {
        QString filename = QString("rtk_log_%1.csv")
            .arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss"));

        logFile.setFileName(filename);
        if (logFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
            QTextStream stream(&logFile);
            stream << "Timestamp,Latitude,Longitude,Height(m),Accuracy(m),Satellites\n";
            qDebug() << "Logging to:" << filename;
        }
    }

    BLEManager *bleManager;
    NTRIPManager *ntripManager;
    QFile logFile;
    QString targetAddress;
    int rtcmMessageCount = 0;
};

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    RTKLogger logger;
    logger.bleManager->startScan();

    return app.exec();
}

#include "main.moc"

Using DataManager for Formatted Display

The DataManager provides pre-formatted GPS data strings optimized for QML display. Instead of formatting coordinates in QML (which would happen every frame), DataManager formats once in C++ and caches the results.

Accessing Formatted Data in C++

#include "DataManager.h"
#include "BLEManager.h"
#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    BLEManager *bleManager = new BLEManager(&app);
    DataManager *dataManager = new DataManager(&app);

    // Connect DataManager to BLEManager signals
    QObject::connect(bleManager, &BLEManager::llaDataChanged,
                     dataManager, &DataManager::onLlaDataChanged);
    QObject::connect(bleManager, &BLEManager::statusDataChanged,
                     dataManager, &DataManager::onStatusDataChanged);
    QObject::connect(bleManager, &BLEManager::configDataChanged,
                     dataManager, &DataManager::onConfigDataChanged);

    // Access formatted data through QVariantMap
    QObject::connect(dataManager, &DataManager::dataChanged,
        [dataManager]() {
            QVariantMap lla = dataManager->llaData();

            // All strings are pre-formatted with proper precision
            qDebug() << "Latitude:" << lla["latitude"].toString();   // "43.641130095°"
            qDebug() << "Longitude:" << lla["longitude"].toString(); // "-72.253870594°"
            qDebug() << "Height:" << lla["height"].toString();       // "123.4567m"
            qDebug() << "H Accuracy:" << lla["hAcc"].toString();     // "0.0234m"
        });

    // Access status data
    QObject::connect(dataManager, &DataManager::statusDataChanged,
        [dataManager]() {
            QVariantMap status = dataManager->statusData();

            qDebug() << "Satellites:" << status["numSV"].toString();     // "12 satellites"
            qDebug() << "Solution:" << status["solType"].toString();     // "RTK Fixed"
            qDebug() << "Battery:" << status["battery"].toString();      // "87%"
            qDebug() << "GPS Fix OK:" << status["gpsFixOk"].toString();  // "Yes"
        });

    // Start BLE connection
    bleManager->startScan();

    return app.exec();
}

Understanding Batched Properties

Why Batched Properties Are Faster:

Traditional approach (slow):

// Would require 15+ separate Q_PROPERTY declarations
Q_PROPERTY(QString latitude READ latitude NOTIFY latitudeChanged)
Q_PROPERTY(QString longitude READ longitude NOTIFY longitudeChanged)
Q_PROPERTY(QString height READ height NOTIFY heightChanged)
// ... 12 more properties ...

// Results in 15+ signal emissions per GPS update
emit latitudeChanged();
emit longitudeChanged();
emit heightChanged();
// ... 12 more signals ...

Batched approach (fast):

// Single Q_PROPERTY with all related data
Q_PROPERTY(QVariantMap llaData READ llaData NOTIFY dataChanged)

// Results in 1 signal emission per GPS update
emit dataChanged();

Performance Impact at 8-10 Hz:

  • Traditional: 120-150 signal emissions/second (15 signals × 8-10 Hz)

  • Batched: 8-10 signal emissions/second (1 signal × 8-10 Hz)

  • 90% reduction in Qt signal routing overhead

Changing Device Mode

Use DataManager’s setDeviceMode() method to change operational modes:

// Change to rover with NTRIP corrections
dataManager->setDeviceMode("ROVER NTRIP");

// Change to fixed base station
dataManager->setDeviceMode("FIXED BASE");

// Change to fixed base with broadcast
dataManager->setDeviceMode("FIXED BASE BROADCAST");

Supported Mode Strings:

  • "ROVER" - Standard rover, no corrections

  • "ROVER NTRIP" - Rover with NTRIP corrections via BLE

  • "ROVER NEAREST" - Rover with Tripod network corrections

  • "FIXED BASE" - Fixed base station

  • "FIXED BASE BROADCAST" - Fixed base with broadcast

Real-Time Map Display with MapManager

The MapManager provides the fastest path to GPS coordinates for real-time map rendering. It’s designed specifically for QtLocation’s Map component.

Basic Map Integration

#include "MapManager.h"
#include "BLEManager.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    // Create managers
    BLEManager *bleManager = new BLEManager(&app);
    MapManager *mapManager = new MapManager(&app);

    // Connect MapManager to BLEManager
    QObject::connect(bleManager, &BLEManager::llaDataChanged,
                     mapManager, &MapManager::onLlaDataChanged);

    // Register for QML access
    engine.rootContext()->setContextProperty("bleManager", bleManager);
    engine.rootContext()->setContextProperty("mapManager", mapManager);

    // Load QML
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

Corresponding QML (MapWindow.qml):

import QtQuick
import QtLocation
import QtPositioning

Window {
    width: 800
    height: 600
    title: mapManager.formattedTitle  // Live title with coordinates

    Map {
        anchors.fill: parent
        plugin: Plugin { name: "osm" }  // OpenStreetMap

        // Live GPS position binding - updates at 8-10 Hz
        center: QtPositioning.coordinate(mapManager.lat, mapManager.lon)
        zoomLevel: 16

        // Device position marker
        MapCircle {
            center: QtPositioning.coordinate(mapManager.lat, mapManager.lon)
            radius: 5  // 5 meters
            color: "red"
            border.color: "darkred"
            border.width: 2
        }
    }

    // Center on GPS button
    Rectangle {
        anchors.top: parent.top
        anchors.right: parent.right
        anchors.margins: 10
        width: 120
        height: 40

        Text {
            anchors.centerIn: parent
            text: "Center on GPS"
        }

        MouseArea {
            anchors.fill: parent
            onClicked: {
                map.center = QtPositioning.coordinate(
                    mapManager.lat, mapManager.lon
                )
            }
        }
    }
}

Understanding MapManager Performance

MapManager is optimized for zero-overhead coordinate access:

// MapManager.cpp - Direct extern access
double MapManager::lat() const {
    return myLla.lat;  // ~5ns, no function call overhead
}

Why This Matters:

At 8-10 Hz update rate with 60 FPS rendering:

  • QML Map re-reads coordinates 60 times per second

  • Each coordinate access: ~5ns

  • Total overhead: ~300ns per frame

  • Map rendering: ~16ms per frame

Coordinate access overhead is 0.002% of total frame time, ensuring smooth real-time map updates.

Contrast with DataManager:

DataManager formats strings for display (expensive operation), so it caches results. MapManager returns raw doubles (cheap operation), so no caching needed.

QML User Interface Components

The application provides four main QML components that integrate with the Manager classes.

Main.qml - Application Structure

Purpose: Main application window with BLE device list and NTRIP client.

Key Features:

  • Device discovery and connection list

  • NTRIP connection configuration (NTRIPClient.qml component)

  • Window management (shows DeviceDataWindow and MapWindow)

  • Device connection state management

Manager Integration:

// Registered context properties in main.cpp
property var bleManager: bleManager
property var ntripManager: ntripManager

// Device discovery connection
Connections {
    target: bleManager
    function onDeviceDiscovered(deviceName, deviceAddress) {
        deviceModel.append({
            deviceName: deviceName,
            deviceAddress: deviceAddress,
            connected: false
        })
    }
}

// Connect to selected device
MouseArea {
    onClicked: {
        bleManager.connectToDevice(model.deviceAddress)
    }
}

DeviceDataWindow.qml - Live Data Display

Purpose: Real-time display of GPS data with configuration editing.

Key Features:

  • Three data sections: LLA, Status, Config

  • Batched property binding for performance

  • Device mode selection (ComboBox)

  • Correction source selection (RadioButtons)

  • Configuration editing with validation

Manager Integration - Batched Properties:

// Batched property bindings - single signal per category
property var lla: dataManager.llaData
property var status: dataManager.statusData
property var config: dataManager.configData

// Display formatted strings from DataManager
GridLayout {
    Text { text: "Latitude" }
    Text { text: lla.latitude }  // "43.641130095°"

    Text { text: "Longitude" }
    Text { text: lla.longitude }  // "-72.253870594°"

    Text { text: "Height" }
    Text { text: lla.height }  // "123.4567m"
}

Device Mode Control:

ComboBox {
    model: ["ROVER", "FIXED BASE", "FIXED BASE BROADCAST"]
    currentIndex: {
        switch(dataManager.deviceStatus.deviceMode) {
            case "ROVER": return 0
            case "FIXED BASE": return 1
            case "FIXED BASE BROADCAST": return 2
            default: return 0
        }
    }
    onActivated: {
        dataManager.setDeviceMode(currentText)
    }
}

Performance Note: Using batched properties (lla.latitude) instead of individual properties reduces QML property binding overhead by ~90%.

NTRIPClient.qml - NTRIP Configuration

Purpose: Collapsible NTRIP connection configuration panel.

Key Features:

  • Server configuration (host, port, mountpoint, credentials)

  • Bidirectional property binding with ntripManager

  • Connection status display with color coding

  • Collapsible UI (Show/Hide button)

Manager Integration - Bidirectional Binding:

TextField {
    id: hostField
    text: ntripManager.serverHost  // QML ← C++
    onTextChanged: {
        if (text !== ntripManager.serverHost)
            ntripManager.serverHost = text  // QML → C++
    }
}

Button {
    text: ntripManager.connected ? "Disconnect" : "Connect"
    onClicked: {
        if (ntripManager.connected)
            ntripManager.disconnectFromServer()
        else
            ntripManager.connectToServer()
    }
}

Text {
    text: ntripManager.connectionStatus
    color: ntripManager.connected ? "green" :
           ntripManager.connectionStatus.includes("Error") ? "red" : "black"
}

Collapsible Pattern:

Rectangle {
    property bool expanded: true

    states: [
        State {
            name: "collapsed"
            when: !expanded
            PropertyChanges { target: ntripClient; height: 50 }
        },
        State {
            name: "expanded"
            when: expanded
            PropertyChanges { target: ntripClient; height: 350 }
        }
    ]

    Behavior on height {
        NumberAnimation { duration: 300; easing.type: Easing.OutCubic }
    }
}

MapWindow.qml - Real-Time GPS Map

Purpose: OpenStreetMap display with live GPS tracking.

Key Features:

  • Real-time map center binding to GPS coordinates

  • Device position marker (red circle)

  • Interactive controls (pinch, drag, zoom)

  • Live title with coordinates and update counter

  • “Center on GPS” button

Manager Integration - Direct Coordinate Binding:

Window {
    // Live window title
    title: mapManager.formattedTitle
    // "43.641130095°, -72.253870594°, 123.4567m - Center Updates: 47"

    Map {
        // Live center binding - updates at 8-10 Hz
        center: QtPositioning.coordinate(mapManager.lat, mapManager.lon)

        // Device marker - also updates at 8-10 Hz
        MapCircle {
            center: QtPositioning.coordinate(mapManager.lat, mapManager.lon)
            radius: 5
            color: "red"
        }
    }
}

Performance: Direct coordinate binding with no intermediate formatting ensures smooth map updates. The Map component automatically throttles rendering to 60 FPS, while coordinate reads happen at the full 8-10 Hz rate.

Interactive Controls (from Qt examples):

// Pinch to zoom
PinchHandler {
    onScaleChanged: (delta) => {
        map.zoomLevel += Math.log2(delta)
    }
}

// Drag to pan
DragHandler {
    onTranslationChanged: (delta) => map.pan(-delta.x, -delta.y)
}

// Mouse wheel zoom
WheelHandler {
    property: "zoomLevel"
}

Next Steps