Ref T259, Ref T243 use elevation plane for altitude

general idea: by using the plane class, we can set a elevation and then find a better one

* use elevation plane in situation
* adjusted depending classes such as hints, lists
* using setGroundElevationChecked so elevation can be gradually improved
This commit is contained in:
Klaus Basan
2018-03-07 01:53:10 +01:00
parent 0c877e1575
commit 83b6578e69
16 changed files with 307 additions and 110 deletions

View File

@@ -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);
}

View File

@@ -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 <QtGlobal>
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 &centerOfGravity, bool *corrected) const
CAltitude CAircraftSituation::getCorrectedAltitude(const CLength &centerOfGravity, 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<qint64>::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<qint64>::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

View File

@@ -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<CAircraftSituation>,
@@ -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<int>(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<CAircraftSituation::OnGroundDetails>(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<int>(onGroundReliability); }
//! On ground details
void setOnGroundDetails(CAircraftSituation::OnGroundDetails details) { m_onGroundDetails = static_cast<int>(details); }
//! On ground info as string
QString getOnGroundInfo() const;
@@ -179,19 +186,29 @@ namespace BlackMisc
virtual std::array<double, 3> 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 &centerOfGravity = {}, bool *corrected = nullptr) const;
CAltitude getCorrectedAltitude(const PhysicalQuantities::CLength &centerOfGravity = {}, 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<int>(CAircraftSituation::OnGroundSituationUnknown);
int m_onGroundDetails = static_cast<int>(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),

View File

@@ -30,29 +30,52 @@ namespace BlackMisc
CSequence<CAircraftSituation>(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

View File

@@ -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<CAircraftSituation>,
public Geo::IGeoObjectList<CAircraftSituation, CAircraftSituationList>,
public ITimestampWithOffsetObjectList<CAircraftSituation, CAircraftSituationList>,
public ICallsignObjectList<CAircraftSituation, CAircraftSituationList>,
public Mixin::MetaType<CAircraftSituationList>
@@ -50,10 +52,16 @@ namespace BlackMisc
CAircraftSituationList(std::initializer_list<CAircraftSituation> 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

View File

@@ -89,15 +89,16 @@ namespace BlackMisc
const ColumnIndex i = index.frontCasted<ColumnIndex>();
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

View File

@@ -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<CElevationPlane, CCoordinateGeodetic>
{
@@ -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

View File

@@ -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);
}

View File

@@ -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<Aviation::CAltitude(const Aviation::CAircraftSituation &)>;
//! 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

View File

@@ -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 <typename Derived>
void CInterpolator<Derived>::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 <typename Derived>
void CInterpolator<Derived>::setGroundFlagFromInterpolator(const CInterpolationHints &hints, double groundFactor, CAircraftSituation &situation)
{

View File

@@ -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);

View File

@@ -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

View File

@@ -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(); }

View File

@@ -20,8 +20,8 @@
#include <QString>
#include <tuple>
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))

View File

@@ -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 <QMetaType>
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

View File

@@ -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;