Enroute Flight Navigation
A navigation app for VFR pilots
GeoMapProvider.h
1/***************************************************************************
2 * Copyright (C) 2019-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 <QCache>
24#include <QFuture>
25#include <QGeoRectangle>
26#include <QImage>
27#include <QProperty>
28#include <QQmlEngine>
29#include <QStandardPaths>
30#include <QTemporaryFile>
31#include <QTimer>
32
33#include "Airspace.h"
34#include "GlobalObject.h"
35#include "TileServer.h"
36#include "Waypoint.h"
37#include "fileFormats/MBTILES.h"
38
39using namespace Qt::Literals::StringLiterals;
40
41
42namespace GeoMaps
43{
44
63
65{
66 Q_OBJECT
67 QML_ELEMENT
68 QML_SINGLETON
69
70public:
77 explicit GeoMapProvider(QObject *parent = nullptr);
78
79 // No default constructor, important for QML singleton
80 explicit GeoMapProvider() = delete;
81
82 // deferred initialization
83 void deferredInitialization() override;
84
85 // factory function for QML singleton
86 static GeoMaps::GeoMapProvider* create(QQmlEngine* /*unused*/, QJSEngine* /*unused*/)
87 {
89 }
90
92 ~GeoMapProvider() override;
93
94
95
96 //
97 // Properties
98 //
99
104 Q_PROPERTY(QList<GeoMaps::Airspace> airspaces READ airspaces BINDABLE bindableAirspaces)
105
106
112
118 Q_PROPERTY(QString copyrightNotice READ copyrightNotice CONSTANT)
119
130
137
143 Q_PROPERTY(QByteArray geoJSON READ geoJSON BINDABLE bindableGeoJSON)
144
153 Q_PROPERTY(QStringList oversizedMaps READ oversizedMaps BINDABLE bindableOversizedMaps)
154
162 Q_PROPERTY(QString serverUrl READ serverUrl NOTIFY serverUrlChanged)
163
173 Q_PROPERTY(QString styleFileURL READ styleFileURL NOTIFY styleFileURLChanged)
174
176 Q_PROPERTY(QList<QSharedPointer<FileFormats::MBTILES>> terrainMapTiles READ terrainMapTiles NOTIFY terrainMapTilesChanged)
177
183 Q_PROPERTY(QList<GeoMaps::Waypoint> waypoints READ waypoints NOTIFY waypointsChanged)
184
185
186
187 //
188 // Getter Methods
189 //
190
195 [[nodiscard]] QList<GeoMaps::Airspace> airspaces() const {return m_airspaces.value();}
196
201 [[nodiscard]] QBindable<QList<GeoMaps::Airspace>> bindableAirspaces() {return &m_airspaces;}
202
207 [[nodiscard]] QStringList availableRasterMaps() const
208 {
209 return m_availableRasterMaps.value();
210 }
211
216 [[nodiscard]] QBindable<QStringList> bindableAvailableRasterMaps() const
217 {
218 return &m_availableRasterMaps;
219 }
220
225 [[nodiscard]] static QString copyrightNotice();
226
231 [[nodiscard]] QString currentRasterMap() const {return m_currentRasterMap.value();}
232
237 [[nodiscard]] QBindable<QString> bindableCurrentRasterMap() const {return &m_currentRasterMap;}
238
243 [[nodiscard]] int currentRasterMapTileSize() const {return m_currentRasterMapTileSize.value();}
244
249 [[nodiscard]] QBindable<int> bindableCurrentRasterMapTileSize() const {return &m_currentRasterMapTileSize;}
250
255 [[nodiscard]] QByteArray geoJSON() const {return m_combinedGeoJSON.value();}
256
261 [[nodiscard]] QBindable<QByteArray> bindableGeoJSON() {return &m_combinedGeoJSON;}
262
267 [[nodiscard]] QStringList oversizedMaps() const {return m_oversizedMaps.value();}
268
273 [[nodiscard]] QBindable<QStringList> bindableOversizedMaps() {return &m_oversizedMaps;}
274
279 [[nodiscard]] QString serverUrl() {return m_tileServer.serverUrl();}
280
285 [[nodiscard]] QString styleFileURL();
286
291 [[nodiscard]] QList<QSharedPointer<FileFormats::MBTILES>> terrainMapTiles() const
292 {
293 return m_terrainMapTiles;
294 }
295
300 [[nodiscard]] QList<Waypoint> waypoints();
301
302
303
304 //
305 // Setter Methods
306 //
307
312 void setCurrentRasterMap(const QString& mapName);
313
314
315
316 //
317 // Methods
318 //
319
328 [[nodiscard]] Q_INVOKABLE QVariantList airspacesAtPosition(const QGeoCoordinate &position);
329
342 [[nodiscard]] Q_INVOKABLE GeoMaps::Waypoint closestWaypoint(QGeoCoordinate position, const QGeoCoordinate &distPosition);
343
351 [[nodiscard]] Q_INVOKABLE static GeoMaps::Waypoint createWaypoint()
352 {
353 return {};
354 }
355
363 [[nodiscard]] Q_INVOKABLE Units::Distance terrainElevationAMSL(const QGeoCoordinate& coordinate);
364
369 [[nodiscard]] Q_INVOKABLE static QByteArray emptyGeoJSON();
370
379 [[nodiscard]] Q_INVOKABLE QVector<GeoMaps::Waypoint> filteredWaypoints(const QString& filter);
380
387 [[nodiscard]] Q_INVOKABLE Waypoint findByID(const QString& icaoID);
388
399 [[nodiscard]] Q_INVOKABLE QList<GeoMaps::Waypoint> nearbyWaypoints(const QGeoCoordinate& position, const QString& type);
400
401
402signals:
405
408
411
414
417
420
421private:
422 Q_DISABLE_COPY_MOVE(GeoMapProvider)
423
424 // This slot is called every time the the set of aviation maps qchanges. It
425 // fills the aviation data cache.
426 void onAviationMapsChanged();
427
428 // This slot is called every time the the set of MBTile files changes. It
429 // sets up the tile server to and generates a new style file.
430 void onMBTILESChanged();
431
432 // This slot is called just before one of the MBTile files is replaced or
433 // deleted. It releases every handle to the file, so that the file can be
434 // replaced (Windows refuses to rename over or delete an open file). The
435 // tile server is set up again with the new file in onMBTILESChanged().
436 void onMBTILESAboutToChange(const QString& fileName);
437
438 // Sets up the tile server to serve the raster map with the given name
439 // under "rasterMap" and updates the properties currentRasterMap and
440 // currentRasterMapTileSize. Does not emit styleFileURLChanged().
441 void serveRasterMap(const QString& mapName);
442
443
444 // Interal function that does most of the work for aviationMapsChanged()
445 // emits geoJSONChanged() when done. This function is meant to be run in a
446 // separate thread.
447 struct aviationDataCacheResult {
448 QList<Waypoint> waypoints;
449 QList<Airspace> airspaces;
450 QByteArray combinedGeoJSON;
451 };
452 aviationDataCacheResult fillAviationDataCache(QStringList JSONFileNames, bool hideGlidingSectors);
453
454 // Caches used to speed up the method simplifySpecialChars
455 QRegularExpression specialChars{QStringLiteral("[^a-zA-Z0-9]")};
456 QHash<QString, QString> simplifySpecialChars_cache;
457
458 // This is the path under which map tiles are available on the m_tileServer.
459 // This is set to a random number that changes every time the set of MBTile
460 // files changes
461 QString _currentBaseMapPath;
462 QString _currentTerrainMapPath;
463
464 // Tile Server
465 TileServer m_tileServer;
466
467 // Temporary file that holds the current style file
468 QPointer<QTemporaryFile> m_styleFile;
469
470 //
471 // Aviation Data Cache
472 //
473 QFuture<GeoMaps::GeoMapProvider::aviationDataCacheResult> _aviationDataCacheFuture; // Future; indicates if fillAviationDataCache() is currently running
474 QTimer _aviationDataCacheTimer; // Timer used to start another run of fillAviationDataCache()
475
476 //
477 // MBTILES
478 //
479 QList<QSharedPointer<FileFormats::MBTILES>> m_baseMapVectorTiles;
480 QProperty<QList<QSharedPointer<FileFormats::MBTILES>>> m_baseMapRasterTiles;
481 QList<QSharedPointer<FileFormats::MBTILES>> m_terrainMapTiles;
482
483 QProperty<QStringList> m_availableRasterMaps;
484 QStringList computeAvailableRasterMaps();
485
486 QProperty<QString> m_currentRasterMap {u"non-empty place holder"_s};
487 QPropertyNotifier m_currentRasterMapNotifier; // Used to save the currentRasterMap
488 QProperty<int> m_currentRasterMapTileSize {512};
489
490 Q_OBJECT_BINDABLE_PROPERTY(GeoMaps::GeoMapProvider, QByteArray, m_combinedGeoJSON, &GeoMaps::GeoMapProvider::geoJSONChanged)
491 QList<Waypoint> _waypoints_; // Cache: Waypoints
492 QProperty<QList<Airspace>> m_airspaces; // Cache: Airspaces
493
494 // Aviation maps whose file size exceeds maxAviationMapFileSize are ignored
495 // when compiling the aviation data; parsing them would exhaust the memory
496 // available on mobile devices (see issue #676). The peak memory used when
497 // parsing is roughly ten times the file size.
498 static constexpr qint64 maxAviationMapFileSize = 50*1024*1024;
499 static constexpr qint64 maxGeoJSONCacheSize = 150*1024*1024;
500 Q_OBJECT_BINDABLE_PROPERTY(GeoMaps::GeoMapProvider, QStringList, m_oversizedMaps, &GeoMaps::GeoMapProvider::oversizedMapsChanged)
501
502 // TerrainImageCache
503 QCache<qint64,QImage> terrainTileCache {6}; // Hold 6 tiles, roughly 1.2MB
504
505 // GeoJSON file
506 QString geoJSONCache {QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + u"/aviationData.json"_s};
507};
508
509} // namespace GeoMaps
A very simple class that describes an airspace.
Definition Airspace.h:33
Provides geographic information.
~GeoMapProvider() override
Destructor.
QBindable< QString > bindableCurrentRasterMap() const
Getter function for the property with the same name.
QList< Waypoint > waypoints()
Getter function for the property with the same name.
Q_INVOKABLE QList< GeoMaps::Waypoint > nearbyWaypoints(const QGeoCoordinate &position, const QString &type)
void terrainMapTilesChanged()
Notification signal for the property with the same name.
void oversizedMapsChanged()
Notification signal for the property with the same name.
QStringList oversizedMaps() const
Getter function for the property with the same name.
QBindable< QList< GeoMaps::Airspace > > bindableAirspaces()
Getter function for the property with the same name.
QBindable< QByteArray > bindableGeoJSON()
Getter function for the property with the same name.
QList< QSharedPointer< FileFormats::MBTILES > > terrainMapTiles() const
Getter function for the property with the same name.
QBindable< QStringList > bindableAvailableRasterMaps() const
Getter function for the property with the same name.
QString serverUrl()
Getter function for the property with the same name.
QStringList availableRasterMaps
Available Raster Maps.
Q_INVOKABLE Waypoint findByID(const QString &icaoID)
QString currentRasterMap
Current Raster Map.
QString currentRasterMap() const
Getter function for the property with the same name.
static Q_INVOKABLE GeoMaps::Waypoint createWaypoint()
Create invalid waypoint.
Q_INVOKABLE QVariantList airspacesAtPosition(const QGeoCoordinate &position)
List of airspaces at a given position.
Q_INVOKABLE QVector< GeoMaps::Waypoint > filteredWaypoints(const QString &filter)
Waypoints containing a given substring.
static Q_INVOKABLE QByteArray emptyGeoJSON()
Create empty GeoJSON document.
QByteArray geoJSON
Union of all aviation maps in GeoJSON format.
QBindable< QStringList > bindableOversizedMaps()
Getter function for the property with the same name.
void styleFileURLChanged()
Notification signal for the property with the same name.
Q_INVOKABLE Units::Distance terrainElevationAMSL(const QGeoCoordinate &coordinate)
Elevation of terrain at a given coordinate, above sea level.
QString serverUrl
URL under which this server is presently reachable.
GeoMapProvider(QObject *parent=nullptr)
Creates a new GeoMap provider.
void geoJSONChanged()
Notification signal for the property with the same name.
QBindable< int > bindableCurrentRasterMapTileSize() const
Getter function for the property with the same name.
QString styleFileURL()
Getter function for the property with the same name.
QString copyrightNotice
Copyright notice for the map.
QList< GeoMaps::Airspace > airspaces
Available Airspaces.
QStringList oversizedMaps
Names of installed aviation maps that are too large to load.
QByteArray geoJSON() const
Getter function for the property with the same name.
QList< GeoMaps::Waypoint > waypoints
Waypoints.
void serverUrlChanged()
Notification signal for the property with the same name.
QStringList availableRasterMaps() const
Getter function for the property with the same name.
void deferredInitialization() override
Non-constructor initialization.
int currentRasterMapTileSize
Current Raster Map Tile Size.
int currentRasterMapTileSize() const
Getter function for the property with the same name.
void waypointsChanged()
Notification signal for the property with the same name.
QString styleFileURL
URL where a style file for the base map can be retrieved.
void setCurrentRasterMap(const QString &mapName)
Setter function for the property with the same name.
QListQSharedPointer< FileFormats::MBTILES > terrainMapTiles
List of terrain map MBTILES.
Q_INVOKABLE GeoMaps::Waypoint closestWaypoint(QGeoCoordinate position, const QGeoCoordinate &distPosition)
Find closest waypoint to a given position.
static QString copyrightNotice()
Getter function for the property with the same name.
Waypoint, such as an airfield, a navaid station or a reporting point.
Definition Waypoint.h:43
static Q_INVOKABLE GeoMaps::GeoMapProvider * geoMapProvider()
Pointer to appplication-wide static GeoMaps::GeoMapProvider instance.
GlobalObject(QObject *parent=nullptr)
Standard constructor.
Convenience class for distance computations.
Definition Distance.h:35