diff --git a/samples/blackmiscsim/main.cpp b/samples/blackmiscsim/main.cpp index a14a88f5a..6bc73ec14 100644 --- a/samples/blackmiscsim/main.cpp +++ b/samples/blackmiscsim/main.cpp @@ -7,12 +7,13 @@ * contained in the LICENSE file. */ -#include "blackmisc/registermetadata.h" +#include "blackcore/application.h" #include "samplesfscommon.h" #include "samplesfsx.h" #include "samplesmodelmapping.h" #include "samplesvpilotrules.h" +#include #include #include #include @@ -23,12 +24,14 @@ //! main int main(int argc, char *argv[]) { - Q_UNUSED(argc); - Q_UNUSED(argv); + + QCoreApplication qa(argc, argv); + BlackCore::CApplication a; + Q_UNUSED(a); + Q_UNUSED(qa); QTextStream streamIn(stdin); QTextStream streamOut(stdout); - BlackMisc::registerMetadata(); streamOut << "Run samples:" << endl; streamOut << "1 .. FS common / Simulation (with cfg files reading)" << endl; diff --git a/samples/blackmiscsim/sampleblackmiscsim.pro b/samples/blackmiscsim/sampleblackmiscsim.pro index 500aa64ae..5fb74e263 100644 --- a/samples/blackmiscsim/sampleblackmiscsim.pro +++ b/samples/blackmiscsim/sampleblackmiscsim.pro @@ -7,10 +7,11 @@ TEMPLATE = app CONFIG += console CONFIG -= app_bundle -CONFIG += blackmisc blacksim +CONFIG += blackmisc blacksim blackcore CONFIG -= app_bundle DEPENDPATH += . ../../src/blackmisc +DEPENDPATH += . ../../src/blackcore INCLUDEPATH += . ../../src DESTDIR = $$DestRoot/bin diff --git a/samples/blackmiscsim/samplesfscommon.cpp b/samples/blackmiscsim/samplesfscommon.cpp index d5f9e9117..f4ae5581f 100644 --- a/samples/blackmiscsim/samplesfscommon.cpp +++ b/samples/blackmiscsim/samplesfscommon.cpp @@ -14,7 +14,6 @@ #include "blackmisc/sampleutils.h" #include "blackmisc/simulation/fscommon/aircraftcfgentrieslist.h" #include "blackmisc/simulation/fscommon/aircraftcfgparser.h" -#include "blackmisc/simulation/aircraftmatcher.h" #include "blackmisc/simulation/simulatorinfo.h" diff --git a/samples/blackmiscsim/samplesmodelmapping.cpp b/samples/blackmiscsim/samplesmodelmapping.cpp index b5bd6d32f..a0725f818 100644 --- a/samples/blackmiscsim/samplesmodelmapping.cpp +++ b/samples/blackmiscsim/samplesmodelmapping.cpp @@ -11,17 +11,18 @@ //! \ingroup sampleblackmiscsim #include "samplesmodelmapping.h" +#include "blackcore/aircraftmatcher.h" #include "blackmisc/registermetadata.h" #include "blackmisc/stringutils.h" #include "blackmisc/sampleutils.h" #include "blackmisc/simulation/fscommon/aircraftcfgparser.h" #include "blackmisc/simulation/fscommon/vpilotrulesreader.h" -#include "blackmisc/simulation/aircraftmatcher.h" #include #include #include +using namespace BlackCore; using namespace BlackMisc; using namespace BlackMisc::Simulation; using namespace BlackMisc::Simulation::FsCommon; @@ -31,7 +32,6 @@ namespace BlackSample { void CSamplesModelMapping::samples(QTextStream &streamOut, QTextStream &streamIn) { - BlackMisc::registerMetadata(); CVPilotRulesReader vpRulesReader; bool s = vpRulesReader.read(true); streamOut << "directory: " << CVPilotRulesReader::standardMappingsDirectory() << endl; diff --git a/src/blackcore/aircraftmatcher.cpp b/src/blackcore/aircraftmatcher.cpp new file mode 100644 index 000000000..c5b3ce27e --- /dev/null +++ b/src/blackcore/aircraftmatcher.cpp @@ -0,0 +1,365 @@ +/* Copyright (C) 2013 + * 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 "aircraftmatcher.h" +#include "blackmisc/logmessage.h" +#include "blackmisc/worker.h" +#include +#include + +using namespace BlackMisc; +using namespace BlackMisc::Simulation; +using namespace BlackMisc::Network; +using namespace BlackMisc::Aviation; + +namespace BlackCore +{ + const CLogCategoryList &CAircraftMatcher::getLogCategories() + { + static const BlackMisc::CLogCategoryList cats { BlackMisc::CLogCategory::matching() }; + return cats; + } + + CAircraftMatcher::CAircraftMatcher(MatchingMode matchingMode, QObject *parent) : + QObject(parent), + m_matchingMode(matchingMode) + { } + + CAircraftMatcher::~CAircraftMatcher() + { } + + CAircraftModel CAircraftMatcher::getClosestMatch(const CSimulatedAircraft &remoteAircraft, CStatusMessageList *log) const + { + CAircraftModelList matchedModels(this->m_modelSet); // Models for this matching + const MatchingMode mode = this->m_matchingMode; + + // Manually set string? + if (remoteAircraft.getModel().hasManuallySetString()) + { + // the user did a manual mapping "by hand", so he really should know what he is doing + // no matching + logDetails(log, remoteAircraft, "Manually set model " + remoteAircraft.getModelString()); + return remoteAircraft.getModel(); + } + + do + { + // try to find in installed models by model string + aircraftModel = matchByExactModelString(remoteAircraft, matchModels, log); + if (aircraftModel.hasModelString()) { break; } + + // by livery, then by ICAO + aircraftModel = matchByLiveryAndIcaoCode(remoteAircraft, matchModels, log); + if (aircraftModel.hasModelString()) { break; } + + // by ICAO data from set + aircraftModel = matchModelsByIcaoData(remoteAircraft, matchModels, false, log); + if (aircraftModel.hasModelString()) { break; } + + // family + QString family = remoteAircraft.getAircraftIcaoCode().getFamily(); + aircraftModel = matchByFamily(remoteAircraft, family, matchModels, "real family", log); + if (aircraftModel.hasModelString()) { break; } + + // scenario: the ICAO actually is the family + family = remoteAircraft.getAircraftIcaoCodeDesignator(); + aircraftModel = matchByFamily(remoteAircraft, family, matchModels, "ICAO treated as family", log); + if (aircraftModel.hasModelString()) { break; } + + // combined code + aircraftModel = matchByCombinedCode(remoteAircraft, matchModels, true, log); + if (aircraftModel.hasModelString()) { break; } + + aircraftModel = getDefaultModel(); + logDetails(log, remoteAircraft, "Using default model " + aircraftModel.getModelString()); + } + while (false); + + // copy over callsign and other data + aircraftModel.setCallsign(remoteAircraft.getCallsign()); + + Q_ASSERT_X(!aircraftModel.getCallsign().isEmpty(), Q_FUNC_INFO, "Missing callsign"); + Q_ASSERT_X(aircraftModel.hasModelString(), Q_FUNC_INFO, "Missing model string"); + Q_ASSERT_X(aircraftModel.getModelType() != CAircraftModel::TypeUnknown, Q_FUNC_INFO, "Missing model type"); + + return aircraftModel; + } + + int CAircraftMatcher::setModelSet(const CAircraftModelList &models) + { + CAircraftModelList modelsCleaned(models); + int r1 = modelsCleaned.removeAllWithoutModelString(); + int r2 = modelsCleaned.removeIfExcluded(); + if ((r1 + r2) > 0) + { + CLogMessage(this).warning("Removed models for matcher, without string %1, excluded %2") << r1 << r2; + } + if (modelsCleaned.isEmpty()) + { + CLogMessage(this).error("No models for matching, that will not work"); + } + else + { + CLogMessage(this).info("Set %1 models in matcher") << modelsCleaned.size(); + } + this->m_modelSet = modelsCleaned; + return models.size(); + } + + const CAircraftModel &CAircraftMatcher::getDefaultModel() const + { + return m_defaultModel; + } + + void CAircraftMatcher::setDefaultModel(const BlackMisc::Simulation::CAircraftModel &defaultModel) + { + m_defaultModel = defaultModel; + m_defaultModel.setModelType(CAircraftModel::TypeModelMatchingDefaultModel); + } + + CAircraftModel CAircraftMatcher::matchByExactModelString(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &models, CStatusMessageList *log) + { + if (remoteAircraft.getModelString().isEmpty()) + { + if (log) { logDetails(log, remoteAircraft, "No model string, no exact match possible"); } + return CAircraftModel(); + } + + CAircraftModel model = models.findFirstByModelStringOrDefault(remoteAircraft.getModelString()); + if (log) + { + if (model.hasModelString()) + { + logDetails(log, remoteAircraft, "Found exact match for " + model.getModelString()); + } + else + { + logDetails(log, remoteAircraft, "No exact match for " + model.getModelString()); + } + } + model.setModelType(CAircraftModel::TypeModelMatching); + model.setCallsign(remoteAircraft.getCallsign()); + return model; + } + + CAircraftModelList CAircraftMatcher::ifPossibleReduceByLiveryAndIcaoCode(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &inList, bool &reduced, CStatusMessageList *log) + { + reduced = false; + if (!remoteAircraft.getLivery().hasCombinedCode()) + { + if (log) { logDetails(log, remoteAircraft, "No livery code, no reduction possible"); } + return inList; + } + + const CAircraftModelList byLivery( + inList.findByAircraftDesignatorAndLiveryCombinedCode( + remoteAircraft.getLivery().getCombinedCode(), + remoteAircraft.getAircraftIcaoCodeDesignator() + )); + + if (byLivery.isEmpty()) + { + if (log) { logDetails(log, remoteAircraft, "Not found by livery code " + remoteAircraft.getLivery().getCombinedCode()); } + return inList; + } + reduced = true; + return byLivery; + } + + CAircraftModelList CAircraftMatcher::ifPossibleReduceByIcaoData(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &inList, bool ignoreAirline, bool &reduced, CStatusMessageList *log) + { + reduced = false; + if (!remoteAircraft.hasAircraftDesignator()) + { + if (log) { logDetails(log, remoteAircraft, "No aircraft designator, skipping step"); } + return inList; + } + + BlackMisc::Simulation::CAircraftModelList searchModels(inList.findByIcaoDesignators( + remoteAircraft.getAircraftIcaoCode(), + ignoreAirline ? CAirlineIcaoCode() : remoteAircraft.getAirlineIcaoCode())); + + if (!searchModels.isEmpty()) + { + if (log) + { + logDetails(log, remoteAircraft, + "Possible aircraft " + QString::number(searchModels.size()) + + ", found by ICAO " + remoteAircraft.getAircraftIcaoCodeDesignator() + " " + + (ignoreAirline ? "" : remoteAircraft.getAirlineIcaoCodeDesignator())); + } + reduced = true; + return searchModels; + } + else + { + if (!ignoreAirline && remoteAircraft.hasAircraftAndAirlineDesignator()) + { + // we have searched by aircraft and airline, but not found anything + if (log) + { + logDetails(log, remoteAircraft, + "Not found by ICAO " + + remoteAircraft.getAircraftIcaoCodeDesignator() + " " + remoteAircraft.getAirlineIcaoCodeDesignator() + + " relaxing to only ICAO " + remoteAircraft.getAircraftIcaoCodeDesignator()); + } + // recursive lookup by ignoring airline + return ifPossibleReduceByIcaoData(remoteAircraft, inList, true, reduced, log); + } + if (log) { logDetails(log, remoteAircraft, "Not found by ICAO " + remoteAircraft.getAircraftIcaoCodeDesignator() + " " + remoteAircraft.getAirlineIcaoCodeDesignator()); } + } + return inList; + } + + CAircraftModelList CAircraftMatcher::ifPossibleReduceByFamily(const CSimulatedAircraft &remoteAircraft, const QString &family, const CAircraftModelList &inList, const QString &hint, bool &reduced, CStatusMessageList *log) + { + // Use an algorithm to find the best match + reduced = true; + if (family.isEmpty()) + { + if (log) { logDetails(log, remoteAircraft, "No family, skipping step (" + hint + ")"); } + return inList; + } + if (inList.isEmpty()) + { + if (log) { logDetails(log, remoteAircraft, "No models for family match (" + hint + ")"); } + return inList; + } + + CAircraftModelList found(inList.findByFamily(family)); + if (found.isEmpty()) + { + if (log) { logDetails(log, remoteAircraft, "Not found by family " + family + " (" + hint + ")"); } + return inList; + } + + reduced = true; + logDetails(log, remoteAircraft, "Found by family " + family + " (" + hint + ") size " + QString::number(found.size())); + return found; + } + + CAircraftModelList CAircraftMatcher::ifPossibleReduceByManufacturer(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &inList, const QString &info, bool &reduced, CStatusMessageList *log) + { + reduced = false; + if (inList.isEmpty()) + { + if (log) { logDetails(log , remoteAircraft, info + " " + "Empty input list, cannot reduce"); } + return inList; + } + + const QString m = remoteAircraft.getAircraftIcaoCode().getManufacturer(); + if (m.isEmpty()) + { + if (log) { logDetails(log , remoteAircraft, info + " No manufacturer, cannot reduce " + QString::number(inList.size()) + " entries"); } + return inList; + } + + const CAircraftModelList outList(inList.findByManunfacturer(m)); + if (outList.isEmpty()) + { + if (log) { logDetails(log , remoteAircraft, info + " Not found " + m + ", cannot reduce"); } + return inList; + } + + if (log) { logDetails(log , remoteAircraft, info + " Reduced by " + m + " results: " + QString::number(outList.size())); } + reduced = true; + return outList; + } + + CAircraftModelList CAircraftMatcher::ifPossibleReduceByAirline(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &inList, const QString &info, bool &reduced, CStatusMessageList *log) + { + reduced = false; + if (inList.isEmpty()) + { + if (log) { logDetails(log , remoteAircraft, info + " " + "Empty input list, cannot reduce"); } + return inList; + } + + if (!remoteAircraft.hasAirlineDesignator()) + { + if (log) { logDetails(log , remoteAircraft, info + " " + "No airline, cannot reduce " + QString::number(inList.size()) + " entries"); } + return inList; + } + + const CAircraftModelList outList(inList.findByIcaoDesignators(CAircraftIcaoCode(), remoteAircraft.getAirlineIcaoCode())); + if (outList.isEmpty()) + { + if (log) { logDetails(log , remoteAircraft, info + " Cannot reduce by " + remoteAircraft.getAirlineIcaoCodeDesignator() + " results: " + QString::number(outList.size())); } + return inList; + } + + if (log) { logDetails(log , remoteAircraft, info + " Reduced reduce by " + remoteAircraft.getAirlineIcaoCodeDesignator() + " to " + QString::number(outList.size())); } + reduced = true; + return outList; + } + + CAircraftModelList CAircraftMatcher::ifPossibleReduceByCombinedCode(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &inList, bool relaxIfNotFound, bool &reduced, CStatusMessageList *log) + { + reduced = false; + if (!remoteAircraft.getAircraftIcaoCode().hasValidCombinedType()) + { + if (log) { logDetails(log, remoteAircraft, "No valid combined code"); } + return inList; + } + + const QString cc = remoteAircraft.getAircraftIcaoCode().getCombinedType(); + CAircraftModelList byCombinedCode(inList.findByCombinedCode(cc)); + if (byCombinedCode.isEmpty()) + { + if (log) { logDetails(log, remoteAircraft, "Not found by combined code " + cc); } + if (relaxIfNotFound) + { + + } + return inList; + } + + if (log) { logDetails(log, remoteAircraft, "Found by combined code " + cc + ", possible " + QString::number(byCombinedCode.size())); } + if (byCombinedCode.size() > 1) + { + byCombinedCode = ifPossibleReduceByAirline(remoteAircraft, byCombinedCode, "Combined code", reduced, log); + byCombinedCode = ifPossibleReduceByManufacturer(remoteAircraft, byCombinedCode, "Combined code", reduced, log); + reduced = true; + } + return byCombinedCode; + } + + CAircraftModelList CAircraftMatcher::ifPossibleReduceByMilitaryFlag(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft, bool military, const CAircraftModelList &inList, bool &reduced, CStatusMessageList *log) + { + reduced = false; + CAircraftModelList byMilitaryFlag(inList.findByMilitaryFlag(military)); + const QString mil(military ? "military" : "civilian"); + if (byMilitaryFlag.isEmpty()) + { + if (log) { logDetails(log, remoteAircraft, "Not found by " + mil); } + return inList; + } + + if (log) + { + if (inList.size() > byMilitaryFlag.size()) + { + logDetails(log, remoteAircraft, "Reduced to " + mil + " aircraft, size " + QString::number(byMilitaryFlag.size())); + } + else + { + logDetails(log, remoteAircraft, "Not reduced by " + mil + ", size " + QString::number(byMilitaryFlag.size())); + } + } + return byMilitaryFlag; + } + + void CAircraftMatcher::logDetails(CStatusMessageList *log, const CSimulatedAircraft &remoteAircraft, const QString &message, CStatusMessage::StatusSeverity s) + { + if (!log) { return; } + if (message.isEmpty()) { return; } + const CStatusMessage m(getLogCategories(), s, remoteAircraft.hasCallsign() ? remoteAircraft.getCallsign().toQString() + ": " + message.trimmed() : message.trimmed()); + log->push_back(m); + } +} // namespace diff --git a/src/blackcore/aircraftmatcher.h b/src/blackcore/aircraftmatcher.h new file mode 100644 index 000000000..d5e2b7e63 --- /dev/null +++ b/src/blackcore/aircraftmatcher.h @@ -0,0 +1,124 @@ +/* Copyright (C) 2015 + * 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 BLACKCORE_AIRCRAFTMATCHER_H +#define BLACKCORE_AIRCRAFTMATCHER_H + +#include "blackcore/blackcoreexport.h" +#include "blackmisc/simulation/simulatedaircraft.h" +#include "blackmisc/simulation/aircraftmodellist.h" +#include +#include +#include +#include +#include + +namespace BlackCore +{ + /*! + * Matcher for all models. + * \details Reads all the mapping rules and all the available flight simulator models. + * Then all rules for models not existing are eliminated ( \sa synchronize ). + * Thereafter all existing models and mappings can be obtained from here. + */ + class BLACKCORE_EXPORT CAircraftMatcher : public QObject + { + Q_OBJECT + + public: + //! Enabled matching mode flags + enum MatchingModeFlag + { + ByModelString = 1 << 0, + ByIcaoData = 1 << 1, + ByFamily = 1 << 2, + All = ByModelString | ByIcaoData | ByFamily + }; + Q_DECLARE_FLAGS(MatchingMode, MatchingModeFlag) + + //! Log categories + static const BlackMisc::CLogCategoryList &getLogCategories(); + + //! Constructor + CAircraftMatcher(MatchingMode matchingMode = All, QObject *parent = nullptr); + + //! Destructor + virtual ~CAircraftMatcher(); + + //! Set the enabled matching modes + void setMatchingModes(MatchingMode matchingModes); + + //! Get the closest matching aircraft model. + //! Result depends on enabled modes. + //! \sa MatchingModeFlag + BlackMisc::Simulation::CAircraftModel getClosestMatch(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft, BlackMisc::CStatusMessageList *log = nullptr) const; + + //! Get the models + BlackMisc::Simulation::CAircraftModelList getModelSet() const { return m_modelSet; } + + //! Set the models we want to use + int setModelSet(const BlackMisc::Simulation::CAircraftModelList &models); + + //! Default model + const BlackMisc::Simulation::CAircraftModel &getDefaultModel() const; + + //! Set default model + void setDefaultModel(const BlackMisc::Simulation::CAircraftModel &defaultModel); + + private: + //! Search in models by key (aka model string) + //! \threadsafe + static BlackMisc::Simulation::CAircraftModel matchByExactModelString(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft, const BlackMisc::Simulation::CAircraftModelList &models, BlackMisc::CStatusMessageList *log); + + //! Installed models by ICAO data + //! \threadsafe + static BlackMisc::Simulation::CAircraftModelList ifPossibleReduceByIcaoData(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft, const BlackMisc::Simulation::CAircraftModelList &models, bool ignoreAirline, bool &reduced, BlackMisc::CStatusMessageList *log); + + //! Find model by aircraft family + //! \threadsafe + static BlackMisc::Simulation::CAircraftModelList ifPossibleReduceByFamily(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft, const QString &family, const BlackMisc::Simulation::CAircraftModelList &inList, const QString &modelSource, bool &reduced, BlackMisc::CStatusMessageList *log); + + //! Search for exact livery and aircraft ICAO code + //! \threadsafe + static BlackMisc::Simulation::CAircraftModelList ifPossibleReduceByLiveryAndIcaoCode(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft, const BlackMisc::Simulation::CAircraftModelList &inList, bool &reduced, BlackMisc::CStatusMessageList *log); + + //! Reduce by manufacturer + //! \threadsafe + static BlackMisc::Simulation::CAircraftModelList ifPossibleReduceByManufacturer(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft, const BlackMisc::Simulation::CAircraftModelList &inList, const QString &info, bool &reduceed, BlackMisc::CStatusMessageList *log); + + //! Reduce by airline ICAO + //! \threadsafe + static BlackMisc::Simulation::CAircraftModelList ifPossibleReduceByAirline(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft, const BlackMisc::Simulation::CAircraftModelList &inList, const QString &info, bool &reduced, BlackMisc::CStatusMessageList *log); + + //! Installed models by combined code (ie L2J, L1P, ...) + //! \threadsafe + static BlackMisc::Simulation::CAircraftModelList ifPossibleReduceByCombinedCode(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft, const BlackMisc::Simulation::CAircraftModelList &inList, bool relaxIfNotFound, bool &reduced, BlackMisc::CStatusMessageList *log); + + //! My military flag + //! \threadsafe + static BlackMisc::Simulation::CAircraftModelList ifPossibleReduceByMilitaryFlag(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft, bool military, const BlackMisc::Simulation::CAircraftModelList &inList, bool &reduced, BlackMisc::CStatusMessageList *log); + + //! Add to log. if applicable + //! \treadsafe + static void logDetails(BlackMisc::CStatusMessageList *log, + const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft, + const QString &message, + BlackMisc::CStatusMessage::StatusSeverity s = BlackMisc::CStatusMessage::SeverityInfo); + + MatchingMode m_matchingMode = All; + BlackMisc::Simulation::CAircraftModel m_defaultModel; //!< model to be used as default model + BlackMisc::Simulation::CAircraftModelList m_modelSet; //!< models used for model matching + }; +} // namespace + +Q_DECLARE_OPERATORS_FOR_FLAGS(BlackCore::CAircraftMatcher::MatchingMode) + +#endif // guard diff --git a/src/blackcore/simulatorcommon.h b/src/blackcore/simulatorcommon.h index d853b54f0..b6f823ac7 100644 --- a/src/blackcore/simulatorcommon.h +++ b/src/blackcore/simulatorcommon.h @@ -15,11 +15,11 @@ #include "blackcore/blackcoreexport.h" #include "blackcore/interpolator.h" #include "blackcore/simulator.h" +#include "blackcore/aircraftmatcher.h" #include "blackmisc/simulation/simulatorplugininfo.h" #include "blackmisc/simulation/simulatorsetup.h" #include "blackmisc/simulation/simulatedaircraftlist.h" #include "blackmisc/simulation/aircraftmodelsetloader.h" -#include "blackmisc/simulation/aircraftmatcher.h" #include "blackmisc/simulation/ownaircraftprovider.h" #include "blackmisc/simulation/remoteaircraftprovider.h" #include "blackmisc/pluginstorageprovider.h" @@ -116,7 +116,7 @@ namespace BlackCore BlackMisc::Simulation::CSimulatorSetup m_simulatorSetup; //!< setup object //! \todo unclear if this is valid for all simulators or for MS/P3D simulators only - BlackMisc::Simulation::CAircraftMatcher m_modelMatcher; //!< Model matcher + BlackCore::CAircraftMatcher m_modelMatcher; //!< Model matcher BlackMisc::Simulation::CAircraftModelSetLoader m_modelSetLoader { BlackMisc::Simulation::CSimulatorInfo(BlackMisc::Simulation::CSimulatorInfo::FSX), this }; //!< load model set from caches private: diff --git a/src/blackgui/components/modelmatchercomponent.h b/src/blackgui/components/modelmatchercomponent.h index bc4faa2c2..789a855c3 100644 --- a/src/blackgui/components/modelmatchercomponent.h +++ b/src/blackgui/components/modelmatchercomponent.h @@ -13,9 +13,9 @@ #define BLACKGUI_COMPONENT_MODELMATCHERCOMPONENT_H #include "blackgui/blackguiexport.h" +#include "blackcore/aircraftmatcher.h" #include "blackmisc/simulation/aircraftmodelsetloader.h" #include "blackmisc/simulation/simulatedaircraft.h" -#include "blackmisc/simulation/aircraftmatcher.h" #include "blackmisc/network/entityflags.h" #include @@ -70,7 +70,7 @@ namespace BlackGui QScopedPointer ui; BlackMisc::Simulation::CAircraftModelSetLoader m_modelSetLoader { BlackMisc::Simulation::CSimulatorInfo(BlackMisc::Simulation::CSimulatorInfo::FSX), this }; - BlackMisc::Simulation::CAircraftMatcher m_matcher { BlackMisc::Simulation::CAircraftMatcher::All, this }; + BlackCore::CAircraftMatcher m_matcher { BlackCore::CAircraftMatcher::All, this }; }; } // ns } // ns diff --git a/src/blackmisc/simulation/aircraftmatcher.cpp b/src/blackmisc/simulation/aircraftmatcher.cpp deleted file mode 100644 index f0dd7f13f..000000000 --- a/src/blackmisc/simulation/aircraftmatcher.cpp +++ /dev/null @@ -1,357 +0,0 @@ -/* Copyright (C) 2013 - * 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 "aircraftmatcher.h" -#include "blackmisc/logmessage.h" -#include "blackmisc/worker.h" -#include -#include - -using namespace BlackMisc; -using namespace BlackMisc::Simulation; -using namespace BlackMisc::Network; -using namespace BlackMisc::Aviation; - -namespace BlackMisc -{ - namespace Simulation - { - const CLogCategoryList &CAircraftMatcher::getLogCategories() - { - static const BlackMisc::CLogCategoryList cats { BlackMisc::CLogCategory::matching() }; - return cats; - } - - CAircraftMatcher::CAircraftMatcher(MatchingMode matchingMode, QObject *parent) : - QObject(parent), - m_matchingMode(matchingMode) - { } - - CAircraftMatcher::~CAircraftMatcher() - { } - - CAircraftModel CAircraftMatcher::getClosestMatch(const CSimulatedAircraft &remoteAircraft, CStatusMessageList *log) const - { - const CAircraftModelList matchModels(this->m_modelSet); // Models for this matching - if (matchModels.isEmpty()) - { - logDetails(log, remoteAircraft, "No models for matching, using default", CStatusMessage::SeverityWarning); - return this->getDefaultModel(); - } - - CAircraftModel aircraftModel(remoteAircraft.getModel()); // set defaults - - // Manually set string? - if (remoteAircraft.getModel().hasManuallySetString()) - { - // the user did a manual mapping "by hand", so he really should know what he is doing - // no matching - logDetails(log, remoteAircraft, "Manually set model " + remoteAircraft.getModelString()); - return remoteAircraft.getModel(); - } - - do - { - // try to find in installed models by model string - aircraftModel = matchByExactModelString(remoteAircraft, matchModels, log); - if (aircraftModel.hasModelString()) { break; } - - // by livery, then by ICAO - aircraftModel = matchByLiveryAndIcaoCode(remoteAircraft, matchModels, log); - if (aircraftModel.hasModelString()) { break; } - - // by ICAO data from set - aircraftModel = matchModelsByIcaoData(remoteAircraft, matchModels, false, log); - if (aircraftModel.hasModelString()) { break; } - - // family - QString family = remoteAircraft.getAircraftIcaoCode().getFamily(); - aircraftModel = matchByFamily(remoteAircraft, family, matchModels, "real family", log); - if (aircraftModel.hasModelString()) { break; } - - // scenario: the ICAO actually is the family - family = remoteAircraft.getAircraftIcaoCodeDesignator(); - aircraftModel = matchByFamily(remoteAircraft, family, matchModels, "ICAO treated as family", log); - if (aircraftModel.hasModelString()) { break; } - - // combined code - aircraftModel = matchByCombinedCode(remoteAircraft, matchModels, true, log); - if (aircraftModel.hasModelString()) { break; } - - aircraftModel = getDefaultModel(); - logDetails(log, remoteAircraft, "Using default model " + aircraftModel.getModelString()); - } - while (false); - - // copy over callsign and other data - aircraftModel.setCallsign(remoteAircraft.getCallsign()); - - Q_ASSERT_X(!aircraftModel.getCallsign().isEmpty(), Q_FUNC_INFO, "Missing callsign"); - Q_ASSERT_X(aircraftModel.hasModelString(), Q_FUNC_INFO, "Missing model string"); - Q_ASSERT_X(aircraftModel.getModelType() != CAircraftModel::TypeUnknown, Q_FUNC_INFO, "Missing model type"); - - return aircraftModel; - } - - int CAircraftMatcher::setModelSet(const CAircraftModelList &models) - { - CAircraftModelList modelsCleaned(models); - int r1 = modelsCleaned.removeAllWithoutModelString(); - int r2 = modelsCleaned.removeIfExcluded(); - if ((r1 + r2) > 0) - { - CLogMessage(this).warning("Removed models for matcher, without string %1, excluded %2") << r1 << r2; - } - if (modelsCleaned.isEmpty()) - { - CLogMessage(this).error("No models for matching, that will not work"); - } - else - { - CLogMessage(this).info("Set %1 models in matcher") << modelsCleaned.size(); - } - this->m_modelSet = modelsCleaned; - return models.size(); - } - - const CAircraftModel &CAircraftMatcher::getDefaultModel() const - { - return m_defaultModel; - } - - void CAircraftMatcher::setDefaultModel(const BlackMisc::Simulation::CAircraftModel &defaultModel) - { - m_defaultModel = defaultModel; - m_defaultModel.setModelType(CAircraftModel::TypeModelMatchingDefaultModel); - } - - CAircraftModel CAircraftMatcher::matchByExactModelString(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &models, CStatusMessageList *log) - { - if (remoteAircraft.getModelString().isEmpty()) - { - if (log) { logDetails(log, remoteAircraft, "No model string, no exact match possible"); } - return CAircraftModel(); - } - - CAircraftModel model = models.findFirstByModelStringOrDefault(remoteAircraft.getModelString()); - if (log) - { - if (model.hasModelString()) - { - logDetails(log, remoteAircraft, "Found exact match for " + model.getModelString()); - } - else - { - logDetails(log, remoteAircraft, "No exact match for " + model.getModelString()); - } - } - model.setModelType(CAircraftModel::TypeModelMatching); - return model; - } - - CAircraftModel CAircraftMatcher::matchByLiveryAndIcaoCode(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &models, CStatusMessageList *log) - { - if (!remoteAircraft.getLivery().hasCombinedCode()) - { - if (log) { logDetails(log, remoteAircraft, "No livery code, no match possible"); } - return CAircraftModel(); - } - - const CAircraftModelList byLivery(models.findByLiveryCode(remoteAircraft.getLivery())); - if (byLivery.isEmpty()) - { - if (log) { logDetails(log, remoteAircraft, "Not found by livery code " + remoteAircraft.getLivery().getCombinedCode()); } - return CAircraftModel(); - } - return matchModelsByIcaoData(remoteAircraft, byLivery, true, log); - } - - CAircraftModel CAircraftMatcher::matchByCombinedCode(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &models, bool relaxIfNotFound, CStatusMessageList *log) - { - CAircraftModel aircraftModel; - if (!remoteAircraft.getAircraftIcaoCode().hasValidCombinedType()) - { - if (log) { logDetails(log, remoteAircraft, "No valid combined code"); } - return aircraftModel; - } - - const QString cc = remoteAircraft.getAircraftIcaoCode().getCombinedType(); - CAircraftModelList byCombinedCode(models.findByCombinedCode(cc)); - if (byCombinedCode.isEmpty()) - { - if (log) { logDetails(log, remoteAircraft, "Not found by combined code " + cc); } - return CAircraftModel(); - } - - if (log) { logDetails(log, remoteAircraft, "Found by combined code " + cc + ", possible " + QString::number(byCombinedCode.size())); } - if (byCombinedCode.size() > 1) - { - byCombinedCode = ifPossibleReduceByAirline(remoteAircraft, byCombinedCode, "Combined code", log); - byCombinedCode = ifPossibleReduceByManufacturer(remoteAircraft, byCombinedCode, "Combined code", log); - } - aircraftModel = byCombinedCode.front(); - aircraftModel.setModelType(CAircraftModel::TypeModelMatching); - return aircraftModel; - } - - CAircraftModel CAircraftMatcher::matchModelsByIcaoData(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &models, bool ignoreAirline, CStatusMessageList *log) - { - CAircraftModel aircraftModel; - if (!remoteAircraft.hasAircraftDesignator()) - { - if (log) { logDetails(log, remoteAircraft, "No aircraft designator, skipping step"); } - return aircraftModel; - } - - BlackMisc::Simulation::CAircraftModelList searchModels(models.findByIcaoDesignators( - remoteAircraft.getAircraftIcaoCode(), - ignoreAirline ? CAirlineIcaoCode() : remoteAircraft.getAirlineIcaoCode())); - - if (!searchModels.isEmpty()) - { - if (log) - { - logDetails(log, remoteAircraft, - "Possible aircraft " + QString::number(searchModels.size()) + - ", found by ICAO " + remoteAircraft.getAircraftIcaoCodeDesignator() + " " + - (ignoreAirline ? "" : remoteAircraft.getAirlineIcaoCodeDesignator())); - } - if (searchModels.size() > 1) - { - searchModels = ifPossibleReduceByManufacturer(remoteAircraft, searchModels, "Match by ICAO", log); - } - aircraftModel = searchModels.front(); - aircraftModel.setModelType(CAircraftModel::TypeModelMatching); - } - else - { - if (!ignoreAirline && remoteAircraft.hasAircraftAndAirlineDesignator()) - { - // we have searched by aircraft and airline, bout not found anything - if (log) - { - logDetails(log, remoteAircraft, - "Not found by ICAO " + - remoteAircraft.getAircraftIcaoCodeDesignator() + " " + remoteAircraft.getAirlineIcaoCodeDesignator() + - " relaxing to only ICAO " + remoteAircraft.getAircraftIcaoCodeDesignator()); - } - // recursive lookup by ignoring airline - return matchModelsByIcaoData(remoteAircraft, models, true, log); - } - if (log) { logDetails(log, remoteAircraft, "Not found by ICAO " + remoteAircraft.getAircraftIcaoCodeDesignator() + " " + remoteAircraft.getAirlineIcaoCodeDesignator()); } - } - return aircraftModel; - } - - CAircraftModel CAircraftMatcher::matchByFamily(const CSimulatedAircraft &remoteAircraft, const QString &family, const CAircraftModelList &models, const QString &hint, CStatusMessageList *log) - { - // Use an algorithm to find the best match - if (family.isEmpty()) - { - if (log) { logDetails(log, remoteAircraft, "No family, skipping step (" + hint + ")"); } - return CAircraftModel(); - } - if (models.isEmpty()) - { - if (log) { logDetails(log, remoteAircraft, "No models for family match (" + hint + ")"); } - return CAircraftModel(); - } - - CAircraftModelList found(models.findByFamily(family)); - if (found.isEmpty()) - { - if (log) { logDetails(log, remoteAircraft, "Not found by family " + family + " (" + hint + ")"); } - return CAircraftModel(); - } - - if (remoteAircraft.hasAirlineDesignator()) - { - const CAircraftModelList foundReduceByAirline = found.findByIcaoDesignators(CAircraftIcaoCode(), remoteAircraft.getAirlineIcaoCode()); - if (!foundReduceByAirline.isEmpty()) - { - CAircraftModel model(found.front()); - if (log) - { - logDetails(log, - remoteAircraft, "Found by family " + family + " and airline " + - remoteAircraft.getAirlineIcaoCodeDesignator() + " (" + hint + ") as " + model.getAircraftIcaoCodeDesignator() + - " size " + QString::number(foundReduceByAirline.size())); - } - model.setModelType(CAircraftModel::TypeModelMatching); - return model; - } - } - - CAircraftModel model(found.front()); - logDetails(log, - remoteAircraft, "Found by family " + family + " (" + hint + ") " + - model.getAircraftIcaoCodeDesignator() + " size " + QString::number(found.size())); - model.setModelType(CAircraftModel::TypeModelMatching); - return model; - } - - CAircraftModelList CAircraftMatcher::ifPossibleReduceByManufacturer(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &inList, const QString &info, CStatusMessageList *log) - { - if (inList.isEmpty()) - { - if (log) { logDetails(log , remoteAircraft, info + " " + "Empty input list, cannot reduce"); } - return inList; - } - - const QString m = remoteAircraft.getAircraftIcaoCode().getManufacturer(); - if (m.isEmpty()) - { - if (log) { logDetails(log , remoteAircraft, info + " No manufacturer, cannot reduce " + QString::number(inList.size()) + " entries"); } - return inList; - } - - const CAircraftModelList outList(inList.findByManunfacturer(m)); - if (outList.isEmpty()) - { - if (log) { logDetails(log , remoteAircraft, info + " Not found " + m + ", cannot reduce"); } - return inList; - } - - if (log) { logDetails(log , remoteAircraft, info + " Reduced by " + m + " results: " + QString::number(outList.size())); } - return outList; - } - - CAircraftModelList CAircraftMatcher::ifPossibleReduceByAirline(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &inList, const QString &info, CStatusMessageList *log) - { - if (inList.isEmpty()) - { - if (log) { logDetails(log , remoteAircraft, info + " " + "Empty input list, cannot reduce"); } - return inList; - } - - if (!remoteAircraft.hasAirlineDesignator()) - { - if (log) { logDetails(log , remoteAircraft, info + " " + "No airline, cannot reduce " + QString::number(inList.size()) + " entries"); } - return inList; - } - - const CAircraftModelList outList(inList.findByIcaoDesignators(CAircraftIcaoCode(), remoteAircraft.getAirlineIcaoCode())); - if (outList.isEmpty()) - { - if (log) { logDetails(log , remoteAircraft, info + " Cannot reduce by " + remoteAircraft.getAirlineIcaoCodeDesignator() + " results: " + QString::number(outList.size())); } - } - - if (log) { logDetails(log , remoteAircraft, info + " Reduced reduce by " + remoteAircraft.getAirlineIcaoCodeDesignator() + " to " + QString::number(outList.size())); } - return outList; - } - - void CAircraftMatcher::logDetails(CStatusMessageList *log, const CSimulatedAircraft &remoteAircraft, const QString &message, CStatusMessage::StatusSeverity s) - { - if (!log) { return; } - if (message.isEmpty()) { return; } - const CStatusMessage m(getLogCategories(), s, remoteAircraft.hasCallsign() ? remoteAircraft.getCallsign().toQString() + ": " + message.trimmed() : message.trimmed()); - log->push_back(m); - } - } -} // namespace diff --git a/src/blackmisc/simulation/aircraftmatcher.h b/src/blackmisc/simulation/aircraftmatcher.h deleted file mode 100644 index e8f2d237c..000000000 --- a/src/blackmisc/simulation/aircraftmatcher.h +++ /dev/null @@ -1,123 +0,0 @@ -/* Copyright (C) 2015 - * 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 BLACKMISC_SIMULATION_AIRCRAFTMATCHER_H -#define BLACKMISC_SIMULATION_AIRCRAFTMATCHER_H - -#include "blackmisc/blackmiscexport.h" -#include "blackmisc/simulation/simulatedaircraft.h" -#include "blackmisc/simulation/aircraftmodellist.h" -#include -#include -#include -#include -#include - -namespace BlackMisc -{ - namespace Simulation - { - /*! - * Matcher for all models. - * \details Reads all the mapping rules and all the available flight simulator models. - * Then all rules for models not existing are eliminated ( \sa synchronize ). - * Thereafter all existing models and mappings can be obtained from here. - */ - class BLACKMISC_EXPORT CAircraftMatcher : public QObject - { - Q_OBJECT - - public: - //! Enabled matching mode flags - enum MatchingModeFlag - { - ByModelString = 1 << 0, - ByIcaoData = 1 << 1, - ByFamily = 1 << 2, - All = ByModelString | ByIcaoData | ByFamily - }; - Q_DECLARE_FLAGS(MatchingMode, MatchingModeFlag) - - //! Log categories - static const BlackMisc::CLogCategoryList &getLogCategories(); - - //! Constructor - CAircraftMatcher(MatchingMode matchingMode = All, QObject *parent = nullptr); - - //! Destructor - virtual ~CAircraftMatcher(); - - //! Set the enabled matching modes - void setMatchingModes(MatchingMode matchingModes); - - //! Get the closest matching aircraft model. - //! Result depends on enabled modes. - //! \sa MatchingModeFlag - CAircraftModel getClosestMatch(const CSimulatedAircraft &remoteAircraft, BlackMisc::CStatusMessageList *log = nullptr) const; - - //! Get the models - BlackMisc::Simulation::CAircraftModelList getModelSet() const { return m_modelSet; } - - //! Set the models we want to use - int setModelSet(const BlackMisc::Simulation::CAircraftModelList &models); - - //! Default model - const BlackMisc::Simulation::CAircraftModel &getDefaultModel() const; - - //! Set default model - void setDefaultModel(const BlackMisc::Simulation::CAircraftModel &defaultModel); - - private: - //! Search in models by key (aka model string) - //! \threadsafe - static CAircraftModel matchByExactModelString(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &models, CStatusMessageList *log); - - //! Search for exact livery - //! \threadsafe - static CAircraftModel matchByLiveryAndIcaoCode(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &models, CStatusMessageList *log); - - //! Installed models by ICAO data - //! \threadsafe - static CAircraftModel matchModelsByIcaoData(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &models, bool ignoreAirline, CStatusMessageList *log); - - //! Installed models by combined code (ie L2J, L1P, ...) - //! \threadsafe - static CAircraftModel matchByCombinedCode(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &models, bool relaxIfNotFound, CStatusMessageList *log); - - //! Find model by aircraft family - //! \threadsafe - static CAircraftModel matchByFamily(const CSimulatedAircraft &remoteAircraft, const QString &family, const CAircraftModelList &models, const QString &modelSource, CStatusMessageList *log); - - //! Reduce by manufacturer - //! \threadsafe - static CAircraftModelList ifPossibleReduceByManufacturer(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &inList, const QString &info, CStatusMessageList *log); - - //! Reduce by airline ICAO - //! \threadsafe - static CAircraftModelList ifPossibleReduceByAirline(const CSimulatedAircraft &remoteAircraft, const CAircraftModelList &inList, const QString &info, CStatusMessageList *log); - - //! Add to log. if applicable - //! \treadsafe - static void logDetails(BlackMisc::CStatusMessageList *log, - const CSimulatedAircraft &remoteAircraft, - const QString &message, - CStatusMessage::StatusSeverity s = CStatusMessage::SeverityInfo); - - MatchingMode m_matchingMode = All; - BlackMisc::Simulation::CAircraftModel m_defaultModel; //!< model to be used as default model - BlackMisc::Simulation::CAircraftModelList m_modelSet; //!< models used for model matching - }; - } -} // namespace - -Q_DECLARE_OPERATORS_FOR_FLAGS(BlackMisc::Simulation::CAircraftMatcher::MatchingMode) - -#endif // guard diff --git a/src/plugins/simulator/fscommon/simulatorfscommon.h b/src/plugins/simulator/fscommon/simulatorfscommon.h index ea031f94d..13730bb0f 100644 --- a/src/plugins/simulator/fscommon/simulatorfscommon.h +++ b/src/plugins/simulator/fscommon/simulatorfscommon.h @@ -14,7 +14,6 @@ #include "blackcore/simulatorcommon.h" #include "blackcore/interpolator.h" -#include "blackmisc/simulation/aircraftmatcher.h" #include "blackmisc/simulation/fscommon/aircraftcfgparser.h" #include "fsuipc.h" diff --git a/src/plugins/simulator/xplane/simulatorxplane.h b/src/plugins/simulator/xplane/simulatorxplane.h index 903d1680d..ecf24b174 100644 --- a/src/plugins/simulator/xplane/simulatorxplane.h +++ b/src/plugins/simulator/xplane/simulatorxplane.h @@ -13,7 +13,6 @@ #define BLACKSIMPLUGIN_SIMULATOR_XPLANE_H #include "blackcore/simulatorcommon.h" -#include "blackmisc/simulation/aircraftmatcher.h" #include "blackmisc/simulation/ownaircraftprovider.h" #include "blackmisc/simulation/aircraftmodellist.h" #include "blackmisc/pixmap.h"