diff --git a/doc/img/Map_plugin_radiotime_dialog.png b/doc/img/Map_plugin_radiotime_dialog.png new file mode 100644 index 000000000..b2f7a11f3 Binary files /dev/null and b/doc/img/Map_plugin_radiotime_dialog.png differ diff --git a/plugins/feature/map/CMakeLists.txt b/plugins/feature/map/CMakeLists.txt index 21528646a..536ba6e22 100644 --- a/plugins/feature/map/CMakeLists.txt +++ b/plugins/feature/map/CMakeLists.txt @@ -33,6 +33,8 @@ if(NOT SERVER_MODE) mapsettingsdialog.ui mapbeacondialog.cpp mapbeacondialog.ui + mapradiotimedialog.cpp + mapradiotimedialog.ui map.qrc icons.qrc ) @@ -43,6 +45,7 @@ if(NOT SERVER_MODE) mapmaidenheaddialog.h mapsettingsdialog.h mapbeacondialog.h + mapradiotimedialog.h ) set(TARGET_NAME map) diff --git a/plugins/feature/map/icons.qrc b/plugins/feature/map/icons.qrc index f462b389c..ba855ff49 100644 --- a/plugins/feature/map/icons.qrc +++ b/plugins/feature/map/icons.qrc @@ -1,5 +1,6 @@ icons/groundtracks.png + icons/clock.png diff --git a/plugins/feature/map/icons/clock.png b/plugins/feature/map/icons/clock.png new file mode 100644 index 000000000..a6dbea210 Binary files /dev/null and b/plugins/feature/map/icons/clock.png differ diff --git a/plugins/feature/map/map.qrc b/plugins/feature/map/map.qrc index 0310f0732..9f6072bb1 100644 --- a/plugins/feature/map/map.qrc +++ b/plugins/feature/map/map.qrc @@ -3,5 +3,6 @@ map/map.qml map/map_5_12.qml map/antenna.png + map/antennatime.png diff --git a/plugins/feature/map/map/antennatime.png b/plugins/feature/map/map/antennatime.png new file mode 100644 index 000000000..61b29c8ae Binary files /dev/null and b/plugins/feature/map/map/antennatime.png differ diff --git a/plugins/feature/map/mapgui.cpp b/plugins/feature/map/mapgui.cpp index 5b8866570..c3cce4ed8 100644 --- a/plugins/feature/map/mapgui.cpp +++ b/plugins/feature/map/mapgui.cpp @@ -679,7 +679,8 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur m_doApplySettings(true), m_mapModel(this), m_beacons(nullptr), - m_beaconDialog(this) + m_beaconDialog(this), + m_radioTimeDialog(this) { ui->setupUi(this); @@ -738,6 +739,8 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur QList *beacons = Beacon::readIARUCSV(MapGUI::getBeaconFilename()); if (beacons != nullptr) setBeacons(beacons); + + addRadioTimeTransmitters(); } MapGUI::~MapGUI() @@ -770,6 +773,37 @@ void MapGUI::setBeacons(QList *beacons) } } +const QList MapGUI::m_radioTimeTransmitters = { + {"MSF", 60000, 54.9075f, -3.27333f, 17}, + {"DCF77", 77500, 50.01611111f, 9.00805556f, 50}, + {"TDF", 162000, 47.1694f, 2.2044f, 800}, + {"WWVB", 60000, 40.67805556f, -105.04666667f, 70}, + {"JJY", 60000, 33.465f, 130.175555f, 50} +}; + +void MapGUI::addRadioTimeTransmitters() +{ + for (int i = 0; i < m_radioTimeTransmitters.size(); i++) + { + SWGSDRangel::SWGMapItem timeMapItem; + // Need to suffix frequency, as there are multiple becaons with same callsign at different locations + QString name = QString("%1").arg(m_radioTimeTransmitters[i].m_callsign); + timeMapItem.setName(new QString(name)); + timeMapItem.setLatitude(m_radioTimeTransmitters[i].m_latitude); + timeMapItem.setLongitude(m_radioTimeTransmitters[i].m_longitude); + timeMapItem.setAltitude(0.0); + timeMapItem.setImage(new QString("antennatime.png")); + timeMapItem.setImageRotation(0); + timeMapItem.setImageMinZoom(8); + QString text = QString("Radio Time Transmitter\nCallsign: %1\nFrequency: %2 kHz\nPower: %3 kW") + .arg(m_radioTimeTransmitters[i].m_callsign) + .arg(m_radioTimeTransmitters[i].m_frequency/1000.0) + .arg(m_radioTimeTransmitters[i].m_power); + timeMapItem.setText(new QString(text)); + m_mapModel.update(m_map, &timeMapItem, MapSettings::SOURCE_RADIO_TIME); + } +} + void MapGUI::blockApplySettings(bool block) { m_doApplySettings = !block; @@ -1033,6 +1067,12 @@ void MapGUI::on_beacons_clicked() m_beaconDialog.show(); } +void MapGUI::on_radiotime_clicked() +{ + m_radioTimeDialog.updateTable(); + m_radioTimeDialog.show(); +} + quint32 MapGUI::getSourceMask(const PipeEndPoint *sourcePipe) { for (int i = 0; i < m_availablePipes.size(); i++) diff --git a/plugins/feature/map/mapgui.h b/plugins/feature/map/mapgui.h index 8bc3474e5..8b2c02005 100644 --- a/plugins/feature/map/mapgui.h +++ b/plugins/feature/map/mapgui.h @@ -31,6 +31,7 @@ #include "mapsettings.h" #include "SWGMapItem.h" #include "mapbeacondialog.h" +#include "mapradiotimedialog.h" class PluginAPI; class FeatureUISet; @@ -45,6 +46,14 @@ class MapModel; class QQuickItem; struct Beacon; +struct RadioTimeTransmitter { + QString m_callsign; + int m_frequency; // In Hz + float m_latitude; // In degrees + float m_longitude; // In degrees + int m_power; // In kW +}; + // Information required about each item displayed on the map class MapItem { @@ -471,6 +480,8 @@ public: static QString getBeaconFilename(); QList *getBeacons() { return m_beacons; } void setBeacons(QList *beacons); + QList getRadioTimeTransmitters() { return m_radioTimeTransmitters; } + void addRadioTimeTransmitters(); void find(const QString& target); private: @@ -487,6 +498,7 @@ private: AzEl m_azEl; // Position of station QList *m_beacons; MapBeaconDialog m_beaconDialog; + MapRadioTimeDialog m_radioTimeDialog; explicit MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr); virtual ~MapGUI(); @@ -502,6 +514,7 @@ private: void enterEvent(QEvent*); static QString getDataDir(); + static const QList m_radioTimeTransmitters; private slots: void onMenuDialogCalled(const QPoint &p); @@ -516,6 +529,7 @@ private slots: void on_displaySettings_clicked(); void on_mapTypes_currentIndexChanged(int index); void on_beacons_clicked(); + void on_radiotime_clicked(); }; diff --git a/plugins/feature/map/mapgui.ui b/plugins/feature/map/mapgui.ui index 05bc51f4a..8a5a5b39b 100644 --- a/plugins/feature/map/mapgui.ui +++ b/plugins/feature/map/mapgui.ui @@ -140,6 +140,20 @@ + + + + Display radio time transmitters dialog + + + + + + + :/map/icons/clock.png:/map/icons/clock.png + + + @@ -165,6 +179,7 @@ Adobe Devanagari + 9 @@ -190,6 +205,7 @@ Adobe Devanagari + 9 diff --git a/plugins/feature/map/mapradiotimedialog.cpp b/plugins/feature/map/mapradiotimedialog.cpp new file mode 100644 index 000000000..4f2ebf478 --- /dev/null +++ b/plugins/feature/map/mapradiotimedialog.cpp @@ -0,0 +1,89 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2021 Jon Beniston, M7RCE // +// // +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "mapradiotimedialog.h" + +#include + +#include "channel/channelwebapiutils.h" +#include "mapgui.h" + +MapRadioTimeDialog::MapRadioTimeDialog(MapGUI *gui, QWidget* parent) : + QDialog(parent), + m_gui(gui), + ui(new Ui::MapRadioTimeDialog) +{ + ui->setupUi(this); + // Don't call updateTable until m_gui->getAzEl() will return valid location +} + +MapRadioTimeDialog::~MapRadioTimeDialog() +{ + delete ui; +} + +void MapRadioTimeDialog::updateTable() +{ + AzEl azEl = *m_gui->getAzEl(); + ui->transmitters->setSortingEnabled(false); + const QList transmitters = m_gui->getRadioTimeTransmitters(); + ui->transmitters->setRowCount(0); + ui->transmitters->setRowCount(transmitters.size()); + QListIterator i(transmitters); + int row = 0; + for (int i = 0; i < transmitters.size(); i++) + { + ui->transmitters->setItem(row, TRANSMITTER_COL_CALLSIGN, new QTableWidgetItem(transmitters[i].m_callsign)); + QTableWidgetItem *freq = new QTableWidgetItem(); + freq->setText(QString("%1").arg(transmitters[i].m_frequency/1000.0)); + freq->setData(Qt::UserRole, transmitters[i].m_frequency); + ui->transmitters->setItem(row, TRANSMITTER_COL_FREQUENCY, freq); + ui->transmitters->setItem(row, TRANSMITTER_COL_LOCATION, new QTableWidgetItem(QString("%1,%2").arg(transmitters[i].m_latitude).arg(transmitters[i].m_longitude))); + ui->transmitters->setItem(row, TRANSMITTER_COL_POWER, new QTableWidgetItem(QString("%1").arg(transmitters[i].m_power))); + azEl.setTarget(transmitters[i].m_latitude, transmitters[i].m_longitude, 1.0); + azEl.calculate(); + ui->transmitters->setItem(row, TRANSMITTER_COL_AZIMUTH, new QTableWidgetItem(QString("%1").arg(round(azEl.getAzimuth())))); + ui->transmitters->setItem(row, TRANSMITTER_COL_ELEVATION, new QTableWidgetItem(QString("%1").arg(round(azEl.getElevation())))); + int km = round(azEl.getDistance()/1000); + QTableWidgetItem *dist = new QTableWidgetItem(); + dist->setData(Qt::DisplayRole, km); + ui->transmitters->setItem(row, TRANSMITTER_COL_DISTANCE, dist); + row++; + } + ui->transmitters->setSortingEnabled(true); + ui->transmitters->resizeColumnsToContents(); +} + +void MapRadioTimeDialog::accept() +{ + QDialog::accept(); +} + +void MapRadioTimeDialog::on_transmitters_cellDoubleClicked(int row, int column) +{ + if ((column == TRANSMITTER_COL_CALLSIGN) || (column ==TRANSMITTER_COL_LOCATION)) + { + // Find transmitter on map + QString location = ui->transmitters->item(row, column)->text(); + m_gui->find(location); + } + else if (column == TRANSMITTER_COL_FREQUENCY) + { + // Tune to transmitter freq + ChannelWebAPIUtils::setCenterFrequency(0, ui->transmitters->item(row, column)->data(Qt::UserRole).toDouble()); + } +} diff --git a/plugins/feature/map/mapradiotimedialog.h b/plugins/feature/map/mapradiotimedialog.h new file mode 100644 index 000000000..b5f812814 --- /dev/null +++ b/plugins/feature/map/mapradiotimedialog.h @@ -0,0 +1,52 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2021 Jon Beniston, M7RCE // +// // +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_MAPRADIOTIMEDIALOG_H +#define INCLUDE_FEATURE_MAPRADIOTIMEDIALOG_H + +#include "ui_mapradiotimedialog.h" + +class MapGUI; + +class MapRadioTimeDialog : public QDialog { + Q_OBJECT + +public: + explicit MapRadioTimeDialog(MapGUI *gui, QWidget* parent = 0); + ~MapRadioTimeDialog(); + void updateTable(); + +private slots: + void accept(); + void on_transmitters_cellDoubleClicked(int row, int column); + +private: + MapGUI *m_gui; + Ui::MapRadioTimeDialog* ui; + + enum TransmitterCol { + TRANSMITTER_COL_CALLSIGN, + TRANSMITTER_COL_FREQUENCY, + TRANSMITTER_COL_LOCATION, + TRANSMITTER_COL_POWER, + TRANSMITTER_COL_AZIMUTH, + TRANSMITTER_COL_ELEVATION, + TRANSMITTER_COL_DISTANCE + }; +}; + +#endif // INCLUDE_FEATURE_MAPRADIOTIMEDIALOG_H diff --git a/plugins/feature/map/mapradiotimedialog.ui b/plugins/feature/map/mapradiotimedialog.ui new file mode 100644 index 000000000..f85e52ac3 --- /dev/null +++ b/plugins/feature/map/mapradiotimedialog.ui @@ -0,0 +1,140 @@ + + + MapRadioTimeDialog + + + + 0 + 0 + 773 + 279 + + + + + Liberation Sans + 9 + + + + Radio Time Transmitters + + + + + + + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + Callsign + + + + + Frequency (kHz) + + + + + Location (°) + + + + + Power (kW) + + + + + Azimuth (°) + + + + + Elevation (°) + + + + + Distance (km) + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + + + buttonBox + accepted() + MapRadioTimeDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + MapRadioTimeDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/plugins/feature/map/mapsettings.h b/plugins/feature/map/mapsettings.h index fa512e551..04c0265aa 100644 --- a/plugins/feature/map/mapsettings.h +++ b/plugins/feature/map/mapsettings.h @@ -63,7 +63,8 @@ struct MapSettings static const quint32 SOURCE_STAR_TRACKER = 0x8; static const quint32 SOURCE_SATELLITE_TRACKER = 0x10; static const quint32 SOURCE_BEACONS = 0x20; - static const quint32 SOURCE_STATION = 0x40; + static const quint32 SOURCE_RADIO_TIME = 0x40; + static const quint32 SOURCE_STATION = 0x80; }; #endif // INCLUDE_FEATURE_MAPSETTINGS_H_ diff --git a/plugins/feature/map/mapsettingsdialog.ui b/plugins/feature/map/mapsettingsdialog.ui index 6308e36ce..d2de8745f 100644 --- a/plugins/feature/map/mapsettingsdialog.ui +++ b/plugins/feature/map/mapsettingsdialog.ui @@ -89,6 +89,14 @@ Checked + + + Radio Time Transmitters + + + Checked + + diff --git a/plugins/feature/map/readme.md b/plugins/feature/map/readme.md index c000a12aa..f9239f58e 100644 --- a/plugins/feature/map/readme.md +++ b/plugins/feature/map/readme.md @@ -11,6 +11,7 @@ On top of this, it can plot data from other plugins, such as: * Satellites from the Satellite Tracker, * The Sun, Moon and Stars from the Star Tracker, * Beacons based on the IARU Region 1 beacon database. +* Radio time transmitters. It can also create tracks showing the path aircraft, ships and APRS objects have taken, as well as predicted paths for satellites. @@ -48,23 +49,32 @@ The beacons will then be displayed in the table and on the map. ![Beacon dialog](../../../doc/img/Map_plugin_beacon_dialog.png) -

5: Display Names

+

5: Display Radio Time Transmitters dialog

+ +When clicked, opens the Radio Time Transmitters dialog. + +* Double clicking in a cell in the table in the Callsign or Location columns, will centre the map on that transmitter. +* Double clicking on the Frequency column will set the Device center frequency. + +![Radio Time transmitters dialog](../../../doc/img/Map_plugin_radiotime_dialog.png) + +

6: Display Names

When checked, names of objects are displayed in a bubble next to each object. -

6: Display tracks for selected object

+

7: Display tracks for selected object

When checked, displays the track (taken or predicted) for the selected object. -

7: Display tracks for all objects

+

8: Display tracks for all objects

When checked, displays the track (taken or predicted) for the all objects. -

8: Delete

+

9: Delete

When clicked, all items will be deleted from the map. -

9: Display settings

+

10: Display settings

When clicked, opens the Map Display Settings dialog, which allows setting: @@ -93,6 +103,8 @@ IARU Region 1 beacon list used with permission from: https://iaru-r1-c5-beacons. Mapping and geolocation services are by Open Street Map: https://www.openstreetmap.org/ esri: https://www.esri.com/ and Mapbox: https://www.mapbox.com/ +Icons made by Google from Flaticon https://www.flaticon.com +

API

Full details of the API can be found in the Swagger documentation. Here is a quick example of how to centre the map on an object from the command line: