diff --git a/src/blackcore/vatsim/networkvatlib.cpp b/src/blackcore/vatsim/networkvatlib.cpp index ef7c70564..8df31c787 100644 --- a/src/blackcore/vatsim/networkvatlib.cpp +++ b/src/blackcore/vatsim/networkvatlib.cpp @@ -659,7 +659,7 @@ namespace BlackCore const QString route = flightPlan.getRoute(); const QString remarks = QString(flightPlan.getRemarks()); - const QString alt = flightPlan.getCruiseAltitude().asFpAltitudeSimpleVatsimString(); + const QString alt = flightPlan.getCruiseAltitude().asFpVatsimAltitudeString(); //! \fixme that would be the official string, can this be used? // const QString alt = flightPlan.getCruiseAltitude().asFpAltitudeString(); diff --git a/src/blackgui/altitudeedit.cpp b/src/blackgui/altitudeedit.cpp index 66a5e547c..63e2291b4 100644 --- a/src/blackgui/altitudeedit.cpp +++ b/src/blackgui/altitudeedit.cpp @@ -33,7 +33,7 @@ namespace BlackGui void CAltitudeEdit::setAltitude(const CAltitude &altitude) { - this->setText(altitude.asFpAltitudeString()); + this->setText(altitude.asFpICAOAltitudeString()); } bool CAltitudeEdit::isValid(CStatusMessageList *msgs) const diff --git a/src/blackmisc/aviation/altitude.cpp b/src/blackmisc/aviation/altitude.cpp index 6c9788375..68c6ef508 100644 --- a/src/blackmisc/aviation/altitude.cpp +++ b/src/blackmisc/aviation/altitude.cpp @@ -15,6 +15,7 @@ #include "blackmisc/comparefunctions.h" #include "blackmisc/iconlist.h" #include "blackmisc/icons.h" +#include "altitude.h" #include #include @@ -173,7 +174,14 @@ namespace BlackMisc bool CAltitude::parseFromFpAltitudeString(const QString &value, CStatusMessageList *msgs) { - QString v(value.trimmed()); + QString v(value.trimmed()); // do not convert case because of units + if (v.startsWith("VFR", Qt::CaseInsensitive)) + { + // we set a more or less meaningful value + *this = CAltitude(5000, MeanSeaLevel, CLengthUnit::ft()); + return true; + } + this->setNull(); if (v.length() < 3) { @@ -210,25 +218,25 @@ namespace BlackMisc } bool ok; - if (v.startsWith("F")) + if (v.startsWith("F", Qt::CaseInsensitive)) { this->setUnit(CLengthUnit::ft()); this->setValueSameUnit(numericPart.toInt(&ok) * 100); m_datum = FlightLevel; } - else if (v.startsWith("S")) + else if (v.startsWith("S", Qt::CaseInsensitive)) { this->setUnit(CLengthUnit::m()); this->setValueSameUnit(numericPart.toInt(&ok) * 10); m_datum = FlightLevel; } - else if (v.startsWith("A")) + else if (v.startsWith("A", Qt::CaseInsensitive)) { this->setUnit(CLengthUnit::ft()); this->setValueSameUnit(numericPart.toInt(&ok) * 100); m_datum = MeanSeaLevel; } - else if (v.startsWith("M")) + else if (v.startsWith("M", Qt::CaseInsensitive)) { this->setUnit(CLengthUnit::m()); this->setValueSameUnit(numericPart.toInt(&ok) * 10); @@ -306,7 +314,7 @@ namespace BlackMisc return true; } - QString CAltitude::asFpAltitudeString() const + QString CAltitude::asFpICAOAltitudeString() const { if (this->isNull()) { return QStringLiteral(""); } if (this->isFlightLevel()) @@ -314,27 +322,29 @@ namespace BlackMisc if (this->getUnit() == CLengthUnit::m()) { int m = this->valueInteger() / 10; - return QString("S%1").arg(m, 4, 10, QChar('0')); + return QStringLiteral("S%1").arg(m, 4, 10, QChar('0')); } int ft = this->valueInteger(CLengthUnit::ft()) / 100; - return QString("FL%1").arg(ft, 3, 10, QChar('0')); + return QStringLiteral("FL%1").arg(ft, 3, 10, QChar('0')); } if (this->getUnit() == CLengthUnit::m()) { int m = this->valueInteger() / 10; - return QString("M%1").arg(m, 4, 10, QChar('0')); + return QStringLiteral("M%1").arg(m, 4, 10, QChar('0')); } int ft = this->valueInteger(CLengthUnit::ft()) / 100; - return QString("A%1").arg(ft, 3, 10, QChar('0')); + return QStringLiteral("A%1").arg(ft, 3, 10, QChar('0')); } - QString CAltitude::asFpAltitudeSimpleVatsimString() const + QString CAltitude::asFpVatsimAltitudeString() const { - CAltitude copy(*this); - copy.switchUnit(CLengthUnit::ft()); - if (copy.isFlightLevel()) { return copy.asFpAltitudeString(); } - return QString::number(copy.valueInteger()); // ft altitude without unit + if (this->isFlightLevel()) { return this->asFpICAOAltitudeString(); } + // the M/A formats are not supported by VATSIM, means by other clients + + // as feed, as none of the other clients + const CAltitude a = this->roundedToNearest100ft(); + return a.valueRoundedWithUnit(CLengthUnit::ft(), 0); } const QRegularExpression &CAltitude::fpAltitudeRegExp() @@ -345,7 +355,8 @@ namespace BlackMisc QString CAltitude::fpAltitudeInfo(const QString &separator) { - static const QString e("FL085, F85 flight level%1S0150 metric level in tens of metres%1A055 altitude in hundreds of feet%12000ft altitude in ft%1M0610 altitude in tens of metres%16100m altitude in meters"); + // remark use arg %01 to avoid clash with numbers, see https://stackoverflow.com/questions/35517025/qstringarg-with-number-after-placeholder + static const QString e("FL085, F85 flight level in hecto feets%1S0150 metric level in tens of meters%1A055 altitude in hundreds of feet%012000ft altitude in ft%1M0610 altitude in tens of meters%016100m altitude in meters"); return e.arg(separator); } @@ -369,6 +380,16 @@ namespace BlackMisc return CLength::compare(*this, otherAltitude); } + CAltitude CAltitude::roundedToNearest100ft() const + { + // 23453 => 234.53 + CAltitude a = this->switchedUnit(CLengthUnit::ft()); + const double ft = a.value(CLengthUnit::ft()) / 100.0; + const int ftR = qRound(ft) * 100; + a.setValueSameUnit(ftR); + return a; + } + const CAltitude &CAltitude::null() { static const CAltitude null(0, CAltitude::MeanSeaLevel, CLengthUnit::nullUnit()); diff --git a/src/blackmisc/aviation/altitude.h b/src/blackmisc/aviation/altitude.h index 9b3d01b15..f40de104c 100644 --- a/src/blackmisc/aviation/altitude.h +++ b/src/blackmisc/aviation/altitude.h @@ -166,10 +166,10 @@ namespace BlackMisc //! * standard metric level in tens of meters, expressed as "S" followed by 4 figures, example: S0150 (which means 1500 metres) //! * altitude in hundreds of feet, expressed as "A" followed by 3 figures, example: A055 (which means 5500 feet altitude) //! * altitude in tens of meters expressed as "M" followed by 4 figures, example: M0610 (which means 6100 metres altitude) - QString asFpAltitudeString() const; + QString asFpICAOAltitudeString() const; //! As simple VATSIM string, only FLxxx or altitude as ft - QString asFpAltitudeSimpleVatsimString() const; + QString asFpVatsimAltitudeString() const; //! Checking FP altitude strings like "A20", "FL100" //! \sa CFlightPlan::asFpAltitudeString @@ -188,6 +188,10 @@ namespace BlackMisc //! \copydoc PhysicalQuantities::CPhysicalQuantity::compare int compare(const CAltitude &otherAltitude) const; + //! Round to the nearest 100ft, like needed for China and Russia + //! \remark https://en.wikipedia.org/wiki/Flight_level + CAltitude roundedToNearest100ft() const; + //! Null altitude (MSL) static const CAltitude &null(); diff --git a/tests/blackmisc/aviation/testflightplan/testflightplan.cpp b/tests/blackmisc/aviation/testflightplan/testflightplan.cpp index acf0ab63c..cc6634c2f 100644 --- a/tests/blackmisc/aviation/testflightplan/testflightplan.cpp +++ b/tests/blackmisc/aviation/testflightplan/testflightplan.cpp @@ -93,15 +93,15 @@ namespace BlackMiscTest // as string a = CAltitude(12500, CAltitude::FlightLevel, CLengthUnit::ft()); - QVERIFY2(a.asFpAltitudeString() == "FL125", "Expect FL125"); - QVERIFY2(a.asFpAltitudeSimpleVatsimString() == "FL125", "Expect FL125"); + QVERIFY2(a.asFpICAOAltitudeString() == "FL125", "Expect FL125"); + QVERIFY2(a.asFpVatsimAltitudeString() == "FL125", "Expect FL125"); a = CAltitude(15000, CAltitude::MeanSeaLevel, CLengthUnit::ft()); - QVERIFY2(a.asFpAltitudeString() == "A150", "Expect A150"); - QVERIFY2(a.asFpAltitudeSimpleVatsimString() == "15000", "Expect 15000"); + QVERIFY2(a.asFpICAOAltitudeString() == "A150", "Expect A150"); + QVERIFY2(a.asFpVatsimAltitudeString() == "15000", "Expect 15000"); a = CAltitude(1500, CAltitude::FlightLevel, CLengthUnit::m()); - QVERIFY2(a.asFpAltitudeString() == "S0150", "Expect S0150"); + QVERIFY2(a.asFpICAOAltitudeString() == "S0150", "Expect S0150"); a = CAltitude(1600, CAltitude::MeanSeaLevel, CLengthUnit::m()); - QVERIFY2(a.asFpAltitudeString() == "M0160", "Expect M0160"); + QVERIFY2(a.asFpICAOAltitudeString() == "M0160", "Expect M0160"); } } // ns