1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-09-27 15:26:33 -04:00

Map: Add DSC and VLF transmitters. Fix removal of polylines from 3D map. Add find support for polylines and polygoins

This commit is contained in:
Jon Beniston 2023-05-15 16:47:29 +01:00
parent 7fe09b9a20
commit a111c1f1a0
8 changed files with 161 additions and 61 deletions

View File

@ -77,6 +77,7 @@ QJsonObject CZML::update(PolygonMapItem *mapItem)
if ( !mapItem->m_itemSettings->m_enabled
|| !mapItem->m_itemSettings->m_display3DTrack
|| filter(mapItem)
|| mapItem->m_deleted
)
{
// Delete obj completely (including any history)
@ -147,6 +148,15 @@ QJsonObject CZML::update(PolygonMapItem *mapItem)
polygon.insert("extrudedHeight", mapItem->m_extrudedHeight);
}
// We need to have a position, otherwise viewer entity tracking doesn't seem to work
QJsonArray coords {
mapItem->m_longitude, mapItem->m_latitude, mapItem->m_altitude
};
QJsonObject position {
{"cartographicDegrees", coords},
};
obj.insert("position", position);
obj.insert("polygon", polygon);
obj.insert("description", mapItem->m_label);
@ -165,6 +175,7 @@ QJsonObject CZML::update(PolylineMapItem *mapItem)
if ( !mapItem->m_itemSettings->m_enabled
|| !mapItem->m_itemSettings->m_display3DTrack
|| filter(mapItem)
|| mapItem->m_deleted
)
{
// Delete obj completely (including any history)
@ -214,6 +225,15 @@ QJsonObject CZML::update(PolylineMapItem *mapItem)
polyline.insert("altitudeReference", m_heightReferences[mapItem->m_altitudeReference]); // Custom code in map3d.html
}
// We need to have a position, otherwise viewer entity tracking doesn't seem to work
QJsonArray coords {
mapItem->m_longitude, mapItem->m_latitude, mapItem->m_altitude
};
QJsonObject position {
{"cartographicDegrees", coords},
};
obj.insert("position", position);
obj.insert("polyline", polyline);
obj.insert("description", mapItem->m_label);

View File

@ -194,6 +194,7 @@ Item {
Text {
id: polygonText
text: label
textFormat: TextEdit.RichText
}
}
}
@ -226,6 +227,7 @@ Item {
Text {
id: polylineText
text: label
textFormat: TextEdit.RichText
}
}
}

View File

@ -309,6 +309,7 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur
addAirspace();
addAirports();
addNavtex();
addVLF();
displaySettings();
applySettings(true);
@ -419,6 +420,53 @@ void MapGUI::addIBPBeacons()
}
}
// https://sidstation.loudet.org/stations-list-en.xhtml
// https://core.ac.uk/download/pdf/224769021.pdf -- Table 1
// GQD/GQZ callsigns: https://groups.io/g/VLF/message/19212?p=%2C%2C%2C20%2C0%2C0%2C0%3A%3Arecentpostdate%2Fsticky%2C%2C19.6%2C20%2C2%2C0%2C38924431
const QList<RadioTimeTransmitter> MapGUI::m_vlfTransmitters = {
// Other signals possibly seen: 13800, 19000
{"VTX2", 17000, 8.387015, 77.752762}, // South Vijayanarayanam, India
{"GQD", 19580, 54.911643, -3.278456, 100}, // Anthorn, UK, Often referred to as GBZ
{"NWC", 19800, -21.816325, 114.16546, 1000}, // Exmouth, Aus
{"ICV", 20270, 40.922946, 9.731881, 50}, // Isola di Tavolara, Italy (Can be distorted on 3D map if terrain used)
{"FTA", 20900, 48.544632, 2.579429, 50}, // Sainte-Assise, France (Satellite imagary obfuscated)
{"NPM", 21400, 21.420166, -158.151140, 600}, // Pearl Harbour, Lualuahei, USA (Not seen?)
{"HWU", 21750, 46.713129, 1.245248, 200}, // Rosnay, France
{"GQZ", 22100, 54.731799, -2.883033, 100}, // Skelton, UK (GVT in paper)
{"DHO38", 23400, 53.078900, 7.615000, 300}, // Rhauderfehn, Germany - Off air 7-8 UTC - Not seen on air!
{"NAA", 24000, 44.644506, -67.284565, 1000}, // Cutler, Maine, USA
{"TFK/NRK", 37500, 63.850365, -22.466773, 100}, // Grindavik, Iceland
{"SRC/SHR", 38000, 57.120328, 16.153083, -1}, // Ruda, Sweden
};
void MapGUI::addVLF()
{
for (int i = 0; i < m_vlfTransmitters.size(); i++)
{
SWGSDRangel::SWGMapItem vlfMapItem;
// Need to suffix frequency, as there are multiple becaons with same callsign at different locations
QString name = QString("%1").arg(m_vlfTransmitters[i].m_callsign);
vlfMapItem.setName(new QString(name));
vlfMapItem.setLatitude(m_vlfTransmitters[i].m_latitude);
vlfMapItem.setLongitude(m_vlfTransmitters[i].m_longitude);
vlfMapItem.setAltitude(0.0);
vlfMapItem.setImage(new QString("antenna.png"));
vlfMapItem.setImageRotation(0);
QString text = QString("VLF Transmitter\nCallsign: %1\nFrequency: %2 kHz")
.arg(m_vlfTransmitters[i].m_callsign)
.arg(m_vlfTransmitters[i].m_frequency/1000.0);
vlfMapItem.setText(new QString(text));
vlfMapItem.setModel(new QString("antenna.glb"));
vlfMapItem.setFixedPosition(true);
vlfMapItem.setOrientation(0);
vlfMapItem.setLabel(new QString(name));
vlfMapItem.setLabelAltitudeOffset(4.5);
vlfMapItem.setAltitudeReference(1);
update(m_map, &vlfMapItem, "VLF");
}
}
const QList<RadioTimeTransmitter> MapGUI::m_radioTimeTransmitters = {
{"MSF", 60000, 54.9075f, -3.27333f, 17}, // UK
{"DCF77", 77500, 50.01611111f, 9.00805556f, 50}, // Germany
@ -1575,8 +1623,7 @@ void MapGUI::find(const QString& target)
}
else
{
// FIXME: Support polygon/polyline
ObjectMapItem *mapItem = m_objectMapModel.findMapItem(target);
ObjectMapItem *mapItem = (ObjectMapItem *)m_objectMapModel.findMapItem(target);
if (mapItem != nullptr)
{
map->setProperty("center", QVariant::fromValue(mapItem->getCoordinates()));
@ -1584,25 +1631,47 @@ void MapGUI::find(const QString& target)
m_cesium->track(target);
}
m_objectMapModel.moveToFront(m_objectMapModel.findMapItemIndex(target).row());
return;
}
PolylineMapItem *polylineMapItem = (PolylineMapItem *)m_polylineMapModel.findMapItem(target);
if (polylineMapItem != nullptr)
{
map->setProperty("center", QVariant::fromValue(polylineMapItem->getCoordinates()));
if (m_cesium) {
m_cesium->track(target);
}
//m_polylineMapModel.moveToFront(m_polylineMapModel.findMapItemIndex(target).row());
return;
}
PolygonMapItem *polygonMapItem = (PolygonMapItem *)m_polylineMapModel.findMapItem(target);
if (polygonMapItem != nullptr)
{
map->setProperty("center", QVariant::fromValue(polygonMapItem->getCoordinates()));
if (m_cesium) {
m_cesium->track(target);
}
//m_polylineMapModel.moveToFront(m_polylineMapModel.findMapItemIndex(target).row());
return;
}
// Search as an address
QGeoServiceProvider* geoSrv = new QGeoServiceProvider("osm");
if (geoSrv != nullptr)
{
QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
geoSrv->setLocale(qLocaleC);
QGeoCodeReply *pQGeoCode = geoSrv->geocodingManager()->geocode(target);
if (pQGeoCode) {
QObject::connect(pQGeoCode, &QGeoCodeReply::finished, this, &MapGUI::geoReply);
} else {
qDebug() << "MapGUI::find: GeoCoding failed";
}
}
else
{
QGeoServiceProvider* geoSrv = new QGeoServiceProvider("osm");
if (geoSrv != nullptr)
{
QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
geoSrv->setLocale(qLocaleC);
QGeoCodeReply *pQGeoCode = geoSrv->geocodingManager()->geocode(target);
if (pQGeoCode) {
QObject::connect(pQGeoCode, &QGeoCodeReply::finished, this, &MapGUI::geoReply);
} else {
qDebug() << "MapGUI::find: GeoCoding failed";
}
}
else
{
qDebug() << "MapGUI::find: osm not available";
}
qDebug() << "MapGUI::find: osm not available";
}
}
}

View File

@ -39,6 +39,14 @@ void MapItem::update(SWGSDRangel::SWGMapItem *mapItem)
m_altitude = mapItem->getAltitude();
}
QGeoCoordinate MapItem::getCoordinates()
{
QGeoCoordinate coords;
coords.setLatitude(m_latitude);
coords.setLongitude(m_longitude);
return coords;
}
void ObjectMapItem::update(SWGSDRangel::SWGMapItem *mapItem)
{
MapItem::update(mapItem);
@ -116,6 +124,7 @@ void PolygonMapItem::update(SWGSDRangel::SWGMapItem *mapItem)
m_colorValid = mapItem->getColorValid();
m_color = mapItem->getColor();
m_altitudeReference = mapItem->getAltitudeReference();
m_deleted = *mapItem->getImage() == "";
qDeleteAll(m_points);
m_points.clear();
@ -151,6 +160,7 @@ void PolylineMapItem::update(SWGSDRangel::SWGMapItem *mapItem)
m_colorValid = mapItem->getColorValid();
m_color = mapItem->getColor();
m_altitudeReference = mapItem->getAltitudeReference();
m_deleted = *mapItem->getImage() == "";
qDeleteAll(m_points);
m_points.clear();
@ -180,14 +190,6 @@ void PolylineMapItem::update(SWGSDRangel::SWGMapItem *mapItem)
m_bounds = QGeoRectangle(QGeoCoordinate(latMax, lonMin), QGeoCoordinate(latMin, lonMax));
}
QGeoCoordinate ObjectMapItem::getCoordinates()
{
QGeoCoordinate coords;
coords.setLatitude(m_latitude);
coords.setLongitude(m_longitude);
return coords;
}
void ObjectMapItem::findFrequency()
{
// Look for a frequency in the text for this object

View File

@ -41,6 +41,7 @@ public:
MapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem);
virtual void update(SWGSDRangel::SWGMapItem *mapItem);
QGeoCoordinate getCoordinates();
protected:
@ -74,7 +75,6 @@ public:
update(mapItem);
}
void update(SWGSDRangel::SWGMapItem *mapItem) override;
QGeoCoordinate getCoordinates();
protected:
void findFrequency();
@ -143,6 +143,7 @@ protected:
bool m_colorValid;
QRgb m_color;
int m_altitudeReference;
bool m_deleted;
};
class PolylineMapItem : public MapItem {
@ -165,6 +166,7 @@ protected:
bool m_colorValid;
QRgb m_color;
int m_altitudeReference;
bool m_deleted;
};
class ImageMapItem : public MapItem {

View File

@ -87,12 +87,11 @@ void MapModel::update(const QObject *sourcePipe, SWGSDRangel::SWGMapItem *swgMap
QString image = *swgMapItem->getImage();
if (image.isEmpty())
{
// Delete the item
// Delete the item from 2D map
remove(item);
// Need to call update, for it to be removed in 3D map
// Item is set to not be available from this point in time
// It will still be available if time is set in the past
// Delete from 3D map
item->update(swgMapItem);
update3D(item);
}
else
{
@ -178,6 +177,36 @@ MapItem *MapModel::findMapItem(const QObject *source, const QString& name)
return nullptr;
}
// FIXME: This should potentially return a list, as we have have multiple items with the same name
// from different sources
MapItem *MapModel::findMapItem(const QString& name)
{
QListIterator<MapItem *> i(m_items);
while (i.hasNext())
{
MapItem *item = i.next();
if (!item->m_name.compare(name, Qt::CaseInsensitive)) {
return item;
}
}
return nullptr;
}
QModelIndex MapModel::findMapItemIndex(const QString& name)
{
int idx = 0;
QListIterator<MapItem *> i(m_items);
while (i.hasNext())
{
MapItem *item = i.next();
if (item->m_name == name) {
return index(idx);
}
idx++;
}
return index(-1);
}
QHash<int, QByteArray> MapModel::roleNames() const
{
QHash<int, QByteArray> roles;
@ -589,36 +618,6 @@ Q_INVOKABLE void ObjectMapModel::moveToBack(int oldRow)
}
}
// FIXME: This should potentially return a list, as we have have multiple items with the same name
// from different sources
ObjectMapItem *ObjectMapModel::findMapItem(const QString& name)
{
QListIterator<MapItem *> i(m_items);
while (i.hasNext())
{
MapItem *item = i.next();
if (!item->m_name.compare(name, Qt::CaseInsensitive)) {
return (ObjectMapItem *)item;
}
}
return nullptr;
}
QModelIndex ObjectMapModel::findMapItemIndex(const QString& name)
{
int idx = 0;
QListIterator<MapItem *> i(m_items);
while (i.hasNext())
{
MapItem *item = i.next();
if (item->m_name == name) {
return index(idx);
}
idx++;
}
return index(-1);
}
QVariant ObjectMapModel::data(const QModelIndex &index, int role) const
{
int row = index.row();

View File

@ -31,6 +31,7 @@ const QStringList MapSettings::m_pipeTypes = {
QStringLiteral("AIS"),
QStringLiteral("APRS"),
QStringLiteral("APTDemod"),
QStringLiteral("DSCDemod"),
QStringLiteral("FT8Demod"),
QStringLiteral("HeatMap"),
QStringLiteral("ILSDemod"),
@ -46,6 +47,7 @@ const QStringList MapSettings::m_pipeURIs = {
QStringLiteral("sdrangel.feature.ais"),
QStringLiteral("sdrangel.feature.aprs"),
QStringLiteral("sdrangel.channel.aptdemod"),
QStringLiteral("sdrangel.channel.dscdemod"),
QStringLiteral("sdrangel.channel.ft8demod"),
QStringLiteral("sdrangel.channel.heatmap"),
QStringLiteral("sdrangel.channel.ilsdemod"),
@ -79,6 +81,7 @@ MapSettings::MapSettings() :
MapItemSettings *aprsSettings = new MapItemSettings("APRS", true, QColor(255, 255, 0), true, false, 11);
aprsSettings->m_extrapolate = 0;
m_itemSettings.insert("APRS", aprsSettings);
m_itemSettings.insert("DSCDemod", new MapItemSettings("DSCDemod", true, QColor(181, 230, 29), true, true, 3));
m_itemSettings.insert("StarTracker", new MapItemSettings("StarTracker", true, QColor(230, 230, 230), true, true, 3));
m_itemSettings.insert("SatelliteTracker", new MapItemSettings("SatelliteTracker", true, QColor(0, 0, 255), true, false, 0, modelMinPixelSize));
m_itemSettings.insert("Beacons", new MapItemSettings("Beacons", true, QColor(255, 0, 0), false, true, 8));
@ -87,6 +90,7 @@ MapSettings::MapSettings() :
m_itemSettings.insert("Radar", new MapItemSettings("Radar", true, QColor(255, 0, 0), false, true, 8));
m_itemSettings.insert("FT8Demod", new MapItemSettings("FT8Demod", true, QColor(0, 192, 255), true, true, 8));
m_itemSettings.insert("HeatMap", new MapItemSettings("HeatMap", true, QColor(102, 40, 220), true, true, 11));
m_itemSettings.insert("VLF", new MapItemSettings("VLF", false, QColor(255, 0, 0), false, true, 8));
m_itemSettings.insert("AM", new MapItemSettings("AM", false, QColor(255, 0, 0), false, true, 10));
MapItemSettings *fmSettings = new MapItemSettings("FM", false, QColor(255, 0, 0), false, true, 12);

View File

@ -15,6 +15,7 @@ On top of this, it can plot data from other plugins, such as:
* RF Heat Maps from the Heap Map channel,
* Radials and estimated position from the VOR localizer feature,
* ILS course line and glide path from the ILS Demodulator.
* DSC geographic call areas.
As well as internet data sources:
@ -25,6 +26,7 @@ As well as internet data sources:
* GRAVES radar,
* Ionosonde station data,
* Navtex transmitters.
* VLF transmitters.
It can also create tracks showing the path aircraft, ships and APRS objects have taken, as well as predicted paths for satellites.