diff --git a/src/blackcore/simulator.h b/src/blackcore/simulator.h index cccd953b7..139ce59f1 100644 --- a/src/blackcore/simulator.h +++ b/src/blackcore/simulator.h @@ -336,7 +336,9 @@ namespace BlackCore //! \param ownAircraftProvider in memory access to own aircraft data //! \param remoteAircraftProvider in memory access to rendered aircraft data such as situation history and aircraft itself //! \param weatherGridProvider in memory access to weather grid data + //! \param clientProvider in memory access to client data //! \return driver instance + //! virtual ISimulator *create( const BlackMisc::Simulation::CSimulatorPluginInfo &info, BlackMisc::Simulation::IOwnAircraftProvider *ownAircraftProvider, diff --git a/src/blackmisc/simulation/interpolator.cpp b/src/blackmisc/simulation/interpolator.cpp index 111af59a5..64ed1ffe0 100644 --- a/src/blackmisc/simulation/interpolator.cpp +++ b/src/blackmisc/simulation/interpolator.cpp @@ -37,16 +37,16 @@ namespace BlackMisc template CInterpolator::CInterpolator(const CCallsign &callsign, ISimulationEnvironmentProvider *simEnvProvider, IInterpolationSetupProvider *setupProvider, - IRemoteAircraftProvider *remoteAircraftProvider, + IRemoteAircraftProvider *remoteProvider, CInterpolationLogger *logger) : m_callsign(callsign) { // normally when created m_cg is still null since there is no CG in the provider yet if (simEnvProvider) { this->setSimulationEnvironmentProvider(simEnvProvider); } if (setupProvider) { this->setInterpolationSetupProvider(setupProvider); } - if (remoteAircraftProvider) + if (remoteProvider) { - this->setRemoteAircraftProvider(remoteAircraftProvider); + this->setRemoteAircraftProvider(remoteProvider); QObject::connect(&m_initTimer, &QTimer::timeout, [ = ] { this->deferredInit(); }); m_initTimer.setSingleShot(true); m_initTimer.start(2500); @@ -75,13 +75,13 @@ namespace BlackMisc CAircraftSituationList CInterpolator::remoteAircraftSituationsAndChange(bool useSceneryOffset) { CAircraftSituationList validSituations = this->remoteAircraftSituations(m_callsign); - m_situationChange = CAircraftSituationChange(validSituations, true, true); - if (useSceneryOffset && m_situationChange.hasSceneryDeviation() && m_model.hasCG()) + m_currentSituationChange = CAircraftSituationChange(validSituations, true, true); + if (useSceneryOffset && m_currentSituationChange.hasSceneryDeviation() && m_model.hasCG()) { - const CLength os = m_situationChange.getGuessedSceneryDeviation(m_model.getCG()); + const CLength os = m_currentSituationChange.getGuessedSceneryDeviation(m_model.getCG()); validSituations.addAltitudeOffset(os); - m_situationChange = CAircraftSituationChange(validSituations, true, true); // recalculate - m_lastSceneryOffset = os; + m_currentSituationChange = CAircraftSituationChange(validSituations, true, true); // recalculate + m_currentSceneryOffset = os; } return validSituations; } @@ -131,33 +131,36 @@ namespace BlackMisc return cats; } - template - CAircraftSituation CInterpolator::getInterpolatedSituation( - qint64 currentTimeMsSinceEpoc, - const CInterpolationAndRenderingSetupPerCallsign &setup, - CInterpolationStatus &status) + template + CInterpolationResult CInterpolator::getInterpolation(qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup) { - Q_ASSERT_X(!m_callsign.isEmpty(), Q_FUNC_INFO, "Missing callsign"); - - // this code is used by linear and spline interpolator - m_interpolatedSituationsCounter++; - status.reset(); - SituationLog log; - const bool doLogging = this->hasAttachedLogger() && setup.logInterpolation(); - - // any data at all? - const CAircraftSituationList situations = this->remoteAircraftSituations(m_callsign); - const int situationsCount = situations.size(); - status.setSituationsCount(situationsCount); - if (situations.isEmpty()) + CInterpolationResult result; + do { - status.setExtraInfo(this->isAircraftInRange(m_callsign) ? - QString("No situations, but remote aircraft '%1'").arg(m_callsign.asString()) : - QString("Unknown remote aircraft: '%1'").arg(m_callsign.asString())); - return CAircraftSituation(m_callsign); + if (!this->initIniterpolationStepData(currentTimeSinceEpoc, setup)) { break; } + + // make sure we can also interpolate parts only (needed in unit tests for instance) + const CAircraftSituation interpolatedSituation = this->getInterpolatedSituation(); + const CAircraftParts interpolatedParts = this->getInterpolatedOrGuessedParts(); + + result.setValues(interpolatedSituation, interpolatedParts); + } + while (false); + + result.setStatus(m_currentInterpolationStatus, m_currentPartsStatus); + return result; + } + + template + CAircraftSituation CInterpolator::getInterpolatedSituation() + { + if (m_currentSituations.isEmpty()) + { + m_lastInterpolation = CAircraftSituation::null(); + return CAircraftSituation::null(); } - const CAircraftSituation latest = situations.front(); + const CAircraftSituation latest = m_currentSituations.front(); CAircraftSituation currentSituation = m_lastInterpolation.isNull() ? latest : m_lastInterpolation; if (currentSituation.getCallsign() != m_callsign) { @@ -173,20 +176,18 @@ namespace BlackMisc } // fetch CG once - const CLength cg = latest.hasCG() ? latest.getCG() : this->getAndFetchModelCG(); + const CLength cg(this->getModelCG()); currentSituation.setCG(cg); - // data, split situations by time - if (currentTimeMsSinceEpoc < 0) { currentTimeMsSinceEpoc = QDateTime::currentMSecsSinceEpoch(); } - // interpolant function from derived class // CInterpolatorLinear::Interpolant or CInterpolatorSpline::Interpolant - const auto interpolant = derived()->getInterpolant(currentTimeMsSinceEpoc, setup, status, log); + SituationLog log; + const auto interpolant = derived()->getInterpolant(log); // succeeded so far? - if (!status.isInterpolated()) + if (!m_currentInterpolationStatus.isInterpolated()) { - status.checkIfValidSituation(currentSituation); + m_currentInterpolationStatus.checkIfValidSituation(currentSituation); return currentSituation; } @@ -212,20 +213,20 @@ namespace BlackMisc } // status - status.setInterpolatedAndCheckSituation(true, currentSituation); + m_currentInterpolationStatus.setInterpolatedAndCheckSituation(true, currentSituation); // logging - if (doLogging) + if (this->doLogging()) { static const QString elv("found %1 missed %2"); const QPair elvStats = this->getElevationsFoundMissed(); - log.tsCurrent = currentTimeMsSinceEpoc; + log.tsCurrent = m_currentTimeMsSinceEpoch; log.callsign = m_callsign; log.groundFactor = currentSituation.getOnGroundFactor(); log.altCorrection = CAircraftSituation::altitudeCorrectionToString(altCorrection); log.situationCurrent = currentSituation; - log.change = m_situationChange; - log.usedSetup = setup; + log.change = m_currentSituationChange; + log.usedSetup = m_currentSetup; log.elevationInfo = elv.arg(elvStats.first).arg(elvStats.second); log.cgAboveGround = cg; log.sceneryOffset = m_currentSceneryOffset; @@ -238,14 +239,9 @@ namespace BlackMisc } template - CAircraftParts CInterpolator::getInterpolatedParts( - qint64 currentTimeMsSinceEpoch, - const CInterpolationAndRenderingSetupPerCallsign &setup, CPartsStatus &partsStatus, bool log) const + CAircraftParts CInterpolator::getInterpolatedParts() { // (!) this code is used by linear and spline interpolator - Q_UNUSED(setup); - partsStatus.reset(); - if (currentTimeMsSinceEpoch < 0) { currentTimeMsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); } // Parts are supposed to be in correct order, latest first const CAircraftPartsList validParts = this->remoteAircraftParts(m_callsign); @@ -254,16 +250,16 @@ namespace BlackMisc if (validParts.isEmpty()) { static const CAircraftParts emptyParts; - this->logParts(currentTimeMsSinceEpoch, emptyParts, validParts.size(), true, log); + this->logParts(emptyParts, validParts.size(), true); return emptyParts; } - partsStatus.setSupportsParts(true); + m_currentPartsStatus.setSupportsParts(true); CAircraftParts currentParts; do { // find the first parts earlier than the current time - const auto pivot = std::partition_point(validParts.begin(), validParts.end(), [ = ](auto &&p) { return p.getAdjustedMSecsSinceEpoch() > currentTimeMsSinceEpoch; }); + const auto pivot = std::partition_point(validParts.begin(), validParts.end(), [ = ](auto &&p) { return p.getAdjustedMSecsSinceEpoch() > m_currentTimeMsSinceEpoch; }); const auto partsNewer = makeRange(validParts.begin(), pivot).reverse(); const auto partsOlder = makeRange(pivot, validParts.end()); @@ -273,32 +269,38 @@ namespace BlackMisc } while (false); - this->logParts(currentTimeMsSinceEpoch, currentParts, validParts.size(), false, log); + this->logParts(currentParts, validParts.size(), false); return currentParts; } template - CAircraftParts CInterpolator::getInterpolatedOrGuessedParts(qint64 currentTimeMsSinceEpoch, const CInterpolationAndRenderingSetupPerCallsign &setup, CPartsStatus &partsStatus, bool log) const + CAircraftParts CInterpolator::getInterpolatedOrGuessedParts() { CAircraftParts parts; - if (setup.isAircraftPartsEnabled()) { parts = this->getInterpolatedParts(currentTimeMsSinceEpoch, setup, partsStatus, log); } - if (!partsStatus.isSupportingParts()) + if (m_currentSetup.isAircraftPartsEnabled()) { parts = this->getInterpolatedParts(); } + if (!m_currentPartsStatus.isSupportingParts()) { // check if model has been thru model matching - parts.guessParts(this->getLastInterpolatedSituation(), m_situationChange, m_model); + parts.guessParts(m_lastInterpolation, m_currentSituationChange, m_model); } - this->logParts(currentTimeMsSinceEpoch, parts, 0, false, log); + this->logParts(parts, 0, false); return parts; } template - void CInterpolator::logParts(qint64 timestamp, const CAircraftParts &parts, int partsNo, bool empty, bool log) const + bool CInterpolator::doLogging() const { - if (!log || !m_logger) { return; } + return this->hasAttachedLogger() && m_currentSetup.logInterpolation(); + } + + template + void CInterpolator::logParts(const CAircraftParts &parts, int partsNo, bool empty) const + { + if (!this->doLogging()) { return; } PartsLog logInfo; logInfo.callsign = m_callsign; logInfo.noNetworkParts = partsNo; - logInfo.tsCurrent = timestamp; + logInfo.tsCurrent = m_currentTimeMsSinceEpoch; logInfo.parts = parts; logInfo.empty = empty; m_logger->logParts(logInfo); @@ -328,6 +330,57 @@ namespace BlackMisc { this->resetLastInterpolation(); m_model = CAircraftModel(); + m_currentSceneryOffset = CLength::null(); + m_currentSituationChange = CAircraftSituationChange::null(); + m_currentSituations.clear(); + m_currentTimeMsSinceEpoch = -1; + m_situationsLastModified = -1; + m_situationsLastModifiedUsed = -1; + m_currentInterpolationStatus.reset(); + m_currentPartsStatus.reset(); + m_interpolatedSituationsCounter = 0; + } + + template + bool CInterpolator::initIniterpolationStepData(qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup) + { + Q_ASSERT_X(!m_callsign.isEmpty(), Q_FUNC_INFO, "Missing callsign"); + + const bool slowUpdates = ((m_interpolatedSituationsCounter % 25) == 0); + m_currentTimeMsSinceEpoch = currentTimeSinceEpoc; + m_situationsLastModified = this->situationsLastModified(m_callsign); + m_currentSetup = setup; + m_currentSituations = this->remoteAircraftSituationsAndChange(true); + m_currentInterpolationStatus.reset(); + m_currentPartsStatus.reset(); + + if (!m_model.hasCG() || slowUpdates) + { + this->getAndFetchModelCG(); // update CG + } + + m_currentInterpolationStatus.setSituationsCount(m_currentSituations.size()); + if (m_currentSituations.isEmpty()) + { + m_lastInterpolation = CAircraftSituation::null(); // no interpolation possible for that step + m_currentInterpolationStatus.setExtraInfo(this->isAircraftInRange(m_callsign) ? + QString("No situations, but remote aircraft '%1'").arg(m_callsign.asString()) : + QString("Unknown remote aircraft: '%1'").arg(m_callsign.asString())); + } + else + { + m_interpolatedSituationsCounter++; + + // with the latest updates of T243 the order and the offsets are supposed to be correct + // so even mixing fast/slow updates shall work + if (!CBuildConfig::isReleaseBuild()) + { + Q_ASSERT_X(m_currentSituations.isSortedAdjustedLatestFirstWithoutNullPositions(), Q_FUNC_INFO, "Wrong sort order"); + Q_ASSERT_X(m_currentSituations.size() <= IRemoteAircraftProvider::MaxSituationsPerCallsign, Q_FUNC_INFO, "Wrong size"); + } + } + + return true; } template @@ -345,12 +398,32 @@ namespace BlackMisc m_model = model; } } - if (m_model.getCG().isNull()) - { - const CLength cg(this->getCG(m_callsign)); - if (!cg.isNull()) { m_model.setCG(cg); } - } - m_model.setCallsign(m_callsign); + this->getAndFetchModelCG(); + } + + CInterpolationResult::CInterpolationResult() + { + this->reset(); + } + + void CInterpolationResult::setValues(const CAircraftSituation &situation, const CAircraftParts &parts) + { + m_interpolatedSituation = situation; + m_interpolatedParts = parts; + } + + void CInterpolationResult::setStatus(const CInterpolationStatus &interpolation, const CPartsStatus &parts) + { + m_interpolationStatus = interpolation; + m_partsStatus = parts; + } + + void CInterpolationResult::reset() + { + m_interpolatedSituation = CAircraftSituation::null(); + m_interpolatedParts = CAircraftParts::null(); + m_interpolationStatus.reset(); + m_partsStatus.reset(); } void CInterpolationStatus::setExtraInfo(const QString &info) diff --git a/src/blackmisc/simulation/interpolator.h b/src/blackmisc/simulation/interpolator.h index 8c7dff4ac..c829f7dfe 100644 --- a/src/blackmisc/simulation/interpolator.h +++ b/src/blackmisc/simulation/interpolator.h @@ -35,108 +35,6 @@ namespace BlackMisc class CInterpolationLogger; class CInterpolatorLinear; class CInterpolatorSpline; - struct CInterpolationStatus; - struct CPartsStatus; - - //! Interpolator, calculation inbetween positions - template - class CInterpolator : - protected CSimulationEnvironmentAware, - protected CInterpolationSetupAware, - protected CRemoteAircraftAware - { - public: - //! Log categories - const CLogCategoryList &getLogCategories(); - - //! Current interpolated situation - Aviation::CAircraftSituation getInterpolatedSituation(qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup, CInterpolationStatus &status); - - //! Parts before given offset time - Aviation::CAircraftParts getInterpolatedParts(qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup, CPartsStatus &partsStatus, bool log = false) const; - - //! Interpolated parts, if not available guessed parts - Aviation::CAircraftParts getInterpolatedOrGuessedParts(qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup, CPartsStatus &partsStatus, bool log = false) const; - - //! Latest interpolation result - const Aviation::CAircraftSituation &getLastInterpolatedSituation() const { return m_lastInterpolation; } - - //! Takes input between 0 and 1 and returns output between 0 and 1 smoothed with an S-shaped curve. - //! - //! Useful for making interpolation seem smoother, efficiently as it just uses simple arithmetic. - //! \see https://en.wikipedia.org/wiki/Smoothstep - //! \see http://sol.gfxile.net/interpolation/ - static double smootherStep(double x) - { - return x * x * x * (x * (x * 6.0 - 15.0) + 10.0); - } - - //! Attach an observer to read the interpolator's state for debugging - //! \remark parts logging has a \c bool \c log flag - void attachLogger(CInterpolationLogger *logger) { m_logger = logger; } - - //! Is logger attached? - bool hasAttachedLogger() const { return m_logger; } - - //! Get an interpolator info string (for debug info) - QString getInterpolatorInfo() const; - - //! Reset last interpolation to null - //! \remark mainly needed in UNIT tests - void resetLastInterpolation(); - - //! Clear all data - //! \remark mainly needed in UNIT tests - void clear(); - - //! Init, or re-init the corressponding model - //! \remark either by passing a model or using the provider - void initCorrespondingModel(const CAircraftModel &model = {}); - - protected: - //! Constructor - CInterpolator(const Aviation::CCallsign &callsign, - ISimulationEnvironmentProvider *simEnvProvider, IInterpolationSetupProvider *setupProvider, IRemoteAircraftProvider *p3, - CInterpolationLogger *logger); - - //! Center of gravity - const PhysicalQuantities::CLength &getModelCG() const { return m_model.getCG(); } - - //! Center of gravity, fetched from provider in case needed - PhysicalQuantities::CLength getAndFetchModelCG(); - - //! Decides threshold when situation is considered on ground - //! \sa BlackMisc::Aviation::CAircraftSituation::setOnGroundFromGroundFactorFromInterpolation - static double groundInterpolationFactor(); - - CAircraftModel m_model; //!< corresponding model - const Aviation::CCallsign m_callsign; //!< corresponding callsign - Aviation::CAircraftSituation m_lastInterpolation { Aviation::CAircraftSituation::null() }; //!< latest interpolation - Aviation::CAircraftSituationChange m_situationChange; //!< situations change - PhysicalQuantities::CLength m_lastSceneryOffset = PhysicalQuantities::CLength::null(); - qint64 m_situationsLastModifiedUsed { -1 }; //!< based on situations last updated - int m_interpolatedSituationsCounter = 0; //!< counter for each interpolated situations: statistics, every n-th interpolation .... - - //! Get situations and calculate change, also correct altitudes if applicable - Aviation::CAircraftSituationList remoteAircraftSituationsAndChange(bool useSceneryOffset); - - //! Verify gnd flag, times, ... true means "OK" - bool verifyInterpolationSituations(const Aviation::CAircraftSituation &oldest, const Aviation::CAircraftSituation &newer, const Aviation::CAircraftSituation &latest, - const CInterpolationAndRenderingSetupPerCallsign &setup = CInterpolationAndRenderingSetupPerCallsign::null()); - - private: - 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 - - //! Log parts - void logParts(qint64 timestamp, const Aviation::CAircraftParts &parts, int partsNo, bool empty, bool log) const; - - //! Deferred init - void deferredInit(); - - Derived *derived() { return static_cast(this); } - const Derived *derived() const { return static_cast(this); } - }; //! Status of interpolation struct BLACKMISC_EXPORT CInterpolationStatus @@ -183,6 +81,12 @@ namespace BlackMisc struct BLACKMISC_EXPORT CPartsStatus { public: + //! Ctor + CPartsStatus() {} + + //! Ctor + CPartsStatus(bool supportsParts) : m_supportsParts(supportsParts) {} + //! all OK bool allTrue() const; @@ -195,16 +99,182 @@ namespace BlackMisc //! Reset to default values void reset(); - //! Ctor - CPartsStatus() {} - - //! Ctor - CPartsStatus(bool supportsParts) : m_supportsParts(supportsParts) {} - private: bool m_supportsParts = false; //!< supports parts for given callsign }; + //! Combined results + class BLACKMISC_EXPORT CInterpolationResult + { + public: + //! Ctor + CInterpolationResult(); + + //! Get situation + const Aviation::CAircraftSituation &getInterpolatedSituation() const { return m_interpolatedSituation; } + + //! Get parts (interpolated or guessed) + const Aviation::CAircraftParts &getInterpolatedParts() const { return m_interpolatedParts; } + + //! Get status + const CInterpolationStatus &getInterpolationStatus() const { return m_interpolationStatus; } + + //! Get status + const CPartsStatus &getPartsStatus() const { return m_partsStatus; } + + //! Set situation + void setInterpolatedSituation(const Aviation::CAircraftSituation &situation) { m_interpolatedSituation = situation; } + + //! Set parts (interpolated or guessed) + void setInterpolatedParts(const Aviation::CAircraftParts &parts) { m_interpolatedParts = parts; } + + //! Set values + void setValues(const Aviation::CAircraftSituation &situation, const Aviation::CAircraftParts &parts); + + //! Set status + void setInterpolationStatus(const CInterpolationStatus &status) { m_interpolationStatus = status; } + + //! Set status + void setPartsStatus(const CPartsStatus &status) { m_partsStatus = status; } + + //! Set status values + void setStatus(const CInterpolationStatus &interpolation, const CPartsStatus &parts); + + //! Reset values + void reset(); + + //! Implicit conversion @{ + operator const Aviation::CAircraftSituation &() const { return m_interpolatedSituation; } + operator const Aviation::CAircraftParts &() const { return m_interpolatedParts; } + //! @} + + private: + Aviation::CAircraftSituation m_interpolatedSituation; //!< interpolated situation + Aviation::CAircraftParts m_interpolatedParts; //!< guessed or interpolated parts + CInterpolationStatus m_interpolationStatus; //!< interpolation status + CPartsStatus m_partsStatus; //!< parts status + }; + + //! Interpolator, calculation inbetween positions + template + class CInterpolator : + protected CSimulationEnvironmentAware, + protected CInterpolationSetupAware, + protected CRemoteAircraftAware + { + public: + //! Log categories + static const CLogCategoryList &getLogCategories(); + + //! Latest interpolation result + const Aviation::CAircraftSituation &getLastInterpolatedSituation() const { return m_lastInterpolation; } + + //! Parts and situation interpolated + CInterpolationResult getInterpolation(qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup); + + //! Takes input between 0 and 1 and returns output between 0 and 1 smoothed with an S-shaped curve. + //! + //! Useful for making interpolation seem smoother, efficiently as it just uses simple arithmetic. + //! \see https://en.wikipedia.org/wiki/Smoothstep + //! \see http://sol.gfxile.net/interpolation/ + static double smootherStep(double x) + { + return x * x * x * (x * (x * 6.0 - 15.0) + 10.0); + } + + //! Attach an observer to read the interpolator's state for debugging + //! \remark parts logging has a \c bool \c log flag + void attachLogger(CInterpolationLogger *logger) { m_logger = logger; } + + //! Is logger attached? + bool hasAttachedLogger() const { return m_logger; } + + //! Get an interpolator info string (for debug info) + QString getInterpolatorInfo() const; + + //! Reset last interpolation to null + //! \remark mainly needed in UNIT tests + void resetLastInterpolation(); + + //! Clear all data + //! \remark mainly needed in UNIT tests + void clear(); + + //! Init, or re-init the corressponding model + //! \remark either by passing a model or using the provider + void initCorrespondingModel(const CAircraftModel &model = {}); + + protected: + //! Constructor + CInterpolator(const Aviation::CCallsign &callsign, + ISimulationEnvironmentProvider *simEnvProvider, IInterpolationSetupProvider *setupProvider, IRemoteAircraftProvider *remoteProvider, + CInterpolationLogger *logger); + + //! Inits all data for this current interpolation step + bool initIniterpolationStepData(qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup); + + //! Current interpolated situation + Aviation::CAircraftSituation getInterpolatedSituation(); + + //! Parts before given offset time + Aviation::CAircraftParts getInterpolatedParts(); + + //! Interpolated parts, if not available guessed parts + Aviation::CAircraftParts getInterpolatedOrGuessedParts(); + + //! Center of gravity + const PhysicalQuantities::CLength &getModelCG() const { return m_model.getCG(); } + + //! 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 + + // values for current interpolation step + qint64 m_currentTimeMsSinceEpoch = -1; //!< current time + Aviation::CAircraftSituationList m_currentSituations; //!< current situations + Aviation::CAircraftSituationChange m_currentSituationChange; //!< situations change + PhysicalQuantities::CLength m_currentSceneryOffset = PhysicalQuantities::CLength::null(); //!< calculated scenery offset if any + CInterpolationAndRenderingSetupPerCallsign m_currentSetup; //!< used setup + CInterpolationStatus m_currentInterpolationStatus; //!< this step's status + CPartsStatus m_currentPartsStatus; //!< this step's status + Aviation::CAircraftSituation m_lastInterpolation { Aviation::CAircraftSituation::null() }; //!< latest interpolation + + qint64 m_situationsLastModified { -1 }; //!< whehn situations were last modified + qint64 m_situationsLastModifiedUsed { -1 }; //!< interpolant based on situations last updated + int m_interpolatedSituationsCounter { 0 }; //!< counter for each interpolated situations: statistics, every n-th interpolation .... + + + //! Verify gnd flag, times, ... true means "OK" + bool verifyInterpolationSituations(const Aviation::CAircraftSituation &oldest, const Aviation::CAircraftSituation &newer, const Aviation::CAircraftSituation &latest, + const CInterpolationAndRenderingSetupPerCallsign &setup = CInterpolationAndRenderingSetupPerCallsign::null()); + + private: + 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 + + //! Log parts + void logParts(const Aviation::CAircraftParts &parts, int partsNo, bool empty) const; + + //! Get situations and calculate change, also correct altitudes if applicable + //! \remark calculates offset (scenery) and situations change + Aviation::CAircraftSituationList remoteAircraftSituationsAndChange(bool useSceneryOffset); + + //! Center of gravity, fetched from provider in case needed + PhysicalQuantities::CLength getAndFetchModelCG(); + + //! Deferred init + void deferredInit(); + + Derived *derived() { return static_cast(this); } + const Derived *derived() const { return static_cast(this); } + }; + //! \cond PRIVATE extern template class BLACKMISC_EXPORT_DECLARE_TEMPLATE CInterpolator; extern template class BLACKMISC_EXPORT_DECLARE_TEMPLATE CInterpolator; diff --git a/src/blackmisc/simulation/interpolatorlinear.cpp b/src/blackmisc/simulation/interpolatorlinear.cpp index b76190fb2..7cbe4f677 100644 --- a/src/blackmisc/simulation/interpolatorlinear.cpp +++ b/src/blackmisc/simulation/interpolatorlinear.cpp @@ -97,37 +97,20 @@ namespace BlackMisc return newSituation; } - CInterpolatorLinear::CInterpolant CInterpolatorLinear::getInterpolant( - qint64 currentTimeMsSinceEpoc, - const CInterpolationAndRenderingSetupPerCallsign &setup, - CInterpolationStatus &status, SituationLog &log) + CInterpolatorLinear::CInterpolant CInterpolatorLinear::getInterpolant(SituationLog &log) { - Q_UNUSED(setup); - status.reset(); - - const qint64 tsLastModified = this->situationsLastModified(m_callsign); - // set default situations CAircraftSituation oldSituation = m_interpolant.getOldSituation(); CAircraftSituation newSituation = m_interpolant.getNewSituation(); - if (m_situationsLastModifiedUsed < tsLastModified || m_situationChange.isNull()) + if (m_situationsLastModifiedUsed < m_situationsLastModified) { - m_situationsLastModifiedUsed = tsLastModified; - - // with the latest updates of T243 the order and the offsets are supposed to be correct - // so even mixing fast/slow updates shall work - const CAircraftSituationList validSituations = this->remoteAircraftSituationsAndChange(true); - if (!CBuildConfig::isReleaseBuild()) - { - BLACK_VERIFY_X(validSituations.isSortedAdjustedLatestFirstWithoutNullPositions(), Q_FUNC_INFO, "Wrong sort order"); - Q_ASSERT_X(validSituations.size() <= IRemoteAircraftProvider::MaxSituationsPerCallsign, Q_FUNC_INFO, "Wrong size"); - } + m_situationsLastModifiedUsed = m_situationsLastModified; // find the first situation earlier than the current time - const auto pivot = std::partition_point(validSituations.begin(), validSituations.end(), [ = ](auto &&s) { return s.getAdjustedMSecsSinceEpoch() > currentTimeMsSinceEpoc; }); - const auto situationsNewer = makeRange(validSituations.begin(), pivot); - const auto situationsOlder = makeRange(pivot, validSituations.end()); + const auto pivot = std::partition_point(m_currentSituations.begin(), m_currentSituations.end(), [ = ](auto &&s) { return s.getAdjustedMSecsSinceEpoch() > m_currentTimeMsSinceEpoch; }); + const auto situationsNewer = makeRange(m_currentSituations.begin(), pivot); + const auto situationsOlder = makeRange(pivot, m_currentSituations.end()); // latest first, now 00:20 split time // time pos @@ -146,7 +129,7 @@ namespace BlackMisc if (situationsOlder.isEmpty()) { const CAircraftSituation currentSituation(*(situationsNewer.end() - 1)); // oldest newest - status.setInterpolatedAndCheckSituation(false, currentSituation); + m_currentInterpolationStatus.setInterpolatedAndCheckSituation(false, currentSituation); m_interpolant = { currentSituation }; return m_interpolant; } @@ -155,7 +138,7 @@ namespace BlackMisc if (situationsOlder.size() < 2) { const CAircraftSituation currentSituation(situationsOlder.front()); // latest oldest - status.setInterpolatedAndCheckSituation(false, currentSituation); + m_currentInterpolationStatus.setInterpolatedAndCheckSituation(false, currentSituation); m_interpolant = { currentSituation }; return m_interpolant; } @@ -195,18 +178,18 @@ namespace BlackMisc // < 0 should not happen due to the split, > 1 can happen if new values are delayed beyond split time // 1) values > 1 mean extrapolation // 2) values > 2 mean no new situations coming in - const double distanceToSplitTimeMs = newSituation.getAdjustedMSecsSinceEpoch() - currentTimeMsSinceEpoc; + const double distanceToSplitTimeMs = newSituation.getAdjustedMSecsSinceEpoch() - m_currentTimeMsSinceEpoch; const double simulationTimeFraction = qMax(1.0 - (distanceToSplitTimeMs / sampleDeltaTimeMs), 0.0); const double deltaTimeFractionMs = sampleDeltaTimeMs * simulationTimeFraction; const qint64 interpolatedTime = oldSituation.getMSecsSinceEpoch() + deltaTimeFractionMs; currentSituation.setTimeOffsetMs(oldSituation.getTimeOffsetMs() + (newSituation.getTimeOffsetMs() - oldSituation.getTimeOffsetMs()) * simulationTimeFraction); currentSituation.setMSecsSinceEpoch(interpolatedTime); - status.setInterpolatedAndCheckSituation(true, currentSituation); + m_currentInterpolationStatus.setInterpolatedAndCheckSituation(true, currentSituation); - if (this->hasAttachedLogger() && setup.logInterpolation()) + if (this->doLogging()) { - log.tsCurrent = currentTimeMsSinceEpoc; + log.tsCurrent = m_currentTimeMsSinceEpoch; log.deltaSampleTimesMs = sampleDeltaTimeMs; log.simTimeFraction = simulationTimeFraction; log.deltaSampleTimesMs = sampleDeltaTimeMs; diff --git a/src/blackmisc/simulation/interpolatorlinear.h b/src/blackmisc/simulation/interpolatorlinear.h index b9f3ca84c..c160f892a 100644 --- a/src/blackmisc/simulation/interpolatorlinear.h +++ b/src/blackmisc/simulation/interpolatorlinear.h @@ -65,7 +65,7 @@ namespace BlackMisc }; //! Get the interpolant for the given time point - CInterpolant getInterpolant(qint64 currentTimeMsSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup, CInterpolationStatus &status, SituationLog &log); + CInterpolant getInterpolant(SituationLog &log); private: CInterpolant m_interpolant; //!< current interpolant diff --git a/src/blackmisc/simulation/interpolatormulti.cpp b/src/blackmisc/simulation/interpolatormulti.cpp index 5c3f4970b..4840c3dd6 100644 --- a/src/blackmisc/simulation/interpolatormulti.cpp +++ b/src/blackmisc/simulation/interpolatormulti.cpp @@ -22,45 +22,16 @@ namespace BlackMisc m_linear(callsign, p1, p2, p3, logger) {} - CAircraftSituation CInterpolatorMulti::getInterpolatedSituation(qint64 currentTimeSinceEpoc, - const CInterpolationAndRenderingSetupPerCallsign &setup, - CInterpolationStatus &status) + CInterpolationResult CInterpolatorMulti::getInterpolation(qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup) { switch (setup.getInterpolatorMode()) { - case CInterpolationAndRenderingSetupBase::Linear: return m_linear.getInterpolatedSituation(currentTimeSinceEpoc, setup, status); - case CInterpolationAndRenderingSetupBase::Spline: return m_spline.getInterpolatedSituation(currentTimeSinceEpoc, setup, status); + case CInterpolationAndRenderingSetupBase::Linear: return m_linear.getInterpolation(currentTimeSinceEpoc, setup); + case CInterpolationAndRenderingSetupBase::Spline: return m_spline.getInterpolation(currentTimeSinceEpoc, setup); default: break; } - return {}; - } - CAircraftParts CInterpolatorMulti::getInterpolatedParts( - qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup, - CPartsStatus &partsStatus, bool log) const - { - switch (setup.getInterpolatorMode()) - { - // currently calls the same interpolation for parts - case CInterpolationAndRenderingSetupBase::Linear: return m_linear.getInterpolatedParts(currentTimeSinceEpoc, setup, partsStatus, log); - case CInterpolationAndRenderingSetupBase::Spline: return m_spline.getInterpolatedParts(currentTimeSinceEpoc, setup, partsStatus, log); - default: break; - } - return {}; - } - - CAircraftParts CInterpolatorMulti::getInterpolatedOrGuessedParts( - qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup, - CPartsStatus &partsStatus, bool log) const - { - switch (setup.getInterpolatorMode()) - { - // currently calls the same interpolation for parts - case CInterpolationAndRenderingSetupBase::Linear: return m_linear.getInterpolatedOrGuessedParts(currentTimeSinceEpoc, setup, partsStatus, log); - case CInterpolationAndRenderingSetupBase::Spline: return m_spline.getInterpolatedOrGuessedParts(currentTimeSinceEpoc, setup, partsStatus, log); - default: break; - } - return {}; + return CInterpolationResult(); } const CAircraftSituation &CInterpolatorMulti::getLastInterpolatedSituation(CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const diff --git a/src/blackmisc/simulation/interpolatormulti.h b/src/blackmisc/simulation/interpolatormulti.h index da1a61739..18c7caa9a 100644 --- a/src/blackmisc/simulation/interpolatormulti.h +++ b/src/blackmisc/simulation/interpolatormulti.h @@ -28,20 +28,8 @@ namespace BlackMisc ISimulationEnvironmentProvider *p1, IInterpolationSetupProvider *p2, IRemoteAircraftProvider *p3, CInterpolationLogger *logger = nullptr); - //! \copydoc CInterpolator::getInterpolatedSituation - Aviation::CAircraftSituation getInterpolatedSituation( - qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup, - CInterpolationStatus &status); - - //! \copydoc CInterpolator::getInterpolatedParts - Aviation::CAircraftParts getInterpolatedParts( - qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup, - CPartsStatus &partsStatus, bool log = false) const; - - //! \copydoc CInterpolator::getInterpolatedOrGuessedParts - Aviation::CAircraftParts getInterpolatedOrGuessedParts( - qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup, - CPartsStatus &partsStatus, bool log) const; + //! \copydoc CInterpolator::getInterpolation + CInterpolationResult getInterpolation(qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup); //! \copydoc CInterpolator::getLastInterpolatedSituation const Aviation::CAircraftSituation &getLastInterpolatedSituation(CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const; diff --git a/src/blackmisc/simulation/interpolatorspline.cpp b/src/blackmisc/simulation/interpolatorspline.cpp index 5ed12bcd9..27459f5c4 100644 --- a/src/blackmisc/simulation/interpolatorspline.cpp +++ b/src/blackmisc/simulation/interpolatorspline.cpp @@ -98,16 +98,16 @@ namespace BlackMisc } } - bool CInterpolatorSpline::fillSituationsArray(const CAircraftSituationList &validSituations) + bool CInterpolatorSpline::fillSituationsArray() { // m_s[0] .. oldest -> m_[2] .. latest // general idea, we interpolate from current situation -> latest situation if (m_lastInterpolation.isNull()) { - if (!validSituations.isEmpty()) + if (!m_currentSituations.isEmpty()) { - m_s[0] = m_s[1] = m_s[2] = validSituations.front(); + m_s[0] = m_s[1] = m_s[2] = m_currentSituations.front(); m_s[0].addMsecs(-CFsdSetup::c_positionTimeOffsetMsec * 2); m_s[1].addMsecs(-CFsdSetup::c_positionTimeOffsetMsec); return true; @@ -120,20 +120,17 @@ namespace BlackMisc m_s[0] = m_s[1] = m_s[2] = m_lastInterpolation; // current m_s[0].addMsecs(-CFsdSetup::c_positionTimeOffsetMsec); // oldest m_s[2].addMsecs(CFsdSetup::c_positionTimeOffsetMsec); // latest - if (validSituations.isEmpty()) { return true; } + if (m_currentSituations.isEmpty()) { return true; } } const qint64 currentAdjusted = m_s[1].getAdjustedMSecsSinceEpoch(); - const CAircraftSituation latest = validSituations.front(); + const CAircraftSituation latest = m_currentSituations.front(); if (latest.isNewerThanAdjusted(m_s[1])) { m_s[2] = latest; } - const CAircraftSituation older = validSituations.findObjectBeforeAdjustedOrDefault(currentAdjusted); + const CAircraftSituation older = m_currentSituations.findObjectBeforeAdjustedOrDefault(currentAdjusted); if (!older.isNull()) { m_s[0] = older; } if (CBuildConfig::isLocalDeveloperDebugBuild()) { - BLACK_VERIFY_X(validSituations.isSortedAdjustedLatestFirstWithoutNullPositions(), Q_FUNC_INFO, "Wrong sort order"); - BLACK_VERIFY_X(validSituations.size() <= IRemoteAircraftProvider::MaxSituationsPerCallsign, Q_FUNC_INFO, "Wrong size"); - const bool verified = this->verifyInterpolationSituations(m_s[0], m_s[1], m_s[2]); // oldest -> latest, only verify order if (!verified) { @@ -145,25 +142,16 @@ namespace BlackMisc return true; } - CInterpolatorSpline::CInterpolant CInterpolatorSpline::getInterpolant( - qint64 currentTimeMsSinceEpoc, - const CInterpolationAndRenderingSetupPerCallsign &setup, - CInterpolationStatus &status, - SituationLog &log) + CInterpolatorSpline::CInterpolant CInterpolatorSpline::getInterpolant(SituationLog &log) { - Q_UNUSED(setup); - // recalculate derivatives only if they changed - const qint64 lastModified = this->situationsLastModified(m_callsign); - const bool recalculate = lastModified > m_situationsLastModifiedUsed; - int situationsSize = -1; + const bool recalculate = m_situationsLastModified > m_situationsLastModifiedUsed; if (recalculate) { // with the latest updates of T243 the order and the offsets are supposed to be correct // so even mixing fast/slow updates shall work - m_situationsLastModifiedUsed = lastModified; - const CAircraftSituationList validSituations = this->remoteAircraftSituationsAndChange(true); - const bool fillStatus = this->fillSituationsArray(validSituations); + m_situationsLastModifiedUsed = m_situationsLastModified; + const bool fillStatus = this->fillSituationsArray(); if (!fillStatus) { return m_interpolant; @@ -186,7 +174,7 @@ namespace BlackMisc // - and the elevation remains (almost) constant for a wider area // - during flying the ground elevation not really matters this->updateElevations(); - const CLength cg(m_s[2].hasCG() ? m_s[2].getCG() : this->getAndFetchModelCG()); + const CLength cg(this->getModelCG()); const double a0 = m_s[0].getCorrectedAltitude(cg).value(); // oldest const double a1 = m_s[1].getCorrectedAltitude(cg).value(); const double a2 = m_s[2].getCorrectedAltitude(cg).value(); // latest @@ -214,7 +202,7 @@ namespace BlackMisc // cur.time 6: dt1=6-5=1, dt2=7-5 => fraction 1/2 // cur.time 9: dt1=9-7=2, dt2=10-7=3 => fraction 2/3 // we use different offset times for fast pos. updates - const double dt1 = static_cast(currentTimeMsSinceEpoc - m_prevSampleAdjustedTime); + const double dt1 = static_cast(m_currentTimeMsSinceEpoch - m_prevSampleAdjustedTime); const double dt2 = static_cast(m_nextSampleAdjustedTime - m_prevSampleAdjustedTime); const double timeFraction = dt1 / dt2; @@ -224,19 +212,19 @@ namespace BlackMisc const qint64 interpolatedTime = m_prevSampleTime + timeFraction * dt2; // time fraction is expected between 0-1 - status.setInterpolated(true); - m_interpolant.setTimes(currentTimeMsSinceEpoc, timeFraction, interpolatedTime); + m_currentInterpolationStatus.setInterpolated(true); + m_interpolant.setTimes(m_currentTimeMsSinceEpoch, timeFraction, interpolatedTime); - if (this->hasAttachedLogger() && setup.logInterpolation()) + if (this->doLogging()) { - if (situationsSize < 0) { situationsSize = this->remoteAircraftSituationsCount(m_callsign); } + log.interpolationSituations.clear(); log.interpolationSituations.push_back(m_s[0]); log.interpolationSituations.push_back(m_s[1]); log.interpolationSituations.push_back(m_s[2]); // latest at end + log.noNetworkSituations = m_currentSituations.size(); log.interpolator = 's'; log.deltaSampleTimesMs = dt2; log.simTimeFraction = timeFraction; - log.noNetworkSituations = situationsSize; log.tsInterpolated = interpolatedTime; // without offsets } diff --git a/src/blackmisc/simulation/interpolatorspline.h b/src/blackmisc/simulation/interpolatorspline.h index 0be5ef027..f6f58df6f 100644 --- a/src/blackmisc/simulation/interpolatorspline.h +++ b/src/blackmisc/simulation/interpolatorspline.h @@ -30,9 +30,9 @@ namespace BlackMisc public: //! Constructor CInterpolatorSpline(const Aviation::CCallsign &callsign, - ISimulationEnvironmentProvider *p1, IInterpolationSetupProvider *p2, IRemoteAircraftProvider *p3, + ISimulationEnvironmentProvider *envProvider, IInterpolationSetupProvider *setupProvider, IRemoteAircraftProvider *aircraftProvider, CInterpolationLogger *logger = nullptr) : - CInterpolator(callsign, p1, p2, p3, logger) {} + CInterpolator(callsign, envProvider, setupProvider, aircraftProvider, logger) {} //! Position arrays for interpolation struct BLACKMISC_EXPORT PosArray @@ -80,8 +80,7 @@ namespace BlackMisc }; //! Strategy used by CInterpolator::getInterpolatedSituation - CInterpolant getInterpolant(qint64 currentTimeMsSinceEpoc, - const CInterpolationAndRenderingSetupPerCallsign &setup, CInterpolationStatus &status, SituationLog &log); + CInterpolant getInterpolant(SituationLog &log); private: //! Update the elevations used in CInterpolatorSpline::m_s @@ -97,7 +96,7 @@ namespace BlackMisc bool areAltitudeUnitsSame(const PhysicalQuantities::CLengthUnit &compare = PhysicalQuantities::CLengthUnit::nullUnit()) const; //! Fill the situations array - bool fillSituationsArray(const BlackMisc::Aviation::CAircraftSituationList &validSituations); + bool fillSituationsArray(); qint64 m_prevSampleAdjustedTime = 0; //!< previous sample time + offset qint64 m_nextSampleAdjustedTime = 0; //!< previous sample time + offset diff --git a/src/plugins/simulator/emulated/simulatoremulated.cpp b/src/plugins/simulator/emulated/simulatoremulated.cpp index 5e8b4fad7..c8928e328 100644 --- a/src/plugins/simulator/emulated/simulatoremulated.cpp +++ b/src/plugins/simulator/emulated/simulatoremulated.cpp @@ -413,13 +413,11 @@ namespace BlackSimPlugin const CCallsign cs = aircraft.getCallsign(); if (!m_interpolators.contains(cs)) { continue; } const CInterpolationAndRenderingSetupPerCallsign setup = this->getInterpolationSetupPerCallsignOrDefault(cs); // threadsafe copy - const bool log = setup.logInterpolation(); CInterpolatorMulti *im = m_interpolators[cs]; - CInterpolationStatus statusInterpolation; - CPartsStatus statusParts; Q_ASSERT_X(im, Q_FUNC_INFO, "interpolator missing"); - const CAircraftSituation s = im->getInterpolatedSituation(now, setup, statusInterpolation); - const CAircraftParts p = im->getInterpolatedOrGuessedParts(now, setup, statusParts, log); + CInterpolationResult result = im->getInterpolation(now, setup); + const CAircraftSituation s = result; + const CAircraftParts p = result; m_countInterpolatedParts++; m_countInterpolatedSituations++; Q_UNUSED(s); diff --git a/src/plugins/simulator/fs9/fs9client.cpp b/src/plugins/simulator/fs9/fs9client.cpp index d60dce23e..6f9e7c3c4 100644 --- a/src/plugins/simulator/fs9/fs9client.cpp +++ b/src/plugins/simulator/fs9/fs9client.cpp @@ -172,14 +172,13 @@ namespace BlackSimPlugin Q_UNUSED(event); if (m_clientStatus == Disconnected) { return; } - CInterpolationStatus status; - CInterpolationAndRenderingSetupPerCallsign setup = this->simulator()->getInterpolationSetupPerCallsignOrDefault(m_callsign); - const CAircraftSituation situation = m_interpolator.getInterpolatedSituation(-1, setup, status); + const CInterpolationAndRenderingSetupPerCallsign setup = this->simulator()->getInterpolationSetupConsolidated(m_callsign); + const CInterpolationResult result = m_interpolator.getInterpolation(QDateTime::currentMSecsSinceEpoch(), setup); // Test only for successful position. FS9 requires constant positions - if (!status.hasValidSituation()) { return; } + if (!result.getInterpolationStatus().hasValidSituation()) { return; } - sendMultiplayerPosition(situation); + sendMultiplayerPosition(result); sendMultiplayerParamaters(); } diff --git a/src/plugins/simulator/fsxcommon/simconnectobject.cpp b/src/plugins/simulator/fsxcommon/simconnectobject.cpp index 86c681330..263b4a78e 100644 --- a/src/plugins/simulator/fsxcommon/simconnectobject.cpp +++ b/src/plugins/simulator/fsxcommon/simconnectobject.cpp @@ -112,37 +112,16 @@ namespace BlackSimPlugin return m_interpolator->getInterpolatorInfo(mode); } - void CSimConnectObject::attachInterpolatorLogger(CInterpolationLogger *logger) + void CSimConnectObject::attachInterpolatorLogger(CInterpolationLogger *logger) const { Q_ASSERT(m_interpolator); return m_interpolator->attachLogger(logger); } - CAircraftSituation CSimConnectObject::getInterpolatedSituation( - qint64 currentTimeSinceEpoc, - const CInterpolationAndRenderingSetupPerCallsign &setup, - CInterpolationStatus &status) const + CInterpolationResult CSimConnectObject::getInterpolation(qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup) const { - Q_ASSERT(m_interpolator); - return m_interpolator->getInterpolatedSituation(currentTimeSinceEpoc, setup, status); - } - - CAircraftParts CSimConnectObject::getInterpolatedParts( - qint64 currentTimeSinceEpoc, - const CInterpolationAndRenderingSetupPerCallsign &setup, - CPartsStatus &partsStatus, bool log) const - { - Q_ASSERT(m_interpolator); - return m_interpolator->getInterpolatedParts(currentTimeSinceEpoc, setup, partsStatus, log); - } - - CAircraftParts CSimConnectObject::getInterpolatedOrGuessedParts( - qint64 currentTimeSinceEpoc, - const CInterpolationAndRenderingSetupPerCallsign &setup, - CPartsStatus &partsStatus, bool log) const - { - Q_ASSERT(m_interpolator); - return m_interpolator->getInterpolatedOrGuessedParts(currentTimeSinceEpoc, setup, partsStatus, log); + if (!m_interpolator) { CInterpolationResult result; result.reset(); return result; } + return m_interpolator->getInterpolation(currentTimeSinceEpoc, setup); } const CAircraftSituation &CSimConnectObject::getLastInterpolatedSituation(CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const diff --git a/src/plugins/simulator/fsxcommon/simconnectobject.h b/src/plugins/simulator/fsxcommon/simconnectobject.h index 0110a74f8..0af70d81c 100644 --- a/src/plugins/simulator/fsxcommon/simconnectobject.h +++ b/src/plugins/simulator/fsxcommon/simconnectobject.h @@ -160,34 +160,16 @@ namespace BlackSimPlugin //! Was the object really added to simulator bool hasValidRequestAndObjectId() const; - //! \copydoc BlackMisc::Simulation::CInterpolatorMulti::toggleMode - void toggleInterpolatorMode(); - //! \copydoc BlackMisc::Simulation::CInterpolator::getInterpolatorInfo QString getInterpolatorInfo(BlackMisc::Simulation::CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const; //! \copydoc BlackMisc::Simulation::CInterpolator::attachLogger - void attachInterpolatorLogger(BlackMisc::Simulation::CInterpolationLogger *logger); + void attachInterpolatorLogger(BlackMisc::Simulation::CInterpolationLogger *logger) const; - //! \copydoc BlackMisc::Simulation::CInterpolator::getInterpolatedSituation - BlackMisc::Aviation::CAircraftSituation getInterpolatedSituation( - qint64 currentTimeSinceEpoc, - const BlackMisc::Simulation::CInterpolationAndRenderingSetupPerCallsign &setup, - BlackMisc::Simulation::CInterpolationStatus &status) const; + //! \copydoc BlackMisc::Simulation::CInterpolator::getInterpolation + BlackMisc::Simulation::CInterpolationResult getInterpolation(qint64 currentTimeSinceEpoc, const BlackMisc::Simulation::CInterpolationAndRenderingSetupPerCallsign &setup) const; - //! \copydoc BlackMisc::Simulation::CInterpolator::getInterpolatedParts - BlackMisc::Aviation::CAircraftParts getInterpolatedParts( - qint64 currentTimeSinceEpoc, - const BlackMisc::Simulation::CInterpolationAndRenderingSetupPerCallsign &setup, - BlackMisc::Simulation::CPartsStatus &partsStatus, bool log) const; - - //! \copydoc BlackMisc::Simulation::CInterpolator::getInterpolatedOrGuessedParts - BlackMisc::Aviation::CAircraftParts getInterpolatedOrGuessedParts( - qint64 currentTimeSinceEpoc, - const BlackMisc::Simulation::CInterpolationAndRenderingSetupPerCallsign &setup, - BlackMisc::Simulation::CPartsStatus &partsStatus, bool log) const; - - //! Last interpolated situation + //! \copydoc BlackMisc::Simulation::CInterpolator::getLastInterpolatedSituation const BlackMisc::Aviation::CAircraftSituation &getLastInterpolatedSituation(BlackMisc::Simulation::CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const; //! Interpolator diff --git a/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp b/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp index 16368d557..baa1996a2 100644 --- a/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp +++ b/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp @@ -1260,17 +1260,14 @@ namespace BlackSimPlugin // setup const CInterpolationAndRenderingSetupPerCallsign setup = this->getInterpolationSetupConsolidated(callsign); - const bool logInterpolationAndParts = setup.logInterpolation(); const bool sendGround = setup.sendGndFlagToSimulator(); // Interpolated situation - CInterpolationStatus interpolatorStatus; - const CAircraftSituation interpolatedSituation = simObject.getInterpolatedSituation(currentTimestamp, setup, interpolatorStatus); - - if (interpolatorStatus.hasValidSituation()) + const CInterpolationResult result = simObject.getInterpolation(currentTimestamp, setup); + if (result.getInterpolationStatus().hasValidSituation()) { // update situation - SIMCONNECT_DATA_INITPOSITION position = this->aircraftSituationToFsxPosition(interpolatedSituation, sendGround); + SIMCONNECT_DATA_INITPOSITION position = this->aircraftSituationToFsxPosition(result, sendGround); if (!simObject.isSameAsSent(position)) { m_simConnectObjects[simObject.getCallsign()].setPositionAsSent(position); @@ -1290,13 +1287,11 @@ namespace BlackSimPlugin else { static const QString so("SimObject id: %1"); - CLogMessage(this).warning(this->getInvalidSituationLogMessage(callsign, interpolatorStatus, so.arg(simObject.getObjectId()))); + CLogMessage(this).warning(this->getInvalidSituationLogMessage(callsign, result.getInterpolationStatus(), so.arg(simObject.getObjectId()))); } // Interpolated parts - CPartsStatus partsStatus; - const CAircraftParts parts = simObject.getInterpolatedOrGuessedParts(currentTimestamp, setup, partsStatus, logInterpolationAndParts); - this->updateRemoteAircraftParts(simObject, parts, partsStatus); + this->updateRemoteAircraftParts(simObject, result); } // all callsigns @@ -1306,10 +1301,12 @@ namespace BlackSimPlugin m_statsUpdateAircraftTimeAvgMs = m_statsUpdateAircraftTimeTotalMs / m_statsUpdateAircraftCountMs; } - bool CSimulatorFsxCommon::updateRemoteAircraftParts(const CSimConnectObject &simObject, const CAircraftParts &parts, const CPartsStatus &partsStatus) + bool CSimulatorFsxCommon::updateRemoteAircraftParts(const CSimConnectObject &simObject, const CInterpolationResult &result) { if (!simObject.hasValidRequestAndObjectId()) { return false; } - if (parts.getPartsDetails() != CAircraftParts::GuessedParts && !partsStatus.isSupportingParts()) { return false; } + + const CAircraftParts parts = result; + if (parts.getPartsDetails() != CAircraftParts::GuessedParts && !result.getPartsStatus().isSupportingParts()) { return false; } DataDefinitionRemoteAircraftPartsWithoutLights ddRemoteAircraftPartsWithoutLights(parts); // no init, all values will be set return this->sendRemoteAircraftPartsToSimulator(simObject, ddRemoteAircraftPartsWithoutLights, parts.getAdjustedLights()); diff --git a/src/plugins/simulator/fsxcommon/simulatorfsxcommon.h b/src/plugins/simulator/fsxcommon/simulatorfsxcommon.h index 3b6fde72b..d35caba41 100644 --- a/src/plugins/simulator/fsxcommon/simulatorfsxcommon.h +++ b/src/plugins/simulator/fsxcommon/simulatorfsxcommon.h @@ -272,8 +272,7 @@ namespace BlackSimPlugin void updateRemoteAircraft(); //! Update remote aircraft parts (send to FSX) - bool updateRemoteAircraftParts(const CSimConnectObject &simObject, - const BlackMisc::Aviation::CAircraftParts &parts, const BlackMisc::Simulation::CPartsStatus &partsStatus); + bool updateRemoteAircraftParts(const CSimConnectObject &simObject, const BlackMisc::Simulation::CInterpolationResult &result); //! Send parts to simulator bool sendRemoteAircraftPartsToSimulator(const CSimConnectObject &simObject, DataDefinitionRemoteAircraftPartsWithoutLights &ddRemoteAircraftParts, const BlackMisc::Aviation::CAircraftLights &lights); diff --git a/src/plugins/simulator/xplane/simulatorxplane.cpp b/src/plugins/simulator/xplane/simulatorxplane.cpp index 6c9f4300d..00edb92ee 100644 --- a/src/plugins/simulator/xplane/simulatorxplane.cpp +++ b/src/plugins/simulator/xplane/simulatorxplane.cpp @@ -678,18 +678,13 @@ namespace BlackSimPlugin // setup const CInterpolationAndRenderingSetupPerCallsign setup = this->getInterpolationSetupConsolidated(callsign); - const bool logInterpolationAndParts = setup.logInterpolation(); - // interpolated situation - CInterpolationStatus interpolatorStatus; - const CAircraftSituation interpolatedSituation = xplaneAircraft.getInterpolatedSituation(currentTimestamp, setup, interpolatorStatus); - - // perts - CPartsStatus partsStatus; - const CAircraftParts parts = xplaneAircraft.getInterpolatedOrGuessedParts(currentTimestamp, setup, partsStatus, logInterpolationAndParts); - - if (interpolatorStatus.hasValidSituation()) + // interpolated situation/parts + const CInterpolationResult result = xplaneAircraft.getInterpolation(currentTimestamp, setup); + if (result.getInterpolationStatus().hasValidSituation()) { + const CAircraftSituation interpolatedSituation(result); + // update situation if (!xplaneAircraft.isSameAsSent(interpolatedSituation)) { @@ -705,10 +700,10 @@ namespace BlackSimPlugin } else { - CLogMessage(this).warning(this->getInvalidSituationLogMessage(callsign, interpolatorStatus)); + CLogMessage(this).warning(this->getInvalidSituationLogMessage(callsign, result.getInterpolationStatus())); } - this->updateRemoteAircraftParts(xplaneAircraft, parts, partsStatus); + this->updateRemoteAircraftParts(xplaneAircraft, result); } // all callsigns @@ -718,10 +713,10 @@ namespace BlackSimPlugin m_statsUpdateAircraftTimeAvgMs = m_statsUpdateAircraftTimeTotalMs / m_statsUpdateAircraftCountMs; } - bool CSimulatorXPlane::updateRemoteAircraftParts(const CXPlaneMPAircraft &xplaneAircraft, const CAircraftParts &parts, const CPartsStatus &partsStatus) + bool CSimulatorXPlane::updateRemoteAircraftParts(const CXPlaneMPAircraft &xplaneAircraft, const CInterpolationResult &result) { - if (!partsStatus.isSupportingParts()) { return false; } - return this->sendRemoteAircraftPartsToSimulator(xplaneAircraft, parts); + if (!result.getPartsStatus().isSupportingParts()) { return false; } + return this->sendRemoteAircraftPartsToSimulator(xplaneAircraft, result); } bool CSimulatorXPlane::sendRemoteAircraftPartsToSimulator(const CXPlaneMPAircraft &xplaneAircraft, const CAircraftParts &parts) diff --git a/src/plugins/simulator/xplane/simulatorxplane.h b/src/plugins/simulator/xplane/simulatorxplane.h index 12d42b5d8..6cae3d144 100644 --- a/src/plugins/simulator/xplane/simulatorxplane.h +++ b/src/plugins/simulator/xplane/simulatorxplane.h @@ -178,8 +178,7 @@ namespace BlackSimPlugin void updateRemoteAircraft(); //! Update remote aircraft parts (send to XSwiftBus) - bool updateRemoteAircraftParts(const CXPlaneMPAircraft &xplaneAircraft, - const BlackMisc::Aviation::CAircraftParts &parts, const BlackMisc::Simulation::CPartsStatus &partsStatus); + bool updateRemoteAircraftParts(const CXPlaneMPAircraft &xplaneAircraft, const BlackMisc::Simulation::CInterpolationResult &result); //! Send parts to simulator bool sendRemoteAircraftPartsToSimulator(const CXPlaneMPAircraft &xplaneAircraft, const BlackMisc::Aviation::CAircraftParts &parts); diff --git a/src/plugins/simulator/xplane/xplanempaircraft.cpp b/src/plugins/simulator/xplane/xplanempaircraft.cpp index e1b9c9499..f29d72ddd 100644 --- a/src/plugins/simulator/xplane/xplanempaircraft.cpp +++ b/src/plugins/simulator/xplane/xplanempaircraft.cpp @@ -42,37 +42,16 @@ namespace BlackSimPlugin return m_interpolator->getInterpolatorInfo(mode); } - void CXPlaneMPAircraft::attachInterpolatorLogger(CInterpolationLogger *logger) + void CXPlaneMPAircraft::attachInterpolatorLogger(CInterpolationLogger *logger) const { Q_ASSERT(m_interpolator); return m_interpolator->attachLogger(logger); } - CAircraftSituation CXPlaneMPAircraft::getInterpolatedSituation( - qint64 currentTimeSinceEpoc, - const CInterpolationAndRenderingSetupPerCallsign &setup, - CInterpolationStatus &status) const + CInterpolationResult CXPlaneMPAircraft::getInterpolation(qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetupPerCallsign &setup) const { Q_ASSERT(m_interpolator); - return m_interpolator->getInterpolatedSituation(currentTimeSinceEpoc, setup, status); - } - - CAircraftParts CXPlaneMPAircraft::getInterpolatedParts( - qint64 currentTimeSinceEpoc, - const CInterpolationAndRenderingSetupPerCallsign &setup, - CPartsStatus &partsStatus, bool log) const - { - Q_ASSERT(m_interpolator); - return m_interpolator->getInterpolatedParts(currentTimeSinceEpoc, setup, partsStatus, log); - } - - CAircraftParts CXPlaneMPAircraft::getInterpolatedOrGuessedParts( - qint64 currentTimeSinceEpoc, - const CInterpolationAndRenderingSetupPerCallsign &setup, - CPartsStatus &partsStatus, bool log) const - { - Q_ASSERT(m_interpolator); - return m_interpolator->getInterpolatedOrGuessedParts(currentTimeSinceEpoc, setup, partsStatus, log); + return m_interpolator->getInterpolation(currentTimeSinceEpoc, setup); } CCallsignSet CXPlaneMPAircraftObjects::getAllCallsigns() const diff --git a/src/plugins/simulator/xplane/xplanempaircraft.h b/src/plugins/simulator/xplane/xplanempaircraft.h index 382cb1fdc..8525fda36 100644 --- a/src/plugins/simulator/xplane/xplanempaircraft.h +++ b/src/plugins/simulator/xplane/xplanempaircraft.h @@ -74,25 +74,10 @@ namespace BlackSimPlugin QString getInterpolatorInfo(BlackMisc::Simulation::CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const; //! \copydoc BlackMisc::Simulation::CInterpolator::attachLogger - void attachInterpolatorLogger(BlackMisc::Simulation::CInterpolationLogger *logger); + void attachInterpolatorLogger(BlackMisc::Simulation::CInterpolationLogger *logger) const; - //! \copydoc BlackMisc::Simulation::CInterpolator::getInterpolatedSituation - BlackMisc::Aviation::CAircraftSituation getInterpolatedSituation( - qint64 currentTimeSinceEpoc, - const BlackMisc::Simulation::CInterpolationAndRenderingSetupPerCallsign &setup, - BlackMisc::Simulation::CInterpolationStatus &status) const; - - //! \copydoc BlackMisc::Simulation::CInterpolator::getInterpolatedParts - BlackMisc::Aviation::CAircraftParts getInterpolatedParts( - qint64 currentTimeSinceEpoc, - const BlackMisc::Simulation::CInterpolationAndRenderingSetupPerCallsign &setup, - BlackMisc::Simulation::CPartsStatus &partsStatus, bool log) const; - - //! \copydoc BlackMisc::Simulation::CInterpolator::getInterpolatedOrGuessedParts - BlackMisc::Aviation::CAircraftParts getInterpolatedOrGuessedParts( - qint64 currentTimeSinceEpoc, - const BlackMisc::Simulation::CInterpolationAndRenderingSetupPerCallsign &setup, - BlackMisc::Simulation::CPartsStatus &partsStatus, bool log) const; + //! \copydoc BlackMisc::Simulation::CInterpolator::getInterpolation + BlackMisc::Simulation::CInterpolationResult getInterpolation(qint64 currentTimeSinceEpoc, const BlackMisc::Simulation::CInterpolationAndRenderingSetupPerCallsign &setup) const; //! Interpolator BlackMisc::Simulation::CInterpolatorMulti *getInterpolator() const { return m_interpolator.data(); } diff --git a/tests/blackmisc/testinterpolatorlinear.cpp b/tests/blackmisc/testinterpolatorlinear.cpp index 870502f0d..c9dd6b7a8 100644 --- a/tests/blackmisc/testinterpolatorlinear.cpp +++ b/tests/blackmisc/testinterpolatorlinear.cpp @@ -64,7 +64,7 @@ namespace BlackMiscTest const qint64 offset = 5000; for (int i = IRemoteAircraftProvider::MaxSituationsPerCallsign - 1; i >= 0; i--) { - CAircraftSituation s(getTestSituation(cs, i, ts, deltaT, offset)); + const CAircraftSituation s(getTestSituation(cs, i, ts, deltaT, offset)); // check height above ground CLength hag = (s.getAltitude() - s.getGroundElevation()); @@ -75,7 +75,7 @@ namespace BlackMiscTest constexpr int partsCount = 10; for (int i = partsCount - 1; i >= 0; i--) { - CAircraftParts p(getTestParts(i, ts, deltaT)); + const CAircraftParts p(getTestParts(i, ts, deltaT)); provider.insertNewAircraftParts(cs, p, false); } @@ -83,7 +83,6 @@ namespace BlackMiscTest QCoreApplication::processEvents(QEventLoop::AllEvents, 1000); // interpolation functional check - CInterpolationStatus status; const CInterpolationAndRenderingSetupPerCallsign setup; double latOld = 360.0; double lngOld = 360.0; @@ -92,10 +91,10 @@ namespace BlackMiscTest // This will use time range // from: ts - 2 * deltaT + offset // to: ts + offset - CAircraftSituation currentSituation( - interpolator.getInterpolatedSituation(currentTime, setup, status) - ); - QVERIFY2(status.isInterpolated(), "Value was not interpolated"); + + const CInterpolationResult result = interpolator.getInterpolation(currentTime, setup); + const CAircraftSituation currentSituation(result); + QVERIFY2(result.getInterpolationStatus().isInterpolated(), "Value was not interpolated"); const double latDeg = currentSituation.getPosition().latitude().valueRounded(CAngleUnit::deg(), 5); const double lngDeg = currentSituation.getPosition().longitude().valueRounded(CAngleUnit::deg(), 5); QVERIFY2(latDeg < latOld && lngDeg < lngOld, QString("Values shall decrease: %1/%2 %3/%4").arg(latDeg).arg(latOld).arg(lngDeg).arg(lngOld).toLatin1()); @@ -122,10 +121,9 @@ namespace BlackMiscTest // This will use range // from: ts - 2* deltaT + offset // to: ts + offset - CAircraftSituation currentSituation( - interpolator.getInterpolatedSituation(currentTime, setup, status) - ); - QVERIFY2(status.isInterpolated(), "Not interpolated"); + const CInterpolationResult result = interpolator.getInterpolation(currentTime, setup); + const CAircraftSituation currentSituation(result); + QVERIFY2(result.getInterpolationStatus().isInterpolated(), "Not interpolated"); QVERIFY2(!currentSituation.getCallsign().isEmpty(), "Empty callsign"); QVERIFY2(currentSituation.getCallsign() == cs, "Wrong callsign"); const double latDeg = currentSituation.getPosition().latitude().valueRounded(CAngleUnit::deg(), 5); @@ -143,11 +141,9 @@ namespace BlackMiscTest timer.start(); for (qint64 currentTime = ts - 2 * deltaT; currentTime < ts; currentTime += 250) { - CPartsStatus partsStatus; - const CAircraftParts pl(interpolator.getInterpolatedParts(ts, setup, partsStatus)); - Q_UNUSED(pl); + const CInterpolationResult result = interpolator.getInterpolation(currentTime, setup); fetchedParts++; - QVERIFY2(partsStatus.isSupportingParts(), "Parts not supported"); + QVERIFY2(result.getPartsStatus().isSupportingParts(), "Parts not supported"); } timeMs = timer.elapsed(); qDebug() << timeMs << "ms" << "for" << fetchedParts << "fetched parts"; diff --git a/tests/blackmisc/testinterpolatorparts.cpp b/tests/blackmisc/testinterpolatorparts.cpp index 3f4336fe5..a741688a3 100644 --- a/tests/blackmisc/testinterpolatorparts.cpp +++ b/tests/blackmisc/testinterpolatorparts.cpp @@ -51,7 +51,6 @@ namespace BlackMiscTest QVERIFY2(parts.size() == number, "Wrong parts size of list"); // interpolation functional check - CPartsStatus status; const CInterpolationAndRenderingSetupPerCallsign setup; const qint64 oldestTs = parts.oldestTimestampMsecsSinceEpoch(); @@ -59,13 +58,15 @@ namespace BlackMiscTest // all on ground flags true provider.insertNewAircraftParts(cs, parts, false); // we work with 0 offsets here QVERIFY2(provider.remoteAircraftPartsCount(cs) == parts.size(), "Wrong parts size"); - CAircraftParts p = interpolator.getInterpolatedParts(farFuture, setup, status); + CInterpolationResult result = interpolator.getInterpolation(farFuture, setup); + CAircraftParts p = result; qint64 pTs = p.getAdjustedMSecsSinceEpoch(); - QVERIFY2(status.isSupportingParts(), "Should support parts"); + QVERIFY2(result.getPartsStatus().isSupportingParts(), "Should support parts"); QVERIFY2(pTs == ts, "Expect latest ts"); - p = interpolator.getInterpolatedParts(farPast, setup, status); + result = interpolator.getInterpolation(farPast, setup); + p = result; pTs = p.getAdjustedMSecsSinceEpoch(); - QVERIFY2(status.isSupportingParts(), "Should support parts"); + QVERIFY2(result.getPartsStatus().isSupportingParts(), "Should support parts"); QVERIFY2(pTs == oldestTs, "Expect oldest ts"); // Testing for a time >> last time @@ -75,9 +76,10 @@ namespace BlackMiscTest parts.setOnGround(false); provider.insertNewAircraftParts(cs, parts, false); // we work with 0 offsets here - p = interpolator.getInterpolatedParts(farFuture, setup, status); + result = interpolator.getInterpolation(farFuture, setup); + p = result; pTs = p.getAdjustedMSecsSinceEpoch(); - QVERIFY2(status.isSupportingParts(), "Should support parts"); + QVERIFY2(result.getPartsStatus().isSupportingParts(), "Should support parts"); QVERIFY2(p.getAdjustedMSecsSinceEpoch() == pTs, "Expect latest ts"); }