refactor: Move OnGround information to own class

This commit is contained in:
Lars Toenning
2024-01-08 22:53:45 +01:00
parent 8b44d3fd4e
commit a27c2b3f51
27 changed files with 452 additions and 366 deletions

View File

@@ -1584,13 +1584,13 @@ namespace BlackCore
while (false); // do we need elevation, find on
// do we already have ground details?
if (situation.getOnGroundDetails() == CAircraftSituation::NotSetGroundDetails)
if (situation.getOnGroundInfo().getGroundDetails() == COnGroundInfo::NotSetGroundDetails)
{
const CClient client = this->getClientOrDefaultForCallsign(callsign);
if (client.hasCapability(CClient::FsdWithGroundFlag))
{
// we rely on situation gnd.flag
correctedSituation.setOnGroundDetails(CAircraftSituation::InFromNetwork);
correctedSituation.setOnGroundDetails(COnGroundInfo::InFromNetwork);
}
else if (client.hasCapability(CClient::FsdWithAircraftConfig))
{

View File

@@ -1241,7 +1241,8 @@ namespace BlackCore::Fsd
CAngle(dataUpdate.m_bank, CAngleUnit::deg()),
CSpeed(dataUpdate.m_groundSpeed, CSpeedUnit::kts()));
situation.setPressureAltitude(CAltitude(dataUpdate.m_altitudePressure, CAltitude::MeanSeaLevel, CAltitude::PressureAltitude, CLengthUnit::ft()));
situation.setOnGround(dataUpdate.m_onGround);
const COnGroundInfo og(dataUpdate.m_onGround ? COnGroundInfo::OnGround : COnGroundInfo::NotOnGround, COnGroundInfo::InFromNetwork);
situation.setOnGroundInfo(og);
// Ref T297, default offset time
situation.setCurrentUtcTime();
@@ -1279,8 +1280,8 @@ namespace BlackCore::Fsd
CAngle(-data.m_pitch, CAngleUnit::deg()),
CAngle(-data.m_bank, CAngleUnit::deg()),
CSpeed(data.m_groundSpeed, CSpeedUnit::kts()));
situation.setOnGround(data.m_onGround);
situation.setOnGroundDetails(CAircraftSituation::InFromNetwork);
const COnGroundInfo og(data.m_onGround ? COnGroundInfo::OnGround : COnGroundInfo::NotOnGround, COnGroundInfo::InFromNetwork);
situation.setOnGroundInfo(og);
// Ref T297, default offset time
situation.setCurrentUtcTime();
@@ -1771,7 +1772,8 @@ namespace BlackCore::Fsd
CAngle(interimPilotDataUpdate.m_pitch, CAngleUnit::deg()),
CAngle(interimPilotDataUpdate.m_bank, CAngleUnit::deg()),
CSpeed(interimPilotDataUpdate.m_groundSpeed, CSpeedUnit::kts()));
situation.setOnGround(interimPilotDataUpdate.m_onGround);
const COnGroundInfo og(interimPilotDataUpdate.m_onGround ? COnGroundInfo::OnGround : COnGroundInfo::NotOnGround, COnGroundInfo::InFromNetwork);
situation.setOnGroundInfo(og);
// Ref T297, default offset time
situation.setCurrentUtcTime();

View File

@@ -28,8 +28,6 @@ namespace BlackGui::Models
m_columns.addColumn(CColumn("longitude", CAircraftSituation::IndexLongitude, new CLatLonFormatter()));
m_columns.addColumn(CColumn("gs.", CAircraftSituation::IndexGroundSpeed, new CSpeedKtsFormatter()));
m_columns.addColumn(CColumn::standardString("PBH", "pitch bank heading", CAircraftSituation::IndexPBHInfo));
m_columns.addColumn(CColumn("on gnd.", "is on gnd.", CAircraftSituation::IndexIsOnGround, new CBoolIconFormatter("yes", "no"), true));
m_columns.addColumn(CColumn::standardString("reliability", CAircraftSituation::IndexOnGroundReliabilityString));
m_columns.addColumn(CColumn::standardString("gnd.elv.", CAircraftSituation::IndexGroundElevationPlusInfo));
m_columns.addColumn(CColumn::standardString("gnd.elv.alt.", { CAircraftSituation::IndexGroundElevationPlane, CElevationPlane::IndexGeodeticHeightAsString }));
m_columns.addColumn(CColumn("elv.radius", { CAircraftSituation::IndexGroundElevationPlane, CElevationPlane::IndexRadius }, new CPhysiqalQuantiyFormatter<CLengthUnit, CLength>(CLengthUnit::m(), 1)));

View File

@@ -90,6 +90,8 @@ add_library(misc SHARED
aviation/modulator.h
aviation/navsystem.h
aviation/percallsign.h
aviation/ongroundinfo.cpp
aviation/ongroundinfo.h
aviation/registermetadataaviation.cpp
aviation/registermetadataaviation.h
aviation/selcal.cpp

View File

@@ -34,7 +34,7 @@ namespace BlackMisc::Aviation
CAircraftLights CAircraftSituation::guessLights() const
{
const bool isOnGround = getOnGround() == CAircraftSituation::OnGround;
const bool isOnGround = this->isOnGround();
const double gsKts = getGroundSpeed().value(CSpeedUnit::kts());
CAircraftLights lights;
lights.setCabinOn(true);
@@ -81,8 +81,6 @@ namespace BlackMisc::Aviation
void CAircraftSituation::registerMetadata()
{
CValueObject<CAircraftSituation>::registerMetadata();
qRegisterMetaType<CAircraftSituation::IsOnGround>();
qRegisterMetaType<CAircraftSituation::OnGroundDetails>();
qRegisterMetaType<CAircraftSituation::AltitudeCorrection>();
qRegisterMetaType<CAircraftSituation::GndElevationInfo>();
}
@@ -116,12 +114,11 @@ namespace BlackMisc::Aviation
u" | " % m_position.toQString(i18n) %
u" | alt: " % this->getAltitude().valueRoundedWithUnit(CLengthUnit::ft(), 1) %
u' ' % this->getCorrectedAltitude().valueRoundedWithUnit(CLengthUnit::ft(), 1) %
u"[cor] | og: " % this->getOnGroundInfo() %
u"[cor] | og: " % this->getOnGroundInfo().toQString(i18n) %
u" | CG: " %
(m_cg.isNull() ? QStringLiteral("null") : m_cg.valueRoundedWithUnit(CLengthUnit::m(), 1) % u' ' % m_cg.valueRoundedWithUnit(CLengthUnit::ft(), 1)) %
u" | offset: " %
(m_sceneryOffset.isNull() ? QStringLiteral("null") : m_sceneryOffset.valueRoundedWithUnit(CLengthUnit::m(), 1) % u' ' % m_sceneryOffset.valueRoundedWithUnit(CLengthUnit::ft(), 1)) %
u" | factor [0..1]: " % QString::number(m_onGroundFactor, 'f', 2) %
u" | skip ng: " % boolToYesNo(this->canLikelySkipNearGroundInterpolation()) %
u" | bank: " % m_bank.toQString(i18n) %
u" | pitch: " % m_pitch.toQString(i18n) %
@@ -131,44 +128,6 @@ namespace BlackMisc::Aviation
u" | elevation [" % this->getGroundElevationInfoAsString() % u"]: " % (m_groundElevationPlane.toQString(i18n));
}
const QString &CAircraftSituation::isOnGroundToString(CAircraftSituation::IsOnGround onGround)
{
static const QString notog("not on ground");
static const QString og("on ground");
static const QString unknown("unknown");
switch (onGround)
{
case CAircraftSituation::NotOnGround: return notog;
case CAircraftSituation::OnGround: return og;
case CAircraftSituation::OnGroundSituationUnknown:
default: return unknown;
}
}
const QString &CAircraftSituation::onGroundDetailsToString(CAircraftSituation::OnGroundDetails reliability)
{
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");
switch (reliability)
{
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::NotSetGroundDetails:
default: return unknown;
}
}
const QString &CAircraftSituation::altitudeCorrectionToString(CAircraftSituation::AltitudeCorrection correction)
{
static const QString under("underflow");
@@ -315,10 +274,7 @@ namespace BlackMisc::Aviation
case IndexGroundSpeed: return m_groundSpeed.propertyByIndex(index.copyFrontRemoved());
case IndexGroundElevationPlane: return m_groundElevationPlane.propertyByIndex(index.copyFrontRemoved());
case IndexCallsign: return m_correspondingCallsign.propertyByIndex(index.copyFrontRemoved());
case IndexIsOnGround: return QVariant::fromValue(m_onGround);
case IndexIsOnGroundString: return QVariant::fromValue(this->onGroundAsString());
case IndexOnGroundReliability: return QVariant::fromValue(m_onGroundDetails);
case IndexOnGroundReliabilityString: return QVariant::fromValue(this->getOnGroundDetailsAsString());
case IndexIsOnGroundInfo: return m_onGroundInfo.propertyByIndex(index.copyFrontRemoved());
case IndexGroundElevationInfo: return QVariant::fromValue(this->getGroundElevationInfo());
case IndexGroundElevationInfoTransferred: return QVariant::fromValue(this->isGroundElevationInfoTransferred());
case IndexGroundElevationInfoString: return QVariant::fromValue(this->getGroundElevationInfoAsString());
@@ -353,8 +309,7 @@ namespace BlackMisc::Aviation
case IndexGroundSpeed: m_groundSpeed.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_onGround = variant.toInt(); break;
case IndexOnGroundReliability: m_onGroundDetails = variant.toInt(); break;
case IndexIsOnGroundInfo: m_onGroundInfo.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
case IndexGroundElevationInfo: m_elvInfo = variant.toInt(); break;
case IndexGroundElevationInfoTransferred: m_isElvInfoTransferred = variant.toBool(); break;
case IndexGroundElevationPlusInfo: break;
@@ -387,12 +342,7 @@ namespace BlackMisc::Aviation
return Compare::compare(this->getGroundElevationInfo(), compareValue.getGroundElevationInfo());
}
case IndexCallsign: return m_correspondingCallsign.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getCallsign());
case IndexIsOnGround:
case IndexIsOnGroundString:
return Compare::compare(m_onGround, compareValue.m_onGround);
case IndexOnGroundReliability:
case IndexOnGroundReliabilityString:
return Compare::compare(m_onGroundDetails, compareValue.m_onGroundDetails);
case IndexIsOnGroundInfo: return m_onGroundInfo.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getOnGroundInfo());
case IndexGroundElevationInfo:
case IndexGroundElevationInfoString:
{
@@ -461,7 +411,7 @@ namespace BlackMisc::Aviation
m_velocity = {};
m_groundElevationPlane.setNull();
m_groundSpeed.setNull();
m_onGroundDetails = CAircraftSituation::NotSetGroundDetails;
m_onGroundInfo = {};
m_elvInfo = NoElevationInfo;
m_isElvInfoTransferred = false;
m_cg.setNull();
@@ -470,63 +420,19 @@ namespace BlackMisc::Aviation
bool CAircraftSituation::isOnGroundFromParts() const
{
return this->isOnGround() && this->getOnGroundDetails() == InFromParts;
return this->isOnGround() && m_onGroundInfo.getGroundDetails() == COnGroundInfo::InFromParts;
}
bool CAircraftSituation::isOnGroundFromNetwork() const
{
return this->isOnGround() && this->getOnGroundDetails() == InFromNetwork;
}
const QString &CAircraftSituation::onGroundAsString() const
{
return CAircraftSituation::isOnGroundToString(this->getOnGround());
return this->isOnGround() && m_onGroundInfo.getGroundDetails() == COnGroundInfo::InFromNetwork;
}
bool CAircraftSituation::isOnGroundInfoAvailable() const
{
if (this->hasInboundGroundDetails()) { return true; }
return this->getOnGround() != CAircraftSituation::OnGroundSituationUnknown &&
this->getOnGroundDetails() != CAircraftSituation::NotSetGroundDetails;
}
bool CAircraftSituation::setOnGround(bool onGround)
{
return this->setOnGround(onGround ? OnGround : NotOnGround);
}
bool CAircraftSituation::setOnGround(CAircraftSituation::IsOnGround onGround)
{
if (this->getOnGround() == onGround) { return false; }
const int og = static_cast<int>(onGround);
m_onGround = og;
m_onGroundFactor = (onGround == OnGround) ? 1.0 : 0.0;
return true;
}
bool CAircraftSituation::setOnGround(CAircraftSituation::IsOnGround onGround, CAircraftSituation::OnGroundDetails details)
{
const bool set = this->setOnGround(onGround);
this->setOnGroundDetails(details);
return set;
}
void CAircraftSituation::setOnGroundFactor(double groundFactor)
{
if (groundFactor < 0.0)
{
groundFactor = -1.0;
}
else if (groundFactor < 0.001)
{
groundFactor = 0.0;
}
else if (groundFactor > 0.999)
{
groundFactor = 1.0;
}
m_onGroundFactor = groundFactor;
return m_onGroundInfo.getOnGround() != COnGroundInfo::OnGroundSituationUnknown &&
m_onGroundInfo.getGroundDetails() != COnGroundInfo::NotSetGroundDetails;
}
bool CAircraftSituation::shouldGuessOnGround() const
@@ -544,39 +450,22 @@ namespace BlackMisc::Aviation
bool CAircraftSituation::hasGroundDetailsForGndInterpolation() const
{
return this->getOnGroundDetails() != CAircraftSituation::NotSetGroundDetails;
return m_onGroundInfo.getGroundDetails() != COnGroundInfo::NotSetGroundDetails;
}
const QString &CAircraftSituation::getOnGroundDetailsAsString() const
COnGroundInfo CAircraftSituation::getOnGroundInfo() const
{
return CAircraftSituation::onGroundDetailsToString(this->getOnGroundDetails());
return m_onGroundInfo;
}
bool CAircraftSituation::setOnGroundDetails(CAircraftSituation::OnGroundDetails details)
void CAircraftSituation::setOnGroundDetails(COnGroundInfo::OnGroundDetails details)
{
if (this->getOnGroundDetails() == details) { return false; }
m_onGroundDetails = static_cast<int>(details);
return true;
m_onGroundInfo.setOnGroundDetails(details);
}
bool CAircraftSituation::setOnGroundFromGroundFactorFromInterpolation(double threshold)
void CAircraftSituation::setOnGroundInfo(const Aviation::COnGroundInfo &info)
{
this->setOnGroundDetails(OnGroundByInterpolation);
if (this->getOnGroundFactor() < 0.0)
{
this->setOnGround(NotSetGroundDetails);
return false;
}
// set on ground but leave factor untouched
const bool og = this->getOnGroundFactor() > threshold; // 1.0 means on ground
m_onGround = og ? OnGround : NotOnGround;
return true;
}
QString CAircraftSituation::getOnGroundInfo() const
{
return this->onGroundAsString() % u' ' % this->getOnGroundDetailsAsString();
m_onGroundInfo = info;
}
CAircraftSituation::GndElevationInfo CAircraftSituation::getGroundElevationInfo() const
@@ -640,21 +529,6 @@ namespace BlackMisc::Aviation
return true;
}
CAircraftSituation::IsOnGround CAircraftSituation::isOnGroundByElevation(const CLength &cg) const
{
const CLength groundDistance = this->getGroundDistance(cg);
if (groundDistance.isNull()) { return OnGroundSituationUnknown; }
if (groundDistance.isNegativeWithEpsilonConsidered()) { return OnGround; }
if (groundDistance.abs() < deltaNearGround()) { return OnGround; }
if (!cg.isNull())
{
// smaller than percentage from CG
const CLength cgFactor(cg * 0.1);
if (groundDistance.abs() < cgFactor.abs()) { return OnGround; }
}
return NotOnGround;
}
bool CAircraftSituation::hasGroundElevation() const
{
return !this->getGroundElevation().isNull();
@@ -662,7 +536,7 @@ namespace BlackMisc::Aviation
bool CAircraftSituation::hasInboundGroundDetails() const
{
return this->getOnGroundDetails() == CAircraftSituation::InFromParts || this->getOnGroundDetails() == CAircraftSituation::InFromNetwork;
return m_onGroundInfo.getGroundDetails() == COnGroundInfo::InFromParts || m_onGroundInfo.getGroundDetails() == COnGroundInfo::InFromNetwork;
}
bool CAircraftSituation::setGroundElevation(const CAltitude &altitude, GndElevationInfo info, bool transferred)
@@ -810,7 +684,7 @@ namespace BlackMisc::Aviation
if (correction) { *correction = NoCorrection; }
return groundPlusCG;
}
const bool forceDragToGround = (enableDragToGround && this->getOnGround() == OnGround) && (this->hasInboundGroundDetails() || this->getOnGroundDetails() == OnGroundByGuessing);
const bool forceDragToGround = (enableDragToGround && isOnGround()) && (this->hasInboundGroundDetails() || m_onGroundInfo.getGroundDetails() == COnGroundInfo::OnGroundByGuessing);
if (forceDragToGround)
{
if (correction) { *correction = DraggedToGround; }
@@ -971,14 +845,14 @@ namespace BlackMisc::Aviation
static const qint64 Max = std::numeric_limits<qint64>::max();
if (differenceMs) { *differenceMs = Max; }
if (this->getOnGroundDetails() == CAircraftSituation::InFromNetwork) { return false; }
if (alwaysSetDetails) { this->setOnGroundDetails(InFromParts); }
if (m_onGroundInfo.getGroundDetails() == COnGroundInfo::InFromNetwork) { return false; }
if (alwaysSetDetails) { m_onGroundInfo.setOnGroundDetails(COnGroundInfo::InFromParts); }
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);
m_onGroundInfo = COnGroundInfo(parts.isOnGround() ? COnGroundInfo::OnGround : COnGroundInfo::NotOnGround, COnGroundInfo::InFromParts);
return true;
}
@@ -988,8 +862,8 @@ namespace BlackMisc::Aviation
static const qint64 Max = std::numeric_limits<qint64>::max();
if (differenceMs) { *differenceMs = Max; }
if (this->getOnGroundDetails() == CAircraftSituation::InFromNetwork) { return false; }
if (alwaysSetDetails) { this->setOnGroundDetails(InFromParts); }
if (m_onGroundInfo.getGroundDetails() == COnGroundInfo::InFromNetwork) { return false; }
if (alwaysSetDetails) { m_onGroundInfo.setOnGroundDetails(COnGroundInfo::InFromParts); }
if (partsList.isEmpty()) { return false; }
CAircraftParts bestParts;
@@ -1009,8 +883,8 @@ namespace BlackMisc::Aviation
}
if (!adjust) { return false; }
const CAircraftSituation::IsOnGround og = bestParts.isOnGround() ? CAircraftSituation::OnGround : CAircraftSituation::NotOnGround;
this->setOnGround(og, CAircraftSituation::InFromParts);
const COnGroundInfo::IsOnGround og = bestParts.isOnGround() ? COnGroundInfo::OnGround : COnGroundInfo::NotOnGround;
m_onGroundInfo = COnGroundInfo(og, COnGroundInfo::InFromParts);
return true;
}
} // namespace

View File

@@ -8,6 +8,7 @@
#include "blackmisc/aviation/altitude.h"
#include "blackmisc/aviation/callsign.h"
#include "blackmisc/aviation/ongroundinfo.h"
#include "blackmisc/aviation/heading.h"
#include "blackmisc/aviation/aircraftvelocity.h"
#include "blackmisc/blackmiscexport.h"
@@ -60,10 +61,7 @@ namespace BlackMisc
IndexAltitude,
IndexHeading,
IndexBank,
IndexIsOnGround,
IndexIsOnGroundString,
IndexOnGroundReliability,
IndexOnGroundReliabilityString,
IndexIsOnGroundInfo,
IndexPitch,
IndexPBHInfo,
IndexVelocity,
@@ -79,29 +77,6 @@ namespace BlackMisc
IndexCanLikelySkipNearGroundInterpolation
};
//! Is on ground?
enum IsOnGround
{
NotOnGround,
OnGround,
OnGroundSituationUnknown
};
//! Reliability of on ground information
enum OnGroundDetails
{
NotSetGroundDetails,
// interpolated situation
OnGroundByInterpolation, //!< strongest for remote aircraft
OnGroundByElevationAndCG,
OnGroundByGuessing, //!< weakest
// received situation
InFromNetwork, //!< received from network
InFromParts, //!< set from aircraft parts
// send information
OutOnGroundOwnAircraft //!< sending on ground
};
//! How was altitude corrected?
enum AltitudeCorrection
{
@@ -205,11 +180,8 @@ namespace BlackMisc
//! \copydoc Geo::ICoordinateGeodetic::longitude()
virtual Geo::CLongitude longitude() const override { return m_position.longitude(); }
//! On ground?
IsOnGround getOnGround() const { return static_cast<CAircraftSituation::IsOnGround>(m_onGround); }
//! Is on ground?
bool isOnGround() const { return this->getOnGround() == OnGround; }
bool isOnGround() const { return m_onGroundInfo.getOnGround() == COnGroundInfo::OnGround; }
//! On ground by parts?
bool isOnGroundFromParts() const;
@@ -217,50 +189,26 @@ namespace BlackMisc
//! On ground by network flag?
bool isOnGroundFromNetwork() const;
//! On ground?
const QString &onGroundAsString() const;
//! On ground info available?
bool isOnGroundInfoAvailable() const;
//! Set on ground
bool setOnGround(bool onGround);
//! Set on ground
bool setOnGround(CAircraftSituation::IsOnGround onGround);
//! Set on ground
bool setOnGround(CAircraftSituation::IsOnGround onGround, CAircraftSituation::OnGroundDetails details);
//! On ground factor 0..1 (on ground), -1 not set
double getOnGroundFactor() const { return m_onGroundFactor; }
//! Set on ground factor 0..1 (on ground), -1 not set
void setOnGroundFactor(double groundFactor);
//! Should we guess on ground?
bool shouldGuessOnGround() const;
//! Distance to ground, null if impossible to calculate
PhysicalQuantities::CLength getGroundDistance(const PhysicalQuantities::CLength &centerOfGravity) const;
//! On ground reliability
OnGroundDetails getOnGroundDetails() const { return static_cast<CAircraftSituation::OnGroundDetails>(m_onGroundDetails); }
//! Do the ground details permit ground interpolation?
bool hasGroundDetailsForGndInterpolation() const;
//! On ground reliability as string
const QString &getOnGroundDetailsAsString() const;
//! On ground details
bool setOnGroundDetails(CAircraftSituation::OnGroundDetails details);
void setOnGroundDetails(COnGroundInfo::OnGroundDetails details);
//! Set on ground as interpolated from ground fatcor
bool setOnGroundFromGroundFactorFromInterpolation(double threshold = 0.5);
//! On ground info
Aviation::COnGroundInfo getOnGroundInfo() const;
//! On ground info as string
QString getOnGroundInfo() const;
//! Set the on ground info
void setOnGroundInfo(const Aviation::COnGroundInfo &info);
//! \copydoc Geo::ICoordinateGeodetic::geodeticHeight
const CAltitude &geodeticHeight() const override { return m_position.geodeticHeight(); }
@@ -313,11 +261,6 @@ namespace BlackMisc
//! \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 PhysicalQuantities::CLength &cg) const;
//! @}
//! Is ground elevation value available
bool hasGroundElevation() const;
@@ -482,12 +425,6 @@ namespace BlackMisc
//! Get flag indicating this is an interim position update
bool isInterim() const { return m_isInterim; }
//! Enum to string
static const QString &isOnGroundToString(IsOnGround onGround);
//! Enum to string
static const QString &onGroundDetailsToString(OnGroundDetails reliability);
//! Enum to string
static const QString &altitudeCorrectionToString(AltitudeCorrection correction);
@@ -569,10 +506,8 @@ namespace BlackMisc
CAircraftVelocity m_velocity;
bool m_isInterim = false; //!< interim situation?
bool m_isElvInfoTransferred = false; //!< the gnd.elevation has been transferred
int m_onGround = static_cast<int>(CAircraftSituation::OnGroundSituationUnknown);
int m_onGroundDetails = static_cast<int>(CAircraftSituation::NotSetGroundDetails);
int m_elvInfo = static_cast<int>(CAircraftSituation::NoElevationInfo); //!< where did we gnd.elevation from?
double m_onGroundFactor = -1; //!< interpolated ground flag, 1..on ground, 0..not on ground, -1 no info
Aviation::COnGroundInfo m_onGroundInfo;
BLACK_METACLASS(
CAircraftSituation,
@@ -588,11 +523,9 @@ namespace BlackMisc
BLACK_METAMEMBER(hasVelocity),
BLACK_METAMEMBER(velocity),
BLACK_METAMEMBER(groundElevationPlane),
BLACK_METAMEMBER(onGround),
BLACK_METAMEMBER(onGroundDetails),
BLACK_METAMEMBER(onGroundInfo),
BLACK_METAMEMBER(elvInfo),
BLACK_METAMEMBER(isElvInfoTransferred),
BLACK_METAMEMBER(onGroundFactor),
BLACK_METAMEMBER(timestampMSecsSinceEpoch),
BLACK_METAMEMBER(timeOffsetMs),
BLACK_METAMEMBER(isInterim)
@@ -602,8 +535,6 @@ namespace BlackMisc
} // namespace
Q_DECLARE_METATYPE(BlackMisc::Aviation::CAircraftSituation)
Q_DECLARE_METATYPE(BlackMisc::Aviation::CAircraftSituation::IsOnGround)
Q_DECLARE_METATYPE(BlackMisc::Aviation::CAircraftSituation::OnGroundDetails)
Q_DECLARE_METATYPE(BlackMisc::Aviation::CAircraftSituation::AltitudeCorrection)
Q_DECLARE_METATYPE(BlackMisc::Aviation::CAircraftSituation::GndElevationInfo)

View File

@@ -94,21 +94,21 @@ namespace BlackMisc::Aviation
{
if (situation.getGroundSpeed().isNegativeWithEpsilonConsidered())
{
situation.setOnGround(CAircraftSituation::OnGround, CAircraftSituation::OnGroundByGuessing);
situation.setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::OnGroundByGuessing });
if (details) { *details = QStringLiteral("No VTOL, push back"); }
return true;
}
if (!situation.isMoving())
{
situation.setOnGround(CAircraftSituation::OnGround, CAircraftSituation::OnGroundByGuessing);
situation.setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::OnGroundByGuessing });
if (details) { *details = QStringLiteral("No VTOL, not moving => on ground"); }
return true;
}
}
// not on ground is default
situation.setOnGround(CAircraftSituation::NotOnGround, CAircraftSituation::OnGroundByGuessing);
situation.setOnGroundInfo({ COnGroundInfo::NotOnGround, COnGroundInfo::OnGroundByGuessing });
CLength cg = situation.hasCG() ? situation.getCG() : model.getCG();
CSpeed guessedRotateSpeed = CSpeed::null();
@@ -146,11 +146,12 @@ namespace BlackMisc::Aviation
// we can detect "on ground" (underflow, near ground), but not "not on ground" because of overflow
// we can detect on ground for underflow, but not for overflow (so we can not rely on NotOnGround)
CAircraftSituation::IsOnGround og = situation.isOnGroundByElevation(cg);
if (og == CAircraftSituation::OnGround)
COnGroundInfo og(cg, situation.getGroundDistance(cg));
if (og.getOnGround() == COnGroundInfo::OnGround)
{
if (details) { *details = QStringLiteral("elevation on ground"); }
situation.setOnGround(og, CAircraftSituation::OnGroundByGuessing);
og.setOnGroundDetails(COnGroundInfo::OnGroundByGuessing);
situation.setOnGroundInfo(og);
return true;
}
@@ -166,7 +167,7 @@ namespace BlackMisc::Aviation
}
// here we stick to ground until we detect rotate up
situation.setOnGround(CAircraftSituation::OnGround, CAircraftSituation::OnGroundByGuessing);
situation.setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::OnGroundByGuessing });
if (details) { *details = QStringLiteral("waiting for rotating up"); }
return true;
}
@@ -183,7 +184,7 @@ namespace BlackMisc::Aviation
if (vtol)
{
// no idea
situation.setOnGround(CAircraftSituation::OnGroundSituationUnknown, CAircraftSituation::NotSetGroundDetails);
situation.setOnGroundInfo({ COnGroundInfo::OnGroundSituationUnknown, COnGroundInfo::NotSetGroundDetails });
return false;
}
@@ -193,7 +194,7 @@ namespace BlackMisc::Aviation
// does the value make any sense?
if (situation.getGroundSpeed() < guessedRotateSpeed)
{
situation.setOnGround(CAircraftSituation::OnGround, CAircraftSituation::OnGroundByGuessing);
situation.setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::OnGroundByGuessing });
if (details) { *details = QStringLiteral("Guessing, max.guessed gs.") + guessedRotateSpeed.valueRoundedWithUnit(CSpeedUnit::kts(), 1); }
return true;
}

View File

@@ -116,7 +116,7 @@ namespace BlackMisc
//! \copydoc BlackMisc::Aviation::CAircraftSituationList::containsPushBack
bool containsPushBack() const { return m_containsPushBack; }
//! \copydoc BlackMisc::Aviation::CAircraftSituationList::elevationStandardDeviationAndMean
//! Elevation standard deviation and mean
CAltitudePair getElevationStdDevAndMean() const { return CAltitudePair(m_elvStdDev, m_elvMean); }
//! Guess on ground flag

View File

@@ -55,22 +55,22 @@ namespace BlackMisc::Aviation
int c = 0;
for (CAircraftSituation &situation : *this)
{
situation.setOnGroundDetails(CAircraftSituation::InFromParts);
situation.setOnGroundDetails(COnGroundInfo::InFromParts);
if (situation.adjustGroundFlag(parts, true, timeDeviationFactor)) { c++; };
}
return c;
}
bool CAircraftSituationList::containsOnGroundDetails(CAircraftSituation::OnGroundDetails details) const
bool CAircraftSituationList::containsOnGroundDetails(COnGroundInfo::OnGroundDetails details) const
{
return this->contains(&CAircraftSituation::getOnGroundDetails, details);
return std::any_of(begin(), end(), [&details](const CAircraftSituation &sit) { return sit.getOnGroundInfo().getGroundDetails() == details; });
}
bool CAircraftSituationList::areAllOnGroundDetailsSame(CAircraftSituation::OnGroundDetails details) const
bool CAircraftSituationList::areAllOnGroundDetailsSame(COnGroundInfo::OnGroundDetails details) const
{
for (const CAircraftSituation &situation : *this)
{
if (situation.getOnGroundDetails() != details) { return false; }
if (situation.getOnGroundInfo().getGroundDetails() != details) { return false; }
}
return true;
}
@@ -79,24 +79,14 @@ namespace BlackMisc::Aviation
{
if (this->isEmpty()) { return false; }
if (this->containsNullPositionOrHeight()) { return false; }
for (const CAircraftSituation &situation : *this)
{
const CAircraftSituation::IsOnGround og = situation.getOnGround();
if (og != CAircraftSituation::OnGround) { return false; }
}
return true;
return std::all_of(begin(), end(), [](const CAircraftSituation &situation) { return situation.isOnGround(); });
}
bool CAircraftSituationList::isConstNotOnGround() const
{
if (this->isEmpty()) { return false; }
if (this->containsNullPositionOrHeight()) { return false; }
for (const CAircraftSituation &situation : *this)
{
const CAircraftSituation::IsOnGround og = situation.getOnGround();
if (og != CAircraftSituation::NotOnGround) { return false; }
}
return true;
return std::all_of(begin(), end(), [](const CAircraftSituation &situation) { return situation.getOnGroundInfo().getOnGround() == COnGroundInfo::NotOnGround; });
}
bool CAircraftSituationList::isConstDescending(bool alreadySortedLatestFirst) const
@@ -178,27 +168,27 @@ namespace BlackMisc::Aviation
return true;
}
QPair<bool, CAircraftSituation::IsOnGround> CAircraftSituationList::isGndFlagStableChanging(bool alreadySortedLatestFirst) const
QPair<bool, COnGroundInfo::IsOnGround> CAircraftSituationList::isGndFlagStableChanging(bool alreadySortedLatestFirst) const
{
if (this->size() < 2) { return QPair<bool, CAircraftSituation::IsOnGround>(false, CAircraftSituation::OnGroundSituationUnknown); }
if (this->size() < 2) { return QPair<bool, COnGroundInfo::IsOnGround>(false, COnGroundInfo::OnGroundSituationUnknown); }
const CAircraftSituationList sorted(alreadySortedLatestFirst ? (*this) : this->getSortedAdjustedLatestFirst());
const CAircraftSituation::IsOnGround f = sorted.front().getOnGround();
const CAircraftSituation::IsOnGround t = sorted.back().getOnGround();
QPair<bool, CAircraftSituation::IsOnGround> ret(false, f); // changing to front (latest)
const COnGroundInfo::IsOnGround f = sorted.front().getOnGroundInfo().getOnGround();
const COnGroundInfo::IsOnGround t = sorted.back().getOnGroundInfo().getOnGround();
QPair<bool, COnGroundInfo::IsOnGround> ret(false, f); // changing to front (latest)
if (f == t) { return ret; }
bool changed = false;
for (const CAircraftSituation &s : sorted)
{
if (!changed && s.getOnGround() == f) { continue; } // find 1st changing
if (!changed && s.getOnGroundInfo().getOnGround() == f) { continue; } // find 1st changing
if (!changed)
{
changed = true;
continue;
} // just changed
if (s.getOnGround() != t) { return ret; } // jitter, something like gnd, no gnd, gnd
if (s.getOnGroundInfo().getOnGround() != t) { return ret; } // jitter, something like gnd, no gnd, gnd
}
ret.first = changed;
return ret;
@@ -210,8 +200,8 @@ namespace BlackMisc::Aviation
const CAircraftSituationList sorted(alreadySortedLatestFirst ? (*this) : this->getSortedAdjustedLatestFirst());
const CAircraftSituation latest = sorted.front();
if (latest.getOnGround() != CAircraftSituation::NotOnGround) { return false; }
const int c = this->countOnGround(CAircraftSituation::OnGround);
if (latest.getOnGroundInfo().getOnGround() != COnGroundInfo::NotOnGround) { return false; }
const int c = this->countOnGround(COnGroundInfo::OnGround);
return this->size() - 1 == c; // all others on ground
}
@@ -221,21 +211,21 @@ namespace BlackMisc::Aviation
const CAircraftSituationList sorted(alreadySortedLatestFirst ? (*this) : this->getSortedAdjustedLatestFirst());
const CAircraftSituation latest = sorted.front();
if (latest.getOnGround() != CAircraftSituation::OnGround) { return false; }
const int c = this->countOnGround(CAircraftSituation::NotOnGround);
if (latest.getOnGroundInfo().getOnGround() != COnGroundInfo::OnGround) { return false; }
const int c = this->countOnGround(COnGroundInfo::NotOnGround);
return this->size() - 1 == c; // all others not on ground
}
bool CAircraftSituationList::isTakingOff(bool alreadySortedLatestFirst) const
{
const QPair<bool, CAircraftSituation::IsOnGround> r = this->isGndFlagStableChanging(alreadySortedLatestFirst);
return r.first && r.second == CAircraftSituation::NotOnGround;
const QPair<bool, COnGroundInfo::IsOnGround> r = this->isGndFlagStableChanging(alreadySortedLatestFirst);
return r.first && r.second == COnGroundInfo::NotOnGround;
}
bool CAircraftSituationList::isTouchingDown(bool alreadySortedLatestFirst) const
{
const QPair<bool, CAircraftSituation::IsOnGround> r = this->isGndFlagStableChanging(alreadySortedLatestFirst);
return r.first && r.second == CAircraftSituation::OnGround;
const QPair<bool, COnGroundInfo::IsOnGround> r = this->isGndFlagStableChanging(alreadySortedLatestFirst);
return r.first && r.second == COnGroundInfo::OnGround;
}
bool CAircraftSituationList::isRotatingUp(bool alreadySortedLatestFirst) const
@@ -258,14 +248,9 @@ namespace BlackMisc::Aviation
return false;
}
int CAircraftSituationList::countOnGround(CAircraftSituation::IsOnGround og) const
int CAircraftSituationList::countOnGround(COnGroundInfo::IsOnGround og) const
{
int c = 0;
for (const CAircraftSituation &situation : *this)
{
if (situation.getOnGround() == og) { c++; }
}
return c;
return std::count_if(begin(), end(), [&og](const CAircraftSituation &situation) { return situation.getOnGroundInfo().getOnGround() == og; });
}
CAircraftSituation CAircraftSituationList::findClosestElevationWithinRange(const ICoordinateGeodetic &coordinate, const CLength &range) const
@@ -293,24 +278,20 @@ namespace BlackMisc::Aviation
return situationWithElevation;
}
int CAircraftSituationList::setOnGround(CAircraftSituation::IsOnGround og)
void CAircraftSituationList::setOnGroundInfo(const COnGroundInfo &info)
{
int c = 0;
for (CAircraftSituation &situation : *this)
{
if (situation.setOnGround(og)) { c++; }
situation.setOnGroundInfo(info);
}
return c;
}
int CAircraftSituationList::setOnGroundDetails(CAircraftSituation::OnGroundDetails details)
void CAircraftSituationList::setOnGroundDetails(COnGroundInfo::OnGroundDetails details)
{
int c = 0;
for (CAircraftSituation &situation : *this)
{
if (situation.setOnGroundDetails(details)) { c++; }
situation.setOnGroundDetails(details);
}
return c;
}
int CAircraftSituationList::addAltitudeOffset(const CLength &offset)

View File

@@ -66,14 +66,14 @@ namespace BlackMisc
int adjustGroundFlag(const CAircraftParts &parts, double timeDeviationFactor = 0.1);
//! Contains on ground details?
bool containsOnGroundDetails(CAircraftSituation::OnGroundDetails details) const;
bool containsOnGroundDetails(COnGroundInfo::OnGroundDetails details) const;
//! Contains any push back?
//! \remark only valid for non VTOL aircraft
bool containsPushBack() const;
//! Are all on ground details the same?
bool areAllOnGroundDetailsSame(CAircraftSituation::OnGroundDetails details) const;
bool areAllOnGroundDetailsSame(COnGroundInfo::OnGroundDetails details) const;
//! Are all situations on ground?
bool isConstOnGround() const;
@@ -94,7 +94,7 @@ namespace BlackMisc
bool isConstDecelarating(bool alreadySortedLatestFirst = false) const;
//! Is the ground flag changing for the situations
QPair<bool, CAircraftSituation::IsOnGround> isGndFlagStableChanging(bool alreadySortedLatestFirst = false) const;
QPair<bool, COnGroundInfo::IsOnGround> isGndFlagStableChanging(bool alreadySortedLatestFirst = false) const;
//! Is just taking off?
bool isJustTakingOff(bool alreadySortedLatestFirst = false) const;
@@ -111,17 +111,17 @@ namespace BlackMisc
//! Is rotating up?
bool isRotatingUp(bool alreadySortedLatestFirst = false) const;
//! Count the number of situations with CAircraftSituation::IsOnGround
int countOnGround(CAircraftSituation::IsOnGround og) const;
//! Count the number of situations with COnGroundInfo::IsOnGround
int countOnGround(COnGroundInfo::IsOnGround og) const;
//! CLosest elevation within given range
CAircraftSituation findClosestElevationWithinRange(const Geo::ICoordinateGeodetic &coordinate, const PhysicalQuantities::CLength &range = Geo::CElevationPlane::singlePointRadius()) const;
//! Set on ground
int setOnGround(CAircraftSituation::IsOnGround og);
void setOnGroundInfo(const COnGroundInfo &info);
//! Set on ground details for all situations
int setOnGroundDetails(CAircraftSituation::OnGroundDetails details);
void setOnGroundDetails(COnGroundInfo::OnGroundDetails details);
//! Add an offset to each altitude
int addAltitudeOffset(const PhysicalQuantities::CLength &offset);

View File

@@ -0,0 +1,180 @@
// SPDX-FileCopyrightText: Copyright (C) swift Project Community / Contributors
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
#include "blackmisc/aviation/ongroundinfo.h"
#include "blackmisc/verify.h"
BLACK_DEFINE_VALUEOBJECT_MIXINS(BlackMisc::Aviation, COnGroundInfo)
using namespace BlackMisc::PhysicalQuantities;
namespace BlackMisc::Aviation
{
COnGroundInfo::COnGroundInfo(IsOnGround onGround, OnGroundDetails details) : m_onGroundDetails(static_cast<int>(details))
{
switch (onGround)
{
case IsOnGround::OnGroundSituationUnknown:
m_onGroundFactor = -1.0;
break;
case IsOnGround::OnGround:
m_onGroundFactor = 1.0;
break;
case IsOnGround::NotOnGround:
m_onGroundFactor = 0.0;
break;
}
}
const QString &COnGroundInfo::isOnGroundToString(IsOnGround onGround)
{
static const QString notog("not on ground");
static const QString og("on ground");
static const QString unknown("unknown");
switch (onGround)
{
case IsOnGround::NotOnGround: return notog;
case IsOnGround::OnGround: return og;
case IsOnGround::OnGroundSituationUnknown:
default: return unknown;
}
}
const QString &COnGroundInfo::onGroundDetailsToString(OnGroundDetails reliability)
{
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");
switch (reliability)
{
case OnGroundDetails::OnGroundByElevationAndCG: return elvCg;
case OnGroundDetails::OnGroundByGuessing: return guess;
case OnGroundDetails::OnGroundByInterpolation: return interpolation;
case OnGroundDetails::OutOnGroundOwnAircraft: return outOwnAircraft;
case OnGroundDetails::InFromNetwork: return inNetwork;
case OnGroundDetails::InFromParts: return inFromParts;
case OnGroundDetails::NotSetGroundDetails:
default: return unknown;
}
}
void COnGroundInfo::registerMetadata()
{
CValueObject<COnGroundInfo>::registerMetadata();
qRegisterMetaType<IsOnGround>();
qRegisterMetaType<OnGroundDetails>();
}
COnGroundInfo::COnGroundInfo(double interpolatedGndFactor) : m_onGroundDetails(static_cast<int>(OnGroundDetails::OnGroundByInterpolation)), m_onGroundFactor(interpolatedGndFactor)
{
// Clip small ground factor values
if (m_onGroundFactor < 0.0)
{
m_onGroundFactor = -1.0;
}
else if (m_onGroundFactor < 0.001)
{
m_onGroundFactor = 0.0;
}
else if (m_onGroundFactor > 0.999)
{
m_onGroundFactor = 1.0;
}
}
COnGroundInfo::COnGroundInfo(const CLength &cg, const CLength &groundDistance)
{
m_onGroundDetails = static_cast<int>(OnGroundDetails::OnGroundByElevationAndCG);
if (groundDistance.isNull())
{
m_onGroundFactor = -1.0;
}
else if (groundDistance.isNegativeWithEpsilonConsidered()) { m_onGroundFactor = 1.0; }
else if (groundDistance.abs() < deltaNearGround()) { m_onGroundFactor = 1.0; }
else if (!cg.isNull())
{
// smaller than percentage from CG
const CLength cgFactor(cg * 0.1);
if (groundDistance.abs() < cgFactor.abs()) { m_onGroundFactor = 1.0; }
}
m_onGroundFactor = 0.0;
}
bool COnGroundInfo::isOnGround() const
{
BLACK_VERIFY_X(m_onGroundFactor >= 0.0, Q_FUNC_INFO, "Should only be called with positive groundfactors");
if (m_onGroundDetails == OnGroundDetails::OnGroundByInterpolation)
{
return m_onGroundFactor > m_groundFactorThreshold;
}
else
{
return Math::CMathUtils::epsilonEqual(m_onGroundFactor, 1.0);
}
}
COnGroundInfo::IsOnGround COnGroundInfo::getOnGround() const
{
if (this->m_onGroundFactor < 0.0)
{
return OnGroundSituationUnknown;
}
const bool onGround = isOnGround();
return onGround ? OnGround : NotOnGround;
}
COnGroundInfo::OnGroundDetails COnGroundInfo::getGroundDetails() const
{
return static_cast<COnGroundInfo::OnGroundDetails>(m_onGroundDetails);
}
const CLength &COnGroundInfo::deltaNearGround()
{
static const CLength small(0.5, CLengthUnit::m());
return small;
}
QString COnGroundInfo::convertToQString(bool /*i18n*/) const
{
return u" | factor: " % QString::number(m_onGroundFactor, 'f', 2) %
u" | source: " % onGroundDetailsToString(static_cast<OnGroundDetails>(m_onGroundDetails));
}
QVariant COnGroundInfo::propertyByIndex(CPropertyIndexRef index) const
{
if (index.isMyself()) { return QVariant::fromValue(*this); }
const ColumnIndex i = index.frontCasted<ColumnIndex>();
switch (i)
{
case IndexOnGroundFactor: return QVariant::fromValue(m_onGroundFactor);
case IndexOnGroundDetails: return QVariant::fromValue(m_onGroundDetails);
default: return CValueObject::propertyByIndex(index);
}
}
void COnGroundInfo::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
{
if (index.isMyself())
{
(*this) = variant.value<COnGroundInfo>();
return;
}
const ColumnIndex i = index.frontCasted<ColumnIndex>();
switch (i)
{
case IndexOnGroundFactor: m_onGroundFactor = variant.toDouble(); break;
case IndexOnGroundDetails: m_onGroundDetails = variant.toInt(); break;
default: CValueObject::setPropertyByIndex(index, variant); break;
}
}
}

View File

@@ -0,0 +1,130 @@
// SPDX-FileCopyrightText: Copyright (C) swift Project Community / Contributors
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
//! \file
#ifndef BLACKMISC_AVIATION_ONGROUNDINFO_H
#define BLACKMISC_AVIATION_ONGROUNDINFO_H
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/valueobject.h"
#include "blackmisc/pq/length.h"
BLACK_DECLARE_VALUEOBJECT_MIXINS(BlackMisc::Aviation, COnGroundInfo)
namespace BlackMisc::Aviation
{
//! Information about the ground status
class BLACKMISC_EXPORT COnGroundInfo : public CValueObject<COnGroundInfo>
{
public:
//! Is on ground?
enum IsOnGround
{
NotOnGround,
OnGround,
OnGroundSituationUnknown
};
//! Reliability of on ground information
enum OnGroundDetails
{
NotSetGroundDetails,
// interpolated situation
OnGroundByInterpolation, //!< strongest for remote aircraft
OnGroundByElevationAndCG,
OnGroundByGuessing, //!< weakest
// received situation
InFromNetwork, //!< received from network
InFromParts, //!< set from aircraft parts
// send information
OutOnGroundOwnAircraft //!< sending on ground
};
//! Properties by index
enum ColumnIndex
{
IndexOnGroundFactor = CPropertyIndexRef::GlobalIndexCOnGroundInfo,
IndexOnGroundDetails,
};
COnGroundInfo() = default;
//! Create GroundInfo with fixed decision (on ground, not on ground or not known) and with
//! info about the source of this knowledge
COnGroundInfo(IsOnGround onGround, OnGroundDetails details);
//! Create GroundInfo from information about CG and distance from ground
COnGroundInfo(const PhysicalQuantities::CLength &cg, const PhysicalQuantities::CLength &groundDistance);
//! Create GroundInfo from interpolated ground factor
explicit COnGroundInfo(double interpolatedGndFactor);
//! Get the ground factor
//! Use this for interpolation only!!
//! For just checking if the info is OnGround or NotOnGround use the getOnGround() method instead.
double getGroundFactor() const { return m_onGroundFactor; }
//! When source of knowledge changes
void setOnGroundDetails(OnGroundDetails details)
{
// TODO Assert not by interpolation
m_onGroundDetails = static_cast<int>(details);
}
//! Is on ground?
//! \return IsOnGround state of this object
IsOnGround getOnGround() const;
//! Get ground details
//! \return ground details of this object
OnGroundDetails getGroundDetails() const;
//! \copydoc Mixin::String::toQString
QString convertToQString(bool i18n = false) const;
//! \copydoc Mixin::Index::propertyByIndex
QVariant propertyByIndex(CPropertyIndexRef index) const;
//! \copydoc Mixin::Index::setPropertyByIndex
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant);
//! Register metadata
static void registerMetadata();
//! Enum to string
static const QString &isOnGroundToString(IsOnGround onGround);
//! Enum to string
static const QString &onGroundDetailsToString(OnGroundDetails reliability);
//! Delta distance, near to ground
static const PhysicalQuantities::CLength &deltaNearGround();
private:
//! Check if the aircraft is considered to be on the ground.
//! Depending on the data source, different definitions are used on when the aircraft
//! is considered to be on the ground.
//! This method should only be called when the m_onGroundFactor is >= 0.0, as it is only does a binary
//! decision.
//! \return true, if the aircraft is considered to be on the ground
bool isOnGround() const;
int m_onGroundDetails = static_cast<int>(OnGroundDetails::NotSetGroundDetails);
double m_onGroundFactor = -1.0; //!< interpolated ground flag, 1..on ground, 0..not on ground, -1 no info
static constexpr double m_groundFactorThreshold = 0.95; //!< With m_onGroundDetails == "OnGroundByInterpolation", this is the threshold used to decide if the ground factor is OnGround or NotOnGround
BLACK_METACLASS(
COnGroundInfo,
BLACK_METAMEMBER(onGroundDetails),
BLACK_METAMEMBER(onGroundFactor));
};
}
Q_DECLARE_METATYPE(BlackMisc::Aviation::COnGroundInfo)
Q_DECLARE_METATYPE(BlackMisc::Aviation::COnGroundInfo::IsOnGround)
Q_DECLARE_METATYPE(BlackMisc::Aviation::COnGroundInfo::OnGroundDetails)
#endif // BLACKMISC_AVIATION_ONGROUNDINFO_H

View File

@@ -39,6 +39,7 @@
#include "blackmisc/aviation/aircraftpartslist.h"
#include "blackmisc/aviation/livery.h"
#include "blackmisc/aviation/liverylist.h"
#include "blackmisc/aviation/ongroundinfo.h"
namespace BlackMisc
{
@@ -86,6 +87,7 @@ namespace BlackMisc
CSelcal::registerMetadata();
CTrack::registerMetadata();
CTransponder::registerMetadata();
COnGroundInfo::registerMetadata();
}
}

View File

@@ -107,7 +107,7 @@ namespace BlackMisc::Network
{
if (situation.getCallsign().isEmpty()) { return false; } // no callsign
if (!situation.isOnGround()) { return false; } // nothing to adjust
if (situation.getOnGroundDetails() != CAircraftSituation::InFromNetwork) { return false; } // not from network
if (situation.getOnGroundInfo().getGroundDetails() != COnGroundInfo::InFromNetwork) { return false; } // not from network
return this->addClientGndCapability(situation.getCallsign());
}

View File

@@ -60,6 +60,7 @@ namespace BlackMisc
GlobalIndexCPresentWeather = 4200,
GlobalIndexCWindLayer = 4300,
GlobalIndexCWeatherScenario = 4700,
GlobalIndexCOnGroundInfo = 4800,
GlobalIndexICoordinateGeodetic = 5000,
GlobalIndexICoordinateWithRelativePosition = 5100,
GlobalIndexCCoordinateGeodetic = 5200,

View File

@@ -361,9 +361,9 @@ namespace BlackMisc::Simulation
u"<td class=\"cur\">" % log.situationCurrent.getGroundElevation().valueRoundedWithUnit(ft, 1) % u" " % log.situationCurrent.getGroundElevationInfoAsString() % u"</td>" %
u"<td>" % QString::number(log.groundFactor) % u"</td>" %
u"<td class=\"old\">" % situationOld.getOnGroundInfo() % u"</td>" %
u"<td class=\"new\">" % situationNew.getOnGroundInfo() % u"</td>" %
u"<td class=\"cur\">" % log.situationCurrent.getOnGroundInfo() % u"</td>" %
u"<td class=\"old\">" % situationOld.getOnGroundInfo().toQString() % u"</td>" %
u"<td class=\"new\">" % situationNew.getOnGroundInfo().toQString() % u"</td>" %
u"<td class=\"cur\">" % log.situationCurrent.getOnGroundInfo().toQString() % u"</td>" %
// tableRows +=
u"<td>" % log.cgAboveGround.valueRoundedWithUnit(ft, 0) % u"</td>" %

View File

@@ -74,14 +74,6 @@ namespace BlackMisc::Simulation
return cg;
}
template <typename Derived>
double CInterpolator<Derived>::groundInterpolationFactor()
{
// done here so we can change value without "larfer" recompilations
static constexpr double f = 0.95;
return f;
}
template <typename Derived>
CAircraftSituationList CInterpolator<Derived>::remoteAircraftSituationsAndChange(const CInterpolationAndRenderingSetupPerCallsign &setup)
{
@@ -181,10 +173,10 @@ namespace BlackMisc::Simulation
if (setup.isNull() || !setup.isAircraftPartsEnabled()) { return sorted; }
bool details = false;
if (situations.containsOnGroundDetails(CAircraftSituation::InFromParts))
if (situations.containsOnGroundDetails(COnGroundInfo::InFromParts))
{
// if a client supports parts, all ground situations are supposed to be parts based
details = situations.areAllOnGroundDetailsSame(CAircraftSituation::InFromParts);
details = situations.areAllOnGroundDetailsSame(COnGroundInfo::InFromParts);
BLACK_VERIFY_X(details, Q_FUNC_INFO, "Once gnd.from parts -> always gnd. from parts");
}
@@ -300,7 +292,7 @@ namespace BlackMisc::Simulation
}
// correct altitude itself
if (!interpolateGndFlag && currentSituation.getOnGroundDetails() != CAircraftSituation::OnGroundByGuessing)
if (!interpolateGndFlag && currentSituation.getOnGroundInfo().getGroundDetails() != COnGroundInfo::OnGroundByGuessing)
{
// just in case
altCorrection = currentSituation.correctAltitude(true); // we have CG set
@@ -377,7 +369,7 @@ namespace BlackMisc::Simulation
{
log.tsCurrent = m_currentTimeMsSinceEpoch;
log.callsign = m_callsign;
log.groundFactor = currentSituation.getOnGroundFactor();
log.groundFactor = currentSituation.getOnGroundInfo().getGroundFactor();
log.altCorrection = CAircraftSituation::altitudeCorrectionToString(altCorrection);
log.situationCurrent = currentSituation;
log.interpolantRecalc = interpolant.isRecalculated();
@@ -524,7 +516,7 @@ namespace BlackMisc::Simulation
CLength guessedCG = model.getCG();
model.getAircraftIcaoCode().guessModelParameters(guessedCG, guessedVRotate);
if (situation.getOnGroundDetails() != CAircraftSituation::NotSetGroundDetails)
if (situation.getOnGroundInfo().getGroundDetails() != COnGroundInfo::NotSetGroundDetails)
{
do
{
@@ -613,10 +605,10 @@ namespace BlackMisc::Simulation
}
else
{
if (situation.getOnGroundDetails() != CAircraftSituation::NotSetGroundDetails)
if (situation.getOnGroundInfo().getGroundDetails() != COnGroundInfo::NotSetGroundDetails)
{
// we have no ground elevation but a ground info
if (situation.getOnGroundDetails() == CAircraftSituation::OnGroundByGuessing)
if (situation.getOnGroundInfo().getGroundDetails() == COnGroundInfo::OnGroundByGuessing)
{
// should be OK
if (details) { *details = QStringLiteral("on ground, no elv."); }

View File

@@ -113,10 +113,6 @@ namespace BlackMisc::Simulation
//! Do logging
bool doLogging() const;
//! Decides threshold when situation is considered on ground
//! \sa BlackMisc::Aviation::CAircraftSituation::setOnGroundFromGroundFactorFromInterpolation
static double groundInterpolationFactor();
const Aviation::CCallsign m_callsign; //!< corresponding callsign
CAircraftModel m_model; //!< corresponding model (required for CG)

View File

@@ -84,21 +84,20 @@ namespace BlackMisc::Simulation
if (interpolateGndFactor)
{
const double startGroundFactor = m_startSituation.getOnGroundFactor();
const double endGroundFactor = m_endSituation.getOnGroundFactor();
const double startGroundFactor = m_startSituation.getOnGroundInfo().getGroundFactor();
const double endGroundFactor = m_endSituation.getOnGroundInfo().getGroundFactor();
if (CAircraftSituation::isGfEqualAirborne(startGroundFactor, endGroundFactor))
{
interpolatedSituation.setOnGround(false);
interpolatedSituation.setOnGroundInfo({ COnGroundInfo::NotOnGround, COnGroundInfo::OnGroundByInterpolation });
}
else if (CAircraftSituation::isGfEqualOnGround(startGroundFactor, endGroundFactor))
{
interpolatedSituation.setOnGround(true);
interpolatedSituation.setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::OnGroundByInterpolation });
}
else
{
const double interpolatedGroundFactor = (endGroundFactor - startGroundFactor) * tf + startGroundFactor;
interpolatedSituation.setOnGroundFactor(interpolatedGroundFactor);
interpolatedSituation.setOnGroundFromGroundFactorFromInterpolation(groundInterpolationFactor());
interpolatedSituation.setOnGroundInfo(COnGroundInfo(interpolatedGroundFactor));
}
}
return interpolatedSituation;

View File

@@ -218,7 +218,7 @@ namespace BlackMisc::Simulation
const double a1 = m_s[1].getCorrectedAltitude(cg).value(altUnit);
const double a2 = m_s[2].getCorrectedAltitude(cg).value(altUnit); // latest
pa.a = { { a0, a1, a2 } };
pa.gnd = { { m_s[0].getOnGroundFactor(), m_s[1].getOnGroundFactor(), m_s[2].getOnGroundFactor() } };
pa.gnd = { { m_s[0].getOnGroundInfo().getGroundFactor(), m_s[1].getOnGroundInfo().getGroundFactor(), m_s[2].getOnGroundInfo().getGroundFactor() } };
pa.da = getDerivatives(pa.t, pa.a);
pa.dgnd = getDerivatives(pa.t, pa.gnd);
@@ -365,24 +365,20 @@ namespace BlackMisc::Simulation
{
const double gnd1 = m_pa.gnd[1];
const double gnd2 = m_pa.gnd[2]; // latest
do
{
newSituation.setOnGroundDetails(CAircraftSituation::OnGroundByInterpolation);
if (CAircraftSituation::isGfEqualAirborne(gnd1, gnd2))
{
newSituation.setOnGround(false);
break;
newSituation.setOnGroundInfo({ COnGroundInfo::NotOnGround, COnGroundInfo::OnGroundByInterpolation });
}
if (CAircraftSituation::isGfEqualOnGround(gnd1, gnd2))
else if (CAircraftSituation::isGfEqualOnGround(gnd1, gnd2))
{
newSituation.setOnGround(true);
break;
newSituation.setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::OnGroundByInterpolation });
}
else
{
const double newGnd = evalSplineInterval(m_currentTimeMsSinceEpoc, t1, t2, gnd1, gnd2, m_pa.dgnd[1], m_pa.dgnd[2]);
newSituation.setOnGroundFactor(newGnd);
newSituation.setOnGroundFromGroundFactorFromInterpolation(groundInterpolationFactor());
newSituation.setOnGroundInfo(COnGroundInfo(newGnd));
}
while (false);
}
return newSituation;
}

View File

@@ -303,7 +303,7 @@ namespace BlackMisc::Simulation
// unify all inbound ground information
if (situation.hasInboundGroundDetails())
{
newSituationsList.setOnGroundDetails(situation.getOnGroundDetails());
newSituationsList.setOnGroundDetails(situation.getOnGroundInfo().getGroundDetails());
}
}
m_latestSituationByCallsign[cs] = situationCorrected;

View File

@@ -59,7 +59,7 @@ namespace BlackSimPlugin::Flightgear
this->pitchesDeg.push_back(situation.getPitch().value(BlackMisc::PhysicalQuantities::CAngleUnit::deg()));
this->rollsDeg.push_back(situation.getBank().value(BlackMisc::PhysicalQuantities::CAngleUnit::deg()));
this->headingsDeg.push_back(situation.getHeading().value(BlackMisc::PhysicalQuantities::CAngleUnit::deg()));
this->onGrounds.push_back(situation.getOnGround() == BlackMisc::Aviation::CAircraftSituation::OnGround);
this->onGrounds.push_back(situation.isOnGround());
this->groundSpeedKts.push_back(situation.getGroundSpeed().value(BlackMisc::PhysicalQuantities::CSpeedUnit::kts()));
}

View File

@@ -652,7 +652,7 @@ namespace BlackSimPlugin::FsxCommon
aircraftSituation.setPressureAltitude(CAltitude(simulatorOwnAircraft.pressureAltitudeM, CAltitude::MeanSeaLevel, CAltitude::PressureAltitude, CLengthUnit::m()));
// set on ground also in situation for consistency and future usage
// it is duplicated in parts
aircraftSituation.setOnGround(dtb(simulatorOwnAircraft.simOnGround) ? CAircraftSituation::OnGround : CAircraftSituation::NotOnGround, CAircraftSituation::OutOnGroundOwnAircraft);
aircraftSituation.setOnGroundInfo({ dtb(simulatorOwnAircraft.simOnGround) ? COnGroundInfo::OnGround : COnGroundInfo::NotOnGround, COnGroundInfo::OutOnGroundOwnAircraft });
CAircraftVelocity aircraftVelocity(simulatorOwnAircraft.velocityWorldX,
simulatorOwnAircraft.velocityWorldY,
@@ -2236,7 +2236,7 @@ namespace BlackSimPlugin::FsxCommon
// send GND flag also when underflow detection is available
if ((sendGnd || forceUnderflowDetection) && situation.isOnGroundInfoAvailable())
{
const bool onGround = (situation.getOnGround() == CAircraftSituation::OnGround);
const bool onGround = situation.isOnGround();
position.OnGround = onGround ? 1U : 0U;
}

View File

@@ -953,7 +953,7 @@ namespace BlackSimPlugin::XPlane
// adjust altitude to compensate for XP12 temperature effect
const CLength relativeAltitude = interpolatedSituation.geodeticHeight() - getOwnAircraftPosition().geodeticHeight();
const double altitudeDeltaWeight = 2 - qBound(3000.0, relativeAltitude.abs().value(CLengthUnit::ft()), 6000.0) / 3000;
const CLength alt = interpolatedSituation.getAltitude() + m_altitudeDelta * altitudeDeltaWeight * (1 - interpolatedSituation.getOnGroundFactor());
const CLength alt = interpolatedSituation.getAltitude() + m_altitudeDelta * altitudeDeltaWeight * (1 - interpolatedSituation.getOnGroundInfo().getGroundFactor());
interpolatedSituation.setAltitude({ alt, interpolatedSituation.getAltitude().getReferenceDatum() });
// update situation

View File

@@ -63,7 +63,7 @@ namespace BlackSimPlugin::XPlane
this->pitchesDeg.push_back(situation.getPitch().value(BlackMisc::PhysicalQuantities::CAngleUnit::deg()));
this->rollsDeg.push_back(situation.getBank().value(BlackMisc::PhysicalQuantities::CAngleUnit::deg()));
this->headingsDeg.push_back(situation.getHeading().value(BlackMisc::PhysicalQuantities::CAngleUnit::deg()));
this->onGrounds.push_back(situation.getOnGround() == BlackMisc::Aviation::CAircraftSituation::OnGround);
this->onGrounds.push_back(situation.isOnGround());
}
QStringList callsigns; //!< List of callsigns

View File

@@ -76,7 +76,7 @@ namespace BlackMiscTest
void CTestAircraftSituation::allGndFlagsAndTakeOff() const
{
CAircraftSituationList situations = testSituations();
situations.setOnGround(CAircraftSituation::OnGround);
situations.setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::NotSetGroundDetails });
const CAircraftSituationChange change(situations, cg(), false);
QVERIFY2(change.isConstOnGround(), "Expect const on ground");
QVERIFY(!change.isConstNotOnGround());
@@ -87,7 +87,7 @@ namespace BlackMiscTest
QVERIFY(situations.isSortedAdjustedLatestFirstWithoutNullPositions());
CAircraftSituation f = situations.front();
f.setOnGround(false);
f.setOnGroundInfo({ COnGroundInfo::NotOnGround, COnGroundInfo::NotSetGroundDetails });
situations.pop_front();
situations.push_front(f);
const CAircraftSituationChange change2(situations, cg(), false);
@@ -100,7 +100,7 @@ namespace BlackMiscTest
void CTestAircraftSituation::allNotGndFlagsAndTouchdown() const
{
CAircraftSituationList situations = testSetDescendingAltitudes(testSituations());
situations.setOnGround(CAircraftSituation::NotOnGround);
situations.setOnGroundInfo({ COnGroundInfo::NotOnGround, COnGroundInfo::NotSetGroundDetails });
const CAircraftSituationChange change(situations, cg(), false);
QVERIFY2(change.isConstNotOnGround(), "Expect const not on ground");
QVERIFY(!change.isConstOnGround());
@@ -111,7 +111,7 @@ namespace BlackMiscTest
QVERIFY(situations.isSortedAdjustedLatestFirstWithoutNullPositions());
CAircraftSituation f = situations.front();
f.setOnGround(true);
f.setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::NotSetGroundDetails });
situations.pop_front();
situations.push_front(f);
const CAircraftSituationChange change2(situations, cg(), false);
@@ -215,7 +215,8 @@ namespace BlackMiscTest
corAlt = situation.getCorrectedAltitude(true, &correction);
QVERIFY2(corAlt == alt, "Expect same altitude, no overflow since not on gnd.");
situation.setOnGround(CAircraftSituation::OnGround, CAircraftSituation::InFromNetwork);
situation.setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::InFromNetwork });
corAlt = situation.getCorrectedAltitude(true, &correction);
QVERIFY2(correction == CAircraftSituation::DraggedToGround, "Expect dragged to gnd.");
QVERIFY2(corAlt < alt, "Expect corrected altitude dragged to gnd.");

View File

@@ -132,27 +132,27 @@ namespace BlackMiscTest
for (int i = 0; i < number; i++)
{
CAircraftSituation s = createTestSituation(cs, i, ts, deltaT, 0);
s.setOnGround(CAircraftSituation::OnGroundSituationUnknown, CAircraftSituation::NotSetGroundDetails);
s.setOnGroundInfo({ COnGroundInfo::OnGroundSituationUnknown, COnGroundInfo::NotSetGroundDetails });
situations.push_back(s);
}
CAircraftSituation s0 = situations[0];
s0.adjustGroundFlag(partsOnGround, true);
QVERIFY2(s0.getOnGround(), "Supposed to be on ground");
QVERIFY2(s0.getOnGroundInfo().getOnGround(), "Supposed to be on ground");
s0 = situations[0];
s0.adjustGroundFlag(partsNotOnGround, true);
QVERIFY2(!s0.getOnGround(), "Supposed to be not on ground");
QVERIFY2(!s0.getOnGroundInfo().getOnGround(), "Supposed to be not on ground");
qint64 distanceMs = -1;
const qint64 Offset = 33;
partsOnGround.addMsecsToOffset(Offset);
CAircraftSituation s1 = situations[1];
s1.setOnGroundDetails(CAircraftSituation::NotSetGroundDetails);
s1.setOnGroundInfo({ COnGroundInfo::OnGroundSituationUnknown, COnGroundInfo::NotSetGroundDetails });
s1.adjustGroundFlag(partsOnGround, true, 0.1, &distanceMs);
QVERIFY2(s1.getOnGround(), "Supposed to be on ground");
QVERIFY2(s1.getOnGroundInfo().getOnGround(), "Supposed to be on ground");
QVERIFY2(distanceMs == deltaT - Offset, "Offset time wrong");
QVERIFY2(s1.getOnGroundDetails() == CAircraftSituation::InFromParts, "Wrong details");
QVERIFY2(s1.getOnGroundInfo().getGroundDetails() == COnGroundInfo::InFromParts, "Wrong details");
}
CAircraftParts CTestInterpolatorParts::createTestParts(int number, qint64 ts, qint64 deltaT, bool onGround)