diff --git a/src/blackmisc/simulation/interpolator.h b/src/blackmisc/simulation/interpolator.h index d74429fc6..f7fd2db99 100644 --- a/src/blackmisc/simulation/interpolator.h +++ b/src/blackmisc/simulation/interpolator.h @@ -26,176 +26,169 @@ #include #include -namespace BlackMisc +namespace BlackMisc::Simulation { - namespace Aviation + class CInterpolationLogger; + class CInterpolatorLinear; + class CInterpolatorSpline; + + //! Interpolator, calculation inbetween positions + template + class CInterpolator : + protected CSimulationEnvironmentAware, + protected CInterpolationSetupAware, + protected CRemoteAircraftAware { - class CAircraftSituation; - class CAircraftSituationChange; - } - namespace Simulation - { - class CInterpolationLogger; - class CInterpolatorLinear; - class CInterpolatorSpline; + public: + //! Log categories + static const QStringList &getLogCategories(); - //! Interpolator, calculation inbetween positions - template - class CInterpolator : - protected CSimulationEnvironmentAware, - protected CInterpolationSetupAware, - protected CRemoteAircraftAware - { - public: - //! Log categories - static const QStringList &getLogCategories(); + //! Latest interpolation result + const Aviation::CAircraftSituation &getLastInterpolatedSituation() const { return m_lastSituation; } - //! Latest interpolation result - const Aviation::CAircraftSituation &getLastInterpolatedSituation() const { return m_lastSituation; } + //! Get interpolated situation + //! \param currentTimeSinceEpoch milliseconds since epoch for which the situation should be interpolated + //! \param setup interpolation setup + //! \param aircraftNumber number used to spread the computational load of part interpolation + //! \return interpolation result + CInterpolationResult getInterpolation(qint64 currentTimeSinceEpoch, const CInterpolationAndRenderingSetupPerCallsign &setup, uint32_t aircraftNumber); - //! Get interpolated situation - //! \param currentTimeSinceEpoch milliseconds since epoch for which the situation should be interpolated - //! \param setup interpolation setup - //! \param aircraftNumber number used to spread the computational load of part interpolation - //! \return interpolation result - CInterpolationResult getInterpolation(qint64 currentTimeSinceEpoch, const CInterpolationAndRenderingSetupPerCallsign &setup, uint32_t aircraftNumber); + //! 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; } - //! 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; } - //! Is logger attached? - bool hasAttachedLogger() const { return m_logger; } + //! Get an interpolator info string (for debug info) + QString getInterpolatorInfo() const; - //! Get an interpolator info string (for debug info) - QString getInterpolatorInfo() const; + //! Reset last interpolation to null + //! \remark mainly needed in UNIT tests + void resetLastInterpolation(); - //! Reset last interpolation to null - //! \remark mainly needed in UNIT tests - void resetLastInterpolation(); + //! Init, or re-init the corressponding model + //! \remark either by passing a model or using the provider + void initCorrespondingModel(const CAircraftModel &model = {}); - //! Init, or re-init the corressponding model - //! \remark either by passing a model or using the provider - void initCorrespondingModel(const CAircraftModel &model = {}); + //! Mark as unit test + void markAsUnitTest(); - //! Mark as unit test - void markAsUnitTest(); + //! Get count of invalid situations + int getInvalidSituationsCount() const { return m_invalidSituations; } - //! Get count of invalid situations - int getInvalidSituationsCount() const { return m_invalidSituations; } + //! Interpolation messages + const CStatusMessageList &getInterpolationMessages() const { return m_interpolationMessages; } - //! Interpolation messages - const CStatusMessageList &getInterpolationMessages() const { return m_interpolationMessages; } + //! Do we have interpolation messages + bool hasInterpolationMessages() const { return !m_interpolationMessages.isEmpty(); } - //! Do we have interpolation messages - bool hasInterpolationMessages() const { return !m_interpolationMessages.isEmpty(); } + protected: + //! Constructor + CInterpolator(const Aviation::CCallsign &callsign, + ISimulationEnvironmentProvider *simEnvProvider, IInterpolationSetupProvider *setupProvider, IRemoteAircraftProvider *remoteProvider, + CInterpolationLogger *logger); - protected: - //! Constructor - CInterpolator(const Aviation::CCallsign &callsign, - ISimulationEnvironmentProvider *simEnvProvider, IInterpolationSetupProvider *setupProvider, IRemoteAircraftProvider *remoteProvider, - CInterpolationLogger *logger); + //! Inits all data members for this current interpolation step + //! \param currentTimeSinceEpoch milliseconds since epoch for which the situation should be interpolated + //! \param setup interpolation setup + //! \param aircraftNumber passing the aircraft number allows to equally distribute among the steps and not to do it always together for all aircraft + bool initIniterpolationStepData(qint64 currentTimeSinceEpoch, const CInterpolationAndRenderingSetupPerCallsign &setup, int aircraftNumber); - //! Inits all data members for this current interpolation step - //! \param currentTimeSinceEpoch milliseconds since epoch for which the situation should be interpolated - //! \param setup interpolation setup - //! \param aircraftNumber passing the aircraft number allows to equally distribute among the steps and not to do it always together for all aircraft - bool initIniterpolationStepData(qint64 currentTimeSinceEpoch, const CInterpolationAndRenderingSetupPerCallsign &setup, int aircraftNumber); + //! Init the interpolated situation + Aviation::CAircraftSituation initInterpolatedSituation(const Aviation::CAircraftSituation &oldSituation, const Aviation::CAircraftSituation &newSituation) const; - //! Init the interpolated situation - Aviation::CAircraftSituation initInterpolatedSituation(const Aviation::CAircraftSituation &oldSituation, const Aviation::CAircraftSituation &newSituation) const; + //! Current interpolated situation + Aviation::CAircraftSituation getInterpolatedSituation(); - //! Current interpolated situation - Aviation::CAircraftSituation getInterpolatedSituation(); + //! Parts before given offset time + Aviation::CAircraftParts getInterpolatedParts(); - //! Parts before given offset time - Aviation::CAircraftParts getInterpolatedParts(); + //! Interpolated parts, if not available guessed parts + Aviation::CAircraftParts getInterpolatedOrGuessedParts(int aircraftNumber); - //! Interpolated parts, if not available guessed parts - Aviation::CAircraftParts getInterpolatedOrGuessedParts(int aircraftNumber); + //! Center of gravity + const PhysicalQuantities::CLength &getModelCG() const { return m_model.getCG(); } - //! Center of gravity - const PhysicalQuantities::CLength &getModelCG() const { return m_model.getCG(); } + //! Do logging + bool doLogging() const; - //! Do logging - bool doLogging() const; + //! Decides threshold when situation is considered on ground + //! \sa BlackMisc::Aviation::CAircraftSituation::setOnGroundFromGroundFactorFromInterpolation + static double groundInterpolationFactor(); - //! Decides threshold when situation is considered on ground - //! \sa BlackMisc::Aviation::CAircraftSituation::setOnGroundFromGroundFactorFromInterpolation - static double groundInterpolationFactor(); + const Aviation::CCallsign m_callsign; //!< corresponding callsign + CAircraftModel m_model; //!< corresponding model (required for CG) - const Aviation::CCallsign m_callsign; //!< corresponding callsign - CAircraftModel m_model; //!< corresponding model (required for CG) + // values for current interpolation step + qint64 m_currentTimeMsSinceEpoch = -1; //!< current time + qint64 m_lastInvalidLogTs = -1; //!< last invalid situation timestamp + Aviation::CAircraftSituationList m_currentSituations; //!< current situations obtained by remoteAircraftSituationsAndChange + Aviation::CAircraftSituationChange m_pastSituationsChange; //!< situations change of provider (i.e. network) situations + CInterpolationAndRenderingSetupPerCallsign m_currentSetup; //!< used setup + CInterpolationStatus m_currentInterpolationStatus; //!< this step's situation status + CPartsStatus m_currentPartsStatus; //!< this step's parts status + CPartsStatus m_lastPartsStatus; //!< status for last parts, used when last parts are re-used because of m_partsToSituationInterpolationRatio + int m_partsToSituationInterpolationRatio = 2; //!< ratio between parts and situation interpolation, 1..always, 2..every 2nd situation + int m_partsToSituationGuessingRatio = 5; //!< ratio between parts guessing and situation interpolation + int m_invalidSituations = 0; //!< mainly when there are no new situations + CStatusMessageList m_interpolationMessages; //!< interpolation messages - // values for current interpolation step - qint64 m_currentTimeMsSinceEpoch = -1; //!< current time - qint64 m_lastInvalidLogTs = -1; //!< last invalid situation timestamp - Aviation::CAircraftSituationList m_currentSituations; //!< current situations obtained by remoteAircraftSituationsAndChange - Aviation::CAircraftSituationChange m_pastSituationsChange; //!< situations change of provider (i.e. network) situations - CInterpolationAndRenderingSetupPerCallsign m_currentSetup; //!< used setup - CInterpolationStatus m_currentInterpolationStatus; //!< this step's situation status - CPartsStatus m_currentPartsStatus; //!< this step's parts status - CPartsStatus m_lastPartsStatus; //!< status for last parts, used when last parts are re-used because of m_partsToSituationInterpolationRatio - int m_partsToSituationInterpolationRatio = 2; //!< ratio between parts and situation interpolation, 1..always, 2..every 2nd situation - int m_partsToSituationGuessingRatio = 5; //!< ratio between parts guessing and situation interpolation - int m_invalidSituations = 0; //!< mainly when there are no new situations - CStatusMessageList m_interpolationMessages; //!< interpolation messages + Aviation::CAircraftSituation m_lastSituation { Aviation::CAircraftSituation::null() }; //!< latest interpolation + Aviation::CAircraftParts m_lastParts { Aviation::CAircraftParts::null() }; //!< latest parts + PhysicalQuantities::CLength m_currentSceneryOffset { PhysicalQuantities::CLength::null() }; //!< calculated scenery offset if any - Aviation::CAircraftSituation m_lastSituation { Aviation::CAircraftSituation::null() }; //!< latest interpolation - Aviation::CAircraftParts m_lastParts { Aviation::CAircraftParts::null() }; //!< latest parts - PhysicalQuantities::CLength m_currentSceneryOffset { PhysicalQuantities::CLength::null() }; //!< calculated scenery offset if any + qint64 m_situationsLastModified { -1 }; //!< when situations were last modified + qint64 m_situationsLastModifiedUsed { -1 }; //!< interpolant based on situations last updated + int m_interpolatedSituationsCounter { 0 }; //!< counter for each interpolated situations: used for statistics, every n-th interpolation .... - qint64 m_situationsLastModified { -1 }; //!< when situations were last modified - qint64 m_situationsLastModifiedUsed { -1 }; //!< interpolant based on situations last updated - int m_interpolatedSituationsCounter { 0 }; //!< counter for each interpolated situations: used for statistics, every n-th interpolation .... + bool m_unitTest = false; //!< mark as unit test - bool m_unitTest = false; //!< mark as unit test + //! 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()); - //! 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 - 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 + //! Guessed parts + static Aviation::CAircraftParts guessParts(const Aviation::CAircraftSituation &situation, const Aviation::CAircraftSituationChange &change, const Simulation::CAircraftModel &model); - //! Guessed parts - static Aviation::CAircraftParts guessParts(const Aviation::CAircraftSituation &situation, const Aviation::CAircraftSituationChange &change, const Simulation::CAircraftModel &model); + //! Log parts + void logParts(const Aviation::CAircraftParts &parts, int partsNo, bool empty) const; - //! 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(const CInterpolationAndRenderingSetupPerCallsign &setup); - //! Get situations and calculate change, also correct altitudes if applicable - //! \remark calculates offset (scenery) and situations change - Aviation::CAircraftSituationList remoteAircraftSituationsAndChange(const CInterpolationAndRenderingSetupPerCallsign &setup); + //! Center of gravity, fetched from provider in case needed + PhysicalQuantities::CLength getAndFetchModelCG(const PhysicalQuantities::CLength &dbCG); - //! Center of gravity, fetched from provider in case needed - PhysicalQuantities::CLength getAndFetchModelCG(const PhysicalQuantities::CLength &dbCG); + //! Preset the ground elevation based on info we already have, either by transfer or elevation + //! \remark either sets a gnd. elevation or sets it to null + //! \remark situationToPreset position is unknown + //! \remark situationToPreset needs to be between oldSituation and newSituation + //! \sa CAircraftSituation::transferGroundElevation + static bool presetGroundElevation(Aviation::CAircraftSituation &situationToPreset, const Aviation::CAircraftSituation &oldSituation, const Aviation::CAircraftSituation &newSituation, const Aviation::CAircraftSituationChange &change); - //! Preset the ground elevation based on info we already have, either by transfer or elevation - //! \remark either sets a gnd. elevation or sets it to null - //! \remark situationToPreset position is unknown - //! \remark situationToPreset needs to be between oldSituation and newSituation - //! \sa CAircraftSituation::transferGroundElevation - static bool presetGroundElevation(Aviation::CAircraftSituation &situationToPreset, const Aviation::CAircraftSituation &oldSituation, const Aviation::CAircraftSituation &newSituation, const Aviation::CAircraftSituationChange &change); + //! Deferred init + void deferredInit(); - //! Deferred init - void deferredInit(); + //! Return NULL parts and log + const BlackMisc::Aviation::CAircraftParts &logAndReturnNullParts(const QString &info, bool log); - //! Return NULL parts and log - const BlackMisc::Aviation::CAircraftParts &logAndReturnNullParts(const QString &info, bool log); + //! @{ + //! Derived class + Derived *derived() { return static_cast(this); } + const Derived *derived() const { return static_cast(this); } + //! @} + }; - //! @{ - //! Derived class - 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; - //! \endcond - } // namespace + //! \cond PRIVATE + extern template class BLACKMISC_EXPORT_DECLARE_TEMPLATE CInterpolator; + extern template class BLACKMISC_EXPORT_DECLARE_TEMPLATE CInterpolator; + //! \endcond } // namespace +// namespace #endif // guard