diff --git a/src/blackmisc/aviation/aircraftsituation.cpp b/src/blackmisc/aviation/aircraftsituation.cpp index 1542e0229..06da7a5d4 100644 --- a/src/blackmisc/aviation/aircraftsituation.cpp +++ b/src/blackmisc/aviation/aircraftsituation.cpp @@ -144,6 +144,7 @@ namespace BlackMisc static const QString change("situation change"); static const QString cache("cached"); static const QString test("test"); + static const QString interpolated("interpolated"); switch (details) { @@ -153,6 +154,7 @@ namespace BlackMisc case SituationChange: return change; case FromCache: return cache; case Test: return test; + case Interpolated: return interpolated; default: break; } return unknown; @@ -176,6 +178,85 @@ namespace BlackMisc return cg; } + bool CAircraftSituation::presetGroundElevation(CAircraftSituation &situationToPreset, const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation, const CAircraftSituationChange &change) + { + // IMPORTANT: we do not know what the situation will be interpolated to, so we cannot transfer + situationToPreset.resetGroundElevation(); + do + { + if (oldSituation.equalNormalVectorDouble(newSituation)) + { + if (oldSituation.hasGroundElevation()) + { + // same positions, we can use existing elevation + // means we were not moving between old an new + situationToPreset.setGroundElevation(oldSituation.getGroundElevationPlane(), CAircraftSituation::TransferredElevation); + break; + } + } + + const CLength distance = newSituation.calculateGreatCircleDistance(oldSituation); + if (distance < newSituation.getDistancePerTime(250)) + { + if (oldSituation.hasGroundElevation()) + { + // almost same positions, we can use existing elevation + situationToPreset.setGroundElevation(oldSituation.getGroundElevationPlane(), CAircraftSituation::TransferredElevation); + break; + } + } + + static const CLength allowedStdDev(3, CLengthUnit::ft()); + QPair elvDevMean = change.getElevationStdDevAndMean(); + if (!elvDevMean.first.isNull() && elvDevMean.first < allowedStdDev) + { + // not much change in known elevations + situationToPreset.setGroundElevation(elvDevMean.second, CAircraftSituation::SituationChange); + break; + } + + const CElevationPlane epInterpolated = CAircraftSituation::interpolateElevation(CAircraftSituation::null(), oldSituation, newSituation, distance); + if (!epInterpolated.isNull()) + { + situationToPreset.setGroundElevation(epInterpolated, CAircraftSituation::Interpolated); + break; + } + } + while (false); + return situationToPreset.hasGroundElevation(); + } + + CElevationPlane CAircraftSituation::interpolateElevation(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(); } + + const double newElvFt = newSituation.getGroundElevation().value(CLengthUnit::ft()); + const double oldElvFt = oldSituation.getGroundElevation().value(CLengthUnit::ft()); + const double deltaElvFt = newElvFt - oldElvFt; + if (deltaElvFt > 25) { return CElevationPlane::null(); } + + if (!situation.isNull()) + { + const double distanceOldNewM = (distance.isNull() ? oldSituation.calculateGreatCircleDistance(newSituation) : distance).value(CLengthUnit::m()); + const double distanceSituationNewM = situation.calculateGreatCircleDistance(newSituation).value(CLengthUnit::m()); + const double distRatio = distanceSituationNewM / distanceOldNewM; + + // very close to the situations we return tehir elevation + if (distRatio < 0.05) { return newSituation.getGroundElevationPlane(); } + if (distRatio > 0.95) { return oldSituation.getGroundElevationPlane(); } + + const double situationElvFt = newElvFt - distRatio * deltaElvFt; + return CElevationPlane(situation, situationElvFt, CElevationPlane::singlePointRadius()); + } + else + { + const double elvSumFt = oldElvFt + newElvFt; + const double elvFt = 0.5 * elvSumFt; + return CElevationPlane(newSituation, elvFt, CElevationPlane::singlePointRadius()); + } + } + CVariant CAircraftSituation::propertyByIndex(const BlackMisc::CPropertyIndex &index) const { if (index.isMyself()) { return CVariant::from(*this); } @@ -563,6 +644,11 @@ namespace BlackMisc return true; } + bool CAircraftSituation::presetGroundElevation(const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation, const CAircraftSituationChange &change) + { + return CAircraftSituation::presetGroundElevation(*this, oldSituation, newSituation, change); + } + CAircraftSituation::IsOnGround CAircraftSituation::isOnGroundByElevation() const { return this->isOnGroundByElevation(m_cg); diff --git a/src/blackmisc/aviation/aircraftsituation.h b/src/blackmisc/aviation/aircraftsituation.h index e083e28be..80ba2f572 100644 --- a/src/blackmisc/aviation/aircraftsituation.h +++ b/src/blackmisc/aviation/aircraftsituation.h @@ -116,6 +116,7 @@ namespace BlackMisc { NoElevationInfo, TransferredElevation, //!< transferred from nearby situation + Interpolated, //!< interpolated between 2 elevations FromProvider, //!< from BlackMisc::Simulation::ISimulationEnvironmentProvider FromCache, //!< from cache SituationChange, //!< from BlackMisc::Aviation::CAircraftSituationChange @@ -283,8 +284,16 @@ namespace BlackMisc bool canTransferGroundElevation(const CAircraftSituation &otherSituation, const PhysicalQuantities::CLength &radius = Geo::CElevationPlane::singlePointRadius()) const; //! 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; + //! 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 + bool presetGroundElevation(const Aviation::CAircraftSituation &oldSituation, const Aviation::CAircraftSituation &newSituation, const CAircraftSituationChange &change); + //! Is on ground by elevation data, requires elevation and CG //! @{ IsOnGround isOnGroundByElevation() const; @@ -471,6 +480,17 @@ namespace BlackMisc } //! @} + //! Preset the ground elevation based on info we already have + //! \remark either sets a gnd. elevation or sets it to null + //! \remark situationToPreset position is unknown + //! \remark situationToPreset needs to be between oldSituation and newSituation + //! \sa CAircraftSituation::transferGroundElevation + static bool presetGroundElevation(CAircraftSituation &situationToPreset, const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation, const CAircraftSituationChange &change); + + //! 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()); + private: CCallsign m_correspondingCallsign; Geo::CCoordinateGeodetic m_position; //!< NULL position as default diff --git a/src/blackmisc/geo/elevationplane.cpp b/src/blackmisc/geo/elevationplane.cpp index 724a86a8b..00156195c 100644 --- a/src/blackmisc/geo/elevationplane.cpp +++ b/src/blackmisc/geo/elevationplane.cpp @@ -38,6 +38,18 @@ namespace BlackMisc CCoordinateGeodetic(coordinate), m_radius(radius) { } + CElevationPlane::CElevationPlane(const ICoordinateGeodetic &coordinate, const CAltitude &altitude, const CLength &radius) : + CCoordinateGeodetic(coordinate), m_radius(radius) + { + this->setGeodeticHeight(altitude); + } + + CElevationPlane::CElevationPlane(const ICoordinateGeodetic &coordinate, double altitudeMSLft, const CLength &radius) : + CCoordinateGeodetic(coordinate), m_radius(radius) + { + this->setGeodeticHeight(CAltitude(altitudeMSLft, CAltitude::MeanSeaLevel, CLengthUnit::ft())); + } + void CElevationPlane::setRadiusOrMinimum(const CLength &radius) { m_radius = ((radius.isNull() || radius < CElevationPlane::singlePointRadius())) ? CElevationPlane::singlePointRadius() : radius; diff --git a/src/blackmisc/geo/elevationplane.h b/src/blackmisc/geo/elevationplane.h index 8eb7da858..4abbea4d2 100644 --- a/src/blackmisc/geo/elevationplane.h +++ b/src/blackmisc/geo/elevationplane.h @@ -39,6 +39,12 @@ namespace BlackMisc //! Plane at given coordinates with radius CElevationPlane(const ICoordinateGeodetic &coordinate, const PhysicalQuantities::CLength &radius); + //! Plane at given coordinates with radius and altitude + CElevationPlane(const ICoordinateGeodetic &coordinate, const Aviation::CAltitude &altitude, const PhysicalQuantities::CLength &radius); + + //! Plane at given coordinates with radius and altitude + CElevationPlane(const ICoordinateGeodetic &coordinate, double altitudeMSLft, const PhysicalQuantities::CLength &radius); + //! Constructors from CCoordinateGeodetic using CCoordinateGeodetic::CCoordinateGeodetic; diff --git a/src/blackmisc/simulation/interpolator.cpp b/src/blackmisc/simulation/interpolator.cpp index d64587d89..5ac9b73fe 100644 --- a/src/blackmisc/simulation/interpolator.cpp +++ b/src/blackmisc/simulation/interpolator.cpp @@ -424,9 +424,9 @@ namespace BlackMisc currentSituation.setCallsign(m_callsign); } - // do not set elevation here, as we do not know where the situation will be - // after the interpolation step! - this->presetGroundElevation(currentSituation, oldSituation, newSituation); + // preset elevation here, as we do not know where the situation will be after the interpolation step! + const bool preset = currentSituation.presetGroundElevation(oldSituation, newSituation, m_situationsChange); + Q_UNUSED(preset); // fetch CG once const CLength cg(this->getModelCG()); @@ -434,47 +434,6 @@ namespace BlackMisc return currentSituation; } - template - bool CInterpolator::presetGroundElevation(CAircraftSituation &situation, const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation) const - { - // IMPORTANT: we do not know what the situation will be interpolated to, so we cannot transfer - situation.resetGroundElevation(); - do - { - if (oldSituation.equalNormalVectorDouble(newSituation)) - { - if (oldSituation.hasGroundElevation()) - { - // same positions, we can use existing elevation - situation.setGroundElevation(oldSituation.getGroundElevationPlane(), CAircraftSituation::TransferredElevation); - break; - } - } - - const CLength distance = newSituation.calculateGreatCircleDistance(oldSituation); - if (distance < newSituation.getDistancePerTime(250)) - { - if (oldSituation.hasGroundElevation()) - { - // almost same positions, we can use existing elevation - situation.setGroundElevation(oldSituation.getGroundElevationPlane(), CAircraftSituation::TransferredElevation); - break; - } - } - - static const CLength allowedStdDev(3, CLengthUnit::ft()); - QPair elvDevMean = m_situationsChange.getElevationStdDevAndMean(); - if (!elvDevMean.first.isNull() && elvDevMean.first < allowedStdDev) - { - // not much change in known elevations - situation.setGroundElevation(elvDevMean.second, CAircraftSituation::SituationChange); - break; - } - } - while (false); - return situation.hasGroundElevation(); - } - template void CInterpolator::initCorrespondingModel(const CAircraftModel &model) { diff --git a/src/blackmisc/simulation/interpolator.h b/src/blackmisc/simulation/interpolator.h index 6fba061a8..1f1684c99 100644 --- a/src/blackmisc/simulation/interpolator.h +++ b/src/blackmisc/simulation/interpolator.h @@ -247,10 +247,6 @@ namespace BlackMisc //! Current interpolated situation Aviation::CAircraftSituation getInterpolatedSituation(); - //! Preset the ground elevation based on info we already have - //! \remark either sets a gnd.elevation or sets it to null - bool presetGroundElevation(Aviation::CAircraftSituation &situation, const Aviation::CAircraftSituation &oldSituation, const Aviation::CAircraftSituation &newSituation) const; - //! Parts before given offset time Aviation::CAircraftParts getInterpolatedParts();