mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-22 16:08:39 -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:
parent
7fe09b9a20
commit
a111c1f1a0
@ -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);
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,9 +1631,32 @@ void MapGUI::find(const QString& target)
|
||||
m_cesium->track(target);
|
||||
}
|
||||
m_objectMapModel.moveToFront(m_objectMapModel.findMapItemIndex(target).row());
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
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)
|
||||
{
|
||||
@ -1606,7 +1676,6 @@ void MapGUI::find(const QString& target)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MapGUI::track3D(const QString& target)
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user