diff --git a/src/xswiftbus/navdatareference.cpp b/src/xswiftbus/navdatareference.cpp new file mode 100644 index 000000000..c38dcde38 --- /dev/null +++ b/src/xswiftbus/navdatareference.cpp @@ -0,0 +1,39 @@ +/* Copyright (C) 2018 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "navdatareference.h" +#include + +namespace XSwiftBus +{ + + //! Converts degree to radian + inline double degreeToRadian(double angle) + { + return M_PI * angle / 180.0; + } + + //! Returns the great circle distance between to nav data references + double calculateGreatCircleDistance(const CNavDataReference &a, const CNavDataReference &b) + { + const static double c_earthRadiusKm = 6372.8; + + double latRad1 = degreeToRadian(a.latitude()); + double latRad2 = degreeToRadian(b.latitude()); + double lonRad1 = degreeToRadian(a.longitude()); + double lonRad2 = degreeToRadian(b.longitude()); + + double diffLa = latRad2 - latRad1; + double doffLo = lonRad2 - lonRad1; + + double computation = asin(sqrt(sin(diffLa / 2) * sin(diffLa / 2) + cos(latRad1) * cos(latRad2) * sin(doffLo / 2) * sin(doffLo / 2))); + return 2 * c_earthRadiusKm * computation; + } + +} diff --git a/src/xswiftbus/navdatareference.h b/src/xswiftbus/navdatareference.h new file mode 100644 index 000000000..30038a4e7 --- /dev/null +++ b/src/xswiftbus/navdatareference.h @@ -0,0 +1,49 @@ +/* Copyright (C) 2018 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKSIM_XSWIFTBUS_NAVDATAREFERENCE_H +#define BLACKSIM_XSWIFTBUS_NAVDATAREFERENCE_H + +namespace XSwiftBus +{ + //! Simplified version of CNavDataReference of \sa BlackMisc::Simulation::XPlane::CNavDataReference + class CNavDataReference + { + public: + //! Default constructor + CNavDataReference() = default; + + //! Constructor + CNavDataReference(int id, double latitudeDegrees, double longitudeDegrees) + : m_id(id), m_latitudeDegrees(latitudeDegrees), m_longitudeDegrees(longitudeDegrees) + { } + + //! \copydoc BlackMisc::Simulation::XPlane::CNavDataReference::id + int id() const { return m_id; } + + //! \copydoc BlackMisc::Simulation::XPlane::CNavDataReference::latitude + double latitude() const { return m_latitudeDegrees; } + + //! \copydoc BlackMisc::Simulation::XPlane::CNavDataReference::longitude + double longitude() const { return m_longitudeDegrees; } + + private: + int m_id = 0; + double m_latitudeDegrees = 0.0; + double m_longitudeDegrees = 0.0; + }; + + //! Free function to calculate great circle distance + double calculateGreatCircleDistance(const CNavDataReference &a, const CNavDataReference &b); + +} // ns + +#endif // guard diff --git a/src/xswiftbus/service.cpp b/src/xswiftbus/service.cpp index cd3a84e9d..75692b143 100644 --- a/src/xswiftbus/service.cpp +++ b/src/xswiftbus/service.cpp @@ -8,16 +8,19 @@ */ #include "service.h" -#include "blackmisc/simulation/xplane/aircraftmodelloaderxplane.h" #include #include #include #include +#include +#include +#include // clazy:excludeall=reserve-candidates namespace XSwiftBus { + CService::CService(CDBusConnection *connection) : CDBusObject(connection) { registerDBusObjectPath(XSWIFTBUS_SERVICE_INTERFACENAME, XSWIFTBUS_SERVICE_OBJECTPATH); @@ -33,7 +36,7 @@ namespace XSwiftBus char filename[256]; char path[512]; XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path); - const auto model = BlackMisc::Simulation::XPlane::CAircraftModelLoaderXPlane::extractAcfProperties(path, QFileInfo(path)); + const auto model = extractAcfProperties(path, QFileInfo(path)); emitAircraftModelChanged(path, filename, getAircraftLivery(), getAircraftIcaoCode(), model.getModelString(), model.getName(), getAircraftDescription()); } @@ -82,7 +85,7 @@ namespace XSwiftBus char filename[256]; char path[512]; XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path); - const auto model = BlackMisc::Simulation::XPlane::CAircraftModelLoaderXPlane::extractAcfProperties(path, QFileInfo(path)); + const auto model = extractAcfProperties(path, QFileInfo(path)); return model.getModelString(); } @@ -91,7 +94,7 @@ namespace XSwiftBus char filename[256]; char path[512]; XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path); - const auto model = BlackMisc::Simulation::XPlane::CAircraftModelLoaderXPlane::extractAcfProperties(path, QFileInfo(path)); + const auto model = extractAcfProperties(path, QFileInfo(path)); return model.getName(); } @@ -138,8 +141,7 @@ namespace XSwiftBus XPLMGetNavAidInfo(i, nullptr, &lat, &lon, nullptr, nullptr, nullptr, icao, nullptr, nullptr); if (icao[0] != 0) { - using namespace BlackMisc::Math; - m_airports.push_back(BlackMisc::Simulation::XPlane::CNavDataReference(i, lat, lon)); + m_airports.emplace_back(i, lat, lon); } } } @@ -147,15 +149,14 @@ namespace XSwiftBus void CService::updateAirportsInRange() { - if (m_airports.isEmpty()) + if (m_airports.empty()) { readAirportsDatabase(); } - using namespace BlackMisc::Math; - using namespace BlackMisc::Geo; std::vector icaos, names; std::vector lats, lons, alts; - for (const auto &navref : m_airports.findClosest(20, CCoordinateGeodetic(getLatitude(), getLongitude(), 0))) + std::vector closestAirports = findClosestAirports(20, getLatitude(), getLongitude()); + for (const auto &navref : closestAirports) { float lat, lon, alt; char icao[32], name[256]; @@ -661,4 +662,121 @@ namespace XSwiftBus sendDBusMessage(signalAirportsInRangeUpdated); } + std::vector CService::findClosestAirports(int number, double latitude, double longitude) + { + CNavDataReference ref(0, latitude, longitude); + auto compareFunction = [ & ](const CNavDataReference & a, const CNavDataReference & b) + { + return calculateGreatCircleDistance(a, ref) < calculateGreatCircleDistance(b, ref); + }; + + auto closestAirports = m_airports; + std::partial_sort(closestAirports.begin(), closestAirports.begin() + number, closestAirports.end(), compareFunction); + closestAirports.resize(number); + return closestAirports; + } + + QString descriptionForFlyableModel(const CAircraftModel &model) + { + if (!model.getName().isEmpty()) + { + if (model.getDistributor().hasDescription() && !model.getName().contains(model.getDistributor().getDescription())) + { + return QStringLiteral("[ACF] ") % model.getName() % QStringLiteral(" by ") % model.getDistributor().getDescription(); + } + else + { + return QStringLiteral("[ACF] ") % model.getName(); + } + } + else if (model.hasAircraftDesignator()) + { + if (model.getDistributor().hasDescription()) + { + return QStringLiteral("[ACF] ") % model.getAircraftIcaoCodeDesignator() % QStringLiteral(" by ") % model.getDistributor().getDescription(); + } + else + { + return QStringLiteral("[ACF] ") % model.getAircraftIcaoCodeDesignator(); + } + } + return QStringLiteral("[ACF]"); + } + + QString stringForFlyableModel(const CAircraftModel &model, const QFileInfo &acfFile) + { + if (model.getDistributor().hasDescription()) + { + if (!model.getName().isEmpty()) + { + if (model.getName().contains(model.getDistributor().getDescription())) + { + return model.getName(); + } + else + { + return model.getDistributor().getDescription() % ' ' % model.getName(); + } + } + else if (model.hasAircraftDesignator()) + { + return model.getDistributor().getDescription() % ' ' % model.getAircraftIcaoCodeDesignator(); + } + } + return acfFile.dir().dirName() % ' ' % acfFile.baseName(); + } + + CAircraftModel CService::extractAcfProperties(const QString &filePath, const QFileInfo &fileInfo) + { + CAircraftModel model; + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return model; } + + QTextStream ts(&file); + if (ts.readLine() == "I" && ts.readLine().contains("version") && ts.readLine() == "ACF") + { + while (!ts.atEnd()) + { + const QString line = ts.readLine(); + QVector tokens = line.splitRef(' ', QString::SkipEmptyParts); + if (tokens.size() < 3 || tokens.at(0) != QLatin1String("P")) { continue; } + if (tokens.at(1) == QLatin1String("acf/_ICAO")) + { + const QString icao(tokens.at(2).toString()); + model.setAircraftIcaoCode(icao); + } + else if (tokens.at(1) == QLatin1String("acf/_descrip")) + { + const QString desc(line.mid(tokens.at(2).position())); + model.setDescription("[ACF] " % desc); + } + else if (tokens.at(1) == QLatin1String("acf/_name")) + { + const QString name(line.mid(tokens.at(2).position())); + model.setName(name); + } + else if (tokens.at(1) == QLatin1String("acf/_studio")) + { + const CDistributor dist(line.mid(tokens.at(2).position())); + model.setDistributor(dist); + } + else if (tokens.at(1) == QLatin1String("acf/_author")) + { + if (model.getDistributor().hasDescription()) { continue; } + thread_local const QRegularExpression end("\\W\\s", QRegularExpression::UseUnicodePropertiesOption); + QString author = line.mid(tokens.at(2).position()); + author = author.left(author.indexOf(end)).trimmed(); + if (author.isEmpty()) { continue; } + const CDistributor dist(author); + model.setDistributor(dist); + } + } + } + file.close(); + + model.setModelString(stringForFlyableModel(model, fileInfo)); + if (!model.hasDescription()) { model.setDescription(descriptionForFlyableModel(model)); } + return model; + } + } diff --git a/src/xswiftbus/service.h b/src/xswiftbus/service.h index f125a8c22..609946666 100644 --- a/src/xswiftbus/service.h +++ b/src/xswiftbus/service.h @@ -19,11 +19,12 @@ #include "dbusobject.h" #include "datarefs.h" #include "messages.h" -#include "blackmisc/simulation/xplane/navdatareference.h" +#include "navdatareference.h" #include #include #include #include +#include class QTimer; @@ -35,6 +36,68 @@ class QTimer; namespace XSwiftBus { + //! Simplified implementation of \sa BlackMisc::Simulation::CDistributor + class CDistributor + { + public: + CDistributor() = default; + CDistributor(const QString &distributor) : m_distributor(distributor) {} + + bool hasDescription() const { return !m_description.isEmpty(); } + QString getDescription() const { return m_description; } + + private: + QString m_distributor; + QString m_description; + }; + + //! Simplified implementation of \sa BlackMisc::Simulation::CAircraftModel + class CAircraftModel + { + public: + CAircraftModel() = default; + + //! \copydoc BlackMisc::Simulation::CAircraftModel::hasDescription + bool hasDescription() const { return !m_description.isEmpty(); } + + //! \copydoc BlackMisc::Simulation::CAircraftModel::hasAircraftDesignator + bool hasAircraftDesignator() const { return !m_icao.isEmpty(); } + + //! \copydoc BlackMisc::Simulation::CAircraftModel::getName + QString getName() const { return m_name; } + + //! \copydoc BlackMisc::Simulation::CAircraftModel::getDistributor + CDistributor getDistributor() const { return m_distributor; } + + //! \copydoc BlackMisc::Simulation::CAircraftModel::getAircraftIcaoCodeDesignator + QString getAircraftIcaoCodeDesignator() const { return m_icao; } + + //! \copydoc BlackMisc::Simulation::CAircraftModel::getModelString + QString getModelString() const { return m_modelString; } + + //! \copydoc BlackMisc::Simulation::CAircraftModel::setAircraftIcaoCode + void setAircraftIcaoCode(const QString &icao) { m_icao = icao; } + + //! \copydoc BlackMisc::Simulation::CAircraftModel::setDescription + void setDescription(const QString &description) { m_description = description; } + + //! \copydoc BlackMisc::Simulation::CAircraftModel::setName + void setName(const QString &name) { m_name = name; } + + //! \copydoc BlackMisc::Simulation::CAircraftModel::setDistributor + void setDistributor(const CDistributor &distributor) { m_distributor = distributor; } + + //! \copydoc BlackMisc::Simulation::CAircraftModel::setModelString + void setModelString(const QString &modelString) { m_modelString = modelString; } + + private: + QString m_name; + QString m_icao; + QString m_description; + CDistributor m_distributor; + QString m_modelString; + }; + /*! * XSwiftBus service object which is accessible through DBus */ @@ -244,10 +307,14 @@ namespace XSwiftBus const std::vector &lats, const std::vector &lons, const std::vector &alts); CMessageBoxControl m_messages { 128, 128, 16 }; - BlackMisc::Simulation::XPlane::CNavDataReferenceList m_airports; + std::vector m_airports; QTimer *m_airportUpdater = nullptr; void readAirportsDatabase(); + std::vector findClosestAirports(int number, double latitude, double longitude); + + static CAircraftModel extractAcfProperties(const QString &filePath, const QFileInfo &fileInfo); + StringDataRef m_liveryPath; StringDataRef m_icao; StringDataRef m_descrip; diff --git a/src/xswiftbus/traffic.cpp b/src/xswiftbus/traffic.cpp index e962c3532..06be601ba 100644 --- a/src/xswiftbus/traffic.cpp +++ b/src/xswiftbus/traffic.cpp @@ -14,7 +14,6 @@ #endif #include "traffic.h" #include "utils.h" -#include "blackmisc/verify.h" #include "XPMPMultiplayer.h" #include "XPMPPlaneRenderer.h" #include @@ -22,6 +21,7 @@ #include #include #include +#include #include #include @@ -218,8 +218,7 @@ namespace XSwiftBus const QList planes = m_planesByCallsign.values(); for (Plane *plane : planes) { - BLACK_VERIFY_X(plane, Q_FUNC_INFO, "Missing Plane"); - if (!plane) { continue; } + assert(plane); XPMPDestroyPlane(plane->id); delete plane; } @@ -281,9 +280,7 @@ namespace XSwiftBus const QList planes = m_planesByCallsign.values(); for (const Plane *plane : planes) { - BLACK_VERIFY_X(plane, Q_FUNC_INFO, "Missing Plane"); - if (!plane) { continue; } - + assert(plane); double lat = plane->position.lat; double lon = plane->position.lon; double elevation = plane->position.elevation; diff --git a/src/xswiftbus/xswiftbus.pro b/src/xswiftbus/xswiftbus.pro index e2055b361..8bbf054f4 100644 --- a/src/xswiftbus/xswiftbus.pro +++ b/src/xswiftbus/xswiftbus.pro @@ -5,7 +5,6 @@ QT += core gui widgets dbus network TEMPLATE = lib CONFIG += shared plugin -CONFIG += blackmisc INCLUDEPATH += $$EXTERNALSROOT/common/include/XPLM