diff --git a/src/blackmisc/aviation/aircraftsituation.cpp b/src/blackmisc/aviation/aircraftsituation.cpp index 06da7a5d4..dd2f8b730 100644 --- a/src/blackmisc/aviation/aircraftsituation.cpp +++ b/src/blackmisc/aviation/aircraftsituation.cpp @@ -90,26 +90,26 @@ namespace BlackMisc const QString &CAircraftSituation::onGroundDetailsToString(CAircraftSituation::OnGroundDetails reliability) { - static const QString intElv("elevation"); - static const QString intElvCg("elevation/CG"); - static const QString intInter("interpolation"); - static const QString intGuess("guessing"); + static const QString elv("elevation"); + static const QString elvCg("elevation/CG"); + static const QString interpolation("interpolation"); + static const QString guess("guessing"); static const QString unknown("unknown"); static const QString outOwnAircraft("own aircraft"); static const QString inNetwork("from network"); static const QString inFromParts("from parts"); - static const QString InNoGroundInfo("no gnd.info"); + static const QString inNoGndInfo("no gnd.info"); switch (reliability) { - case CAircraftSituation::OnGroundByElevation: return intElv; - case CAircraftSituation::OnGroundByElevationAndCG: return intElvCg; - case CAircraftSituation::OnGroundByGuessing: return intGuess; - case CAircraftSituation::OnGroundByInterpolation: return intInter; + case CAircraftSituation::OnGroundByElevation: return elv; + case CAircraftSituation::OnGroundByElevationAndCG: return elvCg; + case CAircraftSituation::OnGroundByGuessing: return guess; + case CAircraftSituation::OnGroundByInterpolation: return interpolation; case CAircraftSituation::OutOnGroundOwnAircraft: return outOwnAircraft; case CAircraftSituation::InFromNetwork: return inNetwork; case CAircraftSituation::InFromParts: return inFromParts; - case CAircraftSituation::InNoGroundInfo: return InNoGroundInfo; + case CAircraftSituation::InNoGroundInfo: return inNoGndInfo; case CAircraftSituation::NotSetGroundDetails: default: return unknown; } @@ -145,6 +145,7 @@ namespace BlackMisc static const QString cache("cached"); static const QString test("test"); static const QString interpolated("interpolated"); + static const QString extrapolated("extrapolated"); switch (details) { @@ -155,6 +156,7 @@ namespace BlackMisc case FromCache: return cache; case Test: return test; case Interpolated: return interpolated; + case Extrapolated: return extrapolated; default: break; } return unknown; @@ -196,7 +198,7 @@ namespace BlackMisc } const CLength distance = newSituation.calculateGreatCircleDistance(oldSituation); - if (distance < newSituation.getDistancePerTime(250)) + if (distance < newSituation.getDistancePerTime250ms()) { if (oldSituation.hasGroundElevation()) { @@ -206,16 +208,15 @@ namespace BlackMisc } } - static const CLength allowedStdDev(3, CLengthUnit::ft()); - QPair elvDevMean = change.getElevationStdDevAndMean(); - if (!elvDevMean.first.isNull() && elvDevMean.first < allowedStdDev) + if (change.hasElevationDevWithinAllowedRange()) { // not much change in known elevations + const CAltitudePair elvDevMean = change.getElevationStdDevAndMean(); situationToPreset.setGroundElevation(elvDevMean.second, CAircraftSituation::SituationChange); break; } - const CElevationPlane epInterpolated = CAircraftSituation::interpolateElevation(CAircraftSituation::null(), oldSituation, newSituation, distance); + const CElevationPlane epInterpolated = CAircraftSituation::interpolatedElevation(CAircraftSituation::null(), oldSituation, newSituation, distance); if (!epInterpolated.isNull()) { situationToPreset.setGroundElevation(epInterpolated, CAircraftSituation::Interpolated); @@ -226,7 +227,7 @@ namespace BlackMisc return situationToPreset.hasGroundElevation(); } - CElevationPlane CAircraftSituation::interpolateElevation(const CAircraftSituation &situation, const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation, const CLength &distance) + CElevationPlane CAircraftSituation::interpolatedElevation(const CAircraftSituation &situation, const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation, const CLength &distance) { if (oldSituation.isNull() || newSituation.isNull()) { return CAircraftSituation::null(); } if (oldSituation.equalNormalVectorDouble(newSituation)) { return newSituation.getGroundElevationPlane(); } @@ -257,6 +258,28 @@ namespace BlackMisc } } + bool CAircraftSituation::extrapolateElevation(CAircraftSituation &newSituation, const CAircraftSituation &oldSituation, const CAircraftSituation &olderSituation, const CAircraftSituationChange &oldChange) + { + if (newSituation.hasGroundElevation()) { return false; } + if (oldSituation.transferGroundElevation(newSituation)) { return true; } + if (oldSituation.isNull() || olderSituation.isNull()) { return false; } + + if (oldChange.isNull()) { return false; } + if (oldChange.isConstOnGround() && oldChange.hasAltitudeDevWithinAllowedRange() && oldChange.hasElevationDevWithinAllowedRange()) + { + // we have almost const altitudes and elevations + const double deltaAltFt = qAbs(newSituation.getAltitude().value(CLengthUnit::ft()) - olderSituation.getAltitude().value(CLengthUnit::ft())); + if (deltaAltFt <= CAircraftSituationChange::allowedAltitudeDeviation().value(CLengthUnit::ft())) + { + // the ccurrent alt is also not much different + newSituation.setGroundElevation(oldSituation.getGroundElevation(), Extrapolated); + return true; + } + } + + return false; + } + CVariant CAircraftSituation::propertyByIndex(const BlackMisc::CPropertyIndex &index) const { if (index.isMyself()) { return CVariant::from(*this); } @@ -636,11 +659,11 @@ namespace BlackMisc return transferable; } - bool CAircraftSituation::transferGroundElevation(CAircraftSituation &otherSituation, const CLength &radius) const + bool CAircraftSituation::transferGroundElevation(CAircraftSituation &transferToSituation, const CLength &radius) const { - if (!this->canTransferGroundElevation(otherSituation, radius)) { return false; } - otherSituation.setGroundElevation(this->getGroundElevationPlane(), TransferredElevation); - Q_ASSERT_X(!otherSituation.getGroundElevationRadius().isNull(), Q_FUNC_INFO, "null radius"); + if (!this->canTransferGroundElevation(transferToSituation, radius)) { return false; } + transferToSituation.setGroundElevation(this->getGroundElevationPlane(), TransferredElevation); + Q_ASSERT_X(!transferToSituation.getGroundElevationRadius().isNull(), Q_FUNC_INFO, "null radius"); return true; } @@ -649,6 +672,19 @@ namespace BlackMisc return CAircraftSituation::presetGroundElevation(*this, oldSituation, newSituation, change); } + bool CAircraftSituation::extrapolateElevation(const CAircraftSituation &oldSituation, const CAircraftSituation &olderSituation, const CAircraftSituationChange &change) + { + return CAircraftSituation::extrapolateElevation(*this, oldSituation, olderSituation, change); + } + + bool CAircraftSituation::interpolateElevation(const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation) + { + const CElevationPlane ep = CAircraftSituation::interpolatedElevation(*this, oldSituation, newSituation); + if (ep.isNull()) { return false; } + this->setGroundElevation(ep, Interpolated); + return true; + } + CAircraftSituation::IsOnGround CAircraftSituation::isOnGroundByElevation() const { return this->isOnGroundByElevation(m_cg); @@ -883,6 +919,11 @@ namespace BlackMisc return d; } + CLength CAircraftSituation::getDistancePerTime250ms() const + { + return this->getDistancePerTime(250); + } + void CAircraftSituation::setCallsign(const CCallsign &callsign) { m_correspondingCallsign = callsign; diff --git a/src/blackmisc/aviation/aircraftsituation.h b/src/blackmisc/aviation/aircraftsituation.h index 80ba2f572..355480263 100644 --- a/src/blackmisc/aviation/aircraftsituation.h +++ b/src/blackmisc/aviation/aircraftsituation.h @@ -95,7 +95,7 @@ namespace BlackMisc // received situation InFromNetwork, //!< received from network InFromParts, //!< set from aircraft parts - InNoGroundInfo, //!< not know + InNoGroundInfo, //!< not known // send information OutOnGroundOwnAircraft //!< sending on ground }; @@ -117,6 +117,7 @@ namespace BlackMisc NoElevationInfo, TransferredElevation, //!< transferred from nearby situation Interpolated, //!< interpolated between 2 elevations + Extrapolated, //!< extrapolated ("guessing") FromProvider, //!< from BlackMisc::Simulation::ISimulationEnvironmentProvider FromCache, //!< from cache SituationChange, //!< from BlackMisc::Aviation::CAircraftSituationChange @@ -286,14 +287,28 @@ namespace BlackMisc //! Transfer from "this" situation to \c otherSituation //! \remark "transfer" can be used, if the positions are known, "preset" if they are still unknown //! \sa CAircraftSituation::interpolateGroundElevation - bool transferGroundElevation(CAircraftSituation &otherSituation, const PhysicalQuantities::CLength &radius = Geo::CElevationPlane::singlePointRadius()) const; + //! \sa CAircraftSituation::interpolateElevation + bool transferGroundElevation(CAircraftSituation &transferToSituation, const PhysicalQuantities::CLength &radius = Geo::CElevationPlane::singlePointRadius()) const; //! Preset "this" elevation from the two adjacent positions //! \remark it is not required that the position of "this" is already known //! \remark "transfer" can be used, if the positions are known, "preset" if they are still unknown //! \sa CAircraftSituation::transferGroundElevation + //! \sa CAircraftSituation::interpolateElevation bool presetGroundElevation(const Aviation::CAircraftSituation &oldSituation, const Aviation::CAircraftSituation &newSituation, const CAircraftSituationChange &change); + //! Set "this" elevation from older situations. + //! \remark this is a future value + //! \sa CAircraftSituation::transferGroundElevation + //! \sa CAircraftSituation::interpolateElevation + bool extrapolateElevation(const Aviation::CAircraftSituation &oldSituation, const Aviation::CAircraftSituation &olderSituation, const CAircraftSituationChange &change); + + //! Interpolate "this" elevation from the two adjacent positions + //! \remark "transfer" can be used, if the positions are known, "preset" if they are still unknown + //! \sa CAircraftSituation::transferGroundElevation + //! \sa CAircraftSituation::presetGroundElevation + bool interpolateElevation(const Aviation::CAircraftSituation &oldSituation, const Aviation::CAircraftSituation &newSituation); + //! Is on ground by elevation data, requires elevation and CG //! @{ IsOnGround isOnGroundByElevation() const; @@ -395,6 +410,9 @@ namespace BlackMisc //! Distance per milliseconds PhysicalQuantities::CLength getDistancePerTime(int milliseconds) const; + //! Distance per milliseconds (250ms) + PhysicalQuantities::CLength getDistancePerTime250ms() const; + //! Corresponding callsign const CCallsign &getCallsign() const { return m_correspondingCallsign; } @@ -487,9 +505,14 @@ namespace BlackMisc //! \sa CAircraftSituation::transferGroundElevation static bool presetGroundElevation(CAircraftSituation &situationToPreset, const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation, const CAircraftSituationChange &change); + //! Extrapolated between the 2 situations for situation + //! \remark situation is not between oldSituation and olderSituation + //! \remark NULL if there are no two elevations + static bool extrapolateElevation(CAircraftSituation &newSituation, const CAircraftSituation &oldSituation, const CAircraftSituation &olderSituation, const CAircraftSituationChange &oldChange); + //! Interpolate between the 2 situations for situation //! \remark NULL if there are no two elevations - static Geo::CElevationPlane interpolateElevation(const CAircraftSituation &situation, const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation, const PhysicalQuantities::CLength &distance = PhysicalQuantities::CLength::null()); + static Geo::CElevationPlane interpolatedElevation(const CAircraftSituation &situation, const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation, const PhysicalQuantities::CLength &distance = PhysicalQuantities::CLength::null()); private: CCallsign m_correspondingCallsign; diff --git a/src/blackmisc/aviation/aircraftsituationlist.cpp b/src/blackmisc/aviation/aircraftsituationlist.cpp index f7eeda704..c347d6f05 100644 --- a/src/blackmisc/aviation/aircraftsituationlist.cpp +++ b/src/blackmisc/aviation/aircraftsituationlist.cpp @@ -114,6 +114,14 @@ namespace BlackMisc return c; } + bool CAircraftSituationList::extrapolateElevation(const CAircraftSituationChange &change) + { + if (this->size() < 3) { return false; } + const CAircraftSituation old = (*this)[1]; + const CAircraftSituation older = (*this)[2]; + return this->front().extrapolateElevation(old, older, change); + } + CAircraftSituationList CAircraftSituationList::findByInboundGroundInformation(bool hasGroundInfo) const { return this->findBy(&CAircraftSituation::hasInboundGroundDetails, hasGroundInfo); @@ -511,6 +519,19 @@ namespace BlackMisc const QPair deltaFt = CMathUtils::standardDeviationAndMean(altElvDeltas); return CAltitudePair(CAltitude(deltaFt.first, CAltitude::MeanSeaLevel, CAltitude::defaultUnit()), CAltitude(deltaFt.second, CAltitude::MeanSeaLevel, CAltitude::defaultUnit())); } + + int CAircraftSituationList::transferElevationForward(const CLength radius) + { + if (this->size() < 2) { return 0; } + Q_ASSERT_X(m_tsAdjustedSortHint == CAircraftSituationList::AdjustedTimestampLatestFirst, Q_FUNC_INFO, "need latest first"); + int c = 0; + for (int i = 1; i < this->size(); ++i) + { + const CAircraftSituation &oldSituation = (*this)[i]; + CAircraftSituation &newSituation = (*this)[i - 1]; + if (oldSituation.transferGroundElevation(newSituation, radius)) { c++; } + } + return c; } } // namespace } // namespace diff --git a/src/blackmisc/aviation/aircraftsituationlist.h b/src/blackmisc/aviation/aircraftsituationlist.h index cbed8833a..b5b6bd275 100644 --- a/src/blackmisc/aviation/aircraftsituationlist.h +++ b/src/blackmisc/aviation/aircraftsituationlist.h @@ -69,6 +69,11 @@ namespace BlackMisc //! Extrapolate ground flag into the future int extrapolateGroundFlag(); + //! Extrapolates elevation into front element from 2nd and 3rd element + //! \sa CAircraftSituation::extrapolateElevation + //! \pre the list must be sorted latest first and containt at least 3 elements + bool extrapolateElevation(const CAircraftSituationChange &change); + //! Find if having inbound information CAircraftSituationList findByInboundGroundInformation(bool hasGroundInfo) const; @@ -182,6 +187,10 @@ namespace BlackMisc //! Min. and max. ground distance PhysicalQuantities::CLengthPair minMaxGroundDistance(const PhysicalQuantities::CLength &cg) const; + + //! Transfer elevations forward from older to newer + //! \pre requires a list which is sorted "latest first" + int transferElevationForward(const PhysicalQuantities::CLength radius = Geo::CElevationPlane::singlePointRadius()); }; //! Situation per callsign