mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 13:00:26 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			403 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			403 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| ///////////////////////////////////////////////////////////////////////////////////
 | |
| // Copyright (C) 2022-2023 Jon Beniston, M7RCE <jon@beniston.com>                //
 | |
| // Copyright (C) 2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com>               //
 | |
| //                                                                               //
 | |
| // This program is free software; you can redistribute it and/or modify          //
 | |
| // it under the terms of the GNU General Public License as published by          //
 | |
| // the Free Software Foundation as version 3 of the License, or                  //
 | |
| // (at your option) any later version.                                           //
 | |
| //                                                                               //
 | |
| // This program is distributed in the hope that it will be useful,               //
 | |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | |
| // GNU General Public License V3 for more details.                               //
 | |
| //                                                                               //
 | |
| // You should have received a copy of the GNU General Public License             //
 | |
| // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | |
| ///////////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| #ifndef INCLUDE_FEATURE_MAPMODEL_H_
 | |
| #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 MapGUI;
 | |
| class CZML;
 | |
| 
 | |
| class MapModel : public QAbstractListModel {
 | |
|     Q_OBJECT
 | |
| 
 | |
| public:
 | |
|     enum MarkerRoles {
 | |
|         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) :
 | |
|         m_gui(gui)
 | |
|     {
 | |
|         connect(this, &MapModel::dataChanged, this, &MapModel::update3DMap);
 | |
|     }
 | |
| 
 | |
|     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 updateItemSettings(QHash<QString, MapSettings::MapItemSettings *> m_itemSettings);
 | |
|     void allUpdated();
 | |
| 
 | |
|     MapItem *findMapItem(const QObject *source, const QString& name);
 | |
|     MapItem *findMapItem(const QString& name);
 | |
|     QModelIndex findMapItemIndex(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,
 | |
|         frequenciesRole = MapModel::lastRole + 7,
 | |
|         frequencyStringsRole = 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 ObjectMapItem *mapItem) const;
 | |
| 
 | |
|     Q_INVOKABLE void moveToFront(int oldRow);
 | |
|     Q_INVOKABLE void moveToBack(int oldRow);
 | |
| 
 | |
|     Q_INVOKABLE void link(const QString& link);
 | |
| 
 | |
|     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
 | |
|     bool setData(const QModelIndex &index, const QVariant& value, int role = Qt::EditRole) override;
 | |
| 
 | |
|     void setDisplayNames(bool displayNames);
 | |
|     void setDisplaySelectedGroundTracks(bool displayGroundTracks);
 | |
|     void setDisplayAllGroundTracks(bool displayGroundTracks);
 | |
|     Q_INVOKABLE void track3D(int index);
 | |
|     Q_INVOKABLE QStringList getDeviceSets() const;
 | |
|     Q_INVOKABLE void setFrequency(qint64 frequency, const QString& deviceSet);
 | |
| 
 | |
|     Q_INVOKABLE void viewChanged(double bottomLeftLongitude, double bottomRightLongitude);
 | |
| 
 | |
|     bool isSelected3D(const ObjectMapItem *item) const
 | |
|     {
 | |
|         return m_selected3D == item->m_name;
 | |
|     }
 | |
| 
 | |
|     void setSelected3D(const QString &selected)
 | |
|     {
 | |
|         m_selected3D = selected;
 | |
|     }
 | |
| 
 | |
| //public slots:
 | |
| //    void update3DMap(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>()) override;
 | |
| 
 | |
| signals:
 | |
|     void linkClicked(const QString& url);
 | |
| 
 | |
| 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:
 | |
|     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;
 | |
|     bool m_displayAllGroundTracks;
 | |
| 
 | |
|     double m_bottomLeftLongitude;
 | |
|     double m_bottomRightLongitude;
 | |
| 
 | |
|     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_
 | |
| 
 |