1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-02-03 09:44:01 -05: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 if ( !mapItem->m_itemSettings->m_enabled
|| !mapItem->m_itemSettings->m_display3DTrack || !mapItem->m_itemSettings->m_display3DTrack
|| filter(mapItem) || filter(mapItem)
|| mapItem->m_deleted
) )
{ {
// Delete obj completely (including any history) // Delete obj completely (including any history)
@ -147,6 +148,15 @@ QJsonObject CZML::update(PolygonMapItem *mapItem)
polygon.insert("extrudedHeight", mapItem->m_extrudedHeight); 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("polygon", polygon);
obj.insert("description", mapItem->m_label); obj.insert("description", mapItem->m_label);
@ -165,6 +175,7 @@ QJsonObject CZML::update(PolylineMapItem *mapItem)
if ( !mapItem->m_itemSettings->m_enabled if ( !mapItem->m_itemSettings->m_enabled
|| !mapItem->m_itemSettings->m_display3DTrack || !mapItem->m_itemSettings->m_display3DTrack
|| filter(mapItem) || filter(mapItem)
|| mapItem->m_deleted
) )
{ {
// Delete obj completely (including any history) // 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 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("polyline", polyline);
obj.insert("description", mapItem->m_label); obj.insert("description", mapItem->m_label);

View File

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

View File

@ -309,6 +309,7 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur
addAirspace(); addAirspace();
addAirports(); addAirports();
addNavtex(); addNavtex();
addVLF();
displaySettings(); displaySettings();
applySettings(true); 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 = { const QList<RadioTimeTransmitter> MapGUI::m_radioTimeTransmitters = {
{"MSF", 60000, 54.9075f, -3.27333f, 17}, // UK {"MSF", 60000, 54.9075f, -3.27333f, 17}, // UK
{"DCF77", 77500, 50.01611111f, 9.00805556f, 50}, // Germany {"DCF77", 77500, 50.01611111f, 9.00805556f, 50}, // Germany
@ -1575,8 +1623,7 @@ void MapGUI::find(const QString& target)
} }
else else
{ {
// FIXME: Support polygon/polyline ObjectMapItem *mapItem = (ObjectMapItem *)m_objectMapModel.findMapItem(target);
ObjectMapItem *mapItem = m_objectMapModel.findMapItem(target);
if (mapItem != nullptr) if (mapItem != nullptr)
{ {
map->setProperty("center", QVariant::fromValue(mapItem->getCoordinates())); map->setProperty("center", QVariant::fromValue(mapItem->getCoordinates()));
@ -1584,25 +1631,47 @@ void MapGUI::find(const QString& target)
m_cesium->track(target); m_cesium->track(target);
} }
m_objectMapModel.moveToFront(m_objectMapModel.findMapItemIndex(target).row()); 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 else
{ {
QGeoServiceProvider* geoSrv = new QGeoServiceProvider("osm"); qDebug() << "MapGUI::find: osm not available";
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";
}
} }
} }
} }

View File

@ -39,6 +39,14 @@ void MapItem::update(SWGSDRangel::SWGMapItem *mapItem)
m_altitude = mapItem->getAltitude(); 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) void ObjectMapItem::update(SWGSDRangel::SWGMapItem *mapItem)
{ {
MapItem::update(mapItem); MapItem::update(mapItem);
@ -116,6 +124,7 @@ void PolygonMapItem::update(SWGSDRangel::SWGMapItem *mapItem)
m_colorValid = mapItem->getColorValid(); m_colorValid = mapItem->getColorValid();
m_color = mapItem->getColor(); m_color = mapItem->getColor();
m_altitudeReference = mapItem->getAltitudeReference(); m_altitudeReference = mapItem->getAltitudeReference();
m_deleted = *mapItem->getImage() == "";
qDeleteAll(m_points); qDeleteAll(m_points);
m_points.clear(); m_points.clear();
@ -151,6 +160,7 @@ void PolylineMapItem::update(SWGSDRangel::SWGMapItem *mapItem)
m_colorValid = mapItem->getColorValid(); m_colorValid = mapItem->getColorValid();
m_color = mapItem->getColor(); m_color = mapItem->getColor();
m_altitudeReference = mapItem->getAltitudeReference(); m_altitudeReference = mapItem->getAltitudeReference();
m_deleted = *mapItem->getImage() == "";
qDeleteAll(m_points); qDeleteAll(m_points);
m_points.clear(); m_points.clear();
@ -180,14 +190,6 @@ void PolylineMapItem::update(SWGSDRangel::SWGMapItem *mapItem)
m_bounds = QGeoRectangle(QGeoCoordinate(latMax, lonMin), QGeoCoordinate(latMin, lonMax)); 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() void ObjectMapItem::findFrequency()
{ {
// Look for a frequency in the text for this object // 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); MapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem);
virtual void update(SWGSDRangel::SWGMapItem *mapItem); virtual void update(SWGSDRangel::SWGMapItem *mapItem);
QGeoCoordinate getCoordinates();
protected: protected:
@ -74,7 +75,6 @@ public:
update(mapItem); update(mapItem);
} }
void update(SWGSDRangel::SWGMapItem *mapItem) override; void update(SWGSDRangel::SWGMapItem *mapItem) override;
QGeoCoordinate getCoordinates();
protected: protected:
void findFrequency(); void findFrequency();
@ -143,6 +143,7 @@ protected:
bool m_colorValid; bool m_colorValid;
QRgb m_color; QRgb m_color;
int m_altitudeReference; int m_altitudeReference;
bool m_deleted;
}; };
class PolylineMapItem : public MapItem { class PolylineMapItem : public MapItem {
@ -165,6 +166,7 @@ protected:
bool m_colorValid; bool m_colorValid;
QRgb m_color; QRgb m_color;
int m_altitudeReference; int m_altitudeReference;
bool m_deleted;
}; };
class ImageMapItem : public MapItem { class ImageMapItem : public MapItem {

View File

@ -87,12 +87,11 @@ void MapModel::update(const QObject *sourcePipe, SWGSDRangel::SWGMapItem *swgMap
QString image = *swgMapItem->getImage(); QString image = *swgMapItem->getImage();
if (image.isEmpty()) if (image.isEmpty())
{ {
// Delete the item // Delete the item from 2D map
remove(item); remove(item);
// Need to call update, for it to be removed in 3D map // Delete from 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
item->update(swgMapItem); item->update(swgMapItem);
update3D(item);
} }
else else
{ {
@ -178,6 +177,36 @@ MapItem *MapModel::findMapItem(const QObject *source, const QString& name)
return nullptr; 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> MapModel::roleNames() const
{ {
QHash<int, QByteArray> roles; 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 QVariant ObjectMapModel::data(const QModelIndex &index, int role) const
{ {
int row = index.row(); int row = index.row();

View File

@ -31,6 +31,7 @@ const QStringList MapSettings::m_pipeTypes = {
QStringLiteral("AIS"), QStringLiteral("AIS"),
QStringLiteral("APRS"), QStringLiteral("APRS"),
QStringLiteral("APTDemod"), QStringLiteral("APTDemod"),
QStringLiteral("DSCDemod"),
QStringLiteral("FT8Demod"), QStringLiteral("FT8Demod"),
QStringLiteral("HeatMap"), QStringLiteral("HeatMap"),
QStringLiteral("ILSDemod"), QStringLiteral("ILSDemod"),
@ -46,6 +47,7 @@ const QStringList MapSettings::m_pipeURIs = {
QStringLiteral("sdrangel.feature.ais"), QStringLiteral("sdrangel.feature.ais"),
QStringLiteral("sdrangel.feature.aprs"), QStringLiteral("sdrangel.feature.aprs"),
QStringLiteral("sdrangel.channel.aptdemod"), QStringLiteral("sdrangel.channel.aptdemod"),
QStringLiteral("sdrangel.channel.dscdemod"),
QStringLiteral("sdrangel.channel.ft8demod"), QStringLiteral("sdrangel.channel.ft8demod"),
QStringLiteral("sdrangel.channel.heatmap"), QStringLiteral("sdrangel.channel.heatmap"),
QStringLiteral("sdrangel.channel.ilsdemod"), QStringLiteral("sdrangel.channel.ilsdemod"),
@ -79,6 +81,7 @@ MapSettings::MapSettings() :
MapItemSettings *aprsSettings = new MapItemSettings("APRS", true, QColor(255, 255, 0), true, false, 11); MapItemSettings *aprsSettings = new MapItemSettings("APRS", true, QColor(255, 255, 0), true, false, 11);
aprsSettings->m_extrapolate = 0; aprsSettings->m_extrapolate = 0;
m_itemSettings.insert("APRS", aprsSettings); 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("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("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)); 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("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("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("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)); 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); 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, * RF Heat Maps from the Heap Map channel,
* Radials and estimated position from the VOR localizer feature, * Radials and estimated position from the VOR localizer feature,
* ILS course line and glide path from the ILS Demodulator. * ILS course line and glide path from the ILS Demodulator.
* DSC geographic call areas.
As well as internet data sources: As well as internet data sources:
@ -25,6 +26,7 @@ As well as internet data sources:
* GRAVES radar, * GRAVES radar,
* Ionosonde station data, * Ionosonde station data,
* Navtex transmitters. * 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. It can also create tracks showing the path aircraft, ships and APRS objects have taken, as well as predicted paths for satellites.