mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 13:00:26 -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:
		
							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) | ||||
|                 { | ||||
| @ -1607,7 +1677,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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user