diff --git a/src/blackcore/airspacemonitor.cpp b/src/blackcore/airspacemonitor.cpp index 2b654d125..d28e6147a 100644 --- a/src/blackcore/airspacemonitor.cpp +++ b/src/blackcore/airspacemonitor.cpp @@ -274,7 +274,7 @@ namespace BlackCore bool CAirspaceMonitor::updateAircraftGroundElevation(const CCallsign &callsign, const CElevationPlane &elevation) { QWriteLocker l(&m_lockAircraft); - const int c = m_aircraftInRange.setGroundElevation(callsign, elevation.geodeticHeight()); + const int c = m_aircraftInRange.setGroundElevationChecked(callsign, elevation); return c > 0; } @@ -1230,7 +1230,7 @@ namespace BlackCore Q_ASSERT(CThreadUtils::isCurrentThreadObjectThread(this)); // update - const CPropertyIndexVariantMap vm( {CSimulatedAircraft::IndexCom1System, CComSystem::IndexActiveFrequency}, CVariant::from(frequency)); + const CPropertyIndexVariantMap vm({CSimulatedAircraft::IndexCom1System, CComSystem::IndexActiveFrequency}, CVariant::from(frequency)); this->updateAircraftInRange(callsign, vm); } diff --git a/src/blackmisc/aviation/aircraftsituation.cpp b/src/blackmisc/aviation/aircraftsituation.cpp index 67e358ffd..28d452fcb 100644 --- a/src/blackmisc/aviation/aircraftsituation.cpp +++ b/src/blackmisc/aviation/aircraftsituation.cpp @@ -8,6 +8,7 @@ */ #include "blackmisc/aviation/aircraftsituation.h" +#include "blackmisc/aviation/aircraftpartslist.h" #include "blackmisc/geo/elevationplane.h" #include "blackmisc/pq/physicalquantity.h" #include "blackmisc/pq/units.h" @@ -18,7 +19,6 @@ #include "QStringBuilder" #include -using namespace BlackMisc; using namespace BlackMisc::PhysicalQuantities; using namespace BlackMisc::Geo; @@ -26,24 +26,22 @@ namespace BlackMisc { namespace Aviation { - CAircraftSituation::CAircraftSituation() - : m_groundElevation({ 0, nullptr }, CAltitude::MeanSeaLevel) {} + CAircraftSituation::CAircraftSituation() {} - CAircraftSituation::CAircraftSituation(const CCallsign &correspondingCallsign) - : m_correspondingCallsign(correspondingCallsign), m_groundElevation({ 0, nullptr }, CAltitude::MeanSeaLevel) + CAircraftSituation::CAircraftSituation(const CCallsign &correspondingCallsign) : m_correspondingCallsign(correspondingCallsign) {} - CAircraftSituation::CAircraftSituation(const CCoordinateGeodetic &position, const CHeading &heading, const CAngle &pitch, const CAngle &bank, const CSpeed &gs, const CAltitude &groundElevation) + CAircraftSituation::CAircraftSituation(const CCoordinateGeodetic &position, const CHeading &heading, const CAngle &pitch, const CAngle &bank, const CSpeed &gs, const CElevationPlane &groundElevation) : m_position(position), m_heading(heading), m_pitch(pitch), - m_bank(bank), m_groundSpeed(gs), m_groundElevation(groundElevation) + m_bank(bank), m_groundSpeed(gs), m_groundElevationPlane(groundElevation) { m_pressureAltitude = position.geodeticHeight().toPressureAltitude(CPressure(1013.25, CPressureUnit::mbar())); } - CAircraftSituation::CAircraftSituation(const CCallsign &correspondingCallsign, const CCoordinateGeodetic &position, const CHeading &heading, const CAngle &pitch, const CAngle &bank, const CSpeed &gs, const CAltitude &groundElevation) + CAircraftSituation::CAircraftSituation(const CCallsign &correspondingCallsign, const CCoordinateGeodetic &position, const CHeading &heading, const CAngle &pitch, const CAngle &bank, const CSpeed &gs, const CElevationPlane &groundElevation) : m_correspondingCallsign(correspondingCallsign), m_position(position), m_heading(heading), m_pitch(pitch), - m_bank(bank), m_groundSpeed(gs), m_groundElevation(groundElevation) + m_bank(bank), m_groundSpeed(gs), m_groundElevationPlane(groundElevation) { m_correspondingCallsign.setTypeHint(CCallsign::Aircraft); m_pressureAltitude = position.geodeticHeight().toPressureAltitude(CPressure(1013.25, CPressureUnit::mbar())); @@ -59,7 +57,7 @@ namespace BlackMisc 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(" elevation: ") % (m_groundElevationPlane.toQString(i18n)); } const QString &CAircraftSituation::isOnGroundToString(CAircraftSituation::IsOnGround onGround) @@ -96,7 +94,7 @@ namespace BlackMisc case CAircraftSituation::OnGroundByGuessing: return intGuess; case CAircraftSituation::OnGroundByInterpolation: return intInter; case CAircraftSituation::OutOnGroundOwnAircraft: return outOwnAircraft; - case CAircraftSituation::InFromNetworkSituation: return inNetwork; + case CAircraftSituation::InFromNetwork: return inNetwork; case CAircraftSituation::InFromParts: return inFromParts; case CAircraftSituation::InNoGroundInfo: return InNoGroundInfo; case CAircraftSituation::NotSet: @@ -122,7 +120,7 @@ namespace BlackMisc case IndexPitch: return m_pitch.propertyByIndex(index.copyFrontRemoved()); case IndexBank: return m_bank.propertyByIndex(index.copyFrontRemoved()); case IndexGroundSpeed: return m_groundSpeed.propertyByIndex(index.copyFrontRemoved()); - case IndexGroundElevation: return m_groundElevation.propertyByIndex(index.copyFrontRemoved()); + case IndexGroundElevationPlane: return m_groundElevationPlane.propertyByIndex(index.copyFrontRemoved()); case IndexCallsign: return m_correspondingCallsign.propertyByIndex(index.copyFrontRemoved()); case IndexIsOnGround: return CVariant::fromValue(m_isOnGround); case IndexIsOnGroundString: return CVariant::fromValue(this->isOnGroundAsString()); @@ -144,7 +142,7 @@ namespace BlackMisc case IndexPitch: m_pitch.setPropertyByIndex(index.copyFrontRemoved(), variant); break; case IndexBank: m_bank.setPropertyByIndex(index.copyFrontRemoved(), variant); break; case IndexGroundSpeed: m_groundSpeed.setPropertyByIndex(index.copyFrontRemoved(), variant); break; - case IndexGroundElevation: m_groundElevation.setPropertyByIndex(index.copyFrontRemoved(), variant); break; + case IndexGroundElevationPlane: m_groundElevationPlane.setPropertyByIndex(index.copyFrontRemoved(), variant); break; case IndexCallsign: m_correspondingCallsign.setPropertyByIndex(index.copyFrontRemoved(), variant); break; case IndexIsOnGround: m_isOnGround = variant.toInt(); break; case IndexOnGroundReliability: m_onGroundDetails = variant.toInt(); break; @@ -164,7 +162,7 @@ namespace BlackMisc case IndexPitch: return m_pitch.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getPitch()); case IndexBank: return m_bank.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getBank()); case IndexGroundSpeed: return m_groundSpeed.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getGroundSpeed()); - case IndexGroundElevation: return m_groundElevation.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getGroundElevation()); + case IndexGroundElevationPlane: return m_groundElevationPlane.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getGroundElevationPlane()); case IndexCallsign: return m_correspondingCallsign.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getCallsign()); case IndexIsOnGround: case IndexIsOnGroundString: @@ -191,7 +189,7 @@ namespace BlackMisc m_heading.setNull(); m_pitch.setNull(); m_bank.setNull(); - m_groundElevation.setNull(); + m_groundElevationPlane.setNull(); m_groundSpeed.setNull(); m_onGroundDetails = CAircraftSituation::NotSet; } @@ -207,10 +205,10 @@ namespace BlackMisc this->getOnGroundDetails() != CAircraftSituation::NotSet; } - void CAircraftSituation::setOnGround(CAircraftSituation::IsOnGround onGround, CAircraftSituation::OnGroundDetails reliability) + void CAircraftSituation::setOnGround(CAircraftSituation::IsOnGround onGround, CAircraftSituation::OnGroundDetails details) { this->setOnGround(onGround); - this->setOnGroundReliabiliy(reliability); + this->setOnGroundDetails(details); } const QString &CAircraftSituation::getOnDetailsAsString() const @@ -228,21 +226,44 @@ namespace BlackMisc return !this->getGroundElevation().isNull(); } - bool CAircraftSituation::setGroundElevationChecked(const CAltitude &elevation, bool ignoreNullValues, bool overrideExisting) + bool CAircraftSituation::hasInboundGroundInformation() const { - if (ignoreNullValues && elevation.isNull()) { return false; } - if (!overrideExisting && this->hasGroundElevation()) { return false; } - m_groundElevation = elevation; - return true; + return this->getOnGroundDetails() == CAircraftSituation::InFromParts || this->getOnGroundDetails() == CAircraftSituation::InFromNetwork; } - bool CAircraftSituation::setGroundElevationChecked(const CElevationPlane &elevationPlane, bool ignoreNullValues, bool overrideExisting) + void CAircraftSituation::setGroundElevation(const CAltitude &altitude) { - if (ignoreNullValues && elevationPlane.isNull()) { return false; } - if (!overrideExisting && this->hasGroundElevation()) { return false; } - if (!elevationPlane.isWithinRange(*this)) { return false; } - m_groundElevation = elevationPlane.getAltitude(); - return true; + if (altitude.isNull()) + { + m_groundElevationPlane = CElevationPlane::null(); + } + else + { + m_groundElevationPlane = CElevationPlane(*this); + m_groundElevationPlane.setSinglePointRadius(); + m_groundElevationPlane.setGeodeticHeight(altitude); + } + } + + bool CAircraftSituation::setGroundElevationChecked(const CElevationPlane &elevationPlane) + { + if (elevationPlane.isNull()) { return false; } + const CLength distance = this->calculateGreatCircleDistance(elevationPlane); + if (distance > elevationPlane.getRadius()) { return false; } + if (m_groundElevationPlane.isNull() || distance < m_groundElevationPlane.getRadius()) + { + // better values + m_groundElevationPlane = elevationPlane; + m_groundElevationPlane.setRadius(distance); + return true; + } + return false; + } + + const CLength &CAircraftSituation::getGroundElevationDistance() const + { + if (!this->hasGroundElevation()) { return CLength::null(); } + return m_groundElevationPlane.getRadius(); } CLength CAircraftSituation::getHeightAboveGround() const @@ -258,29 +279,31 @@ namespace BlackMisc return this->getAltitude() - gh; } - CAltitude CAircraftSituation::getCorrectedAltitude(const CLength ¢erOfGravity, bool *corrected) const + CAltitude CAircraftSituation::getCorrectedAltitude(const CLength ¢erOfGravity, bool dragToGround, bool *corrected) const { if (corrected) { *corrected = false; } - if (this->getGroundElevation().isNull()) { return this->getAltitude(); } + if (!this->hasGroundElevation()) { 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; + BLACK_VERIFY_X(false, Q_FUNC_INFO, "Unsupported"); + return this->getAltitude(); } else { + static const CLength small(0.5, CLengthUnit::m()); const CAltitude groundPlusCG = this->getGroundElevation().withOffset(centerOfGravity); - const bool c = (this->getAltitude() < groundPlusCG); - if (corrected) { *corrected = c; } - return c ? - groundPlusCG : - this->getAltitude(); + const CLength groundDistance = (this->getAltitude() - groundPlusCG); + if (groundDistance.abs() < small) { return this->getAltitude(); } + const bool toGround = (this->getAltitude() < groundPlusCG) || (forceToGround && this->isOnGround() == OnGround); + if (toGround) + { + // underflow or overflow forced to ground + if (corrected) { *corrected = true; } + return groundPlusCG; + } + return this->getAltitude(); } } @@ -311,5 +334,50 @@ namespace BlackMisc m_correspondingCallsign = callsign; m_correspondingCallsign.setTypeHint(CCallsign::Aircraft); } + + bool CAircraftSituation::adjustGroundFlag(const CAircraftParts &parts, double timeDeviationFactor, qint64 *differenceMs) + { + Q_ASSERT_X(timeDeviationFactor >= 0 && timeDeviationFactor <= 1.0, Q_FUNC_INFO, "Expect 0..1"); + static const qint64 Max = std::numeric_limits::max(); + if (differenceMs) { *differenceMs = Max; } + if (this->getOnGroundDetails() == CAircraftSituation::InFromNetwork) { return false; } + const qint64 d = this->getAdjustedTimeDifferenceMs(parts.getAdjustedMSecsSinceEpoch()); + const bool adjust = (d >= 0) || qAbs(d) < (timeDeviationFactor * parts.getTimeOffsetMs()); // future or past within deviation range + if (!adjust) { return false; } + + if (differenceMs) { *differenceMs = d; } + this->setOnGround(parts.isOnGround() ? CAircraftSituation::OnGround : CAircraftSituation::NotOnGround, CAircraftSituation::InFromParts); + return true; + } + + bool CAircraftSituation::adjustGroundFlag(const CAircraftPartsList &partsList, double timeDeviationFactor, qint64 *differenceMs) + { + Q_ASSERT_X(timeDeviationFactor >= 0 && timeDeviationFactor <= 1.0, Q_FUNC_INFO, "Expect 0..1"); + if (this->getOnGroundDetails() == CAircraftSituation::InFromNetwork) { return false; } + if (partsList.isEmpty()) { return false; } + + static const qint64 Max = std::numeric_limits::max(); + if (differenceMs) { *differenceMs = Max; } + CAircraftParts bestParts; + bool adjust = false; + qint64 bestDistance = Max; + for (const CAircraftParts &parts : partsList) + { + const qint64 d = this->getAdjustedTimeDifferenceMs(parts.getAdjustedMSecsSinceEpoch()); + const qint64 posD = qAbs(d); + const bool candidate = (d >= 0) || posD < (timeDeviationFactor * parts.getTimeOffsetMs()); // future or past within deviation range + if (!candidate || bestDistance <= posD) { continue; } + bestDistance = posD; + if (differenceMs) { *differenceMs = d; } + adjust = true; + bestParts = parts; + if (bestDistance == 0) { break; } + } + if (!adjust) { return false; } + + const CAircraftSituation::IsOnGround og = bestParts.isOnGround() ? CAircraftSituation::OnGround : CAircraftSituation::NotOnGround; + this->setOnGround(og, CAircraftSituation::InFromParts); + return true; + } } // namespace } // namespace diff --git a/src/blackmisc/aviation/aircraftsituation.h b/src/blackmisc/aviation/aircraftsituation.h index 3ef780375..62d3c8520 100644 --- a/src/blackmisc/aviation/aircraftsituation.h +++ b/src/blackmisc/aviation/aircraftsituation.h @@ -16,6 +16,7 @@ #include "blackmisc/aviation/callsign.h" #include "blackmisc/aviation/heading.h" #include "blackmisc/blackmiscexport.h" +#include "blackmisc/geo/elevationplane.h" #include "blackmisc/geo/coordinategeodetic.h" #include "blackmisc/geo/latitude.h" #include "blackmisc/geo/longitude.h" @@ -39,6 +40,9 @@ namespace BlackMisc namespace Geo { class CElevationPlane; } namespace Aviation { + class CAircraftParts; + class CAircraftPartsList; + //! Value object encapsulating information of an aircraft's situation class BLACKMISC_EXPORT CAircraftSituation : public CValueObject, @@ -60,7 +64,7 @@ namespace BlackMisc IndexOnGroundReliabilityString, IndexPitch, IndexGroundSpeed, - IndexGroundElevation, + IndexGroundElevationPlane, IndexCallsign }; @@ -82,9 +86,9 @@ namespace BlackMisc OnGroundByElevation, OnGroundByGuessing, //!< weakest // received situation - InFromNetworkSituation, //!< received from network - InFromParts, - InNoGroundInfo, + InFromNetwork, //!< received from network + InFromParts, //!< set from aircraft parts + InNoGroundInfo, //!< not know // send information OutOnGroundOwnAircraft //!< sending on ground }; @@ -101,7 +105,7 @@ namespace BlackMisc const PhysicalQuantities::CAngle &pitch = {}, const PhysicalQuantities::CAngle &bank = {}, const PhysicalQuantities::CSpeed &gs = {}, - const CAltitude &groundElevation = { 0, nullptr }); + const Geo::CElevationPlane &groundElevation = {}); //! Comprehensive constructor CAircraftSituation(const CCallsign &correspondingCallsign, @@ -110,7 +114,7 @@ namespace BlackMisc const PhysicalQuantities::CAngle &pitch = {}, const PhysicalQuantities::CAngle &bank = {}, const PhysicalQuantities::CSpeed &gs = {}, - const CAltitude &groundElevation = { 0, nullptr }); + const Geo::CElevationPlane &groundElevation = {}); //! \copydoc Mixin::Index::propertyByIndex CVariant propertyByIndex(const CPropertyIndex &index) const; @@ -151,11 +155,14 @@ namespace BlackMisc //! On ground info available? bool isOnGroundInfoAvailable() const; + //! Set on ground + void setOnGround(bool onGround) { this->setOnGround(onGround ? OnGround : NotOnGround); } + //! Set on ground void setOnGround(CAircraftSituation::IsOnGround onGround) { m_isOnGround = static_cast(onGround); } //! Set on ground - void setOnGround(CAircraftSituation::IsOnGround onGround, CAircraftSituation::OnGroundDetails reliability); + void setOnGround(CAircraftSituation::IsOnGround onGround, CAircraftSituation::OnGroundDetails details); //! On ground reliability OnGroundDetails getOnGroundDetails() const { return static_cast(m_onGroundDetails); } @@ -163,8 +170,8 @@ namespace BlackMisc //! On ground reliability as string const QString &getOnDetailsAsString() const; - //! Reliability - void setOnGroundReliabiliy(CAircraftSituation::OnGroundDetails onGroundReliability) { m_onGroundDetails = static_cast(onGroundReliability); } + //! On ground details + void setOnGroundDetails(CAircraftSituation::OnGroundDetails details) { m_onGroundDetails = static_cast(details); } //! On ground info as string QString getOnGroundInfo() const; @@ -179,19 +186,29 @@ namespace BlackMisc virtual std::array normalVectorDouble() const override { return m_position.normalVectorDouble(); } //! Elevation of the ground directly beneath - const CAltitude &getGroundElevation() const { return m_groundElevation; } + const CAltitude &getGroundElevation() const { return m_groundElevationPlane.getAltitude(); } + + //! Elevation of the ground directly beneath + const Geo::CElevationPlane &getGroundElevationPlane() const { return m_groundElevationPlane; } //! Is ground elevation value available bool hasGroundElevation() const; + //! Has inbound ground information + bool hasInboundGroundInformation() const; + + //! Elevation of the ground directly beneath at the given situation + void setGroundElevation(const Aviation::CAltitude &altitude); + //! Elevation of the ground directly beneath - void setGroundElevation(const CAltitude &elevation) { m_groundElevation = elevation; } + void setGroundElevation(const Geo::CElevationPlane &elevationPlane) { m_groundElevationPlane = elevationPlane; } //! Set elevation of the ground directly beneath, but checked - bool setGroundElevationChecked(const CAltitude &elevation, bool ignoreNullValues = true, bool overrideExisting = true); + //! \remark override if better + bool setGroundElevationChecked(const Geo::CElevationPlane &elevationPlane); - //! Set elevation of the ground directly beneath, but checked - bool setGroundElevationChecked(const Geo::CElevationPlane &elevationPlane, bool ignoreNullValues = true, bool overrideExisting = true); + //! Distance of ground elevation + const PhysicalQuantities::CLength &getGroundElevationDistance() const; //! Height above ground. PhysicalQuantities::CLength getHeightAboveGround() const; @@ -206,7 +223,7 @@ namespace BlackMisc const CAltitude &getAltitude() const { return m_position.geodeticHeight(); } //! Get altitude under consideration of ground elevation - CAltitude getCorrectedAltitude(const PhysicalQuantities::CLength ¢erOfGravity = {}, bool *corrected = nullptr) const; + CAltitude getCorrectedAltitude(const PhysicalQuantities::CLength ¢erOfGravity = {}, bool forceToGround = true, bool *corrected = nullptr) const; //! Set altitude void setAltitude(const CAltitude &altitude) { m_position.setGeodeticHeight(altitude); } @@ -250,6 +267,20 @@ namespace BlackMisc //! Set flag indicating this is an interim position update void setInterimFlag(bool flag) { m_isInterim = flag; } + //! Transfer ground flag from parts + //! \param parts containing the gnd flag + //! \param alwaysSetDetails mark as CAircraftSituation::InFromParts regardless of parts + //! \param timeDeviationFactor 0..1 (of offset time) small deviations from time are accepted + //! \param differenceMs returns time difference + bool adjustGroundFlag(const CAircraftParts &parts, double timeDeviationFactor = 0.1, qint64 *differenceMs = nullptr); + + //! Transfer ground flag from parts list + //! \param partsList containing the gnd flag + //! \param alwaysSetDetails mark as CAircraftSituation::InFromParts regardless of parts + //! \param timeDeviationFactor 0..1 (of offset time) small deviations from time are accepted + //! \param differenceMs returns time difference + bool adjustGroundFlag(const CAircraftPartsList &partsList, double timeDeviationFactor = 0.1, qint64 *differenceMs = nullptr); + //! Get flag indicating this is an interim position update bool isInterim() const { return m_isInterim; } @@ -270,7 +301,7 @@ namespace BlackMisc PhysicalQuantities::CAngle m_pitch; PhysicalQuantities::CAngle m_bank; PhysicalQuantities::CSpeed m_groundSpeed; - CAltitude m_groundElevation{ 0, CAltitude::MeanSeaLevel, PhysicalQuantities::CLengthUnit::nullUnit() }; + Geo::CElevationPlane m_groundElevationPlane; //!< NULL elevation as default int m_isOnGround = static_cast(CAircraftSituation::OnGroundSituationUnknown); int m_onGroundDetails = static_cast(CAircraftSituation::NotSet); bool m_isInterim = false; @@ -284,7 +315,7 @@ namespace BlackMisc BLACK_METAMEMBER(pitch), BLACK_METAMEMBER(bank), BLACK_METAMEMBER(groundSpeed), - BLACK_METAMEMBER(groundElevation), + BLACK_METAMEMBER(groundElevationPlane), BLACK_METAMEMBER(isOnGround), BLACK_METAMEMBER(onGroundDetails), BLACK_METAMEMBER(timestampMSecsSinceEpoch), diff --git a/src/blackmisc/aviation/aircraftsituationlist.cpp b/src/blackmisc/aviation/aircraftsituationlist.cpp index c161d1000..aaaa41b78 100644 --- a/src/blackmisc/aviation/aircraftsituationlist.cpp +++ b/src/blackmisc/aviation/aircraftsituationlist.cpp @@ -30,29 +30,52 @@ namespace BlackMisc CSequence(il) { } - int CAircraftSituationList::setGroundElevationChecked(const CElevationPlane &elevationPlane, bool ignoreNullValues, bool overrideExisting) + int CAircraftSituationList::setGroundElevationChecked(const CElevationPlane &elevationPlane, qint64 newerThanAdjustedMs) { - if (ignoreNullValues && elevationPlane.isNull()) { return 0; } + if (elevationPlane.isNull()) { return 0; } int c = 0; for (CAircraftSituation &s : *this) { - const bool set = s.setGroundElevationChecked(elevationPlane, ignoreNullValues, overrideExisting); + if (newerThanAdjustedMs >= 0 && s.getAdjustedMSecsSinceEpoch() <= newerThanAdjustedMs) { continue; } + const bool set = s.setGroundElevationChecked(elevationPlane); if (set) { c++; } } return c; } - int CAircraftSituationList::setGroundElevationChecked(const CElevationPlane &elevationPlane, qint64 newerThanAdjustedMs, bool ignoreNullValues, bool overrideExisting) + int CAircraftSituationList::adjustGroundFlag(const CAircraftParts &parts, double timeDeviationFactor) { - if (ignoreNullValues && elevationPlane.isNull()) { return 0; } int c = 0; - for (CAircraftSituation &s : *this) + for (CAircraftSituation &situation : *this) { - if (s.getAdjustedMSecsSinceEpoch() <= newerThanAdjustedMs) { continue; } - const bool set = s.setGroundElevationChecked(elevationPlane, ignoreNullValues, overrideExisting); - if (set) { c++; } + if (situation.adjustGroundFlag(parts, timeDeviationFactor)) { c++; }; } return c; } + + int CAircraftSituationList::extrapolateGroundFlag() + { + if (this->isEmpty()) { return 0; } + CAircraftSituationList withInfo = this->findByInboundGroundInformation(true); + withInfo.sortLatestFirst(); + if (withInfo.isEmpty()) { return 0; } + const CAircraftSituation latest = withInfo.front(); + + int c = 0; + for (CAircraftSituation &situation : *this) + { + if (situation.isNewerThanAdjusted(latest)) + { + situation.setOnGround(latest.isOnGround(), latest.getOnGroundDetails()); + c++; + } + } + return c; + } + + CAircraftSituationList CAircraftSituationList::findByInboundGroundInformation(bool hasGroundInfo) const + { + return this->findBy(&CAircraftSituation::hasInboundGroundInformation, hasGroundInfo); + } } // namespace } // namespace diff --git a/src/blackmisc/aviation/aircraftsituationlist.h b/src/blackmisc/aviation/aircraftsituationlist.h index 1426db31d..4b20d6453 100644 --- a/src/blackmisc/aviation/aircraftsituationlist.h +++ b/src/blackmisc/aviation/aircraftsituationlist.h @@ -14,6 +14,7 @@ #include "blackmisc/aviation/aircraftsituation.h" #include "blackmisc/aviation/callsignobjectlist.h" +#include "blackmisc/geo/geoobjectlist.h" #include "blackmisc/geo/elevationplane.h" #include "blackmisc/blackmiscexport.h" #include "blackmisc/collection.h" @@ -28,11 +29,12 @@ namespace BlackMisc namespace Geo { class CElevationPlane; } namespace Aviation { - class CAircraftSituation; + class CAircraftParts; //! Value object encapsulating a list of aircraft situations class BLACKMISC_EXPORT CAircraftSituationList : public CSequence, + public Geo::IGeoObjectList, public ITimestampWithOffsetObjectList, public ICallsignObjectList, public Mixin::MetaType @@ -50,10 +52,16 @@ namespace BlackMisc CAircraftSituationList(std::initializer_list il); //! Set ground elevation from elevation plane - int setGroundElevationChecked(const Geo::CElevationPlane &elevationPlane, bool ignoreNullValues = true, bool overrideExisting = true); + int setGroundElevationChecked(const Geo::CElevationPlane &elevationPlane, qint64 newerThanAdjustedMs = -1); - //! Set ground elevation from elevation plane - int setGroundElevationChecked(const Geo::CElevationPlane &elevationPlane, qint64 newerThanAdjustedMs, bool ignoreNullValues = true, bool overrideExisting = true); + //! Adjust flag by using CAircraftSituation::adjustGroundFlag + int adjustGroundFlag(const CAircraftParts &parts, double timeDeviationFactor = 0.1); + + //! Extrapolate ground flag into the future + int extrapolateGroundFlag(); + + //! Find if having inbound information + CAircraftSituationList findByInboundGroundInformation(bool hasGroundInfo) const; }; } // namespace } // namespace diff --git a/src/blackmisc/geo/elevationplane.cpp b/src/blackmisc/geo/elevationplane.cpp index d05176f5c..103c4d97c 100644 --- a/src/blackmisc/geo/elevationplane.cpp +++ b/src/blackmisc/geo/elevationplane.cpp @@ -89,15 +89,16 @@ namespace BlackMisc const ColumnIndex i = index.frontCasted(); switch (i) { - case IndexRadius: - m_radius.setPropertyByIndex(index.copyFrontRemoved(), variant); - break; - default: - CCoordinateGeodetic::setPropertyByIndex(index, variant); - break; + case IndexRadius: m_radius.setPropertyByIndex(index.copyFrontRemoved(), variant); break; + default: CCoordinateGeodetic::setPropertyByIndex(index, variant); break; } } + int CElevationPlane::comparePropertyByIndex(const CPropertyIndex &index, const CElevationPlane &elevationPlane) const + { + return this->getAltitude().comparePropertyByIndex(index, elevationPlane.getAltitude()); + } + // 100km/h 27,8m/s // 50km/h 13,9m/s // 100kts 51,4m/s @@ -118,5 +119,11 @@ namespace BlackMisc static const CLength l(1000.0, CLengthUnit::m()); return l; } + + const CElevationPlane &CElevationPlane::null() + { + static const CElevationPlane p; + return p; + } } // namespace } // namespace diff --git a/src/blackmisc/geo/elevationplane.h b/src/blackmisc/geo/elevationplane.h index 2b6a95f33..84441a396 100644 --- a/src/blackmisc/geo/elevationplane.h +++ b/src/blackmisc/geo/elevationplane.h @@ -12,14 +12,15 @@ #ifndef BLACKMISC_GEO_ELEVATIONPLANE_H #define BLACKMISC_GEO_ELEVATIONPLANE_H -#include "blackmisc/blackmiscexport.h" #include "blackmisc/geo/coordinategeodetic.h" +#include "blackmisc/blackmiscexport.h" namespace BlackMisc { namespace Geo { //! Plane of same elevation, can be a single point or larger area (e.g. airport) + //! \remark 100km/h 1sec => 28m class BLACKMISC_EXPORT CElevationPlane : public CValueObject { @@ -73,6 +74,9 @@ namespace BlackMisc //! \copydoc BlackMisc::Mixin::Index::setPropertyByIndex void setPropertyByIndex(const CPropertyIndex &index, const CVariant &variant); + //! Compare by index + int comparePropertyByIndex(const CPropertyIndex &index, const CElevationPlane &elevationPlane) const; + //! \copydoc BlackMisc::Mixin::String::toQString QString convertToQString(bool i18n = false) const; @@ -85,6 +89,9 @@ namespace BlackMisc //! Radius for major airport static const PhysicalQuantities::CLength &majorAirportRadius(); + //! NULL plane + static const CElevationPlane &null(); + private: PhysicalQuantities::CLength m_radius { 0, nullptr }; //!< elevation is valid in radius diff --git a/src/blackmisc/simulation/interpolationhints.cpp b/src/blackmisc/simulation/interpolationhints.cpp index 64a6b1083..854c90a8f 100644 --- a/src/blackmisc/simulation/interpolationhints.cpp +++ b/src/blackmisc/simulation/interpolationhints.cpp @@ -30,10 +30,41 @@ namespace BlackMisc m_isVtol(isVtolAircraft), m_hasParts(hasParts), m_logInterpolation(log) { } + const CElevationPlane &CInterpolationHints::getElevationPlane(ICoordinateGeodetic &reference, const CLength &radius, SituationLog *log) const + { + if (m_elevationPlane.isNull()) + { + if (log) + { + static const QString lm("By provider (no valid plane)"); + log->elevationInfo = lm; + } + return CElevationPlane::null(); + } + const CLength d = reference.calculateGreatCircleDistance(m_elevationPlane); + if (d <= radius) + { + if (log) + { + static const QString lm("Using elevation plane, distance: %1"); + log->elevationInfo = lm.arg(d.valueRoundedWithUnit(CLengthUnit::m(), 1)); + } + return m_elevationPlane; + } + else + { + if (log) + { + static const QString lm("Invalid elevation plane, distance: %1"); + log->elevationInfo = lm.arg(d.valueRoundedWithUnit(CLengthUnit::m(), 1)); + } + return CElevationPlane::null(); + } + } + CAltitude CInterpolationHints::getGroundElevation(const CAircraftSituation &situation, bool useProvider, bool forceProvider, SituationLog *log) const { - static const CLength null = CLength(0, CLengthUnit::nullUnit()); - return this->getGroundElevation(situation, null, useProvider, forceProvider, log); + return this->getGroundElevation(situation, CLength::null(), useProvider, forceProvider, log); } CAltitude CInterpolationHints::getGroundElevation(const CAircraftSituation &situation, const CLength &validRadius, bool useProvider, bool forceProvider, SituationLog *log) const @@ -46,6 +77,7 @@ namespace BlackMisc static const QString lm("By provider (forced)"); log->elevationInfo = lm; } + Q_ASSERT_X(false, Q_FUNC_INFO, "Elevation provider must no longer be used"); return m_elevationProvider(situation); } @@ -80,6 +112,16 @@ namespace BlackMisc return CAltitude::null(); } + CAltitude CInterpolationHints::getGroundElevation(const CAircraftSituation &situation, const CLength &validRadius, SituationLog *log) const + { + return this->getGroundElevation(situation, validRadius, false, false, log); + } + + CAltitude CInterpolationHints::getGroundElevation(const CAircraftSituation &situation, SituationLog *log) const + { + return this->getGroundElevation(situation, CLength::null(), log); + } + void CInterpolationHints::resetElevationPlane() { m_elevationPlane = CElevationPlane(); @@ -87,7 +129,7 @@ namespace BlackMisc bool CInterpolationHints::isWithinRange(const Geo::ICoordinateGeodetic &coordinate) const { - if (m_elevationPlane.isNull()) return false; + if (m_elevationPlane.isNull()) { return false; } return m_elevationPlane.isWithinRange(coordinate); } diff --git a/src/blackmisc/simulation/interpolationhints.h b/src/blackmisc/simulation/interpolationhints.h index 6166dc0c2..52131aeee 100644 --- a/src/blackmisc/simulation/interpolationhints.h +++ b/src/blackmisc/simulation/interpolationhints.h @@ -48,6 +48,9 @@ namespace BlackMisc //! Get elevation plane const Geo::CElevationPlane &getElevationPlane() const { return m_elevationPlane;} + //! Get elevation plane + const Geo::CElevationPlane &getElevationPlane(Geo::ICoordinateGeodetic &reference, const PhysicalQuantities::CLength &radius, SituationLog *log = nullptr) const; + //! Set elevation //! \remark used to store a ground elevation and use it as well for nearby situatons void setElevationPlane(const Geo::CElevationPlane &elevation) { m_elevationPlane = elevation; } @@ -55,6 +58,8 @@ namespace BlackMisc //! Elevation plane set to null void resetElevationPlane(); + private: + //! \todo KB 2018-03 ground flag refactoring //! Get elevation from CInterpolationHints::getElevationProvider or CInterpolationHints::getElevation //! \remark avoid unnecessary calls on XPlane (calling elevation provider) //! \param situation where to check @@ -63,12 +68,23 @@ namespace BlackMisc //! \param log optional chance to write info about elevation //! \see setElevationProvider //! \see setElevationPlane + //! \deprecated Aviation::CAltitude getGroundElevation(const Aviation::CAircraftSituation &situation, bool useProvider, bool forceProvider = false, SituationLog *log = nullptr) const; //! Get elevation from CInterpolationHints::getElevationProvider or CInterpolationHints::getElevation //! \remark if validRadius is >= Geo::CElevationPlane::radius use validRadius + //! \deprecated Aviation::CAltitude getGroundElevation(const Aviation::CAircraftSituation &situation, const PhysicalQuantities::CLength &validRadius, bool useProvider, bool forceProvider = false, SituationLog *log = nullptr) const; + //! Get ground elevation by using the elevation plane + //! \deprecated + Aviation::CAltitude getGroundElevation(const Aviation::CAircraftSituation &situation, const PhysicalQuantities::CLength &validRadius, SituationLog *log = nullptr) const; + + //! Get ground elevation by using the elevation plane + //! \deprecated + Aviation::CAltitude getGroundElevation(const Aviation::CAircraftSituation &situation, SituationLog *log = nullptr) const; + + public: //! Check if elevation is within radius and can be used bool isWithinRange(const Geo::ICoordinateGeodetic &coordinate) const; @@ -110,12 +126,14 @@ namespace BlackMisc using ElevationProvider = std::function; //! Has elevation provider? + //! \deprecated bool hasElevationProvider() const; //! Set function object that can obtain ground elevation //! \remark either a provider can be used or an elevation plan can be set //! \see setElevationPlane //! \see getGroundElevation + //! \deprecated void setElevationProvider(const ElevationProvider &ep) { m_elevationProvider = ep; } //! \copydoc BlackMisc::Mixin::Index::propertyByIndex diff --git a/src/blackmisc/simulation/interpolator.cpp b/src/blackmisc/simulation/interpolator.cpp index 5b117ba65..f2bc3376e 100644 --- a/src/blackmisc/simulation/interpolator.cpp +++ b/src/blackmisc/simulation/interpolator.cpp @@ -74,12 +74,14 @@ namespace BlackMisc currentSituation.setCallsign(m_callsign); } + //! \todo KB 2018-03 ground flag refactoring // Update current position by hints' elevation // * for XP provided by hints.getElevationProvider at current position // * for FSX/P3D provided as hints.getElevation which is set to current position of remote aircraft in simulator // * As XP uses lazy init we will call getGroundElevation only when needed // * default here via getElevationPlane - CAltitude currentGroundElevation(hints.getGroundElevation(currentSituation, currentSituation.getDistancePerTime(1000), true, false, logP)); + // CAltitude currentGroundElevation(hints.getGroundElevation(currentSituation, currentSituation.getDistancePerTime(1000), true, false, logP)); + const CElevationPlane currentGroundElevation = hints.getElevationPlane(currentSituation, currentSituation.getDistancePerTime(1000), logP); currentSituation.setGroundElevation(currentGroundElevation); // set as default // data, split situations by time @@ -410,15 +412,6 @@ namespace BlackMisc return IRemoteAircraftProvider::MaxSituationsPerCallsign; } - template - void CInterpolator::setGroundElevationFromHint(const CInterpolationHints &hints, CAircraftSituation &situation, bool override) - { - if (!override && situation.hasGroundElevation()) { return; } - const CAltitude elevation = hints.getGroundElevation(situation, false); - if (elevation.isNull()) { return; } - situation.setGroundElevation(elevation); - } - template void CInterpolator::setGroundFlagFromInterpolator(const CInterpolationHints &hints, double groundFactor, CAircraftSituation &situation) { diff --git a/src/blackmisc/simulation/interpolator.h b/src/blackmisc/simulation/interpolator.h index 8beac9c47..e6f02e0e1 100644 --- a/src/blackmisc/simulation/interpolator.h +++ b/src/blackmisc/simulation/interpolator.h @@ -112,9 +112,6 @@ namespace BlackMisc //! Constructor CInterpolator(const QString &objectName, const Aviation::CCallsign &callsign, QObject *parent); - //! Set the ground elevation from hints - static void setGroundElevationFromHint(const CInterpolationHints &hints, Aviation::CAircraftSituation &situation, bool override = true); - //! Set on ground flag static void setGroundFlagFromInterpolator(const CInterpolationHints &hints, double groundFactor, Aviation::CAircraftSituation &situation); diff --git a/src/blackmisc/simulation/interpolatorlinear.cpp b/src/blackmisc/simulation/interpolatorlinear.cpp index f2075f932..1b9f6bd5c 100644 --- a/src/blackmisc/simulation/interpolatorlinear.cpp +++ b/src/blackmisc/simulation/interpolatorlinear.cpp @@ -120,8 +120,8 @@ namespace BlackMisc // do not call for XP (lazy init) if (!hints.hasElevationProvider()) { - CInterpolator::setGroundElevationFromHint(hints, oldSituation, false); - CInterpolator::setGroundElevationFromHint(hints, newSituation, false); + oldSituation.setGroundElevationChecked(hints.getElevationPlane()); + newSituation.setGroundElevationChecked(hints.getElevationPlane()); } CAircraftSituation currentSituation(oldSituation); // also sets ground elevation if available diff --git a/src/blackmisc/simulation/simulatedaircraft.h b/src/blackmisc/simulation/simulatedaircraft.h index 61e588e45..894abb4bb 100644 --- a/src/blackmisc/simulation/simulatedaircraft.h +++ b/src/blackmisc/simulation/simulatedaircraft.h @@ -213,7 +213,10 @@ namespace BlackMisc const BlackMisc::Aviation::CAltitude &getGroundElevation() const { return m_situation.getGroundElevation(); } //! \copydoc BlackMisc::Aviation::CAircraftSituation::setGroundElevation - void setGroundElevation(const BlackMisc::Aviation::CAltitude &elevation) { m_situation.setGroundElevation(elevation); } + void setGroundElevation(const Geo::CElevationPlane &elevation) { m_situation.setGroundElevation(elevation); } + + //! \copydoc BlackMisc::Aviation::CAircraftSituation::setGroundElevation + void setGroundElevationChecked(const Geo::CElevationPlane &elevation) { m_situation.setGroundElevationChecked(elevation); } //! \copydoc BlackMisc::Aviation::CAircraftSituation::getHeading const BlackMisc::Aviation::CHeading &getHeading() const { return m_situation.getHeading(); } diff --git a/src/blackmisc/simulation/simulatedaircraftlist.cpp b/src/blackmisc/simulation/simulatedaircraftlist.cpp index b8815e267..c509ee5c9 100644 --- a/src/blackmisc/simulation/simulatedaircraftlist.cpp +++ b/src/blackmisc/simulation/simulatedaircraftlist.cpp @@ -20,8 +20,8 @@ #include #include -using namespace BlackMisc; using namespace BlackMisc::Aviation; +using namespace BlackMisc::Geo; using namespace BlackMisc::PhysicalQuantities; using namespace BlackMisc::Network; @@ -160,13 +160,13 @@ namespace BlackMisc return c; } - int CSimulatedAircraftList::setGroundElevation(const CCallsign &callsign, const CAltitude &elevation, bool onlyFirst) + int CSimulatedAircraftList::setGroundElevationChecked(const CCallsign &callsign, const CElevationPlane &elevation, bool onlyFirst) { int c = 0; for (CSimulatedAircraft &aircraft : (*this)) { if (aircraft.getCallsign() != callsign) { continue; } - aircraft.setGroundElevation(elevation); + aircraft.setGroundElevationChecked(elevation); c++; if (onlyFirst) break; } @@ -227,7 +227,7 @@ namespace BlackMisc return c; } - int CSimulatedAircraftList::countAircraftPartsSyncronized() const + int CSimulatedAircraftList::countAircraftPartsSynchronized() const { int c = 0; for (const CSimulatedAircraft &aircraft : (*this)) diff --git a/src/blackmisc/simulation/simulatedaircraftlist.h b/src/blackmisc/simulation/simulatedaircraftlist.h index 098c13491..4a3eb0268 100644 --- a/src/blackmisc/simulation/simulatedaircraftlist.h +++ b/src/blackmisc/simulation/simulatedaircraftlist.h @@ -12,16 +12,15 @@ #ifndef BLACKMISC_SIMULATION_SIMULATEDNAIRCRAFTLIST_H #define BLACKMISC_SIMULATION_SIMULATEDNAIRCRAFTLIST_H +#include "blackmisc/simulation/simulatedaircraft.h" #include "blackmisc/aviation/callsignobjectlist.h" #include "blackmisc/aviation/callsignset.h" -#include "blackmisc/blackmiscexport.h" -#include "blackmisc/collection.h" #include "blackmisc/geo/geoobjectlist.h" #include "blackmisc/network/userlist.h" +#include "blackmisc/blackmiscexport.h" +#include "blackmisc/collection.h" #include "blackmisc/sequence.h" -#include "blackmisc/simulation/simulatedaircraft.h" #include "blackmisc/variant.h" - #include namespace BlackMisc @@ -92,7 +91,7 @@ namespace BlackMisc int setAircraftSituation(const Aviation::CCallsign &callsign, const Aviation::CAircraftSituation &situation, bool onlyFirst = true); //! Set ground elevation - int setGroundElevation(const Aviation::CCallsign &callsign, const Aviation::CAltitude &elevation, bool onlyFirst = true); + int setGroundElevationChecked(const Aviation::CCallsign &callsign, const Geo::CElevationPlane &elevation, bool onlyFirst = true); //! Enabled? bool isEnabled(const Aviation::CCallsign &callsign) const; @@ -110,7 +109,7 @@ namespace BlackMisc int countRendered() const; //! Number of aircraft with parts - int countAircraftPartsSyncronized() const; + int countAircraftPartsSynchronized() const; }; } //namespace } // namespace diff --git a/tests/blackmisc/testinterpolatorlinear.cpp b/tests/blackmisc/testinterpolatorlinear.cpp index fbd3805c7..ca07d029b 100644 --- a/tests/blackmisc/testinterpolatorlinear.cpp +++ b/tests/blackmisc/testinterpolatorlinear.cpp @@ -165,7 +165,8 @@ namespace BlackMiscTest const CSpeed gs(number * 10, CSpeedUnit::km_h()); const CAltitude gndElev({ 0, CLengthUnit::m() }, CAltitude::MeanSeaLevel); const CCoordinateGeodetic c(lat, lng, alt); - CAircraftSituation s(callsign, c, heading, pitch, bank, gs, gndElev); + CAircraftSituation s(callsign, c, heading, pitch, bank, gs); + s.setGroundElevation(gndElev); s.setMSecsSinceEpoch(ts - deltaT * number); // values in past s.setTimeOffsetMs(offset); return s;