9#include <QStringBuilder>
29using namespace swift::config;
30using namespace swift::misc::aviation;
31using namespace swift::misc::geo;
32using namespace swift::misc::math;
33using namespace swift::misc::network;
34using namespace swift::misc::physical_quantities;
36namespace swift::misc::simulation
57 m_initTimer.setSingleShot(
true);
58 m_initTimer.start(2500);
91 CAircraftSituationList
108 const CLength addValue = os * -1.0;
117 return validSituations;
120 bool CInterpolator::presetGroundElevation(CAircraftSituation &situationToPreset,
121 const CAircraftSituation &oldSituation,
122 const CAircraftSituation &newSituation,
123 const CAircraftSituationChange &change)
161 if (!epInterpolated.
isNull())
171 void CInterpolator::deferredInit()
188 uint32_t aircraftNumber)
192 const bool init = this->initIniterpolationStepData(currentTimeSinceEpoch, setup, aircraftNumber);
194 if (init || m_unitTest)
198 const CAircraftParts interpolatedParts = this->getInterpolatedOrGuessedParts(aircraftNumber);
199 result.
setValues(interpolatedSituation, interpolatedParts);
219 const bool isValidInterpolant = interpolant.isValid();
224 bool isValidInterpolation =
false;
227 if (!isValidInterpolant)
232 const IInterpolatorPbh &pbh = interpolant.pbh();
235 currentSituation = this->initInterpolatedSituation(pbh.getStartSituation(), pbh.getEndSituation());
238 currentSituation.
setHeading(pbh.getHeading());
239 currentSituation.
setPitch(pbh.getPitch());
240 currentSituation.
setBank(pbh.getBank());
244 const auto [interpolatedPosition, interpolatedAltitude] = interpolant.interpolatePositionAndAltitude();
245 currentSituation.
setPosition(interpolatedPosition);
246 currentSituation.
setAltitude(interpolatedAltitude);
249 const bool interpolateGndFlag = pbh.getEndSituation().hasGroundDetailsForGndInterpolation() &&
250 pbh.getStartSituation().hasGroundDetailsForGndInterpolation();
251 if (interpolateGndFlag)
253 currentSituation.
setOnGroundInfo(interpolant.interpolateGroundFactor());
256 if (currentSituation.
isNull())
267 SWIFT_VERIFY_X(
false, Q_FUNC_INFO,
"Invalid interpolation situation");
273 if (!interpolateGndFlag)
284 if (!
m_lastSituation.transferGroundElevationFromMe(currentSituation, radius))
292 const CElevationPlane groundElevation =
300 if (!interpolateGndFlag &&
310 const CAngle correctedPitchOnGround =
m_currentSetup.getPitchOnGround();
311 if (!correctedPitchOnGround.
isNull())
313 currentSituation.
setPitch(correctedPitchOnGround);
317 isValidInterpolation =
true;
321 const bool valid = isValidInterpolant && isValidInterpolation;
338 m = CStatusMessage(
this).
warning(
339 u
"No situation #%1 for interpolation reported for '%2' (Interpolant: %3 interpolation: %4)")
346 m = CStatusMessage(
this).
warning(u
"Invalid situation, diff. %1ms #%2 for interpolation reported "
347 u
"for '%3' (Interpolant: %4 interpolation: %5)")
386 log.situationCurrent = currentSituation;
387 log.interpolantRecalc = interpolant.isRecalculated();
391 log.cgAboveGround = currentSituation.
getCG();
396 m_logger->logInterpolation(log);
400 return currentSituation;
403 CAircraftParts CInterpolator::getInterpolatedParts()
411 static const CAircraftParts emptyParts;
412 this->logParts(emptyParts, validParts.
size(),
true);
417 CAircraftParts currentParts;
420 const auto pivot = std::ranges::partition_point(
422 const auto partsNewer =
makeRange(validParts.
begin(), pivot).reverse();
423 const auto partsOlder =
makeRange(pivot, validParts.
end());
425 if (partsOlder.isEmpty())
427 currentParts = *(partsNewer.begin());
431 currentParts = partsOlder.front();
434 this->logParts(currentParts, validParts.
size(),
false);
438 CAircraftParts CInterpolator::getInterpolatedOrGuessedParts(
int aircraftNumber)
442 const bool needParts = m_unitTest ||
m_lastParts.isNull();
443 const bool doInterpolation =
449 if (!doGuess && !doInterpolation)
452 return this->logAndReturnNullParts(
"neither guess nor interpolation",
true);
459 parts = this->getInterpolatedParts();
467 return this->logAndReturnNullParts(
"not supporting parts, and marked for guessing",
true);
474 this->logParts(parts, 0,
false);
479 return this->logAndReturnNullParts(
"guessing, but no situation yet",
false);
488 const CAircraftParts &CInterpolator::logAndReturnNullParts(
const QString &info,
bool log)
499 const CStatusMessage m = CStatusMessage(
this).
warning(u
"NULL parts reported for '%1', '%2')")
525 const bool vtol = model.
isVtol();
536 const bool isOnGround = situation.
isOnGround();
538 (!isOnGround || situation.
isMoving()) ? 100 : 0);
553 const CSpeed slowSpeed = guessedVRotate * 0.30;
579 *details = QStringLiteral(
"no ground info");
590 const bool isLikelyTakeOffOrClimbing =
597 if (aboveGnd.
isNull() || std::isnan(aboveGnd.
value()))
603 const double nearGround1Ft = 300;
604 const double nearGround2Ft = isLikelyTakeOffOrClimbing ? 500 : 1000;
606 static const QString detailsInfo(
607 "above ground: %1ft near grounds: %2ft %3ft likely takeoff: %4 likely landing: %5");
611 *details = detailsInfo.
arg(aGroundFt)
616 if (aGroundFt < nearGround1Ft)
620 details->
prepend(QStringLiteral(
"near ground: "));
625 else if (aGroundFt < nearGround2Ft)
629 details->
prepend(QStringLiteral(
"2nd layer: "));
631 const bool gearDown =
632 !isLikelyTakeOffOrClimbing && (situation.
getGroundSpeed() < guessedVRotate || isLikelyLanding);
640 details->
prepend(QStringLiteral(
"airborne: "));
656 *details = QStringLiteral(
"on ground, no elv.");
663 const bool gearDown = situation.
getGroundSpeed() < guessedVRotate;
678 void CInterpolator::logParts(
const CAircraftParts &parts,
int partsNo,
bool empty)
const
686 logInfo.noNetworkParts = partsNo;
688 logInfo.parts = parts;
689 logInfo.empty = empty;
690 m_logger->logParts(logInfo);
695 return QStringLiteral(
"Callsign: ") %
m_callsign.asString() % QStringLiteral(
" situations: ") %
703 bool CInterpolator::initIniterpolationStepData(qint64 currentTimeSinceEpoch,
719 if (changedSituations)
730 bool success =
false;
737 static const QString extraNoSituations(
"No situations, but remote aircraft '%1'");
738 static const QString extraNoRemoteAircraft(
"Unknown remote aircraft: '%1'");
740 (inRange ? extraNoSituations : extraNoRemoteAircraft).arg(
m_callsign.asString()));
751 Q_ASSERT_X(
m_currentSituations.isSortedAdjustedLatestFirstWithoutNullPositions(), Q_FUNC_INFO,
761 CAircraftSituation CInterpolator::initInterpolatedSituation(
const CAircraftSituation &oldSituation,
762 const CAircraftSituation &newSituation)
const
782 const bool preset = presetGroundElevation(currentSituation, oldSituation, newSituation,
m_pastSituationsChange);
787 currentSituation.
setCG(cg);
788 return currentSituation;
805 this->getAndFetchModelCG(model.
getCG());
QPair< CAltitude, CAltitude > CAltitudePair
Pair of altitude.
static CAngleUnit deg()
Degrees.
static constexpr bool isReleaseBuild()
Release build?
static bool isLocalDeveloperDebugBuild()
Local build for developers.
static const QString & interpolator()
Interpolator.
static void preformatted(const CStatusMessage &statusMessage)
Sends a verbatim, preformatted message to the log.
bool isEmpty() const
Message empty.
Derived & warning(const char16_t(&format)[N])
Set the severity to warning, providing a format string.
size_type size() const
Returns number of elements in the sequence.
iterator begin()
Returns iterator at the beginning of the sequence.
bool isEmpty() const
Synonym for empty.
iterator end()
Returns iterator one past the end of the sequence.
qint64 getMSecsSinceEpoch() const
Timestamp as ms value.
void setMSecsSinceEpoch(qint64 mSecsSinceEpoch)
Timestamp as ms value.
qint64 getAdjustedMSecsSinceEpoch() const
Timestamp with offset added for interpolation.
qint64 getTimeOffsetMs() const
Milliseconds to add to timestamp for interpolation.
void setTimeOffsetMs(qint64 offset)
Milliseconds to add to timestamp for interpolation.
Value object encapsulating a list of aircraft engines.
void initEngines(int engineNumber, bool on, int engineRpmPercentage)
Init some engines.
void guessModelParameters(physical_quantities::CLength &guessedCGOut, physical_quantities::CSpeed &guessedVRotateOut) const
Guess aircraft model parameters.
Value object encapsulating information of aircraft's parts.
static const CAircraftParts & null()
NULL parts object.
void setEngines(const CAircraftEngineList &engines)
Set engines.
void setGearDown(bool down)
Set gear down.
void setPartsDetails(PartsDetails details)
Set parts details.
void setLights(const CAircraftLights &lights)
Set aircraft lights.
void setFlapsPercent(int flapsPercent)
Set flaps position in percent.
void setSpoilersOut(bool out)
Set spoilers out.
Value object about changes in situations.
bool isConstDescending() const
Constantly descending?
bool isConstAscending() const
Constantly ascending?
CAltitudePair getElevationStdDevAndMean() const
Elevation standard deviation and mean.
bool hasElevationDevWithinAllowedRange() const
Elevation within CAircraftSituation::allowedAltitudeDeviation range.
bool isConstDecelarating() const
Constantly decelarating?
bool isRotatingUp() const
Is rotating up?
static const CAircraftSituationChange & null()
NULL object.
bool guessOnGround(CAircraftSituation &situation, const simulation::CAircraftModel &model) const
Guess on ground flag.
CAircraftSituationChange indexOrNull(int index) const
Index or NULL.
Value object encapsulating information of an aircraft's situation.
AltitudeCorrection correctAltitude(bool enableDragToGround=true)
Set the corrected altitude from CAircraftSituation::getCorrectedAltitude.
void setCallsign(const CCallsign &callsign)
Corresponding callsign.
void resetGroundElevation()
Reset ground elevation.
bool hasGroundElevation() const
Is ground elevation value available.
void setCG(const physical_quantities::CLength &cg)
Set CG.
void setGroundSpeed(const physical_quantities::CSpeed &groundspeed)
Set ground speed.
const physical_quantities::CLength & getCG() const
Get CG if any.
physical_quantities::CLength getDistancePerTime250ms(const physical_quantities::CLength &min=physical_quantities::CLength::null()) const
Distance per milliseconds (250ms).
bool setGroundElevation(const aviation::CAltitude &altitude, GndElevationInfo info, bool transferred=false)
Elevation of the ground directly beneath at the given situation.
void setBank(const physical_quantities::CAngle &bank)
Set bank (angle).
void setHeading(const CHeading &heading)
Set heading.
aviation::COnGroundInfo getOnGroundInfo() const
On ground info.
static const QString & altitudeCorrectionToString(AltitudeCorrection correction)
Enum to string.
AltitudeCorrection
How was altitude corrected?
bool transferGroundElevationToMe(const CAircraftSituation &fromSituation, const physical_quantities::CLength &radius, bool transferred)
Transfer ground elevation from given situation (to me).
@ SituationChange
from swift::misc::aviation::CAircraftSituationChange
@ Interpolated
interpolated between 2 elevations
void setAltitude(const CAltitude &altitude)
Set altitude.
static const CAircraftSituation & null()
Null situation.
bool isOnGround() const
Is on ground?
bool canLikelySkipNearGroundInterpolation() const
Situation looks like an aircraft not near ground.
void setOnGroundInfo(const aviation::COnGroundInfo &info)
Set the on ground info.
CAircraftLights guessLights() const
Guessed lights.
const physical_quantities::CAngle & getPitch() const
Get pitch.
void setPitch(const physical_quantities::CAngle &pitch)
Set pitch.
bool isNull() const
Null situation.
const physical_quantities::CSpeed & getGroundSpeed() const
Get ground speed.
bool interpolateElevation(const aviation::CAircraftSituation &oldSituation, const aviation::CAircraftSituation &newSituation)
Interpolate "this" elevation from the two adjacent positions.
bool isMoving() const
Is moving? Means ground speed > epsilon.
const CCallsign & getCallsign() const
Corresponding callsign.
static geo::CElevationPlane interpolatedElevation(const CAircraftSituation &situation, const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation, const physical_quantities::CLength &distance=physical_quantities::CLength::null())
Interpolate between the 2 situations for situation.
physical_quantities::CLength getHeightAboveGround() const
Height above ground.
void setPosition(const geo::CCoordinateGeodetic &position)
Set position.
int addAltitudeOffset(const physical_quantities::CLength &offset)
Add an offset to each altitude.
Value object encapsulating information of a callsign.
bool isEmpty() const
Is empty?
@ OnGroundByGuessing
weakest
@ NotSetGroundDetails
not set or unknown if correct (e.g.
double getGroundFactor() const
Get the ground factor Use this for interpolation only!! For just checking if the info is OnGround or ...
OnGroundDetails getGroundDetails() const
Get ground details.
static const physical_quantities::CLength & singlePointRadius()
Radius for single point.
bool isNull() const
Existing value?
bool hasMSLGeodeticHeight() const
Geodetic height not null and aviation::CAltitude::MeanSeaLevel.
physical_quantities::CLength calculateGreatCircleDistance(const ICoordinateGeodetic &otherCoordinate) const
Great circle distance.
bool isValidVectorRange() const
Check values.
bool equalNormalVectorDouble(const std::array< double, 3 > &otherVector) const
Is equal? Epsilon considered.
Physical unit length (length).
static CLengthUnit ft()
Foot ft.
bool isNull() const
Is quantity null?
double value(MU unit) const
Value in given unit.
static const CLength & null()
QString valueRoundedWithUnit(const MU &unit, int digits=-1, bool withGroupSeparator=false, bool i18n=false) const
Value to QString with the given unit, e.g. "5.00m".
Aircraft model (used by another pilot, my models on disk).
const aviation::CCallsign & getCallsign() const
Corresponding callsign if applicable.
bool isVtol() const
VTOL aircraft?
const physical_quantities::CLength & getCG() const
Get center of gravity.
const QString & getModelString() const
Model key, either queried or loaded from simulator model.
int getEngineCount() const
Engine count if any, -1 if no value is set.
bool hasCG() const
CG value available?
bool hasModelString() const
Non empty model string?
const aviation::CAircraftIcaoCode & getAircraftIcaoCode() const
Aircraft ICAO code.
Value object for interpolator and rendering per callsign.
Record internal state of interpolator for debugging.
void setValues(const aviation::CAircraftSituation &situation, const aviation::CAircraftParts &parts)
Set values.
void setStatus(const CInterpolationStatus &interpolation, const CPartsStatus &parts)
Set status values.
void setInterpolationSetupProvider(IInterpolationSetupProvider *provider)
Provider.
bool isInterpolated() const
Did interpolation succeed?
int m_partsToSituationGuessingRatio
ratio between parts guessing and situation interpolation
int m_partsToSituationInterpolationRatio
ratio between parts and situation interpolation, 1..always, 2..every 2nd situation
qint64 m_situationsLastModified
when situations were last modified
bool doLogging() const
Do logging.
aviation::CAircraftParts m_lastParts
latest parts
CInterpolator(const aviation::CCallsign &callsign, ISimulationEnvironmentProvider *simEnvProvider, IInterpolationSetupProvider *setupProvider, IRemoteAircraftProvider *remoteProvider, CInterpolationLogger *logger)
Constructor.
const physical_quantities::CLength & getModelCG() const
Center of gravity.
static const QStringList & getLogCategories()
Log categories.
CInterpolationStatus m_currentInterpolationStatus
this step's situation status
physical_quantities::CLength m_currentSceneryOffset
calculated scenery offset if any
CInterpolationResult getInterpolation(qint64 currentTimeSinceEpoch, const CInterpolationAndRenderingSetupPerCallsign &setup, uint32_t aircraftNumber)
Get interpolated situation.
CInterpolationAndRenderingSetupPerCallsign m_currentSetup
used setup
CPartsStatus m_currentPartsStatus
this step's parts status
aviation::CAircraftSituation m_lastSituation
latest interpolation
void attachLogger(CInterpolationLogger *logger)
Attach an observer to read the interpolator's state for debugging.
void resetLastInterpolation()
Reset last interpolation to null.
qint64 m_currentTimeMsSinceEpoch
current time
int m_interpolatedSituationsCounter
counter for each interpolated situations: used for statistics, every n-th interpolation ....
aviation::CAircraftSituationChange m_pastSituationsChange
situations change of provider (i.e.
CStatusMessageList m_interpolationMessages
interpolation messages
QString getInterpolatorInfo() const
Get an interpolator info string (for debug info).
CPartsStatus m_lastPartsStatus
status for last parts, used when last parts are re-used because of m_partsToSituationInterpolationRat...
aviation::CAircraftSituationList m_currentSituations
current situations obtained by remoteAircraftSituationsAndChange
const aviation::CCallsign m_callsign
corresponding callsign
bool hasAttachedLogger() const
Is logger attached?
virtual const IInterpolant & getInterpolant(SituationLog &log)=0
Get the interpolant for the given time point.
void markAsUnitTest()
Mark as unit test.
qint64 m_lastInvalidLogTs
last invalid situation timestamp
int m_invalidSituations
mainly when there are no new situations
CAircraftModel m_model
corresponding model (required for CG)
void initCorrespondingModel(const CAircraftModel &model={})
Init, or re-init the corressponding model.
bool isAircraftInRange(const aviation::CCallsign &callsign) const
Is aircraft in range?
IRemoteAircraftProvider * getRemoteAircraftProvider() const
Get the aircraft provider.
aviation::CAircraftSituationList remoteAircraftSituations(const aviation::CCallsign &callsign) const
Rendered aircraft situations (per callsign, time history).
qint64 situationsLastModified(const aviation::CCallsign &callsign) const
When last modified.
CSimulatedAircraft getAircraftInRangeForCallsign(const aviation::CCallsign &callsign) const
Aircraft for callsign.
void setRemoteAircraftProvider(IRemoteAircraftProvider *remoteAircraftProvider)
Set remote aircraft provider.
aviation::CAircraftPartsList remoteAircraftParts(const aviation::CCallsign &callsign) const
All parts (per callsign, time history).
aviation::CAircraftSituationChangeList remoteAircraftSituationChanges(const aviation::CCallsign &callsign) const
Aircraft changes.
bool isRemoteAircraftSupportingParts(const aviation::CCallsign &callsign) const
Is remote aircraft supporting parts?
int remoteAircraftSituationsCount(const aviation::CCallsign &callsign) const
Number of remote aircraft situations for callsign.
int remoteAircraftPartsCount(const aviation::CCallsign &callsign) const
All parts (per callsign, time history).
const simulation::CAircraftModel & getModel() const
Get model (model used for mapping).
physical_quantities::CLength getSimulatorOrDbCG(const aviation::CCallsign &callsign, const physical_quantities::CLength &dbCG) const
Get CG per callsign, NULL if not found.
geo::CElevationPlane findClosestElevationWithinRange(const geo::ICoordinateGeodetic &reference, const physical_quantities::CLength &range) const
Find closest elevation (or return NULL).
QString getElevationsFoundMissedInfo() const
Elevations found/missed statistics info as string.
void setSimulationEnvironmentProvider(ISimulationEnvironmentProvider *provider)
Set the provider.
Direct in memory access to interpolation setup, normally implemented by simulator.
Direct thread safe in memory access to remote aircraft.
virtual physical_quantities::CLength getCGFromDB(const aviation::CCallsign &callsign) const =0
CG values from DB.
static constexpr int MaxSituationsPerCallsign
How many situations we keep per callsign.
virtual void rememberCGFromDB(const physical_quantities::CLength &cgFromDB, const aviation::CCallsign &callsign)=0
CG values from DB.
Direct in memory access to elevation data.
SWIFT_MISC_EXPORT const QString & boolToTrueFalse(bool v)
Bool to true/false.
SWIFT_MISC_EXPORT const QString & boolToYesNo(bool v)
Bool to yes/no.
auto makeRange(I begin, I2 end) -> CRange< I >
Returns a CRange constructed from begin and end iterators of deduced types.
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QString arg(Args &&... args) const const
QString number(double n, char format, int precision)
QString & prepend(QChar ch)
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.