From 2625c3fb6b856a417926714e2eb3986e2079ae93 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Mon, 18 Jun 2018 03:21:15 +0200 Subject: [PATCH] Ref T275, new function to estimate ground elevation and some provider functions * added "averageElevationOfNonMovingAircraft". Idea: aircraft in the vicinity not moving or on ground likely have the same airport elevation * added "isWithinRange" * added "latestRemoteAircraftSituations" / "remoteAircraftSituation" in provider --- src/blackcore/airspacemonitor.cpp | 26 ++++++--- src/blackcore/context/contextnetworkimpl.cpp | 17 ++++++ src/blackcore/context/contextnetworkimpl.h | 25 +++++---- src/blackmisc/aviation/aircraftsituation.cpp | 6 ++- src/blackmisc/aviation/aircraftsituation.h | 1 + .../aviation/aircraftsituationlist.cpp | 25 ++++++++- .../aviation/aircraftsituationlist.h | 7 ++- src/blackmisc/geo/coordinategeodetic.cpp | 25 ++++++--- src/blackmisc/geo/coordinategeodetic.h | 3 ++ .../simulation/remoteaircraftprovider.cpp | 54 ++++++++++++++++--- .../simulation/remoteaircraftprovider.h | 36 +++++++++++-- 11 files changed, 183 insertions(+), 42 deletions(-) diff --git a/src/blackcore/airspacemonitor.cpp b/src/blackcore/airspacemonitor.cpp index dc7cc0275..bffb1526e 100644 --- a/src/blackcore/airspacemonitor.cpp +++ b/src/blackcore/airspacemonitor.cpp @@ -950,15 +950,27 @@ namespace BlackCore correctedSituation.setGroundElevation(ep, CAircraftSituation::FromCache); if (!correctedSituation.hasGroundElevation()) { - // values before updating - const CAircraftSituationList oldSituations = this->remoteAircraftSituations(callsign); - const CAircraftSituationChangeList oldChanges = this->remoteAircraftSituationChanges(callsign); - if (oldSituations.size() > 1) + // we have a new situation, so we try to get the elevation + // so far we have requested it, but we set it upfront either by + // a) average value from other plane in the vicinity or + // b) by extrapolating + const CElevationPlane averagePlane = this->averageElevationOfNonMovingAircraft(situation, CElevationPlane::minorAirportRadius()); + if (!averagePlane.isNull()) { - const bool extrapolated = correctedSituation.extrapolateElevation(oldSituations[0], oldSituations[1], oldChanges.frontOrDefault()); - Q_UNUSED(extrapolated); + correctedSituation.setGroundElevation(averagePlane, CAircraftSituation::Average); } - } + else + { + // values before updating + const CAircraftSituationList oldSituations = this->remoteAircraftSituations(callsign); + const CAircraftSituationChangeList oldChanges = this->remoteAircraftSituationChanges(callsign); + if (oldSituations.size() > 1) + { + const bool extrapolated = correctedSituation.extrapolateElevation(oldSituations[0], oldSituations[1], oldChanges.frontOrDefault()); + Q_UNUSED(extrapolated); + } + } + } // gnd. elevation } // do we already have ground details? diff --git a/src/blackcore/context/contextnetworkimpl.cpp b/src/blackcore/context/contextnetworkimpl.cpp index 5ea2d5cdd..d67700672 100644 --- a/src/blackcore/context/contextnetworkimpl.cpp +++ b/src/blackcore/context/contextnetworkimpl.cpp @@ -115,6 +115,18 @@ namespace BlackCore return m_airspace->remoteAircraftSituations(callsign); } + CAircraftSituation CContextNetwork::remoteAircraftSituation(const Aviation::CCallsign &callsign, int index) const + { + Q_ASSERT(m_airspace); + return m_airspace->remoteAircraftSituation(callsign, index); + } + + CAircraftSituationList CContextNetwork::latestRemoteAircraftSituations() const + { + Q_ASSERT(m_airspace); + return m_airspace->latestRemoteAircraftSituations(); + } + CAircraftPartsList CContextNetwork::remoteAircraftParts(const CCallsign &callsign) const { Q_ASSERT(m_airspace); @@ -820,6 +832,11 @@ namespace BlackCore return m_airspace->getLatestAirspaceAircraftSnapshot(); } + CElevationPlane CContextNetwork::averageElevationOfNonMovingAircraft(const CAircraftSituation &reference, const CLength &range, int minValues) const + { + return m_airspace->averageElevationOfNonMovingAircraft(reference, range, minValues); + } + void CContextNetwork::setClients(const CClientList &clients) { m_airspace->setClients(clients); diff --git a/src/blackcore/context/contextnetworkimpl.h b/src/blackcore/context/contextnetworkimpl.h index 0fa1281de..68c3c0dee 100644 --- a/src/blackcore/context/contextnetworkimpl.h +++ b/src/blackcore/context/contextnetworkimpl.h @@ -24,6 +24,13 @@ #include "blackcore/corefacadeconfig.h" #include "blackcore/network.h" #include "blackmisc/audio/voiceroomlist.h" +#include "blackmisc/simulation/aircraftmodel.h" +#include "blackmisc/simulation/airspaceaircraftsnapshot.h" +#include "blackmisc/simulation/remoteaircraftprovider.h" +#include "blackmisc/simulation/simulatedaircraft.h" +#include "blackmisc/simulation/simulatedaircraftlist.h" +#include "blackmisc/weather/metar.h" +#include "blackmisc/weather/metarlist.h" #include "blackmisc/aviation/aircraftpartslist.h" #include "blackmisc/aviation/aircraftsituationlist.h" #include "blackmisc/aviation/airporticaocode.h" @@ -38,13 +45,6 @@ #include "blackmisc/network/textmessagelist.h" #include "blackmisc/network/user.h" #include "blackmisc/network/userlist.h" -#include "blackmisc/simulation/aircraftmodel.h" -#include "blackmisc/simulation/airspaceaircraftsnapshot.h" -#include "blackmisc/simulation/remoteaircraftprovider.h" -#include "blackmisc/simulation/simulatedaircraft.h" -#include "blackmisc/simulation/simulatedaircraftlist.h" -#include "blackmisc/weather/metar.h" -#include "blackmisc/weather/metarlist.h" #include "blackmisc/pq/length.h" #include "blackmisc/statusmessage.h" #include "blackmisc/digestsignal.h" @@ -92,6 +92,8 @@ namespace BlackCore //! \ingroup remoteaircraftprovider //! @{ virtual BlackMisc::Aviation::CAircraftSituationList remoteAircraftSituations(const BlackMisc::Aviation::CCallsign &callsign) const override; + virtual BlackMisc::Aviation::CAircraftSituation remoteAircraftSituation(const BlackMisc::Aviation::CCallsign &callsign, int index) const override; + virtual BlackMisc::Aviation::CAircraftSituationList latestRemoteAircraftSituations() const override; virtual int remoteAircraftSituationsCount(const BlackMisc::Aviation::CCallsign &callsign) const override; virtual BlackMisc::Aviation::CAircraftPartsList remoteAircraftParts(const BlackMisc::Aviation::CCallsign &callsign) const override; virtual int remoteAircraftPartsCount(const BlackMisc::Aviation::CCallsign &callsign) const override; @@ -99,6 +101,11 @@ namespace BlackCore virtual BlackMisc::Aviation::CCallsignSet remoteAircraftSupportingParts() const override; virtual BlackMisc::Aviation::CAircraftSituationChangeList remoteAircraftSituationChanges(const BlackMisc::Aviation::CCallsign &callsign) const override; virtual int remoteAircraftSituationChangesCount(const BlackMisc::Aviation::CCallsign &callsign) const override; + virtual bool updateAircraftRendered(const BlackMisc::Aviation::CCallsign &callsign, bool rendered) override; + virtual int updateAircraftGroundElevation(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Geo::CElevationPlane &elevation, BlackMisc::Aviation::CAircraftSituation::GndElevationInfo info) override; + virtual void updateMarkAllAsNotRendered() override; + virtual BlackMisc::Simulation::CAirspaceAircraftSnapshot getLatestAirspaceAircraftSnapshot() const override; + virtual BlackMisc::Geo::CElevationPlane averageElevationOfNonMovingAircraft(const BlackMisc::Aviation::CAircraftSituation &reference, const BlackMisc::PhysicalQuantities::CLength &range, int minValues = 1) const override; virtual QList connectRemoteAircraftProviderSignals( QObject *receiver, std::function addedSituationSlot, @@ -106,10 +113,6 @@ namespace BlackCore std::function removedAircraftSlot, std::function aircraftSnapshotSlot ) override; - virtual bool updateAircraftRendered(const BlackMisc::Aviation::CCallsign &callsign, bool rendered) override; - virtual int updateAircraftGroundElevation(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Geo::CElevationPlane &elevation, BlackMisc::Aviation::CAircraftSituation::GndElevationInfo info) override; - virtual void updateMarkAllAsNotRendered() override; - virtual BlackMisc::Simulation::CAirspaceAircraftSnapshot getLatestAirspaceAircraftSnapshot() const override; //! @} //! \ingroup clientprovider diff --git a/src/blackmisc/aviation/aircraftsituation.cpp b/src/blackmisc/aviation/aircraftsituation.cpp index dd2f8b730..9177ed5c7 100644 --- a/src/blackmisc/aviation/aircraftsituation.cpp +++ b/src/blackmisc/aviation/aircraftsituation.cpp @@ -137,7 +137,7 @@ namespace BlackMisc const QString &CAircraftSituation::gndElevationInfoToString(GndElevationInfo details) { - static const QString no("no details"); + static const QString noDetails("no details"); static const QString unknown("unknown"); static const QString transferred("transferred"); static const QString provider("provider"); @@ -146,10 +146,11 @@ namespace BlackMisc static const QString test("test"); static const QString interpolated("interpolated"); static const QString extrapolated("extrapolated"); + static const QString avg("average"); switch (details) { - case NoElevationInfo: return no; + case NoElevationInfo: return noDetails; case TransferredElevation: return transferred; case FromProvider: return provider; case SituationChange: return change; @@ -157,6 +158,7 @@ namespace BlackMisc case Test: return test; case Interpolated: return interpolated; case Extrapolated: return extrapolated; + case Average: return avg; default: break; } return unknown; diff --git a/src/blackmisc/aviation/aircraftsituation.h b/src/blackmisc/aviation/aircraftsituation.h index 355480263..3dff45e54 100644 --- a/src/blackmisc/aviation/aircraftsituation.h +++ b/src/blackmisc/aviation/aircraftsituation.h @@ -118,6 +118,7 @@ namespace BlackMisc TransferredElevation, //!< transferred from nearby situation Interpolated, //!< interpolated between 2 elevations Extrapolated, //!< extrapolated ("guessing") + Average, //!< average value of "nearby" situation CAircraftSituationList::averageElevationOfNonMovingAircraft FromProvider, //!< from BlackMisc::Simulation::ISimulationEnvironmentProvider FromCache, //!< from cache SituationChange, //!< from BlackMisc::Aviation::CAircraftSituationChange diff --git a/src/blackmisc/aviation/aircraftsituationlist.cpp b/src/blackmisc/aviation/aircraftsituationlist.cpp index c347d6f05..2b7ae16b1 100644 --- a/src/blackmisc/aviation/aircraftsituationlist.cpp +++ b/src/blackmisc/aviation/aircraftsituationlist.cpp @@ -117,6 +117,7 @@ namespace BlackMisc bool CAircraftSituationList::extrapolateElevation(const CAircraftSituationChange &change) { if (this->size() < 3) { return false; } + Q_ASSERT_X(m_tsAdjustedSortHint == CAircraftSituationList::AdjustedTimestampLatestFirst, Q_FUNC_INFO, "Need latest first"); const CAircraftSituation old = (*this)[1]; const CAircraftSituation older = (*this)[2]; return this->front().extrapolateElevation(old, older, change); @@ -520,7 +521,7 @@ namespace BlackMisc return CAltitudePair(CAltitude(deltaFt.first, CAltitude::MeanSeaLevel, CAltitude::defaultUnit()), CAltitude(deltaFt.second, CAltitude::MeanSeaLevel, CAltitude::defaultUnit())); } - int CAircraftSituationList::transferElevationForward(const CLength radius) + 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"); @@ -533,5 +534,27 @@ namespace BlackMisc } return c; } + + CElevationPlane CAircraftSituationList::averageElevationOfNonMovingAircraft(const CAircraftSituation &reference, const CLength &range, int minValues) const + { + if (this->size() < minValues) { return CElevationPlane::null(); } // no change to succeed + + QList valuesInFt; + for (const CAircraftSituation &situation : *this) + { + if (situation.getGroundElevationInfo() != CAircraftSituation::FromProvider) { continue; } + const bool canUse = !situation.isMoving() || (situation.isOnGroundFromNetwork() || situation.isOnGroundFromParts()); + if (!canUse) { continue; } + if (!situation.isWithinRange(reference, range)) { continue; } + const double elvFt = situation.getGroundElevationPlane().getAltitude().value(CLengthUnit::ft()); + valuesInFt.push_back(elvFt); + } + if (valuesInFt.size() < minValues) { return CElevationPlane::null(); } + + static const double MaxDevFt = CAircraftSituationChange::allowedAltitudeDeviation().value(CLengthUnit::ft()); + const QPair elvStdDevMean = CMathUtils::standardDeviationAndMean(valuesInFt); + if (elvStdDevMean.first > MaxDevFt) { return CElevationPlane::null(); } + return CElevationPlane(reference, elvStdDevMean.second, CElevationPlane::singlePointRadius()); + } } // namespace } // namespace diff --git a/src/blackmisc/aviation/aircraftsituationlist.h b/src/blackmisc/aviation/aircraftsituationlist.h index b5b6bd275..a37bc8afe 100644 --- a/src/blackmisc/aviation/aircraftsituationlist.h +++ b/src/blackmisc/aviation/aircraftsituationlist.h @@ -69,7 +69,7 @@ namespace BlackMisc //! Extrapolate ground flag into the future int extrapolateGroundFlag(); - //! Extrapolates elevation into front element from 2nd and 3rd element + //! Extrapolates elevation into front (first) 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); @@ -190,7 +190,10 @@ namespace BlackMisc //! 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()); + int transferElevationForward(const PhysicalQuantities::CLength &radius = Geo::CElevationPlane::singlePointRadius()); + + //! Average elevation for "nearby" aircraft "not moving" and having an elevation + Geo::CElevationPlane averageElevationOfNonMovingAircraft(const CAircraftSituation &reference, const PhysicalQuantities::CLength &range, int minValues = 1) const; }; //! Situation per callsign diff --git a/src/blackmisc/geo/coordinategeodetic.cpp b/src/blackmisc/geo/coordinategeodetic.cpp index 67bb3ae52..d686dd2ec 100644 --- a/src/blackmisc/geo/coordinategeodetic.cpp +++ b/src/blackmisc/geo/coordinategeodetic.cpp @@ -38,16 +38,17 @@ namespace BlackMisc return CCoordinateGeodetic(lat, lon, geodeticHeight); } - PhysicalQuantities::CLength calculateGreatCircleDistance(const ICoordinateGeodetic &coordinate1, const ICoordinateGeodetic &coordinate2) + CLength calculateGreatCircleDistance(const ICoordinateGeodetic &coordinate1, const ICoordinateGeodetic &coordinate2) { + if (coordinate1.isNull() || coordinate2.isNull()) { return CLength::null(); } static const float earthRadiusMeters = 6371000.8f; const QVector3D v1 = coordinate1.normalVector(); const QVector3D v2 = coordinate2.normalVector(); const float d = earthRadiusMeters * std::atan2(QVector3D::crossProduct(v1, v2).length(), QVector3D::dotProduct(v1, v2)); - return { d, PhysicalQuantities::CLengthUnit::m() }; + return { d, CLengthUnit::m() }; } - PhysicalQuantities::CAngle calculateBearing(const ICoordinateGeodetic &coordinate1, const ICoordinateGeodetic &coordinate2) + CAngle calculateBearing(const ICoordinateGeodetic &coordinate1, const ICoordinateGeodetic &coordinate2) { static const QVector3D northPole { 0, 0, 1 }; const QVector3D c1 = QVector3D::crossProduct(coordinate1.normalVector(), coordinate2.normalVector()); @@ -56,7 +57,7 @@ namespace BlackMisc const float sinTheta = std::copysign(cross.length(), QVector3D::dotProduct(cross, coordinate1.normalVector())); const float cosTheta = QVector3D::dotProduct(c1, c2); const float theta = std::atan2(sinTheta, cosTheta); - return { theta, PhysicalQuantities::CAngleUnit::rad() }; + return { theta, CAngleUnit::rad() }; } double calculateEuclideanDistance(const ICoordinateGeodetic &coordinate1, const ICoordinateGeodetic &coordinate2) @@ -91,6 +92,14 @@ namespace BlackMisc return Geo::calculateGreatCircleDistance((*this), otherCoordinate); } + bool ICoordinateGeodetic::isWithinRange(const ICoordinateGeodetic &otherCoordinate, const CLength &range) const + { + if (range.isNull()) { return false; } + const CLength distance = calculateGreatCircleDistance(otherCoordinate); + if (distance.isNull()) { return false; } + return distance <= range; + } + CAngle ICoordinateGeodetic::calculateBearing(const ICoordinateGeodetic &otherCoordinate) const { return Geo::calculateBearing((*this), otherCoordinate); @@ -210,10 +219,10 @@ namespace BlackMisc {} CCoordinateGeodetic::CCoordinateGeodetic(double latitudeDegrees, double longitudeDegrees) : - CCoordinateGeodetic({ latitudeDegrees, PhysicalQuantities::CAngleUnit::deg() }, { longitudeDegrees, PhysicalQuantities::CAngleUnit::deg() }, { 0, nullptr }) {} + CCoordinateGeodetic({ latitudeDegrees, CAngleUnit::deg() }, { longitudeDegrees, CAngleUnit::deg() }, { 0, nullptr }) {} CCoordinateGeodetic::CCoordinateGeodetic(double latitudeDegrees, double longitudeDegrees, double heightFeet) : - CCoordinateGeodetic({ latitudeDegrees, PhysicalQuantities::CAngleUnit::deg() }, { longitudeDegrees, PhysicalQuantities::CAngleUnit::deg() }, { heightFeet, PhysicalQuantities::CLengthUnit::ft() }) {} + CCoordinateGeodetic({ latitudeDegrees, CAngleUnit::deg() }, { longitudeDegrees, CAngleUnit::deg() }, { heightFeet, CLengthUnit::ft() }) {} CCoordinateGeodetic::CCoordinateGeodetic(const ICoordinateGeodetic &coordinate) : m_geodeticHeight(coordinate.geodeticHeight()) @@ -223,13 +232,13 @@ namespace BlackMisc CLatitude CCoordinateGeodetic::latitude() const { - return { std::atan2(m_z, std::hypot(m_x, m_y)), PhysicalQuantities::CAngleUnit::rad() }; + return { std::atan2(m_z, std::hypot(m_x, m_y)), CAngleUnit::rad() }; } CLongitude CCoordinateGeodetic::longitude() const { // in mathematics atan2 of 0,0 is undefined, with IEEE floating-point atan2(0,0) is either 0 or ±180° - return { std::atan2(m_y, m_x), PhysicalQuantities::CAngleUnit::rad() }; + return { std::atan2(m_y, m_x), CAngleUnit::rad() }; } QVector3D CCoordinateGeodetic::normalVector() const diff --git a/src/blackmisc/geo/coordinategeodetic.h b/src/blackmisc/geo/coordinategeodetic.h index f07588a16..6391e772a 100644 --- a/src/blackmisc/geo/coordinategeodetic.h +++ b/src/blackmisc/geo/coordinategeodetic.h @@ -111,6 +111,9 @@ namespace BlackMisc //! Great circle distance PhysicalQuantities::CLength calculateGreatCircleDistance(const ICoordinateGeodetic &otherCoordinate) const; + //! Object within range? + bool isWithinRange(const ICoordinateGeodetic &otherCoordinate, const PhysicalQuantities::CLength &range) const; + //! Initial bearing PhysicalQuantities::CAngle calculateBearing(const ICoordinateGeodetic &otherCoordinate) const; diff --git a/src/blackmisc/simulation/remoteaircraftprovider.cpp b/src/blackmisc/simulation/remoteaircraftprovider.cpp index 159b7d4cc..17437f4e5 100644 --- a/src/blackmisc/simulation/remoteaircraftprovider.cpp +++ b/src/blackmisc/simulation/remoteaircraftprovider.cpp @@ -35,12 +35,11 @@ namespace BlackMisc CSimulatedAircraftList CRemoteAircraftProvider::getAircraftInRange() const { - QList aircraft; - { - QReadLocker l(&m_lockAircraft); - aircraft = m_aircraftInRange.values(); - } - return aircraft; + + QReadLocker l(&m_lockAircraft); + const QList aircraft = m_aircraftInRange.values(); + l.unlock(); + return CSimulatedAircraftList(aircraft); } CCallsignSet CRemoteAircraftProvider::getAircraftInRangeCallsigns() const @@ -71,6 +70,21 @@ namespace BlackMisc return m_situationsByCallsign[callsign]; } + CAircraftSituation CRemoteAircraftProvider::remoteAircraftSituation(const CCallsign &callsign, int index) const + { + CAircraftSituationList situations = this->remoteAircraftSituations(callsign); + if (index < 0 || index >= situations.size()) { return CAircraftSituation::null(); } + return situations[index]; + } + + CAircraftSituationList CRemoteAircraftProvider::latestRemoteAircraftSituations() const + { + QReadLocker l(&m_lockSituations); + const QList situations(m_latestSituationByCallsign.values()); + l.unlock(); + return CAircraftSituationList(situations); + } + int CRemoteAircraftProvider::remoteAircraftSituationsCount(const CCallsign &callsign) const { QReadLocker l(&m_lockSituations); @@ -147,6 +161,7 @@ namespace BlackMisc { QWriteLocker l(&m_lockSituations); m_situationsByCallsign.clear(); + m_latestSituationByCallsign.clear(); m_situationsAdded = 0; m_situationsLastModified.clear(); m_testOffset.clear(); @@ -244,6 +259,7 @@ namespace BlackMisc newSituationsList.setOnGroundDetails(situation.getOnGroundDetails()); } } + m_latestSituationByCallsign[cs] = situationCorrected; // check sort order if (CBuildConfig::isLocalDeveloperDebugBuild()) @@ -611,6 +627,12 @@ namespace BlackMisc return m_partsLastModified.value(callsign, -1); } + CElevationPlane CRemoteAircraftProvider::averageElevationOfNonMovingAircraft(const CAircraftSituation &reference, const CLength &range, int minValues) const + { + const CAircraftSituationList situations = this->latestRemoteAircraftSituations(); + return situations.averageElevationOfNonMovingAircraft(reference, range, minValues); + } + bool CRemoteAircraftProvider::testAddAltitudeOffset(const CCallsign &callsign, const CLength &offset) { const bool remove = offset.isNull() || offset.isZeroEpsilonConsidered(); @@ -670,7 +692,7 @@ namespace BlackMisc bool CRemoteAircraftProvider::removeAircraft(const CCallsign &callsign) { { QWriteLocker l1(&m_lockParts); m_partsByCallsign.remove(callsign); m_aircraftWithParts.remove(callsign); m_partsLastModified.remove(callsign); } - { QWriteLocker l2(&m_lockSituations); m_situationsByCallsign.remove(callsign); m_situationsLastModified.remove(callsign); } + { QWriteLocker l2(&m_lockSituations); m_situationsByCallsign.remove(callsign); m_latestSituationByCallsign.remove(callsign); m_situationsLastModified.remove(callsign); } { QWriteLocker l4(&m_lockPartsHistory); m_aircraftPartsMessages.remove(callsign); } bool removedCallsign = false; { @@ -735,6 +757,18 @@ namespace BlackMisc return this->provider()->remoteAircraftSituations(callsign); } + CAircraftSituation CRemoteAircraftAware::remoteAircraftSituation(const CCallsign &callsign, int index) const + { + Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available"); + return this->provider()->remoteAircraftSituation(callsign, index); + } + + CAircraftSituationList CRemoteAircraftAware::latestRemoteAircraftSituations() const + { + Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available"); + return this->provider()->latestRemoteAircraftSituations(); + } + CAircraftSituationChangeList CRemoteAircraftAware::remoteAircraftSituationChanges(const CCallsign &callsign) const { Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available"); @@ -819,6 +853,12 @@ namespace BlackMisc return this->provider()->partsLastModified(callsign); } + CElevationPlane CRemoteAircraftAware::averageElevationOfNonMovingAircraft(const CAircraftSituation &reference, const CLength &range, int minValues) const + { + Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available"); + return this->provider()->averageElevationOfNonMovingAircraft(reference, range, minValues); + } + bool CRemoteAircraftAware::isRemoteAircraftSupportingParts(const CCallsign &callsign) const { Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available"); diff --git a/src/blackmisc/simulation/remoteaircraftprovider.h b/src/blackmisc/simulation/remoteaircraftprovider.h index 4eeacb82b..2b23611d1 100644 --- a/src/blackmisc/simulation/remoteaircraftprovider.h +++ b/src/blackmisc/simulation/remoteaircraftprovider.h @@ -51,6 +51,9 @@ namespace BlackMisc static constexpr int MaxPartsAgePerCallsignSecs = 60; //!< How many seconds to keep parts for interpolation static constexpr int DefaultOffsetTimeMs = 6000; //!< \fixme copied from CNetworkVatlib::c_positionTimeOffsetMsec + //! Destructor + virtual ~IRemoteAircraftProvider() {} + //! All remote aircraft //! \threadsafe virtual CSimulatedAircraftList getAircraftInRange() const = 0; @@ -87,6 +90,17 @@ namespace BlackMisc //! \threadsafe virtual Aviation::CAircraftSituationList remoteAircraftSituations(const Aviation::CCallsign &callsign) const = 0; + //! Rendered aircraft situations (per callsign and index) + //! \remark if situation does not exist, an NULL situation is returned + //! \param callsign + //! \param index 0..latest, 1..next older, ... + //! \threadsafe + virtual Aviation::CAircraftSituation remoteAircraftSituation(const Aviation::CCallsign &callsign, int index) const = 0; + + //! Latest aircraft situation for all callsigns + //! \threadsafe + virtual Aviation::CAircraftSituationList latestRemoteAircraftSituations() const = 0; + //! Number of remote aircraft situations for callsign //! \remark latest situations first //! \threadsafe @@ -197,8 +211,9 @@ namespace BlackMisc //! \threadsafe virtual qint64 partsLastModified(const Aviation::CCallsign &callsign) const = 0; - //! Destructor - virtual ~IRemoteAircraftProvider() {} + //! \copydoc BlackMisc::Aviation::CAircraftSituationList::averageElevationOfNonMovingAircraft + //! \threadsafe + virtual Geo::CElevationPlane averageElevationOfNonMovingAircraft(const Aviation::CAircraftSituation &reference, const PhysicalQuantities::CLength &range, int minValues = 1) const = 0; //! Connect signals to slot receiver. As the interface is no QObject, slots can not be connected directly. //! In order to disconnect a list of connections is provided, which have to be disconnected manually. @@ -249,6 +264,8 @@ namespace BlackMisc virtual bool isAircraftInRange(const Aviation::CCallsign &callsign) const override; virtual bool isVtolAircraft(const Aviation::CCallsign &callsign) const override; virtual Aviation::CAircraftSituationList remoteAircraftSituations(const Aviation::CCallsign &callsign) const override; + virtual Aviation::CAircraftSituation remoteAircraftSituation(const Aviation::CCallsign &callsign, int index) const override; + virtual Aviation::CAircraftSituationList latestRemoteAircraftSituations() const override; virtual int remoteAircraftSituationsCount(const Aviation::CCallsign &callsign) const override; virtual Aviation::CAircraftPartsList remoteAircraftParts(const Aviation::CCallsign &callsign) const override; virtual int remoteAircraftPartsCount(const Aviation::CCallsign &callsign) const override; @@ -272,6 +289,7 @@ namespace BlackMisc virtual int aircraftPartsAdded() const override; virtual qint64 situationsLastModified(const Aviation::CCallsign &callsign) const override; virtual qint64 partsLastModified(const Aviation::CCallsign &callsign) const override; + virtual Geo::CElevationPlane averageElevationOfNonMovingAircraft(const Aviation::CAircraftSituation &reference, const PhysicalQuantities::CLength &range, int minValues = 1) const override; virtual QList connectRemoteAircraftProviderSignals( QObject *receiver, std::function addedSituationSlot, @@ -388,8 +406,9 @@ namespace BlackMisc //! \threadsafe void storeChange(const Aviation::CAircraftSituationChange &change); - Aviation::CAircraftSituationListPerCallsign m_situationsByCallsign; //!< situations, for performance reasons per callsign, thread safe access required - Aviation::CAircraftPartsListPerCallsign m_partsByCallsign; //!< parts, for performance reasons per callsign, thread safe access required + Aviation::CAircraftSituationListPerCallsign m_situationsByCallsign; //!< situations, for performance reasons per callsign, thread safe access required + Aviation::CAircraftSituationPerCallsign m_latestSituationByCallsign; //!< latest situations, for performance reasons per callsign, thread safe access required + Aviation::CAircraftPartsListPerCallsign m_partsByCallsign; //!< parts, for performance reasons per callsign, thread safe access required Aviation::CAircraftSituationChangeListPerCallsign m_changesByCallsign; //!< changes, for performance reasons per callsign, thread safe access required Aviation::CCallsignSet m_aircraftWithParts; //!< aircraft supporting parts, thread safe access required int m_situationsAdded = 0; //!< total number of situations added, thread safe access required @@ -445,6 +464,12 @@ namespace BlackMisc //! \copydoc IRemoteAircraftProvider::remoteAircraftSituations Aviation::CAircraftSituationList remoteAircraftSituations(const Aviation::CCallsign &callsign) const; + //! \copydoc IRemoteAircraftProvider::remoteAircraftSituation + Aviation::CAircraftSituation remoteAircraftSituation(const Aviation::CCallsign &callsign, int index) const; + + //! \copydoc IRemoteAircraftProvider::latestRemoteAircraftSituations + Aviation::CAircraftSituationList latestRemoteAircraftSituations() const; + //! \copydoc IRemoteAircraftProvider::remoteAircraftSituationsCount int remoteAircraftSituationsCount(const Aviation::CCallsign &callsign) const; @@ -496,6 +521,9 @@ namespace BlackMisc //! \copydoc IRemoteAircraftProvider::partsLastModified qint64 partsLastModified(const Aviation::CCallsign &callsign) const; + //! \copydoc IRemoteAircraftProvider::averageElevationOfNonMovingAircraft + Geo::CElevationPlane averageElevationOfNonMovingAircraft(const Aviation::CAircraftSituation &reference, const PhysicalQuantities::CLength &range, int minValues = 1) const; + //! Set remote aircraft provider void setRemoteAircraftProvider(IRemoteAircraftProvider *remoteAircraftProvider) { this->setProvider(remoteAircraftProvider); }