diff --git a/src/blackmisc/aviation/aircrafticaocode.cpp b/src/blackmisc/aviation/aircrafticaocode.cpp index 5ca9f7461..e9e4d5ba0 100644 --- a/src/blackmisc/aviation/aircrafticaocode.cpp +++ b/src/blackmisc/aviation/aircrafticaocode.cpp @@ -7,10 +7,10 @@ * contained in the LICENSE file. */ +#include "blackmisc/simulation/matchingutils.h" #include "blackmisc/aviation/aircrafticaocode.h" -#include "blackmisc/comparefunctions.h" #include "blackmisc/db/datastoreutility.h" -#include "blackmisc/logcategory.h" +#include "blackmisc/comparefunctions.h" #include "blackmisc/logcategorylist.h" #include "blackmisc/propertyindex.h" #include "blackmisc/statusmessage.h" @@ -28,6 +28,7 @@ using namespace BlackMisc; using namespace BlackMisc::Db; +using namespace BlackMisc::Simulation; namespace BlackMisc { @@ -130,35 +131,48 @@ namespace BlackMisc return this->getCombinedIcaoStringWithKey(); } - int CAircraftIcaoCode::calculateScore(const CAircraftIcaoCode &otherCode) const + int CAircraftIcaoCode::calculateScore(const CAircraftIcaoCode &otherCode, CStatusMessageList *log) const { - if (this->isDbEqual(otherCode)) { return 100; } + if (this->isDbEqual(otherCode)) + { + CMatchingUtils::addLogDetailsToList(log, *this, QString("Equal DB code: 100")); + return 100; + } int score = 0; if (this->hasValidDesignator() && this->getDesignator() == otherCode.getDesignator()) { // 0..65 score += 50; // same designator + CMatchingUtils::addLogDetailsToList(log, *this, QString("Same designator: %1").arg(score)); + int scoreOld = score; if (this->getRank() == 0) { score += 15; } else if (this->getRank() == 1) { score += 12; } else if (this->getRank() < 10) { score += (10 - this->getRank()); } + if (score > scoreOld) + { + CMatchingUtils::addLogDetailsToList(log, *this, QString("Added rank: %1").arg(score)); + } } else { if (this->hasFamily() && this->getFamily() == otherCode.getFamily()) { score += 30; + CMatchingUtils::addLogDetailsToList(log, *this, QString("Added family: %1").arg(score)); } else if (this->hasValidCombinedType() && otherCode.getCombinedType() == this->getCombinedType()) { score += 20; + CMatchingUtils::addLogDetailsToList(log, *this, QString("Added combined code: %1").arg(score)); } else if (this->hasValidCombinedType()) { if (this->getEngineCount() == otherCode.getEngineCount()) { score += 2; } if (this->getEngineType() == otherCode.getEngineType()) { score += 2; } if (this->getAircraftType() == otherCode.getAircraftType()) { score += 2; } + CMatchingUtils::addLogDetailsToList(log, *this, QString("Added combined code parts: %1").arg(score)); } } @@ -168,16 +182,21 @@ namespace BlackMisc if (this->matchesManufacturer(otherCode.getManufacturer())) { score += 10; + CMatchingUtils::addLogDetailsToList(log, *this, QString("Matches manufacturer '%1': %2").arg(this->getManufacturer()).arg(score)); } else if (this->getManufacturer().contains(otherCode.getManufacturer(), Qt::CaseInsensitive)) { + CMatchingUtils::addLogDetailsToList(log, *this, QString("Contains manufacturer '%1': %2").arg(this->getManufacturer()).arg(score)); score += 5; } } // 0..75 so far - if (this->isMilitary() == otherCode.isMilitary()) { score += 10; } - + if (this->isMilitary() == otherCode.isMilitary()) + { + score += 10; + CMatchingUtils::addLogDetailsToList(log, *this, QString("Matches military flag '%1': %2").arg(boolToYesNo(this->isMilitary())).arg(score)); + } // 0..85 return score; } diff --git a/src/blackmisc/aviation/aircrafticaocode.h b/src/blackmisc/aviation/aircrafticaocode.h index 3c1e41092..8732e9b63 100644 --- a/src/blackmisc/aviation/aircrafticaocode.h +++ b/src/blackmisc/aviation/aircrafticaocode.h @@ -289,7 +289,7 @@ namespace BlackMisc //! Considers rank, manufacturer and family 0..100 //! \remark normally used with a selected set of ICAO codes or combined types - int calculateScore(const CAircraftIcaoCode &otherCode) const; + int calculateScore(const CAircraftIcaoCode &otherCode, CStatusMessageList *log = nullptr) const; //! Valid designator? static bool isValidDesignator(const QString &designator); diff --git a/src/blackmisc/aviation/airlineicaocode.cpp b/src/blackmisc/aviation/airlineicaocode.cpp index 63f2c6e06..317dcddfc 100644 --- a/src/blackmisc/aviation/airlineicaocode.cpp +++ b/src/blackmisc/aviation/airlineicaocode.cpp @@ -9,6 +9,7 @@ #include "airlineicaocode.h" #include "callsign.h" +#include "blackmisc/simulation/matchingutils.h" #include "blackmisc/db/datastoreutility.h" #include "blackmisc/comparefunctions.h" #include "blackmisc/icons.h" @@ -32,6 +33,7 @@ using namespace BlackMisc; using namespace BlackMisc::Db; +using namespace BlackMisc::Simulation; namespace BlackMisc { @@ -46,7 +48,7 @@ namespace BlackMisc } } - CAirlineIcaoCode::CAirlineIcaoCode(const QString &airlineDesignator, const QString &airlineName, const BlackMisc::CCountry &country, const QString &telephony, bool virtualAirline, bool operating) + CAirlineIcaoCode::CAirlineIcaoCode(const QString &airlineDesignator, const QString &airlineName, const CCountry &country, const QString &telephony, bool virtualAirline, bool operating) : m_designator(airlineDesignator.trimmed().toUpper()), m_name(airlineName), m_telephonyDesignator(telephony), m_country(country), m_isVa(virtualAirline), m_isOperating(operating) { if (m_designator.length() == 4) @@ -57,7 +59,7 @@ namespace BlackMisc const QString CAirlineIcaoCode::getVDesignator() const { - if (!isVirtualAirline()) { return m_designator; } + if (!this->isVirtualAirline()) { return m_designator; } return QLatin1Char('V') % m_designator; } @@ -89,7 +91,7 @@ namespace BlackMisc QString CAirlineIcaoCode::getSimplifiedName() const { - return BlackMisc::simplifyNameForSearch(this->getName()); + return simplifyNameForSearch(this->getName()); } bool CAirlineIcaoCode::hasValidCountry() const @@ -183,7 +185,7 @@ namespace BlackMisc QLatin1String(" Mil: ") % boolToYesNo(this->isMilitary()); } - CVariant CAirlineIcaoCode::propertyByIndex(const BlackMisc::CPropertyIndex &index) const + CVariant CAirlineIcaoCode::propertyByIndex(const CPropertyIndex &index) const { if (index.isMyself()) { return CVariant::from(*this); } if (IDatastoreObjectWithIntegerKey::canHandleIndex(index)) { return IDatastoreObjectWithIntegerKey::propertyByIndex(index); } @@ -297,7 +299,7 @@ namespace BlackMisc QString s(getVDesignator()); if (s.isEmpty()) s = "????"; if (hasName()) { s = s.append(" ").append(getName()); } - return s.append(getDbKeyAsStringInParentheses(" ")); + return s.append(this->getDbKeyAsStringInParentheses(" ")); } CAirlineIcaoCode CAirlineIcaoCode::thisOrCallsignCode(const CCallsign &callsign) const @@ -360,34 +362,43 @@ namespace BlackMisc return this->getCombinedStringWithKey(); } - int CAirlineIcaoCode::calculateScore(const CAirlineIcaoCode &otherCode) const + int CAirlineIcaoCode::calculateScore(const CAirlineIcaoCode &otherCode, CStatusMessageList *log) const { - if (this->isDbEqual(otherCode)) { return 100; } + if (this->isDbEqual(otherCode)) + { + CMatchingUtils::addLogDetailsToList(log, *this, QStringLiteral("DB equal score: 100")); + return 100; + } const bool bothFromDb = this->isLoadedFromDb() && otherCode.isLoadedFromDb(); int score = 0; if (otherCode.hasValidDesignator() && this->getDesignator() == otherCode.getDesignator()) { score += 60; + CMatchingUtils::addLogDetailsToList(log, *this, QString("Same designator: %1").arg(score)); } // only for DB values we check VA if (bothFromDb && this->isVirtualAirline() == otherCode.isVirtualAirline()) { score += 20; + CMatchingUtils::addLogDetailsToList(log, *this, QString("VA equality: %1").arg(score)); } // consider the various names if (this->hasName() && this->getName() == otherCode.getName()) { score += 20; + CMatchingUtils::addLogDetailsToList(log, *this, QString("Same name '%1': %2").arg(this->getName()).arg(score)); } else if (this->hasTelephonyDesignator() && this->getTelephonyDesignator() == otherCode.getTelephonyDesignator()) { score += 15; + CMatchingUtils::addLogDetailsToList(log, *this, QString("Same telephony '%1': %2").arg(this->getTelephonyDesignator()).arg(score)); } else if (this->hasSimplifiedName() && this->getSimplifiedName() == otherCode.getSimplifiedName()) { score += 10; + CMatchingUtils::addLogDetailsToList(log, *this, QString("Same simplified name '%1': %2").arg(this->getSimplifiedName()).arg(score)); } return score; } diff --git a/src/blackmisc/aviation/airlineicaocode.h b/src/blackmisc/aviation/airlineicaocode.h index c373fbdf3..6e06c7029 100644 --- a/src/blackmisc/aviation/airlineicaocode.h +++ b/src/blackmisc/aviation/airlineicaocode.h @@ -223,7 +223,7 @@ namespace BlackMisc QString asHtmlSummary() const; //! Score against other code 0..100 - int calculateScore(const CAirlineIcaoCode &otherCode) const; + int calculateScore(const CAirlineIcaoCode &otherCode, CStatusMessageList *log = nullptr) const; //! Valid designator? static bool isValidAirlineDesignator(const QString &airline); diff --git a/src/blackmisc/aviation/livery.cpp b/src/blackmisc/aviation/livery.cpp index e2bc73054..ad3a51e0f 100644 --- a/src/blackmisc/aviation/livery.cpp +++ b/src/blackmisc/aviation/livery.cpp @@ -7,10 +7,11 @@ * contained in the LICENSE file. */ +#include "blackmisc/simulation/matchingutils.h" +#include "blackmisc/db/datastoreutility.h" #include "blackmisc/aviation/livery.h" #include "blackmisc/compare.h" #include "blackmisc/comparefunctions.h" -#include "blackmisc/db/datastoreutility.h" #include "blackmisc/logcategory.h" #include "blackmisc/logcategorylist.h" #include "blackmisc/propertyindex.h" @@ -29,6 +30,7 @@ using namespace BlackMisc; using namespace BlackMisc::Db; using namespace BlackMisc::PhysicalQuantities; +using namespace BlackMisc::Simulation; namespace BlackMisc { @@ -113,7 +115,7 @@ namespace BlackMisc bool CLivery::matchesCombinedCode(const QString &candidate) const { if (candidate.isEmpty() || !this->hasCombinedCode()) { return false; } - QString c(candidate.trimmed().toUpper()); + const QString c(candidate.trimmed().toUpper()); return c == m_combinedCode; } @@ -372,9 +374,13 @@ namespace BlackMisc ).replace(" ", " "); } - int CLivery::calculateScore(const CLivery &otherLivery, bool preferColorLiveries) const + int CLivery::calculateScore(const CLivery &otherLivery, bool preferColorLiveries, CStatusMessageList *log) const { - if (this->isDbEqual(otherLivery)) { return 100; } + if (this->isDbEqual(otherLivery)) + { + CMatchingUtils::addLogDetailsToList(log, *this, QStringLiteral("Equal DB code: 100")); + return 100; + } // get a level static const int sameAirlineIcaoLevel = CAirlineIcaoCode("DLH").calculateScore(CAirlineIcaoCode("DLH")); @@ -382,11 +388,13 @@ namespace BlackMisc int score = 0; const double colorMultiplier = 1.0 - this->getColorDistance(otherLivery); + if (this->isColorLivery() && otherLivery.isColorLivery()) { // 2 color liveries 25..85 score = 25; score += 60 * colorMultiplier; + CMatchingUtils::addLogDetailsToList(log, *this, QString("2 color liveries, color multiplier %1: %2").arg(colorMultiplier).arg(score)); } else if (this->isAirlineLivery() && otherLivery.isAirlineLivery()) { @@ -395,9 +403,14 @@ namespace BlackMisc // 0..25 based on color distance // 0..10 based on mil.flag // same ICAO at least means 30, max 50 - score = 0.5 * this->getAirlineIcaoCode().calculateScore(otherLivery.getAirlineIcaoCode()); + score = 0.5 * this->getAirlineIcaoCode().calculateScore(otherLivery.getAirlineIcaoCode(), log); score += 25 * colorMultiplier; - if (this->isMilitary() == otherLivery.isMilitary()) { score += 10; } + CMatchingUtils::addLogDetailsToList(log, *this, QString("2 airline liveries, color multiplier %1: %2").arg(colorMultiplier).arg(score)); + if (this->isMilitary() == otherLivery.isMilitary()) + { + CMatchingUtils::addLogDetailsToList(log, *this, QString("Mil.flag '%1' matches: %2").arg(boolToYesNo(this->isMilitary())).arg(score)); + score += 10; + } } else if ((this->isColorLivery() && otherLivery.isAirlineLivery()) || (otherLivery.isColorLivery() && this->isAirlineLivery())) { @@ -406,6 +419,7 @@ namespace BlackMisc // 25 is weaker as same ICAO code / 2 from above score = preferColorLiveries ? 25 : 0; score += 25 * colorMultiplier; // needs to be the same as in 2 airlines + CMatchingUtils::addLogDetailsToList(log, *this, QString("Color/airline mixed, color multiplier %1: %2").arg(colorMultiplier).arg(score)); } return score; } diff --git a/src/blackmisc/aviation/livery.h b/src/blackmisc/aviation/livery.h index 6e36c61b8..1fd254a9a 100644 --- a/src/blackmisc/aviation/livery.h +++ b/src/blackmisc/aviation/livery.h @@ -178,7 +178,7 @@ namespace BlackMisc //! Score by comparison to another livery 0..100 //! \remark normally used with liveries preselect by airline ICAO code - int calculateScore(const CLivery &otherLivery, bool preferColorLiveries = false) const; + int calculateScore(const CLivery &otherLivery, bool preferColorLiveries = false, CStatusMessageList *log = nullptr) const; //! Object from JSON static CLivery fromDatabaseJson(const QJsonObject &json, const QString &prefix = QString("liv_")); diff --git a/src/blackmisc/simulation/aircraftmodel.cpp b/src/blackmisc/simulation/aircraftmodel.cpp index e9ae6676c..4fa354320 100644 --- a/src/blackmisc/simulation/aircraftmodel.cpp +++ b/src/blackmisc/simulation/aircraftmodel.cpp @@ -578,10 +578,9 @@ namespace BlackMisc int CAircraftModel::calculateScore(const CAircraftModel &compareModel, bool preferColorLiveries, CStatusMessageList *log) const { - const int icaoScore = this->getAircraftIcaoCode().calculateScore(compareModel.getAircraftIcaoCode()); - CMatchingUtils::addLogDetailsToList(log, this->getCallsign(), QString("ICAO score: ").arg(icaoScore)); - const int liveryScore = this->getLivery().calculateScore(compareModel.getLivery(), preferColorLiveries); - CMatchingUtils::addLogDetailsToList(log, this->getCallsign(), QString("Livery score: ").arg(liveryScore)); + const int icaoScore = this->getAircraftIcaoCode().calculateScore(compareModel.getAircraftIcaoCode(), log); + const int liveryScore = this->getLivery().calculateScore(compareModel.getLivery(), preferColorLiveries, log); + CMatchingUtils::addLogDetailsToList(log, this->getCallsign(), QString("ICAO score: %1 | livery score: %2").arg(icaoScore).arg(liveryScore)); return 0.5 * (icaoScore + liveryScore); } diff --git a/src/blackmisc/simulation/aircraftmodellist.cpp b/src/blackmisc/simulation/aircraftmodellist.cpp index 2728c03bb..592d7ad7f 100644 --- a/src/blackmisc/simulation/aircraftmodellist.cpp +++ b/src/blackmisc/simulation/aircraftmodellist.cpp @@ -718,15 +718,23 @@ namespace BlackMisc ScoredModels scoreMap; // normally prefer colors if there is no airline - CMatchingUtils::addLogDetailsToList(log, remoteModel.getCallsign(), QString("Prefer color liveries: %1, airline: '%2', ignore zero scores: %3").arg(boolToYesNo(preferColorLiveries), remoteModel.getAirlineIcaoCodeDesignator(), boolToYesNo(ignoreZeroScores))); - CMatchingUtils::addLogDetailsToList(log, remoteModel.getCallsign(), QString("Scoring in list with %1 models, airline liveries: %2, color liveries: %3").arg(this->size()).arg(this->countModelsWithAirlineLivery()).arg(this->countModelsWithColorLivery())); + CMatchingUtils::addLogDetailsToList(log, remoteModel.getCallsign(), QString("Prefer color liveries: '%1', airline: '%2', ignore zero scores: '%3'").arg(boolToYesNo(preferColorLiveries), remoteModel.getAirlineIcaoCodeDesignator(), boolToYesNo(ignoreZeroScores))); + CMatchingUtils::addLogDetailsToList(log, remoteModel.getCallsign(), QString("--- Start scoring in list with %1 models, airline liveries: %2, color liveries: %3").arg(this->size()).arg(this->countModelsWithAirlineLivery()).arg(this->countModelsWithColorLivery())); + int c = 1; for (const CAircraftModel &model : *this) { - const int score = model.calculateScore(remoteModel, preferColorLiveries, log); + CStatusMessageList subMsgs; + const int score = model.calculateScore(remoteModel, preferColorLiveries, log ? &subMsgs : nullptr); if (ignoreZeroScores && score < 1) { continue; } + + CMatchingUtils::addLogDetailsToList(log, remoteModel.getCallsign(), QString("--- Calculating #%1 '%2'---").arg(c++).arg(model.getModelStringAndDbKey())); + if (log) { log->push_back(subMsgs); } + CMatchingUtils::addLogDetailsToList(log, remoteModel.getCallsign(), QString("--- End calculating #%1 ---").arg(c)); + scoreMap.insertMulti(score, model); } + CMatchingUtils::addLogDetailsToList(log, remoteModel.getCallsign(), QStringLiteral("--- End scoring ---")); return scoreMap; }