7 #include <QStringBuilder>
27 using namespace swift::config;
28 using namespace swift::misc::aviation;
29 using namespace swift::misc::geo;
30 using namespace swift::misc::math;
31 using namespace swift::misc::network;
32 using namespace swift::misc::physical_quantities;
34 namespace swift::misc::simulation
39 : m_callsign(callsign)
48 QObject::connect(&m_initTimer, &QTimer::timeout, [=] { this->deferredInit(); });
49 m_initTimer.setSingleShot(
true);
50 m_initTimer.start(2500);
84 CInterpolator::remoteAircraftSituationsAndChange(
const CInterpolationAndRenderingSetupPerCallsign &setup)
100 const CLength addValue = os * -1.0;
106 return validSituations;
143 situationToPreset.
setGroundElevation(elvDevMean.second, CAircraftSituation::SituationChange);
147 const CElevationPlane epInterpolated = CAircraftSituation::interpolatedElevation(
148 CAircraftSituation::null(), oldSituation, newSituation, distance);
149 if (!epInterpolated.
isNull())
151 situationToPreset.
setGroundElevation(epInterpolated, CAircraftSituation::Interpolated);
159 void CInterpolator::deferredInit()
173 uint32_t aircraftNumber)
177 const bool init = this->initIniterpolationStepData(currentTimeSinceEpoch, setup, aircraftNumber);
179 if (init || m_unitTest)
183 const CAircraftParts interpolatedParts = this->getInterpolatedOrGuessedParts(aircraftNumber);
184 result.
setValues(interpolatedSituation, interpolatedParts);
197 return CAircraftSituation::null();
204 const bool isValidInterpolant = interpolant.isValid();
209 bool isValidInterpolation =
false;
211 if (!isValidInterpolant) {
break; }
213 const IInterpolatorPbh &pbh = interpolant.pbh();
216 currentSituation = this->initInterpolatedSituation(pbh.getStartSituation(), pbh.getEndSituation());
219 currentSituation.
setHeading(pbh.getHeading());
220 currentSituation.
setPitch(pbh.getPitch());
221 currentSituation.
setBank(pbh.getBank());
225 const auto [interpolatedPosition, interpolatedAltitude] = interpolant.interpolatePositionAndAltitude();
226 currentSituation.
setPosition(interpolatedPosition);
227 currentSituation.
setAltitude(interpolatedAltitude);
230 const bool interpolateGndFlag = pbh.getEndSituation().hasGroundDetailsForGndInterpolation() &&
231 pbh.getStartSituation().hasGroundDetailsForGndInterpolation();
232 if (interpolateGndFlag) { currentSituation.
setOnGroundInfo(interpolant.interpolateGroundFactor()); }
234 if (currentSituation.
isNull()) {
break; }
240 if (CBuildConfig::isLocalDeveloperDebugBuild())
242 SWIFT_VERIFY_X(
false, Q_FUNC_INFO,
"Invalid interpolation situation");
244 return CAircraftSituation::null();
248 if (!interpolateGndFlag) { CAircraftSituationChange::null().guessOnGround(currentSituation,
m_model); }
272 if (!interpolateGndFlag &&
283 if (!correctedPitchOnGround.
isNull()) { currentSituation.
setPitch(correctedPitchOnGround); }
286 isValidInterpolation =
true;
290 const bool valid = isValidInterpolant && isValidInterpolation;
307 m = CStatusMessage(
this).warning(
308 u
"No situation #%1 for interpolation reported for '%2' (Interpolant: %3 interpolation: %4)")
315 m = CStatusMessage(
this).warning(u
"Invalid situation, diff. %1ms #%2 for interpolation reported "
316 u
"for '%3' (Interpolant: %4 interpolation: %5)")
354 log.altCorrection = CAircraftSituation::altitudeCorrectionToString(altCorrection);
355 log.situationCurrent = currentSituation;
356 log.interpolantRecalc = interpolant.isRecalculated();
360 log.cgAboveGround = currentSituation.
getCG();
369 return currentSituation;
381 this->logParts(emptyParts, validParts.
size(),
true);
389 const auto pivot = std::partition_point(validParts.
begin(), validParts.
end(), [=](
auto &&p) {
390 return p.getAdjustedMSecsSinceEpoch() > m_currentTimeMsSinceEpoch;
392 const auto partsNewer =
makeRange(validParts.
begin(), pivot).reverse();
393 const auto partsOlder =
makeRange(pivot, validParts.
end());
395 if (partsOlder.isEmpty()) { currentParts = *(partsNewer.begin()); }
398 currentParts = partsOlder.front();
401 this->logParts(currentParts, validParts.
size(),
false);
405 CAircraftParts CInterpolator::getInterpolatedOrGuessedParts(
int aircraftNumber)
410 const bool doInterpolation =
416 if (!doGuess && !doInterpolation)
419 return this->logAndReturnNullParts(
"neither guess nor interpolation",
true);
426 parts = this->getInterpolatedParts();
432 if (!doGuess) {
return this->logAndReturnNullParts(
"not supporting parts, and marked for guessing",
true); }
438 this->logParts(parts, 0,
false);
443 return this->logAndReturnNullParts(
"guessing, but no situation yet",
false);
452 const CAircraftParts &CInterpolator::logAndReturnNullParts(
const QString &info,
bool log)
463 const CStatusMessage m = CStatusMessage(
this).warning(u
"NULL parts reported for '%1', '%2')")
469 return CAircraftParts::null();
483 QString *details =
nullptr;
486 const bool vtol = model.
isVtol();
488 CSpeed guessedVRotate = CSpeed::null();
496 const bool isOnGround = situation.
isOnGround();
512 const CSpeed slowSpeed = guessedVRotate * 0.30;
515 if (details) { *details += u
"slow speed <" % slowSpeed.
valueRoundedWithUnit(1) % u
" on ground"; }
521 if (details) { *details += u
"faster speed >" % slowSpeed.
valueRoundedWithUnit(1) % u
" on ground"; }
530 if (details) { *details = QStringLiteral(
"no ground info"); }
539 const double pitchDeg = situation.
getPitch().
value(CAngleUnit::deg());
540 const bool isLikelyTakeOffOrClimbing =
547 if (aboveGnd.
isNull() || std::isnan(aboveGnd.
value()))
553 const double nearGround1Ft = 300;
554 const double nearGround2Ft = isLikelyTakeOffOrClimbing ? 500 : 1000;
555 const double aGroundFt = aboveGnd.
value(CLengthUnit::ft());
556 static const QString detailsInfo(
557 "above ground: %1ft near grounds: %2ft %3ft likely takeoff: %4 likely landing: %5");
561 *details = detailsInfo.arg(aGroundFt)
566 if (aGroundFt < nearGround1Ft)
568 if (details) { details->prepend(QStringLiteral(
"near ground: ")); }
572 else if (aGroundFt < nearGround2Ft)
574 if (details) { details->prepend(QStringLiteral(
"2nd layer: ")); }
575 const bool gearDown =
576 !isLikelyTakeOffOrClimbing && (situation.
getGroundSpeed() < guessedVRotate || isLikelyLanding);
582 if (details) { details->prepend(QStringLiteral(
"airborne: ")); }
595 if (details) { *details = QStringLiteral(
"on ground, no elv."); }
601 const bool gearDown = situation.
getGroundSpeed() < guessedVRotate;
616 void CInterpolator::logParts(
const CAircraftParts &parts,
int partsNo,
bool empty)
const
621 logInfo.noNetworkParts = partsNo;
623 logInfo.parts = parts;
624 logInfo.empty = empty;
630 return QStringLiteral(
"Callsign: ") %
m_callsign.
asString() % QStringLiteral(
" situations: ") %
638 bool CInterpolator::initIniterpolationStepData(qint64 currentTimeSinceEpoch,
654 if (changedSituations)
662 this->getAndFetchModelCG(CLength::null());
665 bool success =
false;
672 static const QString extraNoSituations(
"No situations, but remote aircraft '%1'");
673 static const QString extraNoRemoteAircraft(
"Unknown remote aircraft: '%1'");
684 if (!CBuildConfig::isReleaseBuild())
708 if (CBuildConfig::isLocalDeveloperDebugBuild())
714 const bool preset = presetGroundElevation(currentSituation, oldSituation, newSituation,
m_pastSituationsChange);
719 currentSituation.
setCG(cg);
720 return currentSituation;
731 this->getAndFetchModelCG(model.
getCG());
QPair< CAltitude, CAltitude > CAltitudePair
Pair of altitude.
static const QString & interpolator()
Interpolator.
static void preformatted(const CStatusMessage &statusMessage)
Sends a verbatim, preformatted message to the log.
size_type size() const
Returns number of elements in the sequence.
iterator begin()
Returns iterator at the beginning of the sequence.
void push_back(const T &value)
Appends an element at the end of the sequence.
reference front()
Access the first element.
bool isEmpty() const
Synonym for empty.
iterator end()
Returns iterator one past the end of the sequence.
int sizeInt() const
Avoid compiler warnings when using with int.
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)
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.
bool isNull() const
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 encapsulating a list of aircraft parts.
Value object about changes in situations.
bool hasSceneryDeviation() const
Scenery deviation available?
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?
physical_quantities::CLength getGuessedSceneryDeviationCG() const
Get scenery deviation under consideration of CG.
Value object encapsulating a list of aircraft parts.
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.
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.
bool transferGroundElevationFromMe(CAircraftSituation &transferToSituation, const physical_quantities::CLength &radius=geo::CElevationPlane::singlePointRadius()) const
Transfer from "this" situation to otherSituation.
void setBank(const physical_quantities::CAngle &bank)
Set bank (angle)
void setHeading(const CHeading &heading)
Set heading.
aviation::COnGroundInfo getOnGroundInfo() const
On ground info.
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)
bool setGroundElevationChecked(const geo::CElevationPlane &elevationPlane, GndElevationInfo info, bool transferred=false)
Set elevation of the ground directly beneath, but checked.
void setAltitude(const CAltitude &altitude)
Set altitude.
bool isOnGround() const
Is on ground?
bool canLikelySkipNearGroundInterpolation() const
Situation looks like an aircraft not near ground.
const CCallsign & getCallsign() const
Corresponding callsign.
const physical_quantities::CSpeed & getGroundSpeed() const
Get ground speed.
void setOnGroundInfo(const aviation::COnGroundInfo &info)
Set the on ground info.
CAircraftLights guessLights() const
Guessed lights.
void setPitch(const physical_quantities::CAngle &pitch)
Set pitch.
virtual bool isNull() const
Null situation.
const physical_quantities::CAngle & getPitch() const
Get pitch.
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 physical_quantities::CLength & getCG() const
Get CG if any.
void setNull()
Set to null.
physical_quantities::CLength getHeightAboveGround() const
Height above ground.
void setPosition(const geo::CCoordinateGeodetic &position)
Set position.
List of aircraft situations.
int addAltitudeOffset(const physical_quantities::CLength &offset)
Add an offset to each altitude.
bool isSortedAdjustedLatestFirstWithoutNullPositions() const
Latest first and no null positions?
Value object encapsulating information of a callsign.
const QString & asString() const
Get callsign (normalized)
bool isEmpty() const
Is empty?
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.
Plane of same elevation, can be a single point or larger area (e.g. airport)
virtual 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 angle (radians, degrees)
Physical unit length (length)
bool isNull() const
Is quantity null?
double value(MU unit) const
Value in given unit.
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.
const QString & getModelString() const
Model key, either queried or loaded from simulator model.
void setCallsign(const aviation::CCallsign &callsign)
Corresponding callsign if applicable.
bool isVtol() const
VTOL aircraft?
const physical_quantities::CLength & getCG() const
Get center of gravity.
void setCG(const physical_quantities::CLength &cg)
Get center of gravity.
const aviation::CAircraftIcaoCode & getAircraftIcaoCode() const
Aircraft ICAO code.
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?
bool logInterpolation() const
Log.interpolation.
bool isAircraftPartsEnabled() const
Aircraft parts enabled (still requires the other aircraft to send parts)
const physical_quantities::CAngle & getPitchOnGround() const
Force a given pitch on ground.
Value object for interpolator and rendering per callsign.
Record internal state of interpolator for debugging.
void logInterpolation(const SituationLog &log)
Log current interpolation cycle, only stores in memory, for performance reasons.
void logParts(const PartsLog &log)
Log current parts cycle, only stores in memory, for performance reasons.
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.
void setSameSituation(bool same)
Interpolating between 2 same situations?
void setInterpolatedAndCheckSituation(bool succeeded, const aviation::CAircraftSituation &situation)
Set succeeded.
bool isInterpolated() const
Did interpolation succeed?
void setSituationsCount(int count)
Set situations count.
void setExtraInfo(const QString &info)
Extra info.
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
static const QStringList & getLogCategories()
Log categories.
const physical_quantities::CLength & getModelCG() const
Center of gravity.
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
virtual const IInterpolant & getInterpolant(SituationLog &log)=0
Get the interpolant for the given time point.
bool hasAttachedLogger() const
Is logger attached?
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.
void setReusedParts(bool reused)
Mark as reused.
void setSupportsParts(bool supports)
Set support flag.
bool isSupportingParts() const
Supporting parts.
bool isAircraftInRange(const aviation::CCallsign &callsign) const
Is aircraft in range?
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.
IRemoteAircraftProvider * getRemoteAircraftProvider() const
Get the aircraft provider.
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.
auto makeRange(I begin, I2 end) -> CRange< I >
Returns a CRange constructed from begin and end iterators of deduced types.
SWIFT_MISC_EXPORT const QString & boolToTrueFalse(bool v)
Bool to true/false.
SWIFT_MISC_EXPORT const QString & boolToYesNo(bool v)
Bool to yes/no.
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.