mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-07 11:05:33 +08:00
Issue #77 Break cyclic dependencies between CAircraftParts, CAircraftLights, CAircraftSituation classes
This commit is contained in:
@@ -11,6 +11,8 @@
|
||||
#include "blackmisc/simulation/interpolationlogger.h"
|
||||
#include "blackmisc/simulation/interpolatorlinear.h"
|
||||
#include "blackmisc/simulation/interpolatorspline.h"
|
||||
#include "blackmisc/aviation/aircraftsituationchange.h"
|
||||
#include "blackmisc/aviation/aircraftsituation.h"
|
||||
#include "blackmisc/network/fsdsetup.h"
|
||||
#include "blackmisc/aviation/callsign.h"
|
||||
#include "blackmisc/aviation/heading.h"
|
||||
@@ -117,6 +119,54 @@ namespace BlackMisc
|
||||
return validSituations;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
bool CInterpolator<Derived>::presetGroundElevation(CAircraftSituation &situationToPreset, const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation, const CAircraftSituationChange &change)
|
||||
{
|
||||
// IMPORTANT: we do not know what the situation will be (interpolated to), so we cannot transfer
|
||||
situationToPreset.resetGroundElevation();
|
||||
do
|
||||
{
|
||||
if (oldSituation.equalNormalVectorDouble(newSituation))
|
||||
{
|
||||
if (oldSituation.hasGroundElevation())
|
||||
{
|
||||
// same positions, we can use existing elevation
|
||||
// means we were not moving between old an new
|
||||
situationToPreset.transferGroundElevationToMe(oldSituation, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const CLength distance = newSituation.calculateGreatCircleDistance(oldSituation);
|
||||
if (distance < newSituation.getDistancePerTime250ms(CElevationPlane::singlePointRadius()))
|
||||
{
|
||||
if (oldSituation.hasGroundElevation())
|
||||
{
|
||||
// almost same positions, we can use existing elevation
|
||||
situationToPreset.transferGroundElevationToMe(oldSituation, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (change.hasElevationDevWithinAllowedRange())
|
||||
{
|
||||
// not much change in known elevations
|
||||
const CAltitudePair elvDevMean = change.getElevationStdDevAndMean();
|
||||
situationToPreset.setGroundElevation(elvDevMean.second, CAircraftSituation::SituationChange);
|
||||
break;
|
||||
}
|
||||
|
||||
const CElevationPlane epInterpolated = CAircraftSituation::interpolatedElevation(CAircraftSituation::null(), oldSituation, newSituation, distance);
|
||||
if (!epInterpolated.isNull())
|
||||
{
|
||||
situationToPreset.setGroundElevation(epInterpolated, CAircraftSituation::Interpolated);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (false);
|
||||
return situationToPreset.hasGroundElevation();
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
void CInterpolator<Derived>::deferredInit()
|
||||
{
|
||||
@@ -238,7 +288,7 @@ namespace BlackMisc
|
||||
}
|
||||
|
||||
// GND flag.
|
||||
if (!interpolateGndFlag) { currentSituation.guessOnGround(CAircraftSituationChange::null(), m_model); }
|
||||
if (!interpolateGndFlag) { CAircraftSituationChange::null().guessOnGround(currentSituation, m_model); }
|
||||
|
||||
// as we now have the position and can interpolate elevation
|
||||
currentSituation.interpolateElevation(pbh.getOldSituation(), pbh.getNewSituation());
|
||||
@@ -428,7 +478,7 @@ namespace BlackMisc
|
||||
// check if model has been thru model matching
|
||||
if (!m_lastSituation.isNull())
|
||||
{
|
||||
parts.guessParts(m_lastSituation, m_pastSituationsChange, m_model);
|
||||
parts = guessParts(m_lastSituation, m_pastSituationsChange, m_model);
|
||||
this->logParts(parts, 0, false);
|
||||
}
|
||||
else
|
||||
@@ -470,6 +520,136 @@ namespace BlackMisc
|
||||
return this->hasAttachedLogger() && m_currentSetup.logInterpolation();
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
CAircraftParts CInterpolator<Derived>::guessParts(const CAircraftSituation &situation, const CAircraftSituationChange &change, const CAircraftModel &model)
|
||||
{
|
||||
CAircraftParts parts;
|
||||
parts.setMSecsSinceEpoch(situation.getMSecsSinceEpoch());
|
||||
parts.setTimeOffsetMs(situation.getTimeOffsetMs());
|
||||
parts.setPartsDetails(CAircraftParts::GuessedParts);
|
||||
parts.setLights(situation.guessLights());
|
||||
|
||||
QString *details = /*CBuildConfig::isLocalDeveloperDebugBuild() ? &parts.m_guessingDetails :*/ nullptr;
|
||||
|
||||
CAircraftEngineList engines;
|
||||
const bool vtol = model.isVtol();
|
||||
const int engineCount = model.getEngineCount();
|
||||
CSpeed guessedVRotate = CSpeed::null();
|
||||
CLength guessedCG = model.getCG();
|
||||
model.getAircraftIcaoCode().guessModelParameters(guessedCG, guessedVRotate);
|
||||
|
||||
if (situation.getOnGroundDetails() != CAircraftSituation::NotSetGroundDetails)
|
||||
{
|
||||
do
|
||||
{
|
||||
// set some reasonable values
|
||||
const bool isOnGround = situation.isOnGround();
|
||||
engines.initEngines(engineCount, !isOnGround || situation.isMoving());
|
||||
parts.setGearDown(isOnGround);
|
||||
parts.setSpoilersOut(false);
|
||||
parts.setEngines(engines);
|
||||
|
||||
if (!change.isNull())
|
||||
{
|
||||
if (change.isConstDecelarating())
|
||||
{
|
||||
parts.setSpoilersOut(true);
|
||||
parts.setFlapsPercent(10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const CSpeed slowSpeed = guessedVRotate * 0.30;
|
||||
if (situation.getGroundSpeed() < slowSpeed)
|
||||
{
|
||||
if (details) { *details += u"slow speed <" % slowSpeed.valueRoundedWithUnit(1) % u" on ground"; }
|
||||
parts.setFlapsPercent(0);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (details) { *details += u"faster speed >" % slowSpeed.valueRoundedWithUnit(1) % u" on ground"; }
|
||||
parts.setFlapsPercent(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (details) { *details = QStringLiteral("no ground info"); }
|
||||
|
||||
// no idea if on ground or not
|
||||
engines.initEngines(engineCount, true);
|
||||
parts.setEngines(engines);
|
||||
parts.setGearDown(true);
|
||||
parts.setSpoilersOut(false);
|
||||
}
|
||||
|
||||
const double pitchDeg = situation.getPitch().value(CAngleUnit::deg());
|
||||
const bool isLikelyTakeOffOrClimbing = change.isNull() ? pitchDeg > 20 : (change.isRotatingUp() || change.isConstAscending());
|
||||
const bool isLikelyLanding = change.isNull() ? false : change.isConstDescending();
|
||||
|
||||
if (situation.hasGroundElevation())
|
||||
{
|
||||
const CLength aboveGnd = situation.getHeightAboveGround();
|
||||
if (aboveGnd.isNull() || std::isnan(aboveGnd.value()))
|
||||
{
|
||||
BLACK_VERIFY_X(false, Q_FUNC_INFO, "above gnd.is null");
|
||||
return parts;
|
||||
}
|
||||
|
||||
const double nearGround1Ft = 300;
|
||||
const double nearGround2Ft = isLikelyTakeOffOrClimbing ? 500 : 1000;
|
||||
const double aGroundFt = aboveGnd.value(CLengthUnit::ft());
|
||||
static const QString detailsInfo("above ground: %1ft near grounds: %2ft %3ft likely takeoff: %4 likely landing: %5");
|
||||
|
||||
if (details) { *details = detailsInfo.arg(aGroundFt).arg(nearGround1Ft).arg(nearGround2Ft).arg(boolToYesNo(isLikelyTakeOffOrClimbing), boolToYesNo(isLikelyLanding)); }
|
||||
if (aGroundFt < nearGround1Ft)
|
||||
{
|
||||
if (details) { details->prepend(QStringLiteral("near ground: ")); }
|
||||
parts.setGearDown(true);
|
||||
parts.setFlapsPercent(25);
|
||||
}
|
||||
else if (aGroundFt < nearGround2Ft)
|
||||
{
|
||||
if (details) { details->prepend(QStringLiteral("2nd layer: ")); }
|
||||
const bool gearDown = !isLikelyTakeOffOrClimbing && (situation.getGroundSpeed() < guessedVRotate || isLikelyLanding);
|
||||
parts.setGearDown(gearDown);
|
||||
parts.setFlapsPercent(10);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (details) { details->prepend(QStringLiteral("airborne: ")); }
|
||||
parts.setGearDown(false);
|
||||
parts.setFlapsPercent(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (situation.getOnGroundDetails() != CAircraftSituation::NotSetGroundDetails)
|
||||
{
|
||||
// we have no ground elevation but a ground info
|
||||
if (situation.getOnGroundDetails() == CAircraftSituation::OnGroundByGuessing)
|
||||
{
|
||||
// should be OK
|
||||
if (details) { *details = QStringLiteral("on ground, no elv."); }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!vtol)
|
||||
{
|
||||
const bool gearDown = situation.getGroundSpeed() < guessedVRotate;
|
||||
parts.setGearDown(gearDown);
|
||||
if (details) { *details = QStringLiteral("not on ground elv., gs < ") + guessedVRotate.valueRoundedWithUnit(1); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
void CInterpolator<Derived>::logParts(const CAircraftParts &parts, int partsNo, bool empty) const
|
||||
{
|
||||
@@ -592,7 +772,7 @@ namespace BlackMisc
|
||||
}
|
||||
|
||||
// preset elevation here, as we do not know where the situation will be after the interpolation step!
|
||||
const bool preset = currentSituation.presetGroundElevation(oldSituation, newSituation, m_pastSituationsChange);
|
||||
const bool preset = presetGroundElevation(currentSituation, oldSituation, newSituation, m_pastSituationsChange);
|
||||
Q_UNUSED(preset)
|
||||
|
||||
// fetch CG once
|
||||
|
||||
@@ -30,6 +30,11 @@
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Aviation
|
||||
{
|
||||
class CAircraftSituation;
|
||||
class CAircraftSituationChange;
|
||||
}
|
||||
namespace Simulation
|
||||
{
|
||||
class CInterpolationLogger;
|
||||
@@ -309,6 +314,9 @@ namespace BlackMisc
|
||||
CInterpolationLogger *m_logger = nullptr; //!< optional interpolation logger
|
||||
QTimer m_initTimer; //!< timer to init model, will be deleted when interpolator is deleted and cancel the call
|
||||
|
||||
//! Guessed parts
|
||||
static Aviation::CAircraftParts guessParts(const Aviation::CAircraftSituation &situation, const Aviation::CAircraftSituationChange &change, const Simulation::CAircraftModel &model);
|
||||
|
||||
//! Log parts
|
||||
void logParts(const Aviation::CAircraftParts &parts, int partsNo, bool empty) const;
|
||||
|
||||
@@ -319,6 +327,13 @@ namespace BlackMisc
|
||||
//! Center of gravity, fetched from provider in case needed
|
||||
PhysicalQuantities::CLength getAndFetchModelCG(const PhysicalQuantities::CLength &dbCG);
|
||||
|
||||
//! Preset the ground elevation based on info we already have, either by transfer or elevation
|
||||
//! \remark either sets a gnd. elevation or sets it to null
|
||||
//! \remark situationToPreset position is unknown
|
||||
//! \remark situationToPreset needs to be between oldSituation and newSituation
|
||||
//! \sa CAircraftSituation::transferGroundElevation
|
||||
static bool presetGroundElevation(Aviation::CAircraftSituation &situationToPreset, const Aviation::CAircraftSituation &oldSituation, const Aviation::CAircraftSituation &newSituation, const Aviation::CAircraftSituationChange &change);
|
||||
|
||||
//! Deferred init
|
||||
void deferredInit();
|
||||
|
||||
|
||||
@@ -321,7 +321,7 @@ namespace BlackMisc
|
||||
const CAircraftSituationChange simpleChange(updatedSituations, situationCorrected.getCG(), aircraftModel.isVtol(), true, false);
|
||||
|
||||
// guess GND
|
||||
newSituationsList.front().guessOnGround(simpleChange, aircraftModel);
|
||||
simpleChange.guessOnGround(newSituationsList.front(), aircraftModel);
|
||||
}
|
||||
updatedSituations = m_situationsByCallsign[cs];
|
||||
|
||||
@@ -504,7 +504,7 @@ namespace BlackMisc
|
||||
{
|
||||
if (aircraftModel.hasCG() && !situation.hasCG()) { situation.setCG(aircraftModel.getCG()); }
|
||||
if (!situation.shouldGuessOnGround()) { return false; }
|
||||
return situation.guessOnGround(change, aircraftModel);
|
||||
return change.guessOnGround(situation, aircraftModel);
|
||||
}
|
||||
|
||||
bool CRemoteAircraftProvider::updateAircraftEnabled(const CCallsign &callsign, bool enabledForRendering)
|
||||
@@ -590,7 +590,7 @@ namespace BlackMisc
|
||||
QWriteLocker l(&m_lockSituations);
|
||||
CAircraftSituationList &situations = m_situationsByCallsign[callsign];
|
||||
if (situations.isEmpty()) { return 0; }
|
||||
updated = situations.setGroundElevationCheckedAndGuessGround(elevation, info, model, &change, &setForOnGndPosition);
|
||||
updated = setGroundElevationCheckedAndGuessGround(situations, elevation, info, model, &change, &setForOnGndPosition);
|
||||
if (updated < 1) { return 0; }
|
||||
m_situationsLastModified[callsign] = now;
|
||||
const CAircraftSituation latestSituation = situations.front();
|
||||
@@ -772,6 +772,52 @@ namespace BlackMisc
|
||||
return m_enableReverseLookupMsgs;
|
||||
}
|
||||
|
||||
int CRemoteAircraftProvider::setGroundElevationCheckedAndGuessGround(
|
||||
CAircraftSituationList &situations, const CElevationPlane &elevationPlane, CAircraftSituation::GndElevationInfo info, const CAircraftModel &model,
|
||||
CAircraftSituationChange *changeOut, bool *setForOnGroundPosition)
|
||||
{
|
||||
if (setForOnGroundPosition) { *setForOnGroundPosition = false; } // set a default
|
||||
if (elevationPlane.isNull()) { return 0; }
|
||||
if (situations.isEmpty()) { return 0; }
|
||||
|
||||
// the change has the timestamps of the latest situation
|
||||
//Q_ASSERT_X(situations.m_tsAdjustedSortHint == CAircraftSituationList::AdjustedTimestampLatestFirst || situations.isSortedAdjustedLatestFirstWithoutNullPositions(), Q_FUNC_INFO, "Need sorted situations without NULL positions");
|
||||
const CAircraftSituationChange simpleChange(situations, model.getCG(), model.isVtol(), true, false);
|
||||
int c = 0; // changed elevations
|
||||
bool latest = true;
|
||||
bool setForOnGndPosition = false;
|
||||
|
||||
for (CAircraftSituation &s : situations)
|
||||
{
|
||||
const bool set = s.setGroundElevationChecked(elevationPlane, info);
|
||||
if (set)
|
||||
{
|
||||
// simpleChange is only valid for the latest situation
|
||||
// this will do nothing if not appropriate!
|
||||
const bool guessed = (latest ? simpleChange : CAircraftSituationChange::null()).guessOnGround(s, model);
|
||||
Q_UNUSED(guessed)
|
||||
c++;
|
||||
|
||||
// if not guessed and "on ground" we mark the "elevation"
|
||||
// as an elevation for a ground position
|
||||
if (!setForOnGndPosition && s.hasInboundGroundDetails() && s.isOnGround())
|
||||
{
|
||||
setForOnGndPosition = true;
|
||||
}
|
||||
}
|
||||
latest = false; // only first pos. is "the latest" one
|
||||
}
|
||||
|
||||
if (setForOnGroundPosition) { *setForOnGroundPosition = setForOnGndPosition; }
|
||||
if (changeOut)
|
||||
{
|
||||
const CAircraftSituationChange change(situations, model.getCG(), model.isVtol(), true, true);
|
||||
*changeOut = change;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
CStatusMessageList CRemoteAircraftProvider::getAircraftPartsHistory(const CCallsign &callsign) const
|
||||
{
|
||||
QReadLocker l(&m_lockPartsHistory);
|
||||
|
||||
@@ -473,6 +473,10 @@ namespace BlackMisc
|
||||
//! \threadsafe
|
||||
ReverseLookupLogging whatToReverseLog() const;
|
||||
|
||||
//! Set ground elevation from elevation plane and guess ground
|
||||
//! \note requires a sorted list latest first
|
||||
static int setGroundElevationCheckedAndGuessGround(Aviation::CAircraftSituationList &situations, const Geo::CElevationPlane &elevationPlane, Aviation::CAircraftSituation::GndElevationInfo info, const Simulation::CAircraftModel &model, Aviation::CAircraftSituationChange *changeOut, bool *setForOnGroundPosition);
|
||||
|
||||
private:
|
||||
//! Store the latest changes
|
||||
//! \remark latest first
|
||||
|
||||
@@ -287,7 +287,7 @@ namespace BlackMisc
|
||||
CElevationPlane ISimulationEnvironmentProvider::averageElevationOfOnGroundAircraft(const CAircraftSituation &reference, const CLength &range, int minValues, int sufficientValues) const
|
||||
{
|
||||
const CCoordinateGeodeticList coordinates = this->getElevationCoordinatesOnGround();
|
||||
return coordinates.averageGeodeticHeight(reference, range, CAircraftSituationChange::allowedAltitudeDeviation(), minValues, sufficientValues);
|
||||
return coordinates.averageGeodeticHeight(reference, range, CAircraftSituation::allowedAltitudeDeviation(), minValues, sufficientValues);
|
||||
}
|
||||
|
||||
CAltitude ISimulationEnvironmentProvider::highestElevation() const
|
||||
|
||||
Reference in New Issue
Block a user