diff --git a/src/blackmisc/aviation/aircraftcategory.cpp b/src/blackmisc/aviation/aircraftcategory.cpp index d14edb504..cd561550d 100644 --- a/src/blackmisc/aviation/aircraftcategory.cpp +++ b/src/blackmisc/aviation/aircraftcategory.cpp @@ -83,6 +83,23 @@ namespace BlackMisc m_l3 = l3; } + bool CAircraftCategory::isLevel(int l1, int l2, int l3) const + { + return l1 == m_l1 && l2 == m_l2 && l3 == m_l3; + } + + bool CAircraftCategory::isLevel(const QList &level) const + { + if (level.size() != 3) { return false;} + return m_l1 == level[0] && m_l2 == level[1] && m_l3 == level[2]; + } + + bool CAircraftCategory::isLevel(const CAircraftCategory &category) const + { + if (category.isNull()) { return false; } + return category.m_l1 == m_l1 && category.m_l2 == m_l2 && category.m_l3 == m_l3; + } + QList CAircraftCategory::getLevel() const { QList l; diff --git a/src/blackmisc/aviation/aircraftcategory.h b/src/blackmisc/aviation/aircraftcategory.h index 30e2238ec..c738ed663 100644 --- a/src/blackmisc/aviation/aircraftcategory.h +++ b/src/blackmisc/aviation/aircraftcategory.h @@ -78,12 +78,24 @@ namespace BlackMisc //! Level void setLevel(int l1, int l2, int l3); + //! Is that given level? + bool isLevel(int l1, int l2, int l3) const; + + //! Is that given level? + bool isLevel(const QList &level) const; + + //! Is that given level? + bool isLevel(const CAircraftCategory &category) const; + //! Levels depending on depth, 3.2 -> 3,2 / 1.0 -> 1 / 4.3.1 -> 4,3,1 QList getLevel() const; //! First level int getFirstLevel() const { return m_l1; } + //! Second level + int getSecondLevel() const { return m_l2; } + //! First level bool isFirstLevel() const; diff --git a/src/blackmisc/aviation/aircraftcategorylist.cpp b/src/blackmisc/aviation/aircraftcategorylist.cpp index 36a163733..1478dc597 100644 --- a/src/blackmisc/aviation/aircraftcategorylist.cpp +++ b/src/blackmisc/aviation/aircraftcategorylist.cpp @@ -71,6 +71,20 @@ namespace BlackMisc { levels.insert(category.getFirstLevel()); } + levels.remove(0); + QList ll = levels.toList(); + std::sort(ll.begin(), ll.end()); + return ll; + } + + QList CAircraftCategoryList::getSecondLevels() const + { + QSet levels; + for (const CAircraftCategory &category : *this) + { + levels.insert(category.getSecondLevel()); + } + levels.remove(0); QList ll = levels.toList(); std::sort(ll.begin(), ll.end()); return ll; @@ -117,12 +131,14 @@ namespace BlackMisc return categories; } - CAircraftCategoryList CAircraftCategoryList::findByLevel(const QList &level) const + CAircraftCategoryList CAircraftCategoryList::findByLevel(const QList &level, bool noRootNode) const { CAircraftCategoryList categories; if (level.isEmpty()) { return categories; } + const int ls = level.size(); for (const CAircraftCategory &category : *this) { + if (noRootNode && ls == category.getDepth()) { continue; } // ignore root nodes if (category.matchesLevel(level)) { categories.push_back(category); @@ -131,6 +147,16 @@ namespace BlackMisc return categories; } + CAircraftCategory CAircraftCategoryList::findByFullLevel(const QList &level) const + { + if (level.size() != 3) { return {}; } + for (const CAircraftCategory &category : *this) + { + if (category.isLevel(level[0], level[1], level[2])) { return category; } + } + return {}; + } + CAircraftCategoryList CAircraftCategoryList::findFirstLevels() const { return this->findBy(&CAircraftCategory::isFirstLevel, true); @@ -147,12 +173,32 @@ namespace BlackMisc else { levels.removeLast(); - categories = this->findByLevel(levels); + categories = this->findByLevel(levels, true); } categories.remove(category); return categories; } + CAircraftCategoryList CAircraftCategoryList::findInParallelBranch(const CAircraftCategory &category) const + { + if (category.isNull() || this->isEmpty()) { return {}; } + if (category.isFirstLevel()) { return {}; } + const bool isL2 = category.getDepth() == 2; + const QList loopLevels = isL2 ? this->getFirstLevels() : this->getSecondLevels(); + if (loopLevels.isEmpty()) { return {}; } + + QList level = category.getLevel(); + CAircraftCategoryList result; + for (int l = loopLevels.front(); loopLevels.back() >= l; ++l) + { + level[isL2 ? 0 : 1] = l; + if (category.isLevel(level)) { continue; } // ignore category itself + const CAircraftCategory cat = this->findByFullLevel(level); + if (!cat.isNull()) { result.push_back(cat); } + } + return result; + } + int CAircraftCategoryList::removeIfLevel(const QList &level) { if (level.isEmpty()) { return 0; } diff --git a/src/blackmisc/aviation/aircraftcategorylist.h b/src/blackmisc/aviation/aircraftcategorylist.h index 39fc575f1..08d8b54ce 100644 --- a/src/blackmisc/aviation/aircraftcategorylist.h +++ b/src/blackmisc/aviation/aircraftcategorylist.h @@ -61,6 +61,9 @@ namespace BlackMisc //! All levels sorted QList getFirstLevels() const; + //! All levels sorted + QList getSecondLevels() const; + //! Find highest (top) level of categories CAircraftCategoryList findHighestLevels(const CAircraftCategoryList &categories); @@ -68,7 +71,10 @@ namespace BlackMisc CAircraftCategoryList findByFirstLevel(int level) const; //! Find by levels - CAircraftCategoryList findByLevel(const QList &level) const; + CAircraftCategoryList findByLevel(const QList &level, bool noRootNode = false) const; + + //! Find by exact levels + CAircraftCategory findByFullLevel(const QList &level) const; //! Find first levels CAircraftCategoryList findFirstLevels() const; @@ -77,6 +83,10 @@ namespace BlackMisc //! \remark if level is 3.2, siblings are 3.1 and 3.3 CAircraftCategoryList findSiblings(const CAircraftCategory &category) const; + //! Find siblings + //! \remark if level is 3.2, finds 1.2, 2.2, and 4.2 + CAircraftCategoryList findInParallelBranch(const CAircraftCategory &category) const; + //! Remove by level int removeIfLevel(const QList &level); diff --git a/src/blackmisc/simulation/categorymatcher.cpp b/src/blackmisc/simulation/categorymatcher.cpp index 5fa343c8e..939941b59 100644 --- a/src/blackmisc/simulation/categorymatcher.cpp +++ b/src/blackmisc/simulation/categorymatcher.cpp @@ -29,6 +29,7 @@ namespace BlackMisc void CCategoryMatcher::setCategories(const CAircraftCategoryList &categories) { m_all = categories; + m_all.sortByLevel(); CAircraftCategoryList gliders = categories.findByName("glider").findFirstLevels(); if (!gliders.isEmpty()) @@ -73,30 +74,52 @@ namespace BlackMisc CMatchingUtils::addLogDetailsToList(log, remoteAircraft, QStringLiteral("Disabled category matching"), getLogCategories()); return modelSet; } + if (!remoteAircraft.getAircraftIcaoCode().hasCategory()) + { + CMatchingUtils::addLogDetailsToList(log, remoteAircraft, QStringLiteral("No category in remote aircraft"), getLogCategories()); + return modelSet; + } + if (log) { CMatchingUtils::addLogDetailsToList(log, remoteAircraft, QStringLiteral("Remote aircraft has category '%1'").arg(remoteAircraft.getAircraftIcaoCode().getCategory().getNameDbKey()), getLogCategories()); } if (!m_gliders.isEmpty() && setup.getMatchingMode().testFlag(CAircraftMatcherSetup::ByCategoryGlider) && this->isGlider(remoteAircraft.getAircraftIcaoCode())) { // we have a glider const int firstLevel = this->gliderFirstLevel(); - const CAircraftModelList gliders = modelSet.findByCategoryFirstLevel(firstLevel); + const CAircraftModelList gliders = modelSet.findByCategoryFirstLevel(firstLevel); // all gliders from model set if (!gliders.isEmpty()) { const CAircraftCategory category = remoteAircraft.getAircraftIcaoCode().getCategory(); - reduced = true; // in any case reduced + reduced = true; // in any case reduced (to gliders) - const CAircraftModelList sameGliders = modelSet.findByCategory(category); + // find same category + const CAircraftModelList sameGliders = gliders.findByCategory(category); if (!sameGliders.isEmpty()) { - if (log) { CMatchingUtils::addLogDetailsToList(log, remoteAircraft, QStringLiteral("Reduced to %1 models by category : '%2'").arg(sameGliders.size()).arg(category.toQString(true)), getLogCategories()); } + if (log) { CMatchingUtils::addLogDetailsToList(log, remoteAircraft, QStringLiteral("Reduced to %1 models by category: '%2'").arg(sameGliders.size()).arg(category.toQString(true)), getLogCategories()); } return sameGliders; } - const CAircraftCategoryList siblings = m_gliders.findSiblings(category); - const CAircraftModelList siblingGliders = modelSet.findByCategories(siblings); - if (!siblings.isEmpty() && !siblingGliders.isEmpty()) + // find parallel branch category + const CAircraftCategoryList otherBranches = m_gliders.findInParallelBranch(category); + if (!otherBranches.isEmpty()) { - if (log) { CMatchingUtils::addLogDetailsToList(log, remoteAircraft, QStringLiteral("Reduced to %1 sibling models by categories : '%2'").arg(siblingGliders.size()).arg(siblings.getLevelsString()), getLogCategories()); } - return sameGliders; + const CAircraftModelList otherBranchGliders = gliders.findByCategories(otherBranches); + if (!otherBranchGliders.isEmpty()) + { + if (log) { CMatchingUtils::addLogDetailsToList(log, remoteAircraft, QStringLiteral("Reduced to %1 parallel branch models of '%2' by categories: '%3'").arg(otherBranchGliders.size()).arg(category.getLevelAndName(), otherBranches.getLevelsString()), getLogCategories()); } + return otherBranchGliders; + } + } + + const CAircraftCategoryList siblings = m_gliders.findSiblings(category); + if (!siblings.isEmpty()) + { + const CAircraftModelList siblingGliders = modelSet.findByCategories(siblings); + if (!siblings.isEmpty() && !siblingGliders.isEmpty()) + { + if (log) { CMatchingUtils::addLogDetailsToList(log, remoteAircraft, QStringLiteral("Reduced to %1 sibling models of '%2' by categories: '%3'").arg(siblingGliders.size()).arg(category.getLevelAndName(), siblings.getLevelsString()), getLogCategories()); } + return siblingGliders; + } } CMatchingUtils::addLogDetailsToList(log, remoteAircraft, QStringLiteral("Reduced to %1 models by 'GLIDER' category").arg(sameGliders.size()), getLogCategories()); @@ -104,7 +127,7 @@ namespace BlackMisc } else { - if (log) { CMatchingUtils::addLogDetailsToList(log, remoteAircraft, QStringLiteral("No glider categories of level id %1 in set").arg(firstLevel), getLogCategories()); } + if (log) { CMatchingUtils::addLogDetailsToList(log, remoteAircraft, QStringLiteral("No glider category '%1' in set").arg(m_gliders.front().getLevelAndName()), getLogCategories()); } static const QStringList substituteIcaos({ "UHEL", "GLID", "ULAC" }); // maybe also GYRO static const QString substituteIcaosStr = substituteIcaos.join(", "); diff --git a/src/blackmisc/simulation/categorymatcher.h b/src/blackmisc/simulation/categorymatcher.h index ba3ba2b25..35b9b585f 100644 --- a/src/blackmisc/simulation/categorymatcher.h +++ b/src/blackmisc/simulation/categorymatcher.h @@ -53,8 +53,8 @@ namespace BlackMisc //! Get the glider top level int gliderFirstLevel() const; - Aviation::CAircraftCategoryList m_all; - Aviation::CAircraftCategoryList m_gliders; + Aviation::CAircraftCategoryList m_all; //!< sorted by level + Aviation::CAircraftCategoryList m_gliders; //!< sorted by level Aviation::CAircraftCategoryList m_militaryWingAircraft; Aviation::CAircraftCategoryList m_militaryRotorAircraft; };