8 #include <QRegularExpression>
9 #include <QStringBuilder>
22 using namespace swift::misc::db;
23 using namespace swift::misc::physical_quantities;
27 namespace swift::misc::aviation
29 CAircraftIcaoCode::CAircraftIcaoCode(
const QString &icao,
const QString &combinedType)
30 : m_designator(icao.trimmed().toUpper()), m_combinedType(combinedType.trimmed().toUpper())
35 bool military,
int rank)
36 : m_designator(icao.trimmed().toUpper()), m_combinedType(combinedType.trimmed().toUpper()),
37 m_manufacturer(manufacturer.trimmed()), m_modelDescription(model.trimmed()), m_wtc(wtc),
38 m_realWorld(realworld), m_legacy(legacy), m_military(military), m_rank(rank)
40 if (m_rank < 0 || m_rank >= 10) { m_rank = 10; }
45 bool realworld,
bool legacy,
bool military,
int rank)
46 : m_designator(icao.trimmed().toUpper()), m_iataCode(iata.trimmed().toUpper()),
47 m_combinedType(combinedType.trimmed().toUpper()), m_manufacturer(manufacturer.trimmed()),
48 m_modelDescription(model.trimmed()), m_wtc(wtc), m_realWorld(realworld), m_legacy(legacy),
49 m_military(military), m_rank(rank)
51 if (m_rank < 0 || m_rank >= 10) { m_rank = 10; }
59 : m_designator(icao.trimmed().toUpper()), m_iataCode(iata.trimmed().toUpper()),
60 m_family(family.trimmed().toUpper()), m_combinedType(combinedType.trimmed().toUpper()),
61 m_manufacturer(manufacturer.trimmed()), m_modelDescription(model.trimmed()),
62 m_modelIataDescription(modelIata.trimmed()), m_modelSwiftDescription(modelSwift.trimmed()), m_wtc(wtc),
63 m_realWorld(realworld), m_legacy(legacy), m_military(military), m_rank(rank)
65 if (m_rank < 0 || m_rank >= 10) { m_rank = 10; }
78 QStringLiteral(
"%1 %2 %3 cat: %4")
82 QStringLiteral(
"%1 %2 %3")
100 if (m_modelIataDescription.
isEmpty())
104 if (m_modelSwiftDescription.
isEmpty())
166 if (log) {
addLogDetailsToList(log, *
this, QStringLiteral(
"Same designator: %1").arg(score)); }
168 int scoreOld = score;
169 if (this->
getRank() == 0) { score += 15; }
170 else if (this->
getRank() == 1) { score += 12; }
171 else if (this->
getRank() < 10) { score += (10 - this->
getRank()); }
172 if (score > scoreOld) {
addLogDetailsToList(log, *
this, QStringLiteral(
"Added rank: %1").arg(score)); }
194 if (eMy == eOther && eMy >= 0) { score += 4; }
195 else if (eMy > 0 && eOther > 0)
197 const int eDiff = qAbs(eMy - eOther);
198 if (eDiff == 1) { score += 2; }
199 else if (eDiff == 2) { score += 1; }
206 if (tMy == tOther) { score += 4; }
214 else if (this->
isVtol() && otherCode.
isVtol()) { score += 4; }
215 addLogDetailsToList(log, *
this, QStringLiteral(
"Added combined code parts: %1").arg(score));
227 QStringLiteral(
"Matches manufacturer '%1': %2").arg(this->
getManufacturer()).arg(score));
233 QStringLiteral(
"Contains manufacturer '%1': %2").arg(this->
getManufacturer()).arg(score));
260 if (!guessedCGOut.
isNull() && !guessedVRotateOut.
isNull()) {
return; }
271 if (engineType ==
'T')
273 guessedCG =
CLength(2.0, CLengthUnit::m());
277 else if (engines == 2)
279 guessedCG =
CLength(2.0, CLengthUnit::m());
280 guessedVRotate =
CSpeed(100, CSpeedUnit::kts());
281 if (engineType ==
'T')
283 guessedCG =
CLength(2.0, CLengthUnit::m());
286 if (engineType ==
'J')
289 guessedVRotate =
CSpeed(120, CSpeedUnit::kts());
290 guessedCG =
CLength(2.5, CLengthUnit::m());
294 else if (engines > 2)
296 guessedCG =
CLength(4.0, CLengthUnit::m());
297 guessedVRotate =
CSpeed(70, CSpeedUnit::kts());
298 if (engineType ==
'J')
301 guessedCG =
CLength(6.0, CLengthUnit::m());
302 guessedVRotate =
CSpeed(140, CSpeedUnit::kts());
307 if (engineType ==
'J')
310 if (this->
isMilitary()) { guessedVRotate *= 1.20; }
315 if (this->
isVtol()) { guessedVRotate =
CSpeed(0, CSpeedUnit::kts()); }
319 if (guessedCGOut.
isNull()) { guessedCGOut = guessedCG; }
320 if (guessedVRotateOut.
isNull()) { guessedVRotateOut = guessedVRotate; }
363 if (m_combinedType.
length() != 3)
return {};
364 return m_combinedType.
right(1);
370 if (et.
length() == 1) {
return et[0]; }
376 if (m_combinedType.
length() < 2) {
return -1; }
378 if (c ==
"-") {
return -1; }
380 int ec = c.
toInt(&ok);
381 if (ok && ec >= 0 && ec < 10) {
return ec; }
387 if (m_combinedType.
length() < 2) {
return {}; }
388 return m_combinedType.
mid(1, 1);
393 if (m_combinedType.
length() < 1) {
return {}; }
395 if (c ==
"-") {
return {}; }
401 if (m_combinedType.
length() < 1) {
return {}; }
403 if (c ==
'-') {
return {}; }
418 combined.removeDuplicates();
419 return combined.join(
", ");
442 if (combinedType.
length() != 3) {
return false; }
445 const bool wildcard = cc.
contains(
'*');
446 if (!wildcard) {
return false; }
453 if (cat.
isEmpty() || cat.
at(0) != at) {
return false; }
459 if (et ==
'*') {
return true; }
461 return cet.
length() == 1 && cet.
at(0) == et;
465 const QString &manufacturer)
const
480 if (manufacturer.
isEmpty()) {
return false; }
481 return (manufacturer.
length() == m_manufacturer.
length() &&
488 if (m_designator.
length() == 4)
490 if (m_designator ==
"BALL" || m_designator ==
"SHIP" || m_designator ==
"GYRO" || m_designator ==
"UHEL")
519 m_military = military;
521 m_realWorld = realWorld;
579 Q_ASSERT_X(fuzzyMatch >= -1 && fuzzyMatch <= 100, Q_FUNC_INFO,
"fuzzyMatch range 0..100 or -1");
580 if (designator.
isEmpty()) {
return false; }
585 if (result) { *result = r; }
586 return (r >= fuzzyMatch);
591 if (result) { *result = e ? 100 : 0; }
598 Q_ASSERT_X(fuzzyMatch >= -1 && fuzzyMatch <= 100, Q_FUNC_INFO,
"fuzzyMatch range 0..100 or -1");
599 if (iata.
isEmpty()) {
return false; }
604 if (result) { *result = r; }
605 return (r >= fuzzyMatch);
610 if (result) { *result = e ? 100 : 0; }
617 Q_ASSERT_X(fuzzyMatch >= -1 && fuzzyMatch <= 100, Q_FUNC_INFO,
"fuzzyMatch range 0..100 or -1");
618 if (family.
isEmpty()) {
return false; }
623 if (result) { *result = r; }
624 return r >= fuzzyMatch;
629 if (result) { *result = e ? 100 : 0; }
636 if (icaoOrIata.
isEmpty()) {
return false; }
642 if (icaoIataOrFamily.
isEmpty()) {
return false; }
650 if (IDatastoreObjectWithIntegerKey::canHandleIndex(index))
652 return IDatastoreObjectWithIntegerKey::propertyByIndex(index);
685 if (IDatastoreObjectWithIntegerKey::canHandleIndex(index))
687 IDatastoreObjectWithIntegerKey::setPropertyByIndex(index, variant);
703 case IndexIsLegacy: m_legacy = variant.
toBool();
break;
704 case IndexIsMilitary: m_military = variant.
toBool();
break;
705 case IndexRank: m_rank = variant.
toInt();
break;
713 if (IDatastoreObjectWithIntegerKey::canHandleIndex(index))
715 return IDatastoreObjectWithIntegerKey::comparePropertyByIndex(index, compareValue);
725 case IndexCombinedAircraftType:
727 case IndexModelDescription:
729 case IndexModelIataDescription:
731 case IndexModelSwiftDescription:
733 case IndexCombinedDescription:
748 case IndexWtc:
return m_wtc == compareValue.
getWtc();
749 case IndexIsLegacy:
return Compare::compare(m_legacy, compareValue.
isLegacyAircraft());
750 case IndexIsMilitary:
return Compare::compare(m_military, compareValue.
isMilitary());
751 case IndexIsVtol:
return Compare::compare(
isVtol(), compareValue.
isVtol());
752 case IndexIsRealworld:
return Compare::compare(m_realWorld, compareValue.
isRealWorld());
753 case IndexRank:
return Compare::compare(m_rank, compareValue.
getRank());
758 Q_ASSERT_X(
false, Q_FUNC_INFO,
"No comparison");
765 if (!designator[0].isUpper()) {
return false; }
771 if (combinedType.
length() != 3) {
return false; }
774 static const QString validDescriptions =
"AGHSLT";
776 static const QString validEngines =
"EJPT-";
778 if (!validDescriptions.
contains(combinedType[0])) {
return false; }
779 if (!combinedType[1].isDigit()) {
return false; }
780 if (!validEngines.
contains(combinedType[2])) {
return false; }
786 static const QString z(
"ZZZZ");
792 static const QString g(
"GLID");
819 {
"L1P",
"L2P" }, {
"L1P",
"S1P" }, {
"L2J",
"L3J" }, {
"L2J",
"L4J" }, {
"L3J",
"L4J" }
823 if (knownCodes.contains(combinedCode)) {
return knownCodes.values(combinedCode); }
833 int engineCount = combinedCode[1].digitValue();
836 for (
int c = 2; c < 5; c++)
838 if (c == engineCount) {
continue; }
849 return e ==
'P' || e ==
'E' || e ==
'T';
866 if (!log) {
return; }
867 if (message.
isEmpty()) {
return; }
879 const int engineCount(json.
value(prefix % u
"enginecount").
toInt(-1));
880 const int categoryId(json.
value(prefix % u
"idcategory").
toInt(-1));
890 const QString combined(createdCombinedString(type, engineCount, engine));
896 wtcString = wtcString.
right(1);
898 Q_ASSERT_X(wtcString.
length() < 2, Q_FUNC_INFO,
"WTC too long");
902 const bool real = CDatastoreUtility::dbBoolStringToBool(json.
value(prefix % u
"realworld").
toString());
903 const bool legacy = CDatastoreUtility::dbBoolStringToBool(json.
value(prefix % u
"legacy").
toString());
904 const bool military = CDatastoreUtility::dbBoolStringToBool(json.
value(prefix % u
"military").
toString());
905 const int rank(json.
value(prefix % u
"rank").
toInt(10));
907 CAircraftIcaoCode code(designator, iata, family, combined, manufacturer, model, modelIata, modelSwift, wtc,
908 real, legacy, military, rank);
917 Q_ASSERT_X(engineCount.
length() < 2, Q_FUNC_INFO,
"Wrong engine count");
919 (engineCount.
isEmpty() ? QStringLiteral(
"-") : engineCount.trimmed()) %
920 (engine.isEmpty() ? QStringLiteral(
"-") : engine.trimmed().left(1).toUpper());
923 QString CAircraftIcaoCode::createdCombinedString(
const QString &type,
int engineCount,
const QString &engine)
925 const bool valid = (engineCount >= 0 && engineCount < 10);
926 return createdCombinedString(type, valid ?
QString::number(engineCount) :
"", engine);
static const QString & aviation()
Aviation specific.
static const QString & validation()
Validation.
A log category is an arbitrary string tag which can be attached to log messages.
A sequence of log categories.
static CLogCategoryList fromQStringList(const QStringList &stringList)
Convert a string list, such as that returned by toQStringList(), into a CLogCategoryList.
Non-owning reference to a CPropertyIndex with a subset of its features.
Q_REQUIRED_RESULT CPropertyIndexRef copyFrontRemoved() const
Copy with first element removed.
CastType frontCasted() const
First element casted to given type, usually the PropertIndex enum.
bool isMyself() const
Myself index, used with nesting.
void push_back(const T &value)
Appends an element at the end of the sequence.
Streamable status message, e.g.
constexpr static auto SeverityError
Status severities.
Status messages, e.g. from Core -> GUI.
QDateTime getUtcTimestamp() const
Get timestamp.
void setUtcTimestamp(const QDateTime ×tamp)
Set timestamp.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
int comparePropertyByIndex(CPropertyIndexRef index, const CAircraftCategory &compareValue) const
Compare for index.
bool isNull() const
Null category?
QString getNameDbKey() const
Designator and DB key.
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Value object for ICAO classification.
CWakeTurbulenceCategory getWtc() const
Get WTC.
QString getCombinedFamilyStringWithKey() const
Combined family descriptive string with key.
static const QString & getUnassignedDesignator()
The unassigned designator ("ZZZZ")
bool isRealWorld() const
Real world aircraft?
bool hasModelDescription() const
Has model description?
QString getCombinedIataStringWithKey() const
Combined IATA descriptive string with key.
void setRank(int rank)
Ranking.
bool hasFamily() const
Has family?
bool isNull() const
Null ICAO?
bool hasDesignator() const
Aircraft designator?
bool hasCategory() const
Has category?
bool isIataSameAsDesignator() const
IATA code same as designator?
bool hasKnownDesignator() const
Has designator and designator is not "ZZZZ".
bool isVtol() const
Is VTOL aircraft (helicopter, tilt wing)
ColumnIndex
Properties by index.
@ IndexDesignatorManufacturer
designator and manufacturer
static bool isEPTEngineType(const QChar engineType)
Engine tye is Electric, Piston, TurboProp.
QString getCombinedIcaoStringWithKey() const
Combined ICAO descriptive string with key.
const QString & getFamily() const
Family (e.g. A350)
QVariant propertyByIndex(swift::misc::CPropertyIndexRef index) const
Property by index.
static bool isValidCombinedType(const QString &combinedType)
Valid combined type.
static const QStringList & getSpecialDesignators()
List of the special designators ("ZZZZ", "UHEL", ...)
bool hasSpecialDesignator() const
Special designator.
void setCodeFlags(bool military, bool legacy, bool realWorld)
Flags.
bool matchesDesignatorOrIata(const QString &icaoOrIata) const
Matches ICAO or IATA code.
static const CAircraftIcaoCode & unassignedIcao()
Unassigned ICAO code "ZZZZ".
QString getAircraftType() const
Aircraft type, such a L(andplane), S(eaplane), H(elicopter)
bool matchesDesignator(const QString &designator, int fuzzyMatch=-1, int *result=nullptr) const
Matches designator string?
CAircraftIcaoCode()
Default constructor.
bool matchesDesignatorIataOrFamily(const QString &icaoIataOrFamily) const
Matches ICAO, IATA, family?
QString getEngineType() const
Get engine type, e.g. "J".
static void addLogDetailsToList(CStatusMessageList *log, const CAircraftIcaoCode &icao, const QString &message, const QStringList &extraCategories={}, CStatusMessage::StatusSeverity s=CStatusMessage::SeverityInfo)
Specialized log for matching / reverse lookup.
QChar getEngineTypeChar() const
Get engine type, e.g. "J".
bool hasIataCode() const
Has IATA code?
int getEnginesCount() const
Engine count if any, -1 if no value is set.
const QString & getDesignator() const
Get ICAO designator, e.g. "B737".
void setModelSwiftDescription(const QString &modelDescription)
Set the alternative swift model description.
bool hasManufacturer() const
Manufacturer.
bool matchesIataCode(const QString &iata, int fuzzyMatch=-1, int *result=nullptr) const
Matches IATA string?
void setMilitary(bool military)
Military.
QString getEngineCountString() const
Engine count as string, if not available "".
void setCategoryId(int id)
Set category id.
QString getCombinedModelDescription() const
Combined description.
QString getDesignatorDbKey() const
Designator and DB key.
const QString & getModelDescription() const
Get IACO model description, e.g. "A-330-200".
void setIataCode(const QString &iata)
Set IATA code.
void setPropertyByIndex(swift::misc::CPropertyIndexRef index, const QVariant &variant)
Set property by index.
void setWtc(CWakeTurbulenceCategory wtc)
Set WTC.
void setManufacturer(const QString &manufacturer)
Set the manufacturer.
const QString & getIataCode() const
IATA code.
static CStatusMessage logMessage(const CAircraftIcaoCode &icaoCode, const QString &message, const QStringList &extraCategories={}, CStatusMessage::StatusSeverity s=CStatusMessage::SeverityInfo)
Specialized log message for matching / reverse lookup.
bool matchesCombinedType(const QString &combinedType) const
Matches given combined code.
void setCombinedType(const QString &type)
Set type.
bool hasValidDesignator() const
Valid aircraft designator?
int comparePropertyByIndex(CPropertyIndexRef index, const CAircraftIcaoCode &compareValue) const
Compare for index.
bool isMilitary() const
Military?
void setModelIataDescription(const QString &modelDescription)
Set the alternative IATA model description.
void updateMissingParts(const CAircraftIcaoCode &otherIcaoCode)
Update missing parts.
static constexpr int DesignatorMinLength
designator length (min)
CStatusMessageList validate() const
Validate data.
bool matchesAnyDescription(const QString &candidate) const
Matches any of the (unempty) descriptions.
int getRank() const
Ranking.
bool isDbDuplicate() const
Is DB duplicate? This means a redundant ICAO DB entry.
static const CAircraftIcaoCode & null()
NULL object.
QString convertToQString(bool i18n=false) const
Cast as QString.
static CAircraftIcaoCode fromDatabaseJson(const QJsonObject &json, const QString &prefix=QString())
From our database JSON format.
int calculateScore(const CAircraftIcaoCode &otherCode, CStatusMessageList *log=nullptr) const
Considers rank, manufacturer and family 0..100.
QString getCombinedIcaoCategoryStringWithKey() const
Combined ICAO descriptive string with category and key.
void setDesignator(const QString &icaoDesignator)
Set ICAO designator, e.g. "B737".
bool isFamilySameAsDesignator() const
Family same as designator?
void setRealWorld(bool realWorld)
Real world.
void setModelDescription(const QString &modelDescription)
Set the model description (ICAO description)
void setLegacy(bool legacy)
Legacy.
QString asHtmlSummary() const
As a brief HTML summary (e.g. used in tooltips)
static QStringList alternativeCombinedCodes(const QString &combinedCode)
Create relaxed combined codes, e.g "L2J" -> "L3J", ...
bool matchesCombinedTypeAndManufacturer(const QString &combinedType, const QString &manufacturer) const
Matches combined type and.
const QString & getCombinedType() const
Get type, e.g. "L2J".
const CAircraftCategory & getCategory() const
Get category.
bool matchesFamily(const QString &family, int fuzzyMatch=-1, int *result=nullptr) const
Matches family?
static constexpr int DesignatorMaxLength
designator length (max)
const QString & getModelSwiftDescription() const
Get swift model description.
bool isLegacyAircraft() const
Legacy aircraft (no current ICAO code)
static bool isValidDesignator(const QString &designator)
Valid designator?
static const QString & getGliderDesignator()
Get the glider designator.
bool hasModelSwiftDescription() const
Has swift model description?
QChar getAircraftTypeChar() const
Aircraft type, such a L(andplane), S(eaplane), H(elicopter)
bool hasCompleteData() const
All data set?
bool hasValidCombinedType() const
Combined type available?
void setFamily(const QString &family)
Set family.
const QString & getManufacturer() const
Get manufacturer, e.g. "Airbus".
static QString normalizeDesignator(const QString &candidate)
Normalize designator, remove illegal characters.
QString getRankString() const
Ranking.
bool matchesManufacturer(const QString &manufacturer) const
Matching the manufacturer?
QString getDesignatorManufacturer() const
Designator + Manufacturer.
const QString & getModelIataDescription() const
Get IATA model description.
void guessModelParameters(physical_quantities::CLength &guessedCGOut, physical_quantities::CSpeed &guessedVRotateOut) const
Guess aircraft model parameters.
bool hasModelIataDescription() const
Has IATA model description?
bool hasValidWtc() const
Valid WTC code?
ICAO wake turbulence category.
int getDbKey() const
Get DB key.
QString getDbKeyAsString() const
DB key as string.
bool isLoadedFromDb() const
Loaded from DB.
static bool existsKey(const QJsonObject &json, const QString &prefix=QString())
Is a key available?
void setDbKey(int key)
Set the DB key.
bool isDbEqual(const IDatastoreObjectWithIntegerKey &other) const
Same DB key and hence equal.
QString getDbKeyAsStringInParentheses(const QString &prefix={}) const
Db key in parentheses, e.g. "(3)".
void setKeyVersionTimestampFromDatabaseJson(const QJsonObject &json, const QString &prefix=QString())
Set key and timestamp values.
bool hasValidDbKey() const
Has valid DB key.
int comparePropertyByIndex(CPropertyIndexRef index, const Derived &compareValue) const
Compare for index.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
QString toQString(bool i18n=false) const
Cast as QString.
Physical unit length (length)
bool isNull() const
Is quantity null?
Free functions in swift::misc.
SWIFT_MISC_EXPORT int fuzzyShortStringComparision(const QString &str1, const QString &str2, Qt::CaseSensitivity cs=Qt::CaseSensitive)
Fuzzy compare for short strings (like ICAO designators)
QString removeChars(const QString &s, F predicate)
Return a string with characters removed that match the given predicate.
int indexOfChar(const QString &s, F predicate)
Index of first character in the string matching the given predicate, or -1 if not found.
StatusSeverity
Status severities.
bool containsChar(const QString &s, F predicate)
True if any character in the string matches the given predicate.
SWIFT_MISC_EXPORT const QString & boolToYesNo(bool v)
Bool to yes/no.
int digitValue(char32_t ucs4)
bool isDigit(char32_t ucs4)
bool isLetterOrNumber(char32_t ucs4)
bool isSpace(char32_t ucs4)
bool isUpper(char32_t ucs4)
char32_t toUpper(char32_t ucs4)
QJsonValue value(QLatin1StringView key) const const
int toInt(int defaultValue) const const
QString toString() const const
void append(QList< T > &&value)
void push_back(QList< T >::parameter_type value)
const QChar at(qsizetype position) const const
int compare(QLatin1StringView s1, const QString &s2, Qt::CaseSensitivity cs)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString left(qsizetype n) &&
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) &&
QString number(double n, char format, int precision)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QString right(qsizetype n) &&
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
int toInt(bool *ok, int base) const const
QString toUpper() const const
QString trimmed() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QVariant fromValue(T &&value)
bool toBool() const const
int toInt(bool *ok) const const
#define SWIFT_DEFINE_VALUEOBJECT_MIXINS(Namespace, Class)
Explicit template definition of mixins for a CValueObject subclass.