1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-08-14 15:33:34 -04:00

Map Updates

Allow OpenSkyNetwork DB, OpenAIP and OurAirports DB stuctures to be
shared by different plugins, to speed up loading.
Perform map anti-aliasing on the whole map, rather than just info boxes,
to improve rendering speed when there are many items. Add map
multisampling as a preference.
Add plotting of airspaces, airports, navaids on Map feature.
Add support for polylines and polygons to be plotted on Map feature.
Add support for images to 2D Map feature.
Add distance and name filters to Map feature.
Filter map items when zoomed out or if off screen, to improve rendering
performance.
Add UK DAB, FM and AM transmitters to Map feature.
Use labelless maps for 2D transmit maps in Map feature (same as in ADS-B
demod).
This commit is contained in:
Jon Beniston
2023-02-14 14:46:08 +00:00
parent 74dcf31bb9
commit 9c7aa8b333
61 changed files with 8373 additions and 1994 deletions
+310 -142
View File
@@ -19,135 +19,227 @@
#define INCLUDE_FEATURE_MAPMODEL_H_
#include <QAbstractListModel>
#include <QSortFilterProxyModel>
#include <QGeoCoordinate>
#include <QGeoRectangle>
#include <QColor>
#include "util/azel.h"
#include "util/openaip.h"
#include "mapsettings.h"
#include "mapitem.h"
#include "cesiuminterface.h"
#include "SWGMapItem.h"
class MapModel;
class MapGUI;
class CZML;
// Information required about each item displayed on the map
class MapItem {
public:
MapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem);
void update(SWGSDRangel::SWGMapItem *mapItem);
QGeoCoordinate getCoordinates();
private:
void findFrequency();
void updateTrack(QList<SWGSDRangel::SWGMapCoordinate *> *track);
void updatePredictedTrack(QList<SWGSDRangel::SWGMapCoordinate *> *track);
friend MapModel;
friend CZML;
QString m_group;
MapSettings::MapItemSettings *m_itemSettings;
const QObject *m_sourcePipe; // Channel/feature that created the item
QString m_name;
QString m_label;
float m_latitude;
float m_longitude;
float m_altitude; // In metres
QDateTime m_positionDateTime;
bool m_useHeadingPitchRoll;
float m_heading;
float m_pitch;
float m_roll;
QDateTime m_orientationDateTime;
QString m_image;
int m_imageRotation;
QString m_text;
double m_frequency; // Frequency to set
QString m_frequencyString;
QList<QGeoCoordinate *> m_predictedTrackCoords;
QList<QDateTime *> m_predictedTrackDateTimes;
QVariantList m_predictedTrack; // Line showing where the object is going
QVariantList m_predictedTrack1;
QVariantList m_predictedTrack2;
QGeoCoordinate m_predictedStart1;
QGeoCoordinate m_predictedStart2;
QGeoCoordinate m_predictedEnd1;
QGeoCoordinate m_predictedEnd2;
QList<QGeoCoordinate *> m_takenTrackCoords;
QList<QDateTime *> m_takenTrackDateTimes;
QVariantList m_takenTrack; // Line showing where the object has been
QVariantList m_takenTrack1;
QVariantList m_takenTrack2;
QGeoCoordinate m_takenStart1;
QGeoCoordinate m_takenStart2;
QGeoCoordinate m_takenEnd1;
QGeoCoordinate m_takenEnd2;
// For 3D map
QString m_model;
int m_altitudeReference;
float m_labelAltitudeOffset;
float m_modelAltitudeOffset;
bool m_fixedPosition;
QList<CesiumInterface::Animation *> m_animations;
};
// Model used for each item on the map
class MapModel : public QAbstractListModel {
Q_OBJECT
public:
using QAbstractListModel::QAbstractListModel;
enum MarkerRoles {
positionRole = Qt::UserRole + 1,
mapTextRole = Qt::UserRole + 2,
mapTextVisibleRole = Qt::UserRole + 3,
mapImageVisibleRole = Qt::UserRole + 4,
mapImageRole = Qt::UserRole + 5,
mapImageRotationRole = Qt::UserRole + 6,
mapImageMinZoomRole = Qt::UserRole + 7,
bubbleColourRole = Qt::UserRole + 8,
selectedRole = Qt::UserRole + 9,
targetRole = Qt::UserRole + 10,
frequencyRole = Qt::UserRole + 11,
frequencyStringRole = Qt::UserRole + 12,
predictedGroundTrack1Role = Qt::UserRole + 13,
predictedGroundTrack2Role = Qt::UserRole + 14,
groundTrack1Role = Qt::UserRole + 15,
groundTrack2Role = Qt::UserRole + 16,
groundTrackColorRole = Qt::UserRole + 17,
predictedGroundTrackColorRole = Qt::UserRole + 18
itemSettingsRole = Qt::UserRole + 1,
nameRole = Qt::UserRole + 2,
labelRole = Qt::UserRole + 3,
positionRole = Qt::UserRole + 4,
mapImageMinZoomRole = Qt::UserRole + 5,
lastRole = Qt::UserRole + 6
};
MapModel(MapGUI *gui);
MapModel(MapGUI *gui) :
m_gui(gui)
{
connect(this, &MapModel::dataChanged, this, &MapModel::update3DMap);
}
void playAnimations(MapItem *item);
Q_INVOKABLE void add(MapItem *item);
virtual void add(MapItem *item);
virtual void remove(MapItem *item);
virtual void removeAll();
void update(const QObject *source, SWGSDRangel::SWGMapItem *swgMapItem, const QString &group="");
void update(MapItem *item);
void remove(MapItem *item);
void allUpdated();
void removeAll();
void updateItemSettings(QHash<QString, MapSettings::MapItemSettings *> m_itemSettings);
void allUpdated();
MapItem *findMapItem(const QObject *source, const QString& name);
QHash<int, QByteArray> roleNames() const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant& value, int role = Qt::EditRole) override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override
{
(void) parent;
return m_items.count();
}
Qt::ItemFlags flags(const QModelIndex &index) const override
{
(void) index;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
}
public slots:
void update3DMap(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>());
protected:
MapGUI *m_gui;
QList<MapItem *> m_items;
QHash<QString, MapItem *> m_itemsHash;
virtual void update(MapItem *item);
virtual void update3D(MapItem *item) = 0;
virtual MapItem *newMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) = 0;
};
class ImageMapModel : public MapModel {
Q_OBJECT
public:
enum MarkerRoles {
imageRole = MapModel::lastRole + 0,
imageZoomLevelRole = MapModel::lastRole + 1,
boundsRole = MapModel::lastRole + 2
};
ImageMapModel(MapGUI *gui) :
MapModel(gui)
{}
QHash<int, QByteArray> roleNames() const override
{
QHash<int, QByteArray> roles = MapModel::roleNames();
roles[imageRole] = "imageData";
roles[imageZoomLevelRole] = "imageZoomLevel";
roles[boundsRole] = "bounds";
return roles;
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
protected:
MapItem *newMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) override;
void update3D(MapItem *item) override;
};
class PolygonMapModel : public MapModel {
Q_OBJECT
public:
enum MarkerRoles {
borderColorRole = MapModel::lastRole + 0,
fillColorRole = MapModel::lastRole + 1,
polygonRole = MapModel::lastRole + 2,
boundsRole = MapModel::lastRole + 3
};
PolygonMapModel(MapGUI *gui) :
MapModel(gui)
{}
QHash<int, QByteArray> roleNames() const override
{
QHash<int, QByteArray> roles = MapModel::roleNames();
roles[borderColorRole] = "borderColor";
roles[fillColorRole] = "fillColor";
roles[polygonRole] = "polygon";
roles[boundsRole] = "bounds";
return roles;
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
protected:
void update3D(MapItem *item) override;
MapItem *newMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) override;
};
class PolylineMapModel : public MapModel {
Q_OBJECT
public:
enum MarkerRoles {
lineColorRole = MapModel::lastRole + 0,
coordinatesRole = MapModel::lastRole + 1,
boundsRole = MapModel::lastRole + 2,
};
PolylineMapModel(MapGUI *gui) :
MapModel(gui)
{}
QHash<int, QByteArray> roleNames() const override
{
QHash<int, QByteArray> roles = MapModel::roleNames();
roles[lineColorRole] = "lineColor";
roles[coordinatesRole] = "coordinates";
roles[boundsRole] = "bounds";
return roles;
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
protected:
void update3D(MapItem *item) override;
MapItem *newMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) override;
};
// Model used for each item on the map
class ObjectMapModel : public MapModel {
Q_OBJECT
public:
enum MarkerRoles {
//itemSettingsRole = Qt::UserRole + 1,
//nameRole = Qt::UserRole + 2,
//positionRole = Qt::UserRole + 3,
// label? mapTextRole = Qt::UserRole + 4,
mapTextVisibleRole =MapModel::lastRole + 0,
mapImageVisibleRole = MapModel::lastRole + 1,
mapImageRole = MapModel::lastRole + 2,
mapImageRotationRole = MapModel::lastRole + 3,
//mapImageMinZoomRole = MapModel::lastRole + 9,
bubbleColourRole = MapModel::lastRole + 4,
selectedRole = MapModel::lastRole + 5,
targetRole = MapModel::lastRole + 6,
frequencyRole = MapModel::lastRole + 7,
frequencyStringRole = MapModel::lastRole + 8,
predictedGroundTrack1Role = MapModel::lastRole + 9,
predictedGroundTrack2Role = MapModel::lastRole + 10,
groundTrack1Role = MapModel::lastRole + 11,
groundTrack2Role = MapModel::lastRole + 12,
groundTrackColorRole = MapModel::lastRole + 13,
predictedGroundTrackColorRole = MapModel::lastRole + 14,
hasTracksRole = MapModel::lastRole + 15
};
ObjectMapModel(MapGUI *gui);
Q_INVOKABLE void add(MapItem *item) override;
//void update(const QObject *source, SWGSDRangel::SWGMapItem *swgMapItem, const QString &group="");
using MapModel::update;
void remove(MapItem *item) override;
void removeAll() override;
QHash<int, QByteArray> roleNames() const override;
void updateTarget();
void setTarget(const QString& name);
bool isTarget(const MapItem *mapItem) const;
bool isTarget(const ObjectMapItem *mapItem) const;
Q_INVOKABLE void moveToFront(int oldRow);
Q_INVOKABLE void moveToBack(int oldRow);
MapItem *findMapItem(const QObject *source, const QString& name);
MapItem *findMapItem(const QString& name);
ObjectMapItem *findMapItem(const QString& name);
QModelIndex findMapItemIndex(const QString& name);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant& value, int role = Qt::EditRole) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
void setDisplayNames(bool displayNames);
void setDisplaySelectedGroundTracks(bool displayGroundTracks);
@@ -155,48 +247,9 @@ public:
Q_INVOKABLE void setFrequency(double frequency);
Q_INVOKABLE void track3D(int index);
void interpolateEast(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, QGeoCoordinate *ci, bool offScreen);
void interpolateWest(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, QGeoCoordinate *ci, bool offScreen);
void interpolate(QGeoCoordinate *c1, QGeoCoordinate *c2, double bottomLeftLongitude, double bottomRightLongitude, QGeoCoordinate* ci, bool offScreen);
void splitTracks(MapItem *item);
void splitTrack(const QList<QGeoCoordinate *>& coords, const QVariantList& track,
QVariantList& track1, QVariantList& track2,
QGeoCoordinate& start1, QGeoCoordinate& start2,
QGeoCoordinate& end1, QGeoCoordinate& end2);
Q_INVOKABLE void viewChanged(double bottomLeftLongitude, double bottomRightLongitude);
QHash<int, QByteArray> roleNames() const
{
QHash<int, QByteArray> roles;
roles[positionRole] = "position";
roles[mapTextRole] = "mapText";
roles[mapTextVisibleRole] = "mapTextVisible";
roles[mapImageVisibleRole] = "mapImageVisible";
roles[mapImageRole] = "mapImage";
roles[mapImageRotationRole] = "mapImageRotation";
roles[mapImageMinZoomRole] = "mapImageMinZoom";
roles[bubbleColourRole] = "bubbleColour";
roles[selectedRole] = "selected";
roles[targetRole] = "target";
roles[frequencyRole] = "frequency";
roles[frequencyStringRole] = "frequencyString";
roles[predictedGroundTrack1Role] = "predictedGroundTrack1";
roles[predictedGroundTrack2Role] = "predictedGroundTrack2";
roles[groundTrack1Role] = "groundTrack1";
roles[groundTrack2Role] = "groundTrack2";
roles[groundTrackColorRole] = "groundTrackColor";
roles[predictedGroundTrackColorRole] = "predictedGroundTrackColor";
return roles;
}
// Linear interpolation
double interpolate(double x0, double y0, double x1, double y1, double x)
{
return (y0*(x1-x) + y1*(x-x0)) / (x1-x0);
}
bool isSelected3D(const MapItem *item) const
bool isSelected3D(const ObjectMapItem *item) const
{
return m_selected3D == item->m_name;
}
@@ -206,13 +259,24 @@ public:
m_selected3D = selected;
}
public slots:
void update3DMap(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>());
//public slots:
// void update3DMap(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>()) override;
protected:
void playAnimations(ObjectMapItem *item);
MapItem *newMapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) override;
void update(MapItem *item) override;
void update3D(MapItem *item) override;
// Linear interpolation
double interpolate(double x0, double y0, double x1, double y1, double x) const
{
return (y0*(x1-x) + y1*(x-x0)) / (x1-x0);
}
private:
MapGUI *m_gui;
QList<MapItem *> m_items;
QList<bool> m_selected;
QList<bool> m_selected; // Whether each item on 2D map is selected
QString m_selected3D; // Name of item selected on 3D map - only supports 1 item, unlike 2D map
int m_target; // Row number of current target, or -1 for none
bool m_displayNames;
bool m_displaySelectedGroundTracks;
@@ -221,8 +285,112 @@ private:
double m_bottomLeftLongitude;
double m_bottomRightLongitude;
QString m_selected3D; // Name of item selected on 3D map - only supports 1 item, unlike 2D map
void interpolateEast(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, QGeoCoordinate *ci, bool offScreen);
void interpolateWest(QGeoCoordinate *c1, QGeoCoordinate *c2, double x, QGeoCoordinate *ci, bool offScreen);
void interpolate(QGeoCoordinate *c1, QGeoCoordinate *c2, double bottomLeftLongitude, double bottomRightLongitude, QGeoCoordinate* ci, bool offScreen);
void splitTracks(ObjectMapItem *item);
void splitTrack(const QList<QGeoCoordinate *>& coords, const QVariantList& track,
QVariantList& track1, QVariantList& track2,
QGeoCoordinate& start1, QGeoCoordinate& start2,
QGeoCoordinate& end1, QGeoCoordinate& end2);
};
class PolygonFilter : public QSortFilterProxyModel {
Q_OBJECT
public:
PolygonFilter() :
m_zoomLevel(10),
m_settings(nullptr)
{
}
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
Q_INVOKABLE void viewChanged(double topLeftLongitude, double topLeftLatitude, double bottomRightLongitude, double bottomRightLatitude, double zoomLevel);
Q_INVOKABLE int mapRowToSource(int row);
void setPosition(const QGeoCoordinate& position);
private:
QGeoRectangle m_view;
double m_zoomLevel;
MapSettings *m_settings;
QGeoCoordinate m_position;;
};
class PolylineFilter : public QSortFilterProxyModel {
Q_OBJECT
public:
PolylineFilter() :
m_zoomLevel(10),
m_settings(nullptr)
{
}
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
Q_INVOKABLE void viewChanged(double topLeftLongitude, double topLeftLatitude, double bottomRightLongitude, double bottomRightLatitude, double zoomLevel);
Q_INVOKABLE int mapRowToSource(int row);
void setPosition(const QGeoCoordinate& position);
private:
QGeoRectangle m_view;
double m_zoomLevel;
MapSettings *m_settings;
QGeoCoordinate m_position;;
};
class ObjectMapFilter : public QSortFilterProxyModel {
Q_OBJECT
public:
ObjectMapFilter() :
m_topLeftLongitude(0),
m_topLeftLatitude(0),
m_bottomRightLongitude(0),
m_bottomRightLatitude(0),
m_zoomLevel(10),
m_settings(nullptr)
{
}
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
Q_INVOKABLE void viewChanged(double topLeftLongitude, double topLeftLatitude, double bottomRightLongitude, double bottomRightLatitude, double zoomLevel);
void applySettings(MapSettings *settings);
Q_INVOKABLE int mapRowToSource(int row);
void setPosition(const QGeoCoordinate& position);
private:
double m_topLeftLongitude;
double m_topLeftLatitude;
double m_bottomRightLongitude;
double m_bottomRightLatitude;
double m_zoomLevel;
MapSettings *m_settings;
QGeoCoordinate m_position;
};
class ImageFilter : public QSortFilterProxyModel {
Q_OBJECT
public:
ImageFilter() :
m_zoomLevel(10),
m_settings(nullptr)
{
}
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
Q_INVOKABLE void viewChanged(double topLeftLongitude, double topLeftLatitude, double bottomRightLongitude, double bottomRightLatitude, double zoomLevel);
Q_INVOKABLE int mapRowToSource(int row);
void setPosition(const QGeoCoordinate& position);
private:
QGeoRectangle m_view;
double m_zoomLevel;
MapSettings *m_settings;
QGeoCoordinate m_position;;
};
#endif // INCLUDE_FEATURE_MAPMODEL_H_