Enroute Flight Navigation
A navigation app for VFR pilots
PositionProvider.h
1/***************************************************************************
2 * Copyright (C) 2019-2025 by Stefan Kebekus *
3 * stefan.kebekus@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 3 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21#pragma once
22
23#include <QBindable>
24#include <QElapsedTimer>
25#include <QQmlEngine>
26#include <QSet>
27
28#include "GlobalObject.h"
29#include "positioning/PositionInfoSource_Satellite.h"
30
31
32namespace Positioning {
33
49
50class PositionProvider : public QObject
51{
52 Q_OBJECT
53 QML_ELEMENT
54 QML_SINGLETON
55
56
57public:
62 explicit PositionProvider(QObject* parent = nullptr);
63
64 // No default constructor, important for QML singleton
65 explicit PositionProvider() = delete;
66
69
70
71 // factory function for QML singleton
72 static Positioning::PositionProvider* create(QQmlEngine* /*unused*/, QJSEngine* /*unused*/)
73 {
75 }
76
77
78 //
79 // PROPERTIES
80 //
81
88
89
96 Q_PROPERTY(QString icon READ icon BINDABLE bindableIcon)
97
106
114 Q_PROPERTY(QGeoCoordinate mapCenter READ mapCenter WRITE setMapCenter BINDABLE bindableMapCenter NOTIFY mapCenterChanged)
115
122 Q_PROPERTY(Units::Angle lastValidTT READ lastValidTT BINDABLE bindableLastValidTT)
123
131 Q_PROPERTY(Positioning::PositionInfo positionInfo READ positionInfo BINDABLE bindablePositionInfo NOTIFY positionInfoChanged)
132
142
160 Q_PROPERTY(bool pressureAltitudeImplausible READ pressureAltitudeImplausible BINDABLE bindablePressureAltitudeImplausible NOTIFY pressureAltitudeImplausibleChanged)
161
169
176 Q_PROPERTY(QString statusString READ statusString BINDABLE bindableStatusString)
177
178
179 //
180 // Getter Methods
181 //
182
187 [[nodiscard]] QGeoCoordinate approximateLastValidCoordinate() const {return m_approximateLastValidCoordinate.value();}
188
193 [[nodiscard]] QBindable<QGeoCoordinate> bindableApproximateLastValidCoordinate() const {return &m_approximateLastValidCoordinate;}
194
199 [[nodiscard]] QString icon() const {return m_icon.value();}
200
205 [[nodiscard]] QBindable<QString> bindableIcon() const {return &m_icon;}
206
211 [[nodiscard]] static QGeoCoordinate lastValidCoordinate();
212
217 [[nodiscard]] QBindable<QGeoCoordinate> bindableLastValidCoordinate() {return &m_lastValidCoordinate;}
218
223 [[nodiscard]] static Units::Angle lastValidTT();
224
229 [[nodiscard]] QBindable<Units::Angle> bindableLastValidTT() {return &m_lastValidTT;}
230
235 [[nodiscard]] QGeoCoordinate mapCenter() const {return m_mapCenter.value();}
236
241 [[nodiscard]] QBindable<QGeoCoordinate> bindableMapCenter() {return &m_mapCenter;}
242
247 void setMapCenter(const QGeoCoordinate& newMapCenter) {m_mapCenter = newMapCenter;}
248
253 [[nodiscard]] Positioning::PositionInfo positionInfo() const {return m_positionInfo.value();}
254
259 [[nodiscard]] QBindable<Positioning::PositionInfo> bindablePositionInfo() const {return &m_positionInfo;}
260
265 [[nodiscard]] Units::Distance pressureAltitude() const {return m_pressureAltitude.value();}
266
271 [[nodiscard]] QBindable<Units::Distance> bindablePressureAltitude() const {return &m_pressureAltitude;}
272
277 [[nodiscard]] bool pressureAltitudeImplausible() const {return m_pressureAltitudeImplausible.value();}
278
283 [[nodiscard]] QBindable<bool> bindablePressureAltitudeImplausible() const {return &m_pressureAltitudeImplausible;}
284
289 [[nodiscard]] bool receivingPositionInfo() const {return m_receivingPositionInfo.value();}
290
295 [[nodiscard]] QBindable<bool> bindableReceivingPositionInfo() {return &m_receivingPositionInfo;}
296
301 [[nodiscard]] QString statusString() const {return m_statusString.value();}
302
307 [[nodiscard]] QBindable<QString> bindableStatusString() const {return &m_statusString;}
308
309
310 //
311 // Constants
312 //
313
321
322
323 //
324 // Methods
325 //
326
333 Q_INVOKABLE void startUpdates() { satelliteSource.startUpdates(); }
334
345 Q_INVOKABLE void setBackgroundUpdates(const QString& caller, bool enable);
346
347signals:
348 // Notifier signal
349 void approximateLastValidCoordinateChanged();
350
351 // Notifier signal
352 void mapCenterChanged();
353
354 // Notifier signal
355 void positionInfoChanged(const Positioning::PositionInfo& info);
356
357 // Notifier signal
358 void pressureAltitudeImplausibleChanged();
359
360 // Notifier signal
361 void receivingPositionInfoChanged(bool);
362
363private slots:
364 // Intializations that are moved out of the constructor, in order to avoid
365 // nested uses of constructors in Global.
366 void deferredInitialization();
367
368 // Saves last valid position and track
369 void savePositionAndTrack();
370
371private:
372 Q_DISABLE_COPY_MOVE(PositionProvider)
373
374#ifdef Q_OS_IOS
375 QSet<QString> m_backgroundUpdateCallers;
376 void updateBackgroundLocation();
377#endif
378
379 // Computation method for property with the same name
380 QString computeStatusString();
381
382 // Aircraft is considered flying if speed is at least this high
383 static constexpr double minFlightSpeedInKT = 30.0;
384 // Hysteresis for flight speed
385 static constexpr double flightSpeedHysteresis = 5.0;
386
387 // Coordinates of EDTF airfield
388 static constexpr double EDTF_lat = 48.022653;
389 static constexpr double EDTF_lon = 7.832583;
390 static constexpr double EDTF_ele = 244;
391
392 PositionInfoSource_Satellite satelliteSource;
393
394 // The incoming position info is set by a binding that monitors
395 // the satelliteSource and the TrafficDataSource
396 QProperty<Positioning::PositionInfo> m_incomingPositionInfo;
397 Positioning::PositionInfo computeIncomingPositionInfo();
398
399 // This method updates m_approximateLastValidCoordinate, m_lastValidCoordinate and m_lastValidTT
400 // whenever m_incomingPositionInfo changes.
401 void onIncomingPositionInfoUpdated();
402 QPropertyNotifier m_incomingPositionInfoNotifier;
403
404 Q_OBJECT_BINDABLE_PROPERTY(Positioning::PositionProvider, Positioning::PositionInfo, m_positionInfo, &Positioning::PositionProvider::positionInfoChanged);
405 Q_OBJECT_BINDABLE_PROPERTY(Positioning::PositionProvider, QGeoCoordinate, m_approximateLastValidCoordinate, &Positioning::PositionProvider::approximateLastValidCoordinateChanged);
406 QProperty<QGeoCoordinate> m_lastValidCoordinate {QGeoCoordinate(EDTF_lat, EDTF_lon, EDTF_ele)};
407 QProperty<Units::Angle> m_lastValidTT;
408 Q_OBJECT_BINDABLE_PROPERTY(Positioning::PositionProvider, QGeoCoordinate, m_mapCenter, &Positioning::PositionProvider::mapCenterChanged);
409
410 Q_OBJECT_BINDABLE_PROPERTY(Positioning::PositionProvider, bool, m_receivingPositionInfo, &Positioning::PositionProvider::receivingPositionInfoChanged);
411 QProperty<QString> m_icon;
412 QProperty<QString> m_statusString;
413
414 QProperty<Units::Distance> m_pressureAltitude;
415 static Units::Distance computePressureAltitude();
416
417 // This method updates m_pressureAltitudeImplausible. It is called whenever
418 // m_positionInfo or m_pressureAltitude change.
419 void updatePressureAltitudeImplausible();
420 QPropertyNotifier m_pressureAltitudeNotifier;
421
422 // Hysteresis for the pressure altitude plausibility check: once the warning
423 // is active, it clears only when the difference drops below this value.
424 static constexpr Units::Distance pressureAltitudePlausibleThreshold = Units::Distance::fromFT(3000.0);
425 // The difference must persist for at least this long before the warning is raised.
426 static constexpr qint64 pressureAltitudeImplausibleDwellTime_ms = 30LL*1000;
427 // Measures for how long pressure altitude and geometric altitude have been
428 // differing by more than pressureAltitudeImplausibleThreshold.
429 QElapsedTimer m_pressureAltitudeDivergenceTimer;
430 Q_OBJECT_BINDABLE_PROPERTY(Positioning::PositionProvider, bool, m_pressureAltitudeImplausible, &Positioning::PositionProvider::pressureAltitudeImplausibleChanged);
431};
432
433} // namespace Positioning
static Q_INVOKABLE Positioning::PositionProvider * positionProvider()
Pointer to appplication-wide static PositionProvider instance.
Geographic position.
Central Position Provider.
QBindable< Positioning::PositionInfo > bindablePositionInfo() const
Getter method for property with the same name.
PositionProvider(QObject *parent=nullptr)
Standard constructor.
Units::Distance pressureAltitude
Pressure altitude.
Positioning::PositionInfo positionInfo() const
Getter method for property with the same name.
QString statusString() const
Getter method for property with the same name.
QBindable< QGeoCoordinate > bindableLastValidCoordinate()
Getter function for the property with the same name.
Units::Angle lastValidTT
Last valid true track.
QBindable< QGeoCoordinate > bindableMapCenter()
Getter function for the property with the same name.
Q_INVOKABLE void setBackgroundUpdates(const QString &caller, bool enable)
Request or release background location updates (iOS only).
Units::Distance pressureAltitude() const
Getter method for property with the same name.
QBindable< bool > bindablePressureAltitudeImplausible() const
Getter method for property with the same name.
QGeoCoordinate mapCenter() const
Getter function for the property with the same name.
QBindable< Units::Angle > bindableLastValidTT()
Getter function for the property with the same name.
static QGeoCoordinate lastValidCoordinate()
Getter function for the property with the same name.
QGeoCoordinate mapCenter
Map center coordinate.
QGeoCoordinate lastValidCoordinate
Last valid coordinate reading.
QBindable< Units::Distance > bindablePressureAltitude() const
Getter method for property with the same name.
QBindable< QString > bindableStatusString() const
Getter method for property with the same name.
QGeoCoordinate approximateLastValidCoordinate
Approximate last valid coordinate.
Positioning::PositionInfo positionInfo
Position information.
static Units::Angle lastValidTT()
Getter function for the property with the same name.
QString statusString
Source status.
QBindable< bool > bindableReceivingPositionInfo()
Getter method for property with the same name.
bool receivingPositionInfo() const
Getter method for property with the same name.
QBindable< QGeoCoordinate > bindableApproximateLastValidCoordinate() const
Getter function for the property with the same name.
static constexpr Units::Distance pressureAltitudeImplausibleThreshold
Threshold for the pressure altitude plausibility check.
Q_INVOKABLE void startUpdates()
startUpdates
QString icon() const
Getter function for the property with the same name.
QBindable< QString > bindableIcon() const
Getter function for the property with the same name.
bool pressureAltitudeImplausible() const
Getter method for property with the same name.
~PositionProvider() override
Standard destructor.
void setMapCenter(const QGeoCoordinate &newMapCenter)
Setter function for the property with the same name.
bool receivingPositionInfo
Indicator that position information is being received.
bool pressureAltitudeImplausible
Indicator that pressure altitude and geometric altitude are inconsistent.
Convenience class for angle computations.
Definition Angle.h:41
Convenience class for distance computations.
Definition Distance.h:35
static Q_INVOKABLE constexpr Units::Distance fromFT(double distanceInFT)
Constructs a distance.
Definition Distance.h:108
Conversion between units used in aviation.
Definition Angle.h:34