1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-07-31 21:12:28 -04:00

Use combined aircraft database.

Use png rather than bmp.
Add sideview images.
This commit is contained in:
srcejon 2025-06-04 20:22:09 +01:00
parent 276083d3e8
commit 4678abf091
2 changed files with 193 additions and 36 deletions

View File

@ -28,9 +28,11 @@
#endif
#include "util/osndb.h"
#include "util/corsproxy.h"
QHash<QString, QIcon *> AircraftInformation::m_airlineIcons;
QHash<QString, bool> AircraftInformation::m_airlineMissingIcons;
QHash<QString, QIcon *> AircraftInformation::m_sideviewIcons;
QHash<QString, QIcon *> AircraftInformation::m_flagIcons;
QHash<QString, QString> *AircraftInformation::m_prefixMap;
QHash<QString, QString> *AircraftInformation::m_militaryMap;
@ -38,6 +40,7 @@ QMutex AircraftInformation::m_mutex;
QSharedPointer<const QHash<int, AircraftInformation *>> OsnDB::m_aircraftInformation;
QSharedPointer<const QHash<QString, AircraftInformation *>> OsnDB::m_aircraftInformationByReg;
QSharedPointer<const QHash<QString, AircraftRouteInformation *>> OsnDB::m_aircraftRouteInformation;
QDateTime OsnDB::m_modifiedDateTime;
@ -54,9 +57,9 @@ OsnDB::~OsnDB()
void OsnDB::downloadAircraftInformation()
{
QString filename = OsnDB::getOSNDBZipFilename();
QString filename = OsnDB::getZipFilename();
QString urlString = OSNDB_URL;
QUrl dbURL(urlString);
QUrl dbURL(CORSProxy::adjustHost(urlString));
qDebug() << "OsnDB::downloadAircraftInformation: Downloading " << urlString;
emit downloadingURL(urlString);
QNetworkReply *reply = m_dlm.download(dbURL, filename);
@ -72,38 +75,18 @@ void OsnDB::downloadFinished(const QString& filename, bool success)
qWarning() << "OsnDB::downloadFinished: Failed to download: " << filename;
emit downloadError(QString("Failed to download: %1").arg(filename));
}
else if (filename == OsnDB::getOSNDBZipFilename())
else if (filename == OsnDB::getZipFilename())
{
// Extract .csv file from .zip file
QZipReader reader(filename);
QByteArray database = reader.fileData("media/data/samples/metadata/aircraftDatabase.csv");
if (database.size() > 0)
if (reader.extractAll(getDataDir()))
{
QFile file(OsnDB::getOSNDBFilename());
if (file.open(QIODevice::WriteOnly))
{
file.write(database);
file.close();
emit downloadAircraftInformationFinished();
}
else
{
qWarning() << "OsnDB::downloadFinished - Failed to open " << file.fileName() << " for writing";
emit downloadError(QString("Failed to open %1 for writing").arg(file.fileName()));
}
emit downloadAircraftInformationFinished();
}
else
{
qWarning() << "OsnDB::downloadFinished - aircraftDatabase.csv not in expected dir. Extracting all.";
if (reader.extractAll(getDataDir()))
{
emit downloadAircraftInformationFinished();
}
else
{
qWarning() << "OsnDB::downloadFinished - Failed to extract files from " << filename;
emit downloadError(QString("Failed to extract files from ").arg(filename));
}
qWarning() << "OsnDB::downloadFinished - Failed to extract files from " << filename;
emit downloadError(QString("Failed to extract files from ").arg(filename));
}
}
else
@ -153,6 +136,14 @@ QSharedPointer<const QHash<QString, AircraftInformation *>> OsnDB::getAircraftIn
return m_aircraftInformationByReg;
}
QSharedPointer<const QHash<QString, AircraftRouteInformation *>> OsnDB::getAircraftRouteInformation()
{
if (!m_aircraftRouteInformation) {
m_aircraftRouteInformation = QSharedPointer<const QHash<QString, AircraftRouteInformation *>>(OsnDB::readRouteDB(getRouteDBFilename()));
}
return m_aircraftRouteInformation;
}
QHash<int, AircraftInformation *> *OsnDB::readOSNDB(const QString &filename)
{
int cnt = 0;
@ -163,6 +154,7 @@ QHash<int, AircraftInformation *> *OsnDB::readOSNDB(const QString &filename)
int registrationCol = 1;
int manufacturerNameCol = 3;
int modelCol = 4;
int typeCodeCol = 5;
int ownerCol = 13;
int operatorCol = 9;
int operatorICAOCol = 11;
@ -193,6 +185,8 @@ QHash<int, AircraftInformation *> *OsnDB::readOSNDB(const QString &filename)
manufacturerNameCol = idx;
else if (!strcmp(p, "model"))
modelCol = idx;
else if (!strcmp(p, "typecode"))
typeCodeCol = idx;
else if (!strcmp(p, "owner"))
ownerCol = idx;
else if (!strcmp(p, "operator"))
@ -215,6 +209,8 @@ QHash<int, AircraftInformation *> *OsnDB::readOSNDB(const QString &filename)
size_t manufacturerNameLen = 0;
char *model = NULL;
size_t modelLen = 0;
char *typeCode = NULL;
size_t typeCodeLen = 0;
char *owner = NULL;
size_t ownerLen = 0;
char *operatorName = NULL;
@ -264,6 +260,12 @@ QHash<int, AircraftInformation *> *OsnDB::readOSNDB(const QString &filename)
modelLen = strlen(model)-1;
model[modelLen] = '\0';
}
else if (idx == typeCodeCol)
{
typeCode = p+1;
typeCodeLen = strlen(typeCode)-1;
typeCode[typeCodeLen] = '\0';
}
else if (idx == ownerCol)
{
owner = p+1;
@ -315,6 +317,7 @@ QHash<int, AircraftInformation *> *OsnDB::readOSNDB(const QString &filename)
aircraft->m_registration = QString(registration);
aircraft->m_manufacturerName = QString(manufacturerName);
aircraft->m_model = modelQ;
aircraft->m_type = QString(typeCode);
aircraft->m_owner = QString(owner);
aircraft->m_operator = QString(operatorName);
aircraft->m_operatorICAO = QString(operatorICAO);
@ -353,7 +356,7 @@ bool OsnDB::writeFastDB(const QString &filename, const QHash<int, AircraftInform
QFile file(filename);
if (file.open(QIODevice::WriteOnly))
{
file.write("icao24,registration,manufacturername,model,owner,operator,operatoricao,registered\n");
file.write("icao24,registration,manufacturername,model,typecode,owner,operator,operatoricao,registered\n");
QHash<int, AircraftInformation *>::const_iterator i = aircraftInfo->begin();
while (i != aircraftInfo->end())
{
@ -366,6 +369,8 @@ bool OsnDB::writeFastDB(const QString &filename, const QHash<int, AircraftInform
file.write(",");
file.write(info->m_model.toUtf8());
file.write(",");
file.write(info->m_type.toUtf8());
file.write(",");
file.write(info->m_owner.toUtf8());
file.write(",");
file.write(info->m_operator.toUtf8());
@ -402,7 +407,7 @@ QHash<int, AircraftInformation *> *OsnDB::readFastDB(const QString &filename)
if (fgets(row, sizeof(row), file))
{
// Check header
if (!strcmp(row, "icao24,registration,manufacturername,model,owner,operator,operatoricao,registered\n"))
if (!strcmp(row, "icao24,registration,manufacturername,model,typecode,owner,operator,operatoricao,registered\n"))
{
aircraftInfo = new QHash<int, AircraftInformation *>();
aircraftInfo->reserve(500000);
@ -417,6 +422,7 @@ QHash<int, AircraftInformation *> *OsnDB::readFastDB(const QString &filename)
aircraft->m_registration = QString(csvNext(&p));
aircraft->m_manufacturerName = QString(csvNext(&p));
aircraft->m_model = QString(csvNext(&p));
aircraft->m_type = QString(csvNext(&p));
aircraft->m_owner = QString(csvNext(&p));
aircraft->m_operator = QString(csvNext(&p));
aircraft->m_operatorICAO = QString(csvNext(&p));
@ -426,7 +432,7 @@ QHash<int, AircraftInformation *> *OsnDB::readFastDB(const QString &filename)
}
}
else
qDebug() << "AircraftInformation::readFastDB: Unexpected header";
qDebug() << "AircraftInformation::readFastDB: Unexpected header" << row;
}
else
qDebug() << "AircraftInformation::readFastDB: Empty file";
@ -440,6 +446,60 @@ QHash<int, AircraftInformation *> *OsnDB::readFastDB(const QString &filename)
return aircraftInfo;
}
QHash<QString, AircraftRouteInformation *> *OsnDB::readRouteDB(const QString &filename)
{
int cnt = 0;
QHash<QString, AircraftRouteInformation *> *routeInfo = nullptr;
qDebug() << "AircraftInformation::readRouteDB: " << filename;
FILE *file;
QByteArray utfFilename = filename.toUtf8();
if ((file = fopen(utfFilename.constData(), "r")) != NULL)
{
char row[2048];
if (fgets(row, sizeof(row), file))
{
// Check header
if (!strcmp(row, "callsign,dep,arr,stops\n"))
{
routeInfo = new QHash<QString, AircraftRouteInformation *>();
routeInfo->reserve(600000);
// Read data
while (fgets(row, sizeof(row), file))
{
char *p = row;
AircraftRouteInformation *route = new AircraftRouteInformation();
route->m_callsign = QString(csvNext(&p));
route->m_dep = QString(csvNext(&p));
route->m_arr = QString(csvNext(&p));
route->m_stops = QString(csvNext(&p));
routeInfo->insert(route->m_callsign, route);
cnt++;
}
}
else
{
qDebug() << "AircraftInformation::readRouteDB: Unexpected header" << row;
}
}
else
{
qDebug() << "AircraftInformation::readRouteDB: Empty file";
}
fclose(file);
}
else
{
qDebug() << "AircraftInformation::readRouteDB: Failed to open " << filename;
}
qDebug() << "AircraftInformation::readRouteDB - read " << cnt << " routes";
return routeInfo;
}
QString AircraftInformation::getFlag() const
{
QString flag;
@ -499,7 +559,7 @@ QString AircraftInformation::getFlag() const
QString AircraftInformation::getAirlineIconPath(const QString &operatorICAO)
{
QString endPath = QString("/airlinelogos/%1.bmp").arg(operatorICAO);
QString endPath = QString("/airlinelogos/%1.png").arg(operatorICAO);
// Try in user directory first, so they can customise
QString userIconPath = OsnDB::getDataDir() + endPath;
QFile file(userIconPath);
@ -539,7 +599,7 @@ QIcon *AircraftInformation::getAirlineIcon(const QString &operatorICAO)
{
if (!m_airlineMissingIcons.contains(operatorICAO))
{
qDebug() << "ADSBDemodGUI: No airline logo for " << operatorICAO;
qDebug() << "AircraftInformation: No airline logo for " << operatorICAO;
m_airlineMissingIcons.insert(operatorICAO, true);
}
}
@ -547,6 +607,75 @@ QIcon *AircraftInformation::getAirlineIcon(const QString &operatorICAO)
}
}
QString AircraftInformation::getSideviewIconPath(const QString &registration, const QString &operatorICAO, const QString &modelICAO)
{
QString p1 = QString(":/sideviews/%1.png").arg(registration);
QResource r1(p1);
if (r1.isValid()) {
return p1;
}
QString opModel = operatorICAO + modelICAO;
QString p2 = QString(":/sideviews/%1.png").arg(opModel);
QResource r2(p2);
if (r2.isValid()) {
return p2;
}
QString p3 = QString(":/sideviews/%1.png").arg(modelICAO);
QResource r3(p3);
if (r3.isValid()) {
return p3;
}
return QString();
}
QIcon *AircraftInformation::getSideviewIcon(const QString &registration, const QString &operatorICAO, const QString &modelICAO)
{
QIcon *icon = nullptr;
if (m_sideviewIcons.contains(registration)) {
return m_sideviewIcons.value(registration);
}
QString p1 = QString(":/sideviews/%1.png").arg(registration);
QResource r1(p1);
if (r1.isValid())
{
icon = new QIcon(p1);
m_sideviewIcons.insert(registration, icon);
return icon;
}
QString opModel = operatorICAO + modelICAO;
if (m_sideviewIcons.contains(opModel)) {
return m_sideviewIcons.value(opModel);
}
QString p2 = QString(":/sideviews/%1.png").arg(opModel);
QResource r2(p2);
if (r2.isValid())
{
icon = new QIcon(p2);
m_sideviewIcons.insert(opModel, icon);
return icon;
}
if (m_sideviewIcons.contains(modelICAO)) {
return m_sideviewIcons.value(modelICAO);
}
QString p3 = QString(":/sideviews/%1.png").arg(modelICAO);
QResource r3(p3);
if (r3.isValid())
{
icon = new QIcon(p3);
m_sideviewIcons.insert(modelICAO, icon);
return icon;
}
qDebug() << "AircraftInformation: No sideview for " << opModel;
return nullptr;
}
QString AircraftInformation::getFlagIconPath(const QString &country)
{
QString endPath = QString("/flags/%1.bmp").arg(country);
@ -572,9 +701,13 @@ QString AircraftInformation::getFlagIconPath(const QString &country)
QString AircraftInformation::getFlagIconURL(const QString &country)
{
QString path = getFlagIconPath(country);
return resourcePathToURL(getFlagIconPath(country));
}
QString AircraftInformation::resourcePathToURL(const QString &path)
{
if (path.startsWith(':')) {
path = "qrc://" + path.mid(1);
return "qrc://" + path.mid(1);
}
return path;
}

View File

@ -34,7 +34,15 @@
#include "util/httpdownloadmanager.h"
#include "export.h"
#define OSNDB_URL "https://s3.opensky-network.org/data-samples/metadata/aircraftDatabase.zip"
//#define OSNDB_URL "https://s3.opensky-network.org/data-samples/metadata/aircraftDatabase.zip"
#define OSNDB_URL "https://sdrangel.org/downloads/aircraftDatabase.zip"
struct SDRBASE_API AircraftRouteInformation {
QString m_callsign; // Aircraft callsign
QString m_dep; // Departure airport ICAO
QString m_arr; // Arrival airport ICAO
QString m_stops; // Airport ICAO of stops on route '-' separated list
};
struct SDRBASE_API AircraftInformation {
@ -42,6 +50,7 @@ struct SDRBASE_API AircraftInformation {
QString m_registration;
QString m_manufacturerName;
QString m_model;
QString m_type;
QString m_owner;
QString m_operator;
QString m_operatorICAO;
@ -68,16 +77,22 @@ struct SDRBASE_API AircraftInformation {
// Try to find an airline logo based on ICAO
static QIcon *getAirlineIcon(const QString &operatorICAO);
static QIcon *getSideviewIcon(const QString &registration, const QString &operatorICAO, const QString &modelICAO);
static QString getSideviewIconPath(const QString &registration, const QString &operatorICAO, const QString &modelICAO);
static QString getFlagIconPath(const QString &country);
static QString getFlagIconURL(const QString &country);
// Try to find an flag logo based on a country
static QIcon *getFlagIcon(const QString &country);
static QString resourcePathToURL(const QString &path);
private:
static QHash<QString, QIcon *> m_airlineIcons; // Hashed on airline ICAO
static QHash<QString, bool> m_airlineMissingIcons; // Hash containing which ICAOs we don't have icons for
static QHash<QString, QIcon *> m_sideviewIcons;
static QHash<QString, QIcon *> m_flagIcons; // Hashed on country
static QHash<QString, QString> *m_prefixMap; // Registration to country (flag name)
static QHash<QString, QString> *m_militaryMap; // Operator airforce to military (flag name)
@ -97,8 +112,9 @@ public:
static QSharedPointer<const QHash<int, AircraftInformation *>> getAircraftInformation();
static QSharedPointer<const QHash<QString, AircraftInformation *>> getAircraftInformationByReg();
static QSharedPointer<const QHash<QString, AircraftRouteInformation *>> getAircraftRouteInformation();
static QString getOSNDBZipFilename()
static QString getZipFilename()
{
return getDataDir() + "/aircraftDatabase.zip";
}
@ -121,6 +137,7 @@ private:
static QSharedPointer<const QHash<int, AircraftInformation *>> m_aircraftInformation;
static QSharedPointer<const QHash<QString, AircraftInformation *>> m_aircraftInformationByReg;
static QSharedPointer<const QHash<QString, AircraftRouteInformation *>> m_aircraftRouteInformation;
static QDateTime m_modifiedDateTime;
// Write a reduced size and validated version of the DB, so it loads quicker
@ -129,6 +146,8 @@ private:
// Read smaller CSV file with no validation. Takes about 0.5s instead of 2s.
static QHash<int, AircraftInformation *> *readFastDB(const QString &filename);
static QHash<QString, AircraftRouteInformation *> *readRouteDB(const QString &filename);
// Read OpenSky Network CSV file
// This is large and contains lots of data we don't want, so we convert to
// a smaller version to speed up loading time
@ -141,6 +160,11 @@ private:
return getDataDir() + "/aircraftDatabaseFast.csv";
}
static QString getRouteDBFilename()
{
return getDataDir() + "/aircraftRouteDatabase.csv";
}
// Create hash table using registration as key
static QHash<QString, AircraftInformation *> *registrationHash(const QHash<int, AircraftInformation *> *in);