diff --git a/src/blackmisc/aviation/aircraftsituation.cpp b/src/blackmisc/aviation/aircraftsituation.cpp index 2f20b4387..680c2f86d 100644 --- a/src/blackmisc/aviation/aircraftsituation.cpp +++ b/src/blackmisc/aviation/aircraftsituation.cpp @@ -46,14 +46,15 @@ namespace BlackMisc QString CAircraftSituation::convertToQString(bool i18n) const { - const QString s = (m_position.toQString(i18n)) % - QLatin1String(" bank: ") % (m_bank.toQString(i18n)) % - QLatin1String(" pitch: ") % (m_pitch.toQString(i18n)) % - QLatin1String(" gs: ") % (m_groundSpeed.toQString(i18n)) % - QLatin1String(" elevation: ") % (m_groundElevation.toQString(i18n)) % - QLatin1String(" heading: ") % (m_heading.toQString(i18n)) % - QLatin1String(" timestamp: ") % (this->hasValidTimestamp() ? this->getFormattedUtcTimestampDhms() : QStringLiteral("-")); - return s; + return m_position.toQString(i18n) % + QStringLiteral(" bank: ") % (m_bank.toQString(i18n)) % + QStringLiteral(" pitch: ") % (m_pitch.toQString(i18n)) % + QStringLiteral(" heading: ") % (m_heading.toQString(i18n)) % + QStringLiteral(" og: ") % this->getOnGroundInfo() % + QStringLiteral(" gs: ") % m_groundSpeed.valueRoundedWithUnit(CSpeedUnit::kts(), 1, true) % + QStringLiteral(" ") % m_groundSpeed.valueRoundedWithUnit(CSpeedUnit::m_s(), 1, true) % + QStringLiteral(" elevation: ") % (m_groundElevation.toQString(i18n)) % + QStringLiteral(" timestamp: ") % (this->hasValidTimestamp() ? this->getFormattedUtcTimestampDhms() : QStringLiteral("-")); } const QString &CAircraftSituation::isOnGroundToString(CAircraftSituation::IsOnGround onGround) @@ -104,7 +105,7 @@ namespace BlackMisc case IndexLatitude: return this->latitude().propertyByIndex(index.copyFrontRemoved()); case IndexLongitude: return this->longitude().propertyByIndex(index.copyFrontRemoved()); case IndexAltitude: return this->getAltitude().propertyByIndex(index.copyFrontRemoved()); - case IndexHeading: return m_heading.propertyByIndex(index.copyFrontRemoved()); + case IndexHeading:return m_heading.propertyByIndex(index.copyFrontRemoved()); case IndexPitch: return m_pitch.propertyByIndex(index.copyFrontRemoved()); case IndexBank: return m_bank.propertyByIndex(index.copyFrontRemoved()); case IndexGroundSpeed: return m_groundSpeed.propertyByIndex(index.copyFrontRemoved()); @@ -121,11 +122,7 @@ namespace BlackMisc void CAircraftSituation::setPropertyByIndex(const CPropertyIndex &index, const CVariant &variant) { if (index.isMyself()) { (*this) = variant.to(); return; } - if (ITimestampBased::canHandleIndex(index)) - { - ITimestampBased::setPropertyByIndex(index, variant); - return; - } + if (ITimestampBased::canHandleIndex(index)) { ITimestampBased::setPropertyByIndex(index, variant); return; } const ColumnIndex i = index.frontCasted(); switch (i) @@ -201,6 +198,13 @@ namespace BlackMisc return !this->getGroundElevation().isNull(); } + void CAircraftSituation::setGroundElevationChecked(const CAltitude &elevation, bool ignoreNullValues, bool overrideExisting) + { + if (ignoreNullValues && elevation.isNull()) { return; } + if (!overrideExisting && this->hasGroundElevation()) { return; } + m_groundElevation = elevation; + } + CLength CAircraftSituation::getHeightAboveGround() const { if (this->getAltitude().isNull()) { return { 0, nullptr }; } @@ -214,14 +218,30 @@ namespace BlackMisc return this->getAltitude() - gh; } - CAltitude CAircraftSituation::getCorrectedAltitude(const CLength ¢erOfGravity) const + CAltitude CAircraftSituation::getCorrectedAltitude(const CLength ¢erOfGravity, bool *corrected) const { - CAltitude altPlusCG = this->getAltitude(); - if (!centerOfGravity.isNull()) { altPlusCG += centerOfGravity; } - if (this->getGroundElevation().isNull()) { return altPlusCG; } - if (this->getAltitude().getReferenceDatum() != CAltitude::MeanSeaLevel) { return altPlusCG; } - if (this->getGroundElevation() < this->getAltitude()) { return altPlusCG; } - return this->getGroundElevation(); + if (corrected) { *corrected = false; } + if (this->getGroundElevation().isNull()) { return this->getAltitude(); } + + // above ground + if (this->getAltitude().getReferenceDatum() == CAltitude::AboveGround) + { + const CAltitude aboveGround = this->getAltitude().withOffset(centerOfGravity); + const bool c = !aboveGround.isPositiveWithEpsilonConsidered(); + if (corrected) { *corrected = c; } + return c ? + CAltitude(0, CAltitude::AboveGround, aboveGround.getUnit()) : + aboveGround; + } + else + { + CAltitude groundPlusCG = this->getGroundElevation().withOffset(centerOfGravity); + const bool c = (this->getAltitude() < groundPlusCG); + if (corrected) { *corrected = c; } + return c ? + groundPlusCG : + this->getAltitude(); + } } void CAircraftSituation::setPressureAltitude(const CAltitude &altitude) @@ -230,6 +250,22 @@ namespace BlackMisc m_pressureAltitude = altitude; } + CLength CAircraftSituation::getDistancePerTime(const CTime &time) const + { + if (this->getGroundSpeed().isNull()) { return CLength(0, CLengthUnit::nullUnit()); } + const int ms = time.valueInteger(CTimeUnit::ms()); + return this->getDistancePerTime(ms); + } + + CLength CAircraftSituation::getDistancePerTime(int milliseconds) const + { + if (this->getGroundSpeed().isNull()) { return CLength(0, CLengthUnit::nullUnit()); } + const double seconds = milliseconds / 1000; + const double gsMeterSecond = this->getGroundSpeed().value(CSpeedUnit::m_s()); + const CLength d(seconds * gsMeterSecond, CLengthUnit::m()); + return d; + } + void CAircraftSituation::setCallsign(const CCallsign &callsign) { m_correspondingCallsign = callsign; diff --git a/src/blackmisc/aviation/aircraftsituation.h b/src/blackmisc/aviation/aircraftsituation.h index 39ace5c7e..8225c3e1d 100644 --- a/src/blackmisc/aviation/aircraftsituation.h +++ b/src/blackmisc/aviation/aircraftsituation.h @@ -23,6 +23,7 @@ #include "blackmisc/pq/angle.h" #include "blackmisc/pq/length.h" #include "blackmisc/pq/speed.h" +#include "blackmisc/pq/time.h" #include "blackmisc/propertyindex.h" #include "blackmisc/timestampbased.h" #include "blackmisc/valueobject.h" @@ -169,6 +170,9 @@ namespace BlackMisc //! Elevation of the ground directly beneath void setGroundElevation(const CAltitude &elevation) { m_groundElevation = elevation; } + //! Set elevation of the ground directly beneath, but checked + void setGroundElevationChecked(const CAltitude &elevation, bool ignoreNullValues = true, bool overrideExisting = true); + //! Height above ground. PhysicalQuantities::CLength getHeightAboveGround() const; @@ -182,7 +186,7 @@ namespace BlackMisc const CAltitude &getAltitude() const { return m_position.geodeticHeight(); } //! Get altitude under consideration of ground elevation - CAltitude getCorrectedAltitude(const PhysicalQuantities::CLength ¢erOfGravity = {}) const; + CAltitude getCorrectedAltitude(const PhysicalQuantities::CLength ¢erOfGravity = {}, bool *corrected = nullptr) const; //! Set altitude void setAltitude(const CAltitude &altitude) { m_position.setGeodeticHeight(altitude); } @@ -211,6 +215,12 @@ namespace BlackMisc //! Set ground speed void setGroundSpeed(const PhysicalQuantities::CSpeed &groundspeed) { m_groundSpeed = groundspeed; } + //! Distance per time + PhysicalQuantities::CLength getDistancePerTime(const PhysicalQuantities::CTime &time) const; + + //! Distance per milliseconds + PhysicalQuantities::CLength getDistancePerTime(int milliseconds) const; + //! Corresponding callsign const CCallsign &getCallsign() const { return m_correspondingCallsign; } @@ -243,7 +253,7 @@ namespace BlackMisc private: CCallsign m_correspondingCallsign; - Geo::CCoordinateGeodetic m_position; + Geo::CCoordinateGeodetic m_position; // NULL position Aviation::CAltitude m_pressureAltitude { 0, nullptr }; CHeading m_heading; PhysicalQuantities::CAngle m_pitch; diff --git a/src/blackmisc/aviation/altitude.cpp b/src/blackmisc/aviation/altitude.cpp index 3441b08bd..77d532d75 100644 --- a/src/blackmisc/aviation/altitude.cpp +++ b/src/blackmisc/aviation/altitude.cpp @@ -28,6 +28,13 @@ namespace BlackMisc this->parseFromString(altitudeAsString, mode); } + CAltitude CAltitude::withOffset(const CLength &offset) const + { + CAltitude copy(*this); + if (!offset.isNull() && !offset.isZeroEpsilonConsidered()) { copy += offset; } + return copy; + } + QString CAltitude::convertToQString(bool i18n) const { if (this->m_datum == FlightLevel) diff --git a/src/blackmisc/aviation/altitude.h b/src/blackmisc/aviation/altitude.h index dd68ab381..f5e9955da 100644 --- a/src/blackmisc/aviation/altitude.h +++ b/src/blackmisc/aviation/altitude.h @@ -100,6 +100,11 @@ namespace BlackMisc //! Constructor by CLength CAltitude(const PhysicalQuantities::CLength &altitude, ReferenceDatum datum) : CLength(altitude), m_datum(datum) {} + //! Altitude with offset + //! \remark null offset adds nothing + //! \remark epsilon 0 (zero) values ignored + CAltitude withOffset(const CLength &offset) const; + //! AGL Above ground level? bool isAboveGroundLevel() const { return AboveGround == this->m_datum; } diff --git a/src/blackmisc/aviation/callsignset.cpp b/src/blackmisc/aviation/callsignset.cpp index 0ba10d51e..1859987f6 100644 --- a/src/blackmisc/aviation/callsignset.cpp +++ b/src/blackmisc/aviation/callsignset.cpp @@ -26,6 +26,11 @@ namespace BlackMisc CCollection(other) { } + bool CCallsignSet::containsCallsign(const QString &callsign) const + { + return this->contains(CCallsign(callsign)); + } + QStringList CCallsignSet::getCallsignStrings(bool sorted) const { QStringList callsigns; diff --git a/src/blackmisc/aviation/callsignset.h b/src/blackmisc/aviation/callsignset.h index cdafed6a1..508bf320c 100644 --- a/src/blackmisc/aviation/callsignset.h +++ b/src/blackmisc/aviation/callsignset.h @@ -38,6 +38,9 @@ namespace BlackMisc //! Construct from a base class object. CCallsignSet(const CCollection &other); + //! Contains by string + bool containsCallsign(const QString &callsign) const; + //! The callsign strings QStringList getCallsignStrings(bool sorted = false) const; diff --git a/src/blackmisc/geo/elevationplane.cpp b/src/blackmisc/geo/elevationplane.cpp index e073073dd..8903a58ab 100644 --- a/src/blackmisc/geo/elevationplane.cpp +++ b/src/blackmisc/geo/elevationplane.cpp @@ -42,7 +42,7 @@ namespace BlackMisc { if (isNull()) { return false; } const CLength d = this->calculateGreatCircleDistance(coordinate); - const bool inRange = m_radius >= d; + const bool inRange = (m_radius >= d); return inRange; } @@ -88,9 +88,12 @@ namespace BlackMisc } } + // 100km/h 27,8m/s + // 50km/h 13,9m/s + // 100kts 51,4m/s const CLength &CElevationPlane::singlePointRadius() { - static const CLength l(10.0, CLengthUnit::m()); + static const CLength l(25.0, CLengthUnit::m()); return l; } diff --git a/src/blackmisc/geo/elevationplane.h b/src/blackmisc/geo/elevationplane.h index 45752ea07..ab164e933 100644 --- a/src/blackmisc/geo/elevationplane.h +++ b/src/blackmisc/geo/elevationplane.h @@ -27,29 +27,32 @@ namespace BlackMisc //! Properties by index enum ColumnIndex { - IndexRadius = BlackMisc::CPropertyIndex::GlobalIndexCElevationPlane + IndexRadius = CPropertyIndex::GlobalIndexCElevationPlane }; //! Default constructor CElevationPlane() {} - //! Constructor + //! Constructors from CCoordinateGeodetic using CValueObject::CValueObject; //! Radius - const BlackMisc::PhysicalQuantities::CLength &getRadius() const { return m_radius; } + const PhysicalQuantities::CLength &getRadius() const { return m_radius; } //! Radius - void setRadius(const BlackMisc::PhysicalQuantities::CLength &radius) { m_radius = radius; } + void setRadius(const PhysicalQuantities::CLength &radius) { m_radius = radius; } //! Altitude when within radius, else null const Aviation::CAltitude &getAltitudeIfWithinRadius(const ICoordinateGeodetic &coordinate) const; + //! Altitude (synonym for geodetic height) + const Aviation::CAltitude &getAltitude() const { return this->geodeticHeight(); } + //! Existing value bool isNull() const; //! Check if elevation is within radius and can be used - bool isWithinRange(const BlackMisc::Geo::ICoordinateGeodetic &coordinate) const; + bool isWithinRange(const ICoordinateGeodetic &coordinate) const; //! Treat as single point as obtained from simulator void setSinglePointRadius(); @@ -61,25 +64,25 @@ namespace BlackMisc void setMajorAirportRadius(); //! \copydoc BlackMisc::Mixin::Index::propertyByIndex - CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const; + CVariant propertyByIndex(const CPropertyIndex &index) const; //! \copydoc BlackMisc::Mixin::Index::setPropertyByIndex - void setPropertyByIndex(const BlackMisc::CPropertyIndex &index, const CVariant &variant); + void setPropertyByIndex(const CPropertyIndex &index, const CVariant &variant); //! \copydoc BlackMisc::Mixin::String::toQString QString convertToQString(bool i18n = false) const; //! Radius for single point - static const BlackMisc::PhysicalQuantities::CLength &singlePointRadius(); + static const PhysicalQuantities::CLength &singlePointRadius(); //! Radius for minor airport - static const BlackMisc::PhysicalQuantities::CLength &minorAirportRadius(); + static const PhysicalQuantities::CLength &minorAirportRadius(); //! Radius for major airport - static const BlackMisc::PhysicalQuantities::CLength &majorAirportRadius(); + static const PhysicalQuantities::CLength &majorAirportRadius(); private: - BlackMisc::PhysicalQuantities::CLength m_radius { 0, nullptr }; //!< elevation is valid in radius + PhysicalQuantities::CLength m_radius { 0, nullptr }; //!< elevation is valid in radius BLACK_METACLASS( CElevationPlane,