Enroute Flight Navigation
A navigation app for VFR pilots
NOTAMProvider.h
1/***************************************************************************
2 * Copyright (C) 2023-2024 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 <QNetworkReply>
25#include <QQmlEngine>
26#include <QStandardPaths>
27
28#include "GlobalObject.h"
29#include "notam/NOTAMList.h"
30
31using namespace Qt::Literals::StringLiterals;
32
33
34namespace NOTAM {
35
46
47class NOTAMProvider : public GlobalObject {
48 Q_OBJECT
49 QML_ELEMENT
50 QML_SINGLETON
51
52public:
53 explicit NOTAMProvider(QObject* parent = nullptr);
54
55 // deferred initialization
56 void deferredInitialization() override;
57
58 // No default constructor, important for QML singleton
59 explicit NOTAMProvider() = delete;
60
62 ~NOTAMProvider() override;
63
64 // factory function for QML singleton
65 static NOTAMProvider* create(QQmlEngine* /*unused*/, QJSEngine* /*unused*/)
66 {
68 }
69
70 // NOTAM data is considered to cover a given point if the data covers a
71 // circle of radius minimumRadiusPoint around that point.
72 static constexpr Units::Distance minimumRadiusPoint = Units::Distance::fromNM(20.0);
73
74 // NOTAM data is considered to cover the flight route if it covers a region of at least
75 // minimumRadiusFlightRoute around the route
76 static constexpr Units::Distance minimumRadiusFlightRoute = Units::Distance::fromNM(3.0);
77
78
79 //
80 // Properties
81 //
82
87 Q_PROPERTY(QByteArray geoJSON READ geoJSON BINDABLE bindableGeoJSON)
88
89
94 Q_PROPERTY(QDateTime lastUpdate READ lastUpdate BINDABLE bindableLastUpdate NOTIFY lastUpdateChanged)
95
101 Q_PROPERTY(QString status READ status BINDABLE bindableStatus)
102
103
104 //
105 // Getter Methods
106 //
107
112 Q_REQUIRED_RESULT QByteArray geoJSON() const {return m_geoJSON.value();}
113
118 Q_REQUIRED_RESULT QBindable<QByteArray> bindableGeoJSON() const {return &m_geoJSON;}
119
124 Q_REQUIRED_RESULT QDateTime lastUpdate() const {return m_lastUpdate.value();}
125
130 Q_REQUIRED_RESULT QBindable<QDateTime> bindableLastUpdate() const {return &m_lastUpdate;}
131
136 Q_REQUIRED_RESULT QString status() const {return {m_status};}
137
142 Q_REQUIRED_RESULT QBindable<QString> bindableStatus() const {return &m_status;}
143
144
145 //
146 // Methods
147 //
148
149
167 Q_REQUIRED_RESULT Q_INVOKABLE NOTAMList notams(const GeoMaps::Waypoint& waypoint);
168
175 Q_REQUIRED_RESULT Q_INVOKABLE bool isRead(const QString& number) const { return m_readNotamNumbers.contains(number); }
176
183 Q_INVOKABLE void setRead(const QString& number, bool read);
184
185signals:
188
189private:
190
191
192private:
193 Q_DISABLE_COPY_MOVE(NOTAMProvider)
194
195
196 //
197 // Private Methods
198 //
199
200 // Removes outdated NOTAMs and outdated NOTAMLists.
201 Q_REQUIRED_RESULT static QList<NOTAMList> cleaned(const QList<NOTAMList>& notamLists, const QSet<QString>& cancelledNotams = {});
202
203 // This method reads the incoming data from network replies and adds it to
204 // the database. It cleans up the list of network replies in
205 // m_networkReplies. On error, it requests a call to updateData in five
206 // minutes. This method is connected to signals QNetworkReply::finished and
207 // QNetworkReply::errorOccurred of the QNetworkReply contained in the list
208 // in m_networkReply.
209 void downloadFinished();
210
211 // Check if current NOTAM data exists for a circle of radius minimalRadius
212 // around position. This method ignores outdated NOTAM data. An invalid
213 // position is always considered to be covered.
214 //
215 // includeDataThatNeedsUpdate: If true, then also count NOTAM lists that
216 // need an update as NOTAM data
217 //
218 // includeRunningDownloads: If true, then also count running downloads as
219 // NOTAM data
220 Q_REQUIRED_RESULT bool hasDataForPosition(const QGeoCoordinate& position, bool includeDataThatNeedsUpdate, bool includeRunningDownloads) const;
221
222 // Save NOTAM data to a file, using the filename found in m_stdFileName.
223 // There are no error checks of any kind. The propertyNotifier ensures that
224 // the method save() is called whenever m_notamLists changes.
225 void save() const;
226 QPropertyNotifier m_saveNotifier;
227
228 // Request NOTAM data from the FAA, for a circle of radius requestRadius
229 // around the coordinate. For performance reasons, the request will be
230 // ignored if existing NOTAM data or ongoing download requests cover the
231 // position alreads.
232 void startRequest(const QGeoCoordinate& coordinate);
233
234 // Checks if NOTAM data is available for an area of marginRadius around the
235 // current position and around the current flight route. If not, requests
236 // the data.
237 void updateData();
238
239
240 //
241 // Private Members and Member Computing Methods
242 //
243
244 // List with numbers of notams that have been marked as read
245 QList<QString> m_readNotamNumbers;
246
247 // List of pending network requests
248 QList<QPointer<QNetworkReply>> m_networkReplies;
249
250 // List of NOTAMLists, sorted so that newest lists come first
251 QProperty<QList<NOTAMList>> m_notamLists;
252
253 // This is a list of control points. The computing function guarantees that
254 // the NOTAM data covers a region of at least marginRadiusFlightRoute around
255 // the route if the data covers a circle of radius marginRadius around every
256 // control point point. Exeption: For performance reasons, this guarantee is
257 // lifted if the flight route contains a leg of size >
258 // maximumFlightRouteLegLength.
259 QProperty<QList<QGeoCoordinate>> m_controlPoints4FlightRoute;
260 Q_REQUIRED_RESULT static QList<QGeoCoordinate> computeControlPoints4FlightRoute();
261
262 // GeoJSON, for use in map
263 QProperty<QByteArray> m_geoJSON;
264 Q_REQUIRED_RESULT QByteArray computeGeoJSON() const;
265
266 // Time of last update to data
267 Q_OBJECT_BINDABLE_PROPERTY(NOTAMProvider, QDateTime, m_lastUpdate, &NOTAMProvider::lastUpdateChanged)
268 Q_REQUIRED_RESULT QDateTime computeLastUpdate() const;
269
270 // Filename for loading/saving NOTAM data
271 QProperty<QString> m_status;
272 Q_REQUIRED_RESULT QString computeStatus() const;
273
274 // Filename for loading/saving NOTAM data
275 QString m_stdFileName { QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)+u"/notam.dat"_s };
276
277 // NOTAM data is considered to cover the flight route if it covers a region
278 // of at least marginRadiusFlightRoute around the route
279 static constexpr Units::Distance maximumFlightRouteLegLength = Units::Distance::fromNM(200.0);
280
281 // Requests for Notam data are requestRadius around given position. This is
282 // the maximum that FAA API currently allows (FAA max is 100NM)
283 static constexpr Units::Distance requestRadius = Units::Distance::fromNM(99.0);
284};
285
286} // namespace NOTAM
287
Waypoint, such as an airfield, a navaid station or a reporting point.
Definition Waypoint.h:43
GlobalObject(QObject *parent=nullptr)
Standard constructor.
static Q_INVOKABLE NOTAM::NOTAMProvider * notamProvider()
Pointer to appplication-wide static notification manager instance.
A list of NOTAMs.
Definition NOTAMList.h:39
Manage NOTAM data and download NOTAM data from the FAA if required.
Q_REQUIRED_RESULT QBindable< QDateTime > bindableLastUpdate() const
Getter function for the property with the same name.
QString status
Status.
Q_INVOKABLE void setRead(const QString &number, bool read)
Register NOTAM number as read or unread.
QDateTime lastUpdate
Time of last database update.
~NOTAMProvider() override
Standard destructor.
Q_REQUIRED_RESULT QBindable< QByteArray > bindableGeoJSON() const
Getter function for property with the same name.
void deferredInitialization() override
Non-constructor initialization.
Q_REQUIRED_RESULT Q_INVOKABLE NOTAMList notams(const GeoMaps::Waypoint &waypoint)
NOTAMs for a given waypoint.
Q_REQUIRED_RESULT QString status() const
Getter function for the property with the same name.
Q_REQUIRED_RESULT QDateTime lastUpdate() const
Getter function for the property with the same name.
Q_REQUIRED_RESULT QBindable< QString > bindableStatus() const
Getter function for the property with the same name.
QByteArray geoJSON
List of NOTAM points.
void lastUpdateChanged()
Notification signal for property with the same name.
Q_REQUIRED_RESULT Q_INVOKABLE bool isRead(const QString &number) const
Check if a NOTAM number is registred as read.
Convenience class for distance computations.
Definition Distance.h:35
static Q_INVOKABLE constexpr Units::Distance fromNM(double distanceInNM)
Constructs a distance.
Definition Distance.h:82